Compare commits
1 Commits
master
...
memstream-
Author | SHA1 | Date |
---|---|---|
|
a6649365a5 | 3 years ago |
@ -1,23 +1,24 @@
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Linux",
|
||||
"intelliSenseMode": "clang-x64",
|
||||
"includePath": [
|
||||
"/usr/include/",
|
||||
"${workspaceFolder}/runtime/include/",
|
||||
"${workspaceFolder}/runtime/thirdparty/ck/include/",
|
||||
"${workspaceFolder}/runtime/thirdparty/http-parser/",
|
||||
"${workspaceFolder}/runtime/thirdparty/jsmn/",
|
||||
"${workspaceFolder}/awsm/runtime/libc/wasi/include/",
|
||||
"${workspaceFolder}/libsledge/include"
|
||||
],
|
||||
"defines": [
|
||||
"x86_64",
|
||||
"_GNU_SOURCE"
|
||||
],
|
||||
"cStandard": "c17"
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
}
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Linux",
|
||||
"intelliSenseMode": "clang-x64",
|
||||
"includePath": [
|
||||
"/usr/include/",
|
||||
"${workspaceFolder}/runtime/include/",
|
||||
"${workspaceFolder}/runtime/thirdparty/ck/include/",
|
||||
"${workspaceFolder}/runtime/thirdparty/http-parser/",
|
||||
"${workspaceFolder}/runtime/thirdparty/jsmn/",
|
||||
"${workspaceFolder}/awsm/runtime/libc/wasi/include/",
|
||||
"${workspaceFolder}/libsledge/include"
|
||||
],
|
||||
"defines": [
|
||||
"x86_64",
|
||||
"_GNU_SOURCE"
|
||||
],
|
||||
"cStandard": "c17",
|
||||
"compilerPath": "/usr/bin/clang"
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
}
|
||||
|
@ -0,0 +1 @@
|
||||
Subproject commit 0b9f67d75fd9dab652e1995e7adf91806080523b
|
@ -1 +1 @@
|
||||
Subproject commit 272fcf42b6559ccb5c5213eb78edfc0f703520ab
|
||||
Subproject commit 28f3cbfb45db367bab63fa0131865ea63ae98d4a
|
@ -1,19 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef ADMISSIONS_CONTROL
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define ADMISSIONS_CONTROL_GRANULARITY 1000000
|
||||
extern _Atomic uint64_t admissions_control_admitted;
|
||||
extern uint64_t admissions_control_capacity;
|
||||
|
||||
void admissions_control_initialize(void);
|
||||
void admissions_control_add(uint64_t admissions_estimate);
|
||||
void admissions_control_subtract(uint64_t admissions_estimate);
|
||||
uint64_t admissions_control_calculate_estimate(uint64_t estimated_execution, uint64_t relative_deadline);
|
||||
uint64_t admissions_control_calculate_estimate_us(uint32_t estimated_execution_us, uint32_t relative_deadline_us);
|
||||
void admissions_control_log_decision(uint64_t admissions_estimate, bool admitted);
|
||||
uint64_t admissions_control_decide(uint64_t admissions_estimate);
|
||||
|
||||
#endif
|
@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include "perf_window_t.h"
|
||||
|
||||
struct admissions_info {
|
||||
struct perf_window perf_window;
|
||||
uint8_t percentile; /* 50 - 99 */
|
||||
int control_index; /* Precomputed Lookup index when perf_window is full */
|
||||
uint64_t estimate; /* cycles */
|
||||
uint64_t relative_deadline; /* Relative deadline in cycles. This is duplicated state */
|
||||
};
|
||||
|
||||
void admissions_info_initialize(struct admissions_info *admissions_info, uint8_t percentile,
|
||||
uint64_t expected_execution, uint64_t relative_deadline);
|
||||
void admissions_info_update(struct admissions_info *admissions_info, uint64_t execution_duration);
|
@ -1,44 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "likely.h"
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
struct auto_buf {
|
||||
FILE *handle;
|
||||
char *data;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
static inline int
|
||||
auto_buf_init(struct auto_buf *buf)
|
||||
{
|
||||
FILE *res = open_memstream(&buf->data, &buf->size);
|
||||
if (res == NULL) return errno;
|
||||
|
||||
buf->handle = res;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
auto_buf_flush(struct auto_buf *buf)
|
||||
{
|
||||
return fflush(buf->handle);
|
||||
}
|
||||
|
||||
static inline void
|
||||
auto_buf_deinit(struct auto_buf *buf)
|
||||
{
|
||||
if (likely(buf->handle != NULL)) {
|
||||
fclose(buf->handle);
|
||||
buf->handle = NULL;
|
||||
}
|
||||
|
||||
if (likely(buf->data != NULL)) {
|
||||
free(buf->data);
|
||||
buf->data = NULL;
|
||||
}
|
||||
|
||||
buf->size = 0;
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
enum epoll_tag
|
||||
{
|
||||
EPOLL_TAG_INVALID = 0,
|
||||
EPOLL_TAG_TENANT_SERVER_SOCKET = 1,
|
||||
EPOLL_TAG_METRICS_SERVER_SOCKET,
|
||||
EPOLL_TAG_HTTP_SESSION_CLIENT_SOCKET,
|
||||
};
|
@ -1,14 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "perf_window_t.h"
|
||||
|
||||
struct execution_histogram {
|
||||
struct perf_window perf_window;
|
||||
uint8_t percentile; /* 50 - 99 */
|
||||
int control_index; /* Precomputed Lookup index when perf_window is full */
|
||||
uint64_t estimated_execution; /* cycles */
|
||||
};
|
||||
|
||||
void execution_histogram_initialize(struct execution_histogram *execution_histogram, uint8_t percentile,
|
||||
uint64_t expected_execution);
|
||||
void execution_histogram_update(struct execution_histogram *execution_histogram, uint64_t execution_duration);
|
@ -1,26 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef EXECUTION_REGRESSION
|
||||
|
||||
#include "http_session.h"
|
||||
#include <stdint.h>
|
||||
|
||||
static inline uint64_t
|
||||
get_regression_prediction(struct http_session *session)
|
||||
{
|
||||
/* Default Pre-processing - Extract payload size */
|
||||
const int payload_size = session->http_request.body_length;
|
||||
|
||||
const double regression_params[2] = {payload_size, session->regression_param};
|
||||
|
||||
/* Perform Linear Regression using the factors provided by the regressor performed AoT on Matlab using training
|
||||
* tenant-given dataset */
|
||||
const struct regression_model model = session->route->regr_model;
|
||||
const uint64_t prediction = (regression_params[0] / model.scale * model.beta1
|
||||
+ regression_params[1] / model.scale * model.beta2)
|
||||
+ model.bias;
|
||||
|
||||
return prediction;
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <threads.h>
|
||||
|
||||
extern thread_local uint64_t generic_thread_lock_duration;
|
||||
extern thread_local uint64_t generic_thread_lock_longest;
|
||||
extern thread_local uint64_t generic_thread_start_timestamp;
|
||||
|
||||
void generic_thread_dump_lock_overhead(void);
|
||||
void generic_thread_initialize(void);
|
@ -1,48 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdatomic.h>
|
||||
|
||||
#ifdef HTTP_ROUTE_TOTAL_COUNTERS
|
||||
struct http_route_total {
|
||||
atomic_ulong total_requests;
|
||||
atomic_ulong total_2XX;
|
||||
atomic_ulong total_4XX;
|
||||
atomic_ulong total_5XX;
|
||||
};
|
||||
#else
|
||||
struct http_route_total {
|
||||
};
|
||||
#endif
|
||||
|
||||
static inline void
|
||||
http_route_total_init(struct http_route_total *rm)
|
||||
{
|
||||
#ifdef HTTP_ROUTE_TOTAL_COUNTERS
|
||||
atomic_init(&rm->total_requests, 0);
|
||||
atomic_init(&rm->total_2XX, 0);
|
||||
atomic_init(&rm->total_4XX, 0);
|
||||
atomic_init(&rm->total_5XX, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void
|
||||
http_route_total_increment_request(struct http_route_total *rm)
|
||||
{
|
||||
#ifdef HTTP_ROUTE_TOTAL_COUNTERS
|
||||
atomic_fetch_add(&rm->total_requests, 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void
|
||||
http_route_total_increment(struct http_route_total *rm, int status_code)
|
||||
{
|
||||
#ifdef HTTP_ROUTE_TOTAL_COUNTERS
|
||||
if (status_code >= 200 && status_code <= 299) {
|
||||
atomic_fetch_add(&rm->total_2XX, 1);
|
||||
} else if (status_code >= 400 && status_code <= 499) {
|
||||
atomic_fetch_add(&rm->total_4XX, 1);
|
||||
} else if (status_code >= 500 && status_code <= 599) {
|
||||
atomic_fetch_add(&rm->total_5XX, 1);
|
||||
}
|
||||
#endif
|
||||
}
|
@ -1,81 +1,68 @@
|
||||
#pragma once
|
||||
|
||||
#include <assert.h>
|
||||
#include <spinlock/mcs.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "arch/getcycles.h"
|
||||
#include "runtime.h"
|
||||
#include "generic_thread.h"
|
||||
|
||||
|
||||
/* A linked list of nodes */
|
||||
struct lock_wrapper {
|
||||
uint64_t longest_held;
|
||||
uint64_t total_held;
|
||||
ck_spinlock_mcs_t lock;
|
||||
};
|
||||
|
||||
/* A node on the linked list */
|
||||
struct lock_node {
|
||||
struct ck_spinlock_mcs node;
|
||||
uint64_t time_locked;
|
||||
};
|
||||
|
||||
typedef struct lock_wrapper lock_t;
|
||||
typedef struct lock_node lock_node_t;
|
||||
typedef ck_spinlock_mcs_t lock_t;
|
||||
|
||||
/**
|
||||
* Initializes a lock
|
||||
* Initializes a lock of type lock_t
|
||||
* @param lock - the address of the lock
|
||||
*/
|
||||
static inline void
|
||||
lock_init(lock_t *self)
|
||||
{
|
||||
self->total_held = 0;
|
||||
self->longest_held = 0;
|
||||
ck_spinlock_mcs_init(&self->lock);
|
||||
}
|
||||
#define LOCK_INIT(lock) ck_spinlock_mcs_init((lock))
|
||||
|
||||
/**
|
||||
* Checks if a lock is locked
|
||||
* @param lock - the address of the lock
|
||||
* @returns bool if lock is locked
|
||||
*/
|
||||
static inline bool
|
||||
lock_is_locked(lock_t *self)
|
||||
{
|
||||
return ck_spinlock_mcs_locked(&self->lock);
|
||||
}
|
||||
|
||||
#define LOCK_IS_LOCKED(lock) ck_spinlock_mcs_locked((lock))
|
||||
|
||||
/**
|
||||
* Locks a lock, keeping track of overhead
|
||||
* @param lock - the address of the lock
|
||||
* @param node - node to add to lock
|
||||
* @param unique_variable_name - a unique prefix to hygienically namespace an associated lock/unlock pair
|
||||
*/
|
||||
static inline void
|
||||
lock_lock(lock_t *self, lock_node_t *node)
|
||||
{
|
||||
assert(node->time_locked == 0);
|
||||
|
||||
node->time_locked = __getcycles();
|
||||
ck_spinlock_mcs_lock(&self->lock, &node->node);
|
||||
}
|
||||
#define LOCK_LOCK_WITH_BOOKKEEPING(lock, unique_variable_name) \
|
||||
struct ck_spinlock_mcs _hygiene_##unique_variable_name##_node; \
|
||||
uint64_t _hygiene_##unique_variable_name##_pre = __getcycles(); \
|
||||
ck_spinlock_mcs_lock((lock), &(_hygiene_##unique_variable_name##_node)); \
|
||||
uint64_t _hygiene_##unique_variable_name##_duration = (__getcycles() - _hygiene_##unique_variable_name##_pre); \
|
||||
if (_hygiene_##unique_variable_name##_duration > generic_thread_lock_longest) { \
|
||||
generic_thread_lock_longest = _hygiene_##unique_variable_name##_duration; \
|
||||
} \
|
||||
generic_thread_lock_duration += _hygiene_##unique_variable_name##_duration;
|
||||
|
||||
/**
|
||||
* Unlocks a lock
|
||||
* @param lock - the address of the lock
|
||||
* @param node - node used when calling lock_lock
|
||||
* @param unique_variable_name - a unique prefix to hygienically namespace an associated lock/unlock pair
|
||||
*/
|
||||
static inline void
|
||||
lock_unlock(lock_t *self, lock_node_t *node)
|
||||
{
|
||||
assert(node->time_locked > 0);
|
||||
#define LOCK_UNLOCK_WITH_BOOKKEEPING(lock, unique_variable_name) \
|
||||
ck_spinlock_mcs_unlock(lock, &(_hygiene_##unique_variable_name##_node));
|
||||
|
||||
ck_spinlock_mcs_unlock(&self->lock, &node->node);
|
||||
uint64_t now = __getcycles();
|
||||
assert(node->time_locked < now);
|
||||
uint64_t duration = now - node->time_locked;
|
||||
node->time_locked = 0;
|
||||
if (unlikely(duration > self->longest_held)) { self->longest_held = duration; }
|
||||
self->total_held += duration;
|
||||
}
|
||||
/**
|
||||
* Locks a lock, keeping track of overhead
|
||||
* Assumes the availability of DEFAULT as a hygienic prefix for DEFAULT_node and DEFAULT_pre
|
||||
*
|
||||
* As such, this API can only be used once in a lexical scope.
|
||||
*
|
||||
* Use LOCK_LOCK_WITH_BOOKKEEPING and LOCK_UNLOCK_WITH_BOOKKEEPING if multiple locks are required
|
||||
* @param lock - the address of the lock
|
||||
*/
|
||||
#define LOCK_LOCK(lock) LOCK_LOCK_WITH_BOOKKEEPING(lock, DEFAULT)
|
||||
|
||||
/**
|
||||
* Unlocks a lock
|
||||
* Uses lock node NODE_DEFAULT and timestamp PRE_DEFAULT, so this assumes use of LOCK_LOCK
|
||||
* This API can only be used once in a lexical scope. If this isn't true, use LOCK_LOCK_WITH_BOOKKEEPING and
|
||||
* LOCK_UNLOCK_WITH_BOOKKEEPING
|
||||
* @param lock - the address of the lock
|
||||
*/
|
||||
#define LOCK_UNLOCK(lock) LOCK_UNLOCK_WITH_BOOKKEEPING(lock, DEFAULT)
|
||||
|
@ -1,17 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include "epoll_tag.h"
|
||||
#include "tcp_server.h"
|
||||
|
||||
struct metrics_server {
|
||||
enum epoll_tag tag;
|
||||
struct tcp_server tcp;
|
||||
pthread_attr_t thread_settings;
|
||||
};
|
||||
|
||||
|
||||
extern struct metrics_server metrics_server;
|
||||
extern struct tcp_server metrics_server;
|
||||
|
||||
void metrics_server_init();
|
||||
void metrics_server_thread_spawn(int client_socket);
|
||||
int metrics_server_listen();
|
||||
int metrics_server_close();
|
||||
void metrics_server_handler(int client_socket);
|
||||
|
@ -1,103 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "runtime.h" /* For runtime_pid */
|
||||
|
||||
/* Used to read process-level metrics associated with sledgert from procfs
|
||||
* The parsing behavior is based on prtstat -r
|
||||
*/
|
||||
|
||||
|
||||
enum PROC_STAT
|
||||
{
|
||||
PROC_STAT_PID = 0, /* Process ID */
|
||||
PROC_STAT_COMM = 1, /* Process Name */
|
||||
PROC_STAT_STATE = 2, /* State */
|
||||
PROC_STAT_PPID, /* Parent Process ID */
|
||||
PROC_STAT_PGRP, /* Group ID */
|
||||
PROC_STAT_SESSION, /* Session ID */
|
||||
PROC_STAT_TTY_NR, /* ??? */
|
||||
PROC_STAT_TPGID, /* ??? */
|
||||
PROC_STAT_FLAGS, /* ??? */
|
||||
PROC_STAT_MINFLT, /* Minor Page Faults */
|
||||
PROC_STAT_CMINFLT, /* Minor Page Faults of children */
|
||||
PROC_STAT_MAJFLT, /* Major Page Faults */
|
||||
PROC_STAT_CMAJFLT, /* Major Page Faults of children */
|
||||
PROC_STAT_UTIME, /* User Time */
|
||||
PROC_STAT_STIME, /* System Time */
|
||||
PROC_STAT_CUTIME, /* Child User Time */
|
||||
PROC_STAT_CSTIME, /* Child System Time */
|
||||
PROC_STAT_PRIORITY,
|
||||
PROC_STAT_NICE,
|
||||
PROC_STAT_NUM_THREADS,
|
||||
PROC_STAT_ITREALVALUE,
|
||||
PROC_STAT_STARTTIME, /* Start Time */
|
||||
PROC_STAT_VSIZE, /* Virtual Memory */
|
||||
PROC_STAT_RSS,
|
||||
PROC_STAT_RSSLIM,
|
||||
PROC_STAT_STARTCODE,
|
||||
PROC_STAT_ENDCODE,
|
||||
PROC_STAT_STARTSTACK,
|
||||
PROC_STAT_KSTKESP,
|
||||
PROC_STAT_KSTKEIP,
|
||||
PROC_STAT_WCHAN,
|
||||
PROC_STAT_NSWAP,
|
||||
PROC_STAT_CNSWAP,
|
||||
PROC_STAT_EXIT_SIGNAL,
|
||||
PROC_STAT_PROCESSOR,
|
||||
PROC_STAT_RT_PRIORITY,
|
||||
PROC_STAT_POLICY,
|
||||
PROC_STAT_DELAYACCR_BLKIO_TICKS,
|
||||
PROC_STAT_GUEST_TIME,
|
||||
PROC_STAT_CGUEST_TIME,
|
||||
PROC_STAT_COUNT
|
||||
};
|
||||
|
||||
struct proc_stat_metrics {
|
||||
uint64_t minor_page_faults;
|
||||
uint64_t major_page_faults;
|
||||
uint64_t child_minor_page_faults;
|
||||
uint64_t child_major_page_faults;
|
||||
uint64_t user_time;
|
||||
uint64_t system_time;
|
||||
uint64_t guest_time;
|
||||
};
|
||||
|
||||
static inline void
|
||||
proc_stat_metrics_init(struct proc_stat_metrics *stat)
|
||||
{
|
||||
assert(runtime_pid > 0);
|
||||
|
||||
// Open sledgert's stat file in procfs
|
||||
char path[256];
|
||||
snprintf(path, 256, "/proc/%d/stat", runtime_pid);
|
||||
FILE *proc_stat = fopen(path, "r");
|
||||
|
||||
/* Read stat file into in-memory buffer */
|
||||
char buf[BUFSIZ];
|
||||
fgets(buf, BUFSIZ, proc_stat);
|
||||
fclose(proc_stat);
|
||||
|
||||
/* Parse into an array of tokens with indices aligning to the PROC_STAT enum */
|
||||
char *pos = NULL;
|
||||
char *proc_stat_values[PROC_STAT_COUNT];
|
||||
for (int i = 0; i < PROC_STAT_COUNT; i++) {
|
||||
char *tok = i == 0 ? strtok_r(buf, " ", &pos) : strtok_r(NULL, " ", &pos);
|
||||
proc_stat_values[i] = tok;
|
||||
}
|
||||
|
||||
/* Fill the proc_state_metrics struct with metrics of interest */
|
||||
/* Minor Page Faults, Major Page Faults, Vsize, User, System, Guest, Uptime */
|
||||
stat->minor_page_faults = strtoul(proc_stat_values[PROC_STAT_MINFLT], NULL, 10);
|
||||
stat->major_page_faults = strtoul(proc_stat_values[PROC_STAT_MAJFLT], NULL, 10);
|
||||
stat->child_minor_page_faults = strtoul(proc_stat_values[PROC_STAT_CMINFLT], NULL, 10);
|
||||
stat->child_major_page_faults = strtoul(proc_stat_values[PROC_STAT_CMAJFLT], NULL, 10);
|
||||
stat->user_time = strtoul(proc_stat_values[PROC_STAT_UTIME], NULL, 10);
|
||||
stat->system_time = strtoul(proc_stat_values[PROC_STAT_STIME], NULL, 10);
|
||||
stat->guest_time = strtoul(proc_stat_values[PROC_STAT_GUEST_TIME], NULL, 10);
|
||||
}
|
@ -1,32 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "execution_histogram.h"
|
||||
#include "http_route_total.h"
|
||||
#include "admissions_info.h"
|
||||
#include "module.h"
|
||||
#include "perf_window.h"
|
||||
|
||||
struct regression_model {
|
||||
double bias;
|
||||
double scale;
|
||||
uint32_t num_of_param;
|
||||
double beta1;
|
||||
double beta2;
|
||||
};
|
||||
|
||||
/* Assumption: entrypoint is always _start. This should be enhanced later */
|
||||
struct route {
|
||||
char *route;
|
||||
struct http_route_total metrics;
|
||||
struct module *module;
|
||||
char *route;
|
||||
struct module *module;
|
||||
/* HTTP State */
|
||||
uint32_t relative_deadline_us;
|
||||
uint64_t relative_deadline; /* cycles */
|
||||
char *response_content_type;
|
||||
struct execution_histogram execution_histogram;
|
||||
struct perf_window latency;
|
||||
struct module *module_proprocess;
|
||||
struct regression_model regr_model;
|
||||
uint32_t relative_deadline_us;
|
||||
uint64_t relative_deadline; /* cycles */
|
||||
size_t response_size;
|
||||
char *response_content_type;
|
||||
struct admissions_info admissions_info;
|
||||
};
|
||||
|
@ -1,38 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "perf_window.h"
|
||||
|
||||
static inline void
|
||||
route_latency_init(struct perf_window *route_latency)
|
||||
{
|
||||
#ifdef ROUTE_LATENCY
|
||||
perf_window_initialize(route_latency);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline uint64_t
|
||||
route_latency_get(struct perf_window *route_latency, uint8_t percentile, int precomputed_index)
|
||||
{
|
||||
#ifdef ROUTE_LATENCY
|
||||
lock_node_t node = {};
|
||||
lock_lock(&route_latency->lock, &node);
|
||||
uint64_t res = perf_window_get_percentile(route_latency, percentile, precomputed_index);
|
||||
lock_unlock(&route_latency->lock, &node);
|
||||
return res;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void
|
||||
route_latency_add(struct perf_window *route_latency, uint64_t value)
|
||||
{
|
||||
#ifdef ROUTE_LATENCY
|
||||
lock_node_t node = {};
|
||||
lock_lock(&route_latency->lock, &node);
|
||||
perf_window_add(route_latency, value);
|
||||
lock_unlock(&route_latency->lock, &node);
|
||||
#endif
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
#pragma once
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "http_session.h"
|
||||
#include "panic.h"
|
||||
#include "runtime.h"
|
||||
#include "sandbox_functions.h"
|
||||
#include "sandbox_set_as_error.h"
|
||||
#include "sandbox_state.h"
|
||||
#include "sandbox_types.h"
|
||||
#include "worker_thread.h"
|
||||
|
||||
|
||||
/**
|
||||
* Run all outstanding events in the local thread's epoll loop
|
||||
*/
|
||||
static inline void
|
||||
scheduler_execute_epoll_loop(void)
|
||||
{
|
||||
while (true) {
|
||||
struct epoll_event epoll_events[RUNTIME_MAX_EPOLL_EVENTS];
|
||||
int descriptor_count = epoll_wait(worker_thread_epoll_file_descriptor, epoll_events,
|
||||
RUNTIME_MAX_EPOLL_EVENTS, 0);
|
||||
|
||||
if (descriptor_count < 0) {
|
||||
if (errno == EINTR) continue;
|
||||
|
||||
panic_err();
|
||||
}
|
||||
|
||||
if (descriptor_count == 0) break;
|
||||
|
||||
for (int i = 0; i < descriptor_count; i++) {
|
||||
if (epoll_events[i].events & (EPOLLIN | EPOLLOUT)) {
|
||||
/* Re-add to runqueue if asleep */
|
||||
struct sandbox *sandbox = (struct sandbox *)epoll_events[i].data.ptr;
|
||||
assert(sandbox);
|
||||
|
||||
if (sandbox->state == SANDBOX_ASLEEP) { sandbox_wakeup(sandbox); }
|
||||
} else if (epoll_events[i].events & (EPOLLERR | EPOLLHUP)) {
|
||||
/* Close socket and set as error on socket error or unexpected client hangup */
|
||||
struct sandbox *sandbox = (struct sandbox *)epoll_events[i].data.ptr;
|
||||
int error = 0;
|
||||
socklen_t errlen = sizeof(error);
|
||||
getsockopt(epoll_events[i].data.fd, SOL_SOCKET, SO_ERROR, (void *)&error, &errlen);
|
||||
|
||||
if (error > 0) {
|
||||
debuglog("Socket error: %s", strerror(error));
|
||||
} else if (epoll_events[i].events & EPOLLHUP) {
|
||||
debuglog("Client Hungup");
|
||||
} else {
|
||||
debuglog("Unknown Socket error");
|
||||
}
|
||||
|
||||
switch (sandbox->state) {
|
||||
case SANDBOX_RETURNED:
|
||||
case SANDBOX_COMPLETE:
|
||||
case SANDBOX_ERROR:
|
||||
panic("Expected to have closed socket");
|
||||
default:
|
||||
sandbox_set_as_error(sandbox, sandbox->state);
|
||||
}
|
||||
} else {
|
||||
panic("Mystery epoll event!\n");
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include "worker_thread.h"
|
||||
|
||||
static inline void
|
||||
worker_thread_epoll_add_sandbox(struct sandbox *sandbox)
|
||||
{
|
||||
assert(sandbox != NULL);
|
||||
/* Freshly allocated sandbox going runnable for first time, so register client socket with epoll */
|
||||
struct epoll_event accept_evt;
|
||||
accept_evt.data.ptr = (void *)sandbox;
|
||||
accept_evt.events = EPOLLIN | EPOLLOUT | EPOLLET;
|
||||
int rc = epoll_ctl(worker_thread_epoll_file_descriptor, EPOLL_CTL_ADD, sandbox->http->socket, &accept_evt);
|
||||
if (unlikely(rc < 0)) panic_err();
|
||||
}
|
||||
|
||||
static inline void
|
||||
worker_thread_epoll_remove_sandbox(struct sandbox *sandbox)
|
||||
{
|
||||
assert(sandbox != NULL);
|
||||
int rc = epoll_ctl(worker_thread_epoll_file_descriptor, EPOLL_CTL_DEL, sandbox->http->socket, NULL);
|
||||
if (unlikely(rc < 0)) panic_err();
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
#include "admissions_info.h"
|
||||
#include "debuglog.h"
|
||||
|
||||
/**
|
||||
* Initializes perf window
|
||||
* @param admissions_info
|
||||
*/
|
||||
void
|
||||
admissions_info_initialize(struct admissions_info *admissions_info, uint8_t percentile, uint64_t expected_execution,
|
||||
uint64_t relative_deadline)
|
||||
{
|
||||
#ifdef ADMISSIONS_CONTROL
|
||||
assert(relative_deadline > 0);
|
||||
assert(expected_execution > 0);
|
||||
admissions_info->relative_deadline = relative_deadline;
|
||||
admissions_info->estimate = admissions_control_calculate_estimate(expected_execution, relative_deadline);
|
||||
debuglog("Initial Estimate: %lu\n", admissions_info->estimate);
|
||||
assert(admissions_info != NULL);
|
||||
|
||||
perf_window_initialize(&admissions_info->perf_window);
|
||||
|
||||
if (unlikely(percentile < 50 || percentile > 99)) panic("Invalid admissions percentile");
|
||||
admissions_info->percentile = percentile;
|
||||
|
||||
admissions_info->control_index = PERF_WINDOW_BUFFER_SIZE * percentile / 100;
|
||||
#ifdef LOG_ADMISSIONS_CONTROL
|
||||
debuglog("Percentile: %u\n", admissions_info->percentile);
|
||||
debuglog("Control Index: %d\n", admissions_info->control_index);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Adds an execution value to the perf window and calculates and caches and updated estimate
|
||||
* @param admissions_info
|
||||
* @param execution_duration
|
||||
*/
|
||||
void
|
||||
admissions_info_update(struct admissions_info *admissions_info, uint64_t execution_duration)
|
||||
{
|
||||
#ifdef ADMISSIONS_CONTROL
|
||||
struct perf_window *perf_window = &admissions_info->perf_window;
|
||||
|
||||
LOCK_LOCK(&admissions_info->perf_window.lock);
|
||||
perf_window_add(perf_window, execution_duration);
|
||||
uint64_t estimated_execution = perf_window_get_percentile(perf_window, admissions_info->percentile,
|
||||
admissions_info->control_index);
|
||||
admissions_info->estimate = admissions_control_calculate_estimate(estimated_execution,
|
||||
admissions_info->relative_deadline);
|
||||
LOCK_UNLOCK(&admissions_info->perf_window.lock);
|
||||
#endif
|
||||
}
|
@ -1,50 +0,0 @@
|
||||
#ifdef EXECUTION_HISTOGRAM
|
||||
|
||||
#include "execution_histogram.h"
|
||||
#include "debuglog.h"
|
||||
#include "perf_window.h"
|
||||
|
||||
/**
|
||||
* Initializes execution_histogram and its perf window
|
||||
* @param execution_histogram
|
||||
*/
|
||||
void
|
||||
execution_histogram_initialize(struct execution_histogram *execution_histogram, uint8_t percentile,
|
||||
uint64_t expected_execution)
|
||||
{
|
||||
assert(expected_execution > 0);
|
||||
execution_histogram->estimated_execution = expected_execution;
|
||||
|
||||
assert(execution_histogram != NULL);
|
||||
perf_window_initialize(&execution_histogram->perf_window);
|
||||
|
||||
if (unlikely(percentile < 50 || percentile > 99)) panic("Invalid percentile");
|
||||
execution_histogram->percentile = percentile;
|
||||
execution_histogram->control_index = PERF_WINDOW_CAPACITY * percentile / 100;
|
||||
#ifdef LOG_EXECUTION_HISTOGRAM
|
||||
debuglog("Percentile: %u\n", execution_histogram->percentile);
|
||||
debuglog("Control Index: %d\n", execution_histogram->control_index);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Adds an execution value to the perf window
|
||||
* @param execution_histogram
|
||||
* @param execution_duration
|
||||
*/
|
||||
void
|
||||
execution_histogram_update(struct execution_histogram *execution_histogram, uint64_t execution_duration)
|
||||
{
|
||||
struct perf_window *perf_window = &execution_histogram->perf_window;
|
||||
|
||||
lock_node_t node = {};
|
||||
lock_lock(&perf_window->lock, &node);
|
||||
perf_window_add(perf_window, execution_duration);
|
||||
uint64_t estimated_execution = perf_window_get_percentile(perf_window, execution_histogram->percentile,
|
||||
execution_histogram->control_index);
|
||||
execution_histogram->estimated_execution = estimated_execution;
|
||||
lock_unlock(&perf_window->lock, &node);
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,39 @@
|
||||
#include <stdint.h>
|
||||
#include <threads.h>
|
||||
|
||||
#include "arch/getcycles.h"
|
||||
#include "debuglog.h"
|
||||
|
||||
extern uint32_t runtime_processor_speed_MHz;
|
||||
extern uint32_t runtime_quantum_us;
|
||||
|
||||
/* Implemented by listener and workers */
|
||||
|
||||
thread_local uint64_t generic_thread_lock_duration = 0;
|
||||
thread_local uint64_t generic_thread_lock_longest = 0;
|
||||
thread_local uint64_t generic_thread_start_timestamp = 0;
|
||||
|
||||
void
|
||||
generic_thread_initialize()
|
||||
{
|
||||
generic_thread_start_timestamp = __getcycles();
|
||||
generic_thread_lock_longest = 0;
|
||||
generic_thread_lock_duration = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports lock contention
|
||||
*/
|
||||
void
|
||||
generic_thread_dump_lock_overhead()
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
#ifdef LOG_LOCK_OVERHEAD
|
||||
uint64_t duration = __getcycles() - generic_thread_start_timestamp;
|
||||
debuglog("Locks consumed %lu / %lu cycles, or %f%%\n", generic_thread_lock_duration, duration,
|
||||
(double)generic_thread_lock_duration / duration * 100);
|
||||
debuglog("Longest Held Lock was %lu cycles, or %f quantums\n", generic_thread_lock_longest,
|
||||
(double)generic_thread_lock_longest / ((uint64_t)runtime_processor_speed_MHz * runtime_quantum_us));
|
||||
#endif
|
||||
#endif
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue