Merge pull request #355 from gwsystems/feat-prometheus

feat: Initial metrics server
master
Sean McBride 2 years ago committed by GitHub
commit 92ac9b056f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -125,7 +125,8 @@
"pool.h": "c",
"local_cleanup_queue.h": "c",
"sandbox_state_transition.h": "c",
"http_session_perf_log.h": "c"
"http_session_perf_log.h": "c",
"perf_window.h": "c"
},
"files.exclude": {
"**/.git": true,

@ -75,10 +75,17 @@ BINARY_NAME=sledgert
# page is allocated. This helps understand the relationship to memory allocation and execution time.
# CFLAGS += -DLOG_SANDBOX_MEMORY_PROFILE
# This flag dumps totals of incoming requests and outgoing responses, broken out by status code
# family, such as 2XX, 4XX, 5XX. It is useful to debug clients hanging waiting for a response.
# This flag enables runtime-level metrics from procfs
# CFLAGS += -DPROC_STAT_METRICS
# This flag enables HTTP-level counters of incoming requests and outgoing responses, broken out by status code
# family, such as 2XX, 4XX, 5XX.
# To log, run `call http_total_log()` while in GDB
# CFLAGS += -DLOG_TOTAL_REQS_RESPS
# CFLAGS += -DHTTP_TOTAL_COUNTERS
# This flag enables per-route counters of incoming requests and outgoing responses, broken out by status code
# family, such as 2XX, 4XX, 5XX.
# CFLAGS += -DHTTP_ROUTE_TOTAL_COUNTERS
# This flag tracks the total number of sandboxes in the various states
# It is useful to debug if sandboxes are "getting caught" in a particular state

@ -3,7 +3,11 @@
#include <stdbool.h>
#include <stdint.h>
#ifdef ADMISSIONS_CONTROL
#define ADMISSIONS_CONTROL_GRANULARITY 1000000
extern _Atomic uint64_t admissions_control_admitted;
extern uint64_t admissions_control_capacity;
#endif
void admissions_control_initialize(void);
void admissions_control_add(uint64_t admissions_estimate);

@ -0,0 +1,9 @@
#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,
};

@ -5,8 +5,8 @@
#include "http_total.h"
#include "panic.h"
#define HTTP_MAX_HEADER_COUNT 16
#define HTTP_MAX_HEADER_LENGTH 32
#define HTTP_MAX_HEADER_COUNT 32
#define HTTP_MAX_HEADER_LENGTH 64
#define HTTP_MAX_HEADER_VALUE_LENGTH 256
#define HTTP_MAX_FULL_URL_LENGTH 256
@ -63,38 +63,22 @@
static inline const char *
http_header_build(int status_code)
{
const char *response;
int rc;
switch (status_code) {
case 400:
response = HTTP_RESPONSE_400_BAD_REQUEST;
http_total_increment_4XX();
break;
return HTTP_RESPONSE_400_BAD_REQUEST;
case 404:
response = HTTP_RESPONSE_404_NOT_FOUND;
http_total_increment_4XX();
break;
return HTTP_RESPONSE_404_NOT_FOUND;
case 413:
response = HTTP_RESPONSE_413_PAYLOAD_TOO_LARGE;
http_total_increment_4XX();
break;
return HTTP_RESPONSE_413_PAYLOAD_TOO_LARGE;
case 429:
response = HTTP_RESPONSE_429_TOO_MANY_REQUESTS;
http_total_increment_4XX();
break;
return HTTP_RESPONSE_429_TOO_MANY_REQUESTS;
case 500:
response = HTTP_RESPONSE_500_INTERNAL_SERVER_ERROR;
http_total_increment_5XX();
break;
return HTTP_RESPONSE_500_INTERNAL_SERVER_ERROR;
case 503:
response = HTTP_RESPONSE_503_SERVICE_UNAVAILABLE;
http_total_increment_5XX();
break;
return HTTP_RESPONSE_503_SERVICE_UNAVAILABLE;
default:
panic("%d is not a valid status code\n", status_code);
}
return response;
}
static inline size_t

@ -0,0 +1,48 @@
#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
}

@ -37,6 +37,8 @@ http_router_add_route(http_router_t *router, struct route_config *config, struct
.response_size = config->http_resp_size,
.response_content_type = config->http_resp_content_type };
http_route_total_init(&route.metrics);
/* Admissions Control */
uint64_t expected_execution = (uint64_t)config->expected_execution_us * runtime_processor_speed_MHz;
admissions_info_initialize(&route.admissions_info, config->admissions_percentile, expected_execution,
@ -59,3 +61,9 @@ http_router_match_route(http_router_t *router, char *route)
return NULL;
}
static inline void
http_router_foreach(http_router_t *router, void (*cb)(route_t *, void *, void *), void *arg_one, void *arg_two)
{
for (int i = 0; i < router->length; i++) { cb(&router->buffer[i], arg_one, arg_two); }
}

@ -9,14 +9,18 @@
#include <sys/socket.h>
#include <unistd.h>
#include "tcp_session.h"
#include "debuglog.h"
#include "http_request.h"
#include "epoll_tag.h"
#include "http_parser.h"
#include "http_parser_settings.h"
#include "http_request.h"
#include "http_route_total.h"
#include "http_session_perf_log.h"
#include "http_total.h"
#include "route.h"
#include "tcp_session.h"
#include "tenant.h"
#include "vec.h"
#include "http_session_perf_log.h"
#define HTTP_SESSION_DEFAULT_REQUEST_RESPONSE_SIZE (PAGE_SIZE)
#define HTTP_SESSION_RESPONSE_HEADER_CAPACITY 256
@ -42,6 +46,7 @@ enum http_session_state
};
struct http_session {
enum epoll_tag tag;
enum http_session_state state;
struct sockaddr client_address; /* client requesting connection! */
int socket;
@ -54,6 +59,7 @@ struct http_session {
struct vec_u8 response_buffer;
size_t response_buffer_written;
struct tenant *tenant; /* Backlink required when read blocks on listener core */
struct route *route; /* Backlink required to handle http metrics */
uint64_t request_arrival_timestamp;
uint64_t request_downloaded_timestamp;
uint64_t response_takeoff_timestamp;
@ -89,7 +95,9 @@ http_session_init(struct http_session *session, int socket_descriptor, const str
assert(socket_descriptor >= 0);
assert(socket_address != NULL);
session->tag = EPOLL_TAG_HTTP_SESSION_CLIENT_SOCKET;
session->tenant = tenant;
session->route = NULL;
session->socket = socket_descriptor;
session->request_arrival_timestamp = request_arrival_timestamp;
memcpy(&session->client_address, socket_address, sizeof(struct sockaddr));
@ -174,6 +182,10 @@ http_session_set_response_header(struct http_session *session, int status_code,
{
assert(session != NULL);
assert(status_code >= 200 && status_code <= 599);
http_total_increment_response(status_code);
/* We might not have actually matched a route */
if (likely(session->route != NULL)) { http_route_total_increment(&session->route->metrics, status_code); }
if (status_code == 200) {
session->response_header_length = snprintf(session->response_header,
@ -185,7 +197,7 @@ http_session_set_response_header(struct http_session *session, int status_code,
? HTTP_SESSION_RESPONSE_HEADER_CAPACITY
: header_len;
strncpy(session->response_header, http_header_build(status_code), to_copy - 1);
strncpy(session->response_header, http_header_build(status_code), to_copy);
session->response_header_length = to_copy;
}

@ -9,10 +9,9 @@
* behind a compiler flag. 2XX and 4XX can be incremented by worker cores, so they are behind a flag because
* of concerns about contention
*/
#ifdef HTTP_TOTAL_COUNTERS
extern _Atomic uint32_t http_total_requests;
extern _Atomic uint32_t http_total_5XX;
#ifdef LOG_TOTAL_REQS_RESPS
extern _Atomic uint32_t http_total_2XX;
extern _Atomic uint32_t http_total_4XX;
#endif
@ -20,38 +19,32 @@ extern _Atomic uint32_t http_total_4XX;
static inline void
http_total_init()
{
#ifdef HTTP_TOTAL_COUNTERS
atomic_init(&http_total_requests, 0);
atomic_init(&http_total_5XX, 0);
#ifdef LOG_TOTAL_REQS_RESPS
atomic_init(&http_total_2XX, 0);
atomic_init(&http_total_4XX, 0);
atomic_init(&http_total_5XX, 0);
#endif
}
static inline void
http_total_increment_request()
{
#ifdef HTTP_TOTAL_COUNTERS
atomic_fetch_add(&http_total_requests, 1);
}
static inline void
http_total_increment_2XX()
{
#ifdef LOG_TOTAL_REQS_RESPS
atomic_fetch_add(&http_total_2XX, 1);
#endif
}
static inline void
http_total_increment_4XX()
http_total_increment_response(int status_code)
{
#ifdef LOG_TOTAL_REQS_RESPS
atomic_fetch_add(&http_total_4XX, 1);
#ifdef HTTP_TOTAL_COUNTERS
if (status_code >= 200 && status_code <= 299) {
atomic_fetch_add(&http_total_2XX, 1);
} else if (status_code >= 400 && status_code <= 499) {
atomic_fetch_add(&http_total_4XX, 1);
} else if (status_code >= 500 && status_code <= 599) {
atomic_fetch_add(&http_total_5XX, 1);
}
#endif
}
static inline void
http_total_increment_5XX()
{
atomic_fetch_add(&http_total_5XX, 1);
}

@ -0,0 +1,17 @@
#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;
void metrics_server_init();
void metrics_server_thread_spawn(int client_socket);
int metrics_server_close();

@ -21,8 +21,8 @@ perf_window_initialize(struct perf_window *perf_window)
lock_init(&perf_window->lock);
perf_window->count = 0;
memset(perf_window->by_duration, 0, sizeof(struct execution_node) * perf_window_capacity);
memset(perf_window->by_termination, 0, sizeof(uint16_t) * perf_window_capacity);
memset(perf_window->by_duration, 0, sizeof(struct execution_node) * PERF_WINDOW_CAPACITY);
memset(perf_window->by_termination, 0, sizeof(uint16_t) * PERF_WINDOW_CAPACITY);
}
@ -38,8 +38,8 @@ perf_window_swap(struct perf_window *perf_window, uint16_t first_by_duration_idx
{
assert(lock_is_locked(&perf_window->lock));
assert(perf_window != NULL);
assert(first_by_duration_idx < perf_window_capacity);
assert(second_by_duration_idx < perf_window_capacity);
assert(first_by_duration_idx < PERF_WINDOW_CAPACITY);
assert(second_by_duration_idx < PERF_WINDOW_CAPACITY);
uint16_t first_by_termination_idx = perf_window->by_duration[first_by_duration_idx].by_termination_idx;
uint16_t second_by_termination_idx = perf_window->by_duration[second_by_duration_idx].by_termination_idx;
@ -70,12 +70,12 @@ perf_window_swap(struct perf_window *perf_window, uint16_t first_by_duration_idx
static inline void
perf_window_fill(struct perf_window *perf_window, uint64_t newest_execution_time)
{
for (uint16_t i = 0; i < perf_window_capacity; i++) {
for (uint16_t i = 0; i < PERF_WINDOW_CAPACITY; i++) {
perf_window->by_termination[i] = i;
perf_window->by_duration[i] = (struct execution_node){ .execution_time = newest_execution_time,
.by_termination_idx = i };
}
perf_window->count = perf_window_capacity;
perf_window->count = PERF_WINDOW_CAPACITY;
}
/**
@ -104,7 +104,7 @@ perf_window_add(struct perf_window *perf_window, uint64_t newest_execution_time)
}
/* If full, replace the oldest execution_time. Save the old execution time to know which direction to swap */
idx_to_replace = perf_window->by_termination[perf_window->count % perf_window_capacity];
idx_to_replace = perf_window->by_termination[perf_window->count % PERF_WINDOW_CAPACITY];
previous_execution_time = perf_window->by_duration[idx_to_replace].execution_time;
perf_window->by_duration[idx_to_replace].execution_time = newest_execution_time;
@ -112,7 +112,7 @@ perf_window_add(struct perf_window *perf_window, uint64_t newest_execution_time)
* right. We can determine which direction to shift by comparing with the previous execution time. */
if (newest_execution_time > previous_execution_time) {
for (uint16_t i = idx_to_replace;
i + 1 < perf_window_capacity
i + 1 < PERF_WINDOW_CAPACITY
&& perf_window->by_duration[i + 1].execution_time < perf_window->by_duration[i].execution_time;
i++) {
perf_window_swap(perf_window, i, i + 1);
@ -127,13 +127,13 @@ perf_window_add(struct perf_window *perf_window, uint64_t newest_execution_time)
}
/* The idx that we replaces should still point to the same newest_execution_time */
assert(perf_window->by_duration[perf_window->by_termination[perf_window->count % perf_window_capacity]]
assert(perf_window->by_duration[perf_window->by_termination[perf_window->count % PERF_WINDOW_CAPACITY]]
.execution_time
== newest_execution_time);
/* The by_duration array should be ordered by execution time */
#ifndef NDEBUG
for (int i = 1; i < perf_window_capacity; i++) {
for (int i = 1; i < PERF_WINDOW_CAPACITY; i++) {
assert(perf_window->by_duration[i - 1].execution_time <= perf_window->by_duration[i].execution_time);
}
#endif
@ -156,10 +156,11 @@ perf_window_get_percentile(struct perf_window *perf_window, uint8_t percentile,
{
assert(perf_window != NULL);
assert(percentile >= 50 && percentile <= 99);
assert(perf_window->count > 0);
if (unlikely(perf_window->count == 0)) return 0;
int idx = precomputed_index;
if (unlikely(perf_window->count < perf_window_capacity)) idx = perf_window->count * percentile / 100;
if (unlikely(perf_window->count < PERF_WINDOW_CAPACITY)) idx = perf_window->count * percentile / 100;
return perf_window->by_duration[idx].execution_time;
}

@ -7,13 +7,13 @@
enum
{
perf_window_capacity = 32
PERF_WINDOW_CAPACITY = 32
};
static_assert(perf_window_capacity && !(perf_window_capacity & (perf_window_capacity - 1)),
"perf_window_capacity must be power of 2!");
static_assert(PERF_WINDOW_CAPACITY && !(PERF_WINDOW_CAPACITY & (PERF_WINDOW_CAPACITY - 1)),
"PERF_WINDOW_CAPACITY must be power of 2!");
static_assert(perf_window_capacity <= UINT16_MAX, "perf_window_capacity must be indexable by a 16-bit unsigned int");
static_assert(PERF_WINDOW_CAPACITY <= UINT16_MAX, "PERF_WINDOW_CAPACITY must be indexable by a 16-bit unsigned int");
/*
* The by_duration array sorts the last N executions by execution time
@ -28,8 +28,8 @@ struct execution_node {
};
struct perf_window {
struct execution_node by_duration[perf_window_capacity];
uint16_t by_termination[perf_window_capacity];
struct execution_node by_duration[PERF_WINDOW_CAPACITY];
uint16_t by_termination[PERF_WINDOW_CAPACITY];
uint64_t count;
lock_t lock;
};

@ -0,0 +1,103 @@
#pragma once
#include <assert.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdio.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);
}

@ -5,11 +5,13 @@
#include "admissions_info.h"
#include "module.h"
#include "http_route_total.h"
/* Assumption: entrypoint is always _start. This should be enhanced later */
struct route {
char *route;
struct module *module;
char *route;
struct http_route_total metrics;
struct module *module;
/* HTTP State */
uint32_t relative_deadline_us;
uint64_t relative_deadline; /* cycles */

@ -2,6 +2,7 @@
#include <pthread.h>
#include <sys/epoll.h> /* for epoll_create1(), epoll_ctl(), struct epoll_event */
#include <sys/types.h> /* for pid_t */
#include <stdatomic.h>
#include <stdbool.h>
@ -34,6 +35,7 @@ enum RUNTIME_SIGALRM_HANDLER
RUNTIME_SIGALRM_HANDLER_TRIAGED = 1
};
extern pid_t runtime_pid;
extern bool runtime_preemption_enabled;
extern uint32_t runtime_processor_speed_MHz;
extern uint32_t runtime_quantum_us;

@ -1,5 +1,6 @@
#pragma once
#include "epoll_tag.h"
#include "http_router.h"
#include "map.h"
#include "module_database.h"
@ -32,6 +33,7 @@ struct tenant_global_request_queue {
};
struct tenant {
enum epoll_tag tag; /* Tag must be first member */
char *name;
struct tcp_server tcp_server;
http_router_t router;

@ -20,6 +20,9 @@ struct tenant *tenant_database_find_by_socket_descriptor(int socket_descriptor);
struct tenant *tenant_database_find_by_port(uint16_t port);
struct tenant *tenant_database_find_by_ptr(void *ptr);
typedef void (*tenant_database_foreach_cb_t)(struct tenant *, void *, void *);
void tenant_database_foreach(tenant_database_foreach_cb_t, void *, void *);
static inline int
tenant_policy_specific_init(struct tenant *tenant, struct tenant_config *config)
{
@ -84,6 +87,7 @@ tenant_alloc(struct tenant_config *config)
struct tenant *tenant = (struct tenant *)calloc(1, sizeof(struct tenant));
/* Move name */
tenant->tag = EPOLL_TAG_TENANT_SERVER_SOCKET;
tenant->name = config->name;
config->name = NULL;

@ -1,3 +1,4 @@
#include <assert.h>
#include <stdatomic.h>
#include <unistd.h>
@ -17,10 +18,12 @@
* These estimates are incremented on request acceptance and decremented on request completion (either
* success or failure)
*/
#ifdef ADMISSIONS_CONTROL
_Atomic uint64_t admissions_control_admitted;
uint64_t admissions_control_capacity;
const double admissions_control_overhead = 0.2;
const double admissions_control_overhead = 0.2;
#endif
void
admissions_control_initialize()
@ -92,10 +95,12 @@ admissions_control_calculate_estimate_us(uint32_t estimated_execution_us, uint32
void
admissions_control_log_decision(uint64_t admissions_estimate, bool admitted)
{
#ifdef ADMISSIONS_CONTROL
#ifdef LOG_ADMISSIONS_CONTROL
debuglog("Admitted: %lu, Capacity: %lu, Estimate: %lu, Admitted? %s\n", admissions_control_admitted,
admissions_control_capacity, admissions_estimate, admitted ? "yes" : "no");
#endif /* LOG_ADMISSIONS_CONTROL */
#endif /* ADMISSIONS_CONTROL */
}
uint64_t

@ -24,7 +24,7 @@ admissions_info_initialize(struct admissions_info *admissions_info, uint8_t perc
if (unlikely(percentile < 50 || percentile > 99)) panic("Invalid admissions percentile");
admissions_info->percentile = percentile;
admissions_info->control_index = perf_window_capacity * percentile / 100;
admissions_info->control_index = PERF_WINDOW_CAPACITY * percentile / 100;
#ifdef LOG_ADMISSIONS_CONTROL
debuglog("Percentile: %u\n", admissions_info->percentile);
debuglog("Control Index: %d\n", admissions_info->control_index);

@ -5,31 +5,26 @@
/* 2XX + 4XX should equal sandboxes */
/* Listener Core Bookkeeping */
#ifdef HTTP_TOTAL_COUNTERS
_Atomic uint32_t http_total_requests = 0;
_Atomic uint32_t http_total_5XX = 0;
#ifdef LOG_TOTAL_REQS_RESPS
_Atomic uint32_t http_total_2XX = 0;
_Atomic uint32_t http_total_4XX = 0;
_Atomic uint32_t http_total_2XX = 0;
_Atomic uint32_t http_total_4XX = 0;
#endif
/* Primarily intended to be called via GDB */
void
http_total_log()
{
uint32_t total_reqs = atomic_load(&http_total_requests);
uint32_t total_5XX = atomic_load(&http_total_5XX);
#ifdef LOG_TOTAL_REQS_RESPS
uint32_t total_2XX = atomic_load(&http_total_2XX);
uint32_t total_4XX = atomic_load(&http_total_4XX);
int64_t total_responses = total_2XX + total_4XX + total_5XX;
int64_t outstanding_requests = (int64_t)total_reqs - total_responses;
#ifdef HTTP_TOTAL_COUNTERS
uint32_t total_reqs = atomic_load(&http_total_requests);
uint32_t total_2XX = atomic_load(&http_total_2XX);
uint32_t total_4XX = atomic_load(&http_total_4XX);
uint32_t total_5XX = atomic_load(&http_total_5XX);
int64_t total_responses = total_2XX + total_4XX + total_5XX;
int64_t outstanding_requests = (int64_t)total_reqs - total_responses;
debuglog("Requests: %u (%ld outstanding)\n\tResponses: %ld\n\t\t2XX: %u\n\t\t4XX: %u\n\t\t5XX: %u\n",
total_reqs, outstanding_requests, total_responses, total_2XX, total_4XX, total_5XX);
#else
debuglog("Requests: %u\n\tResponses:\n\t\t\t5XX: %u\n", total_reqs, total_5XX);
#endif
};

@ -4,6 +4,7 @@
#include "arch/getcycles.h"
#include "global_request_scheduler.h"
#include "listener_thread.h"
#include "metrics_server.h"
#include "module.h"
#include "runtime.h"
#include "sandbox_functions.h"
@ -133,6 +134,23 @@ listener_thread_register_tenant(struct tenant *tenant)
return rc;
}
int
listener_thread_register_metrics_server()
{
if (unlikely(listener_thread_epoll_file_descriptor == 0)) {
panic("Attempting to register metrics_server before listener thread initialization");
}
int rc = 0;
struct epoll_event accept_evt;
accept_evt.data.ptr = (void *)&metrics_server;
accept_evt.events = EPOLLIN;
rc = epoll_ctl(listener_thread_epoll_file_descriptor, EPOLL_CTL_ADD, metrics_server.tcp.socket_descriptor,
&accept_evt);
return rc;
}
static void
panic_on_epoll_error(struct epoll_event *evt)
{
@ -214,6 +232,8 @@ on_client_request_received(struct http_session *session)
return;
}
session->route = route;
/*
* Perform admissions control.
* If 0, workload was rejected, so close with 429 "Too Many Requests" and continue
@ -323,6 +343,30 @@ on_tenant_socket_epoll_event(struct epoll_event *evt)
}
}
static void
on_metrics_server_epoll_event(struct epoll_event *evt)
{
assert((evt->events & EPOLLIN) == EPOLLIN);
/* Accept Client Request as a nonblocking socket, saving address information */
struct sockaddr_in client_address;
socklen_t address_length = sizeof(client_address);
/* Accept as many clients requests as possible, returning when we would have blocked */
while (true) {
/* We accept the client connection with blocking semantics because we spawn ephemeral worker threads */
int client_socket = accept4(metrics_server.tcp.socket_descriptor, (struct sockaddr *)&client_address,
&address_length, 0);
if (unlikely(client_socket < 0)) {
if (errno == EWOULDBLOCK || errno == EAGAIN) return;
panic("accept4: %s", strerror(errno));
}
metrics_server_thread_spawn(client_socket);
}
}
static void
on_client_socket_epoll_event(struct epoll_event *evt)
{
@ -366,6 +410,9 @@ listener_thread_main(void *dummy)
{
struct epoll_event epoll_events[RUNTIME_MAX_EPOLL_EVENTS];
metrics_server_init();
listener_thread_register_metrics_server();
/* Set my priority */
// runtime_set_pthread_prio(pthread_self(), 2);
pthread_setschedprio(pthread_self(), -20);
@ -386,10 +433,20 @@ listener_thread_main(void *dummy)
for (int i = 0; i < descriptor_count; i++) {
panic_on_epoll_error(&epoll_events[i]);
if (tenant_database_find_by_ptr(epoll_events[i].data.ptr) != NULL) {
enum epoll_tag tag = *(enum epoll_tag *)epoll_events[i].data.ptr;
switch (tag) {
case EPOLL_TAG_TENANT_SERVER_SOCKET:
on_tenant_socket_epoll_event(&epoll_events[i]);
} else {
break;
case EPOLL_TAG_HTTP_SESSION_CLIENT_SOCKET:
on_client_socket_epoll_event(&epoll_events[i]);
break;
case EPOLL_TAG_METRICS_SERVER_SOCKET:
on_metrics_server_epoll_event(&epoll_events[i]);
break;
default:
panic("Unknown epoll type!");
}
}
}

@ -7,6 +7,7 @@
#include <sched.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#ifdef LOG_TO_FILE
@ -39,6 +40,7 @@ enum RUNTIME_SIGALRM_HANDLER runtime_sigalrm_handler = RUNTIME_SIGALRM_HANDLER_B
bool runtime_preemption_enabled = true;
uint32_t runtime_quantum_us = 5000; /* 5ms */
uint64_t runtime_boot_timestamp;
pid_t runtime_pid = 0;
/**
* Returns instructions on use of CLI if used incorrectly
@ -317,10 +319,22 @@ log_compiletime_config()
pretty_print_key_disabled("Log State Changes");
#endif
#ifdef LOG_TOTAL_REQS_RESPS
pretty_print_key_enabled("Log Total Reqs/Resps");
#ifdef HTTP_TOTAL_COUNTERS
pretty_print_key_enabled("HTTP Total Counters");
#else
pretty_print_key_disabled("HTTP Total Counters");
#endif
#ifdef HTTP_ROUTE_TOTAL_COUNTERS
pretty_print_key_enabled("HTTP Route Total Counters");
#else
pretty_print_key_disabled("Log Total Reqs/Resps");
pretty_print_key_disabled("HTTP Route Total Counters");
#endif
#ifdef PROC_STAT_METRICS
pretty_print_key_enabled("procfs Metrics");
#else
pretty_print_key_disabled("procfs Metrics");
#endif
#ifdef SANDBOX_STATE_TOTALS
@ -424,6 +438,8 @@ main(int argc, char **argv)
exit(-1);
}
runtime_pid = getpid();
printf("Starting the Sledge runtime\n");
log_compiletime_config();

@ -0,0 +1,228 @@
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "admissions_control.h"
#include "debuglog.h"
#include "http.h"
#include "http_total.h"
#include "metrics_server.h"
#include "proc_stat.h"
#include "runtime.h"
#include "sandbox_total.h"
#include "sandbox_state.h"
#include "tcp_server.h"
/* We run threads on the "reserved OS core" using blocking semantics */
#define METRICS_SERVER_CORE_ID 0
#define METRICS_SERVER_PORT 1776
struct metrics_server metrics_server;
static void *metrics_server_handler(void *arg);
extern void metrics_server_route_level_metrics_render(FILE *ostream);
void
metrics_server_init()
{
metrics_server.tag = EPOLL_TAG_METRICS_SERVER_SOCKET;
tcp_server_init(&metrics_server.tcp, METRICS_SERVER_PORT);
int rc = tcp_server_listen(&metrics_server.tcp);
assert(rc == 0);
/* Configure pthread attributes to pin metrics server threads to CPU 0 */
pthread_attr_init(&metrics_server.thread_settings);
cpu_set_t cs;
CPU_ZERO(&cs);
CPU_SET(METRICS_SERVER_CORE_ID, &cs);
pthread_attr_setaffinity_np(&metrics_server.thread_settings, sizeof(cpu_set_t), &cs);
}
int
metrics_server_close()
{
return tcp_server_close(&metrics_server.tcp);
}
void
metrics_server_thread_spawn(int client_socket)
{
/* Duplicate fd so fclose doesn't close the actual client_socket */
int temp_fd = dup(client_socket);
FILE *req_body = fdopen(temp_fd, "r");
/* Basic L7 routing to filter out favicon requests */
char http_status_code_buf[256];
fgets(http_status_code_buf, 256, req_body);
fclose(req_body);
if (strncmp(http_status_code_buf, "GET /metrics HTTP", 10) != 0) {
write(client_socket, http_header_build(404), http_header_len(404));
close(client_socket);
return;
}
/* Fire and forget, so we don't save the thread handles */
pthread_t metrics_server_thread;
int rc = pthread_create(&metrics_server_thread, &metrics_server.thread_settings, metrics_server_handler,
(void *)(long)client_socket);
if (rc != 0) {
debuglog("Metrics Server failed to spawn pthread with %s\n", strerror(rc));
close(client_socket);
}
}
static void *
metrics_server_handler(void *arg)
{
/* Intermediate cast to integral value of 64-bit width to silence compiler nits */
int client_socket = (int)(long)arg;
int rc = 0;
char *ostream_base = NULL;
size_t ostream_size = 0;
FILE *ostream = open_memstream(&ostream_base, &ostream_size);
assert(ostream != NULL);
#ifdef HTTP_TOTAL_COUNTERS
uint32_t total_reqs = atomic_load(&http_total_requests);
uint32_t total_5XX = atomic_load(&http_total_5XX);
uint32_t total_2XX = atomic_load(&http_total_2XX);
uint32_t total_4XX = atomic_load(&http_total_4XX);
#endif
uint32_t total_sandboxes = atomic_load(&sandbox_total);
#ifdef SANDBOX_STATE_TOTALS
uint32_t total_sandboxes_uninitialized = atomic_load(&sandbox_state_totals[SANDBOX_UNINITIALIZED]);
uint32_t total_sandboxes_allocated = atomic_load(&sandbox_state_totals[SANDBOX_ALLOCATED]);
uint32_t total_sandboxes_initialized = atomic_load(&sandbox_state_totals[SANDBOX_INITIALIZED]);
uint32_t total_sandboxes_runnable = atomic_load(&sandbox_state_totals[SANDBOX_RUNNABLE]);
uint32_t total_sandboxes_preempted = atomic_load(&sandbox_state_totals[SANDBOX_PREEMPTED]);
uint32_t total_sandboxes_running_sys = atomic_load(&sandbox_state_totals[SANDBOX_RUNNING_SYS]);
uint32_t total_sandboxes_running_user = atomic_load(&sandbox_state_totals[SANDBOX_RUNNING_USER]);
uint32_t total_sandboxes_interrupted = atomic_load(&sandbox_state_totals[SANDBOX_INTERRUPTED]);
uint32_t total_sandboxes_asleep = atomic_load(&sandbox_state_totals[SANDBOX_ASLEEP]);
uint32_t total_sandboxes_returned = atomic_load(&sandbox_state_totals[SANDBOX_RETURNED]);
uint32_t total_sandboxes_complete = atomic_load(&sandbox_state_totals[SANDBOX_COMPLETE]);
uint32_t total_sandboxes_error = atomic_load(&sandbox_state_totals[SANDBOX_ERROR]);
#endif
#ifdef ADMISSIONS_CONTROL
uint32_t work_admitted = atomic_load(&admissions_control_admitted);
double work_admitted_percentile = (double)work_admitted / admissions_control_capacity * 100;
#endif
#ifdef PROC_STAT_METRICS
struct proc_stat_metrics stat;
proc_stat_metrics_init(&stat);
#endif
fprintf(ostream, "HTTP/1.1 200 OK\r\n\r\n");
#ifdef PROC_STAT_METRICS
fprintf(ostream, "# TYPE os_proc_major_page_faults counter\n");
fprintf(ostream, "os_proc_major_page_faults: %lu\n", stat.major_page_faults);
fprintf(ostream, "# TYPE os_proc_minor_page_faults counter\n");
fprintf(ostream, "os_proc_minor_page_faults: %lu\n", stat.minor_page_faults);
fprintf(ostream, "# TYPE os_proc_child_major_page_faults counter\n");
fprintf(ostream, "os_proc_child_major_page_faults: %lu\n", stat.child_major_page_faults);
fprintf(ostream, "# TYPE os_proc_child_minor_page_faults counter\n");
fprintf(ostream, "os_proc_child_minor_page_faults: %lu\n", stat.child_minor_page_faults);
fprintf(ostream, "# TYPE os_proc_user_time counter\n");
fprintf(ostream, "os_proc_user_time: %lu\n", stat.user_time);
fprintf(ostream, "# TYPE os_proc_sys_time counter\n");
fprintf(ostream, "os_proc_sys_time: %lu\n", stat.system_time);
fprintf(ostream, "# TYPE os_proc_guest_time counter\n");
fprintf(ostream, "os_proc_guest_time: %lu\n", stat.guest_time);
#endif /* PROC_STAT_METRICS */
#ifdef ADMISSIONS_CONTROL
fprintf(ostream, "# TYPE work_admitted_percentile gauge\n");
fprintf(ostream, "work_admitted_percentile: %f\n", work_admitted_percentile);
#endif
#ifdef HTTP_TOTAL_COUNTERS
fprintf(ostream, "# TYPE total_requests counter\n");
fprintf(ostream, "total_requests: %d\n", total_reqs);
fprintf(ostream, "# TYPE total_2XX counter\n");
fprintf(ostream, "total_2XX: %d\n", total_2XX);
fprintf(ostream, "# TYPE total_4XX counter\n");
fprintf(ostream, "total_4XX: %d\n", total_4XX);
fprintf(ostream, "# TYPE total_5XX counter\n");
fprintf(ostream, "total_5XX: %d\n", total_5XX);
#endif
metrics_server_route_level_metrics_render(ostream);
// This global is padded by 1 for error handling, so decrement here for true value
fprintf(ostream, "# TYPE total_sandboxes counter\n");
fprintf(ostream, "total_sandboxes: %d\n", total_sandboxes - 1);
#ifdef SANDBOX_STATE_TOTALS
fprintf(ostream, "# TYPE total_sandboxes_uninitialized gauge\n");
fprintf(ostream, "total_sandboxes_uninitialized: %d\n", total_sandboxes_uninitialized);
fprintf(ostream, "# TYPE total_sandboxes_allocated gauge\n");
fprintf(ostream, "total_sandboxes_allocated: %d\n", total_sandboxes_allocated);
fprintf(ostream, "# TYPE total_sandboxes_initialized gauge\n");
fprintf(ostream, "total_sandboxes_initialized: %d\n", total_sandboxes_initialized);
fprintf(ostream, "# TYPE total_sandboxes_runnable gauge\n");
fprintf(ostream, "total_sandboxes_runnable: %d\n", total_sandboxes_runnable);
fprintf(ostream, "# TYPE total_sandboxes_preempted gauge\n");
fprintf(ostream, "total_sandboxes_preempted: %d\n", total_sandboxes_preempted);
fprintf(ostream, "# TYPE total_sandboxes_running_sys gauge\n");
fprintf(ostream, "total_sandboxes_running_sys: %d\n", total_sandboxes_running_sys);
fprintf(ostream, "# TYPE total_sandboxes_running_user gauge\n");
fprintf(ostream, "total_sandboxes_running_user: %d\n", total_sandboxes_running_user);
fprintf(ostream, "# TYPE total_sandboxes_interrupted gauge\n");
fprintf(ostream, "total_sandboxes_interrupted: %d\n", total_sandboxes_interrupted);
fprintf(ostream, "# TYPE total_sandboxes_asleep gauge\n");
fprintf(ostream, "total_sandboxes_asleep: %d\n", total_sandboxes_asleep);
fprintf(ostream, "# TYPE total_sandboxes_returned gauge\n");
fprintf(ostream, "total_sandboxes_returned: %d\n", total_sandboxes_returned);
fprintf(ostream, "# TYPE total_sandboxes_complete gauge\n");
fprintf(ostream, "total_sandboxes_complete: %d\n", total_sandboxes_complete);
fprintf(ostream, "# TYPE total_sandboxes_error gauge\n");
fprintf(ostream, "total_sandboxes_error: %d\n", total_sandboxes_error);
#endif
fflush(ostream);
assert(ostream_size > 0);
rc = fclose(ostream);
assert(rc == 0);
/* Closing the memstream does not close the generated buffer */
ssize_t nwritten = write(client_socket, ostream_base, ostream_size);
assert(nwritten == ostream_size);
free(ostream_base);
ostream_size = 0;
close(client_socket);
pthread_exit(NULL);
}

@ -0,0 +1,68 @@
#include <stdatomic.h>
#include <stdint.h>
#include "perf_window.h"
#include "tenant_functions.h"
static const int p50_idx = PERF_WINDOW_CAPACITY * 50 / 100;
static const int p90_idx = PERF_WINDOW_CAPACITY * 90 / 100;
void
render_routes(struct route *route, void *arg_one, void *arg_two)
{
#ifdef HTTP_ROUTE_TOTAL_COUNTERS
FILE *ostream = (FILE *)arg_one;
struct tenant *tenant = (struct tenant *)arg_two;
#ifdef ADMISSIONS_CONTROL
uint64_t latency_p50 = perf_window_get_percentile(&route->admissions_info.perf_window, 50, p50_idx);
uint64_t latency_p90 = perf_window_get_percentile(&route->admissions_info.perf_window, 90, p90_idx);
#endif
uint64_t total_requests = atomic_load(&route->metrics.total_requests);
uint64_t total_2XX = atomic_load(&route->metrics.total_2XX);
uint64_t total_4XX = atomic_load(&route->metrics.total_4XX);
uint64_t total_5XX = atomic_load(&route->metrics.total_5XX);
// Strip leading /
const char *route_label = &route->route[1];
fprintf(ostream, "# TYPE %s_%s_total_requests counter\n", tenant->name, route_label);
fprintf(ostream, "%s_%s_total_requests: %lu\n", tenant->name, route_label, total_requests);
fprintf(ostream, "# TYPE %s_%s_total_2XX counter\n", tenant->name, route_label);
fprintf(ostream, "%s_%s_total_2XX: %lu\n", tenant->name, route_label, total_2XX);
fprintf(ostream, "# TYPE %s_%s_total_4XX counter\n", tenant->name, route_label);
fprintf(ostream, "%s_%s_total_4XX: %lu\n", tenant->name, route_label, total_4XX);
fprintf(ostream, "# TYPE %s_%s_total_5XX counter\n", tenant->name, route_label);
fprintf(ostream, "%s_%s_total_5XX: %lu\n", tenant->name, route_label, total_5XX);
#ifdef ADMISSIONS_CONTROL
fprintf(ostream, "# TYPE %s_%s_latency_p50 gauge\n", tenant->name, route_label);
fprintf(ostream, "%s_%s_latency_p50: %lu\n", tenant->name, route_label, latency_p50);
fprintf(ostream, "# TYPE %s_%s_latency_p90 gauge\n", tenant->name, route_label);
fprintf(ostream, "%s_%s_latency_p90: %lu\n", tenant->name, route_label, latency_p90);
#endif
#endif /* HTTP_ROUTE_TOTAL_COUNTERS */
}
void
render_tenant_routers(struct tenant *tenant, void *arg_one, void *arg_two)
{
FILE *ostream = (FILE *)arg_one;
char *name = tenant->name;
http_router_foreach(&tenant->router, render_routes, ostream, tenant);
}
void
metrics_server_route_level_metrics_render(FILE *ostream)
{
#ifdef HTTP_ROUTE_TOTAL_COUNTERS
tenant_database_foreach(render_tenant_routers, ostream, NULL);
#endif
}

@ -93,3 +93,12 @@ tenant_database_find_by_ptr(void *ptr)
}
return NULL;
}
void
tenant_database_foreach(void (*cb)(struct tenant *, void *), void *arg)
{
for (size_t i = 0; i < tenant_database_count; i++) {
assert(tenant_database[i]);
cb(tenant_database[i], arg);
}
}

@ -38,16 +38,16 @@ run_samples() {
# Scrape the perf window size from the source if possible
# TODO: Make a util function
local -r perf_window_path="$(path_join "$__run_sh__base_path" ../../../runtime/include/perf_window_t.h)"
local -i perf_window_capacity
if ! perf_window_capacity=$(grep "perf_window_capacity =" < "$perf_window_path" | cut -d\ -f3); then
printf "Failed to scrape perf_window_capacity from ../../include/perf_window.h\n"
local -i PERF_WINDOW_CAPACITY
if ! PERF_WINDOW_CAPACITY=$(grep "PERF_WINDOW_CAPACITY =" < "$perf_window_path" | cut -d\ -f3); then
printf "Failed to scrape PERF_WINDOW_CAPACITY from ../../include/perf_window.h\n"
printf "Defaulting to 16\n"
perf_window_capacity=16
PERF_WINDOW_CAPACITY=16
fi
local -ir perf_window_capacity
local -ir PERF_WINDOW_CAPACITY
printf "Running Samples: "
hey -disable-compression -disable-keepalive -disable-redirects -n "$perf_window_capacity" -c "$perf_window_capacity" -q 200 -cpus 3 -o csv -m GET "http://${hostname}:10000/empty" 1> /dev/null 2> /dev/null || {
hey -disable-compression -disable-keepalive -disable-redirects -n "$PERF_WINDOW_CAPACITY" -c "$PERF_WINDOW_CAPACITY" -q 200 -cpus 3 -o csv -m GET "http://${hostname}:10000/empty" 1> /dev/null 2> /dev/null || {
printf "[ERR]\n"
panic "samples failed"
return 1

@ -41,22 +41,22 @@ run_samples() {
# Scrape the perf window size from the source if possible
# TODO: Make a util function
local -r perf_window_path="$(path_join "$__run_sh__base_path" ../../../runtime/include/perf_window_t.h)"
local -i perf_window_capacity
if ! perf_window_capacity=$(grep "perf_window_capacity =" < "$perf_window_path" | cut -d\ -f3); then
printf "Failed to scrape perf_window_capacity from ../../../runtime/include/perf_window.h\n"
local -i PERF_WINDOW_CAPACITY
if ! PERF_WINDOW_CAPACITY=$(grep "PERF_WINDOW_CAPACITY =" < "$perf_window_path" | cut -d\ -f3); then
printf "Failed to scrape PERF_WINDOW_CAPACITY from ../../../runtime/include/perf_window.h\n"
printf "Defaulting to 16\n"
perf_window_capacity=16
PERF_WINDOW_CAPACITY=16
fi
local -ir perf_window_capacity
local -ir PERF_WINDOW_CAPACITY
printf "Running Samples: "
hey -disable-compression -disable-keepalive -disable-redirects -n "$perf_window_capacity" -c "$perf_window_capacity" -cpus 3 -t 0 -o csv -m GET -d "40\n" "http://${hostname}:10010/fib2" 1> /dev/null 2> /dev/null || {
hey -disable-compression -disable-keepalive -disable-redirects -n "$PERF_WINDOW_CAPACITY" -c "$PERF_WINDOW_CAPACITY" -cpus 3 -t 0 -o csv -m GET -d "40\n" "http://${hostname}:10010/fib2" 1> /dev/null 2> /dev/null || {
printf "[ERR]\n"
panic "fib40 samples failed with $?"
return 1
}
hey -disable-compression -disable-keepalive -disable-redirects -n "$perf_window_capacity" -c "$perf_window_capacity" -cpus 3 -t 0 -o csv -m GET -d "10\n" "http://${hostname}:100010/fib" 1> /dev/null 2> /dev/null || {
hey -disable-compression -disable-keepalive -disable-redirects -n "$PERF_WINDOW_CAPACITY" -c "$PERF_WINDOW_CAPACITY" -cpus 3 -t 0 -o csv -m GET -d "10\n" "http://${hostname}:100010/fib" 1> /dev/null 2> /dev/null || {
printf "[ERR]\n"
panic "fib10 samples failed with $?"
return 1

@ -38,22 +38,22 @@ run_samples() {
# Scrape the perf window size from the source if possible
# TODO: Make a util function
local -r perf_window_path="$(path_join "$__run_sh__base_path" ../../runtime/include/perf_window_t.h)"
local -i perf_window_capacity
if ! perf_window_capacity=$(grep "perf_window_capacity =" < "$perf_window_path" | cut -d\ -f3); then
printf "Failed to scrape perf_window_capacity from ../../runtime/include/perf_window.h\n"
local -i PERF_WINDOW_CAPACITY
if ! PERF_WINDOW_CAPACITY=$(grep "PERF_WINDOW_CAPACITY =" < "$perf_window_path" | cut -d\ -f3); then
printf "Failed to scrape PERF_WINDOW_CAPACITY from ../../runtime/include/perf_window.h\n"
printf "Defaulting to 16\n"
perf_window_capacity=16
PERF_WINDOW_CAPACITY=16
fi
local -ir perf_window_capacity
local -ir PERF_WINDOW_CAPACITY
printf "Running Samples: "
hey -disable-compression -disable-keepalive -disable-redirects -n "$perf_window_capacity" -c "$perf_window_capacity" -cpus 3 -t 0 -o csv -m GET -d "40\n" "http://${hostname}:10000/fibonacci_10" 1> /dev/null 2> /dev/null || {
hey -disable-compression -disable-keepalive -disable-redirects -n "$PERF_WINDOW_CAPACITY" -c "$PERF_WINDOW_CAPACITY" -cpus 3 -t 0 -o csv -m GET -d "40\n" "http://${hostname}:10000/fibonacci_10" 1> /dev/null 2> /dev/null || {
printf "[ERR]\n"
panic "fibonacci_40 samples failed with $?"
return 1
}
hey -disable-compression -disable-keepalive -disable-redirects -n "$perf_window_capacity" -c "$perf_window_capacity" -cpus 3 -t 0 -o csv -m GET -d "10\n" "http://${hostname}:10000/fibonacci_10" 1> /dev/null 2> /dev/null || {
hey -disable-compression -disable-keepalive -disable-redirects -n "$PERF_WINDOW_CAPACITY" -c "$PERF_WINDOW_CAPACITY" -cpus 3 -t 0 -o csv -m GET -d "10\n" "http://${hostname}:10000/fibonacci_10" 1> /dev/null 2> /dev/null || {
printf "[ERR]\n"
panic "fibonacci_10 samples failed with $?"
return 1

Loading…
Cancel
Save