feat: route level metrics

master
Sean McBride 3 years ago
parent e40d139536
commit 36edac7425

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

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

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

@ -5,10 +5,12 @@
#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 route_metrics metrics;
struct module *module;
/* HTTP State */
uint32_t relative_deadline_us;

@ -0,0 +1,55 @@
#pragma once
#include <stdatomic.h>
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);
}
}

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

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

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

@ -0,0 +1,62 @@
#include <stdatomic.h>
#include <stdint.h>
#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);
}

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

Loading…
Cancel
Save