github.com/eth-easl/loader@v0.0.0-20230908084258-8a37e1d94279/pkg/workload/standard/workload.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 standard 26 27 import ( 28 "context" 29 "fmt" 30 tracing "github.com/ease-lab/vhive/utils/tracing/go" 31 util "github.com/eth-easl/loader/pkg/common" 32 "github.com/eth-easl/loader/pkg/workload/proto" 33 log "github.com/sirupsen/logrus" 34 "google.golang.org/grpc" 35 "google.golang.org/grpc/reflection" 36 "net" 37 "os" 38 "strconv" 39 "time" 40 ) 41 42 // static double SQRTSD (double x) { 43 // double r; 44 // __asm__ ("sqrtsd %1, %0" : "=x" (r) : "x" (x)); 45 // return r; 46 // } 47 import "C" 48 49 const ( 50 // ContainerImageSizeMB was chosen as a median of the container physical memory usage. 51 // Allocate this much less memory inside the actual function. 52 ContainerImageSizeMB = 15 53 ) 54 55 const EXEC_UNIT int = 1e2 56 57 var hostname string 58 var iterationsMultiplier int 59 var serverSideCode FunctionType 60 61 type FunctionType int 62 63 const ( 64 TraceFunction FunctionType = 0 65 EmptyFunction FunctionType = 1 66 ) 67 68 func takeSqrts() C.double { 69 var tmp C.double // Circumvent compiler optimizations 70 for i := 0; i < EXEC_UNIT; i++ { 71 tmp = C.SQRTSD(C.double(10)) 72 } 73 return tmp 74 } 75 76 type funcServer struct { 77 proto.UnimplementedExecutorServer 78 } 79 80 func busySpin(runtimeMilli uint32) { 81 totalIterations := iterationsMultiplier * int(runtimeMilli) 82 83 for i := 0; i < totalIterations; i++ { 84 takeSqrts() 85 } 86 } 87 88 func (s *funcServer) Execute(_ context.Context, req *proto.FaasRequest) (*proto.FaasReply, error) { 89 var msg string 90 start := time.Now() 91 92 if serverSideCode == TraceFunction { 93 // Minimum execution time is AWS billing granularity - 1ms, 94 // as defined in SpecificationGenerator::generateExecutionSpecs 95 timeLeftMilliseconds := req.RuntimeInMilliSec 96 /*toAllocate := util.Mib2b(req.MemoryInMebiBytes - ContainerImageSizeMB) 97 if toAllocate < 0 { 98 toAllocate = 0 99 }*/ 100 101 // make is equivalent to `calloc` in C. The memory gets allocated 102 // and zero is written to every byte, i.e. each page should be touched at least once 103 //memory := make([]byte, toAllocate) 104 // NOTE: the following statement to make sure the compiler does not treat the allocation as dead code 105 //log.Debugf("Allocated memory size: %d\n", len(memory)) 106 107 timeConsumedMilliseconds := uint32(time.Since(start).Milliseconds()) 108 if timeConsumedMilliseconds < timeLeftMilliseconds { 109 timeLeftMilliseconds -= timeConsumedMilliseconds 110 if timeLeftMilliseconds > 0 { 111 busySpin(timeLeftMilliseconds) 112 } 113 114 msg = fmt.Sprintf("OK - %s", hostname) 115 } 116 } else { 117 msg = fmt.Sprintf("OK - EMPTY - %s", hostname) 118 } 119 120 return &proto.FaasReply{ 121 Message: msg, 122 DurationInMicroSec: uint32(time.Since(start).Microseconds()), 123 MemoryUsageInKb: req.MemoryInMebiBytes * 1024, 124 }, nil 125 } 126 127 func readEnvironmentalVariables() { 128 if _, ok := os.LookupEnv("ITERATIONS_MULTIPLIER"); ok { 129 iterationsMultiplier, _ = strconv.Atoi(os.Getenv("ITERATIONS_MULTIPLIER")) 130 } else { 131 // Cloudlab xl170 benchmark @ 1 second function execution time 132 iterationsMultiplier = 102 133 } 134 135 log.Infof("ITERATIONS_MULTIPLIER = %d\n", iterationsMultiplier) 136 137 var err error 138 hostname, err = os.Hostname() 139 if err != nil { 140 log.Warn("Failed to get HOSTNAME environmental variable.") 141 hostname = "Unknown host" 142 } 143 } 144 145 func StartGRPCServer(serverAddress string, serverPort int, functionType FunctionType, zipkinUrl string) { 146 readEnvironmentalVariables() 147 serverSideCode = functionType 148 149 if tracing.IsTracingEnabled() { 150 log.Infof("Zipkin URL: %s\n", zipkinUrl) 151 shutdown, err := tracing.InitBasicTracer(zipkinUrl, "") 152 if err != nil { 153 log.Warn(err) 154 } 155 defer shutdown() 156 } 157 158 lis, err := net.Listen("tcp", fmt.Sprintf("%s:%d", serverAddress, serverPort)) 159 if err != nil { 160 log.Fatalf("failed to listen: %v", err) 161 } 162 163 var grpcServer *grpc.Server 164 if tracing.IsTracingEnabled() { 165 grpcServer = tracing.GetGRPCServerWithUnaryInterceptor() 166 } else { 167 grpcServer = grpc.NewServer() 168 } 169 reflection.Register(grpcServer) // gRPC Server Reflection is used by gRPC CLI 170 proto.RegisterExecutorServer(grpcServer, &funcServer{}) 171 err = grpcServer.Serve(lis) 172 util.Check(err) 173 }