github.com/eth-easl/loader@v0.0.0-20230908084258-8a37e1d94279/server/timed/timed.go (about) 1 /* 2 * MIT License 3 * 4 * Copyright (c) 2023 EASL and the vHive community 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a copy 7 * of this software and associated documentation files (the "Software"), to deal 8 * in the Software without restriction, including without limitation the rights 9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 * copies of the Software, and to permit persons to whom the Software is 11 * furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in all 14 * copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 * SOFTWARE. 23 */ 24 25 package main 26 27 import ( 28 "context" 29 "errors" 30 "fmt" 31 util "github.com/eth-easl/loader/pkg/common" 32 "github.com/eth-easl/loader/pkg/workload/proto" 33 "net" 34 "os" 35 "strconv" 36 "time" 37 38 log "github.com/sirupsen/logrus" 39 "golang.org/x/sys/unix" 40 "google.golang.org/grpc" 41 "google.golang.org/grpc/reflection" 42 ) 43 44 //! We don't enforce this limit anymore because no limits have set for the containers themselves 45 //! (i.e., they are busrtable workloads controlled by K8s and won't get OOM-killed by the kernel). 46 // const containerMemoryLimitMib = 512 // Default limit of k8s. 47 48 type funcServer struct { 49 proto.UnimplementedExecutorServer 50 } 51 52 func busySpin(timeoutSem <-chan time.Time) { 53 /** `for { }` generates the assembly `jmp self`, which is a spin lock. */ 54 for { 55 select { 56 case <-timeoutSem: //* Fulfill requested runtime. 57 return 58 default: //* Non-blocking. 59 continue 60 } 61 } 62 } 63 64 func (s *funcServer) Execute(ctx context.Context, req *proto.FaasRequest) (*proto.FaasReply, error) { 65 start := time.Now() 66 runtimeRequested := req.RuntimeInMilliSec 67 timeoutSem := time.After(time.Duration(runtimeRequested) * time.Millisecond) 68 if runtimeRequested <= 0 { 69 //* Some of the durations were incorrectly recorded as 0 in the trace. 70 return &proto.FaasReply{}, errors.New("non-positive execution time") 71 } 72 73 //* To avoid unecessary overheads, memory allocation is at the granularity of os pages. 74 delta := 2 //* Emperical skewness. 75 pageSize := unix.Getpagesize() 76 numPagesRequested := util.Mib2b(req.MemoryInMebiBytes) / uint32(pageSize) / uint32(delta) 77 bytes := make([]byte, numPagesRequested*uint32(pageSize)) 78 timeout := false 79 for i := 0; i < int(numPagesRequested); i += pageSize { 80 select { 81 case <-timeoutSem: 82 timeout = true 83 goto finish //* Skip spin-lock. 84 default: 85 bytes[i] = byte(1) //* Materialise allocated memory. 86 } 87 } 88 89 busySpin(timeoutSem) 90 91 finish: 92 var msg string 93 if msg = "Timed func -- OK"; timeout { 94 msg = "Timeout when materialising allocated memory." 95 } 96 97 return &proto.FaasReply{ 98 Message: msg, 99 DurationInMicroSec: uint32(time.Since(start).Microseconds()), 100 MemoryUsageInKb: util.B2Kib(numPagesRequested * uint32(unix.Getpagesize())), 101 }, nil 102 } 103 104 func main() { 105 serverPort := 80 // For containers. 106 // 50051 for firecracker. 107 if len(os.Args) > 1 { 108 serverPort, _ = strconv.Atoi(os.Args[1]) 109 } 110 111 lis, err := net.Listen("tcp", fmt.Sprintf(":%d", serverPort)) 112 if err != nil { 113 log.Fatalf("failed to listen: %v", err) 114 } 115 116 funcServer := &funcServer{} 117 grpcServer := grpc.NewServer() 118 reflection.Register(grpcServer) // gRPC Server Reflection is used by gRPC CLI. 119 proto.RegisterExecutorServer(grpcServer, funcServer) 120 err = grpcServer.Serve(lis) 121 util.Check(err) 122 }