From 684e8d18bcc31543bfc6038e535cd97dd7c4a16a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lazar=20Cvetkovi=C4=87?= Date: Tue, 3 Sep 2024 18:57:38 +0200 Subject: [PATCH] Deploy and invoke interfaces MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Lazar Cvetković --- .github/configs/wordlist.txt | 12 +- .gitignore | 10 +- cmd/config_dirigent_dandelion_rps.json | 35 ++++ cmd/config_dirigent_dandelion_trace.json | 27 +++ cmd/config_dirigent_rps.json | 35 ++++ ...rigent.json => config_dirigent_trace.json} | 13 +- cmd/config_knative_rps.json | 35 ++++ ...{config.json => config_knative_trace.json} | 11 +- cmd/loader.go | 165 +++++++++------- docs/configuration.md | 32 +++- go.mod | 36 ++-- go.sum | 76 ++++---- pkg/common/trace_types.go | 3 + pkg/config/configuration.go | 26 +++ pkg/config/parser.go | 25 ++- pkg/driver/clients/aws_client.go | 58 ++++++ pkg/driver/clients/dandelion_interface.go | 108 +++++++++++ pkg/driver/{ => clients}/grpc_client.go | 24 ++- pkg/driver/{ => clients}/grpc_client_test.go | 18 +- pkg/driver/clients/http_client.go | 168 ++++++++++++++++ pkg/driver/clients/http_client_factory.go | 50 +++++ pkg/driver/clients/invoker.go | 40 ++++ pkg/driver/clients/openwhisk_client.go | 181 ++++++++++++++++++ pkg/driver/deploy.sh | 41 ---- .../aws_lambda.go} | 24 ++- .../aws_serverless_config.go} | 26 +-- pkg/driver/deployment/deployer.go | 28 +++ pkg/driver/deployment/dirigent.go | 99 ++++++++++ pkg/driver/deployment/knative.go | 127 ++++++++++++ pkg/driver/deployment/knative.sh | 17 ++ pkg/driver/deployment/openwhisk.go | 64 +++++++ pkg/driver/trace_driver.go | 98 +++------- pkg/driver/trace_driver_test.go | 18 +- pkg/metric/record.go | 37 +--- workloads/container/trace_func_py.yaml | 12 -- workloads/container/wimpy.yaml | 20 -- workloads/firecracker/timed.yaml | 20 -- workloads/other/helloworld.yaml | 12 -- workloads/other/producer.yaml | 28 --- 39 files changed, 1419 insertions(+), 440 deletions(-) create mode 100644 cmd/config_dirigent_dandelion_rps.json create mode 100644 cmd/config_dirigent_dandelion_trace.json create mode 100644 cmd/config_dirigent_rps.json rename cmd/{config_dirigent.json => config_dirigent_trace.json} (67%) create mode 100644 cmd/config_knative_rps.json rename cmd/{config.json => config_knative_trace.json} (73%) create mode 100644 pkg/config/configuration.go create mode 100644 pkg/driver/clients/aws_client.go create mode 100644 pkg/driver/clients/dandelion_interface.go rename pkg/driver/{ => clients}/grpc_client.go (87%) rename pkg/driver/{ => clients}/grpc_client_test.go (88%) create mode 100644 pkg/driver/clients/http_client.go create mode 100644 pkg/driver/clients/http_client_factory.go create mode 100644 pkg/driver/clients/invoker.go create mode 100644 pkg/driver/clients/openwhisk_client.go delete mode 100755 pkg/driver/deploy.sh rename pkg/driver/{deployment_awslambda.go => deployment/aws_lambda.go} (95%) rename pkg/driver/{serverless_config.go => deployment/aws_serverless_config.go} (81%) create mode 100644 pkg/driver/deployment/deployer.go create mode 100644 pkg/driver/deployment/dirigent.go create mode 100644 pkg/driver/deployment/knative.go create mode 100644 pkg/driver/deployment/knative.sh create mode 100644 pkg/driver/deployment/openwhisk.go delete mode 100644 workloads/container/trace_func_py.yaml delete mode 100644 workloads/container/wimpy.yaml delete mode 100644 workloads/firecracker/timed.yaml delete mode 100644 workloads/other/helloworld.yaml delete mode 100644 workloads/other/producer.yaml diff --git a/.github/configs/wordlist.txt b/.github/configs/wordlist.txt index c24bc022..d3fbc3d6 100644 --- a/.github/configs/wordlist.txt +++ b/.github/configs/wordlist.txt @@ -753,4 +753,14 @@ ethz lazar xvzf untar -len \ No newline at end of file +len +CooldownSeconds +RpsCooldownSeconds +Dirigent +RpsColdStartRatioPercentage +RpsIterationMultiplier +RpsMemoryMB +RpsRuntimeMs +RpsTarget +SQRT +RpsImage \ No newline at end of file diff --git a/.gitignore b/.gitignore index a01b14b2..d82e886b 100644 --- a/.gitignore +++ b/.gitignore @@ -107,7 +107,6 @@ __pycache__/ *$py.class # C extensions -*.so # Distribution / packaging .Python @@ -155,7 +154,6 @@ coverage.xml *.pot # Django stuff: -*.log local_settings.py # Flask stuff: @@ -187,7 +185,6 @@ celerybeat-schedule .env # virtualenv -.venv venv/ ENV/ @@ -205,7 +202,10 @@ ENV/ .mypy_cache/ # IDE settings -.vscode/ .idea/ -tools/plotter/test-out \ No newline at end of file +tools/plotter/test-out +*.swp + +data/traces/azure_* +data/traces/day* \ No newline at end of file diff --git a/cmd/config_dirigent_dandelion_rps.json b/cmd/config_dirigent_dandelion_rps.json new file mode 100644 index 00000000..c0ac2b86 --- /dev/null +++ b/cmd/config_dirigent_dandelion_rps.json @@ -0,0 +1,35 @@ +{ + "Seed": 42, + + "Platform": "Dirigent-Dandelion-RPS", + "InvokeProtocol" : "http1", + "EndpointPort": 80, + + "DirigentControlPlaneIP": "10.0.1.253:9091", + "BusyLoopOnSandboxStartup": false, + + "RpsTarget": 1, + "RpsColdStartRatioPercentage": 0, + "RpsCooldownSeconds": 10, + "RpsImage": "empty", + "RpsRuntimeMs": 10, + "RpsMemoryMB": 2048, + "RpsIterationMultiplier": 80, + + "TracePath": "data/traces/example", + "Granularity": "minute", + "OutputPathPrefix": "data/out/experiment", + "IATDistribution": "equidistant", + "CPULimit": "1vCPU", + "ExperimentDuration": 1, + "WarmupDuration": 0, + + "IsPartiallyPanic": false, + "EnableZipkinTracing": false, + "EnableMetricsScrapping": false, + "MetricScrapingPeriodSeconds": 15, + "AutoscalingMetric": "concurrency", + + "GRPCConnectionTimeoutSeconds": 5, + "GRPCFunctionTimeoutSeconds": 900 +} \ No newline at end of file diff --git a/cmd/config_dirigent_dandelion_trace.json b/cmd/config_dirigent_dandelion_trace.json new file mode 100644 index 00000000..ad289055 --- /dev/null +++ b/cmd/config_dirigent_dandelion_trace.json @@ -0,0 +1,27 @@ +{ + "Seed": 42, + + "Platform": "Dirigent-Dandelion", + "InvokeProtocol" : "http1", + "EndpointPort": 80, + + "DirigentControlPlaneIP": "10.0.1.253:9091", + "BusyLoopOnSandboxStartup": false, + + "TracePath": "data/traces/example", + "Granularity": "minute", + "OutputPathPrefix": "data/out/experiment", + "IATDistribution": "exponential", + "CPULimit": "1vCPU", + "ExperimentDuration": 2, + "WarmupDuration": 0, + + "IsPartiallyPanic": false, + "EnableZipkinTracing": false, + "EnableMetricsScrapping": false, + "MetricScrapingPeriodSeconds": 15, + "AutoscalingMetric": "concurrency", + + "GRPCConnectionTimeoutSeconds": 15, + "GRPCFunctionTimeoutSeconds": 180 +} \ No newline at end of file diff --git a/cmd/config_dirigent_rps.json b/cmd/config_dirigent_rps.json new file mode 100644 index 00000000..3d20f5dc --- /dev/null +++ b/cmd/config_dirigent_rps.json @@ -0,0 +1,35 @@ +{ + "Seed": 42, + + "Platform": "Dirigent-RPS", + "InvokeProtocol" : "http2", + "EndpointPort": 80, + + "DirigentControlPlaneIP": "10.0.1.253:9092", + "BusyLoopOnSandboxStartup": false, + + "RpsTarget": 1, + "RpsColdStartRatioPercentage": 0, + "RpsCooldownSeconds": 10, + "RpsImage": "docker.io/cvetkovic/dirigent_empty_function:latest", + "RpsRuntimeMs": 10, + "RpsMemoryMB": 2048, + "RpsIterationMultiplier": 80, + + "TracePath": "data/traces/example", + "Granularity": "minute", + "OutputPathPrefix": "data/out/experiment", + "IATDistribution": "equidistant", + "CPULimit": "1vCPU", + "ExperimentDuration": 1, + "WarmupDuration": 0, + + "IsPartiallyPanic": false, + "EnableZipkinTracing": false, + "EnableMetricsScrapping": false, + "MetricScrapingPeriodSeconds": 15, + "AutoscalingMetric": "concurrency", + + "GRPCConnectionTimeoutSeconds": 5, + "GRPCFunctionTimeoutSeconds": 900 +} \ No newline at end of file diff --git a/cmd/config_dirigent.json b/cmd/config_dirigent_trace.json similarity index 67% rename from cmd/config_dirigent.json rename to cmd/config_dirigent_trace.json index 9e692299..7f62ccdf 100644 --- a/cmd/config_dirigent.json +++ b/cmd/config_dirigent_trace.json @@ -2,14 +2,18 @@ "Seed": 42, "Platform": "Dirigent", + "InvokeProtocol" : "http2", "EndpointPort": 80, - "TracePath": "data/traces/example", + "DirigentControlPlaneIP": "10.0.1.253:9092", + "BusyLoopOnSandboxStartup": false, + + "TracePath": "data/traces/azure_500", "Granularity": "minute", "OutputPathPrefix": "data/out/experiment", - "IATDistribution": "equidistant", + "IATDistribution": "exponential", "CPULimit": "1vCPU", - "ExperimentDuration": 5, + "ExperimentDuration": 30, "WarmupDuration": 0, "IsPartiallyPanic": false, @@ -17,8 +21,7 @@ "EnableMetricsScrapping": false, "MetricScrapingPeriodSeconds": 15, "AutoscalingMetric": "concurrency", - "GRPCConnectionTimeoutSeconds": 15, "GRPCFunctionTimeoutSeconds": 900, "DAGMode": false -} +} \ No newline at end of file diff --git a/cmd/config_knative_rps.json b/cmd/config_knative_rps.json new file mode 100644 index 00000000..3a72fd7d --- /dev/null +++ b/cmd/config_knative_rps.json @@ -0,0 +1,35 @@ +{ + "Seed": 42, + + "Platform": "Knative-RPS", + "InvokeProtocol" : "grpc", + "YAMLSelector": "container", + "EndpointPort": 80, + + "BusyLoopOnSandboxStartup": false, + + "RpsTarget": 1, + "RpsColdStartRatioPercentage": 100, + "RpsCooldownSeconds": 10, + "RpsImage": "ghcr.io/vhive-serverless/invitro_empty_function:latest", + "RpsRuntimeMs": 10, + "RpsMemoryMB": 2048, + "RpsIterationMultiplier": 80, + + "TracePath": "data/traces/example", + "Granularity": "minute", + "OutputPathPrefix": "data/out/experiment", + "IATDistribution": "equidistant", + "CPULimit": "1vCPU", + "ExperimentDuration": 2, + "WarmupDuration": 0, + + "IsPartiallyPanic": false, + "EnableZipkinTracing": false, + "EnableMetricsScrapping": false, + "MetricScrapingPeriodSeconds": 15, + "AutoscalingMetric": "concurrency", + + "GRPCConnectionTimeoutSeconds": 15, + "GRPCFunctionTimeoutSeconds": 900 +} \ No newline at end of file diff --git a/cmd/config.json b/cmd/config_knative_trace.json similarity index 73% rename from cmd/config.json rename to cmd/config_knative_trace.json index 3fbfa0f8..5c2fe34f 100644 --- a/cmd/config.json +++ b/cmd/config_knative_trace.json @@ -2,15 +2,18 @@ "Seed": 42, "Platform": "Knative", + "InvokeProtocol" : "grpc", "YAMLSelector": "container", "EndpointPort": 80, - "TracePath": "data/traces/example", + "BusyLoopOnSandboxStartup": false, + + "TracePath": "data/traces/azure_500", "Granularity": "minute", "OutputPathPrefix": "data/out/experiment", - "IATDistribution": "equidistant", + "IATDistribution": "exponential", "CPULimit": "1vCPU", - "ExperimentDuration": 5, + "ExperimentDuration": 30, "WarmupDuration": 0, "IsPartiallyPanic": false, @@ -22,4 +25,4 @@ "GRPCConnectionTimeoutSeconds": 15, "GRPCFunctionTimeoutSeconds": 900, "DAGMode": false -} \ No newline at end of file +} diff --git a/cmd/loader.go b/cmd/loader.go index 3c062762..f72886e5 100644 --- a/cmd/loader.go +++ b/cmd/loader.go @@ -1,43 +1,21 @@ -/* - * MIT License - * - * Copyright (c) 2023 EASL and the vHive community - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - package main import ( + "encoding/json" "flag" "fmt" - "golang.org/x/exp/slices" - "os" - "time" - "github.com/vhive-serverless/loader/pkg/common" "github.com/vhive-serverless/loader/pkg/config" "github.com/vhive-serverless/loader/pkg/driver" + "github.com/vhive-serverless/loader/pkg/generator" "github.com/vhive-serverless/loader/pkg/trace" + "golang.org/x/exp/slices" + "os" + "strconv" + "strings" + "time" log "github.com/sirupsen/logrus" - tracer "github.com/vhive-serverless/vSwarm/utils/tracing/go" ) @@ -49,7 +27,7 @@ var ( configPath = flag.String("config", "config.json", "Path to loader configuration file") verbosity = flag.String("verbosity", "info", "Logging verbosity - choose from [info, debug, trace]") iatGeneration = flag.Bool("iatGeneration", false, "Generate iats only or run invocations as well") - generated = flag.Bool("generated", false, "True if iats were already generated") + iatFromFile = flag.Bool("generated", false, "True if iats were already generated") ) func init() { @@ -70,38 +48,52 @@ func init() { log.SetLevel(log.InfoLevel) } } - func main() { cfg := config.ReadConfigurationFile(*configPath) - if cfg.EnableZipkinTracing { // TODO: how not to exclude Zipkin spans here? - file a feature request log.Warnf("Zipkin tracing has been enabled. This will exclude Istio spans from the Zipkin traces.") - shutdown, err := tracer.InitBasicTracer(zipkinAddr, "loader") if err != nil { log.Print(err) } - defer shutdown() } - if cfg.ExperimentDuration < 1 { log.Fatal("Runtime duration should be longer, at least a minute.") } + if *iatGeneration { + durationToParse := determineDurationToParse(cfg.ExperimentDuration, cfg.WarmupDuration) + iatDistribution, shiftIAT := parseIATDistribution(&cfg) + traceParser := trace.NewAzureParser(cfg.TracePath, durationToParse) + functions := traceParser.Parse(cfg.Platform) + + justGenerateIAT(cfg.Seed, iatDistribution, shiftIAT, parseTraceGranularity(&cfg), functions) + } + supportedPlatforms := []string{ "Knative", + "Knative-RPS", "OpenWhisk", + "OpenWhisk-RPS", "AWSLambda", + "AWSLambda-RPS", "Dirigent", + "Dirigent-RPS", + "Dirigent-Dandelion-RPS", + "Dirigent-Dandelion", } if !slices.Contains(supportedPlatforms, cfg.Platform) { - log.Fatal("Unsupported platform! Supported platforms are [Knative, OpenWhisk, AWSLambda, Dirigent]") + log.Fatal("Unsupported platform!") } - runTraceMode(&cfg, *iatGeneration, *generated) + if !strings.HasSuffix(cfg.Platform, "-RPS") { + runTraceMode(&cfg, *iatFromFile) + } else { + runRPSMode(&cfg) + } } func determineDurationToParse(runtimeDuration int, warmupDuration int) int { @@ -117,74 +109,105 @@ func determineDurationToParse(runtimeDuration int, warmupDuration int) int { return result } -func runTraceMode(cfg *config.LoaderConfiguration, iatOnly bool, generated bool) { - durationToParse := determineDurationToParse(cfg.ExperimentDuration, cfg.WarmupDuration) - - traceParser := trace.NewAzureParser(cfg.TracePath, durationToParse) - functions := traceParser.Parse(cfg.Platform) - - log.Infof("Traces contain the following %d functions:\n", len(functions)) - for _, function := range functions { - fmt.Printf("\t%s\n", function.Name) - } - - var iatType common.IatDistribution - shiftIAT := false +func parseIATDistribution(cfg *config.LoaderConfiguration) (common.IatDistribution, bool) { switch cfg.IATDistribution { case "exponential": - iatType = common.Exponential + return common.Exponential, false case "exponential_shift": - iatType = common.Exponential - shiftIAT = true + return common.Exponential, true case "uniform": - iatType = common.Uniform + return common.Uniform, false case "uniform_shift": - iatType = common.Uniform - shiftIAT = true + return common.Uniform, true case "equidistant": - iatType = common.Equidistant + return common.Equidistant, false default: log.Fatal("Unsupported IAT distribution.") } - var yamlSpecificationPath string + return common.Exponential, false +} + +func parseYAMLSpecification(cfg *config.LoaderConfiguration) string { switch cfg.YAMLSelector { - case "wimpy": - yamlSpecificationPath = "workloads/container/wimpy.yaml" case "container": - yamlSpecificationPath = "workloads/container/trace_func_go.yaml" + return "workloads/container/trace_func_go.yaml" case "firecracker": - yamlSpecificationPath = "workloads/firecracker/trace_func_go.yaml" + return "workloads/firecracker/trace_func_go.yaml" default: - if cfg.Platform != "Dirigent" { + if cfg.Platform != "Dirigent" && cfg.Platform != "Dirigent-RPS" && cfg.Platform != "Dirigent-Dandelion-RPS" && cfg.Platform != "Dirigent-Dandelion" { log.Fatal("Invalid 'YAMLSelector' parameter.") } } - var traceGranularity common.TraceGranularity + return "" +} + +func parseTraceGranularity(cfg *config.LoaderConfiguration) common.TraceGranularity { switch cfg.Granularity { case "minute": - traceGranularity = common.MinuteGranularity + return common.MinuteGranularity case "second": - traceGranularity = common.SecondGranularity + return common.SecondGranularity default: log.Fatal("Invalid trace granularity parameter.") } - log.Infof("Using %s as a service YAML specification file.\n", yamlSpecificationPath) + return common.MinuteGranularity +} + +func runTraceMode(cfg *config.LoaderConfiguration, readIATFromFile bool) { + durationToParse := determineDurationToParse(cfg.ExperimentDuration, cfg.WarmupDuration) + yamlPath := parseYAMLSpecification(cfg) + + traceParser := trace.NewAzureParser(cfg.TracePath, durationToParse) + functions := traceParser.Parse(cfg.Platform) - experimentDriver := driver.NewDriver(&driver.DriverConfiguration{ + log.Infof("Traces contain the following %d functions:\n", len(functions)) + for _, function := range functions { + fmt.Printf("\t%s\n", function.Name) + } + + iatType, shiftIAT := parseIATDistribution(cfg) + + experimentDriver := driver.NewDriver(&config.Configuration{ LoaderConfiguration: cfg, IATDistribution: iatType, ShiftIAT: shiftIAT, - TraceGranularity: traceGranularity, + TraceGranularity: parseTraceGranularity(cfg), TraceDuration: durationToParse, - YAMLPath: yamlSpecificationPath, + YAMLPath: yamlPath, TestMode: false, Functions: functions, }) - experimentDriver.RunExperiment(iatOnly, generated) + log.Infof("Using %s as a service YAML specification file.\n", experimentDriver.Configuration.YAMLPath) + + experimentDriver.RunExperiment(false, readIATFromFile) +} + +func justGenerateIAT(seed int64, iatDistribution common.IatDistribution, shiftIAT bool, traceGranularity common.TraceGranularity, functions []*common.Function) { + specificationGenerator := generator.NewSpecificationGenerator(seed) + + for i, function := range functions { + spec := specificationGenerator.GenerateInvocationData( + function, + iatDistribution, + shiftIAT, + traceGranularity, + ) + functions[i].Specification = spec + + file, _ := json.MarshalIndent(spec, "", " ") + err := os.WriteFile("iat"+strconv.Itoa(i)+".json", file, 0644) + if err != nil { + log.Fatalf("Writing the loader config file failed: %s", err) + } + } +} + +func runRPSMode(cfg *config.LoaderConfiguration) { + panic("Not yet implemented") } diff --git a/docs/configuration.md b/docs/configuration.md index adb76bc2..5f3069c9 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -3,14 +3,24 @@ | Parameter name | Data type | Possible values | Default value | Description | |------------------------------|-----------|---------------------------------------------------------------------|---------------------|--------------------------------------------------------------------------------------| | Seed | int64 | any | 42 | Seed for specification generator (for reproducibility) | -| Platform | string | Knative, OpenWhisk, AWSLambda | Knative | The serverless platform the functions will be executed on | +| Platform [^1] | string | Knative, OpenWhisk, AWSLambda, Dirigent, Dirigent-Dandelion | Knative | The serverless platform the functions will be executed on | +| InvokeProtocol | string | grpc, http1, http2 | N/A | Protocol to use to communicate with the sandbox | | YAMLSelector | string | wimpy, container, firecracker | container | Service YAML depending on sandbox type | | EndpointPort | int | > 0 | 80 | Port to be appended to the service URL | +| DirigentControlPlaneIP | string | N/A | N/A | IP address of the Dirigent control plane (for function deployment) | +| BusyLoopOnSandboxStartup | bool | true/false | false | Enable artificial delay on sandbox startup | +| RpsTarget | int | >= 0 | 0 | Number of requests per second to issue | +| RpsColdStartRatioPercentage | int | >= 0 && <= 100 | 0 | Percentage of cold starts out of specified RPS | +| RpsCooldownSeconds | int | > 0 | 0 | The time it takes for the autoscaler to downscale function (higher for higher RPS) | +| RpsImage | string | N/A | N/A | Function image to use for RPS experiments | +| RpsRuntimeMs | int | >=0 | 0 | Requested execution time | +| RpsMemoryMB | int | >=0 | 0 | Requested memory | +| RpsIterationMultiplier | int | >=0 | 0 | Iteration multiplier for RPS mode | | TracePath | string | string | data/traces | Folder with Azure trace dimensions (invocations.csv, durations.csv, memory.csv) | -| Granularity | string | minute, second | minute | Granularity for trace interpretation[^1] | +| Granularity | string | minute, second | minute | Granularity for trace interpretation[^2] | | OutputPathPrefix | string | any | data/out/experiment | Results file(s) output path prefix | -| IATDistribution | string | exponential, exponential_shift, uniform, uniform_shift, equidistant | exponential | IAT distribution[^2] | -| CPULimit | string | 1vCPU, GCP | 1vCPU | Imposed CPU limits on worker containers (only applicable for 'Knative' platform)[^3] | +| IATDistribution | string | exponential, exponential_shift, uniform, uniform_shift, equidistant | exponential | IAT distribution[^3] | +| CPULimit | string | 1vCPU, GCP | 1vCPU | Imposed CPU limits on worker containers (only applicable for 'Knative' platform)[^4] | | ExperimentDuration | int | > 0 | 1 | Experiment duration in minutes of trace to execute excluding warmup | | WarmupDuration | int | > 0 | 0 | Warmup duration in minutes(disabled if zero) | | IsPartiallyPanic | bool | true/false | false | Pseudo-panic-mode only in Knative | @@ -18,15 +28,17 @@ | EnableMetricsScrapping | bool | true/false | false | Scrap cluster-wide metrics | | MetricScrapingPeriodSeconds | int | > 0 | 15 | Period of Prometheus metrics scrapping | | GRPCConnectionTimeoutSeconds | int | > 0 | 60 | Timeout for establishing a gRPC connection | -| GRPCFunctionTimeoutSeconds | int | > 0 | 90 | Maximum time given to function to execute[^4] | -| DAGMode | bool | true/false | false | Sequential invocation of all functions one after another | -[^1]: The second granularity feature interprets each column of the trace as a second, rather than as a minute, and +| GRPCFunctionTimeoutSeconds | int | > 0 | 90 | Maximum time given to function to execute[^5] | +| DAGMode | bool | true/false | false | Sequential invocation of all functions one after another | +[^1]: To run RPS experiments add suffix `-RPS`. + +[^2]: The second granularity feature interprets each column of the trace as a second, rather than as a minute, and generates IAT for each second. This feature is useful for fine-grained and precise invocation scheduling in experiments involving stable low load. -[^2]: `_shift` modifies the IAT generation in the following way: by default, generation will create first invocation in the beginning of the minute, with `_shift` modifier, it will be shifted inside the minute to remove the burst of invocations from all the functions. +[^3]: `_shift` modifies the IAT generation in the following way: by default, generation will create first invocation in the beginning of the minute, with `_shift` modifier, it will be shifted inside the minute to remove the burst of invocations from all the functions. -[^3]: Limits are set by resource->limits->CPU in the service YAML. `1vCPU` means limit of 1CPU is set, at the same time execution is also limited by the container concurrency limit of 1. `GCP` means limits are set to multiples of 1/12th of vCPU, based on the memory consumption of the function according to this [table](https://cloud.google.com/functions/pricing#compute_time) for Google Cloud Functions. +[^4]: Limits are set by resource->limits->CPU in the service YAML. `1vCPU` means limit of 1CPU is set, at the same time execution is also limited by the container concurrency limit of 1. `GCP` means limits are set to multiples of 1/12th of vCPU, based on the memory consumption of the function according to this [table](https://cloud.google.com/functions/pricing#compute_time) for Google Cloud Functions. -[^4]: Function can execute for at most 15 minutes as in AWS +[^5]: Function can execute for at most 15 minutes as in AWS Lambda; https://aws.amazon.com/about-aws/whats-new/2018/10/aws-lambda-supports-functions-that-can-run-up-to-15-minutes/ diff --git a/go.mod b/go.mod index 28eb87fe..daea4980 100644 --- a/go.mod +++ b/go.mod @@ -1,28 +1,27 @@ module github.com/vhive-serverless/loader -go 1.21 +go 1.22 require ( github.com/gocarina/gocsv v0.0.0-20211203214250-4735fba0c1d9 github.com/golang/protobuf v1.5.4 github.com/sfreiberg/simplessh v0.0.0-20220719182921-185eafd40485 - github.com/sirupsen/logrus v1.9.0 + github.com/sirupsen/logrus v1.9.3 golang.org/x/sys v0.24.0 gonum.org/v1/gonum v0.15.0 gonum.org/v1/plot v0.14.0 - google.golang.org/grpc v1.63.2 + google.golang.org/grpc v1.65.0 ) require ( github.com/aws/aws-lambda-go v1.47.0 github.com/stretchr/testify v1.9.0 - github.com/vhive-serverless/vSwarm/utils/tracing/go v0.0.0-20230926064847-68cc9b8b8e84 + go.mongodb.org/mongo-driver v1.16.1 golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa gopkg.in/yaml.v3 v3.0.1 ) require ( - cloud.google.com/go/compute/metadata v0.2.3 // indirect git.sr.ht/~sbinet/gg v0.5.0 // indirect github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b // indirect github.com/campoy/embedmd v1.0.0 // indirect @@ -30,27 +29,30 @@ require ( github.com/davidmz/go-pageant v1.0.2 // indirect github.com/go-fonts/liberation v0.3.2 // indirect github.com/go-latex/latex v0.0.0-20231108140139-5c1ce85aa4ea // indirect - github.com/go-logr/logr v1.2.3 // indirect + github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-pdf/fpdf v0.9.0 // indirect github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect + github.com/google/uuid v1.6.0 // indirect github.com/kr/fs v0.1.0 // indirect github.com/pkg/sftp v1.13.4 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - go.opentelemetry.io/otel/exporters/zipkin v1.8.0 // indirect - golang.org/x/crypto v0.25.0 // indirect + github.com/vhive-serverless/vSwarm/utils/tracing/go v0.0.0-20240827121957-11be651eb39a // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 // indirect + go.opentelemetry.io/otel/exporters/zipkin v1.28.0 // indirect + go.opentelemetry.io/otel/metric v1.29.0 // indirect + golang.org/x/crypto v0.26.0 // indirect golang.org/x/image v0.14.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240822170219-fc7c04adadcd // indirect ) require ( github.com/containerd/containerd v1.6.13 // indirect - github.com/openzipkin/zipkin-go v0.4.0 // indirect - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.33.0 - go.opentelemetry.io/otel v1.11.1 // indirect - go.opentelemetry.io/otel/sdk v1.8.0 // indirect - go.opentelemetry.io/otel/trace v1.11.1 // indirect - golang.org/x/net v0.27.0 - golang.org/x/text v0.16.0 // indirect - google.golang.org/protobuf v1.33.0 // indirect + github.com/openzipkin/zipkin-go v0.4.3 // indirect + go.opentelemetry.io/otel v1.29.0 // indirect + go.opentelemetry.io/otel/sdk v1.28.0 // indirect + go.opentelemetry.io/otel/trace v1.29.0 // indirect + golang.org/x/net v0.28.0 + golang.org/x/text v0.17.0 // indirect + google.golang.org/protobuf v1.34.2 // indirect ) diff --git a/go.sum b/go.sum index a8c70020..38afde72 100644 --- a/go.sum +++ b/go.sum @@ -1,10 +1,5 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.99.0 h1:y/cM2iqGgGi5D5DQZl6D9STN/3dR/Vx5Mp8s752oJTY= -cloud.google.com/go/compute v1.24.0 h1:phWcR2eWzRJaL/kOiJwfFsPs4BaKq1j6vnpZrc1YlVg= -cloud.google.com/go/compute v1.24.0/go.mod h1:kw1/T+h/+tK2LJK0wiPPx1intgdAM3j/g3hFDlscY40= -cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= -cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= git.sr.ht/~sbinet/cmpimg v0.1.0 h1:E0zPRk2muWuCqSKSVZIWsgtU9pjsw3eKHi8VmQeScxo= git.sr.ht/~sbinet/cmpimg v0.1.0/go.mod h1:FU12psLbF4TfNXkKH2ZZQ29crIqoiqTZmeQ7dkp/pxE= git.sr.ht/~sbinet/gg v0.5.0 h1:6V43j30HM623V329xA9Ntq+WJrMjDxRjuAB1LFWF5m8= @@ -27,8 +22,6 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa h1:jQCWAUqqlij9Pgj2i/PB79y4KOPYVyFYdROxgaCwdTQ= -github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa/go.mod h1:x/1Gn8zydmfq8dk6e9PdstVsDgu9RuyIIJqAaF//0IM= github.com/containerd/containerd v1.6.13 h1:7llWEzjLH/fao0f2lppn1L6NhjsvxqMdUQa2mgVCs+U= github.com/containerd/containerd v1.6.13/go.mod h1:vDm+BbU+dD9uvuUlHr+KmcY0HKX8WDyI6dzJjNi4ee8= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= @@ -47,8 +40,6 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/envoyproxy/protoc-gen-validate v1.0.4 h1:gVPz/FMfvh57HdSJQyvBtF00j8JU4zdyUgIUNhlgg0A= -github.com/envoyproxy/protoc-gen-validate v1.0.4/go.mod h1:qys6tmnRsYrQqIhm2bvKZH4Blx/1gTIZ2UKVY1M+Yew= github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= @@ -63,8 +54,8 @@ github.com/go-fonts/liberation v0.3.2/go.mod h1:N0QsDLVUQPy3UYg9XAc3Uh3UDMp2Z7M1 github.com/go-latex/latex v0.0.0-20231108140139-5c1ce85aa4ea h1:DfZQkvEbdmOe+JK2TMtBM+0I9GSdzE2y/L1/AmD8xKc= github.com/go-latex/latex v0.0.0-20231108140139-5c1ce85aa4ea/go.mod h1:Y7Vld91/HRbTBm7JwoI7HejdDB0u+e9AUBO9MB7yuZk= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= -github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-pdf/fpdf v0.9.0 h1:PPvSaUuo1iMi9KkaAn90NuKi+P4gwMedWPHhj8YlJQw= @@ -102,6 +93,8 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= @@ -135,6 +128,8 @@ github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1y github.com/onsi/gomega v1.16.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= github.com/openzipkin/zipkin-go v0.4.0 h1:CtfRrOVZtbDj8rt1WXjklw0kqqJQwICrCKmlfUuBUUw= github.com/openzipkin/zipkin-go v0.4.0/go.mod h1:4c3sLeE8xjNqehmF5RpAFLPLJxXscc0R4l6Zg0P1tTQ= +github.com/openzipkin/zipkin-go v0.4.3 h1:9EGwpqkgnwdEIJ+Od7QVSEIH+ocmm5nPat0G7sjsSdg= +github.com/openzipkin/zipkin-go v0.4.3/go.mod h1:M9wCJZFWCo2RiY+o1eBCEMe0Dp2S5LDHcMZmk3RmK7c= github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -153,6 +148,8 @@ github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeV github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= @@ -164,20 +161,32 @@ github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8 github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= github.com/vhive-serverless/vSwarm/utils/tracing/go v0.0.0-20230926064847-68cc9b8b8e84 h1:1X25KcPzwMt4WVtPKrQ+LkoDiKjgAjfyWECdRovj5oU= github.com/vhive-serverless/vSwarm/utils/tracing/go v0.0.0-20230926064847-68cc9b8b8e84/go.mod h1:rShQ4wy7Rpv9/9GolKSeNbCZ2dtmLmo5k/YNO/n3m0o= +github.com/vhive-serverless/vSwarm/utils/tracing/go v0.0.0-20240827121957-11be651eb39a h1:Wq/7eNz96WxQWPMEnhg3ai5sZQufCyplAUotEC+j5Kc= +github.com/vhive-serverless/vSwarm/utils/tracing/go v0.0.0-20240827121957-11be651eb39a/go.mod h1:7PjQe6bDZ5W5cWHTpNeKRobMy9NK0odj6ROXrfa/CLQ= github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs= github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.33.0 h1:z6rnla1Asjzn0FrhohzIbDi4bxbtc6EMmQ7f5ZPn+pA= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.33.0/go.mod h1:y/SlJpJQPd2UzfBCj0E9Flk9FDCtTyqUmaCB41qFrWI= -go.opentelemetry.io/otel v1.11.1 h1:4WLLAmcfkmDk2ukNXJyq3/kiz/3UzCaYq6PskJsaou4= -go.opentelemetry.io/otel v1.11.1/go.mod h1:1nNhXBbWSD0nsL38H6btgnFN2k4i0sNLHNNMZMSbUGE= +go.mongodb.org/mongo-driver v1.16.1 h1:rIVLL3q0IHM39dvE+z2ulZLp9ENZKThVfuvN/IiN4l8= +go.mongodb.org/mongo-driver v1.16.1/go.mod h1:oB6AhJQvFQL4LEHyXi6aJzQJtBiTQHiAd83l0GdFaiw= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 h1:9G6E0TXzGFVfTnawRzrPl83iHOAV7L8NJiR8RSGYV1g= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0/go.mod h1:azvtTADFQJA8mX80jIH/akaE7h+dbm/sVuaHqN13w74= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0 h1:r6I7RJCN86bpD/FQwedZ0vSixDpwuWREjW9oRMsmqDc= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0/go.mod h1:B9yO6b04uB80CzjedvewuqDhxJxi11s7/GtiGa8bAjI= +go.opentelemetry.io/otel v1.29.0 h1:PdomN/Al4q/lN6iBJEN3AwPvUiHPMlt93c8bqTG5Llw= +go.opentelemetry.io/otel v1.29.0/go.mod h1:N/WtXPs1CNCUEx+Agz5uouwCba+i+bJGFicT8SR4NP8= go.opentelemetry.io/otel/exporters/zipkin v1.8.0 h1:PIAiDdROZzATAFfxr5ASYuSOG0JIJxRq3GwlpJGbSYQ= go.opentelemetry.io/otel/exporters/zipkin v1.8.0/go.mod h1:0uYAyCuGT67MFV9Z/Mmx93wGuugHw0FbxMc74fs3LNo= +go.opentelemetry.io/otel/exporters/zipkin v1.28.0 h1:q86SrM4sgdc1eDABeA+307DUWy1qaT3fDCVbeKYGfY4= +go.opentelemetry.io/otel/exporters/zipkin v1.28.0/go.mod h1:mkxt8tmE/1YujUHsMIgTPvBN2HVE3kXlRZWeKsTsFgI= +go.opentelemetry.io/otel/metric v1.29.0 h1:vPf/HFWTNkPu1aYeIsc98l4ktOQaL6LeSoeV2g+8YLc= +go.opentelemetry.io/otel/metric v1.29.0/go.mod h1:auu/QWieFVWx+DmQOUMgj0F8LHWdgalxXqvp7BII/W8= go.opentelemetry.io/otel/sdk v1.8.0 h1:xwu69/fNuwbSHWe/0PGS888RmjWY181OmcXDQKu7ZQk= go.opentelemetry.io/otel/sdk v1.8.0/go.mod h1:uPSfc+yfDH2StDM/Rm35WE8gXSNdvCg023J6HeGNO0c= -go.opentelemetry.io/otel/trace v1.11.1 h1:ofxdnzsNrGBYXbP7t7zpUK281+go5rF7dvdIZXF8gdQ= -go.opentelemetry.io/otel/trace v1.11.1/go.mod h1:f/Q9G7vzk5u91PhbmKbg1Qn0rzH1LJ4vbPHFGkTPtOk= +go.opentelemetry.io/otel/sdk v1.28.0 h1:b9d7hIry8yZsgtbmM0DKyPWMMUMlK9NEKuIG4aBqWyE= +go.opentelemetry.io/otel/sdk v1.28.0/go.mod h1:oYj7ClPUA7Iw3m+r7GeEjz0qckQRJK2B8zjcZEfu7Pg= +go.opentelemetry.io/otel/trace v1.29.0 h1:J/8ZNK4XgR7a21DZUAsbF8pZ5Jcw1VhACmnYt39JTi4= +go.opentelemetry.io/otel/trace v1.29.0/go.mod h1:eHl3w0sp3paPkYstJOmAimxhiFXPg+MMTlEh3nsQgWQ= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -186,8 +195,8 @@ golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/crypto v0.0.0-20210920023735-84f357641f63/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= -golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= +golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= +golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa h1:FRnLl4eNAQl8hwxVVC17teOw8kdjVDVAiFMtgUdTSRQ= golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE= @@ -212,12 +221,10 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210917221730-978cfadd31cf/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys= -golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= +golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= +golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.17.0 h1:6m3ZPmLEFdVxKKWnKq4VqZ60gutO35zm+zrAHVmHyDQ= -golang.org/x/oauth2 v0.17.0/go.mod h1:OzPDGQiuQMguemayvdylqddI7qcD9lnSDb+1FiwQ5HA= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -243,15 +250,15 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk= -golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4= +golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU= +golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= -golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= +golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= +golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -270,14 +277,12 @@ gonum.org/v1/plot v0.14.0 h1:+LBDVFYwFe4LHhdP8coW6296MBEY4nQ+Y4vuUpJopcE= gonum.org/v1/plot v0.14.0/go.mod h1:MLdR9424SJed+5VqC6MsouEpig9pZX2VZ57H9ko2bXU= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= -google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de h1:cZGRis4/ot9uVm639a+rHCUaG0JJHEsdyzSQTMX+suY= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:H4O17MA/PE9BsGx3w+a+W2VOLLD1Qf7oJneAoU6WktY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240822170219-fc7c04adadcd h1:6TEm2ZxXoQmFWFlt1vNxvVOa1Q0dXFQD1m/rYjXmS0E= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240822170219-fc7c04adadcd/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= @@ -285,8 +290,8 @@ google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8 google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k= -google.golang.org/grpc v1.63.2 h1:MUeiw1B2maTVZthpU5xvASfTh3LDbxHd6IJ6QQVU+xM= -google.golang.org/grpc v1.63.2/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA= +google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc= +google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -299,8 +304,9 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= -google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= diff --git a/pkg/common/trace_types.go b/pkg/common/trace_types.go index 05bf3b06..75e0be60 100644 --- a/pkg/common/trace_types.go +++ b/pkg/common/trace_types.go @@ -78,6 +78,7 @@ type DirigentMetadata struct { ScalingUpperBound int `csv:"ScalingUpperBound"` ScalingLowerBound int `csv:"ScalingLowerBound"` IterationMultiplier int `csv:"IterationMultiplier"` + IOPercentage int `csv:"IOPercentage"` } type Function struct { @@ -92,6 +93,8 @@ type Function struct { MemoryStats *FunctionMemoryStats DirigentMetadata *DirigentMetadata + ColdStartBusyLoopMs int + CPURequestsMilli int MemoryRequestsMiB int CPULimitsMilli int diff --git a/pkg/config/configuration.go b/pkg/config/configuration.go new file mode 100644 index 00000000..960eabd2 --- /dev/null +++ b/pkg/config/configuration.go @@ -0,0 +1,26 @@ +package config + +import ( + "github.com/vhive-serverless/loader/pkg/common" +) + +type Configuration struct { + LoaderConfiguration *LoaderConfiguration + IATDistribution common.IatDistribution + ShiftIAT bool // shift the invocations inside minute + TraceGranularity common.TraceGranularity + TraceDuration int // in minutes + + YAMLPath string + TestMode bool + + Functions []*common.Function +} + +func (c *Configuration) WithWarmup() bool { + if c.LoaderConfiguration.WarmupDuration > 0 { + return true + } else { + return false + } +} diff --git a/pkg/config/parser.go b/pkg/config/parser.go index ee78140e..7216be84 100644 --- a/pkg/config/parser.go +++ b/pkg/config/parser.go @@ -34,10 +34,29 @@ import ( type LoaderConfiguration struct { Seed int64 `json:"Seed"` - Platform string `json:"Platform"` + Platform string `json:"Platform"` + InvokeProtocol string `json:"InvokeProtocol"` + YAMLSelector string `json:"YAMLSelector"` + EndpointPort int `json:"EndpointPort"` - YAMLSelector string `json:"YAMLSelector"` - EndpointPort int `json:"EndpointPort"` + DirigentControlPlaneIP string `json:"DirigentControlPlaneIP"` + BusyLoopOnSandboxStartup bool `json:"BusyLoopOnSandboxStartup"` + + AsyncMode bool `json:"AsyncMode"` + AsyncResponseURL string `json:"AsyncResponseURL"` + AsyncWaitToCollectMin int `json:"AsyncWaitToCollectMin"` + + FailAt int `json:"FailAt"` + FailComponent string `json:"FailComponent"` + FailNode string `json:"FailNode"` + + RpsTarget float64 `json:"RpsTarget"` + RpsColdStartRatioPercentage float64 `json:"RpsColdStartRatioPercentage"` + RpsCooldownSeconds int `json:"RpsCooldownSeconds"` + RpsImage string `json:"RpsImage"` + RpsRuntimeMs int `json:"RpsRuntimeMs"` + RpsMemoryMB int `json:"RpsMemoryMB"` + RpsIterationMultiplier int `json:"RpsIterationMultiplier"` TracePath string `json:"TracePath"` Granularity string `json:"Granularity"` diff --git a/pkg/driver/clients/aws_client.go b/pkg/driver/clients/aws_client.go new file mode 100644 index 00000000..d347a1d2 --- /dev/null +++ b/pkg/driver/clients/aws_client.go @@ -0,0 +1,58 @@ +package clients + +import ( + "encoding/json" + "fmt" + log "github.com/sirupsen/logrus" + "github.com/vhive-serverless/loader/pkg/common" + mc "github.com/vhive-serverless/loader/pkg/metric" + "io" + "sync" +) + +type awsLambdaInvoker struct { + announceDoneExe *sync.WaitGroup +} + +func newAWSLambdaInvoker(announceDoneExe *sync.WaitGroup) *awsLambdaInvoker { + return &awsLambdaInvoker{ + announceDoneExe: announceDoneExe, + } +} + +func (i *awsLambdaInvoker) Invoke(function *common.Function, runtimeSpec *common.RuntimeSpecification) (bool, *mc.ExecutionRecord) { + log.Tracef("(Invoke)\t %s: %d[ms], %d[MiB]", function.Name, runtimeSpec.Runtime, runtimeSpec.Memory) + + dataString := fmt.Sprintf(`{"RuntimeInMilliSec": %d, "MemoryInMebiBytes": %d}`, runtimeSpec.Runtime, runtimeSpec.Memory) + success, executionRecordBase, res := httpInvocation(dataString, function, i.announceDoneExe, false) + + executionRecordBase.RequestedDuration = uint32(runtimeSpec.Runtime * 1e3) + record := &mc.ExecutionRecord{ExecutionRecordBase: *executionRecordBase} + + if !success { + return false, record + } + + // Read the response body + responseBody, err := io.ReadAll(res.Body) + if err != nil { + log.Debugf("Error reading response body:%s", err) + return false, record + } + + // Create a variable to store the JSON data + var httpResBody HTTPResBody + + // Unmarshal the response body into the JSON object + if err := json.Unmarshal(responseBody, &httpResBody); err != nil { + log.Debugf("Error unmarshaling JSON:%s", err) + return false, record + } + + record.ActualDuration = httpResBody.DurationInMicroSec + record.ActualMemoryUsage = common.Kib2Mib(httpResBody.MemoryUsageInKb) + + logInvocationSummary(function, &record.ExecutionRecordBase, res) + + return true, record +} diff --git a/pkg/driver/clients/dandelion_interface.go b/pkg/driver/clients/dandelion_interface.go new file mode 100644 index 00000000..2a24275f --- /dev/null +++ b/pkg/driver/clients/dandelion_interface.go @@ -0,0 +1,108 @@ +package clients + +import ( + "bytes" + "fmt" + "github.com/sirupsen/logrus" + "github.com/vhive-serverless/loader/pkg/common" + "github.com/vhive-serverless/loader/pkg/metric" + "go.mongodb.org/mongo-driver/bson" + "strings" +) + +type InputItem struct { + Identifier string `bson:"identifier"` + Key int64 `bson:"key"` + Data []byte `bson:"data"` +} + +type InputSet struct { + Identifier string `bson:"identifier"` + Items []InputItem `bson:"items"` +} + +type DandelionRequest struct { + Name string `bson:"name"` + Sets []InputSet `bson:"sets"` +} + +type DandelionDeserializeResponse struct { + Sets []InputSet `bson:"sets"` +} + +/*func composeDandelionMatMulBody(functionName string) *bytes.Buffer { + request := DandelionRequest{ + Name: functionName, + Sets: []InputSet{ + { + Identifier: "", + Items: []InputItem{ + { + Identifier: "", + Key: 0, + Data: []byte{1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0}, + }, + }, + }, + }, + } + body, err := bson.Marshal(request) + if err != nil { + logrus.Debugf("Error encoding Dandelion MatMul request - %v", err) + return nil + } + return bytes.NewBuffer(body) +}*/ + +func composeBusyLoopBody(functionName, image string, runtime, iterations int) *bytes.Buffer { + request := DandelionRequest{ + Name: functionName, + Sets: []InputSet{ + { + Identifier: "", + Items: []InputItem{ + { + Identifier: "input.csv", + Key: 0, + Data: []byte(fmt.Sprintf( + "%s,%s,%d,%d", + functionName, + image, + // TODO: bug in the current image '\0'. Remove '* 10' when new image is applied + runtime*10, + iterations, + )), + }, + }, + }, + }, + } + + body, err := bson.Marshal(request) + if err != nil { + logrus.Debugf("Error encoding Dandelion MatMul request - %v", err) + return nil + } + + return bytes.NewBuffer(body) +} + +func DeserializeDandelionResponse(function *common.Function, body []byte, record *metric.ExecutionRecord) error { + var result DandelionDeserializeResponse + err := bson.Unmarshal(body, &result) + if err != nil { + return fmt.Errorf("error deserializing response body - %v", err) + } + + rawResponseData := result.Sets[0].Items[0].Data + data := strings.Split(string(rawResponseData), ",") + + if len(data) > 0 && !strings.Contains(strings.ToLower(data[0]), "ok") { + record.FunctionTimeout = false + } + + record.Instance = function.Name + record.ActualDuration = 0 // this field is not used yet in benchmark + + return nil +} diff --git a/pkg/driver/grpc_client.go b/pkg/driver/clients/grpc_client.go similarity index 87% rename from pkg/driver/grpc_client.go rename to pkg/driver/clients/grpc_client.go index a4f51ba0..dbd82fb0 100644 --- a/pkg/driver/grpc_client.go +++ b/pkg/driver/clients/grpc_client.go @@ -22,7 +22,7 @@ * SOFTWARE. */ -package driver +package clients import ( "context" @@ -37,12 +37,20 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" - "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc" - mc "github.com/vhive-serverless/loader/pkg/metric" ) -func InvokeGRPC(function *common.Function, runtimeSpec *common.RuntimeSpecification, cfg *config.LoaderConfiguration) (bool, *mc.ExecutionRecord) { +type grpcInvoker struct { + cfg *config.LoaderConfiguration +} + +func newGRPCInvoker(cfg *config.LoaderConfiguration) *grpcInvoker { + return &grpcInvoker{ + cfg: cfg, + } +} + +func (i *grpcInvoker) Invoke(function *common.Function, runtimeSpec *common.RuntimeSpecification) (bool, *mc.ExecutionRecord) { log.Tracef("(Invoke)\t %s: %d[ms], %d[MiB]", function.Name, runtimeSpec.Runtime, runtimeSpec.Memory) record := &mc.ExecutionRecord{ @@ -57,16 +65,12 @@ func InvokeGRPC(function *common.Function, runtimeSpec *common.RuntimeSpecificat start := time.Now() record.StartTime = start.UnixMicro() - dialContext, cancelDialing := context.WithTimeout(context.Background(), time.Duration(cfg.GRPCConnectionTimeoutSeconds)*time.Second) + dialContext, cancelDialing := context.WithTimeout(context.Background(), time.Duration(i.cfg.GRPCConnectionTimeoutSeconds)*time.Second) defer cancelDialing() var dialOptions []grpc.DialOption dialOptions = append(dialOptions, grpc.WithTransportCredentials(insecure.NewCredentials())) dialOptions = append(dialOptions, grpc.WithBlock()) - if cfg.EnableZipkinTracing { - // NOTE: if enabled it will exclude Istio span from the Zipkin trace - dialOptions = append(dialOptions, grpc.WithUnaryInterceptor(otelgrpc.UnaryClientInterceptor())) - } grpcStart := time.Now() @@ -85,7 +89,7 @@ func InvokeGRPC(function *common.Function, runtimeSpec *common.RuntimeSpecificat grpcClient := proto.NewExecutorClient(conn) - executionCxt, cancelExecution := context.WithTimeout(context.Background(), time.Duration(cfg.GRPCFunctionTimeoutSeconds)*time.Second) + executionCxt, cancelExecution := context.WithTimeout(context.Background(), time.Duration(i.cfg.GRPCFunctionTimeoutSeconds)*time.Second) defer cancelExecution() response, err := grpcClient.Execute(executionCxt, &proto.FaasRequest{ diff --git a/pkg/driver/grpc_client_test.go b/pkg/driver/clients/grpc_client_test.go similarity index 88% rename from pkg/driver/grpc_client_test.go rename to pkg/driver/clients/grpc_client_test.go index 28912fc2..c755e1ff 100644 --- a/pkg/driver/grpc_client_test.go +++ b/pkg/driver/clients/grpc_client_test.go @@ -22,23 +22,24 @@ * SOFTWARE. */ -package driver +package clients import ( "fmt" + "github.com/vhive-serverless/loader/pkg/config" "os" "testing" "time" "github.com/sirupsen/logrus" "github.com/vhive-serverless/loader/pkg/common" - "github.com/vhive-serverless/loader/pkg/config" "github.com/vhive-serverless/loader/pkg/workload/standard" ) func createFakeLoaderConfiguration() *config.LoaderConfiguration { return &config.LoaderConfiguration{ Platform: "Knative", + InvokeProtocol: "grpc", OutputPathPrefix: "test", EnableZipkinTracing: true, GRPCConnectionTimeoutSeconds: 5, @@ -59,7 +60,8 @@ func TestGRPCClientWithServerUnreachable(t *testing.T) { cfg := createFakeLoaderConfiguration() cfg.EnableZipkinTracing = true - success, record := InvokeGRPC(&testFunction, &testRuntimeSpecs, cfg) + invoker := CreateInvoker(cfg, nil, nil) + success, record := invoker.Invoke(&testFunction, &testRuntimeSpecs) if record.Instance != "" || record.RequestedDuration != uint32(testRuntimeSpecs.Runtime*1000) || @@ -73,7 +75,7 @@ func TestGRPCClientWithServerUnreachable(t *testing.T) { } func TestGRPCClientWithServerReachable(t *testing.T) { - address, port := "localhost", 8080 + address, port := "localhost", 18080 testFunction.Endpoint = fmt.Sprintf("%s:%d", address, port) go standard.StartGRPCServer(address, port, standard.TraceFunction, "") @@ -82,9 +84,10 @@ func TestGRPCClientWithServerReachable(t *testing.T) { time.Sleep(2 * time.Second) cfg := createFakeLoaderConfiguration() + invoker := CreateInvoker(cfg, nil, nil) start := time.Now() - success, record := InvokeGRPC(&testFunction, &testRuntimeSpecs, cfg) + success, record := invoker.Invoke(&testFunction, &testRuntimeSpecs) logrus.Info("Elapsed: ", time.Since(start).Milliseconds(), " ms") if !success || @@ -106,7 +109,7 @@ func TestGRPCClientWithServerBatchWorkload(t *testing.T) { t.Error(err) } - address, port := "localhost", 8081 + address, port := "localhost", 18081 testFunction.Endpoint = fmt.Sprintf("%s:%d", address, port) go standard.StartGRPCServer(address, port, standard.TraceFunction, "") @@ -115,9 +118,10 @@ func TestGRPCClientWithServerBatchWorkload(t *testing.T) { time.Sleep(2 * time.Second) cfg := createFakeLoaderConfiguration() + invoker := CreateInvoker(cfg, nil, nil) for i := 0; i < 50; i++ { - success, record := InvokeGRPC(&testFunction, &testRuntimeSpecs, cfg) + success, record := invoker.Invoke(&testFunction, &testRuntimeSpecs) if !success || record.MemoryAllocationTimeout != false || diff --git a/pkg/driver/clients/http_client.go b/pkg/driver/clients/http_client.go new file mode 100644 index 00000000..5d6cd051 --- /dev/null +++ b/pkg/driver/clients/http_client.go @@ -0,0 +1,168 @@ +package clients + +import ( + "bytes" + "encoding/json" + log "github.com/sirupsen/logrus" + "github.com/vhive-serverless/loader/pkg/common" + "github.com/vhive-serverless/loader/pkg/config" + mc "github.com/vhive-serverless/loader/pkg/metric" + "io" + "net/http" + "strconv" + "strings" + "time" +) + +type FunctionResponse struct { + Status string `json:"Status"` + Function string `json:"Function"` + MachineName string `json:"MachineName"` + ExecutionTime int64 `json:"ExecutionTime"` +} + +type httpInvoker struct { + client *http.Client + cfg *config.LoaderConfiguration +} + +func newHTTPInvoker(cfg *config.LoaderConfiguration) *httpInvoker { + return &httpInvoker{ + client: CreateHTTPClient(cfg.GRPCFunctionTimeoutSeconds, cfg.InvokeProtocol), + cfg: cfg, + } +} + +func (i *httpInvoker) Invoke(function *common.Function, runtimeSpec *common.RuntimeSpecification) (bool, *mc.ExecutionRecord) { + isDandelion := strings.Contains(strings.ToLower(i.cfg.Platform), "dandelion") + isKnative := strings.Contains(strings.ToLower(i.cfg.Platform), "knative") + + log.Tracef("(Invoke)\t %s: %d[ms], %d[MiB]", function.Name, runtimeSpec.Runtime, runtimeSpec.Memory) + + record := &mc.ExecutionRecord{ + ExecutionRecordBase: mc.ExecutionRecordBase{ + RequestedDuration: uint32(runtimeSpec.Runtime * 1e3), + }, + } + + //////////////////////////////////// + // INVOKE FUNCTION + //////////////////////////////////// + start := time.Now() + record.StartTime = start.UnixMicro() + + requestBody := &bytes.Buffer{} + /*if body := composeDandelionMatMulBody(function.Name); isDandelion && body != nil { + requestBody = body + }*/ + if body := composeBusyLoopBody(function.Name, function.DirigentMetadata.Image, runtimeSpec.Runtime, function.DirigentMetadata.IterationMultiplier); isDandelion && body != nil { + requestBody = body + } + + req, err := http.NewRequest("GET", "http://"+function.Endpoint, requestBody) + if err != nil { + log.Errorf("Failed to create a HTTP request - %v\n", err) + + record.ResponseTime = time.Since(start).Microseconds() + record.ConnectionTimeout = true + + return false, record + } + + // add system specific stuff + if !isKnative { + req.Host = function.Name + } + + req.Header.Set("workload", function.DirigentMetadata.Image) + req.Header.Set("function", function.Name) + req.Header.Set("requested_cpu", strconv.Itoa(runtimeSpec.Runtime)) + req.Header.Set("requested_memory", strconv.Itoa(runtimeSpec.Memory)) + req.Header.Set("multiplier", strconv.Itoa(function.DirigentMetadata.IterationMultiplier)) + req.Header.Set("io_percentage", strconv.Itoa(function.DirigentMetadata.IOPercentage)) + + if isDandelion { + req.URL.Path = "/hot/matmul" + } + + resp, err := i.client.Do(req) + if err != nil { + log.Errorf("%s - Failed to send an HTTP request to the server - %v\n", function.Name, err) + + record.ResponseTime = time.Since(start).Microseconds() + record.ConnectionTimeout = true + + return false, record + } + + record.GRPCConnectionEstablishTime = time.Since(start).Microseconds() + + defer HandleBodyClosing(resp) + body, err := io.ReadAll(resp.Body) + + if err != nil || resp.StatusCode != http.StatusOK || len(body) == 0 { + if err != nil { + log.Errorf("HTTP request failed - %s - %v", function.Name, err) + } else if len(body) == 0 { + log.Errorf("HTTP request failed - %s - %s - empty response (status code: %d)", function.Name, function.Endpoint, resp.StatusCode) + } else if resp.StatusCode != http.StatusOK { + log.Errorf("HTTP request failed - %s - %s - non-empty response: %v - status code: %d", function.Name, function.Endpoint, string(body), resp.StatusCode) + } + + record.ResponseTime = time.Since(start).Microseconds() + record.FunctionTimeout = true + + return false, record + } + + if isDandelion { + err = DeserializeDandelionResponse(function, body, record) + if err != nil { + log.Warnf("Failed to deserialize Dandelion response - %v - %v", string(body), err) + } + } else if i.cfg.AsyncMode { + record.AsyncResponseID = string(body) + } else { + err = DeserializeDirigentResponse(body, record) + if err != nil { + log.Warnf("Failed to deserialize Dirigent response - %v - %v", string(body), err) + } + } + + record.ResponseTime = time.Since(start).Microseconds() + + if strings.HasPrefix(string(body), "FAILURE - mem_alloc") { + record.MemoryAllocationTimeout = true + } else { + record.ActualMemoryUsage = 0 + } + + log.Tracef("(Replied)\t %s: %s, %.2f[ms], %d[MiB]", function.Name, string(body), float64(0)/1e3, common.Kib2Mib(0)) + log.Tracef("(E2E Latency) %s: %.2f[ms]\n", function.Name, float64(record.ResponseTime)/1e3) + + return true, record +} + +func DeserializeDirigentResponse(body []byte, record *mc.ExecutionRecord) error { + var deserializedResponse FunctionResponse + err := json.Unmarshal(body, &deserializedResponse) + if err != nil { + return err + } + + record.Instance = deserializedResponse.Function + record.ActualDuration = uint32(deserializedResponse.ExecutionTime) + + return nil +} + +func HandleBodyClosing(response *http.Response) { + if response == nil || response.Body == nil { + return + } + + err := response.Body.Close() + if err != nil { + log.Errorf("Error closing response body - %v", err) + } +} diff --git a/pkg/driver/clients/http_client_factory.go b/pkg/driver/clients/http_client_factory.go new file mode 100644 index 00000000..8b81d5ce --- /dev/null +++ b/pkg/driver/clients/http_client_factory.go @@ -0,0 +1,50 @@ +package clients + +import ( + "context" + "crypto/tls" + "github.com/sirupsen/logrus" + "golang.org/x/net/http2" + "net" + "net/http" + "time" +) + +func CreateHTTPClient(timeout int, invokeProtocol string) *http.Client { + client := &http.Client{ + Timeout: time.Duration(timeout) * time.Second, + } + + switch invokeProtocol { + case "http1": + client.Transport = getHttp1Transport(timeout) + case "http2": + client.Transport = getHttp2Transport() + case "grpc": + default: + logrus.Errorf("Invalid invoke protocol in the configuration file.") + } + + return client +} + +func getHttp1Transport(timeout int) *http.Transport { + return &http.Transport{ + DialContext: (&net.Dialer{ + Timeout: time.Duration(timeout) * time.Second, + }).DialContext, + IdleConnTimeout: 5 * time.Second, + MaxIdleConns: 100, + MaxIdleConnsPerHost: 10, + MaxConnsPerHost: 10, + } +} + +func getHttp2Transport() *http2.Transport { + return &http2.Transport{ + AllowHTTP: true, + DialTLSContext: func(ctx context.Context, network, addr string, cfg *tls.Config) (net.Conn, error) { + return net.Dial(network, addr) + }, + } +} diff --git a/pkg/driver/clients/invoker.go b/pkg/driver/clients/invoker.go new file mode 100644 index 00000000..e6c21587 --- /dev/null +++ b/pkg/driver/clients/invoker.go @@ -0,0 +1,40 @@ +package clients + +import ( + "github.com/sirupsen/logrus" + "github.com/vhive-serverless/loader/pkg/common" + "github.com/vhive-serverless/loader/pkg/config" + "github.com/vhive-serverless/loader/pkg/metric" + "sync" +) + +type Invoker interface { + Invoke(*common.Function, *common.RuntimeSpecification) (bool, *metric.ExecutionRecord) +} + +func CreateInvoker(cfg *config.LoaderConfiguration, announceDoneExe *sync.WaitGroup, readOpenWhiskMetadata *sync.Mutex) Invoker { + switch cfg.Platform { + case "AWSLambda", "AWSLambda-RPS": + return newAWSLambdaInvoker(announceDoneExe) + case "Dirigent", "Dirigent-RPS": + if cfg.InvokeProtocol == "grpc" { + return newGRPCInvoker(cfg) + } else { + return newHTTPInvoker(cfg) + } + case "Dirigent-Dandelion", "Dirigent-Dandelion-RPS": + return newHTTPInvoker(cfg) + case "Knative", "Knative-RPS": + if cfg.InvokeProtocol == "grpc" { + return newGRPCInvoker(cfg) + } else { + return newHTTPInvoker(cfg) + } + case "OpenWhisk", "OpenWhisk-RPS": + return newOpenWhiskInvoker(announceDoneExe, readOpenWhiskMetadata) + default: + logrus.Fatal("Unsupported platform.") + } + + return nil +} diff --git a/pkg/driver/clients/openwhisk_client.go b/pkg/driver/clients/openwhisk_client.go new file mode 100644 index 00000000..f29bb48a --- /dev/null +++ b/pkg/driver/clients/openwhisk_client.go @@ -0,0 +1,181 @@ +package clients + +import ( + "bytes" + "crypto/tls" + "encoding/base64" + "encoding/json" + "fmt" + "io" + "net/http" + "sync" + "time" + + log "github.com/sirupsen/logrus" + "github.com/vhive-serverless/loader/pkg/common" + mc "github.com/vhive-serverless/loader/pkg/metric" +) + +type ActivationMetadata struct { + Duration uint32 //ms + StartType mc.StartType + WaitTime int64 //ms + InitTime int64 //ms +} +type HTTPResBody struct { + DurationInMicroSec uint32 `json:"DurationInMicroSec"` + MemoryUsageInKb uint32 `json:"MemoryUsageInKb"` +} + +type openWhiskInvoker struct { + announceDoneExe *sync.WaitGroup + readOpenWhiskMetadata *sync.Mutex +} + +func newOpenWhiskInvoker(announceDoneExe *sync.WaitGroup, readOpenWhiskMetadata *sync.Mutex) *openWhiskInvoker { + return &openWhiskInvoker{ + announceDoneExe: announceDoneExe, + readOpenWhiskMetadata: readOpenWhiskMetadata, + } +} + +func (i *openWhiskInvoker) Invoke(function *common.Function, runtimeSpec *common.RuntimeSpecification) (bool, *mc.ExecutionRecord) { + log.Tracef("(Invoke)\t %s: %d[ms], %d[MiB]", function.Name, runtimeSpec.Runtime, runtimeSpec.Memory) + + qs := fmt.Sprintf("cpu=%d", runtimeSpec.Runtime) + + success, executionRecordBase, res := httpInvocation(qs, function, i.announceDoneExe, true) + //announceDoneExe.Wait() // To postpone querying OpenWhisk during the experiment for performance reasons (Issue 329: https://github.com/vhive-serverless/invitro/issues/329) + + executionRecordBase.RequestedDuration = uint32(runtimeSpec.Runtime * 1e3) + record := &mc.ExecutionRecord{ExecutionRecordBase: *executionRecordBase} + if !success { + return false, record + } + + /*activationID := res.Header.Get("X-Openwhisk-Activation-Id") + readOpenWhiskMetadata.Lock() + //read data from OpenWhisk based on the activation ID + cmd := exec.Command("wsk", "-i", "activation", "get", activationID) + var out bytes.Buffer + cmd.Stdout = &out + err := cmd.Run() + if err != nil { + log.Debugf("error reading activation information from OpenWhisk %s - %s", function.Name, err) + readOpenWhiskMetadata.Unlock() + return false, record + } + readOpenWhiskMetadata.Unlock() + err, activationMetadata := parseActivationMetadata(out.String()) + if err != nil { + log.Debugf("error parsing activation metadata %s - %s", function.Name, err) + return false, record + }*/ + + //record.ActualDuration = activationMetadata.Duration * 1000 //ms to micro sec + /*record.StartType = activationMetadata.StartType + record.InitTime = activationMetadata.InitTime * 1000 //ms to micro sec + record.WaitTime = activationMetadata.WaitTime * 1000 //ms to micro sec*/ + logInvocationSummary(function, &record.ExecutionRecordBase, res) + return true, record +} + +/*func parseActivationMetadata(response string) (error, ActivationMetadata) { + var result ActivationMetadata + var jsonMap map[string]interface{} + @@ -128,46 +141,11 @@ func parseActivationMetadata(response string) (error, ActivationMetadata) { + } + return nil, result +}*/ + +func httpInvocation(dataString string, function *common.Function, AnnounceDoneExe *sync.WaitGroup, tlsSkipVerify bool) (bool, *mc.ExecutionRecordBase, *http.Response) { + defer AnnounceDoneExe.Done() + + record := &mc.ExecutionRecordBase{} + + start := time.Now() + record.StartTime = start.UnixMicro() + record.Instance = function.Name + requestURL := function.Endpoint + if tlsSkipVerify { + http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{InsecureSkipVerify: true} + } + + if dataString != "" { + requestURL += "?" + dataString + } + req, err := http.NewRequest(http.MethodGet, requestURL, bytes.NewBuffer([]byte(""))) + if err != nil { + log.Warnf("http request creation failed for function %s - %s", function.Name, err) + + record.ResponseTime = time.Since(start).Microseconds() + record.ConnectionTimeout = true + + return false, record, nil + } + + req.Header.Set("Content-Type", "application/json") // To avoid data being base64encoded + + resp, err := http.DefaultClient.Do(req) + if err != nil { + log.Debugf("http request for function %s failed - %s", function.Name, err) + + record.ResponseTime = time.Since(start).Microseconds() + record.ConnectionTimeout = true + + return false, record, resp + } + defer resp.Body.Close() + + if resp.StatusCode < 200 || resp.StatusCode >= 300 { + log.Debugf("http request for function %s failed - error code: %s", function.Name, resp.Status) + + record.ResponseTime = time.Since(start).Microseconds() + record.ConnectionTimeout = true + + return false, record, resp + } + + bodyBytes, err := io.ReadAll(resp.Body) + if err != nil { + log.Warnf("Failed to read output %s - %v", function.Name, err) + + record.ResponseTime = time.Since(start).Microseconds() + record.FunctionTimeout = true + + return false, record, resp + } + + rawJson, err := base64.StdEncoding.DecodeString(string(bodyBytes)) + if err != nil { + log.Warnf("Failed to decode base64 output %s - %v", function.Name, err) + + record.ResponseTime = time.Since(start).Microseconds() + record.FunctionTimeout = true + + return false, record, resp + } + + var deserializedResponse FunctionResponse + err = json.Unmarshal(rawJson, &deserializedResponse) + if err != nil { + log.Warnf("Failed to deserialize response %s - %v", function.Name, err) + + record.ResponseTime = time.Since(start).Microseconds() + record.FunctionTimeout = true + + return false, record, resp + } + + record.Instance = deserializedResponse.Function + record.ResponseTime = time.Since(start).Microseconds() + record.ActualDuration = uint32(deserializedResponse.ExecutionTime) + + return true, record, resp +} + +func logInvocationSummary(function *common.Function, record *mc.ExecutionRecordBase, res *http.Response) { + log.Tracef("(Replied)\t %s: %d[ms]", function.Name, record.ActualDuration) + log.Tracef("(E2E Latency) %s: %.2f[ms]\n", function.Name, float64(record.ResponseTime)/1e3) + log.Tracef("(Client status code) %s: %d", function.Name, res.StatusCode) +} diff --git a/pkg/driver/deploy.sh b/pkg/driver/deploy.sh deleted file mode 100755 index 902fcaba..00000000 --- a/pkg/driver/deploy.sh +++ /dev/null @@ -1,41 +0,0 @@ -#!/usr/bin/env bash - -# -# MIT License -# -# Copyright (c) 2023 EASL and the vHive community -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# - -CONFIG_FILE=$1 -export FUNC_NAME=$2 - -export CPU_REQUEST=$3 -export CPU_LIMITS=$4 -export MEMORY_REQUESTS=$5 -INIT_SCALE=$6 - -export PANIC_WINDOW=$7 -export PANIC_THRESHOLD=$8 - -export AUTOSCALING_METRIC=$9 -export AUTOSCALING_TARGET=${10} - -cat $CONFIG_FILE | envsubst | kn service apply $FUNC_NAME --scale-init $INIT_SCALE --concurrency-target 1 --wait-timeout 2000000 -f /dev/stdin \ No newline at end of file diff --git a/pkg/driver/deployment_awslambda.go b/pkg/driver/deployment/aws_lambda.go similarity index 95% rename from pkg/driver/deployment_awslambda.go rename to pkg/driver/deployment/aws_lambda.go index 040e96f3..14eedc5d 100644 --- a/pkg/driver/deployment_awslambda.go +++ b/pkg/driver/deployment/aws_lambda.go @@ -1,17 +1,35 @@ -package driver +package deployment import ( "fmt" log "github.com/sirupsen/logrus" "github.com/vhive-serverless/loader/pkg/common" + "github.com/vhive-serverless/loader/pkg/config" "os/exec" "strings" "sync" "sync/atomic" ) -// DeployFunctionsAWSLambda deploys functions to AWS Lambda using the Serverless.com framework, with additional dependencies on AWS CLI, Docker -func DeployFunctionsAWSLambda(functions []*common.Function) { +type awsLambdaDeployer struct { + functions []*common.Function +} + +func newAWSLambdaDeployer() *awsLambdaDeployer { + return &awsLambdaDeployer{} +} + +func (ld *awsLambdaDeployer) Deploy(cfg *config.Configuration) { + ld.functions = cfg.Functions + + internalAWSDeployment(cfg.Functions) +} + +func (ld *awsLambdaDeployer) Clean() { + CleanAWSLambda(ld.functions) +} + +func internalAWSDeployment(functions []*common.Function) { const provider = "aws" // Check if all required dependencies are installed, verify that AWS account is clean and ready for deployment diff --git a/pkg/driver/serverless_config.go b/pkg/driver/deployment/aws_serverless_config.go similarity index 81% rename from pkg/driver/serverless_config.go rename to pkg/driver/deployment/aws_serverless_config.go index ce736565..205f9830 100644 --- a/pkg/driver/serverless_config.go +++ b/pkg/driver/deployment/aws_serverless_config.go @@ -1,28 +1,4 @@ -/* - * MIT License - * - * Copyright (c) 2023 EASL and the vHive community - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package driver +package deployment import ( "fmt" diff --git a/pkg/driver/deployment/deployer.go b/pkg/driver/deployment/deployer.go new file mode 100644 index 00000000..f82d952d --- /dev/null +++ b/pkg/driver/deployment/deployer.go @@ -0,0 +1,28 @@ +package deployment + +import ( + "github.com/sirupsen/logrus" + "github.com/vhive-serverless/loader/pkg/config" +) + +type FunctionDeployer interface { + Deploy(cfg *config.Configuration) + Clean() +} + +func CreateDeployer(cfg *config.Configuration) FunctionDeployer { + switch cfg.LoaderConfiguration.Platform { + case "AWSLambda", "AWSLambda-RPS": + return newAWSLambdaDeployer() + case "Dirigent", "Dirigent-RPS", "Dirigent-Dandelion", "Dirigent-Dandelion-RPS": + return newDirigentDeployer() + case "Knative", "Knative-RPS": + return newKnativeDeployer() + case "OpenWhisk", "OpenWhisk-RPS": + return newOpenWhiskDeployer() + default: + logrus.Fatal("Unsupported platform.") + } + + return nil +} diff --git a/pkg/driver/deployment/dirigent.go b/pkg/driver/deployment/dirigent.go new file mode 100644 index 00000000..3f128334 --- /dev/null +++ b/pkg/driver/deployment/dirigent.go @@ -0,0 +1,99 @@ +package deployment + +import ( + "fmt" + log "github.com/sirupsen/logrus" + "github.com/vhive-serverless/loader/pkg/common" + "github.com/vhive-serverless/loader/pkg/config" + "io" + "math/rand" + "net" + "net/http" + "net/url" + "strconv" + "strings" + "time" +) + +type dirigentDeployer struct{} + +type dirigentDeploymentConfiguration struct { + RegistrationServer string +} + +func newDirigentDeployer() *dirigentDeployer { + return &dirigentDeployer{} +} + +func newDirigentDeployerConfiguration(cfg *config.Configuration) dirigentDeploymentConfiguration { + return dirigentDeploymentConfiguration{ + RegistrationServer: cfg.LoaderConfiguration.DirigentControlPlaneIP, + } +} + +func (*dirigentDeployer) Deploy(cfg *config.Configuration) { + dirigentConfig := newDirigentDeployerConfiguration(cfg) + + for i := 0; i < len(cfg.Functions); i++ { + deployDirigent(cfg.Functions[i], dirigentConfig.RegistrationServer, cfg.LoaderConfiguration.BusyLoopOnSandboxStartup) + } +} + +func (*dirigentDeployer) Clean() {} + +var registrationClient = &http.Client{ + Timeout: 5 * time.Second, // time for a request to timeout + Transport: &http.Transport{ + DialContext: (&net.Dialer{ + Timeout: 1500 * time.Millisecond, // time to open socket + }).DialContext, + IdleConnTimeout: 2 * time.Second, // unused connections from pool expire after + MaxIdleConns: 2, + MaxIdleConnsPerHost: 2, + }, +} + +func deployDirigent(function *common.Function, controlPlaneAddress string, busyLoopOnColdStart bool) { + metadata := function.DirigentMetadata + + if metadata == nil { + log.Fatalf("No Dirigent metadata for function %s", function.Name) + } + + payload := url.Values{ + "name": {function.Name}, + "image": {metadata.Image}, + "port_forwarding": {strconv.Itoa(metadata.Port), metadata.Protocol}, + "scaling_upper_bound": {strconv.Itoa(metadata.ScalingUpperBound)}, + "scaling_lower_bound": {strconv.Itoa(metadata.ScalingLowerBound)}, + "requested_cpu": {strconv.Itoa(function.CPURequestsMilli)}, + "requested_memory": {strconv.Itoa(function.MemoryRequestsMiB)}, + } + + if busyLoopOnColdStart { + payload["iteration_multiplier"] = []string{strconv.Itoa(function.DirigentMetadata.IterationMultiplier)} + payload["cold_start_busy_loop_ms"] = []string{strconv.Itoa(function.ColdStartBusyLoopMs)} + } + + log.Debug(payload) + + resp, err := registrationClient.PostForm(fmt.Sprintf("http://%s/registerService", controlPlaneAddress), payload) + if err != nil { + log.Error("Failed to register a service with the control plane - ", err.Error()) + return + } + defer resp.Body.Close() + + body, err := io.ReadAll(resp.Body) + if err != nil { + log.Error("Failed to read response body.") + return + } + + endpoints := strings.Split(string(body), ";") + if len(endpoints) == 0 { + log.Error("Function registration returned no data plane(s).") + return + } + function.Endpoint = endpoints[rand.Intn(len(endpoints))] +} diff --git a/pkg/driver/deployment/knative.go b/pkg/driver/deployment/knative.go new file mode 100644 index 00000000..723de24d --- /dev/null +++ b/pkg/driver/deployment/knative.go @@ -0,0 +1,127 @@ +package deployment + +import ( + "bytes" + "fmt" + log "github.com/sirupsen/logrus" + "github.com/vhive-serverless/loader/pkg/common" + "github.com/vhive-serverless/loader/pkg/config" + "math" + "os/exec" + "regexp" + "strconv" +) + +const ( + bareMetalLbGateway = "10.200.3.4.sslip.io" // Address of the bare-metal load balancer. + namespace = "default" +) + +var ( + urlRegex = regexp.MustCompile("at URL:\nhttp://([^\n]+)") +) + +type knativeDeployer struct{} + +type knativeDeploymentConfiguration struct { + YamlPath string + IsPartiallyPanic bool + EndpointPort int + AutoscalingMetric string +} + +func newKnativeDeployer() *knativeDeployer { + return &knativeDeployer{} +} + +func newKnativeDeployerConfiguration(cfg *config.Configuration) knativeDeploymentConfiguration { + return knativeDeploymentConfiguration{ + YamlPath: cfg.YAMLPath, + IsPartiallyPanic: cfg.LoaderConfiguration.IsPartiallyPanic, + EndpointPort: cfg.LoaderConfiguration.EndpointPort, + AutoscalingMetric: cfg.LoaderConfiguration.AutoscalingMetric, + } +} + +func (*knativeDeployer) Deploy(cfg *config.Configuration) { + knativeConfig := newKnativeDeployerConfiguration(cfg) + + for i := 0; i < len(cfg.Functions); i++ { + knativeDeploySingleFunction( + cfg.Functions[i], + knativeConfig.YamlPath, + knativeConfig.IsPartiallyPanic, + knativeConfig.EndpointPort, + knativeConfig.AutoscalingMetric, + ) + } +} + +func (*knativeDeployer) Clean() { + cmd := exec.Command("kn", "service", "delete", "--all") + + var out bytes.Buffer + cmd.Stdout = &out + + if err := cmd.Run(); err != nil { + log.Errorf("Unable to delete Knative services - %s", err) + } +} + +func knativeDeploySingleFunction(function *common.Function, yamlPath string, isPartiallyPanic bool, endpointPort int, + autoscalingMetric string) bool { + panicWindow := "\"10.0\"" + panicThreshold := "\"200.0\"" + if isPartiallyPanic { + panicWindow = "\"100.0\"" + panicThreshold = "\"1000.0\"" + } + autoscalingTarget := 100 // default for concurrency + if autoscalingMetric == "rps" { + autoscalingTarget = int(math.Round(1000.0 / function.RuntimeStats.Average)) + // for rps mode use the average runtime in milliseconds to determine how many requests a pod can process per + // second, then round to an integer as that is what the knative config expects + } + + cmd := exec.Command( + "bash", + "./pkg/driver/deployment/knative.sh", + yamlPath, + function.Name, + + strconv.Itoa(function.CPURequestsMilli)+"m", + strconv.Itoa(function.CPULimitsMilli)+"m", + strconv.Itoa(function.MemoryRequestsMiB)+"Mi", + strconv.Itoa(function.InitialScale), + panicWindow, + panicThreshold, + + wrapString(autoscalingMetric), + wrapString(strconv.Itoa(autoscalingTarget)), + + wrapString(strconv.Itoa(function.ColdStartBusyLoopMs)), + ) + + stdoutStderr, err := cmd.CombinedOutput() + log.Debug("CMD response: ", string(stdoutStderr)) + if err != nil { + // TODO: there should be a toggle to turn off deployment because if this is fatal then we cannot test the thing locally + log.Warnf("Failed to deploy function %s: %v\n%s\n", function.Name, err, stdoutStderr) + return false + } + if endpoint := urlRegex.FindStringSubmatch(string(stdoutStderr))[1]; endpoint != function.Endpoint { + // TODO: check when this situation happens + log.Debugf("Update function endpoint to %s\n", endpoint) + function.Endpoint = endpoint + } else { + function.Endpoint = fmt.Sprintf("%s.%s.%s", function.Name, namespace, bareMetalLbGateway) + } + // adding port to the endpoint + function.Endpoint = fmt.Sprintf("%s:%d", function.Endpoint, endpointPort) + log.Debugf("Deployed function on %s\n", function.Endpoint) + return true +} + +func wrapString(value string) string { + return "\"" + value + "\"" +} diff --git a/pkg/driver/deployment/knative.sh b/pkg/driver/deployment/knative.sh new file mode 100644 index 00000000..57e5047d --- /dev/null +++ b/pkg/driver/deployment/knative.sh @@ -0,0 +1,17 @@ +CONFIG_FILE=$1 +export FUNC_NAME=$2 + +export CPU_REQUEST=$3 +export CPU_LIMITS=$4 +export MEMORY_REQUESTS=$5 +INIT_SCALE=$6 + +export PANIC_WINDOW=$7 +export PANIC_THRESHOLD=$8 + +export AUTOSCALING_METRIC=$9 +export AUTOSCALING_TARGET=${10} + +export COLD_START_BUSY_LOOP_MS=${11} + +cat $CONFIG_FILE | envsubst | kn service apply $FUNC_NAME --scale-init $INIT_SCALE --concurrency-target 1 --wait-timeout 2000000 -f /dev/stdin \ No newline at end of file diff --git a/pkg/driver/deployment/openwhisk.go b/pkg/driver/deployment/openwhisk.go new file mode 100644 index 00000000..db3174f1 --- /dev/null +++ b/pkg/driver/deployment/openwhisk.go @@ -0,0 +1,64 @@ +package deployment + +import ( + "bytes" + "fmt" + "github.com/vhive-serverless/loader/pkg/config" + "os/exec" + "strings" + + log "github.com/sirupsen/logrus" + "github.com/vhive-serverless/loader/pkg/common" +) + +type openWhiskDeployer struct { + functions []*common.Function +} + +func newOpenWhiskDeployer() *openWhiskDeployer { + return &openWhiskDeployer{} +} + +func (owd *openWhiskDeployer) Deploy(cfg *config.Configuration) { + owd.functions = cfg.Functions + + cmd := exec.Command("wsk", "-i", "property", "get", "--apihost") + + var out bytes.Buffer + cmd.Stdout = &out + + err := cmd.Run() + if err != nil { + log.Fatalf("Unable to read OpenWhisk API host data - %s", err) + } + result := strings.Split(out.String(), "\t") + endpoint := strings.TrimSpace(result[len(result)-1]) + + const actionLocation = "./pkg/workload/openwhisk/workload_openwhisk.go" + + for i := 0; i < len(owd.functions); i++ { + cmd = exec.Command("wsk", "-i", "action", "create", owd.functions[i].Name, actionLocation, "--kind", "go:1.17", "--web", "true") + + err = cmd.Run() + if err != nil { + log.Fatalf("Unable to create OpenWhisk action for function %s - %s", owd.functions[i].Name, err) + } + + owd.functions[i].Endpoint = fmt.Sprintf("https://%s/api/v1/web/guest/default/%s", endpoint, owd.functions[i].Name) + } +} + +func (owd *openWhiskDeployer) Clean() { + for i := 0; i < len(owd.functions); i++ { + // TODO: check if there is a command such as "... delete --all" + cmd := exec.Command("wsk", "-i", "action", "delete", owd.functions[i].Name) + + var out bytes.Buffer + cmd.Stdout = &out + + err := cmd.Run() + if err != nil { + log.Debugf("Unable to delete OpenWhisk action for function %s - %s", owd.functions[i].Name, err) + } + } +} diff --git a/pkg/driver/trace_driver.go b/pkg/driver/trace_driver.go index c9e61b03..6afd4e99 100644 --- a/pkg/driver/trace_driver.go +++ b/pkg/driver/trace_driver.go @@ -29,6 +29,9 @@ import ( "encoding/csv" "encoding/json" "fmt" + "github.com/vhive-serverless/loader/pkg/config" + "github.com/vhive-serverless/loader/pkg/driver/clients" + "github.com/vhive-serverless/loader/pkg/driver/deployment" "math" "os" "strconv" @@ -39,43 +42,32 @@ import ( "github.com/gocarina/gocsv" log "github.com/sirupsen/logrus" "github.com/vhive-serverless/loader/pkg/common" - "github.com/vhive-serverless/loader/pkg/config" "github.com/vhive-serverless/loader/pkg/generator" mc "github.com/vhive-serverless/loader/pkg/metric" "github.com/vhive-serverless/loader/pkg/trace" ) -type DriverConfiguration struct { - LoaderConfiguration *config.LoaderConfiguration - IATDistribution common.IatDistribution - ShiftIAT bool // shift the invocations inside minute - TraceGranularity common.TraceGranularity - TraceDuration int // in minutes - - YAMLPath string - TestMode bool - - Functions []*common.Function -} - type Driver struct { - Configuration *DriverConfiguration + Configuration *config.Configuration SpecificationGenerator *generator.SpecificationGenerator + Invoker clients.Invoker + + readOpenWhiskMetadata sync.Mutex + allFunctionsInvoked sync.WaitGroup } -func NewDriver(driverConfig *DriverConfiguration) *Driver { - return &Driver{ +func NewDriver(driverConfig *config.Configuration) *Driver { + d := &Driver{ Configuration: driverConfig, SpecificationGenerator: generator.NewSpecificationGenerator(driverConfig.LoaderConfiguration.Seed), - } -} -func (c *DriverConfiguration) WithWarmup() bool { - if c.LoaderConfiguration.WarmupDuration > 0 { - return true - } else { - return false + readOpenWhiskMetadata: sync.Mutex{}, + allFunctionsInvoked: sync.WaitGroup{}, } + + d.Invoker = clients.CreateInvoker(driverConfig.LoaderConfiguration, &d.allFunctionsInvoked, &d.readOpenWhiskMetadata) + + return d } // /////////////////////////////////////// @@ -217,35 +209,9 @@ func (d *Driver) invokeFunction(metadata *InvocationMetadata) { for node != nil { function := node.Value.(*common.Function) runtimeSpecifications = &function.Specification.RuntimeSpecification[metadata.MinuteIndex][metadata.InvocationIndex] - switch d.Configuration.LoaderConfiguration.Platform { - case "Knative": - success, record = InvokeGRPC( - function, - runtimeSpecifications, - d.Configuration.LoaderConfiguration, - ) - case "OpenWhisk": - success, record = InvokeOpenWhisk( - function, - runtimeSpecifications, - metadata.AnnounceDoneExe, - metadata.ReadOpenWhiskMetadata, - ) - case "AWSLambda": - success, record = InvokeAWSLambda( - function, - runtimeSpecifications, - metadata.AnnounceDoneExe, - ) - case "Dirigent": - success, record = InvokeDirigent( - function, - runtimeSpecifications, - d.Configuration.LoaderConfiguration, - ) - default: - log.Fatal("Unsupported platform.") - } + + success, record = d.Invoker.Invoke(function, runtimeSpecifications) + record.Phase = int(metadata.Phase) record.InvocationID = composeInvocationID(d.Configuration.TraceGranularity, metadata.MinuteIndex, metadata.InvocationIndex) metadata.RecordOutputChannel <- record @@ -680,32 +646,12 @@ func (d *Driver) RunExperiment(iatOnly bool, generated bool) { trace.ApplyResourceLimits(d.Configuration.Functions, d.Configuration.LoaderConfiguration.CPULimit) - switch d.Configuration.LoaderConfiguration.Platform { - case "Knative": - DeployFunctions(d.Configuration.Functions, - d.Configuration.YAMLPath, - d.Configuration.LoaderConfiguration.IsPartiallyPanic, - d.Configuration.LoaderConfiguration.EndpointPort, - d.Configuration.LoaderConfiguration.AutoscalingMetric) - case "OpenWhisk": - DeployFunctionsOpenWhisk(d.Configuration.Functions) - case "AWSLambda": - DeployFunctionsAWSLambda(d.Configuration.Functions) - case "Dirigent": - DeployDirigent(d.Configuration.Functions) - default: - log.Fatal("Unsupported platform.") - } + deployer := deployment.CreateDeployer(d.Configuration) + deployer.Deploy(d.Configuration) // Generate load d.internalRun(iatOnly, generated) // Clean up - if d.Configuration.LoaderConfiguration.Platform == "Knative" { - CleanKnative() - } else if d.Configuration.LoaderConfiguration.Platform == "OpenWhisk" { - CleanOpenWhisk(d.Configuration.Functions) - } else if d.Configuration.LoaderConfiguration.Platform == "AWSLambda" { - CleanAWSLambda(d.Configuration.Functions) - } + deployer.Clean() } diff --git a/pkg/driver/trace_driver_test.go b/pkg/driver/trace_driver_test.go index ee8515bc..61d49808 100644 --- a/pkg/driver/trace_driver_test.go +++ b/pkg/driver/trace_driver_test.go @@ -27,6 +27,7 @@ package driver import ( "container/list" "fmt" + "github.com/vhive-serverless/loader/pkg/config" "log" "os" "sync" @@ -40,10 +41,21 @@ import ( "github.com/vhive-serverless/loader/pkg/workload/standard" ) +func createFakeLoaderConfiguration() *config.LoaderConfiguration { + return &config.LoaderConfiguration{ + Platform: "Knative", + InvokeProtocol: "grpc", + OutputPathPrefix: "test", + EnableZipkinTracing: true, + GRPCConnectionTimeoutSeconds: 5, + GRPCFunctionTimeoutSeconds: 15, + } +} + func createTestDriver() *Driver { cfg := createFakeLoaderConfiguration() - driver := NewDriver(&DriverConfiguration{ + driver := NewDriver(&config.Configuration{ LoaderConfiguration: cfg, IATDistribution: common.Equidistant, TraceDuration: 1, @@ -281,7 +293,7 @@ func TestGlobalMetricsCollector(t *testing.T) { var record []metric.ExecutionRecord err = gocsv.UnmarshalFile(f, &record) if err != nil { - log.Fatalf(err.Error()) + log.Fatal(err.Error()) } for i := 0; i < driver.Configuration.Functions[0].InvocationStats.Invocations[0]; i++ { @@ -372,7 +384,7 @@ func TestDriverCompletely(t *testing.T) { var records []metric.ExecutionRecordBase err = gocsv.UnmarshalFile(f, &records) if err != nil { - log.Fatalf(err.Error()) + log.Fatal(err.Error()) } successfulInvocation, failedInvocations := 0, 0 diff --git a/pkg/metric/record.go b/pkg/metric/record.go index 54266bd8..9b2621bd 100644 --- a/pkg/metric/record.go +++ b/pkg/metric/record.go @@ -76,38 +76,11 @@ type ExecutionRecord struct { ActualMemoryUsage uint32 `csv:"actualMemoryUsage"` MemoryAllocationTimeout bool `csv:"memoryAllocationTimeout"` - // TODO: EVERYTHING BELOW ARE UNTESTED FIELDS - - //* In KiB - /*Memory uint32 `csv:"memory"` - MemoryLoad float64 `csv:"mem_load"` - Interval int64 `csv:"interval"` - - //* Infra statistics are all in percentages. - MasterCpu float64 `csv:"master_cpu"` - MasterMem float64 `csv:"master_mem"` - WorkerCpuAvg float64 `csv:"worker_cpu_avg"` - WorkerCpuMax float64 `csv:"worker_cpu_max"` - WorkerCpuActiveAvg float64 `csv:"worker_cpu_active_avg"` - WorkerMemAvg float64 `csv:"worker_mem"` - - DesiredPods int `csv:"desired_pods"` - UnreadyPods int `csv:"unready_pods"` - PendingPods int `csv:"pending_pods"` - RequestedPods int `csv:"requested_pods"` - RunningPods int `csv:"running_pods"` - - ActivatorQueue float64 `csv:"activator_queue"` - ActivatorRequestCount int `csv:"activator_request_count"` - AutoscalerStableQueue float64 `csv:"autoscaler_stable_queue"` - AutoscalerPanicQueue float64 `csv:"autoscaler_panic_queue"` - - SchedulingP99 float64 `csv:"scheduling_p99"` - SchedulingP50 float64 `csv:"scheduling_p50"` - E2ePlacementP99 float64 `csv:"e2e_placement_p99"` - E2ePlacementP50 float64 `csv:"e2e_placement_p50"` - - ColdStartCount int `csv:"coldstart_count"`*/ + AsyncResponseID string `csv:"-"` + TimeToSubmitMs int64 `csv:"timeToSubmitMs"` + UserCodeExecutionMs int64 `csv:"userCodeExecutionMs"` + + TimeToGetResponseMs int64 `csv:"timeToGetResponseMs"` } type DeploymentScale struct { diff --git a/workloads/container/trace_func_py.yaml b/workloads/container/trace_func_py.yaml deleted file mode 100644 index 288ab353..00000000 --- a/workloads/container/trace_func_py.yaml +++ /dev/null @@ -1,12 +0,0 @@ -apiVersion: serving.knative.dev/v1 -kind: Service -metadata: - namespace: default -spec: - template: - spec: - containers: - - image: docker.io/hyhe/trace-func-py:latest - ports: - - name: h2c # For gRPC support - containerPort: 80 \ No newline at end of file diff --git a/workloads/container/wimpy.yaml b/workloads/container/wimpy.yaml deleted file mode 100644 index 2cc79837..00000000 --- a/workloads/container/wimpy.yaml +++ /dev/null @@ -1,20 +0,0 @@ -apiVersion: serving.knative.dev/v1 -kind: Service -metadata: - namespace: default -spec: - template: - metadata: - annotations: - autoscaling.knative.dev/initial-scale: "0" # Should start from 0, otherwise we can't deploy more functions than the node physically permits. - autoscaling.knative.dev/min-scale: "0" # This parameter only has a per-revision key, so it's necessary to have here in case of the warmup messes up. - autoscaling.knative.dev/target-burst-capacity: "-1" # Put activator always in the path explicitly. - autoscaling.knative.dev/max-scale: "200" # Maximum instances limit of Azure. - spec: - containerConcurrency: 1 - containers: - - image: docker.io/hyhe/wimpy:latest - # imagePullPolicy: Always # No need if the tag is `latest`. - ports: - - name: h2c # For gRPC support - containerPort: 80 \ No newline at end of file diff --git a/workloads/firecracker/timed.yaml b/workloads/firecracker/timed.yaml deleted file mode 100644 index 207a1857..00000000 --- a/workloads/firecracker/timed.yaml +++ /dev/null @@ -1,20 +0,0 @@ -apiVersion: serving.knative.dev/v1 -kind: Service -metadata: - namespace: default -spec: - template: - spec: - containerConcurrency: 1 - containers: - - image: crccheck/hello-world:latest # Stub image. See https://github.com/ease-lab/vhive/issues/68 - ports: - - name: h2c # For GRPC support - containerPort: 50051 - env: - - name: GUEST_PORT # Port on which the firecracker-containerd container is accepting requests - value: "50051" - - name: GUEST_IMAGE # Container image to use for firecracker-containerd container - value: "amohoste/timed:latest" - - name: MEM_SIZE_MB - value: "2048" diff --git a/workloads/other/helloworld.yaml b/workloads/other/helloworld.yaml deleted file mode 100644 index 6ee19db9..00000000 --- a/workloads/other/helloworld.yaml +++ /dev/null @@ -1,12 +0,0 @@ -apiVersion: serving.knative.dev/v1 -kind: Service -metadata: - namespace: default -spec: - template: - spec: - containers: - - image: docker.io/hyhe/helloworld:go1.7 - env: - - name: TARGET - value: "there!" \ No newline at end of file diff --git a/workloads/other/producer.yaml b/workloads/other/producer.yaml deleted file mode 100644 index 1801798e..00000000 --- a/workloads/other/producer.yaml +++ /dev/null @@ -1,28 +0,0 @@ -apiVersion: serving.knative.dev/v1 -kind: Service -metadata: - namespace: default -spec: - template: - spec: - containers: - - image: docker.io/vhiveease/chained-functions-serving-producer:latest - imagePullPolicy: Always - args: ["-addr", "consumer.default.svc.cluster.local"] - env: - - name: TRANSFER_TYPE - value: "S3" - # replace with envsubt - - name: AWS_ACCESS_KEY - value: ${AWS_ACCESS_KEY} - - name: AWS_SECRET_KEY - value: ${AWS_SECRET_KEY} - - name: AWS_REGION - value: "us-west-1" - - name: ENABLE_TRACING - value: "false" - ports: - # For `h2c`, see https://knative.tips/networking/http2/ - - name: h2c - # Container mode (don't try to call firecracker via 50051 here) - containerPort: 80 \ No newline at end of file