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  }