128 lines
3.8 KiB
C++
128 lines
3.8 KiB
C++
#pragma once
|
|
// bench_runner — headless benchmark harness for data_table::render().
|
|
// Issue 0133: perf gate for 10M-row refactor.
|
|
//
|
|
// Architecture: the Runner is driven frame-by-frame from within fn::run_app's
|
|
// render callback. Each frame it calls data_table::render() for the current
|
|
// scenario and measures the frame time. After duration_s seconds it moves to
|
|
// the next scenario. After all 4 scenarios it signals completion.
|
|
//
|
|
// Usage in render callback:
|
|
// static bench::Runner runner(cfg);
|
|
// runner.tick(); // called every frame
|
|
// if (runner.done()) { ... print + persist + close window ... }
|
|
|
|
#include <chrono>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
namespace bench {
|
|
|
|
enum class Scenario {
|
|
LinearScroll, // advance row offset each frame
|
|
FilterLike, // filter name CONTAINS "foo"
|
|
SortNumeric, // sort score col descending
|
|
ColorRule, // NumericRange color rule on value col
|
|
};
|
|
|
|
inline const char* scenario_name(Scenario s) {
|
|
switch (s) {
|
|
case Scenario::LinearScroll: return "linear_scroll";
|
|
case Scenario::FilterLike: return "filter_like";
|
|
case Scenario::SortNumeric: return "sort_numeric";
|
|
case Scenario::ColorRule: return "color_rule";
|
|
}
|
|
return "unknown";
|
|
}
|
|
|
|
struct ScenarioResult {
|
|
Scenario scenario = Scenario::LinearScroll;
|
|
double fps_p50 = 0.0;
|
|
double fps_p1 = 0.0;
|
|
double mem_rss_mb = 0.0;
|
|
double cpu_pct = 0.0;
|
|
double duration_s = 0.0;
|
|
bool pass = false;
|
|
};
|
|
|
|
struct Config {
|
|
long long rows = 10000000;
|
|
int cols = 20;
|
|
double duration_s = 30.0;
|
|
double fps_threshold = 60.0;
|
|
std::string db_path = "operations.db";
|
|
std::string commit_sha;
|
|
bool verbose = false;
|
|
};
|
|
|
|
class Runner {
|
|
public:
|
|
explicit Runner(const Config& cfg);
|
|
|
|
// Called once per render frame. Internally manages scenario transitions.
|
|
// Returns true when all scenarios are finished.
|
|
bool tick();
|
|
|
|
// Returns true when all scenarios have completed.
|
|
bool done() const { return done_; }
|
|
|
|
// Print JSON summary to stdout.
|
|
void print_json() const;
|
|
|
|
// Persist results into bench_runs SQLite table.
|
|
void persist(const std::string& db_path) const;
|
|
|
|
// Returns false if any scenario failed fps_threshold assertion.
|
|
bool all_passed() const;
|
|
|
|
const std::vector<ScenarioResult>& results() const { return results_; }
|
|
|
|
private:
|
|
Config cfg_;
|
|
std::vector<ScenarioResult> results_;
|
|
bool done_ = false;
|
|
|
|
// Backing storage for synthetic dataset (row-major strings).
|
|
std::vector<std::string> backing_;
|
|
std::vector<const char*> ptrs_;
|
|
|
|
// Per-scenario timing state.
|
|
int current_scenario_ = 0;
|
|
bool scenario_started_ = false;
|
|
|
|
// Frame timing for current scenario.
|
|
using Clock = std::chrono::steady_clock;
|
|
Clock::time_point scenario_wall_start_;
|
|
Clock::time_point last_frame_start_;
|
|
std::vector<double> frame_fps_;
|
|
double user_start_ = 0.0;
|
|
double sys_start_ = 0.0;
|
|
|
|
// Scenario-specific state (rebuilt each scenario).
|
|
struct ScenarioState;
|
|
ScenarioState* sc_state_ = nullptr;
|
|
|
|
int scroll_row_ = 0;
|
|
|
|
static constexpr Scenario kScenarios[] = {
|
|
Scenario::LinearScroll,
|
|
Scenario::FilterLike,
|
|
Scenario::SortNumeric,
|
|
Scenario::ColorRule,
|
|
};
|
|
static constexpr int kNumScenarios = 4;
|
|
|
|
void seed_dataset();
|
|
void begin_scenario(Scenario s);
|
|
void finish_scenario();
|
|
void render_table_frame(Scenario s);
|
|
};
|
|
|
|
// Measure RSS memory in MB (Linux: /proc/self/status).
|
|
double measure_rss_mb();
|
|
|
|
// Measure CPU % from RUSAGE delta over wall time.
|
|
double measure_cpu_pct(double wall_s, double user_s, double sys_s);
|
|
|
|
} // namespace bench
|