feat: more explicit config logging and validation

main
Sean McBride 4 years ago
parent 02244fd76f
commit 5968d9b72e

@ -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

@ -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);

@ -9,6 +9,12 @@
#include <sys/time.h>
#include <unistd.h>
#ifdef LOG_TO_FILE
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/fcntl.h>
#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;
// 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();

@ -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,

Loading…
Cancel
Save