From 0df4e501aee0eeaec61217312eddddc077ca53a7 Mon Sep 17 00:00:00 2001 From: Paul Oliver Date: Sat, 30 May 2026 22:16:12 +0200 Subject: Reorganize source files in single directory --- arch/dummy/arch.c | 4 + arch/dummy/arch_plots.cpp | 2 + arch/v1/arch_plots.cpp | 2 - core/client.cpp | 749 ++++++++++++++++++++++++++++++++++++++++++++++ core/render.c | 91 ++++++ core/server.c | 224 ++++++++++++++ data/client.cpp | 749 ---------------------------------------------- data/render.c | 91 ------ data/server.c | 224 -------------- salis.py | 4 +- 10 files changed, 1072 insertions(+), 1068 deletions(-) create mode 100644 arch/dummy/arch_plots.cpp create mode 100644 core/client.cpp create mode 100644 core/render.c create mode 100644 core/server.c delete mode 100644 data/client.cpp delete mode 100644 data/render.c delete mode 100644 data/server.c diff --git a/arch/dummy/arch.c b/arch/dummy/arch.c index aaf0f9d..1fcfbc3 100644 --- a/arch/dummy/arch.c +++ b/arch/dummy/arch.c @@ -147,9 +147,13 @@ const char *arch_mnemonic(uint8_t inst) { #if defined(COMMAND_NEW) void arch_push_data_header(void) { assert(g_sim_db); + log_info("Creating arch table in SQLite database"); + sql_exec(0, NULL, NULL, NULL, NULL, "create table arch (step int not null);"); } #endif void arch_push_data_line(void) { assert(g_sim_db); + log_info("Pushing row to arch table in SQLite database"); + sql_exec(0, NULL, NULL, NULL, NULL, "insert into arch (step) values (%ld);", g_steps); } diff --git a/arch/dummy/arch_plots.cpp b/arch/dummy/arch_plots.cpp new file mode 100644 index 0000000..3631339 --- /dev/null +++ b/arch/dummy/arch_plots.cpp @@ -0,0 +1,2 @@ +std::array g_arch_traces; +std::array g_arch_plots; diff --git a/arch/v1/arch_plots.cpp b/arch/v1/arch_plots.cpp index fb49816..8d35c87 100644 --- a/arch/v1/arch_plots.cpp +++ b/arch/v1/arch_plots.cpp @@ -14,5 +14,3 @@ std::array g_arch_plots = std::to_array({ #undef FOR_CORE }}, }); - -#define ARCH_PLOT_COUNT g_arch_plots.size() diff --git a/core/client.cpp b/core/client.cpp new file mode 100644 index 0000000..227ebaa --- /dev/null +++ b/core/client.cpp @@ -0,0 +1,749 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "logger.c" + +// ---------------------------------------------------------------------------- +// Defines +// ---------------------------------------------------------------------------- +#define COLOR_BLACK ImVec4(0.f, 0.f, 0.f, 1.f) +#define FONT_SIZE 12.f +#define FONT_SOURCE "/usr/share/fonts/droid/DroidSansMono.ttf" +#define GLSL_VERSION "#version 130" +#define PLOT_MAX_COLS 8 +#define PLOT_MIN_COLS 1 +#define PLOT_SCROLL_OFFSET 28.f + +#define IMGUI_WINDOW_FLAGS ( \ + ImGuiWindowFlags_NoBackground | \ + ImGuiWindowFlags_NoDecoration | \ + ImGuiWindowFlags_NoMove | \ + ImGuiWindowFlags_NoSavedSettings \ +) + +#define DATA_FETCH_INTERVAL 10 +#define DATA_FETCH_INTERVAL_SUBDIV 1000 + +#define DEFVAL_ENTRIES 0x800l +#define DEFVAL_NTH 1l +#define DEFVAL_X_AXIS 0 +#define DEFVAL_X_LOW 0l +#define DEFVAL_X_HIGH INT64_MAX +#define DEFVAL_HM_LEFT 0l +#define DEFVAL_HM_PIXEL_COUNT 0x400l + +// ---------------------------------------------------------------------------- +// Declarations +// ---------------------------------------------------------------------------- +enum Status { + STATUS_STOPPED, + STATUS_RUNNING, + STATUS_STOPPING, +}; + +struct CompString { + bool operator()(const char *a, const char *b) const { + return strcmp(a, b) < 0; + } +}; + +struct Plot { + const char *name; + const char *section; + std::vector traces; +}; + +// ---------------------------------------------------------------------------- +// Plots +// ---------------------------------------------------------------------------- +#include "arch_plots.cpp" + +template +std::array merge_array(const std::array &first, const std::array &second) { + std::array result{}; + for (size_t i = 0; i < N; i++) result[i] = first[i]; + for (size_t i = 0; i < M; i++) result[N + i] = second[i]; + return result; +} + +std::array g_core_traces = std::to_array({ + "rowid", + "step", +#define FOR_CORE(i) \ + "cycl_" #i, \ + "mall_" #i, \ + "pnum_" #i, \ + "pfst_" #i, \ + "plst_" #i, \ + "amb0_" #i, \ + "amb1_" #i, \ + "emb0_" #i, \ + "emb1_" #i, \ + "eliv_" #i, \ + "edea_" #i, + FOR_CORES +#undef FOR_CORE +}); + +std::array g_core_plots = std::to_array({ + {"cycl", "general", { +#define FOR_CORE(i) "cycl_" #i, + FOR_CORES +#undef FOR_CORE + }}, + {"mall", "general", { +#define FOR_CORE(i) "mall_" #i, + FOR_CORES +#undef FOR_CORE + }}, + {"pnum", "general", { +#define FOR_CORE(i) "pnum_" #i, + FOR_CORES +#undef FOR_CORE + }}, + {"ppop", "general", { +#define FOR_CORE(i) "pfst_" #i, "plst_" #i, + FOR_CORES +#undef FOR_CORE + }}, + {"ambs", "general", { +#define FOR_CORE(i) "amb0_" #i, "amb1_" #i, + FOR_CORES +#undef FOR_CORE + }}, + {"eevs", "general", { +#define FOR_CORE(i) "emb0_" #i, "emb1_" #i, "eliv_" #i, "edea_" #i, + FOR_CORES +#undef FOR_CORE + }}, +}); + +std::map, CompString> g_trace_map; +std::array g_traces = merge_array(g_core_traces, g_arch_traces); +std::array g_plots = merge_array(g_core_plots, g_arch_plots); + +#define TRACE_COUNT g_traces.size() +#define PLOT_COUNT g_plots.size() + +// ---------------------------------------------------------------------------- +// Globals +// ---------------------------------------------------------------------------- +GLFWwindow *g_window; +ImGuiIO *g_imgui_io; +ImGuiStyle *g_imgui_style; +ImPlotStyle *g_implot_style; + +const char *g_x_axes[] = { + "rowid", + "step", +#define FOR_CORE(i) "cycl_" #i, + FOR_CORES +#undef FOR_CORE +}; + +int g_status; +int g_x_axis = DEFVAL_X_AXIS; +int64_t g_entries = DEFVAL_ENTRIES; +int64_t g_nth = DEFVAL_NTH; +int64_t g_x_low = DEFVAL_X_LOW; +int64_t g_x_high = DEFVAL_X_HIGH; +int64_t g_hm_left = DEFVAL_HM_LEFT; +int64_t g_hm_pixel_count = DEFVAL_HM_PIXEL_COUNT; +int64_t g_hm_pixel_pow; // calculate on startup +int64_t g_x_current = -1l; + +thrd_t g_fetching_thread; +mtx_t g_fetching_mutex; +int g_trace_len; +int g_trace_offset; + +// Layout globals +bool g_data_col_visible = true; +bool g_plot_maximized; +bool g_plot_scroll; +float g_plot_scroll_current; +float g_plot_scroll_to; +float g_data_col_width; +float g_plot_cells_top[PLOT_MAX_COLS][PLOT_COUNT]; +float g_plot_cells_bottom[PLOT_MAX_COLS][PLOT_COUNT]; +Plot *g_plot_cells[PLOT_MAX_COLS][PLOT_COUNT]; +Plot *g_plot_selected = &g_plots[0]; +int g_plot_cols = 2; +int g_plot_col_selected; +int g_plot_row_selected; + +// ---------------------------------------------------------------------------- +// Data functions +// ---------------------------------------------------------------------------- +int64_t data_max_hm_pixel_pow(void) { + return (int64_t)floor(log2((double)(MVEC_SIZE - g_hm_left) / (double)g_hm_pixel_count)); +} + +void data_on_field_change(void) { + g_entries = std::clamp(g_entries, 1l, DEFVAL_ENTRIES); + g_nth = std::clamp(g_nth, DEFVAL_NTH, INT64_MAX); + g_x_low = std::clamp(g_x_low, DEFVAL_X_LOW, INT64_MAX); + g_x_high = std::clamp(g_x_high, g_x_low + 1l, DEFVAL_X_HIGH); + #if !defined(MVEC_LOOP) + g_hm_left = std::clamp(g_hm_left, DEFVAL_HM_LEFT, (int64_t)MVEC_SIZE); + #endif + g_hm_pixel_count = std::clamp(g_hm_pixel_count, 1l, DEFVAL_HM_PIXEL_COUNT); + g_hm_pixel_pow = std::clamp(g_hm_pixel_pow, 0l, data_max_hm_pixel_pow()); + + g_x_current = -1l; + + for (auto &trace : g_trace_map) { + trace.second.clear(); + } +} + +void data_reset_fields(void) { + g_entries = DEFVAL_ENTRIES; + g_nth = DEFVAL_NTH; + g_x_axis = DEFVAL_X_AXIS; + g_x_low = DEFVAL_X_LOW; + g_x_high = DEFVAL_X_HIGH; + g_hm_left = DEFVAL_HM_LEFT; + g_hm_pixel_count = DEFVAL_HM_PIXEL_COUNT; + g_hm_pixel_pow = data_max_hm_pixel_pow(); + + g_trace_len = 0; + g_trace_offset = 0; + + data_on_field_change(); +} + +void data_reset_plot_cells(void) { + memset(g_plot_cells, 0, PLOT_MAX_COLS * PLOT_COUNT * sizeof(nullptr)); + memset(g_plot_cells_top, 0, PLOT_MAX_COLS * PLOT_COUNT * sizeof(float)); + memset(g_plot_cells_bottom, 0, PLOT_MAX_COLS * PLOT_COUNT * sizeof(float)); +} + +void data_fetch(void) { + struct json_object *request = json_object_new_object(); + json_object_object_add(request, "request", json_object_new_string("data")); + json_object_object_add(request, "entries", json_object_new_int64(g_entries)); + json_object_object_add(request, "nth", json_object_new_int64(g_nth)); + json_object_object_add(request, "x-axis", json_object_new_string(g_x_axes[g_x_axis])); + json_object_object_add(request, "x-low", json_object_new_int64(g_x_low)); + json_object_object_add(request, "x-high", json_object_new_int64(g_x_high)); + json_object_object_add(request, "hm-left", json_object_new_int64(g_hm_left)); + json_object_object_add(request, "hm-pixel-count", json_object_new_int64(g_hm_pixel_count)); + json_object_object_add(request, "hm-pixel-pow", json_object_new_int64(g_hm_pixel_pow)); + json_object_object_add(request, "x-current", json_object_new_int64(g_x_current)); + const char *request_str = json_object_to_json_string(request); + + log_info("Sending request to server: %s", request_str); + int socket_fd = socket(AF_INET, SOCK_STREAM, 0); + struct sockaddr_in socket_addr; + memset(&socket_addr, 0, sizeof(struct sockaddr_in)); + socket_addr.sin_family = AF_INET; + socket_addr.sin_port = htons(PORT); + inet_pton(AF_INET, IP, &socket_addr.sin_addr); + if (connect(socket_fd, (struct sockaddr *)&socket_addr, sizeof(struct sockaddr_in))) assert(false); + json_object_to_fd(socket_fd, request, 0); + shutdown(socket_fd, SHUT_WR); + + struct json_object *response = json_object_from_fd(socket_fd); + const char *response_str = json_object_to_json_string(response); + log_info("Server responded with: %s", response_str); + + mtx_lock(&g_fetching_mutex); + + json_object_object_foreach(response, key, value) { + if (g_trace_map.contains(key)) { + for (size_t i = 0; i < json_object_array_length(value); i++) { + ImS64 point = json_object_get_int64(json_object_array_get_idx(value, i)); + g_trace_map.at(key).push_back(point); + } + } + } + + g_x_current = g_trace_map.at(g_x_axes[g_x_axis]).back(); + json_object_put(request); + json_object_put(response); + + g_trace_len = g_trace_map.at("rowid").size(); + + if (g_trace_len >= g_entries * 2) { + for (auto &trace : g_trace_map) { + trace.second.erase(trace.second.begin(), trace.second.end() - g_entries); + } + + g_trace_len = g_trace_map.at("rowid").size(); + } + + g_trace_offset = 0; + + if (g_trace_len > g_entries) { + g_trace_offset = g_trace_len - g_entries; + g_trace_len = g_entries; + } + + mtx_unlock(&g_fetching_mutex); +} + +int data_fetching_thread(void *data) { + (void)data; + + assert(!data); + assert(g_status == STATUS_RUNNING || g_status == STATUS_STOPPING); + + while (g_status == STATUS_RUNNING) { + data_fetch(); + + for (int i = 0; i < DATA_FETCH_INTERVAL_SUBDIV && g_status == STATUS_RUNNING; i++) { + usleep((DATA_FETCH_INTERVAL * 1000000) / DATA_FETCH_INTERVAL_SUBDIV); + } + } + + assert(g_status == STATUS_STOPPING); + g_status = STATUS_STOPPED; + return 0; +} + +void data_start_fetching(void) { + log_info("Starting data fetching thread"); + g_status = STATUS_RUNNING; + thrd_create(&g_fetching_thread, (thrd_start_t)data_fetching_thread, nullptr); +} + +void data_stop_fetching(void) { + assert(g_status == STATUS_RUNNING); + log_info("Stopping data fetching thread"); + g_status = STATUS_STOPPING; + thrd_join(g_fetching_thread, nullptr); +} + +// ---------------------------------------------------------------------------- +// GUI functions +// ---------------------------------------------------------------------------- +void gui_render_data_input(const char *label, int64_t *target) { + assert(label); + assert(target); + + if (ImGui::InputScalar(label, ImGuiDataType_U64, target, nullptr, nullptr, "%#lx")) { + data_on_field_change(); + } +} + +void gui_render_data_col(void) { + const ImGuiViewport *viewport = ImGui::GetMainViewport(); + const ImVec2 win_pos = viewport->Pos; + const ImVec2 win_size = ImVec2(-1.f, viewport->Size.y); + + ImGui::SetNextWindowPos(win_pos); + ImGui::SetNextWindowSize(win_size); + ImGui::Begin("data-col", nullptr, IMGUI_WINDOW_FLAGS); + g_data_col_width = ImGui::GetWindowWidth(); + + ImGui::SeparatorText("SALIS data client"); + ImGui::LabelText("name", NAME); + ImGui::LabelText("seed", "%#lx", SEED); + ImGui::LabelText("server", IP ":" PORT_STR); + ImGui::LabelText("arch", ARCH); + ImGui::LabelText("cores", "%d", CORES); + ImGui::LabelText("mvec-size", "%#lx", MVEC_SIZE); + #if defined(MVEC_LOOP) + ImGui::LabelText("mvec-loop", "true"); + #else + ImGui::LabelText("mvec-loop", "false"); + #endif + ImGui::LabelText("data-push", "%#lx", DATA_PUSH_INTERVAL); + + ImGui::SeparatorText("Data fields"); + + switch (g_status) { + case STATUS_STOPPED: + gui_render_data_input("entries", &g_entries); + gui_render_data_input("nth", &g_nth); + + if (ImGui::BeginCombo("x-axis", g_x_axes[g_x_axis])) { + for (int i = 0; i < CORES + 2; i++) { + if (ImGui::Selectable(g_x_axes[i], g_x_axis == i)) { + data_reset_fields(); + g_x_axis = i; + } + } + + ImGui::EndCombo(); + } + + gui_render_data_input("x-low", &g_x_low); + gui_render_data_input("x-high", &g_x_high); + gui_render_data_input("hm-left", &g_hm_left); + gui_render_data_input("hm-pxl-count", &g_hm_pixel_count); + gui_render_data_input("hm-pxl-pow", &g_hm_pixel_pow); + break; + case STATUS_RUNNING: + case STATUS_STOPPING: + ImGui::LabelText("entries", "%#lx", g_entries); + ImGui::LabelText("nth", "%#lx", g_nth); + ImGui::LabelText("x-axis", "%s", g_x_axes[g_x_axis]); + ImGui::LabelText("x-low", "%#lx", g_x_low); + ImGui::LabelText("x-high", "%#lx", g_x_high); + ImGui::LabelText("hm-left", "%#lx", g_hm_left); + ImGui::LabelText("hm-pxl-count", "%#lx", g_hm_pixel_count); + ImGui::LabelText("hm-pxl-pow", "%#lx", g_hm_pixel_pow); + } + + switch (g_status) { + case STATUS_STOPPED: + if (ImGui::Button("Run", ImVec2(-1.f, 0.f))) { + data_start_fetching(); + } + + if (ImGui::Button("Reset", ImVec2(-1.f, 0.f))) { + data_reset_fields(); + } + + break; + case STATUS_RUNNING: + if (ImGui::Button("Stop", ImVec2(-1.f, 0.f))) { + data_stop_fetching(); + } + + ImGui::LabelText("##", "Running"); + break; + case STATUS_STOPPING: + ImGui::LabelText("##", "Stopping"); + break; + } + + ImGui::SeparatorText("Layout"); + ImGui::SliderInt("cols", &g_plot_cols, PLOT_MIN_COLS, PLOT_MAX_COLS); + ImGui::End(); +} + +void gui_render_plot(const Plot *plot, const ImVec2 &frame_size=ImVec2(-1.f, 0.f)) { + int plot_flags = ImPlotFlags_NoMenus; + int axis_flags = ImPlotAxisFlags_NoMenus; + + if (g_status != STATUS_STOPPED) { + ImPlot::SetNextAxesToFit(); + plot_flags |= ImPlotFlags_NoInputs | ImPlotFlags_NoMouseText; + axis_flags |= ImPlotAxisFlags_NoHighlight; + } + + if (ImPlot::BeginPlot(plot->name, frame_size, plot_flags)) { + ImPlot::SetupAxes(nullptr, nullptr, axis_flags, axis_flags); + ImS64 *x = g_trace_map.at(g_x_axes[g_x_axis]).data() + g_trace_offset; + + for (auto &trace : plot->traces) { + ImS64 *y = g_trace_map.at(trace).data() + g_trace_offset; + ImPlot::PlotLine(trace, x, y, g_trace_len); + } + + ImPlot::EndPlot(); + } +} + +void gui_render_plots(void) { + const char *section_current = g_plots[0].section; + const char *section_next = nullptr; + bool plots_covered[PLOT_COUNT] = { 0 }; + + const ImGuiViewport *viewport = ImGui::GetMainViewport(); + const ImVec2 win_pos = g_data_col_visible ? ImVec2(g_data_col_width, viewport->Pos.y) : viewport->Pos; + const ImVec2 win_size = g_data_col_visible ? ImVec2(viewport->Size.x - g_data_col_width, -1.f) : ImVec2(viewport->Size.x, -1.f); + + if (g_plot_scroll) { + ImGui::SetNextWindowScroll(ImVec2(-1.f, g_plot_scroll_to)); + g_plot_scroll = false; + g_plot_scroll_to = 0.f; + } + + ImGui::SetNextWindowPos(win_pos); + ImGui::SetNextWindowSize(win_size); + ImGui::Begin("plots", nullptr, IMGUI_WINDOW_FLAGS); + g_plot_scroll_current = ImGui::GetScrollY(); + + int col = 0; + int row = 0; + + mtx_lock(&g_fetching_mutex); + + while (section_current) { + ImGui::SeparatorText(section_current); + ImGui::BeginTable("plots-table", g_plot_cols); + + for (size_t i = 0; i < PLOT_COUNT; i++) { + if (g_plots[i].section != section_current) { + section_next = (!section_next && !plots_covered[i]) ? g_plots[i].section : section_next; + continue; + } + + ImGui::TableNextColumn(); + g_plot_cells[col][row] = &g_plots[i]; + g_plot_cells_top[col][row] = ImGui::GetCursorPosY(); + + if (&g_plots[i] == g_plot_selected) { + g_plot_col_selected = col; + g_plot_row_selected = row; + g_implot_style->Colors[ImPlotCol_FrameBg] = g_imgui_style->Colors[ImGuiCol_FrameBg]; + } + + gui_render_plot(&g_plots[i]); + + if (&g_plots[i] == g_plot_selected) { + g_implot_style->Colors[ImPlotCol_FrameBg] = COLOR_BLACK; + } + + g_plot_cells_bottom[col][row] = ImGui::GetCursorPosY(); + col = (col + 1) % g_plot_cols; + row += col ? 0 : 1; + plots_covered[i] = true; + } + + section_current = section_next; + section_next = nullptr; + ImGui::EndTable(); + row += col ? 1 : 0; + col = 0; + } + + mtx_unlock(&g_fetching_mutex); + + ImGui::End(); +} + +void gui_render_plot_maximized(void) { + const ImGuiViewport *viewport = ImGui::GetMainViewport(); + ImGui::SetNextWindowPos(viewport->Pos); + ImGui::SetNextWindowSize(viewport->Size); + ImGui::Begin("plot-fullscreen", nullptr, IMGUI_WINDOW_FLAGS); + + gui_render_plot(g_plot_selected, viewport->Size); + + ImGui::End(); +} + +void gui_plot_queue_scroll(int col_selected, int row_selected) { + const ImGuiViewport *viewport = ImGui::GetMainViewport(); + float plot_top = g_plot_cells_top[col_selected][row_selected]; + float plot_bottom = g_plot_cells_bottom[col_selected][row_selected]; + float win_top = g_plot_scroll_current; + float win_bottom = win_top + viewport->Size.y; + + if (plot_bottom > win_bottom) { + g_plot_scroll_to = win_top + (plot_bottom - win_bottom); + g_plot_scroll = true; + } + + if (plot_top < win_top) { + g_plot_scroll_to = plot_top - PLOT_SCROLL_OFFSET; + g_plot_scroll = true; + } +} + +void gui_render(void) { + if (g_plot_maximized) { + gui_render_plot_maximized(); + return; + } + + if (g_data_col_visible) { + gui_render_data_col(); + } + + gui_render_plots(); +} + +// ---------------------------------------------------------------------------- +// Main functions +// ---------------------------------------------------------------------------- +void win_sig_handler(int signo) { + (void)signo; + + log_warn("Signal received, will stop SALIS data client..."); + + if (g_status == STATUS_RUNNING) { + data_stop_fetching(); + } + + glfwSetWindowShouldClose(g_window, GLFW_TRUE); +} + +void win_error_callback(int error, const char* description) { + log_warn("GLFW error %d: %s", error, description); +} + +void win_key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) { + (void)window; + (void)scancode; + + if (action != GLFW_PRESS || ImGui::IsAnyItemActive()) { + return; + } + + if (g_plot_maximized) { + if (mods == GLFW_MOD_CONTROL && key == GLFW_KEY_C) { + glfwSetWindowShouldClose(g_window, GLFW_TRUE); + } + + if (mods == 0 && key == GLFW_KEY_F) { + g_plot_maximized = !g_plot_maximized; + } + + return; + } + + switch (mods) { + case GLFW_MOD_CONTROL: + switch (key) { + case GLFW_KEY_C: + glfwSetWindowShouldClose(g_window, GLFW_TRUE); + break; + case GLFW_KEY_N: + g_data_col_visible = !g_data_col_visible; + break; + case GLFW_KEY_LEFT: + g_plot_cols -= g_plot_cols > 1 ? 1 : 0; + data_reset_plot_cells(); + break; + case GLFW_KEY_RIGHT: + g_plot_cols += g_plot_cols < PLOT_MAX_COLS ? 1 : 0; + data_reset_plot_cells(); + break; + } + + break; + + case 0: + switch (key) { + case GLFW_KEY_LEFT: + g_plot_col_selected -= g_plot_col_selected ? 1 : 0; + g_plot_selected = g_plot_cells[g_plot_col_selected][g_plot_row_selected]; + break; + case GLFW_KEY_RIGHT: + g_plot_col_selected += (g_plot_col_selected < PLOT_MAX_COLS - 1 && g_plot_cells[g_plot_col_selected + 1][g_plot_row_selected]) ? 1 : 0; + g_plot_selected = g_plot_cells[g_plot_col_selected][g_plot_row_selected]; + break; + case GLFW_KEY_UP: + g_plot_row_selected -= g_plot_row_selected ? 1 : 0; + g_plot_selected = g_plot_cells[g_plot_col_selected][g_plot_row_selected]; + gui_plot_queue_scroll(g_plot_col_selected, g_plot_row_selected); + break; + case GLFW_KEY_DOWN: + g_plot_row_selected += (g_plot_row_selected < (int)PLOT_COUNT - 1 && g_plot_cells[g_plot_col_selected][g_plot_row_selected + 1]) ? 1 : 0; + g_plot_selected = g_plot_cells[g_plot_col_selected][g_plot_row_selected]; + gui_plot_queue_scroll(g_plot_col_selected, g_plot_row_selected); + break; + case GLFW_KEY_F: + g_plot_maximized = !g_plot_maximized; + break; + case GLFW_KEY_SPACE: + switch (g_status) { + case STATUS_STOPPED: + data_start_fetching(); + break; + case STATUS_RUNNING: + data_stop_fetching(); + break; + } + + break; + } + + break; + } +} + +int main(int argc, char **argv) { + (void)argc; + (void)argv; + + signal(SIGINT, win_sig_handler); + signal(SIGTERM, win_sig_handler); + + log_info("Starting SALIS data client"); + + log_info("Initializing GLFW"); + glfwSetErrorCallback(win_error_callback); + glfwInitHint(GLFW_WAYLAND_LIBDECOR, GLFW_WAYLAND_DISABLE_LIBDECOR); + if (!glfwInit()) assert(false); + + float scale = ImGui_ImplGlfw_GetContentScaleForMonitor(glfwGetPrimaryMonitor()); + g_window = glfwCreateWindow((int)(800 * scale), (int)(600 * scale), "SALIS data client", nullptr, nullptr); + assert(g_window); + glfwSetKeyCallback(g_window, win_key_callback); + glfwMakeContextCurrent(g_window); + glfwSwapInterval(1); // enable vsync + + log_info("Initializing ImGui"); + IMGUI_CHECKVERSION(); + ImGui::CreateContext(); + ImPlot::CreateContext(); + + g_imgui_io = &ImGui::GetIO(); + g_imgui_io->Fonts->AddFontFromFileTTF(FONT_SOURCE); + g_imgui_io->IniFilename = nullptr; + + g_imgui_style = &ImGui::GetStyle(); + g_imgui_style->Colors[ImGuiCol_WindowBg] = COLOR_BLACK; + g_imgui_style->FontScaleDpi = scale; + g_imgui_style->FontSizeBase = FONT_SIZE; + g_imgui_style->ItemSpacing = ImVec2(g_imgui_style->ItemSpacing.x, 2.f); + g_imgui_style->ScaleAllSizes(scale); + + g_implot_style = &ImPlot::GetStyle(); + g_implot_style->Colors[ImPlotCol_FrameBg] = COLOR_BLACK; + + ImGui_ImplGlfw_InitForOpenGL(g_window, true); + ImGui_ImplOpenGL3_Init(GLSL_VERSION); + + for (auto &i : g_traces) { + g_trace_map[i] = {}; + g_trace_map[i].reserve(g_entries); + } + + g_hm_pixel_pow = data_max_hm_pixel_pow(); + + mtx_init(&g_fetching_mutex, mtx_plain); + + while (!glfwWindowShouldClose(g_window)) { + glfwPollEvents(); + + ImGui_ImplOpenGL3_NewFrame(); + ImGui_ImplGlfw_NewFrame(); + ImGui::NewFrame(); + + gui_render(); + + ImGui::Render(); + int display_w; + int display_h; + glfwGetFramebufferSize(g_window, &display_w, &display_h); + glViewport(0, 0, display_w, display_h); + glClearColor(0.f, 0.f, 0.f, 1.f); + glClear(GL_COLOR_BUFFER_BIT); + ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); + glfwSwapBuffers(g_window); + } + + mtx_destroy(&g_fetching_mutex); + + ImGui_ImplOpenGL3_Shutdown(); + ImGui_ImplGlfw_Shutdown(); + ImPlot::DestroyContext(); + ImGui::DestroyContext(); + + log_info("Stopping SALIS data client"); + glfwDestroyWindow(g_window); + glfwTerminate(); + + return 0; +} diff --git a/core/render.c b/core/render.c new file mode 100644 index 0000000..08ff6dd --- /dev/null +++ b/core/render.c @@ -0,0 +1,91 @@ +#include +SQLITE_EXTENSION_INIT1 + +#include +#include +#include +#include + +#include "compress.c" + +void eva_render(sqlite3_context *context, int argc, sqlite3_value **argv) { + assert(context); + assert(argc == 4); + assert(argv); + + (void)argc; + + size_t left = (size_t)sqlite3_value_int(argv[0]); +#if defined(MVEC_LOOP) + left %= MVEC_SIZE; +#endif + + size_t px_count = (size_t)sqlite3_value_int(argv[1]); + size_t px_pow = (size_t)sqlite3_value_int(argv[2]); + size_t px_res = 1 << px_pow; +#if !defined(MVEC_LOOP) +#if !defined(NDEBUG) + size_t right = left + px_res * px_count; +#endif + assert(left < MVEC_SIZE); + assert(right <= MVEC_SIZE); +#endif + + const void *blob = sqlite3_value_blob(argv[3]); + size_t blob_size = (size_t)sqlite3_value_bytes(argv[3]); + + // Inflate blob + size_t out_size = sizeof(uint64_t) * px_count; + uint64_t *eva = sqlite3_malloc(EVA_SIZE); + uint64_t *out = sqlite3_malloc(out_size); + + struct InflateParams params = { + .avail_in = blob_size, + .size = EVA_SIZE, + .in = (Bytef *)blob, + .out = (Bytef *)eva, + }; + + comp_inflate(¶ms); + comp_inflate_end(¶ms); + + // Render image + for (size_t i = 0; i < px_count; i++) { + out[i] = 0; + + for (size_t j = 0; j < px_res; j++) { + size_t in_coord = left + i * px_res + j; +#if defined(MVEC_LOOP) + in_coord %= MVEC_SIZE; +#endif + out[i] += eva[in_coord]; + } + } + + sqlite3_free(eva); + + // Transform rendered image into textual representation + // A comma-separated list of hexadecimal integers + char *csv = sqlite3_malloc(px_count * 17 + 1); + char *ptr = csv; + + for (size_t i = 0; i < px_count; i++) { + ptr += sprintf(ptr, "%lx ", out[i]); + } + + *(--ptr) = '\0'; + sqlite3_free(out); + + sqlite3_result_text(context, csv, -1, sqlite3_free); +} + +int sqlite3_render_init(sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi) { + assert(db); + assert(pzErrMsg); + assert(pApi); + + (void)pzErrMsg; + + SQLITE_EXTENSION_INIT2(pApi); + return sqlite3_create_function(db, "eva_render", 4, SQLITE_DETERMINISTIC | SQLITE_INNOCUOUS | SQLITE_UTF8, NULL, eva_render, NULL, NULL); +} diff --git a/core/server.c b/core/server.c new file mode 100644 index 0000000..d54d853 --- /dev/null +++ b/core/server.c @@ -0,0 +1,224 @@ +#include +#include +#include +#include +#include +#include + +#include "logger.c" +#include "sql.c" + +#define BACKLOG 10 + +struct Socket { + int fd; + struct sockaddr_in addr; +}; + +struct json_object *g_response_header; + +// ---------------------------------------------------------------------------- +// SQL callbacks +// ---------------------------------------------------------------------------- +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(!strcmp(sqlite3_column_name(sql_stmt, 0), "name")); + + const char *col_name = (const char *)sqlite3_column_text(sql_stmt, 0); + struct json_object *response = (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()); + } +} + +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); + + if (col_data) { + if (sqlite3_column_type(sql_stmt, i) == SQLITE_BLOB) { + // TODO: render blobs in parallel + } else { + json_object_array_add(col_data, json_object_new_int64(sqlite3_column_int64(sql_stmt, i))); + } + } + } +} + +// ---------------------------------------------------------------------------- +// Main functions +// ---------------------------------------------------------------------------- +void sig_handler(int signo) { + (void)signo; + log_warn("Signal received, will stop SALIS data server"); + json_object_put(g_response_header); + sql_close(); + exit(0); +} + +void respond_name(int socket_fd) { + log_info("Client requested simulation name"); + + struct json_object *sim_name = json_object_new_object(); + json_object_object_add(sim_name, "name", json_object_new_string(NAME)); + json_object_to_fd(socket_fd, sim_name, 0); + json_object_put(sim_name); +} + +void respond_opts(int socket_fd) { + log_info("Client requested simulation options"); + + struct json_object *sim_opts = json_object_from_file(SIM_OPTS); + json_object_to_fd(socket_fd, sim_opts, 0); + json_object_put(sim_opts); +} + +void respond_hash(int socket_fd) { + log_info("Client requested git hash"); + + char buff[41] = { 0 }; + FILE *pipe = popen("git rev-parse HEAD", "r"); + fread(buff, sizeof(char), 40, pipe); + pclose(pipe); + + struct json_object *git_hash = json_object_new_object(); + json_object_object_add(git_hash, "hash", json_object_new_string(buff)); + json_object_to_fd(socket_fd, git_hash, 0); + json_object_put(git_hash); +} + +void respond_data(int socket_fd, struct json_object *request) { + assert(request); + + const char *request_str = json_object_to_json_string(request); + log_info("Client requested simulation data with the following parameters: %s", request_str); + const char *x_axis = json_object_get_string(json_object_object_get(request, "x-axis")); + int64_t x_current = json_object_get_int64(json_object_object_get(request, "x-current")); + int64_t x_high = json_object_get_int64(json_object_object_get(request, "x-high")); + 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 json_object *response = NULL; + json_object_deep_copy(g_response_header, &response, NULL); + + sql_exec( + 0, NULL, NULL, + sql_callback_add_data, + response, + "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 " + "order by %s%s desc limit %ld" + ") order by %s asc;", + x_axis_pref, + x_axis, + x_current, + x_axis_pref, + x_axis, + x_high, + nth, + x_axis_pref, + x_axis, + entries, + 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); + + shutdown(socket_fd, SHUT_WR); +} + +int handle_client(struct Socket *socket) { + assert(socket); + + char socket_ip[INET_ADDRSTRLEN]; + inet_ntop(AF_INET, &socket->addr.sin_addr, socket_ip, INET_ADDRSTRLEN); + log_info("Client connected: %s:%d", socket_ip, ntohs(socket->addr.sin_port)); + + struct json_object *request_json = json_object_from_fd(socket->fd); + struct json_object *request_str = NULL; + + if (!json_object_object_get_ex(request_json, "request", &request_str)) assert(false); + + const char *request = json_object_get_string(request_str); + assert(request); + + if (!strcmp(request, "name")) { + respond_name(socket->fd); + } else if (!strcmp(request, "opts")) { + respond_opts(socket->fd); + } else if (!strcmp(request, "hash")) { + respond_hash(socket->fd); + } else if (!strcmp(request, "data")) { + respond_data(socket->fd, request_json); + } else { + assert(false); + } + + json_object_put(request_json); + + log_info("Client disconnected: %s:%d", socket_ip, ntohs(socket->addr.sin_port)); + close(socket->fd); + + free(socket); + return 0; +} + +int main(void) { + log_info("Initializing salis data server"); + log_info("Connecting to database in: %s", DATA_PUSH_PATH); + sql_open(); + + signal(SIGINT, sig_handler); + signal(SIGTERM, sig_handler); + + log_info("Creating response header"); + g_response_header = json_object_new_object(); + json_object_object_add(g_response_header, "rowid", json_object_new_array()); + sql_exec( + 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');" + ); + + log_info("Binding to port: %d", PORT); + int opt = 1; + int socket_fd = socket(AF_INET, SOCK_STREAM, 0); + setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); + struct sockaddr_in socket_addr = { 0 }; + socket_addr.sin_family = AF_INET; + socket_addr.sin_addr.s_addr = INADDR_ANY; + socket_addr.sin_port = htons(PORT); + bind(socket_fd, (struct sockaddr *)&socket_addr, sizeof(struct sockaddr_in)); + + listen(socket_fd, BACKLOG); + log_info("Listening..."); + + while (true) { + struct Socket *socket = calloc(1, sizeof(struct Socket)); + 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); + } + + return 0; +} diff --git a/data/client.cpp b/data/client.cpp deleted file mode 100644 index 227ebaa..0000000 --- a/data/client.cpp +++ /dev/null @@ -1,749 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "logger.c" - -// ---------------------------------------------------------------------------- -// Defines -// ---------------------------------------------------------------------------- -#define COLOR_BLACK ImVec4(0.f, 0.f, 0.f, 1.f) -#define FONT_SIZE 12.f -#define FONT_SOURCE "/usr/share/fonts/droid/DroidSansMono.ttf" -#define GLSL_VERSION "#version 130" -#define PLOT_MAX_COLS 8 -#define PLOT_MIN_COLS 1 -#define PLOT_SCROLL_OFFSET 28.f - -#define IMGUI_WINDOW_FLAGS ( \ - ImGuiWindowFlags_NoBackground | \ - ImGuiWindowFlags_NoDecoration | \ - ImGuiWindowFlags_NoMove | \ - ImGuiWindowFlags_NoSavedSettings \ -) - -#define DATA_FETCH_INTERVAL 10 -#define DATA_FETCH_INTERVAL_SUBDIV 1000 - -#define DEFVAL_ENTRIES 0x800l -#define DEFVAL_NTH 1l -#define DEFVAL_X_AXIS 0 -#define DEFVAL_X_LOW 0l -#define DEFVAL_X_HIGH INT64_MAX -#define DEFVAL_HM_LEFT 0l -#define DEFVAL_HM_PIXEL_COUNT 0x400l - -// ---------------------------------------------------------------------------- -// Declarations -// ---------------------------------------------------------------------------- -enum Status { - STATUS_STOPPED, - STATUS_RUNNING, - STATUS_STOPPING, -}; - -struct CompString { - bool operator()(const char *a, const char *b) const { - return strcmp(a, b) < 0; - } -}; - -struct Plot { - const char *name; - const char *section; - std::vector traces; -}; - -// ---------------------------------------------------------------------------- -// Plots -// ---------------------------------------------------------------------------- -#include "arch_plots.cpp" - -template -std::array merge_array(const std::array &first, const std::array &second) { - std::array result{}; - for (size_t i = 0; i < N; i++) result[i] = first[i]; - for (size_t i = 0; i < M; i++) result[N + i] = second[i]; - return result; -} - -std::array g_core_traces = std::to_array({ - "rowid", - "step", -#define FOR_CORE(i) \ - "cycl_" #i, \ - "mall_" #i, \ - "pnum_" #i, \ - "pfst_" #i, \ - "plst_" #i, \ - "amb0_" #i, \ - "amb1_" #i, \ - "emb0_" #i, \ - "emb1_" #i, \ - "eliv_" #i, \ - "edea_" #i, - FOR_CORES -#undef FOR_CORE -}); - -std::array g_core_plots = std::to_array({ - {"cycl", "general", { -#define FOR_CORE(i) "cycl_" #i, - FOR_CORES -#undef FOR_CORE - }}, - {"mall", "general", { -#define FOR_CORE(i) "mall_" #i, - FOR_CORES -#undef FOR_CORE - }}, - {"pnum", "general", { -#define FOR_CORE(i) "pnum_" #i, - FOR_CORES -#undef FOR_CORE - }}, - {"ppop", "general", { -#define FOR_CORE(i) "pfst_" #i, "plst_" #i, - FOR_CORES -#undef FOR_CORE - }}, - {"ambs", "general", { -#define FOR_CORE(i) "amb0_" #i, "amb1_" #i, - FOR_CORES -#undef FOR_CORE - }}, - {"eevs", "general", { -#define FOR_CORE(i) "emb0_" #i, "emb1_" #i, "eliv_" #i, "edea_" #i, - FOR_CORES -#undef FOR_CORE - }}, -}); - -std::map, CompString> g_trace_map; -std::array g_traces = merge_array(g_core_traces, g_arch_traces); -std::array g_plots = merge_array(g_core_plots, g_arch_plots); - -#define TRACE_COUNT g_traces.size() -#define PLOT_COUNT g_plots.size() - -// ---------------------------------------------------------------------------- -// Globals -// ---------------------------------------------------------------------------- -GLFWwindow *g_window; -ImGuiIO *g_imgui_io; -ImGuiStyle *g_imgui_style; -ImPlotStyle *g_implot_style; - -const char *g_x_axes[] = { - "rowid", - "step", -#define FOR_CORE(i) "cycl_" #i, - FOR_CORES -#undef FOR_CORE -}; - -int g_status; -int g_x_axis = DEFVAL_X_AXIS; -int64_t g_entries = DEFVAL_ENTRIES; -int64_t g_nth = DEFVAL_NTH; -int64_t g_x_low = DEFVAL_X_LOW; -int64_t g_x_high = DEFVAL_X_HIGH; -int64_t g_hm_left = DEFVAL_HM_LEFT; -int64_t g_hm_pixel_count = DEFVAL_HM_PIXEL_COUNT; -int64_t g_hm_pixel_pow; // calculate on startup -int64_t g_x_current = -1l; - -thrd_t g_fetching_thread; -mtx_t g_fetching_mutex; -int g_trace_len; -int g_trace_offset; - -// Layout globals -bool g_data_col_visible = true; -bool g_plot_maximized; -bool g_plot_scroll; -float g_plot_scroll_current; -float g_plot_scroll_to; -float g_data_col_width; -float g_plot_cells_top[PLOT_MAX_COLS][PLOT_COUNT]; -float g_plot_cells_bottom[PLOT_MAX_COLS][PLOT_COUNT]; -Plot *g_plot_cells[PLOT_MAX_COLS][PLOT_COUNT]; -Plot *g_plot_selected = &g_plots[0]; -int g_plot_cols = 2; -int g_plot_col_selected; -int g_plot_row_selected; - -// ---------------------------------------------------------------------------- -// Data functions -// ---------------------------------------------------------------------------- -int64_t data_max_hm_pixel_pow(void) { - return (int64_t)floor(log2((double)(MVEC_SIZE - g_hm_left) / (double)g_hm_pixel_count)); -} - -void data_on_field_change(void) { - g_entries = std::clamp(g_entries, 1l, DEFVAL_ENTRIES); - g_nth = std::clamp(g_nth, DEFVAL_NTH, INT64_MAX); - g_x_low = std::clamp(g_x_low, DEFVAL_X_LOW, INT64_MAX); - g_x_high = std::clamp(g_x_high, g_x_low + 1l, DEFVAL_X_HIGH); - #if !defined(MVEC_LOOP) - g_hm_left = std::clamp(g_hm_left, DEFVAL_HM_LEFT, (int64_t)MVEC_SIZE); - #endif - g_hm_pixel_count = std::clamp(g_hm_pixel_count, 1l, DEFVAL_HM_PIXEL_COUNT); - g_hm_pixel_pow = std::clamp(g_hm_pixel_pow, 0l, data_max_hm_pixel_pow()); - - g_x_current = -1l; - - for (auto &trace : g_trace_map) { - trace.second.clear(); - } -} - -void data_reset_fields(void) { - g_entries = DEFVAL_ENTRIES; - g_nth = DEFVAL_NTH; - g_x_axis = DEFVAL_X_AXIS; - g_x_low = DEFVAL_X_LOW; - g_x_high = DEFVAL_X_HIGH; - g_hm_left = DEFVAL_HM_LEFT; - g_hm_pixel_count = DEFVAL_HM_PIXEL_COUNT; - g_hm_pixel_pow = data_max_hm_pixel_pow(); - - g_trace_len = 0; - g_trace_offset = 0; - - data_on_field_change(); -} - -void data_reset_plot_cells(void) { - memset(g_plot_cells, 0, PLOT_MAX_COLS * PLOT_COUNT * sizeof(nullptr)); - memset(g_plot_cells_top, 0, PLOT_MAX_COLS * PLOT_COUNT * sizeof(float)); - memset(g_plot_cells_bottom, 0, PLOT_MAX_COLS * PLOT_COUNT * sizeof(float)); -} - -void data_fetch(void) { - struct json_object *request = json_object_new_object(); - json_object_object_add(request, "request", json_object_new_string("data")); - json_object_object_add(request, "entries", json_object_new_int64(g_entries)); - json_object_object_add(request, "nth", json_object_new_int64(g_nth)); - json_object_object_add(request, "x-axis", json_object_new_string(g_x_axes[g_x_axis])); - json_object_object_add(request, "x-low", json_object_new_int64(g_x_low)); - json_object_object_add(request, "x-high", json_object_new_int64(g_x_high)); - json_object_object_add(request, "hm-left", json_object_new_int64(g_hm_left)); - json_object_object_add(request, "hm-pixel-count", json_object_new_int64(g_hm_pixel_count)); - json_object_object_add(request, "hm-pixel-pow", json_object_new_int64(g_hm_pixel_pow)); - json_object_object_add(request, "x-current", json_object_new_int64(g_x_current)); - const char *request_str = json_object_to_json_string(request); - - log_info("Sending request to server: %s", request_str); - int socket_fd = socket(AF_INET, SOCK_STREAM, 0); - struct sockaddr_in socket_addr; - memset(&socket_addr, 0, sizeof(struct sockaddr_in)); - socket_addr.sin_family = AF_INET; - socket_addr.sin_port = htons(PORT); - inet_pton(AF_INET, IP, &socket_addr.sin_addr); - if (connect(socket_fd, (struct sockaddr *)&socket_addr, sizeof(struct sockaddr_in))) assert(false); - json_object_to_fd(socket_fd, request, 0); - shutdown(socket_fd, SHUT_WR); - - struct json_object *response = json_object_from_fd(socket_fd); - const char *response_str = json_object_to_json_string(response); - log_info("Server responded with: %s", response_str); - - mtx_lock(&g_fetching_mutex); - - json_object_object_foreach(response, key, value) { - if (g_trace_map.contains(key)) { - for (size_t i = 0; i < json_object_array_length(value); i++) { - ImS64 point = json_object_get_int64(json_object_array_get_idx(value, i)); - g_trace_map.at(key).push_back(point); - } - } - } - - g_x_current = g_trace_map.at(g_x_axes[g_x_axis]).back(); - json_object_put(request); - json_object_put(response); - - g_trace_len = g_trace_map.at("rowid").size(); - - if (g_trace_len >= g_entries * 2) { - for (auto &trace : g_trace_map) { - trace.second.erase(trace.second.begin(), trace.second.end() - g_entries); - } - - g_trace_len = g_trace_map.at("rowid").size(); - } - - g_trace_offset = 0; - - if (g_trace_len > g_entries) { - g_trace_offset = g_trace_len - g_entries; - g_trace_len = g_entries; - } - - mtx_unlock(&g_fetching_mutex); -} - -int data_fetching_thread(void *data) { - (void)data; - - assert(!data); - assert(g_status == STATUS_RUNNING || g_status == STATUS_STOPPING); - - while (g_status == STATUS_RUNNING) { - data_fetch(); - - for (int i = 0; i < DATA_FETCH_INTERVAL_SUBDIV && g_status == STATUS_RUNNING; i++) { - usleep((DATA_FETCH_INTERVAL * 1000000) / DATA_FETCH_INTERVAL_SUBDIV); - } - } - - assert(g_status == STATUS_STOPPING); - g_status = STATUS_STOPPED; - return 0; -} - -void data_start_fetching(void) { - log_info("Starting data fetching thread"); - g_status = STATUS_RUNNING; - thrd_create(&g_fetching_thread, (thrd_start_t)data_fetching_thread, nullptr); -} - -void data_stop_fetching(void) { - assert(g_status == STATUS_RUNNING); - log_info("Stopping data fetching thread"); - g_status = STATUS_STOPPING; - thrd_join(g_fetching_thread, nullptr); -} - -// ---------------------------------------------------------------------------- -// GUI functions -// ---------------------------------------------------------------------------- -void gui_render_data_input(const char *label, int64_t *target) { - assert(label); - assert(target); - - if (ImGui::InputScalar(label, ImGuiDataType_U64, target, nullptr, nullptr, "%#lx")) { - data_on_field_change(); - } -} - -void gui_render_data_col(void) { - const ImGuiViewport *viewport = ImGui::GetMainViewport(); - const ImVec2 win_pos = viewport->Pos; - const ImVec2 win_size = ImVec2(-1.f, viewport->Size.y); - - ImGui::SetNextWindowPos(win_pos); - ImGui::SetNextWindowSize(win_size); - ImGui::Begin("data-col", nullptr, IMGUI_WINDOW_FLAGS); - g_data_col_width = ImGui::GetWindowWidth(); - - ImGui::SeparatorText("SALIS data client"); - ImGui::LabelText("name", NAME); - ImGui::LabelText("seed", "%#lx", SEED); - ImGui::LabelText("server", IP ":" PORT_STR); - ImGui::LabelText("arch", ARCH); - ImGui::LabelText("cores", "%d", CORES); - ImGui::LabelText("mvec-size", "%#lx", MVEC_SIZE); - #if defined(MVEC_LOOP) - ImGui::LabelText("mvec-loop", "true"); - #else - ImGui::LabelText("mvec-loop", "false"); - #endif - ImGui::LabelText("data-push", "%#lx", DATA_PUSH_INTERVAL); - - ImGui::SeparatorText("Data fields"); - - switch (g_status) { - case STATUS_STOPPED: - gui_render_data_input("entries", &g_entries); - gui_render_data_input("nth", &g_nth); - - if (ImGui::BeginCombo("x-axis", g_x_axes[g_x_axis])) { - for (int i = 0; i < CORES + 2; i++) { - if (ImGui::Selectable(g_x_axes[i], g_x_axis == i)) { - data_reset_fields(); - g_x_axis = i; - } - } - - ImGui::EndCombo(); - } - - gui_render_data_input("x-low", &g_x_low); - gui_render_data_input("x-high", &g_x_high); - gui_render_data_input("hm-left", &g_hm_left); - gui_render_data_input("hm-pxl-count", &g_hm_pixel_count); - gui_render_data_input("hm-pxl-pow", &g_hm_pixel_pow); - break; - case STATUS_RUNNING: - case STATUS_STOPPING: - ImGui::LabelText("entries", "%#lx", g_entries); - ImGui::LabelText("nth", "%#lx", g_nth); - ImGui::LabelText("x-axis", "%s", g_x_axes[g_x_axis]); - ImGui::LabelText("x-low", "%#lx", g_x_low); - ImGui::LabelText("x-high", "%#lx", g_x_high); - ImGui::LabelText("hm-left", "%#lx", g_hm_left); - ImGui::LabelText("hm-pxl-count", "%#lx", g_hm_pixel_count); - ImGui::LabelText("hm-pxl-pow", "%#lx", g_hm_pixel_pow); - } - - switch (g_status) { - case STATUS_STOPPED: - if (ImGui::Button("Run", ImVec2(-1.f, 0.f))) { - data_start_fetching(); - } - - if (ImGui::Button("Reset", ImVec2(-1.f, 0.f))) { - data_reset_fields(); - } - - break; - case STATUS_RUNNING: - if (ImGui::Button("Stop", ImVec2(-1.f, 0.f))) { - data_stop_fetching(); - } - - ImGui::LabelText("##", "Running"); - break; - case STATUS_STOPPING: - ImGui::LabelText("##", "Stopping"); - break; - } - - ImGui::SeparatorText("Layout"); - ImGui::SliderInt("cols", &g_plot_cols, PLOT_MIN_COLS, PLOT_MAX_COLS); - ImGui::End(); -} - -void gui_render_plot(const Plot *plot, const ImVec2 &frame_size=ImVec2(-1.f, 0.f)) { - int plot_flags = ImPlotFlags_NoMenus; - int axis_flags = ImPlotAxisFlags_NoMenus; - - if (g_status != STATUS_STOPPED) { - ImPlot::SetNextAxesToFit(); - plot_flags |= ImPlotFlags_NoInputs | ImPlotFlags_NoMouseText; - axis_flags |= ImPlotAxisFlags_NoHighlight; - } - - if (ImPlot::BeginPlot(plot->name, frame_size, plot_flags)) { - ImPlot::SetupAxes(nullptr, nullptr, axis_flags, axis_flags); - ImS64 *x = g_trace_map.at(g_x_axes[g_x_axis]).data() + g_trace_offset; - - for (auto &trace : plot->traces) { - ImS64 *y = g_trace_map.at(trace).data() + g_trace_offset; - ImPlot::PlotLine(trace, x, y, g_trace_len); - } - - ImPlot::EndPlot(); - } -} - -void gui_render_plots(void) { - const char *section_current = g_plots[0].section; - const char *section_next = nullptr; - bool plots_covered[PLOT_COUNT] = { 0 }; - - const ImGuiViewport *viewport = ImGui::GetMainViewport(); - const ImVec2 win_pos = g_data_col_visible ? ImVec2(g_data_col_width, viewport->Pos.y) : viewport->Pos; - const ImVec2 win_size = g_data_col_visible ? ImVec2(viewport->Size.x - g_data_col_width, -1.f) : ImVec2(viewport->Size.x, -1.f); - - if (g_plot_scroll) { - ImGui::SetNextWindowScroll(ImVec2(-1.f, g_plot_scroll_to)); - g_plot_scroll = false; - g_plot_scroll_to = 0.f; - } - - ImGui::SetNextWindowPos(win_pos); - ImGui::SetNextWindowSize(win_size); - ImGui::Begin("plots", nullptr, IMGUI_WINDOW_FLAGS); - g_plot_scroll_current = ImGui::GetScrollY(); - - int col = 0; - int row = 0; - - mtx_lock(&g_fetching_mutex); - - while (section_current) { - ImGui::SeparatorText(section_current); - ImGui::BeginTable("plots-table", g_plot_cols); - - for (size_t i = 0; i < PLOT_COUNT; i++) { - if (g_plots[i].section != section_current) { - section_next = (!section_next && !plots_covered[i]) ? g_plots[i].section : section_next; - continue; - } - - ImGui::TableNextColumn(); - g_plot_cells[col][row] = &g_plots[i]; - g_plot_cells_top[col][row] = ImGui::GetCursorPosY(); - - if (&g_plots[i] == g_plot_selected) { - g_plot_col_selected = col; - g_plot_row_selected = row; - g_implot_style->Colors[ImPlotCol_FrameBg] = g_imgui_style->Colors[ImGuiCol_FrameBg]; - } - - gui_render_plot(&g_plots[i]); - - if (&g_plots[i] == g_plot_selected) { - g_implot_style->Colors[ImPlotCol_FrameBg] = COLOR_BLACK; - } - - g_plot_cells_bottom[col][row] = ImGui::GetCursorPosY(); - col = (col + 1) % g_plot_cols; - row += col ? 0 : 1; - plots_covered[i] = true; - } - - section_current = section_next; - section_next = nullptr; - ImGui::EndTable(); - row += col ? 1 : 0; - col = 0; - } - - mtx_unlock(&g_fetching_mutex); - - ImGui::End(); -} - -void gui_render_plot_maximized(void) { - const ImGuiViewport *viewport = ImGui::GetMainViewport(); - ImGui::SetNextWindowPos(viewport->Pos); - ImGui::SetNextWindowSize(viewport->Size); - ImGui::Begin("plot-fullscreen", nullptr, IMGUI_WINDOW_FLAGS); - - gui_render_plot(g_plot_selected, viewport->Size); - - ImGui::End(); -} - -void gui_plot_queue_scroll(int col_selected, int row_selected) { - const ImGuiViewport *viewport = ImGui::GetMainViewport(); - float plot_top = g_plot_cells_top[col_selected][row_selected]; - float plot_bottom = g_plot_cells_bottom[col_selected][row_selected]; - float win_top = g_plot_scroll_current; - float win_bottom = win_top + viewport->Size.y; - - if (plot_bottom > win_bottom) { - g_plot_scroll_to = win_top + (plot_bottom - win_bottom); - g_plot_scroll = true; - } - - if (plot_top < win_top) { - g_plot_scroll_to = plot_top - PLOT_SCROLL_OFFSET; - g_plot_scroll = true; - } -} - -void gui_render(void) { - if (g_plot_maximized) { - gui_render_plot_maximized(); - return; - } - - if (g_data_col_visible) { - gui_render_data_col(); - } - - gui_render_plots(); -} - -// ---------------------------------------------------------------------------- -// Main functions -// ---------------------------------------------------------------------------- -void win_sig_handler(int signo) { - (void)signo; - - log_warn("Signal received, will stop SALIS data client..."); - - if (g_status == STATUS_RUNNING) { - data_stop_fetching(); - } - - glfwSetWindowShouldClose(g_window, GLFW_TRUE); -} - -void win_error_callback(int error, const char* description) { - log_warn("GLFW error %d: %s", error, description); -} - -void win_key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) { - (void)window; - (void)scancode; - - if (action != GLFW_PRESS || ImGui::IsAnyItemActive()) { - return; - } - - if (g_plot_maximized) { - if (mods == GLFW_MOD_CONTROL && key == GLFW_KEY_C) { - glfwSetWindowShouldClose(g_window, GLFW_TRUE); - } - - if (mods == 0 && key == GLFW_KEY_F) { - g_plot_maximized = !g_plot_maximized; - } - - return; - } - - switch (mods) { - case GLFW_MOD_CONTROL: - switch (key) { - case GLFW_KEY_C: - glfwSetWindowShouldClose(g_window, GLFW_TRUE); - break; - case GLFW_KEY_N: - g_data_col_visible = !g_data_col_visible; - break; - case GLFW_KEY_LEFT: - g_plot_cols -= g_plot_cols > 1 ? 1 : 0; - data_reset_plot_cells(); - break; - case GLFW_KEY_RIGHT: - g_plot_cols += g_plot_cols < PLOT_MAX_COLS ? 1 : 0; - data_reset_plot_cells(); - break; - } - - break; - - case 0: - switch (key) { - case GLFW_KEY_LEFT: - g_plot_col_selected -= g_plot_col_selected ? 1 : 0; - g_plot_selected = g_plot_cells[g_plot_col_selected][g_plot_row_selected]; - break; - case GLFW_KEY_RIGHT: - g_plot_col_selected += (g_plot_col_selected < PLOT_MAX_COLS - 1 && g_plot_cells[g_plot_col_selected + 1][g_plot_row_selected]) ? 1 : 0; - g_plot_selected = g_plot_cells[g_plot_col_selected][g_plot_row_selected]; - break; - case GLFW_KEY_UP: - g_plot_row_selected -= g_plot_row_selected ? 1 : 0; - g_plot_selected = g_plot_cells[g_plot_col_selected][g_plot_row_selected]; - gui_plot_queue_scroll(g_plot_col_selected, g_plot_row_selected); - break; - case GLFW_KEY_DOWN: - g_plot_row_selected += (g_plot_row_selected < (int)PLOT_COUNT - 1 && g_plot_cells[g_plot_col_selected][g_plot_row_selected + 1]) ? 1 : 0; - g_plot_selected = g_plot_cells[g_plot_col_selected][g_plot_row_selected]; - gui_plot_queue_scroll(g_plot_col_selected, g_plot_row_selected); - break; - case GLFW_KEY_F: - g_plot_maximized = !g_plot_maximized; - break; - case GLFW_KEY_SPACE: - switch (g_status) { - case STATUS_STOPPED: - data_start_fetching(); - break; - case STATUS_RUNNING: - data_stop_fetching(); - break; - } - - break; - } - - break; - } -} - -int main(int argc, char **argv) { - (void)argc; - (void)argv; - - signal(SIGINT, win_sig_handler); - signal(SIGTERM, win_sig_handler); - - log_info("Starting SALIS data client"); - - log_info("Initializing GLFW"); - glfwSetErrorCallback(win_error_callback); - glfwInitHint(GLFW_WAYLAND_LIBDECOR, GLFW_WAYLAND_DISABLE_LIBDECOR); - if (!glfwInit()) assert(false); - - float scale = ImGui_ImplGlfw_GetContentScaleForMonitor(glfwGetPrimaryMonitor()); - g_window = glfwCreateWindow((int)(800 * scale), (int)(600 * scale), "SALIS data client", nullptr, nullptr); - assert(g_window); - glfwSetKeyCallback(g_window, win_key_callback); - glfwMakeContextCurrent(g_window); - glfwSwapInterval(1); // enable vsync - - log_info("Initializing ImGui"); - IMGUI_CHECKVERSION(); - ImGui::CreateContext(); - ImPlot::CreateContext(); - - g_imgui_io = &ImGui::GetIO(); - g_imgui_io->Fonts->AddFontFromFileTTF(FONT_SOURCE); - g_imgui_io->IniFilename = nullptr; - - g_imgui_style = &ImGui::GetStyle(); - g_imgui_style->Colors[ImGuiCol_WindowBg] = COLOR_BLACK; - g_imgui_style->FontScaleDpi = scale; - g_imgui_style->FontSizeBase = FONT_SIZE; - g_imgui_style->ItemSpacing = ImVec2(g_imgui_style->ItemSpacing.x, 2.f); - g_imgui_style->ScaleAllSizes(scale); - - g_implot_style = &ImPlot::GetStyle(); - g_implot_style->Colors[ImPlotCol_FrameBg] = COLOR_BLACK; - - ImGui_ImplGlfw_InitForOpenGL(g_window, true); - ImGui_ImplOpenGL3_Init(GLSL_VERSION); - - for (auto &i : g_traces) { - g_trace_map[i] = {}; - g_trace_map[i].reserve(g_entries); - } - - g_hm_pixel_pow = data_max_hm_pixel_pow(); - - mtx_init(&g_fetching_mutex, mtx_plain); - - while (!glfwWindowShouldClose(g_window)) { - glfwPollEvents(); - - ImGui_ImplOpenGL3_NewFrame(); - ImGui_ImplGlfw_NewFrame(); - ImGui::NewFrame(); - - gui_render(); - - ImGui::Render(); - int display_w; - int display_h; - glfwGetFramebufferSize(g_window, &display_w, &display_h); - glViewport(0, 0, display_w, display_h); - glClearColor(0.f, 0.f, 0.f, 1.f); - glClear(GL_COLOR_BUFFER_BIT); - ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); - glfwSwapBuffers(g_window); - } - - mtx_destroy(&g_fetching_mutex); - - ImGui_ImplOpenGL3_Shutdown(); - ImGui_ImplGlfw_Shutdown(); - ImPlot::DestroyContext(); - ImGui::DestroyContext(); - - log_info("Stopping SALIS data client"); - glfwDestroyWindow(g_window); - glfwTerminate(); - - return 0; -} diff --git a/data/render.c b/data/render.c deleted file mode 100644 index 08ff6dd..0000000 --- a/data/render.c +++ /dev/null @@ -1,91 +0,0 @@ -#include -SQLITE_EXTENSION_INIT1 - -#include -#include -#include -#include - -#include "compress.c" - -void eva_render(sqlite3_context *context, int argc, sqlite3_value **argv) { - assert(context); - assert(argc == 4); - assert(argv); - - (void)argc; - - size_t left = (size_t)sqlite3_value_int(argv[0]); -#if defined(MVEC_LOOP) - left %= MVEC_SIZE; -#endif - - size_t px_count = (size_t)sqlite3_value_int(argv[1]); - size_t px_pow = (size_t)sqlite3_value_int(argv[2]); - size_t px_res = 1 << px_pow; -#if !defined(MVEC_LOOP) -#if !defined(NDEBUG) - size_t right = left + px_res * px_count; -#endif - assert(left < MVEC_SIZE); - assert(right <= MVEC_SIZE); -#endif - - const void *blob = sqlite3_value_blob(argv[3]); - size_t blob_size = (size_t)sqlite3_value_bytes(argv[3]); - - // Inflate blob - size_t out_size = sizeof(uint64_t) * px_count; - uint64_t *eva = sqlite3_malloc(EVA_SIZE); - uint64_t *out = sqlite3_malloc(out_size); - - struct InflateParams params = { - .avail_in = blob_size, - .size = EVA_SIZE, - .in = (Bytef *)blob, - .out = (Bytef *)eva, - }; - - comp_inflate(¶ms); - comp_inflate_end(¶ms); - - // Render image - for (size_t i = 0; i < px_count; i++) { - out[i] = 0; - - for (size_t j = 0; j < px_res; j++) { - size_t in_coord = left + i * px_res + j; -#if defined(MVEC_LOOP) - in_coord %= MVEC_SIZE; -#endif - out[i] += eva[in_coord]; - } - } - - sqlite3_free(eva); - - // Transform rendered image into textual representation - // A comma-separated list of hexadecimal integers - char *csv = sqlite3_malloc(px_count * 17 + 1); - char *ptr = csv; - - for (size_t i = 0; i < px_count; i++) { - ptr += sprintf(ptr, "%lx ", out[i]); - } - - *(--ptr) = '\0'; - sqlite3_free(out); - - sqlite3_result_text(context, csv, -1, sqlite3_free); -} - -int sqlite3_render_init(sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi) { - assert(db); - assert(pzErrMsg); - assert(pApi); - - (void)pzErrMsg; - - SQLITE_EXTENSION_INIT2(pApi); - return sqlite3_create_function(db, "eva_render", 4, SQLITE_DETERMINISTIC | SQLITE_INNOCUOUS | SQLITE_UTF8, NULL, eva_render, NULL, NULL); -} diff --git a/data/server.c b/data/server.c deleted file mode 100644 index d54d853..0000000 --- a/data/server.c +++ /dev/null @@ -1,224 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#include "logger.c" -#include "sql.c" - -#define BACKLOG 10 - -struct Socket { - int fd; - struct sockaddr_in addr; -}; - -struct json_object *g_response_header; - -// ---------------------------------------------------------------------------- -// SQL callbacks -// ---------------------------------------------------------------------------- -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(!strcmp(sqlite3_column_name(sql_stmt, 0), "name")); - - const char *col_name = (const char *)sqlite3_column_text(sql_stmt, 0); - struct json_object *response = (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()); - } -} - -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); - - if (col_data) { - if (sqlite3_column_type(sql_stmt, i) == SQLITE_BLOB) { - // TODO: render blobs in parallel - } else { - json_object_array_add(col_data, json_object_new_int64(sqlite3_column_int64(sql_stmt, i))); - } - } - } -} - -// ---------------------------------------------------------------------------- -// Main functions -// ---------------------------------------------------------------------------- -void sig_handler(int signo) { - (void)signo; - log_warn("Signal received, will stop SALIS data server"); - json_object_put(g_response_header); - sql_close(); - exit(0); -} - -void respond_name(int socket_fd) { - log_info("Client requested simulation name"); - - struct json_object *sim_name = json_object_new_object(); - json_object_object_add(sim_name, "name", json_object_new_string(NAME)); - json_object_to_fd(socket_fd, sim_name, 0); - json_object_put(sim_name); -} - -void respond_opts(int socket_fd) { - log_info("Client requested simulation options"); - - struct json_object *sim_opts = json_object_from_file(SIM_OPTS); - json_object_to_fd(socket_fd, sim_opts, 0); - json_object_put(sim_opts); -} - -void respond_hash(int socket_fd) { - log_info("Client requested git hash"); - - char buff[41] = { 0 }; - FILE *pipe = popen("git rev-parse HEAD", "r"); - fread(buff, sizeof(char), 40, pipe); - pclose(pipe); - - struct json_object *git_hash = json_object_new_object(); - json_object_object_add(git_hash, "hash", json_object_new_string(buff)); - json_object_to_fd(socket_fd, git_hash, 0); - json_object_put(git_hash); -} - -void respond_data(int socket_fd, struct json_object *request) { - assert(request); - - const char *request_str = json_object_to_json_string(request); - log_info("Client requested simulation data with the following parameters: %s", request_str); - const char *x_axis = json_object_get_string(json_object_object_get(request, "x-axis")); - int64_t x_current = json_object_get_int64(json_object_object_get(request, "x-current")); - int64_t x_high = json_object_get_int64(json_object_object_get(request, "x-high")); - 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 json_object *response = NULL; - json_object_deep_copy(g_response_header, &response, NULL); - - sql_exec( - 0, NULL, NULL, - sql_callback_add_data, - response, - "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 " - "order by %s%s desc limit %ld" - ") order by %s asc;", - x_axis_pref, - x_axis, - x_current, - x_axis_pref, - x_axis, - x_high, - nth, - x_axis_pref, - x_axis, - entries, - 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); - - shutdown(socket_fd, SHUT_WR); -} - -int handle_client(struct Socket *socket) { - assert(socket); - - char socket_ip[INET_ADDRSTRLEN]; - inet_ntop(AF_INET, &socket->addr.sin_addr, socket_ip, INET_ADDRSTRLEN); - log_info("Client connected: %s:%d", socket_ip, ntohs(socket->addr.sin_port)); - - struct json_object *request_json = json_object_from_fd(socket->fd); - struct json_object *request_str = NULL; - - if (!json_object_object_get_ex(request_json, "request", &request_str)) assert(false); - - const char *request = json_object_get_string(request_str); - assert(request); - - if (!strcmp(request, "name")) { - respond_name(socket->fd); - } else if (!strcmp(request, "opts")) { - respond_opts(socket->fd); - } else if (!strcmp(request, "hash")) { - respond_hash(socket->fd); - } else if (!strcmp(request, "data")) { - respond_data(socket->fd, request_json); - } else { - assert(false); - } - - json_object_put(request_json); - - log_info("Client disconnected: %s:%d", socket_ip, ntohs(socket->addr.sin_port)); - close(socket->fd); - - free(socket); - return 0; -} - -int main(void) { - log_info("Initializing salis data server"); - log_info("Connecting to database in: %s", DATA_PUSH_PATH); - sql_open(); - - signal(SIGINT, sig_handler); - signal(SIGTERM, sig_handler); - - log_info("Creating response header"); - g_response_header = json_object_new_object(); - json_object_object_add(g_response_header, "rowid", json_object_new_array()); - sql_exec( - 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');" - ); - - log_info("Binding to port: %d", PORT); - int opt = 1; - int socket_fd = socket(AF_INET, SOCK_STREAM, 0); - setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); - struct sockaddr_in socket_addr = { 0 }; - socket_addr.sin_family = AF_INET; - socket_addr.sin_addr.s_addr = INADDR_ANY; - socket_addr.sin_port = htons(PORT); - bind(socket_fd, (struct sockaddr *)&socket_addr, sizeof(struct sockaddr_in)); - - listen(socket_fd, BACKLOG); - log_info("Listening..."); - - while (true) { - struct Socket *socket = calloc(1, sizeof(struct Socket)); - 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); - } - - return 0; -} diff --git a/salis.py b/salis.py index 9d0613b..1feb041 100755 --- a/salis.py +++ b/salis.py @@ -401,7 +401,7 @@ if args.command == "load": # Populate for server if args.command == "server": - ns.b = Build("data/server.c", log) + ns.b = Build("core/server.c", log) pop_data_push_vars() pop_sim_path_vars() pop_net_vars() @@ -409,7 +409,7 @@ if args.command == "server": # Populate for client if args.command == "client": - ns.b = Build("data/client.cpp", log, cpp=True) + ns.b = Build("core/client.cpp", log, cpp=True) pop_net_vars() pop_general() ns.b.defines.add(f"-DIP=\"{args.ip}\"") -- cgit v1.3