From 5968d9b72e562b862418ec53aa0056a51f8836ae Mon Sep 17 00:00:00 2001 From: Sean McBride Date: Wed, 24 Mar 2021 11:17:25 -0400 Subject: [PATCH] feat: more explicit config logging and validation --- runtime/Makefile | 23 +++-- runtime/include/admissions_info.h | 3 +- runtime/src/main.c | 143 +++++++++++++++++++++++++++--- runtime/src/module.c | 57 ++++++++++-- 4 files changed, 195 insertions(+), 31 deletions(-) diff --git a/runtime/Makefile b/runtime/Makefile index f9244c4..af3bcaf 100644 --- a/runtime/Makefile +++ b/runtime/Makefile @@ -1,4 +1,10 @@ ARCH := $(shell uname -m) +ifneq ($(ARCH),x86_64) +ifneq ($(ARCH),aarch64) +$(error Unsupported Architecture. Supports x86_64 and aarch64, found $(ARCH)) +endif +endif + TOTAL_CORES := $(shell getconf _NPROCESSORS_CONF) PAGE_SIZE=$(shell getconf PAGESIZE) @@ -11,16 +17,14 @@ CC_OPTIONS = -O3 -flto -g -pthread -D_GNU_SOURCE BINARY_NAME=sledgert -# Options: {USE_MEM_GENERIC, USE_MEM_VM} -USE_MEM = USE_MEM_VM # Feature Toggles -# CFLAGS += -DADMISSIONS_CONTROL +CFLAGS += -DADMISSIONS_CONTROL # Debugging Flags # Strips out calls to assert() and disables debuglog -# CFLAGS += -DNDEBUG +CFLAGS += -DNDEBUG # Redirects debuglogs to /runtime/bin/sledge.log # CFLAGS += -DLOG_TO_FILE @@ -60,7 +64,8 @@ CFLAGS += -DPAGE_SIZE=$(PAGE_SIZE) # Optionally Disable preemption # CFLAGS += -DPREEMPT_DISABLE -CFLAGS += -D${USE_MEM} +# Sandboxes running on Sledge always use WebAssembly linear memory +CFLAGS += -DUSE_MEM_VM # Preprocessor LDFLAGS += -Wl,--export-dynamic -ldl -lm @@ -72,14 +77,8 @@ CFILES += src/*.c CFILES += src/arch/${ARCH}/*.c CFILES += src/libc/*.c CFILES += src/memory/common.c -CFILES += thirdparty/dist/lib/http_parser.o -# TODO: Is USE_MEM_GENERIC out of date? I do not see that file. -# Does that mean we can make USE_MEM_VM an invariant? -ifeq ($(USE_MEM),USE_MEM_GENERIC) -CFILES += src/memory/generic.c -else ifeq ($(USE_MEM),USE_MEM_VM) CFILES += src/memory/64bit_nix.c -endif +CFILES += thirdparty/dist/lib/http_parser.o # Configuring Jasmine JSMNCFLAGS += -DJSMN_STATIC diff --git a/runtime/include/admissions_info.h b/runtime/include/admissions_info.h index 55211e3..e239236 100644 --- a/runtime/include/admissions_info.h +++ b/runtime/include/admissions_info.h @@ -20,7 +20,8 @@ admissions_info_initialize(struct admissions_info *self, int percentile, uint64_ uint64_t relative_deadline) { #ifdef ADMISSIONS_CONTROL - + assert(relative_deadline > 0); + assert(expected_execution > 0); self->relative_deadline = relative_deadline; self->estimate = admissions_control_calculate_estimate(expected_execution, relative_deadline); debuglog("Initial Estimate: %lu\n", self->estimate); diff --git a/runtime/src/main.c b/runtime/src/main.c index 1a3290f..6390565 100644 --- a/runtime/src/main.c +++ b/runtime/src/main.c @@ -9,6 +9,12 @@ #include #include +#ifdef LOG_TO_FILE +#include +#include +#include +#endif + #include "debuglog.h" #include "module.h" #include "panic.h" @@ -81,7 +87,7 @@ runtime_allocate_available_cores() { /* Find the number of processors currently online */ runtime_total_online_processors = sysconf(_SC_NPROCESSORS_ONLN); - printf("Detected %u cores\n", runtime_total_online_processors); + printf("\tCore Count: %u\n", runtime_total_online_processors); uint32_t max_possible_workers = runtime_total_online_processors - 1; if (runtime_total_online_processors < 2) panic("Runtime requires at least two cores!"); @@ -98,8 +104,9 @@ runtime_allocate_available_cores() runtime_worker_threads_count = max_possible_workers; } - printf("Running one listener core at ID %u and %u worker core(s) starting at ID %u\n", LISTENER_THREAD_CORE_ID, - runtime_worker_threads_count, runtime_first_worker_processor); + printf("\tListener core ID: %u\n", LISTENER_THREAD_CORE_ID); + printf("\tFirst Worker core ID: %u\n", runtime_first_worker_processor); + printf("\tWorker core count: %u\n", runtime_worker_threads_count); } /** @@ -205,39 +212,155 @@ runtime_configure() } else { panic("Invalid scheduler policy: %s. Must be {EDF|FIFO}\n", scheduler_policy); } - printf("Scheduler Policy: %s\n", print_runtime_scheduler(runtime_scheduler)); + printf("\tScheduler Policy: %s\n", print_runtime_scheduler(runtime_scheduler)); /* Runtime Perf Log */ char *runtime_sandbox_perf_log_path = getenv("SLEDGE_SANDBOX_PERF_LOG"); if (runtime_sandbox_perf_log_path != NULL) { - printf("Logging Sandbox Performance to: %s\n", runtime_sandbox_perf_log_path); + printf("\tSandbox Performance Log: %s\n", runtime_sandbox_perf_log_path); runtime_sandbox_perf_log = fopen(runtime_sandbox_perf_log_path, "w"); if (runtime_sandbox_perf_log == NULL) { perror("sandbox perf log"); } fprintf(runtime_sandbox_perf_log, "id,function,state,deadline,actual,queued,initializing,runnable," "running,blocked,returned,memory\n"); + } else { + printf("\tSandbox Performance Log: Disabled\n"); } } +void +log_compiletime_config() +{ + printf("Static Compiler Flags:\n"); +#ifdef ADMISSIONS_CONTROL + printf("\tAdmissions Control: Enabled\n"); +#else + printf("\tAdmissions Control: Disabled\n"); +#endif + +#ifdef NDEBUG + printf("\tAssertions and Debug Logs: Disabled\n"); +#else + printf("\tAssertions and Debug Logs: Enabled\n"); +#endif + +#ifdef LOG_TO_FILE + printf("\tLogging to: %s\n", RUNTIME_LOG_FILE); +#else + printf("\tLogging to: STDOUT and STDERR\n"); +#endif + +#if defined(aarch64) + printf("\tArchitecture: %s\n", "aarch64"); +#elif defined(x86_64) + printf("\tArchitecture: %s\n", "x86_64"); +#endif + + // TODO: Static assertion of define + int ncores = NCORES; + printf("\tTotal Cores: %d\n", ncores); + int page_size = PAGE_SIZE; + printf("\tPage Size: %d\n", page_size); + +#ifdef LOG_HTTP_PARSER + printf("\tLog HTTP Parser: Enabled\n"); +#else + printf("\tLog HTTP Parser: Disabled\n"); +#endif + +#ifdef LOG_STATE_CHANGES + printf("\tLog State Changes: Enabled\n"); +#else + printf("\tLog State Changes: Disabled\n"); +#endif + +#ifdef LOG_LOCK_OVERHEAD + printf("\tLog Lock Overhead: Enabled\n"); +#else + printf("\tLog Lock Overhead: Disabled\n"); +#endif + +#ifdef LOG_LISTENER_LOCK_OVERHEAD + printf("\tLog Listener Lock Overhead: Enabled\n"); +#else + printf("\tLog Listener Lock Overhead: Disabled\n"); +#endif + +#ifdef LOG_CONTEXT_SWITCHES + printf("\tLog Context Switches: Enabled\n"); +#else + printf("\tLog Context Switches: Disabled\n"); +#endif + +#ifdef LOG_ADMISSIONS_CONTROL + printf("\tLog Admissions Control: Enabled\n"); +#else + printf("\tLog Admissions Control: Disabled\n"); +#endif + +#ifdef LOG_REQUEST_ALLOCATION + printf("\tLog Request Allocation: Enabled\n"); +#else + printf("\tLog Request Allocation: Disabled\n"); +#endif + +#ifdef LOG_PREEMPTION + printf("\tLog Preemption: Enabled\n"); +#else + printf("\tLog Preemption: Disabled\n"); +#endif + +#ifdef LOG_MODULE_LOADING + printf("\tLog Module Loading: Enabled\n"); +#else + printf("\tLog Module Loading: Disabled\n"); +#endif + +#ifdef LOG_TOTAL_REQS_RESPS + printf("\tLog Total Reqs/Resps: Enabled\n"); +#else + printf("\tLog Total Reqs/Resps: Disabled\n"); +#endif + +#ifdef LOG_SANDBOX_COUNT + printf("\tLog Sandbox Count: Enabled\n"); +#else + printf("\tLog Sandbox Count: Disabled\n"); +#endif + +#ifdef LOG_LOCAL_RUNQUEUE + printf("\tLog Local Runqueue: Enabled\n"); +#else + printf("\tLog Local Runqueue: Disabled\n"); +#endif +} + int main(int argc, char **argv) { - runtime_process_debug_log_behavior(); - - printf("Starting the Sledge runtime\n"); if (argc != 2) { runtime_usage(argv[0]); exit(-1); } + printf("Starting the Sledge runtime\n"); + + log_compiletime_config(); + runtime_process_debug_log_behavior(); + + printf("Runtime Environment:\n"); + memset(runtime_worker_threads, 0, sizeof(pthread_t) * WORKER_THREAD_CORE_COUNT); runtime_processor_speed_MHz = runtime_get_processor_speed_MHz(); if (unlikely(runtime_processor_speed_MHz == 0)) panic("Failed to detect processor speed\n"); - runtime_relative_deadline_us_max = UINT64_MAX / runtime_processor_speed_MHz; + runtime_relative_deadline_us_max = UINT64_MAX / runtime_processor_speed_MHz; + // TODO: Just here for troubleshooting. Delete me later + printf("Runtime Relative Deadline Max: %lu\n", runtime_relative_deadline_us_max); + printf("UINT32_MAX: %u\n", UINT32_MAX); software_interrupt_interval_duration_in_cycles = (uint64_t)SOFTWARE_INTERRUPT_INTERVAL_DURATION_IN_USEC * runtime_processor_speed_MHz; - printf("Detected processor speed of %u MHz\n", runtime_processor_speed_MHz); + printf("\tProcessor Speed: %u MHz\n", runtime_processor_speed_MHz); runtime_set_resource_limits_to_max(); runtime_allocate_available_cores(); diff --git a/runtime/src/module.c b/runtime/src/module.c index 03439ab..fc8d881 100644 --- a/runtime/src/module.c +++ b/runtime/src/module.c @@ -386,23 +386,49 @@ module_new_from_json(char *file_name) file_buffer + tokens[j + i + 1].start); sprintf(key, "%.*s", tokens[j + i].end - tokens[j + i].start, file_buffer + tokens[j + i].start); + + if (strlen(key) == 0) panic("Unexpected encountered empty key\n"); + if (strlen(val) == 0) panic("%s field contained empty string\n", key); + if (strcmp(key, "name") == 0) { + // TODO: Currently, multiple modules can have identical names. Ports are the true unique + // identifiers. Consider enforcing unique names in future strcpy(module_name, val); } else if (strcmp(key, "path") == 0) { + // Invalid path will crash on dlopen strcpy(module_path, val); } else if (strcmp(key, "port") == 0) { - port = atoi(val); + // Validate sane port + // If already taken, will error on bind call in module_listen + int buffer = atoi(val); + if (buffer < 0 || buffer > 65535) + panic("Expected port between 0 and 65535, saw %d\n", buffer); + port = buffer; } else if (strcmp(key, "argsize") == 0) { + // Validate in expected range 0..127. Unclear if 127 is an actual hard limit argument_count = atoi(val); + if (argument_count < 0 || argument_count > 127) + panic("Expected argument count between 0 and 127, saw %d\n", argument_count); } else if (strcmp(key, "active") == 0) { - is_active = (strcmp(val, "yes") == 0); + if (strcmp(val, "yes") == 0) { + is_active = true; + } else if (strcmp(val, "no") == 0) { + is_active = false; + } else { + panic("Expected active key to have value of yes or no, was %s\n", val); + } } else if (strcmp(key, "relative-deadline-us") == 0) { - unsigned long long buffer = strtoull(val, NULL, 10); - if (buffer > runtime_relative_deadline_us_max) - panic("Max relative-deadline-us is %u, but entry was %llu\n", UINT32_MAX, - buffer); + // Panic on overflow + // TODO: Consider underflow + int64_t buffer = strtoll(val, NULL, 10); + if (buffer < 0 || buffer > (int64_t)runtime_relative_deadline_us_max) + panic("Relative-deadline-us must be between 0 and %lu, was %ld\n", + runtime_relative_deadline_us_max, buffer); relative_deadline_us = (uint32_t)buffer; } else if (strcmp(key, "expected-execution-us") == 0) { + // Panic on overflow + // TODO: Consider underflow + debuglog("expected-execution-us: %s\n", val); unsigned long long buffer = strtoull(val, NULL, 10); if (buffer > UINT32_MAX) panic("Max expected-execution-us is %u, but entry was %llu\n", UINT32_MAX, @@ -458,11 +484,26 @@ module_new_from_json(char *file_name) } i += ntoks; -/* Validate presence of required fields */ + /* Validate presence of required fields */ + + if (strlen(module_name) == 0) panic("name field is required\n"); + if (strlen(module_path) == 0) panic("path field is required\n"); + if (port == 0) panic("port field is required\n"); + #ifdef ADMISSIONS_CONTROL - if (expected_execution_us == 0) panic("expected-execution-us is required for EDF\n"); + /* expected-execution-us and relative-deadline-us are required in case of admissions control */ + if (expected_execution_us == 0) panic("expected-execution-us is required\n"); + if (relative_deadline_us == 0) panic("relative_deadline_us is required\n"); +#else + /* relative-deadline-us is required if scheduler is EDF */ + if (runtime_scheduler == RUNTIME_SCHEDULER_EDF && relative_deadline_us == 0) + panic("relative_deadline_us is required\n"); #endif + /* argsize defaults to 0 if absent */ + /* http-req-headers defaults to empty if absent */ + /* http-req-headers defaults to empty if absent */ + if (is_active) { /* Allocate a module based on the values from the JSON */ struct module *module = module_new(module_name, module_path, argument_count, 0, 0,