aboutsummaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/client.cpp686
-rw-r--r--core/compress.c4
-rw-r--r--core/render.c91
-rw-r--r--core/salis.c4
-rw-r--r--core/server.c166
5 files changed, 694 insertions, 257 deletions
diff --git a/core/client.cpp b/core/client.cpp
index 1c63540..a5cf6d6 100644
--- a/core/client.cpp
+++ b/core/client.cpp
@@ -9,8 +9,8 @@
#include <threads.h>
#include <algorithm>
+#include <array>
#include <map>
-#include <string>
#include <vector>
#include "logger.c"
@@ -20,10 +20,18 @@
// ----------------------------------------------------------------------------
#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 PLOT_MAX_COLS 8
+#define PLOT_MIN_HEIGHT 100.f
+#define PLOT_MAX_HEIGHT 800.f
+#define PLOT_HEIGHT_INTERVAL 50.f
+#define PLOT_SCROLL_MARGIN 28.f
+#define HM_SCALE_POW_MIN -1.f
+#define HM_SCALE_POW_MAX 64.f
+#define HM_SCALE_POW_INTERVAL 1.f
+#define HM_COLORSCALE_WIDTH 80.f
#define IMGUI_WINDOW_FLAGS ( \
ImGuiWindowFlags_NoBackground | \
@@ -41,10 +49,10 @@
#define DEFVAL_X_LOW 0l
#define DEFVAL_X_HIGH INT64_MAX
#define DEFVAL_HM_LEFT 0l
-#define DEFVAL_HM_PIXEL_COUNT 0x400l
+#define DEFVAL_HM_PIXEL_COUNT 0x400l // must equal HM_PIXEL_COUNT in server.c
// ----------------------------------------------------------------------------
-// Declarations
+// State declaration
// ----------------------------------------------------------------------------
enum Status {
STATUS_STOPPED,
@@ -52,37 +60,115 @@ enum Status {
STATUS_STOPPING,
};
-template <class T> struct Trace : public std::vector<T> {
+// ----------------------------------------------------------------------------
+// Trace declarations
+// ----------------------------------------------------------------------------
+template <class T>
+class Trace {
+public:
Trace();
+ virtual ~Trace();
+ virtual size_t start_offset() const;
+ virtual void trim();
+#if !defined(NDEBUG)
+ virtual void validate() const;
+#endif
+
+ size_t size() const;
+ T &back();
+ T &operator[](size_t n);
T *start();
- void trim();
+ T max() const;
+ T operator[](size_t n) const;
+ void clear();
+ void push_back(T);
+
+protected:
+ void trim_spec(int mult = 1);
+
+ std::vector<T> m_data;
+ size_t m_max_index;
+};
+
+template <class T>
+class TraceNamed : public Trace<T> {
+public:
+ TraceNamed(const char *name, const char *name_fmt);
+
+ const char *m_name;
+ const char *m_name_fmt;
+};
+
+template <class T>
+class TraceHeatmap : public TraceNamed<T> {
+public:
+ TraceHeatmap(const char *name, const char *name_fmt);
+ size_t start_offset() const;
+ void trim();
#if !defined(NDEBUG)
- T &operator[](size_t n);
+ void validate() const;
#endif
};
-template <class T> struct TraceNamed : public Trace<T> {
- std::string m_name;
- std::string m_name_fmt;
- TraceNamed(std::string name, std::string name_fmt);
-};
+// ----------------------------------------------------------------------------
+// Plot declarations
+// ----------------------------------------------------------------------------
+typedef int (*AxisFormatter)(double value, char *buff, int size, void *data);
-struct Plot {
- std::string m_name;
- std::string m_section;
- std::vector<std::string> m_trace_keys;
- Plot(std::string name, std::string section, std::vector<std::string> trace_keys);
+class Plot {
+public:
+ Plot(const char *name, const char *section);
virtual ~Plot();
- virtual void render();
+ void render(ImVec2 frame_size);
+
+ const char *m_name;
+ const char *m_section;
+
+private:
+ static int hex_axis_formatter(double value, char *buff, int size, void *data);
+ virtual AxisFormatter x_axis_formatter();
+ virtual AxisFormatter y_axis_formatter();
+ virtual float frame_right_margin();
+ virtual int plot_flags();
+ virtual void render_internal() = 0;
+ virtual void render_post(ImVec2 frame_size);
};
-struct PlotStacked : public Plot {
+class PlotLines : public Plot {
+public:
+ PlotLines(const char *name, const char *section, std::vector<const char *> trace_keys);
+ std::vector<const char *> m_trace_keys;
+
+private:
+ void render_internal();
+};
+
+class PlotStacked : public Plot {
+public:
+ PlotStacked(const char *name, const char *section, std::vector<const char *> trace_keys);
+
std::vector<ImS64> m_totals;
std::vector<double> m_old_trace;
std::vector<double> m_new_trace;
- PlotStacked(std::string name, std::string section, std::vector<std::string> trace_keys);
- void render();
+ std::vector<const char *> m_trace_keys;
+
+private:
+ AxisFormatter y_axis_formatter();
+ static int percent_axis_formatter(double value, char *buff, int size, void *data);
+ void render_internal();
+};
+
+class PlotHeatmap : public Plot {
+public:
+ PlotHeatmap(const char *name, const char *section, const char *trace_key);
+ const char *m_trace_key;
+
+private:
+ float frame_right_margin();
+ int plot_flags();
+ void render_internal();
+ void render_post(ImVec2 frame_size);
};
// ----------------------------------------------------------------------------
@@ -90,7 +176,7 @@ struct PlotStacked : public Plot {
// ----------------------------------------------------------------------------
#include "arch_plots.cpp"
-std::vector<TraceNamed<ImS64>> g_core_traces = {
+std::array g_core_traces = std::to_array<TraceNamed<ImS64>>({
{"rowid", "rowid"},
{"step", "step"},
#define FOR_CORE(i) \
@@ -107,9 +193,18 @@ std::vector<TraceNamed<ImS64>> g_core_traces = {
{"edea_" #i, "edea_" #i},
FOR_CORES
#undef FOR_CORE
-};
+});
-std::vector<Plot> g_core_plots = {
+std::array g_core_traces_heatmaps = std::to_array<TraceHeatmap<ImS64>>({
+#define FOR_CORE(i) \
+ {"aev_" #i, "aev_" #i}, \
+ {"eev_" #i, "eev_" #i}, \
+ {"bev_" #i, "bev_" #i},
+ FOR_CORES
+#undef FOR_CORE
+});
+
+std::array g_core_plots = std::to_array<PlotLines>({
{"cycl", "general", {
#define FOR_CORE(i) "cycl_" #i,
FOR_CORES
@@ -140,7 +235,38 @@ std::vector<Plot> g_core_plots = {
FOR_CORES
#undef FOR_CORE
}},
-};
+});
+
+std::array g_core_plots_heatmaps = std::to_array<PlotHeatmap>({
+#define FOR_CORE(i) \
+ {"aev_" #i, "heatmaps", "aev_" #i},
+ FOR_CORES
+#undef FOR_CORE
+#define FOR_CORE(i) \
+ {"eev_" #i, "heatmaps", "eev_" #i},
+ FOR_CORES
+#undef FOR_CORE
+#define FOR_CORE(i) \
+ {"bev_" #i, "heatmaps", "bev_" #i},
+ FOR_CORES
+#undef FOR_CORE
+});
+
+// ----------------------------------------------------------------------------
+// Heatmap colormap
+// ----------------------------------------------------------------------------
+std::array g_hm_colormap_cols = std::to_array<ImVec4>({
+ {0.000f, 0.000f, 0.016f, 1.f},
+ {0.106f, 0.047f, 0.255f, 1.f},
+ {0.290f, 0.047f, 0.420f, 1.f},
+ {0.471f, 0.110f, 0.427f, 1.f},
+ {0.647f, 0.173f, 0.376f, 1.f},
+ {0.812f, 0.267f, 0.275f, 1.f},
+ {0.929f, 0.412f, 0.145f, 1.f},
+ {0.984f, 0.608f, 0.024f, 1.f},
+ {0.969f, 0.820f, 0.239f, 1.f},
+ {0.988f, 1.000f, 0.643f, 1.f},
+});
// ----------------------------------------------------------------------------
// Globals
@@ -151,13 +277,13 @@ ImGuiStyle *g_imgui_style;
ImPlotStyle *g_implot_style;
// Data
-std::vector<std::string> g_x_axes = {
+std::array g_x_axes = std::to_array<const char *>({
"rowid",
"step",
#define FOR_CORE(i) "cycl_" #i,
FOR_CORES
#undef FOR_CORE
-};
+});
int g_status;
int g_x_axis = DEFVAL_X_AXIS;
@@ -188,12 +314,22 @@ std::vector<float> g_plot_cells_top;
std::vector<float> g_plot_cells_bottom;
std::vector<bool> g_plots_covered;
Plot *g_plot_selected;
+Plot *g_plot_hovered;
int g_plot_cols = 2;
int g_plot_col_selected;
int g_plot_row_selected;
+float g_plot_height = 300.f;
+float g_hm_scale_pow = HM_SCALE_POW_MIN;
+ImPlotColormap g_hm_colormap;
// Plots
-std::map<std::string, TraceNamed<ImS64> *> g_trace_map;
+struct CompStr {
+ bool operator()(const char *a, const char *b) const {
+ return strcmp(a, b) < 0;
+ }
+};
+
+std::map<const char *, TraceNamed<ImS64> *, CompStr> g_trace_map;
std::vector<TraceNamed<ImS64> *> g_traces;
std::vector<Plot *> g_plots;
Trace<double> g_x_axis_normal;
@@ -201,57 +337,205 @@ Trace<double> g_x_axis_normal;
// ----------------------------------------------------------------------------
// Trace definitions
// ----------------------------------------------------------------------------
-template <class T> Trace<T>::Trace() : std::vector<T>() {}
+template <class T>
+Trace<T>::Trace() : m_data({}), m_max_index(0) {}
+
+template <class T>
+Trace<T>::~Trace() {}
+
+template <class T>
+size_t Trace<T>::start_offset() const {
+ return g_trace_offset;
+}
+
+template <class T>
+void Trace<T>::trim() {
+ trim_spec(1);
+}
-template <class T> T *Trace<T>::start() {
- return this->size() ? &this->operator[](g_trace_offset) : nullptr;
+#if !defined(NDEBUG)
+template <class T>
+void Trace<T>::validate() const {
+ assert(size() == g_traces[0]->size());
}
+#endif
-template <class T> void Trace<T>::trim() {
- assert((int64_t)this->size() >= g_entries * 2);
- this->erase(this->begin(), this->end() - g_entries);
+template <class T>
+size_t Trace<T>::size() const {
+ return m_data.size();
}
+template <class T>
+T &Trace<T>::back() {
+ return m_data.back();
+}
+
+template <class T>
+T &Trace<T>::operator[](size_t n) {
#if !defined(NDEBUG)
-template <class T> T &Trace<T>::operator[](size_t n) {
- return this->at(n);
+ return m_data.at(n);
+#else
+ return m_data[n];
+#endif
+}
+
+template <class T>
+T *Trace<T>::start() {
+ return size() ? &operator[](start_offset()) : nullptr;
+}
+
+template <class T>
+T Trace<T>::max() const {
+ return size() ? operator[](m_max_index) : 0;
}
+
+template <class T>
+T Trace<T>::operator[](size_t n) const {
+#if !defined(NDEBUG)
+ return m_data.at(n);
+#else
+ return m_data[n];
#endif
+}
+
+template <class T>
+void Trace<T>::clear() {
+ m_data.clear();
+ m_max_index = 0;
+}
+
+template <class T>
+void Trace<T>::push_back(T value) {
+ m_data.push_back(value);
+
+ if (value > operator[](m_max_index)) {
+ m_max_index = size() - 1;
+ }
+}
+
+template <class T>
+void Trace<T>::trim_spec(int mult) {
+ assert((int64_t)size() >= g_entries * mult * 2);
+ m_data.erase(m_data.begin(), m_data.end() - (g_entries * mult));
+
+ for (size_t i = 0; i < size(); i++) {
+ m_max_index = std::max(operator[](m_max_index), operator[](i));
+ }
+}
// ----------------------------------------------------------------------------
// TraceNamed definitions
// ----------------------------------------------------------------------------
-template <class T> TraceNamed<T>::TraceNamed(std::string name, std::string name_fmt) : m_name(name), m_name_fmt(name_fmt) {}
+template <class T>
+TraceNamed<T>::TraceNamed(const char *name, const char *name_fmt) : m_name(name), m_name_fmt(name_fmt) {}
+
+// ----------------------------------------------------------------------------
+// TraceHeatmap definitions
+// ----------------------------------------------------------------------------
+template <class T>
+TraceHeatmap<T>::TraceHeatmap(const char *name, const char *name_fmt) : TraceNamed<T>(name, name_fmt) {}
+
+template <class T>
+size_t TraceHeatmap<T>::start_offset() const {
+ return g_trace_offset * g_hm_pixel_count;
+}
+
+template <class T>
+void TraceHeatmap<T>::trim() {
+ this->trim_spec(g_hm_pixel_count);
+}
+
+#if !defined(NDEBUG)
+template <class T>
+void TraceHeatmap<T>::validate() const {
+ assert(this->size() == g_traces[0]->size() * g_hm_pixel_count);
+}
+#endif
// ----------------------------------------------------------------------------
// Plot definitions
// ----------------------------------------------------------------------------
-Plot::Plot(std::string name, std::string section, std::vector<std::string> trace_keys) : m_name(name), m_section(section), m_trace_keys(trace_keys) {}
+Plot::Plot(const char *name, const char *section) : m_name(name), m_section(section) {}
Plot::~Plot() {}
-void Plot::render() {
+void Plot::render(ImVec2 frame_size) {
+ if (ImPlot::BeginPlot(m_name, ImVec2(frame_size.x - frame_right_margin(), frame_size.y), plot_flags())) {
+ int axis_flags = ImPlotAxisFlags_Foreground | (g_status != STATUS_STOPPED ? ImPlotAxisFlags_AutoFit : 0);
+ ImPlot::SetupAxes(nullptr, nullptr, axis_flags, axis_flags);
+ ImPlot::SetupAxisFormat(ImAxis_X1, x_axis_formatter());
+ ImPlot::SetupAxisFormat(ImAxis_Y1, y_axis_formatter());
+ if (ImPlot::IsPlotHovered()) g_plot_hovered = this;
+ render_internal();
+ ImPlot::EndPlot();
+ }
+
+ render_post(frame_size);
+}
+
+int Plot::hex_axis_formatter(double value, char *buff, int size, void *data) {
+ (void)data;
+ snprintf(buff, size, "%s%#lx", value < 0. ? "-" : "", abs((int64_t)value));
+ return 0;
+}
+
+AxisFormatter Plot::x_axis_formatter() {
+ return Plot::hex_axis_formatter;
+}
+
+AxisFormatter Plot::y_axis_formatter() {
+ return Plot::hex_axis_formatter;
+}
+
+float Plot::frame_right_margin() {
+ return 0.f;
+}
+
+int Plot::plot_flags() {
+ return 0;
+}
+
+void Plot::render_post(ImVec2 frame_size) {
+ (void)frame_size;
+}
+
+// ----------------------------------------------------------------------------
+// PlotLines definitions
+// ----------------------------------------------------------------------------
+PlotLines::PlotLines(const char *name, const char *section, std::vector<const char *> trace_keys) : Plot(name, section), m_trace_keys(trace_keys) {}
+
+void PlotLines::render_internal() {
ImS64 *x = g_trace_map[g_x_axes[g_x_axis]]->start();
for (auto &trace : m_trace_keys) {
TraceNamed<ImS64> *trace_obj = g_trace_map[trace];
ImS64 *y = trace_obj->start();
- ImPlot::PlotLine(trace_obj->m_name_fmt.c_str(), x, y, g_trace_len);
+ ImPlot::PlotLine(trace_obj->m_name_fmt, x, y, g_trace_len);
}
}
// ----------------------------------------------------------------------------
// PlotStacked definitions
// ----------------------------------------------------------------------------
-PlotStacked::PlotStacked(std::string name, std::string section, std::vector<std::string> trace_keys) : Plot(name, section, trace_keys) {}
+PlotStacked::PlotStacked(const char *name, const char *section, std::vector<const char *> trace_keys) : Plot(name, section), m_trace_keys(trace_keys) {}
+
+AxisFormatter PlotStacked::y_axis_formatter() {
+ return PlotStacked::percent_axis_formatter;
+}
+
+int PlotStacked::percent_axis_formatter(double value, char *buff, int size, void *data) {
+ (void)data;
+ snprintf(buff, size, "%3.0f%%", value * 100.);
+ return 0;
+}
-void PlotStacked::render() {
+void PlotStacked::render_internal() {
m_totals.resize(g_trace_len);
m_old_trace.resize(g_trace_len);
m_new_trace.resize(g_trace_len);
for (size_t i = 0; i < m_trace_keys.size(); i++) {
- ImPlot::PlotDummy(g_trace_map[m_trace_keys[i]]->m_name_fmt.c_str());
+ ImPlot::PlotDummy(g_trace_map[m_trace_keys[i]]->m_name_fmt);
}
for (int i = 0; i < (int)m_trace_keys.size(); i++) {
@@ -264,15 +548,17 @@ void PlotStacked::render() {
for (int i = 0; i < (int)m_trace_keys.size(); i++) {
if (GImPlot->CurrentPlot->Items.GetLegendItem(i)->Show) {
- ImPlotSpec spec = ImPlotSpec(ImPlotProp_FillAlpha, GImPlot->CurrentPlot->Items.GetLegendItem(i)->LegendHovered ? 0.9f : 0.7f);
+ ImPlotSpec spec = ImPlotSpec(ImPlotProp_FillAlpha, GImPlot->CurrentPlot->Items.GetLegendItem(i)->LegendHovered ? 1.f : 0.9f);
+ TraceNamed<ImS64> *trace = g_trace_map[m_trace_keys[i]];
+ const char *trace_name = trace->m_name_fmt;
for (int j = 0; j < g_trace_len; j++) {
- m_new_trace[j] = m_totals[j] ? (m_old_trace[j] + (double)g_trace_map[m_trace_keys[i]]->start()[j] / (double)m_totals[j]) : 0.;
+ m_new_trace[j] = m_totals[j] ? (m_old_trace[j] + (double)trace->start()[j] / (double)m_totals[j]) : 0.;
}
- ImPlot::PlotShaded(g_trace_map[m_trace_keys[i]]->m_name_fmt.c_str(), g_x_axis_normal.start(), m_old_trace.data(), m_new_trace.data(), g_trace_len, spec);
- ImPlot::PlotLine(g_trace_map[m_trace_keys[i]]->m_name_fmt.c_str(), g_x_axis_normal.start(), m_old_trace.data(), g_trace_len);
- ImPlot::PlotLine(g_trace_map[m_trace_keys[i]]->m_name_fmt.c_str(), g_x_axis_normal.start(), m_new_trace.data(), g_trace_len);
+ ImPlot::PlotShaded(trace_name, g_x_axis_normal.start(), m_old_trace.data(), m_new_trace.data(), g_trace_len, spec);
+ ImPlot::PlotLine(trace_name, g_x_axis_normal.start(), m_old_trace.data(), g_trace_len);
+ ImPlot::PlotLine(trace_name, g_x_axis_normal.start(), m_new_trace.data(), g_trace_len);
std::swap(m_old_trace, m_new_trace);
}
}
@@ -283,6 +569,35 @@ void PlotStacked::render() {
}
// ----------------------------------------------------------------------------
+// PlotHeatmap definitions
+// ----------------------------------------------------------------------------
+PlotHeatmap::PlotHeatmap(const char *name, const char *section, const char *trace_key) : Plot(name, section), m_trace_key(trace_key) {}
+
+float PlotHeatmap::frame_right_margin() {
+ return HM_COLORSCALE_WIDTH;
+}
+
+int PlotHeatmap::plot_flags() {
+ return ImPlotFlags_NoLegend;
+}
+
+void PlotHeatmap::render_internal() {
+ TraceNamed<ImS64> *trace = g_trace_map[m_trace_key];
+ ImPlot::PushColormap(g_hm_colormap);
+ double scale_max = g_hm_scale_pow == HM_SCALE_POW_MIN ? 0. : pow(2., (double)g_hm_scale_pow);
+ ImPlot::PlotHeatmap(trace->m_name_fmt, trace->start(), g_trace_len, g_hm_pixel_count, 0., scale_max, nullptr, ImPlotPoint(0, g_x_current), ImPlotPoint(MVEC_SIZE, 0));
+ ImPlot::PopColormap();
+}
+
+void PlotHeatmap::render_post(ImVec2 frame_size) {
+ ImGui::SameLine();
+ ImPlot::PushColormap(g_hm_colormap);
+ double scale_max = g_hm_scale_pow == HM_SCALE_POW_MIN ? (double)g_trace_map[m_trace_key]->max() : pow(2., (double)g_hm_scale_pow);
+ ImPlot::ColormapScale("##hm-scale", 0., scale_max, ImVec2(HM_COLORSCALE_WIDTH, frame_size.y), "%.1e");
+ ImPlot::PopColormap();
+}
+
+// ----------------------------------------------------------------------------
// Data functions
// ----------------------------------------------------------------------------
int64_t data_max_hm_pixel_pow(void) {
@@ -327,27 +642,21 @@ void data_reset_plot_cells(void) {
std::fill(g_plot_cells_bottom.begin(), g_plot_cells_bottom.end(), 0.f);
}
-#if !defined(NDEBUG)
-void data_validate_traces(void) {
- for (auto &trace : g_traces) assert(trace->size() == g_traces[0]->size());
-}
-#endif
-
void data_fetch(void) {
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].c_str()));
+ 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));
- std::string request_str = json_object_to_json_string(request);
+ const char *request_str = json_object_to_json_string(request);
- log_info("Sending request to server: %s", request_str.c_str());
+ log_info("Sending request to server: %s", request_str);
int socket_fd = socket(AF_INET, SOCK_STREAM, 0);
sockaddr_in socket_addr;
memset(&socket_addr, 0, sizeof(sockaddr_in));
@@ -359,23 +668,25 @@ void data_fetch(void) {
shutdown(socket_fd, SHUT_WR);
json_object *response = json_object_from_fd(socket_fd);
- std::string response_str = json_object_to_json_string(response);
- log_info("Server responded with: %s", response_str.c_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++) {
+ size_t new_rows = json_object_array_length(value);
+
+ if (!strcmp(key, g_x_axes[g_x_axis])) {
+ log_info("Received %lu rows of data from server", new_rows);
+
+ for (size_t i = 0; i < new_rows; i++) {
ImS64 point = json_object_get_int64(json_object_array_get_idx(value, i));
- g_trace_map[key]->push_back(point);
+ g_x_axis_normal.push_back((double)point);
}
}
- if (std::string(key) == g_x_axes[g_x_axis]) {
- for (size_t i = 0; i < json_object_array_length(value); i++) {
+ if (g_trace_map.contains(key)) {
+ for (size_t i = 0; i < new_rows; i++) {
ImS64 point = json_object_get_int64(json_object_array_get_idx(value, i));
- g_x_axis_normal.push_back((double)point);
+ g_trace_map[key]->push_back(point);
}
}
}
@@ -385,7 +696,7 @@ void data_fetch(void) {
json_object_put(response);
#if !defined(NDEBUG)
- data_validate_traces();
+ for (auto &trace : g_traces) trace->validate();
#endif
if ((int64_t)g_traces[0]->size() >= g_entries * 2) {
@@ -394,7 +705,7 @@ void data_fetch(void) {
}
#if !defined(NDEBUG)
- data_validate_traces();
+ for (auto &trace : g_traces) trace->validate();
#endif
int64_t current_size = g_traces[0]->size();
@@ -439,10 +750,10 @@ void data_stop_fetching(void) {
// ----------------------------------------------------------------------------
// GUI functions
// ----------------------------------------------------------------------------
-void gui_render_data_input(std::string label, int64_t *target) {
+void gui_render_data_input(const char *label, int64_t *target) {
assert(target);
- if (ImGui::InputScalar(label.c_str(), ImGuiDataType_U64, target, nullptr, nullptr, "%#lx")) {
+ if (ImGui::InputScalar(label, ImGuiDataType_U64, target, nullptr, nullptr, "%#lx")) {
data_on_field_change();
}
}
@@ -478,9 +789,9 @@ void gui_render_data_col(void) {
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].c_str())) {
+ 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].c_str(), g_x_axis == i)) {
+ if (ImGui::Selectable(g_x_axes[i], g_x_axis == i)) {
data_reset_fields();
g_x_axis = i;
}
@@ -499,7 +810,7 @@ void gui_render_data_col(void) {
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].c_str());
+ 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);
@@ -531,40 +842,44 @@ void gui_render_data_col(void) {
}
ImGui::SeparatorText("Layout");
- ImGui::SliderInt("cols", &g_plot_cols, PLOT_MIN_COLS, PLOT_MAX_COLS);
+ ImGui::DragInt("cols", &g_plot_cols, 1, PLOT_MIN_COLS, PLOT_MAX_COLS);
+ ImGui::DragFloat("plot-height", &g_plot_height, PLOT_HEIGHT_INTERVAL, PLOT_MIN_HEIGHT, PLOT_MAX_HEIGHT, "%.0f");
+ ImGui::DragFloat("hm-pow", &g_hm_scale_pow, HM_SCALE_POW_INTERVAL, HM_SCALE_POW_MIN, HM_SCALE_POW_MAX, "%.0f");
+
ImGui::End();
}
-int gui_plot_cell_index(int col, int row) {
- int index = col * PLOT_MAX_COLS + row;
+int gui_plot_cell_index(int row, int col) {
+ int index = row * PLOT_MAX_COLS + col;
assert(index < (int)g_plot_cells.size());
assert(index < (int)g_plot_cells_top.size());
assert(index < (int)g_plot_cells_bottom.size());
return index;
}
-void gui_render_plot(Plot *plot, const ImVec2 &frame_size=ImVec2(-1.f, 0.f)) {
- assert(plot);
+int gui_plot_cell_row_up() {
+ for (int row = g_plot_row_selected - 1; row >= 0; row--) {
+ if (g_plot_cells[gui_plot_cell_index(row, g_plot_col_selected)]) {
+ return row;
+ }
+ }
- int plot_flags = ImPlotFlags_NoMenus;
- int axis_flags = ImPlotAxisFlags_NoMenus;
+ return g_plot_row_selected;
+}
- if (g_status != STATUS_STOPPED) {
- ImPlot::SetNextAxesToFit();
- plot_flags |= ImPlotFlags_NoInputs | ImPlotFlags_NoMouseText;
- axis_flags |= ImPlotAxisFlags_NoHighlight;
+int gui_plot_cell_row_down() {
+ for (int row = g_plot_row_selected + 1; row < (int)g_plots.size(); row++) {
+ if (g_plot_cells[gui_plot_cell_index(row, g_plot_col_selected)]) {
+ return row;
+ }
}
- if (ImPlot::BeginPlot(plot->m_name.c_str(), frame_size, plot_flags)) {
- ImPlot::SetupAxes(nullptr, nullptr, axis_flags, axis_flags);
- plot->render();
- ImPlot::EndPlot();
- }
+ return g_plot_row_selected;
}
void gui_render_plots(void) {
- std::string section_current = g_plots[0]->m_section;
- std::string section_next;
+ const char *section_current = g_plots[0]->m_section;
+ const char *section_next = nullptr;
g_plots_covered.clear();
g_plots_covered.resize(g_plots.size(), false);
@@ -583,25 +898,27 @@ void gui_render_plots(void) {
ImGui::SetNextWindowSize(win_size);
ImGui::Begin("plots", nullptr, IMGUI_WINDOW_FLAGS);
g_plot_scroll_current = ImGui::GetScrollY();
+ g_plot_hovered = nullptr;
- int col = 0;
int row = 0;
+ int col = 0;
mtx_lock(&g_fetching_mutex);
- while (section_current.length()) {
- ImGui::SeparatorText(section_current.c_str());
+ while (section_current) {
+ ImGui::SeparatorText(section_current);
ImGui::BeginTable("plots-table", g_plot_cols);
for (size_t i = 0; i < g_plots.size(); i++) {
- if (g_plots[i]->m_section != section_current) {
- section_next = (!section_next.length() && !g_plots_covered[i]) ? g_plots[i]->m_section : section_next;
+ if (strcmp(g_plots[i]->m_section, section_current)) {
+ section_next = (!section_next && !g_plots_covered[i]) ? g_plots[i]->m_section : section_next;
continue;
}
ImGui::TableNextColumn();
- g_plot_cells[gui_plot_cell_index(col, row)] = g_plots[i];
- g_plot_cells_top[gui_plot_cell_index(col, row)] = ImGui::GetCursorPosY();
+ ImVec2 frame_size = ImVec2(ImGui::GetContentRegionAvail().x, g_plot_height);
+ g_plot_cells[gui_plot_cell_index(row, col)] = g_plots[i];
+ g_plot_cells_top[gui_plot_cell_index(row, col)] = ImGui::GetCursorPosY();
if (g_plots[i] == g_plot_selected) {
g_plot_col_selected = col;
@@ -609,20 +926,21 @@ void gui_render_plots(void) {
g_implot_style->Colors[ImPlotCol_FrameBg] = g_imgui_style->Colors[ImGuiCol_FrameBg];
}
- gui_render_plot(g_plots[i]);
+ g_plots[i]->render(frame_size);
if (g_plots[i] == g_plot_selected) {
g_implot_style->Colors[ImPlotCol_FrameBg] = COLOR_BLACK;
}
- g_plot_cells_bottom[gui_plot_cell_index(col, row)] = ImGui::GetCursorPosY();
+ g_plot_cells_bottom[gui_plot_cell_index(row, col)] = ImGui::GetCursorPosY();
col = (col + 1) % g_plot_cols;
row += col ? 0 : 1;
+
g_plots_covered[i] = true;
}
section_current = section_next;
- section_next = std::string();
+ section_next = nullptr;
ImGui::EndTable();
row += col ? 1 : 0;
col = 0;
@@ -639,25 +957,47 @@ void gui_render_plot_maximized(void) {
ImGui::SetNextWindowSize(viewport->Size);
ImGui::Begin("plot-fullscreen", nullptr, IMGUI_WINDOW_FLAGS);
- gui_render_plot(g_plot_selected, viewport->Size);
+ ImVec2 frame_size = {
+ viewport->Size.x - g_imgui_style->WindowPadding.x * 2,
+ viewport->Size.y - g_imgui_style->WindowPadding.y * 2,
+ };
+
+ g_plot_selected->render(frame_size);
ImGui::End();
}
-void gui_plot_queue_scroll(int col_selected, int row_selected) {
+void gui_plot_queue_scroll_to_position(bool increased_plot_height) {
+ int row = 0;
+ float selected_plot_top = 0.f;
+
+ for (row = 0; row < (int)g_plots.size(); row++) {
+ for (int col = 0; col < PLOT_MAX_COLS; col++) {
+ if (g_plot_selected == g_plot_cells[gui_plot_cell_index(row, col)]) {
+ selected_plot_top = g_plot_cells_top[gui_plot_cell_index(row, col)];
+ goto loop_exit;
+ }
+ }
+ }
+
+ loop_exit:
+ g_plot_scroll_to = selected_plot_top + (PLOT_HEIGHT_INTERVAL * (float)row * (increased_plot_height ? 1.f : -1.f)) - PLOT_SCROLL_MARGIN;
+ g_plot_scroll = true;
+}
+
+void gui_plot_queue_scroll_to_selected() {
const ImGuiViewport *viewport = ImGui::GetMainViewport();
- float plot_top = g_plot_cells_top[gui_plot_cell_index(col_selected, row_selected)];
- float plot_bottom = g_plot_cells_bottom[gui_plot_cell_index(col_selected, row_selected)];
- float win_top = g_plot_scroll_current;
- float win_bottom = win_top + viewport->Size.y;
+ float plot_top = g_plot_cells_top[gui_plot_cell_index(g_plot_row_selected, g_plot_col_selected)];
+ float plot_bottom = g_plot_cells_bottom[gui_plot_cell_index(g_plot_row_selected, g_plot_col_selected)];
+ float win_bottom = g_plot_scroll_current + viewport->Size.y;
if (plot_bottom > win_bottom) {
- g_plot_scroll_to = win_top + (plot_bottom - win_bottom);
+ g_plot_scroll_to = g_plot_scroll_current + (plot_bottom - win_bottom);
g_plot_scroll = true;
}
- if (plot_top < win_top) {
- g_plot_scroll_to = plot_top - PLOT_SCROLL_OFFSET;
+ if (plot_top < g_plot_scroll_current) {
+ g_plot_scroll_to = plot_top - PLOT_SCROLL_MARGIN;
g_plot_scroll = true;
}
}
@@ -691,23 +1031,62 @@ void app_error_callback(int error, const char* description) {
log_warn("GLFW error %d: %s", error, description);
}
+void app_toggle_state() {
+ switch (g_status) {
+ case STATUS_STOPPED:
+ data_start_fetching();
+ break;
+ case STATUS_RUNNING:
+ data_stop_fetching();
+ break;
+ }
+}
+
+void app_key_callback_plot_maximized(int key, int mods) {
+ switch (mods) {
+ case GLFW_MOD_CONTROL:
+ switch (key) {
+ case GLFW_KEY_C:
+ glfwSetWindowShouldClose(g_window, GLFW_TRUE);
+ break;
+ case GLFW_KEY_COMMA:
+ g_hm_scale_pow = std::max(g_hm_scale_pow - HM_SCALE_POW_INTERVAL, HM_SCALE_POW_MIN);
+ break;
+ case GLFW_KEY_PERIOD:
+ g_hm_scale_pow = std::min(g_hm_scale_pow + HM_SCALE_POW_INTERVAL, HM_SCALE_POW_MAX);
+ break;
+ }
+
+ break;
+
+ case 0:
+ switch (key) {
+ case GLFW_KEY_F:
+ g_plot_maximized = false;
+ break;
+ case GLFW_KEY_SPACE:
+ app_toggle_state();
+ break;
+ }
+
+ break;
+ }
+}
+
void app_key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) {
(void)window;
(void)scancode;
- if (action != GLFW_PRESS || ImGui::IsAnyItemActive()) {
+ if (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;
- }
+ if (action != GLFW_PRESS && action != GLFW_REPEAT) {
+ return;
+ }
+ if (g_plot_maximized) {
+ app_key_callback_plot_maximized(key, mods);
return;
}
@@ -721,13 +1100,27 @@ void app_key_callback(GLFWwindow* window, int key, int scancode, int action, int
g_data_col_visible = !g_data_col_visible;
break;
case GLFW_KEY_LEFT:
- g_plot_cols -= g_plot_cols > 1 ? 1 : 0;
+ g_plot_cols = std::max(g_plot_cols - 1, PLOT_MIN_COLS);
data_reset_plot_cells();
break;
case GLFW_KEY_RIGHT:
- g_plot_cols += g_plot_cols < PLOT_MAX_COLS ? 1 : 0;
+ g_plot_cols = std::min(g_plot_cols + 1, PLOT_MAX_COLS);
data_reset_plot_cells();
break;
+ case GLFW_KEY_UP:
+ g_plot_height = std::min(g_plot_height + PLOT_HEIGHT_INTERVAL, PLOT_MAX_HEIGHT);
+ gui_plot_queue_scroll_to_position(true);
+ break;
+ case GLFW_KEY_DOWN:
+ g_plot_height = std::max(g_plot_height - PLOT_HEIGHT_INTERVAL, PLOT_MIN_HEIGHT);
+ gui_plot_queue_scroll_to_position(false);
+ break;
+ case GLFW_KEY_COMMA:
+ g_hm_scale_pow = std::max(g_hm_scale_pow - HM_SCALE_POW_INTERVAL, HM_SCALE_POW_MIN);
+ break;
+ case GLFW_KEY_PERIOD:
+ g_hm_scale_pow = std::min(g_hm_scale_pow + HM_SCALE_POW_INTERVAL, HM_SCALE_POW_MAX);
+ break;
}
break;
@@ -735,36 +1128,28 @@ void app_key_callback(GLFWwindow* window, int key, int scancode, int action, int
case 0:
switch (key) {
case GLFW_KEY_LEFT:
- g_plot_col_selected -= g_plot_col_selected ? 1 : 0;
- g_plot_selected = g_plot_cells[gui_plot_cell_index(g_plot_col_selected, g_plot_row_selected)];
+ g_plot_col_selected = std::max(g_plot_col_selected - 1, 0);
+ g_plot_selected = g_plot_cells[gui_plot_cell_index(g_plot_row_selected, g_plot_col_selected)];
break;
case GLFW_KEY_RIGHT:
- g_plot_col_selected += (g_plot_col_selected < PLOT_MAX_COLS - 1 && g_plot_cells[gui_plot_cell_index(g_plot_col_selected + 1, g_plot_row_selected)]) ? 1 : 0;
- g_plot_selected = g_plot_cells[gui_plot_cell_index(g_plot_col_selected, g_plot_row_selected)];
+ g_plot_col_selected += (g_plot_col_selected < PLOT_MAX_COLS - 1 && g_plot_cells[gui_plot_cell_index(g_plot_row_selected, g_plot_col_selected + 1)]) ? 1 : 0;
+ g_plot_selected = g_plot_cells[gui_plot_cell_index(g_plot_row_selected, g_plot_col_selected)];
break;
case GLFW_KEY_UP:
- g_plot_row_selected -= (g_plot_row_selected && g_plot_cells[gui_plot_cell_index(g_plot_col_selected, g_plot_row_selected - 1)]) ? 1 : 0;
- g_plot_selected = g_plot_cells[gui_plot_cell_index(g_plot_col_selected, g_plot_row_selected)];
- gui_plot_queue_scroll(g_plot_col_selected, g_plot_row_selected);
+ g_plot_row_selected = gui_plot_cell_row_up();
+ g_plot_selected = g_plot_cells[gui_plot_cell_index(g_plot_row_selected, g_plot_col_selected)];
+ gui_plot_queue_scroll_to_selected();
break;
case GLFW_KEY_DOWN:
- g_plot_row_selected += (g_plot_row_selected < (int)g_plots.size() - 1 && g_plot_cells[gui_plot_cell_index(g_plot_col_selected, g_plot_row_selected + 1)]) ? 1 : 0;
- g_plot_selected = g_plot_cells[gui_plot_cell_index(g_plot_col_selected, g_plot_row_selected)];
- gui_plot_queue_scroll(g_plot_col_selected, g_plot_row_selected);
+ g_plot_row_selected = gui_plot_cell_row_down();
+ g_plot_selected = g_plot_cells[gui_plot_cell_index(g_plot_row_selected, g_plot_col_selected)];
+ gui_plot_queue_scroll_to_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;
- }
-
+ app_toggle_state();
break;
}
@@ -772,6 +1157,19 @@ void app_key_callback(GLFWwindow* window, int key, int scancode, int action, int
}
}
+void app_mouse_button_callback(GLFWwindow* window, int button, int action, int mods) {
+ (void)window;
+ (void)mods;
+
+ if (button != GLFW_MOUSE_BUTTON_LEFT) return;
+
+ switch (action) {
+ case GLFW_PRESS:
+ g_plot_selected = g_plot_hovered ? g_plot_hovered : g_plot_selected;
+ break;
+ }
+}
+
void init() {
signal(SIGINT, app_sig_handler);
signal(SIGTERM, app_sig_handler);
@@ -787,6 +1185,7 @@ void init() {
g_window = glfwCreateWindow((int)(800 * scale), (int)(600 * scale), "SALIS data client", nullptr, nullptr);
assert(g_window);
glfwSetKeyCallback(g_window, app_key_callback);
+ glfwSetMouseButtonCallback(g_window, app_mouse_button_callback);
glfwMakeContextCurrent(g_window);
glfwSwapInterval(1); // enable vsync
@@ -796,7 +1195,7 @@ void init() {
ImPlot::CreateContext();
g_imgui_io = &ImGui::GetIO();
- g_imgui_io->Fonts->AddFontDefaultVector();
+ g_imgui_io->Fonts->AddFontFromFileTTF(FONT_SOURCE, FONT_SIZE);
g_imgui_io->IniFilename = nullptr;
g_imgui_style = &ImGui::GetStyle();
@@ -808,15 +1207,20 @@ void init() {
g_implot_style = &ImPlot::GetStyle();
g_implot_style->Colors[ImPlotCol_FrameBg] = COLOR_BLACK;
+ g_hm_colormap = ImPlot::AddColormap("Inferno", g_hm_colormap_cols.data(), g_hm_colormap_cols.size(), false);
ImGui_ImplGlfw_InitForOpenGL(g_window, true);
ImGui_ImplOpenGL3_Init(GLSL_VERSION);
for (auto &trace : g_core_traces) g_traces.push_back(&trace);
for (auto &trace : g_arch_traces) g_traces.push_back(&trace);
+ for (auto &trace : g_core_traces_heatmaps) g_traces.push_back(&trace);
+ for (auto &trace : g_arch_traces_heatmaps) g_traces.push_back(&trace);
for (auto &plot : g_core_plots) g_plots.push_back(&plot);
for (auto &plot : g_arch_plots) g_plots.push_back(&plot);
for (auto &plot : g_arch_plots_stacked) g_plots.push_back(&plot);
+ for (auto &plot : g_core_plots_heatmaps) g_plots.push_back(&plot);
+ for (auto &plot : g_arch_plots_heatmaps) g_plots.push_back(&plot);
for (auto &i : g_traces) g_trace_map[i->m_name] = i;
g_plot_cells = std::vector<Plot *>(g_plots.size() * PLOT_MAX_COLS);
diff --git a/core/compress.c b/core/compress.c
index b45a583..8790011 100644
--- a/core/compress.c
+++ b/core/compress.c
@@ -5,7 +5,9 @@ struct DeflateParams {
size_t size;
Bytef *in;
Bytef *out;
+#if defined(THREAD_GAP)
uint8_t tgap[THREAD_GAP];
+#endif
};
struct InflateParams {
@@ -14,7 +16,9 @@ struct InflateParams {
size_t size;
Bytef *in;
Bytef *out;
+#if defined(THREAD_GAP)
uint8_t tgap[THREAD_GAP];
+#endif
};
int comp_deflate(struct DeflateParams *params) {
diff --git a/core/render.c b/core/render.c
deleted file mode 100644
index 08ff6dd..0000000
--- a/core/render.c
+++ /dev/null
@@ -1,91 +0,0 @@
-#include <sqlite3ext.h>
-SQLITE_EXTENSION_INIT1
-
-#include <assert.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <zlib.h>
-
-#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(&params);
- comp_inflate_end(&params);
-
- // 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/salis.c b/core/salis.c
index a5b517a..3740f3c 100644
--- a/core/salis.c
+++ b/core/salis.c
@@ -750,8 +750,8 @@ void salis_push_data_line(void) {
uint64_t *in = NULL;
switch (j) {
-#define EVENT_ARRAY(core, idx, ev) \
- case idx: in = g_cores[i].ev##a; break;
+#define EVENT_ARRAY(core, index, ev) \
+ case index: in = g_cores[i].ev##a; break;
EVENT_ARRAYS(core)
#undef EVENT_ARRAY
default: assert(false);
diff --git a/core/server.c b/core/server.c
index d54d853..292c3d9 100644
--- a/core/server.c
+++ b/core/server.c
@@ -1,21 +1,104 @@
#include <arpa/inet.h>
+#include <assert.h>
#include <json-c/json.h>
#include <signal.h>
#include <sqlite3.h>
#include <string.h>
#include <threads.h>
+#include <zlib.h>
+#include "compress.c"
#include "logger.c"
#include "sql.c"
+// ----------------------------------------------------------------------------
+// Defines
+// ----------------------------------------------------------------------------
#define BACKLOG 10
+#define EVA_SIZE (sizeof(uint64_t) * MVEC_SIZE)
+#define MAX_HM_PIXEL_COUNT 0x400 // must equal DEFVAL_HM_PIXEL_COUNT in client.cpp
+// ----------------------------------------------------------------------------
+// Declarations
+// ----------------------------------------------------------------------------
struct Socket {
int fd;
struct sockaddr_in addr;
};
+struct CallbackContext {
+ struct json_object *response;
+ int64_t response_rows;
+ int64_t hm_left;
+ int64_t hm_pixel_count;
+ int64_t hm_pixel_pow;
+};
+
+struct RenderContext {
+ const struct CallbackContext *callback_context;
+ const void *blob;
+ size_t blob_size;
+ uint64_t eva[EVA_SIZE];
+ int64_t out[MAX_HM_PIXEL_COUNT];
+};
+
+// ----------------------------------------------------------------------------
+// Globals
+// ----------------------------------------------------------------------------
struct json_object *g_response_header;
+size_t g_blob_count;
+
+// ----------------------------------------------------------------------------
+// Event array render function
+// ----------------------------------------------------------------------------
+int eva_render(void *data) {
+ assert(data);
+
+ struct RenderContext *render_context = (struct RenderContext *)data;
+ int64_t hm_left = render_context->callback_context->hm_left;
+ int64_t hm_pixel_count = render_context->callback_context->hm_pixel_count;
+ int64_t hm_pixel_pow = render_context->callback_context->hm_pixel_pow;
+ int64_t hm_pixel_res = 1 << hm_pixel_pow;
+ const void *blob = render_context->blob;
+ size_t blob_size = render_context->blob_size;
+
+#if defined(MVEC_LOOP)
+ hm_left %= MVEC_SIZE;
+#endif
+
+#if !defined(MVEC_LOOP)
+#if !defined(NDEBUG)
+ int64_t hm_right = hm_left + hm_pixel_res * hm_pixel_count;
+#endif
+ assert(hm_left < (int64_t)MVEC_SIZE);
+ assert(hm_right <= (int64_t)MVEC_SIZE);
+#endif
+
+ // Inflate blob
+ struct InflateParams params = {
+ .avail_in = blob_size,
+ .size = EVA_SIZE,
+ .in = (Bytef *)blob,
+ .out = (Bytef *)render_context->eva,
+ };
+
+ comp_inflate(&params);
+ comp_inflate_end(&params);
+
+ for (int64_t i = 0; i < hm_pixel_count; i++) {
+ render_context->out[i] = 0l;
+
+ for (int64_t j = 0; j < hm_pixel_res; j++) {
+ int64_t coord = hm_left + (i * hm_pixel_res) + j;
+#if defined(MVEC_LOOP)
+ coord %= MVEC_SIZE;
+#endif
+ render_context->out[i] += render_context->eva[coord];
+ }
+ }
+
+ return 0;
+}
// ----------------------------------------------------------------------------
// SQL callbacks
@@ -24,13 +107,20 @@ void sql_callback_add_column_name(sqlite3_stmt *sql_stmt, void *data) {
assert(sql_stmt);
assert(data);
assert(sqlite3_column_type(sql_stmt, 0) == SQLITE_TEXT);
+ assert(sqlite3_column_type(sql_stmt, 1) == SQLITE_TEXT);
assert(!strcmp(sqlite3_column_name(sql_stmt, 0), "name"));
+ assert(!strcmp(sqlite3_column_name(sql_stmt, 1), "type"));
const char *col_name = (const char *)sqlite3_column_text(sql_stmt, 0);
- struct json_object *response = (struct json_object *)data;
+ const char *col_type = (const char *)sqlite3_column_text(sql_stmt, 1);
+ struct json_object *response_header = (struct json_object *)data;
- if (!json_object_object_get_ex(response, col_name, NULL)) {
- json_object_object_add(response, col_name, json_object_new_array());
+ if (!json_object_object_get_ex(response_header, col_name, NULL)) {
+ json_object_object_add(response_header, col_name, json_object_new_array());
+ }
+
+ if (!strcmp(col_type, "BLOB")) {
+ g_blob_count++;
}
}
@@ -38,20 +128,42 @@ void sql_callback_add_data(sqlite3_stmt *sql_stmt, void *data) {
assert(sql_stmt);
assert(data);
- struct json_object *response = (struct json_object *)data;
-
- for (int i = 0; i < sqlite3_column_count(sql_stmt); i++) {
- const char *col_name = sqlite3_column_name(sql_stmt, i);
- struct json_object *col_data = json_object_object_get(response, col_name);
+ struct CallbackContext *callback_context = (struct CallbackContext *)data;
+ struct json_object *col_data = NULL;
+ struct RenderContext *render_contexts = calloc(g_blob_count, sizeof(struct RenderContext));
+ thrd_t *threads = calloc(g_blob_count, sizeof(thrd_t));
- if (col_data) {
+ for (int i = 0, tid = 0; i < sqlite3_column_count(sql_stmt); i++) {
+ if (json_object_object_get_ex(callback_context->response, sqlite3_column_name(sql_stmt, i), &col_data)) {
if (sqlite3_column_type(sql_stmt, i) == SQLITE_BLOB) {
- // TODO: render blobs in parallel
+ render_contexts[tid].callback_context = callback_context;
+ render_contexts[tid].blob = sqlite3_value_blob(sqlite3_column_value(sql_stmt, i));
+ render_contexts[tid].blob_size = sqlite3_value_bytes(sqlite3_column_value(sql_stmt, i));
+ thrd_create(&threads[tid], (thrd_start_t)eva_render, &render_contexts[tid]);
+ tid++;
} else {
json_object_array_add(col_data, json_object_new_int64(sqlite3_column_int64(sql_stmt, i)));
}
}
}
+
+ for (int i = 0, tid = 0; i < sqlite3_column_count(sql_stmt); i++) {
+ if (json_object_object_get_ex(callback_context->response, sqlite3_column_name(sql_stmt, i), &col_data)) {
+ if (sqlite3_column_type(sql_stmt, i) == SQLITE_BLOB) {
+ thrd_join(threads[tid], NULL);
+
+ for (int64_t j = 0; j < callback_context->hm_pixel_count; j++) {
+ json_object_array_add(col_data, json_object_new_int64(render_contexts[tid].out[j]));
+ }
+
+ tid++;
+ }
+ }
+ }
+
+ callback_context->response_rows++;
+ free(render_contexts);
+ free(threads);
}
// ----------------------------------------------------------------------------
@@ -107,15 +219,22 @@ void respond_data(int socket_fd, struct json_object *request) {
int64_t nth = json_object_get_int64(json_object_object_get(request, "nth"));
int64_t entries = json_object_get_int64(json_object_object_get(request, "entries"));
- const char *x_axis_pref = (!strcmp(x_axis, "rowid") || !strcmp(x_axis, "step")) ? "core." : "";
+ struct CallbackContext callback_context = {
+ .response = NULL,
+ .response_rows = 0l,
+ .hm_left = json_object_get_int64(json_object_object_get(request, "hm-left")),
+ .hm_pixel_count = json_object_get_int64(json_object_object_get(request, "hm-pixel-count")),
+ .hm_pixel_pow = json_object_get_int64(json_object_object_get(request, "hm-pixel-pow")),
+ };
+
+ json_object_deep_copy(g_response_header, &callback_context.response, NULL);
- struct json_object *response = NULL;
- json_object_deep_copy(g_response_header, &response, NULL);
+ const char *x_axis_pref = (!strcmp(x_axis, "rowid") || !strcmp(x_axis, "step")) ? "core." : "";
sql_exec(
0, NULL, NULL,
sql_callback_add_data,
- response,
+ &callback_context,
"select * from ("
"select core.rowid, core.step, * from core inner join arch "
"where core.rowid = arch.rowid and %s%s > %ld and %s%s <= %ld and core.rowid %% %ld == 0 "
@@ -134,10 +253,9 @@ void respond_data(int socket_fd, struct json_object *request) {
x_axis
);
- const char *response_str = json_object_to_json_string(response);
- log_info("Responding to client with: %s", response_str);
- json_object_to_fd(socket_fd, response, 0);
- json_object_put(response);
+ log_info("Sending client %ld rows of data", callback_context.response_rows);
+ json_object_to_fd(socket_fd, callback_context.response, 0);
+ json_object_put(callback_context.response);
shutdown(socket_fd, SHUT_WR);
}
@@ -193,10 +311,12 @@ int main(void) {
0, NULL, NULL,
sql_callback_add_column_name,
g_response_header,
- "select name from pragma_table_info('core') union "
- "select name from pragma_table_info('arch');"
+ "select name, type from pragma_table_info('core') union "
+ "select name, type from pragma_table_info('arch');"
);
+ log_info("Found %lu blob columns in database", g_blob_count);
+
log_info("Binding to port: %d", PORT);
int opt = 1;
int socket_fd = socket(AF_INET, SOCK_STREAM, 0);
@@ -215,9 +335,9 @@ int main(void) {
socklen_t socket_len = sizeof(struct sockaddr_in);
socket->fd = accept(socket_fd, (struct sockaddr *)&socket->addr, &socket_len);
- thrd_t thrd;
- thrd_create(&thrd, (thrd_start_t)handle_client, socket);
- thrd_detach(thrd);
+ thrd_t thread;
+ thrd_create(&thread, (thrd_start_t)handle_client, socket);
+ thrd_detach(thread);
}
return 0;