From 36edac74257165d87c0e0d24e0a2bd53354c91bd Mon Sep 17 00:00:00 2001 From: Sean McBride Date: Tue, 2 Aug 2022 18:37:35 -0400 Subject: [PATCH] feat: route level metrics --- runtime/include/http_router.h | 8 +++ runtime/include/http_session.h | 5 ++ runtime/include/perf_window.h | 3 +- runtime/include/route.h | 6 +- runtime/include/route_metrics.h | 55 ++++++++++++++++ runtime/include/tenant_functions.h | 3 + runtime/src/listener_thread.c | 2 + runtime/src/metrics_server.c | 4 ++ .../src/metrics_server_route_level_metrics.c | 62 +++++++++++++++++++ runtime/src/tenant_database.c | 9 +++ 10 files changed, 154 insertions(+), 3 deletions(-) create mode 100644 runtime/include/route_metrics.h create mode 100644 runtime/src/metrics_server_route_level_metrics.c diff --git a/runtime/include/http_router.h b/runtime/include/http_router.h index 13c96f2..1291ad9 100644 --- a/runtime/include/http_router.h +++ b/runtime/include/http_router.h @@ -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 }; + route_metrics_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); } +} diff --git a/runtime/include/http_session.h b/runtime/include/http_session.h index baeb685..8dc91b4 100644 --- a/runtime/include/http_session.h +++ b/runtime/include/http_session.h @@ -15,6 +15,8 @@ #include "http_parser.h" #include "http_parser_settings.h" #include "http_total.h" +#include "route.h" +#include "route_metrics.h" #include "tenant.h" #include "vec.h" #include "http_session_perf_log.h" @@ -54,6 +56,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; @@ -90,6 +93,7 @@ http_session_init(struct http_session *session, int socket_descriptor, const str assert(socket_address != NULL); 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)); @@ -175,6 +179,7 @@ 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(status_code); + route_metrics_increment(&session->route->metrics, status_code); if (status_code == 200) { session->response_header_length = snprintf(session->response_header, diff --git a/runtime/include/perf_window.h b/runtime/include/perf_window.h index 0045a97..50cc054 100644 --- a/runtime/include/perf_window.h +++ b/runtime/include/perf_window.h @@ -149,7 +149,8 @@ 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; if (likely(perf_window->count >= PERF_WINDOW_BUFFER_SIZE)) return perf_window->by_duration[precomputed_index].execution_time; diff --git a/runtime/include/route.h b/runtime/include/route.h index af4b490..8b01aa6 100644 --- a/runtime/include/route.h +++ b/runtime/include/route.h @@ -5,11 +5,13 @@ #include "admissions_info.h" #include "module.h" +#include "route_metrics.h" /* Assumption: entrypoint is always _start. This should be enhanced later */ struct route { - char *route; - struct module *module; + char *route; + struct route_metrics metrics; + struct module *module; /* HTTP State */ uint32_t relative_deadline_us; uint64_t relative_deadline; /* cycles */ diff --git a/runtime/include/route_metrics.h b/runtime/include/route_metrics.h new file mode 100644 index 0000000..d7480ad --- /dev/null +++ b/runtime/include/route_metrics.h @@ -0,0 +1,55 @@ +#pragma once + +#include + +struct route_metrics { + atomic_ulong total_requests; + atomic_ulong total_2XX; + atomic_ulong total_4XX; + atomic_ulong total_5XX; +}; + +static inline void +route_metrics_init(struct route_metrics *rm) +{ + atomic_init(&rm->total_requests, 0); + atomic_init(&rm->total_2XX, 0); + atomic_init(&rm->total_4XX, 0); + atomic_init(&rm->total_5XX, 0); +} + +static inline void +route_metrics_increment_request(struct route_metrics *rm) +{ + atomic_fetch_add(&rm->total_requests, 1); +} + +static inline void +route_metrics_increment_2XX(struct route_metrics *rm) +{ + atomic_fetch_add(&rm->total_2XX, 1); +} + +static inline void +route_metrics_increment_4XX(struct route_metrics *rm) +{ + atomic_fetch_add(&rm->total_4XX, 1); +} + +static inline void +route_metrics_increment_5XX(struct route_metrics *rm) +{ + atomic_fetch_add(&rm->total_5XX, 1); +} + +static inline void +route_metrics_increment(struct route_metrics *rm, int status_code) +{ + if (status_code >= 200 && status_code <= 299) { + route_metrics_increment_2XX(rm); + } else if (status_code >= 400 && status_code <= 499) { + route_metrics_increment_4XX(rm); + } else if (status_code >= 500 && status_code <= 599) { + route_metrics_increment_5XX(rm); + } +} diff --git a/runtime/include/tenant_functions.h b/runtime/include/tenant_functions.h index cb76651..be9d355 100644 --- a/runtime/include/tenant_functions.h +++ b/runtime/include/tenant_functions.h @@ -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) { diff --git a/runtime/src/listener_thread.c b/runtime/src/listener_thread.c index 9aa1b73..93b887d 100644 --- a/runtime/src/listener_thread.c +++ b/runtime/src/listener_thread.c @@ -233,6 +233,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 diff --git a/runtime/src/metrics_server.c b/runtime/src/metrics_server.c index e0ba75a..b8cd157 100644 --- a/runtime/src/metrics_server.c +++ b/runtime/src/metrics_server.c @@ -21,6 +21,8 @@ static pthread_attr_t metrics_server_thread_settings; struct tcp_server metrics_server; static void *metrics_server_handler(void *arg); +extern void metrics_server_route_level_metrics_render(FILE *ostream); + void metrics_server_init() { @@ -201,6 +203,8 @@ metrics_server_handler(void *arg) fprintf(ostream, "# TYPE os_proc_guest_time counter\n"); fprintf(ostream, "os_proc_guest_time: %lu\n", stat.guest_time); + metrics_server_route_level_metrics_render(ostream); + fflush(ostream); assert(ostream_size > 0); rc = fclose(ostream); diff --git a/runtime/src/metrics_server_route_level_metrics.c b/runtime/src/metrics_server_route_level_metrics.c new file mode 100644 index 0000000..2936a5d --- /dev/null +++ b/runtime/src/metrics_server_route_level_metrics.c @@ -0,0 +1,62 @@ +#include +#include + +#include "perf_window.h" +#include "tenant_functions.h" + +// tenant_database_foreach_cb_t + +static const int p50_idx = PERF_WINDOW_BUFFER_SIZE * 50 / 100; +static const int p90_idx = PERF_WINDOW_BUFFER_SIZE * 90 / 100; + +void +render_routes(struct route *route, void *arg_one, void *arg_two) +{ + 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); + + fprintf(ostream, "# TYPE %s_%s_total_requests counter\n", tenant->name, route->route); + fprintf(ostream, "%s_%s_total_requests: %lu\n", tenant->name, route->route, total_requests); + + fprintf(ostream, "# TYPE %s_%s_total_2XX counter\n", tenant->name, route->route); + fprintf(ostream, "%s_%s_total_2XX: %lu\n", tenant->name, route->route, total_2XX); + + fprintf(ostream, "# TYPE %s_%s_total_4XX counter\n", tenant->name, route->route); + fprintf(ostream, "%s_%s_total_4XX: %lu\n", tenant->name, route->route, total_4XX); + + fprintf(ostream, "# TYPE %s_%s_total_5XX counter\n", tenant->name, route->route); + fprintf(ostream, "%s_%s_total_5XX: %lu\n", tenant->name, route->route, total_5XX); + +#ifdef ADMISSIONS_CONTROL + fprintf(ostream, "# TYPE %s_%s_latency_p50 gauge\n", tenant->name, route->route); + fprintf(ostream, "%s_%s_latency_p50: %lu\n", tenant->name, route->route, latency_p50); + + fprintf(ostream, "# TYPE %s_%s_latency_p90 gauge\n", tenant->name, route->route); + fprintf(ostream, "%s_%s_latency_p90: %lu\n", tenant->name, route->route, latency_p90); +#endif +} + +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) +{ + tenant_database_foreach(render_tenant_routers, ostream, NULL); +} diff --git a/runtime/src/tenant_database.c b/runtime/src/tenant_database.c index 7844072..db90980 100644 --- a/runtime/src/tenant_database.c +++ b/runtime/src/tenant_database.c @@ -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); + } +}