diff options
| -rw-r--r-- | arch/dummy/arch_plots.cpp | 8 | ||||
| -rw-r--r-- | arch/v1/arch_plots.cpp | 58 | ||||
| -rw-r--r-- | core/client.cpp | 686 | ||||
| -rw-r--r-- | core/compress.c | 4 | ||||
| -rw-r--r-- | core/render.c | 91 | ||||
| -rw-r--r-- | core/salis.c | 4 | ||||
| -rw-r--r-- | core/server.c | 166 |
7 files changed, 736 insertions, 281 deletions
diff --git a/arch/dummy/arch_plots.cpp b/arch/dummy/arch_plots.cpp index 15d6a7b..8cece2f 100644 --- a/arch/dummy/arch_plots.cpp +++ b/arch/dummy/arch_plots.cpp @@ -1,3 +1,5 @@ -std::vector<TraceNamed<ImS64>> g_arch_traces = {}; -std::vector<Plot> g_arch_plots = {}; -std::vector<PlotStacked> g_arch_plots_stacked = {}; +std::array<TraceNamed<ImS64>, 0> g_arch_traces = {}; +std::array<TraceHeatmap<ImS64>, 0> g_arch_traces_heatmaps = {}; +std::array<PlotLines, 0> g_arch_plots = {}; +std::array<PlotStacked, 0> g_arch_plots_stacked = {}; +std::array<PlotHeatmap, 0> g_arch_plots_heatmaps = {}; diff --git a/arch/v1/arch_plots.cpp b/arch/v1/arch_plots.cpp index d88a2a1..d9147cb 100644 --- a/arch/v1/arch_plots.cpp +++ b/arch/v1/arch_plots.cpp @@ -1,43 +1,59 @@ -#define INST_EVENT_ARRAYS(core) \ - INST_EVENT_ARRAY(core, pop) /* instruction population */ \ - INST_EVENT_ARRAY(core, exe) /* instruction executions */ \ - INST_EVENT_ARRAY(core, wrt) /* instruction writes */ - -std::vector<TraceNamed<ImS64>> g_arch_traces = { +std::array g_arch_traces = std::to_array<TraceNamed<ImS64>>({ #define INST(core, pref, index, label, mnemonic, symbol) \ {#label "_" #pref "_" #core, #label}, -#define INST_EVENT_ARRAY(core, iv) \ - INST_SET(core, iv) #define FOR_CORE(i) \ {"wmb0_" #i, "wmb0_" #i}, \ {"wmb1_" #i, "wmb1_" #i}, \ {"wdea_" #i, "wdea_" #i}, \ - INST_EVENT_ARRAYS(i) + INST_SET(i, pop) \ + INST_SET(i, exe) \ + INST_SET(i, wrt) FOR_CORES #undef FOR_CORE -#undef INST_EVENT_ARRAY #undef INST -}; +}); + +std::array g_arch_traces_heatmaps = std::to_array<TraceHeatmap<ImS64>>({ +#define FOR_CORE(i) \ + {"wev_" #i, "wev_" #i}, \ + {"xev_" #i, "xev_" #i}, + FOR_CORES +#undef FOR_CORE +}); -std::vector<Plot> g_arch_plots = { +std::array g_arch_plots = std::to_array<PlotLines>({ {"wevs", "general", { #define FOR_CORE(i) "wmb0_" #i, "wmb1_" #i, "wdea_" #i, FOR_CORES #undef FOR_CORE }}, -}; +}); -std::vector<PlotStacked> g_arch_plots_stacked = { +std::array g_arch_plots_stacked = std::to_array<PlotStacked>({ #define INST(core, pref, index, label, mnemonic, symbol) \ #label "_" #pref "_" #core, -#define INST_EVENT_ARRAY(core, iv) \ - {"i" #iv "%_" #core, "population", { \ - INST_SET(core, iv) \ - }}, #define FOR_CORE(i) \ - INST_EVENT_ARRAYS(i) + {"ipop%_" #i, "population", { INST_SET(i, pop) }}, + FOR_CORES +#undef FOR_CORE +#define FOR_CORE(i) \ + {"iexe%_" #i, "population", { INST_SET(i, exe) }}, + FOR_CORES +#undef FOR_CORE +#define FOR_CORE(i) \ + {"iwrt%_" #i, "population", { INST_SET(i, wrt) }}, FOR_CORES #undef FOR_CORE -#undef INST_EVENT_ARRAY #undef INST -}; +}); + +std::array g_arch_plots_heatmaps = std::to_array<PlotHeatmap>({ +#define FOR_CORE(i) \ + {"wev_" #i, "heatmaps", "wev_" #i}, + FOR_CORES +#undef FOR_CORE +#define FOR_CORE(i) \ + {"xev_" #i, "heatmaps", "xev_" #i}, + FOR_CORES +#undef FOR_CORE +}); 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(¶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/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(¶ms); + comp_inflate_end(¶ms); + + for (int64_t i = 0; i < hm_pixel_count; i++) { + render_context->out[i] = 0l; + + for (int64_t j = 0; j < hm_pixel_res; j++) { + int64_t coord = hm_left + (i * hm_pixel_res) + j; +#if defined(MVEC_LOOP) + coord %= MVEC_SIZE; +#endif + render_context->out[i] += render_context->eva[coord]; + } + } + + return 0; +} // ---------------------------------------------------------------------------- // SQL callbacks @@ -24,13 +107,20 @@ void sql_callback_add_column_name(sqlite3_stmt *sql_stmt, void *data) { assert(sql_stmt); assert(data); assert(sqlite3_column_type(sql_stmt, 0) == SQLITE_TEXT); + assert(sqlite3_column_type(sql_stmt, 1) == SQLITE_TEXT); assert(!strcmp(sqlite3_column_name(sql_stmt, 0), "name")); + assert(!strcmp(sqlite3_column_name(sql_stmt, 1), "type")); const char *col_name = (const char *)sqlite3_column_text(sql_stmt, 0); - struct json_object *response = (struct json_object *)data; + const char *col_type = (const char *)sqlite3_column_text(sql_stmt, 1); + struct json_object *response_header = (struct json_object *)data; - if (!json_object_object_get_ex(response, col_name, NULL)) { - json_object_object_add(response, col_name, json_object_new_array()); + if (!json_object_object_get_ex(response_header, col_name, NULL)) { + json_object_object_add(response_header, col_name, json_object_new_array()); + } + + if (!strcmp(col_type, "BLOB")) { + g_blob_count++; } } @@ -38,20 +128,42 @@ void sql_callback_add_data(sqlite3_stmt *sql_stmt, void *data) { assert(sql_stmt); assert(data); - struct json_object *response = (struct json_object *)data; - - for (int i = 0; i < sqlite3_column_count(sql_stmt); i++) { - const char *col_name = sqlite3_column_name(sql_stmt, i); - struct json_object *col_data = json_object_object_get(response, col_name); + struct CallbackContext *callback_context = (struct CallbackContext *)data; + struct json_object *col_data = NULL; + struct RenderContext *render_contexts = calloc(g_blob_count, sizeof(struct RenderContext)); + thrd_t *threads = calloc(g_blob_count, sizeof(thrd_t)); - if (col_data) { + for (int i = 0, tid = 0; i < sqlite3_column_count(sql_stmt); i++) { + if (json_object_object_get_ex(callback_context->response, sqlite3_column_name(sql_stmt, i), &col_data)) { if (sqlite3_column_type(sql_stmt, i) == SQLITE_BLOB) { - // TODO: render blobs in parallel + render_contexts[tid].callback_context = callback_context; + render_contexts[tid].blob = sqlite3_value_blob(sqlite3_column_value(sql_stmt, i)); + render_contexts[tid].blob_size = sqlite3_value_bytes(sqlite3_column_value(sql_stmt, i)); + thrd_create(&threads[tid], (thrd_start_t)eva_render, &render_contexts[tid]); + tid++; } else { json_object_array_add(col_data, json_object_new_int64(sqlite3_column_int64(sql_stmt, i))); } } } + + for (int i = 0, tid = 0; i < sqlite3_column_count(sql_stmt); i++) { + if (json_object_object_get_ex(callback_context->response, sqlite3_column_name(sql_stmt, i), &col_data)) { + if (sqlite3_column_type(sql_stmt, i) == SQLITE_BLOB) { + thrd_join(threads[tid], NULL); + + for (int64_t j = 0; j < callback_context->hm_pixel_count; j++) { + json_object_array_add(col_data, json_object_new_int64(render_contexts[tid].out[j])); + } + + tid++; + } + } + } + + callback_context->response_rows++; + free(render_contexts); + free(threads); } // ---------------------------------------------------------------------------- @@ -107,15 +219,22 @@ void respond_data(int socket_fd, struct json_object *request) { int64_t nth = json_object_get_int64(json_object_object_get(request, "nth")); int64_t entries = json_object_get_int64(json_object_object_get(request, "entries")); - const char *x_axis_pref = (!strcmp(x_axis, "rowid") || !strcmp(x_axis, "step")) ? "core." : ""; + struct CallbackContext callback_context = { + .response = NULL, + .response_rows = 0l, + .hm_left = json_object_get_int64(json_object_object_get(request, "hm-left")), + .hm_pixel_count = json_object_get_int64(json_object_object_get(request, "hm-pixel-count")), + .hm_pixel_pow = json_object_get_int64(json_object_object_get(request, "hm-pixel-pow")), + }; + + json_object_deep_copy(g_response_header, &callback_context.response, NULL); - struct json_object *response = NULL; - json_object_deep_copy(g_response_header, &response, NULL); + const char *x_axis_pref = (!strcmp(x_axis, "rowid") || !strcmp(x_axis, "step")) ? "core." : ""; sql_exec( 0, NULL, NULL, sql_callback_add_data, - response, + &callback_context, "select * from (" "select core.rowid, core.step, * from core inner join arch " "where core.rowid = arch.rowid and %s%s > %ld and %s%s <= %ld and core.rowid %% %ld == 0 " @@ -134,10 +253,9 @@ void respond_data(int socket_fd, struct json_object *request) { x_axis ); - const char *response_str = json_object_to_json_string(response); - log_info("Responding to client with: %s", response_str); - json_object_to_fd(socket_fd, response, 0); - json_object_put(response); + log_info("Sending client %ld rows of data", callback_context.response_rows); + json_object_to_fd(socket_fd, callback_context.response, 0); + json_object_put(callback_context.response); shutdown(socket_fd, SHUT_WR); } @@ -193,10 +311,12 @@ int main(void) { 0, NULL, NULL, sql_callback_add_column_name, g_response_header, - "select name from pragma_table_info('core') union " - "select name from pragma_table_info('arch');" + "select name, type from pragma_table_info('core') union " + "select name, type from pragma_table_info('arch');" ); + log_info("Found %lu blob columns in database", g_blob_count); + log_info("Binding to port: %d", PORT); int opt = 1; int socket_fd = socket(AF_INET, SOCK_STREAM, 0); @@ -215,9 +335,9 @@ int main(void) { socklen_t socket_len = sizeof(struct sockaddr_in); socket->fd = accept(socket_fd, (struct sockaddr *)&socket->addr, &socket_len); - thrd_t thrd; - thrd_create(&thrd, (thrd_start_t)handle_client, socket); - thrd_detach(thrd); + thrd_t thread; + thrd_create(&thread, (thrd_start_t)handle_client, socket); + thrd_detach(thread); } return 0; |
