aboutsummaryrefslogtreecommitdiff
path: root/data
diff options
context:
space:
mode:
authorPaul Oliver <contact@pauloliver.dev>2026-05-12 22:52:37 +0200
committerPaul Oliver <contact@pauloliver.dev>2026-05-25 04:38:15 +0200
commitbe2c37ac8c8e317eb7e05829ff2078c1b3bbce4e (patch)
tree46caefa23c106ae789bdd49ab59daeca69cb2d3d /data
parent522e11c8086b7d8ab76b9be07c1861f35ed2327f (diff)
Reimplement client with ImGui and ImPlot (scaffold)
Diffstat (limited to 'data')
-rw-r--r--data/client.c522
-rw-r--r--data/client.cpp528
-rw-r--r--data/plots.c35
-rw-r--r--data/server.c1
4 files changed, 528 insertions, 558 deletions
diff --git a/data/client.c b/data/client.c
deleted file mode 100644
index d5e8e56..0000000
--- a/data/client.c
+++ /dev/null
@@ -1,522 +0,0 @@
-#include <curses.h>
-#include <locale.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "logger.c"
-#include "plots.c"
-#include "tui.c"
-
-#define UI_AVAIL_PLOTS_COL PANE_AND_MARGIN_WIDTH
-#define UI_WINDOWS_COL (PANE_AND_MARGIN_WIDTH * 2)
-#define UI_PLOTS_COL (PANE_AND_MARGIN_WIDTH * 3)
-
-#define MAX_WINDOW_ROWS 4
-#define MAX_WINDOW_COLS 4
-#define MAX_WINDOW_PLOTS (MAX_WINDOW_ROWS * MAX_WINDOW_COLS)
-
-#define CTRL(x) (x & 0x1f)
-
-enum {
- PAIR_HEADER = 1,
- PAIR_SELECTED = 2,
- PAIR_TO_BE_CREATED = 3,
- PAIR_TO_BE_UPDATED = 4,
- PAIR_TO_BE_REMOVED = 5,
-};
-
-enum UIColumn {
- UICOL_AVAIL_PLOTS,
- UICOL_WINDOWS,
- UICOL_PLOTS,
- UICOL_COUNT,
-};
-
-enum WindowState {
- WINDOW_TO_BE_CREATED,
- WINDOW_TO_BE_UPDATED,
- WINDOW_IS_LIVE,
- WINDOW_TO_BE_REMOVED,
-};
-
-enum WindowPlotState {
- PLOT_TO_BE_CREATED,
- PLOT_IS_LIVE,
- PLOT_TO_BE_REMOVED,
-};
-
-struct WindowHandle {
- size_t wid;
- size_t rows;
- size_t cols;
- size_t rows_update;
- size_t cols_update;
- enum WindowState state;
- size_t plot_count;
- size_t plot_sel;
- enum WindowPlotState plot_states[MAX_WINDOW_PLOTS];
- struct PlotDef *plot_defs[MAX_WINDOW_PLOTS];
-};
-
-// Globals
-bool g_exit;
-enum UIColumn g_col_sel;
-size_t g_apsel;
-size_t g_wsel;
-size_t g_apscroll;
-size_t g_wscroll;
-size_t g_pscroll;
-size_t g_wid_count;
-struct WindowHandle *g_window_handles;
-size_t g_window_count;
-size_t g_window_cap;
-
-// ----------------------------------------------------------------------------
-// UI functions
-// ----------------------------------------------------------------------------
-void ui_print_sim_description(void) {
- // Simulation desciption
- int l = 1;
-
- tui_line(false, l++, PAIR_HEADER, A_BOLD, "SALIS DATA CLIENT");
- tui_str_field(l++, "name", NAME);
- tui_ulx_field(l++, "seed", SEED);
- tui_str_field(l++, "conn", IP ":" PORT_STR);
- tui_str_field(l++, "anc", ANC);
- tui_str_field(l++, "arch", ARCH);
- tui_ulx_field(l++, "asav", AUTOSAVE_INTERVAL);
- tui_ulx_field(l++, "cres", CORES);
-#if defined(MUTA_FLIP)
- tui_str_field(l++, "mflp", "true");
-#else
- tui_str_field(l++, "mflp", "false");
-#endif
- tui_ulx_field(l++, "mrng", MUTA_RANGE);
- tui_ulx_field(l++, "size", MVEC_SIZE);
-#if defined(MVEC_LOOP)
- tui_str_field(l++, "loop", "true");
-#else
- tui_str_field(l++, "loop", "false");
-#endif
-#if defined(COMPRESS)
- tui_str_field(l++, "xsav", "enabled");
-#else
- tui_str_field(l++, "xsav", "disabled");
-#endif
- tui_ulx_field(l++, "dpsi", DATA_PUSH_INTERVAL);
-
- // Window summary
- l++;
-
- tui_line(false, l++, PAIR_HEADER, A_BOLD, "SUMMARY");
- tui_uld_field(l++, "wcnt", g_window_count);
- tui_uld_field(l++, "wcap", g_window_cap);
- tui_uld_field(l++, "widc", g_wid_count);
-}
-
-void ui_print_avail_plots(void) {
- int l = 1;
- int pair = g_col_sel == UICOL_AVAIL_PLOTS ? PAIR_SELECTED : PAIR_HEADER;
-
- tui_field(l++, UI_AVAIL_PLOTS_COL, pair, A_BOLD, "AVAIL PLOTS [%ld:%ld]", g_apsel, g_apscroll);
-
- for (size_t i = g_apscroll; i < g_general_plots_count; i++) {
- pair = i == g_apsel ? PAIR_SELECTED : PAIR_NORMAL;
- tui_field(l++, UI_AVAIL_PLOTS_COL, pair, A_NORMAL, g_general_plots_def[i].name);
- }
-}
-
-void ui_print_windows(void) {
- int l = 1;
- int pair = g_col_sel == UICOL_WINDOWS ? PAIR_SELECTED : PAIR_HEADER;
-
- struct WindowHandle *whdl = &g_window_handles[g_wsel];
- tui_field(l++, UI_WINDOWS_COL, pair, A_BOLD, "WINDOWS [%ld:%ld]", whdl->wid, g_wscroll);
-
- for (size_t i = g_wscroll; i < g_window_count; i++) {
- whdl = &g_window_handles[i];
- char mark = ' ';
-
- switch (whdl->state) {
- case WINDOW_TO_BE_CREATED:
- pair = PAIR_TO_BE_CREATED;
- mark = '+';
- break;
- case WINDOW_TO_BE_UPDATED:
- pair = PAIR_TO_BE_UPDATED;
- mark = 'u';
- break;
- case WINDOW_IS_LIVE:
- pair = PAIR_NORMAL;
- break;
- case WINDOW_TO_BE_REMOVED:
- pair = PAIR_TO_BE_REMOVED;
- mark = 'd';
- break;
- }
-
- pair = i == g_wsel ? PAIR_SELECTED : pair;
- tui_field(l++, UI_WINDOWS_COL, pair, A_NORMAL, "wid:%ld [%dx%d] %c", whdl->wid, whdl->rows_update, whdl->cols_update, mark);
- }
-}
-
-void ui_print_plots(void) {
- int l = 1;
- int pair = g_col_sel == UICOL_PLOTS ? PAIR_SELECTED : PAIR_HEADER;
-
- struct WindowHandle *whdl = &g_window_handles[g_wsel];
- tui_field(l++, UI_PLOTS_COL, pair, A_BOLD, "PLOTS [%ld:%ld]", whdl->plot_sel, g_pscroll);
-
- if (!g_window_count) return;
-
- for (size_t i = g_pscroll; i < whdl->plot_count; i++) {
- struct PlotDef *plot_def = whdl->plot_defs[i];
- enum WindowPlotState plot_state = whdl->plot_states[i];
- char mark = ' ';
-
- switch (plot_state) {
- case PLOT_TO_BE_CREATED:
- pair = PAIR_TO_BE_CREATED;
- mark = '+';
- break;
- case PLOT_IS_LIVE:
- pair = PAIR_NORMAL;
- break;
- case PLOT_TO_BE_REMOVED:
- pair = PAIR_TO_BE_REMOVED;
- mark = 'd';
- break;
- }
-
- pair = i == whdl->plot_sel ? PAIR_SELECTED : pair;
- tui_field(l++, UI_PLOTS_COL, pair, A_NORMAL, "%s %c", plot_def->name, mark);
- plot_def++;
- }
-}
-
-void ui_print_footer(void) {
- tui_field(LINES - 1, 1, PAIR_NORMAL, A_NORMAL, "[+] new window | [enter] add plot | [x] delete elem | [ctrl+c] quit");
-}
-
-void ui_print(void) {
- ui_print_sim_description();
- ui_print_avail_plots();
- ui_print_windows();
- ui_print_plots();
- ui_print_footer();
-}
-
-// ----------------------------------------------------------------------------
-// Control function
-// ----------------------------------------------------------------------------
-void ev_scroll(int ev) {
- size_t *scroll_var = NULL;
-
- switch (g_col_sel) {
- case UICOL_AVAIL_PLOTS:
- scroll_var = &g_apscroll;
- break;
- case UICOL_WINDOWS:
- scroll_var = &g_wscroll;
- break;
- case UICOL_PLOTS:
- scroll_var = &g_pscroll;
- break;
- default:;
- }
-
- assert(scroll_var);
-
- switch (ev) {
- case 'w':
- *scroll_var += 1;
- break;
- case 's':
- *scroll_var -= (*scroll_var ? 1 : 0);
- break;
- case 'q':
- *scroll_var = 0;
- break;
- }
-}
-
-void ev_new_window(void) {
- if (g_window_count == g_window_cap) {
- // Reallocate dynamic array
- size_t new_window_cap = g_window_cap * 2;
- struct WindowHandle *new_window_handles = calloc(new_window_cap, sizeof(struct WindowHandle));
- memcpy(new_window_handles, g_window_handles, sizeof(struct WindowHandle) * g_window_count);
- free(g_window_handles);
- g_window_cap = new_window_cap;
- g_window_handles = new_window_handles;
- }
-
- g_window_count++;
- g_window_handles[g_window_count - 1] = (struct WindowHandle){
- .wid = g_wid_count++,
- .rows = 2,
- .cols = 2,
- .rows_update = 2,
- .cols_update = 2,
- .state = WINDOW_TO_BE_CREATED,
- };
-}
-
-void ev_delete_window_handle(size_t widx) {
- assert(g_window_count);
- assert(widx < g_window_count);
- assert(g_window_handles[widx].state == WINDOW_TO_BE_CREATED);
-
- for (size_t i = widx; i < g_window_count - 1; i++) {
- memcpy(&g_window_handles[i], &g_window_handles[i + 1], sizeof(struct WindowHandle));
- }
-
- g_window_handles[g_window_count - 1] = (struct WindowHandle){ 0 };
- g_window_count--;
- g_wsel -= (g_window_count && g_wsel == g_window_count) ? 1 : 0;
-}
-
-void ev_add_plot(void) {
- assert(g_col_sel == UICOL_AVAIL_PLOTS);
- assert(g_window_count);
-
- struct WindowHandle *whdl = &g_window_handles[g_wsel];
- size_t max_plots = whdl->rows_update * whdl->cols_update;
- size_t pidx = 0;
-
- do {
- if (!whdl->plot_defs[pidx]) break;
- pidx++;
- } while (pidx < max_plots);
-
- if (pidx == max_plots) return;
-
- whdl->plot_count++;
- whdl->plot_states[pidx] = PLOT_TO_BE_CREATED;
- whdl->plot_defs[pidx] = &g_general_plots_def[g_apsel];
-}
-
-void ev_delete_plot(size_t widx) {
- assert(g_window_count);
- assert(widx < g_window_count);
-
- struct WindowHandle *whdl = &g_window_handles[g_wsel];
- assert(whdl->plot_count);
- assert(whdl->plot_sel < whdl->plot_count);
- assert(whdl->plot_states[whdl->plot_sel] == PLOT_TO_BE_CREATED);
-
- for (size_t i = whdl->plot_sel; i < whdl->plot_count - 1; i++) {
- whdl->plot_states[i] = whdl->plot_states[i + 1];
- whdl->plot_defs[i] = whdl->plot_defs[i + 1];
- }
-
- whdl->plot_states[whdl->plot_count - 1] = 0;
- whdl->plot_defs[whdl->plot_count - 1] = NULL;
- whdl->plot_count--;
-
- if (!whdl->plot_count) {
- whdl->plot_sel = 0;
- } else if (whdl->plot_sel >= whdl->plot_count) {
- whdl->plot_sel = whdl->plot_count - 1;
- }
-}
-
-void ev_delete_elem(void) {
- if (g_col_sel == UICOL_WINDOWS && g_window_count) {
- struct WindowHandle *whdl = &g_window_handles[g_wsel];
-
- switch (whdl->state) {
- case WINDOW_TO_BE_CREATED:
- ev_delete_window_handle(g_wsel);
- break;
- case WINDOW_TO_BE_UPDATED:
- break;
- case WINDOW_IS_LIVE:
- break;
- case WINDOW_TO_BE_REMOVED:
- break;
- }
- }
-
- if (g_col_sel == UICOL_PLOTS && g_window_count && g_window_handles[g_wsel].plot_count) {
- struct WindowHandle *whdl = &g_window_handles[g_wsel];
-
- switch (whdl->plot_states[whdl->plot_sel]) {
- case PLOT_TO_BE_CREATED:
- ev_delete_plot(g_wsel);
- break;
- case PLOT_IS_LIVE:
- break;
- case PLOT_TO_BE_REMOVED:
- break;
- }
- }
-}
-
-void ev_resize_window(int ev) {
- assert(g_col_sel == UICOL_WINDOWS);
- assert(g_window_count);
-
- struct WindowHandle *whdl = &g_window_handles[g_wsel];
-
- switch (ev) {
- case 'A':
- if (whdl->cols_update > 1 && (whdl->rows_update * (whdl->cols_update - 1)) >= whdl->plot_count) whdl->cols_update--;
- break;
- case 'D':
- whdl->cols_update += whdl->cols_update < MAX_WINDOW_COLS ? 1 : 0;
- break;
- case 'W':
- if (whdl->rows_update > 1 && (whdl->cols_update * (whdl->rows_update - 1)) >= whdl->plot_count) whdl->rows_update--;
- break;
- case 'S':
- whdl->rows_update += whdl->rows_update < MAX_WINDOW_ROWS ? 1 : 0;
- break;
- }
-}
-
-void ev_swap_plots(int ev) {
- assert(g_col_sel == UICOL_PLOTS);
- assert(g_window_count);
-
- struct WindowHandle *whdl = &g_window_handles[g_wsel];
- size_t pidx1;
- size_t pidx2;
-
- switch (ev) {
- case 'W':
- if (!whdl->plot_count || !whdl->plot_sel) return;
- pidx1 = whdl->plot_sel;
- pidx2 = whdl->plot_sel - 1;
- whdl->plot_sel--;
- break;
- case 'S':
- if (!whdl->plot_count || whdl->plot_sel >= whdl->plot_count - 1) return;
- pidx1 = whdl->plot_sel;
- pidx2 = whdl->plot_sel + 1;
- whdl->plot_sel++;
- break;
- }
-
- enum WindowPlotState tmp_state = whdl->plot_states[pidx1];
- whdl->plot_states[pidx1] = whdl->plot_states[pidx2];
- whdl->plot_states[pidx2] = tmp_state;
-
- struct PlotDef *tmp_def = whdl->plot_defs[pidx1];
- whdl->plot_defs[pidx1] = whdl->plot_defs[pidx2];
- whdl->plot_defs[pidx2] = tmp_def;
-}
-
-void ev_handle(void) {
- int ev = getch();
-
- switch (ev) {
- case CTRL('c'):
- g_exit = true;
- break;
- case KEY_RESIZE:
- tui_line_buff_resize();
- break;
- case 'w':
- case 's':
- case 'q':
- ev_scroll(ev);
- break;
- case 'Q':
- g_apscroll = 0;
- g_wscroll = 0;
- g_pscroll = 0;
- break;
- case KEY_LEFT:
- g_col_sel -= g_col_sel ? 1 : 0;
- break;
- case KEY_RIGHT:
- g_col_sel += g_col_sel < UICOL_COUNT - 1 ? 1 : 0;
- break;
- case KEY_UP:
- if (g_col_sel == UICOL_AVAIL_PLOTS && g_apsel) g_apsel--;
- if (g_col_sel == UICOL_WINDOWS && g_wsel) g_wsel--;
- if (g_col_sel == UICOL_PLOTS && g_window_count && g_window_handles[g_wsel].plot_sel) g_window_handles[g_wsel].plot_sel--;
- break;
- case KEY_DOWN:
- if (g_col_sel == UICOL_AVAIL_PLOTS && g_apsel < g_general_plots_count - 1) g_apsel++;
- if (g_col_sel == UICOL_WINDOWS && g_window_count && g_wsel < g_window_count - 1) g_wsel++;
- if (g_col_sel == UICOL_PLOTS && g_window_count && g_window_handles[g_wsel].plot_count && g_window_handles[g_wsel].plot_sel < g_window_handles[g_wsel].plot_count - 1) g_window_handles[g_wsel].plot_sel++;
- break;
- case '+':
- ev_new_window();
- break;
- case '\n':
- if (g_col_sel == UICOL_AVAIL_PLOTS && g_window_count) ev_add_plot();
- break;
- case 'x':
- ev_delete_elem();
- break;
- case 'A':
- case 'D':
- case 'W':
- case 'S':
- if (g_col_sel == UICOL_WINDOWS && g_window_count) ev_resize_window(ev);
- if (g_col_sel == UICOL_PLOTS && g_window_count) ev_swap_plots(ev);
- break;
- default:
- break;
- }
-}
-
-// ----------------------------------------------------------------------------
-// Main functions
-// ----------------------------------------------------------------------------
-void init(void) {
- log_info("Initializing salis data client");
-
- setlocale(LC_ALL, "");
-
- initscr();
- raw();
- noecho();
- curs_set(0);
- keypad(stdscr, TRUE);
-
- start_color();
- init_color(COLOR_BLACK, 0, 0, 0);
-
- init_pair(PAIR_NORMAL, COLOR_WHITE, COLOR_BLACK);
- init_pair(PAIR_HEADER, COLOR_BLUE, COLOR_BLACK);
- init_pair(PAIR_SELECTED, COLOR_YELLOW, COLOR_BLACK);
- init_pair(PAIR_TO_BE_CREATED, COLOR_GREEN, COLOR_BLACK);
- init_pair(PAIR_TO_BE_UPDATED, COLOR_GREEN, COLOR_BLACK);
- init_pair(PAIR_TO_BE_REMOVED, COLOR_RED, COLOR_BLACK);
-
- tui_line_buff_resize();
-
- g_window_count = 0;
- g_window_cap = 1;
- g_window_handles = calloc(g_window_cap, sizeof(struct WindowHandle));
-}
-
-void exec(void) {
- while (!g_exit) {
- ui_print();
- ev_handle();
- clear();
- }
-}
-
-void quit(void) {
- tui_line_buff_free();
- endwin();
- log_info("Shutting down salis data client");
-}
-
-int main(void) {
- init();
- exec();
- quit();
-
- free(g_window_handles);
- g_window_count = 0;
- g_window_cap = 0;
-
- return 0;
-}
diff --git a/data/client.cpp b/data/client.cpp
new file mode 100644
index 0000000..74f2bc5
--- /dev/null
+++ b/data/client.cpp
@@ -0,0 +1,528 @@
+#include <GLFW/glfw3.h>
+#include <imgui.h>
+#include <imgui_impl_glfw.h>
+#include <imgui_impl_opengl3.h>
+#include <implot.h>
+#include <limits.h>
+#include <math.h>
+
+#include <initializer_list>
+
+#include "logger.c"
+
+#define COLOR_BG 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 WINDOW_STYLE (ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoSavedSettings)
+
+#define DEFAULT_ENTRIES 2000
+#define DEFAULT_NTH 1
+#define DEFAULT_X_AXIS 0
+#define DEFAULT_X_LOW 0
+#define DEFAULT_X_HIGH INT_MAX
+#define DEFAULT_HM_LEFT 0
+#define DEFAULT_HM_PIXEL_COUNT 0x400
+
+#define PLOT_MIN_COLS 1
+#define PLOT_MAX_COLS 8
+
+enum Status {
+ STATUS_STOPPED,
+ STATUS_RUNNING,
+ STATUS_STOPPING,
+};
+
+struct Plot {
+ Plot(const char *name, const char *section, std::initializer_list<const char *> cols)
+ : name(name), section(section), cols(cols.begin()) {}
+
+ const char *name;
+ const char *section;
+ const char *const *cols;
+};
+
+// Globals
+GLFWwindow *g_window;
+ImGuiIO *g_io;
+ImGuiStyle *g_imgui_style;
+ImPlotStyle *g_implot_style;
+int g_status;
+
+// Data col
+bool g_data_col_visible = true;
+float g_data_col_width;
+
+const char *g_x_axes[] = {
+ "rowid",
+ "steps",
+#define FOR_CORE(i) "cycl_" #i,
+ FOR_CORES
+#undef FOR_CORE
+};
+
+int g_entries = DEFAULT_ENTRIES;
+int g_nth = DEFAULT_NTH;
+int g_x_axis = DEFAULT_X_AXIS;
+int g_x_low = DEFAULT_X_LOW;
+int g_x_high = DEFAULT_X_HIGH;
+int g_hm_left = DEFAULT_HM_LEFT;
+int g_hm_pixel_count = DEFAULT_HM_PIXEL_COUNT;
+int g_hm_pixel_pow; // calculate on startup
+bool g_data_touched;
+
+// Plots
+Plot g_plots[] = {
+ Plot("cycl", "general", {
+#define FOR_CORE(i) "cycl_" #i,
+ FOR_CORES
+#undef FOR_CORE
+ nullptr,
+ }),
+ Plot("mall", "general", {
+#define FOR_CORE(i) "mall_" #i,
+ FOR_CORES
+#undef FOR_CORE
+ nullptr,
+ }),
+ Plot("pnum", "general", {
+#define FOR_CORE(i) "pnum_" #i,
+ FOR_CORES
+#undef FOR_CORE
+ nullptr,
+ }),
+ Plot("ppop", "general", {
+#define FOR_CORE(i) "pfst_" #i, "plst_" #i,
+ FOR_CORES
+#undef FOR_CORE
+ nullptr,
+ }),
+ Plot("ambs", "general", {
+#define FOR_CORE(i) "amb0_" #i, "amb1_" #i,
+ FOR_CORES
+#undef FOR_CORE
+ nullptr,
+ }),
+ Plot("eevs", "general", {
+#define FOR_CORE(i) "emb0_" #i, "emb1_" #i, "eliv_" #i, "edea_" #i,
+ FOR_CORES
+#undef FOR_CORE
+ nullptr,
+ }),
+};
+
+#define PLOT_COUNT (int)(sizeof(g_plots) / sizeof(g_plots[0]))
+
+// Layout
+int g_plot_cols = 2;
+int g_plot_col_selected;
+int g_plot_row_selected;
+Plot *g_plot_cells[PLOT_MAX_COLS][PLOT_COUNT];
+Plot *g_plot_selected = &g_plots[0];
+bool g_plot_maximized;
+
+// ----------------------------------------------------------------------------
+// Data functions
+// ----------------------------------------------------------------------------
+int data_calc_max_hm_pixel_pow(void) {
+ return (int)floor(log2((float)(MVEC_SIZE - g_hm_left) / (float)g_hm_pixel_count));
+}
+
+void data_clamp(int *field, int low, int high) {
+ assert(field);
+ if (*field < low) *field = low;
+ if (*field > high) *field = high;
+}
+
+void data_validate(void) {
+ data_clamp(&g_entries, 1, DEFAULT_ENTRIES);
+ data_clamp(&g_nth, DEFAULT_NTH, INT_MAX);
+ data_clamp(&g_x_low, DEFAULT_X_LOW, INT_MAX);
+ data_clamp(&g_x_high, g_x_low + 1, DEFAULT_X_HIGH);
+ #if !defined(MVEC_LOOP)
+ data_clamp(&g_hm_left, DEFAULT_HM_LEFT, MVEC_SIZE);
+ #endif
+ data_clamp(&g_hm_pixel_count, 1, DEFAULT_HM_PIXEL_COUNT);
+ data_clamp(&g_hm_pixel_pow, 0, data_calc_max_hm_pixel_pow());
+ g_data_touched = false;
+}
+
+void data_reset_values(void) {
+ g_entries = DEFAULT_ENTRIES;
+ g_nth = DEFAULT_NTH;
+ g_x_axis = DEFAULT_X_AXIS;
+ g_x_low = DEFAULT_X_LOW;
+ g_x_high = DEFAULT_X_HIGH;
+ g_hm_left = DEFAULT_HM_LEFT;
+ g_hm_pixel_count = DEFAULT_HM_PIXEL_COUNT;
+ g_hm_pixel_pow = data_calc_max_hm_pixel_pow();
+}
+
+void data_reset_plot_cells(void) {
+ for (size_t i = 0; i < PLOT_MAX_COLS; i++) {
+ for (size_t j = 0; j < PLOT_COUNT; j++) {
+ g_plot_cells[i][j] = nullptr;
+ }
+ }
+}
+
+void data_start_fetching(void) {
+ assert(g_status == STATUS_RUNNING);
+ log_info("Starting data fetching thread");
+ // start data fetching thread
+}
+
+void data_stop_fetching(void) {
+ assert(g_status == STATUS_STOPPING);
+ log_info("Stopping data fetching thread");
+ // join data fetching thread (set STATUS_STOPPED from within thread)
+ g_status = STATUS_STOPPED;
+}
+
+// ----------------------------------------------------------------------------
+// GUI functions
+// ----------------------------------------------------------------------------
+void gui_print_data_col(void) {
+ const ImGuiViewport *viewport = ImGui::GetMainViewport();
+ const ImVec2 next_win_pos = viewport->Pos;
+ const ImVec2 next_win_size = ImVec2(-1.f, viewport->Size.y);
+
+ ImGui::SetNextWindowPos(next_win_pos);
+ ImGui::SetNextWindowSize(next_win_size);
+ ImGui::Begin("data-col", nullptr, WINDOW_STYLE);
+ 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);
+
+ switch (g_status) {
+ case STATUS_STOPPED:
+ ImGui::LabelText("status", "%s", "stopped");
+ break;
+ case STATUS_RUNNING:
+ ImGui::LabelText("status", "%s", "running");
+ break;
+ case STATUS_STOPPING:
+ ImGui::LabelText("status", "%s", "stopping");
+ break;
+ }
+
+ ImGui::SeparatorText("Data fields");
+
+ switch (g_status) {
+ case STATUS_STOPPED:
+ if (ImGui::InputInt("entries", &g_entries, 0, 0, ImGuiInputTextFlags_CharsDecimal)) g_data_touched = true;
+ if (ImGui::InputInt("nth", &g_nth, 0, 0, ImGuiInputTextFlags_CharsDecimal)) g_data_touched = true;
+
+ 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)) {
+ g_x_axis = i;
+ g_data_touched = true;
+ }
+ }
+
+ ImGui::EndCombo();
+ }
+
+ if (ImGui::InputInt("x-low", &g_x_low, 0, 0, ImGuiInputTextFlags_CharsDecimal)) g_data_touched = true;
+ if (ImGui::InputInt("x-high", &g_x_high, 0, 0, ImGuiInputTextFlags_CharsDecimal)) g_data_touched = true;
+ if (ImGui::InputInt("hm-left", &g_hm_left, 0, 0, ImGuiInputTextFlags_CharsDecimal)) g_data_touched = true;
+ if (ImGui::InputInt("hm-pxl-count", &g_hm_pixel_count, 0, 0, ImGuiInputTextFlags_CharsDecimal)) g_data_touched = true;
+ if (ImGui::InputInt("hm-pxl-pow", &g_hm_pixel_pow, 0, 0, ImGuiInputTextFlags_CharsDecimal)) g_data_touched = true;
+
+ if (ImGui::Button("Run", ImVec2(-1.f, 0.f))) {
+ g_status = STATUS_RUNNING;
+ data_start_fetching();
+ }
+
+ if (ImGui::Button("Reset", ImVec2(-1.f, 0.f))) data_reset_values();
+
+ break;
+ case STATUS_RUNNING:
+ case STATUS_STOPPING:
+ ImGui::LabelText("entries", "%d", g_entries);
+ ImGui::LabelText("nth", "%d", g_nth);
+ ImGui::LabelText("x-axis", "%s", g_x_axes[g_x_axis]);
+ ImGui::LabelText("x-low", "%d", g_x_low);
+ ImGui::LabelText("x-high", "%d", g_x_high);
+ ImGui::LabelText("hm-left", "%d", g_hm_left);
+ ImGui::LabelText("hm-pxl-count", "%d", g_hm_pixel_count);
+ ImGui::LabelText("hm-pxl-pow", "%d", g_hm_pixel_pow);
+
+ if (g_status == STATUS_RUNNING) {
+ if (ImGui::Button("Stop", ImVec2(-1.f, 0.f))) {
+ g_status = STATUS_STOPPING;
+ data_stop_fetching();
+ }
+ }
+ }
+
+ ImGui::SeparatorText("Layout");
+ ImGui::SliderInt("cols", &g_plot_cols, PLOT_MIN_COLS, PLOT_MAX_COLS);
+
+ ImGui::End();
+}
+
+void gui_print_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 next_win_pos = g_data_col_visible ? ImVec2(g_data_col_width, viewport->Pos.y) : viewport->Pos;
+ const ImVec2 next_win_size = g_data_col_visible ? ImVec2(viewport->Size.x - g_data_col_width, -1.f) : ImVec2(viewport->Size.x, -1.f);
+
+ ImGui::SetNextWindowPos(next_win_pos);
+ ImGui::SetNextWindowSize(next_win_size);
+ ImGui::Begin("plots", nullptr, WINDOW_STYLE);
+
+ int col = 0;
+ int row = 0;
+
+ while (section_current) {
+ ImGui::SeparatorText(section_current);
+ ImGui::BeginTable("plots-table", g_plot_cols);
+
+ for (int 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();
+
+ 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];
+ }
+
+ if (ImPlot::BeginPlot(g_plots[i].name)) {
+ int test_x[] = {0,1,2,3};
+ int test_y1[] = {1,2,3,4};
+ int test_y2[] = {2,4,8,16};
+ ImPlot::PlotLine("test1", test_x, test_y1, 4);
+ ImPlot::PlotLine("test2", test_x, test_y2, 4);
+ ImPlot::EndPlot();
+ }
+
+ g_implot_style->Colors[ImPlotCol_FrameBg] = COLOR_BG;
+
+ g_plot_cells[col][row] = &g_plots[i];
+ 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;
+ }
+
+ ImGui::End();
+}
+
+void gui_print_plot_maximized(void) {
+ const ImGuiViewport *viewport = ImGui::GetMainViewport();
+ ImGui::SetNextWindowPos(viewport->Pos);
+ ImGui::SetNextWindowSize(viewport->Size);
+ ImGui::Begin("plot-fullscreen", nullptr, WINDOW_STYLE);
+
+ if (ImPlot::BeginPlot(g_plot_selected->name, viewport->Size)) {
+ int test_x[] = {0,1,2,3};
+ int test_y1[] = {1,2,3,4};
+ int test_y2[] = {2,4,8,16};
+ ImPlot::PlotLine("test1", test_x, test_y1, 4);
+ ImPlot::PlotLine("test2", test_x, test_y2, 4);
+ ImPlot::EndPlot();
+ }
+
+ ImGui::End();
+}
+
+void gui_print(void) {
+ if (g_plot_maximized) {
+ gui_print_plot_maximized();
+ } else {
+ if (g_data_col_visible) gui_print_data_col();
+ gui_print_plots();
+ }
+}
+
+// ----------------------------------------------------------------------------
+// Main functions
+// ----------------------------------------------------------------------------
+void glfw_error_callback(int error, const char* description) {
+ log_warn("GLFW error %d: %s", error, description);
+}
+
+void glfw_key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) {
+ (void)window;
+ (void)scancode;
+
+ if (action != GLFW_PRESS) return;
+
+ if (g_plot_maximized) {
+ switch (mods) {
+ case GLFW_MOD_CONTROL:
+ switch (key) {
+ case GLFW_KEY_C:
+ glfwSetWindowShouldClose(g_window, GLFW_TRUE);
+ break;
+ }
+
+ break;
+
+ case 0:
+ switch (key) {
+ case GLFW_KEY_F:
+ g_plot_maximized = !g_plot_maximized;
+ break;
+ }
+
+ break;
+ }
+
+ 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];
+ break;
+ case GLFW_KEY_DOWN:
+ g_plot_row_selected += (g_plot_row_selected < 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];
+ break;
+ case GLFW_KEY_F:
+ g_plot_maximized = !g_plot_maximized;
+ break;
+ }
+
+ break;
+ }
+}
+
+int main(int argc, char **argv) {
+ (void)argc;
+ (void)argv;
+
+ log_info("Starting SALIS data client");
+
+ log_info("Initializing GLFW");
+ glfwSetErrorCallback(glfw_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, glfw_key_callback);
+ glfwMakeContextCurrent(g_window);
+ glfwSwapInterval(1); // enable vsync
+
+ log_info("Initializing ImGui");
+ IMGUI_CHECKVERSION();
+ ImGui::CreateContext();
+ ImPlot::CreateContext();
+
+ g_io = &ImGui::GetIO();
+ g_io->Fonts->AddFontFromFileTTF(FONT_SOURCE);
+ g_io->IniFilename = nullptr;
+
+ g_imgui_style = &ImGui::GetStyle();
+ g_imgui_style->Colors[ImGuiCol_WindowBg] = COLOR_BG;
+ 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_BG;
+
+ ImGui_ImplGlfw_InitForOpenGL(g_window, true);
+ ImGui_ImplOpenGL3_Init(GLSL_VERSION);
+
+ g_hm_pixel_pow = data_calc_max_hm_pixel_pow();
+
+ // Main loop
+ while (!glfwWindowShouldClose(g_window)) {
+ glfwPollEvents();
+
+ ImGui_ImplOpenGL3_NewFrame();
+ ImGui_ImplGlfw_NewFrame();
+ ImGui::NewFrame();
+
+ gui_print();
+
+ if (g_data_touched) {
+ data_validate();
+ }
+
+ ImGui::Render();
+ int display_w, 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);
+ }
+
+ 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/plots.c b/data/plots.c
deleted file mode 100644
index 211346f..0000000
--- a/data/plots.c
+++ /dev/null
@@ -1,35 +0,0 @@
-enum PlotType {
- PLOT_LINES,
-};
-
-struct PlotDef {
- const char *name;
- const char *table;
- enum PlotType plot_type;
- const char **cols;
-};
-
-struct PlotDef g_general_plots_def[] = {
- { .name = "cycl", .table = "general", .plot_type = PLOT_LINES, .cols = (const char *[]){
-#define FOR_CORE(i) "cycl_" #i,
- FOR_CORES
-#undef FOR_CORE
- }},
- { .name = "mall", .table = "general", .plot_type = PLOT_LINES, .cols = (const char *[]){
-#define FOR_CORE(i) "mall_" #i,
- FOR_CORES
-#undef FOR_CORE
- }},
- { .name = "pnum", .table = "general", .plot_type = PLOT_LINES, .cols = (const char *[]){
-#define FOR_CORE(i) "pnum_" #i,
- FOR_CORES
-#undef FOR_CORE
- }},
- { .name = "ppop", .table = "general", .plot_type = PLOT_LINES, .cols = (const char *[]){
-#define FOR_CORE(i) "pfst_" #i, "plst_" #i,
- FOR_CORES
-#undef FOR_CORE
- }},
-};
-
-size_t g_general_plots_count = sizeof(g_general_plots_def) / sizeof(struct PlotDef);
diff --git a/data/server.c b/data/server.c
index f7f1121..c2fd276 100644
--- a/data/server.c
+++ b/data/server.c
@@ -25,7 +25,6 @@ void respond_name(int client_fd) {
json_object_to_fd(client_fd, sim_name, JSON_C_TO_STRING_PRETTY);
json_object_put(sim_name);
}
-break;
void respond_opts(int client_fd) {
log_info("Client requested simulation options");