diff --git a/cmd/config_dirigent_dandelion_rps.json b/cmd/config_dirigent_dandelion_rps.json index d4b32e21..964580e1 100644 --- a/cmd/config_dirigent_dandelion_rps.json +++ b/cmd/config_dirigent_dandelion_rps.json @@ -19,6 +19,7 @@ "RpsRuntimeMs": 10, "RpsMemoryMB": 2048, "RpsIterationMultiplier": 80, + "RpsDataSizeMB": 0.00, "TracePath": "data/traces/example", "Granularity": "minute", diff --git a/cmd/config_dirigent_rps.json b/cmd/config_dirigent_rps.json index cf295202..c61608d1 100644 --- a/cmd/config_dirigent_rps.json +++ b/cmd/config_dirigent_rps.json @@ -19,6 +19,7 @@ "RpsRuntimeMs": 10, "RpsMemoryMB": 2048, "RpsIterationMultiplier": 80, + "RpsDataSizeMB": 0.00, "TracePath": "data/traces/example", "Granularity": "minute", diff --git a/cmd/config_knative_rps.json b/cmd/config_knative_rps.json index 3a72fd7d..cf1d9325 100644 --- a/cmd/config_knative_rps.json +++ b/cmd/config_knative_rps.json @@ -15,6 +15,7 @@ "RpsRuntimeMs": 10, "RpsMemoryMB": 2048, "RpsIterationMultiplier": 80, + "RpsDataSizeMB": 0.00, "TracePath": "data/traces/example", "Granularity": "minute", diff --git a/docs/configuration.md b/docs/configuration.md index 7382484a..f920be5f 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -19,6 +19,7 @@ | RpsRuntimeMs | int | >=0 | 0 | Requested execution time | | RpsMemoryMB | int | >=0 | 0 | Requested memory | | RpsIterationMultiplier | int | >=0 | 0 | Iteration multiplier for RPS mode | +| RpsDataSizeMB | float64 | >= 0 | 0 | Amount of random data (same for all requests) to embed into each request | | 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[^2] | | OutputPathPrefix | string | any | data/out/experiment | Results file(s) output path prefix | @@ -55,7 +56,8 @@ Lambda; https://aws.amazon.com/about-aws/whats-new/2018/10/aws-lambda-supports-f [^6]: Dirigent specific -[^7] It is recommended that the first 10% of cold starts are discarded from the experiment results for low cold start RPS. +[^7] It is recommended that the first 10% of cold starts are discarded from the experiment results for low cold start +RPS. --- diff --git a/pkg/config/parser.go b/pkg/config/parser.go index c6015d67..6cbb40eb 100644 --- a/pkg/config/parser.go +++ b/pkg/config/parser.go @@ -61,6 +61,7 @@ type LoaderConfiguration struct { RpsRuntimeMs int `json:"RpsRuntimeMs"` RpsMemoryMB int `json:"RpsMemoryMB"` RpsIterationMultiplier int `json:"RpsIterationMultiplier"` + RpsDataSizeMB float64 `json:"RpsDataSizeMB"` TracePath string `json:"TracePath"` Granularity string `json:"Granularity"` diff --git a/pkg/driver/clients/http_client.go b/pkg/driver/clients/http_client.go index 5d6cd051..6fdec5e1 100644 --- a/pkg/driver/clients/http_client.go +++ b/pkg/driver/clients/http_client.go @@ -2,6 +2,7 @@ package clients import ( "bytes" + "crypto/rand" "encoding/json" log "github.com/sirupsen/logrus" "github.com/vhive-serverless/loader/pkg/common" @@ -33,6 +34,23 @@ func newHTTPInvoker(cfg *config.LoaderConfiguration) *httpInvoker { } } +var payload []byte = nil + +func CreateRequestPayload(sizeInMB float64) *bytes.Buffer { + byteCount := int(sizeInMB * 1024.0 * 1024.0) // MB -> B + + if payload == nil { + payload = make([]byte, byteCount) + + n, err := rand.Read(payload) + if err != nil || n != byteCount { + log.Errorf("Failed to generate random %d bytes.", byteCount) + } + } + + return bytes.NewBuffer(payload) +} + 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") @@ -48,8 +66,6 @@ func (i *httpInvoker) Invoke(function *common.Function, runtimeSpec *common.Runt //////////////////////////////////// // INVOKE FUNCTION //////////////////////////////////// - start := time.Now() - record.StartTime = start.UnixMicro() requestBody := &bytes.Buffer{} /*if body := composeDandelionMatMulBody(function.Name); isDandelion && body != nil { @@ -58,8 +74,16 @@ func (i *httpInvoker) Invoke(function *common.Function, runtimeSpec *common.Runt if body := composeBusyLoopBody(function.Name, function.DirigentMetadata.Image, runtimeSpec.Runtime, function.DirigentMetadata.IterationMultiplier); isDandelion && body != nil { requestBody = body } + if i.cfg.RpsTarget != 0 { + ts := time.Now() + requestBody = CreateRequestPayload(i.cfg.RpsDataSizeMB) + log.Debugf("Took %v to generate request body.", time.Since(ts)) + } + + start := time.Now() + record.StartTime = start.UnixMicro() - req, err := http.NewRequest("GET", "http://"+function.Endpoint, requestBody) + req, err := http.NewRequest("POST", "http://"+function.Endpoint, requestBody) if err != nil { log.Errorf("Failed to create a HTTP request - %v\n", err) diff --git a/pkg/driver/deployment/dirigent.go b/pkg/driver/deployment/dirigent.go index fd068283..3c55297d 100644 --- a/pkg/driver/deployment/dirigent.go +++ b/pkg/driver/deployment/dirigent.go @@ -130,6 +130,8 @@ func deployDirigent(function *common.Function, controlPlaneAddress string, busyL log.Error("Function registration returned no data plane(s).") return } + + log.Debugf("Got the following endpoints: %v", endpoints) function.Endpoint = endpoints[rand.Intn(len(endpoints))] checkForRegistration(controlPlaneAddress, function.Name, prepullMode)