diff options
| author | Paul Oliver <contact@pauloliver.dev> | 2026-06-04 17:59:17 +0200 |
|---|---|---|
| committer | Paul Oliver <contact@pauloliver.dev> | 2026-06-07 03:29:41 +0200 |
| commit | 6d225cc44104306bac5d32c41734fefc1af95614 (patch) | |
| tree | 85ddda2b0c3cd738773c8d3ca756d7fbf0eeef2c /core/server.c | |
| parent | eb5f9f6643e0729d35f705c8a7b7b46cb5874a6a (diff) | |
Adds heatmaps (WIP)
Diffstat (limited to 'core/server.c')
| -rw-r--r-- | core/server.c | 166 |
1 files changed, 143 insertions, 23 deletions
diff --git a/core/server.c b/core/server.c index d54d853..292c3d9 100644 --- a/core/server.c +++ b/core/server.c @@ -1,21 +1,104 @@ #include <arpa/inet.h> +#include <assert.h> #include <json-c/json.h> #include <signal.h> #include <sqlite3.h> #include <string.h> #include <threads.h> +#include <zlib.h> +#include "compress.c" #include "logger.c" #include "sql.c" +// ---------------------------------------------------------------------------- +// Defines +// ---------------------------------------------------------------------------- #define BACKLOG 10 +#define EVA_SIZE (sizeof(uint64_t) * MVEC_SIZE) +#define MAX_HM_PIXEL_COUNT 0x400 // must equal DEFVAL_HM_PIXEL_COUNT in client.cpp +// ---------------------------------------------------------------------------- +// Declarations +// ---------------------------------------------------------------------------- struct Socket { int fd; struct sockaddr_in addr; }; +struct CallbackContext { + struct json_object *response; + int64_t response_rows; + int64_t hm_left; + int64_t hm_pixel_count; + int64_t hm_pixel_pow; +}; + +struct RenderContext { + const struct CallbackContext *callback_context; + const void *blob; + size_t blob_size; + uint64_t eva[EVA_SIZE]; + int64_t out[MAX_HM_PIXEL_COUNT]; +}; + +// ---------------------------------------------------------------------------- +// Globals +// ---------------------------------------------------------------------------- struct json_object *g_response_header; +size_t g_blob_count; + +// ---------------------------------------------------------------------------- +// Event array render function +// ---------------------------------------------------------------------------- +int eva_render(void *data) { + assert(data); + + struct RenderContext *render_context = (struct RenderContext *)data; + int64_t hm_left = render_context->callback_context->hm_left; + int64_t hm_pixel_count = render_context->callback_context->hm_pixel_count; + int64_t hm_pixel_pow = render_context->callback_context->hm_pixel_pow; + int64_t hm_pixel_res = 1 << hm_pixel_pow; + const void *blob = render_context->blob; + size_t blob_size = render_context->blob_size; + +#if defined(MVEC_LOOP) + hm_left %= MVEC_SIZE; +#endif + +#if !defined(MVEC_LOOP) +#if !defined(NDEBUG) + int64_t hm_right = hm_left + hm_pixel_res * hm_pixel_count; +#endif + assert(hm_left < (int64_t)MVEC_SIZE); + assert(hm_right <= (int64_t)MVEC_SIZE); +#endif + + // Inflate blob + struct InflateParams params = { + .avail_in = blob_size, + .size = EVA_SIZE, + .in = (Bytef *)blob, + .out = (Bytef *)render_context->eva, + }; + + comp_inflate(¶ms); + comp_inflate_end(¶ms); + + for (int64_t i = 0; i < hm_pixel_count; i++) { + render_context->out[i] = 0l; + + for (int64_t j = 0; j < hm_pixel_res; j++) { + int64_t coord = hm_left + (i * hm_pixel_res) + j; +#if defined(MVEC_LOOP) + coord %= MVEC_SIZE; +#endif + render_context->out[i] += render_context->eva[coord]; + } + } + + return 0; +} // ---------------------------------------------------------------------------- // SQL callbacks @@ -24,13 +107,20 @@ void sql_callback_add_column_name(sqlite3_stmt *sql_stmt, void *data) { assert(sql_stmt); assert(data); assert(sqlite3_column_type(sql_stmt, 0) == SQLITE_TEXT); + assert(sqlite3_column_type(sql_stmt, 1) == SQLITE_TEXT); assert(!strcmp(sqlite3_column_name(sql_stmt, 0), "name")); + assert(!strcmp(sqlite3_column_name(sql_stmt, 1), "type")); const char *col_name = (const char *)sqlite3_column_text(sql_stmt, 0); - struct json_object *response = (struct json_object *)data; + const char *col_type = (const char *)sqlite3_column_text(sql_stmt, 1); + struct json_object *response_header = (struct json_object *)data; - if (!json_object_object_get_ex(response, col_name, NULL)) { - json_object_object_add(response, col_name, json_object_new_array()); + if (!json_object_object_get_ex(response_header, col_name, NULL)) { + json_object_object_add(response_header, col_name, json_object_new_array()); + } + + if (!strcmp(col_type, "BLOB")) { + g_blob_count++; } } @@ -38,20 +128,42 @@ void sql_callback_add_data(sqlite3_stmt *sql_stmt, void *data) { assert(sql_stmt); assert(data); - struct json_object *response = (struct json_object *)data; - - for (int i = 0; i < sqlite3_column_count(sql_stmt); i++) { - const char *col_name = sqlite3_column_name(sql_stmt, i); - struct json_object *col_data = json_object_object_get(response, col_name); + struct CallbackContext *callback_context = (struct CallbackContext *)data; + struct json_object *col_data = NULL; + struct RenderContext *render_contexts = calloc(g_blob_count, sizeof(struct RenderContext)); + thrd_t *threads = calloc(g_blob_count, sizeof(thrd_t)); - if (col_data) { + for (int i = 0, tid = 0; i < sqlite3_column_count(sql_stmt); i++) { + if (json_object_object_get_ex(callback_context->response, sqlite3_column_name(sql_stmt, i), &col_data)) { if (sqlite3_column_type(sql_stmt, i) == SQLITE_BLOB) { - // TODO: render blobs in parallel + render_contexts[tid].callback_context = callback_context; + render_contexts[tid].blob = sqlite3_value_blob(sqlite3_column_value(sql_stmt, i)); + render_contexts[tid].blob_size = sqlite3_value_bytes(sqlite3_column_value(sql_stmt, i)); + thrd_create(&threads[tid], (thrd_start_t)eva_render, &render_contexts[tid]); + tid++; } else { json_object_array_add(col_data, json_object_new_int64(sqlite3_column_int64(sql_stmt, i))); } } } + + for (int i = 0, tid = 0; i < sqlite3_column_count(sql_stmt); i++) { + if (json_object_object_get_ex(callback_context->response, sqlite3_column_name(sql_stmt, i), &col_data)) { + if (sqlite3_column_type(sql_stmt, i) == SQLITE_BLOB) { + thrd_join(threads[tid], NULL); + + for (int64_t j = 0; j < callback_context->hm_pixel_count; j++) { + json_object_array_add(col_data, json_object_new_int64(render_contexts[tid].out[j])); + } + + tid++; + } + } + } + + callback_context->response_rows++; + free(render_contexts); + free(threads); } // ---------------------------------------------------------------------------- @@ -107,15 +219,22 @@ void respond_data(int socket_fd, struct json_object *request) { int64_t nth = json_object_get_int64(json_object_object_get(request, "nth")); int64_t entries = json_object_get_int64(json_object_object_get(request, "entries")); - const char *x_axis_pref = (!strcmp(x_axis, "rowid") || !strcmp(x_axis, "step")) ? "core." : ""; + struct CallbackContext callback_context = { + .response = NULL, + .response_rows = 0l, + .hm_left = json_object_get_int64(json_object_object_get(request, "hm-left")), + .hm_pixel_count = json_object_get_int64(json_object_object_get(request, "hm-pixel-count")), + .hm_pixel_pow = json_object_get_int64(json_object_object_get(request, "hm-pixel-pow")), + }; + + json_object_deep_copy(g_response_header, &callback_context.response, NULL); - struct json_object *response = NULL; - json_object_deep_copy(g_response_header, &response, NULL); + const char *x_axis_pref = (!strcmp(x_axis, "rowid") || !strcmp(x_axis, "step")) ? "core." : ""; sql_exec( 0, NULL, NULL, sql_callback_add_data, - response, + &callback_context, "select * from (" "select core.rowid, core.step, * from core inner join arch " "where core.rowid = arch.rowid and %s%s > %ld and %s%s <= %ld and core.rowid %% %ld == 0 " @@ -134,10 +253,9 @@ void respond_data(int socket_fd, struct json_object *request) { x_axis ); - const char *response_str = json_object_to_json_string(response); - log_info("Responding to client with: %s", response_str); - json_object_to_fd(socket_fd, response, 0); - json_object_put(response); + log_info("Sending client %ld rows of data", callback_context.response_rows); + json_object_to_fd(socket_fd, callback_context.response, 0); + json_object_put(callback_context.response); shutdown(socket_fd, SHUT_WR); } @@ -193,10 +311,12 @@ int main(void) { 0, NULL, NULL, sql_callback_add_column_name, g_response_header, - "select name from pragma_table_info('core') union " - "select name from pragma_table_info('arch');" + "select name, type from pragma_table_info('core') union " + "select name, type from pragma_table_info('arch');" ); + log_info("Found %lu blob columns in database", g_blob_count); + log_info("Binding to port: %d", PORT); int opt = 1; int socket_fd = socket(AF_INET, SOCK_STREAM, 0); @@ -215,9 +335,9 @@ int main(void) { socklen_t socket_len = sizeof(struct sockaddr_in); socket->fd = accept(socket_fd, (struct sockaddr *)&socket->addr, &socket_len); - thrd_t thrd; - thrd_create(&thrd, (thrd_start_t)handle_client, socket); - thrd_detach(thrd); + thrd_t thread; + thrd_create(&thread, (thrd_start_t)handle_client, socket); + thrd_detach(thread); } return 0; |
