feat: initial scaffold data_table_bench (issue 0133)
This commit is contained in:
@@ -0,0 +1,163 @@
|
||||
// data_table_bench — headless performance gate for data_table::render().
|
||||
// Issue 0133: 10M-row bench for the upcoming data_table refactor.
|
||||
//
|
||||
// Usage:
|
||||
// ./data_table_bench --rows 10000000 --duration 30
|
||||
// ./data_table_bench --rows 100000 --duration 5 # CI smoke (fast)
|
||||
// ./data_table_bench --rows 1000000 --duration 10 --no-db
|
||||
//
|
||||
// Output: JSON to stdout.
|
||||
// Exit 0 if all scenarios pass (fps_p1 >= threshold), 1 otherwise.
|
||||
//
|
||||
// Headless strategy:
|
||||
// fn::run_app creates the GL context (needed for ImGui clipper to work
|
||||
// on 10M-row virtual scroll). We hide the GLFW window via glfwHideWindow()
|
||||
// on the first frame. The Runner::tick() is called each frame to drive the
|
||||
// benchmark state machine across all 4 scenarios. When tick() returns true
|
||||
// (all done) we close the window and fn::run_app exits.
|
||||
|
||||
#include "app_base.h"
|
||||
#include "core/logger.h"
|
||||
#include "bench_runner.h"
|
||||
|
||||
#include <imgui.h>
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Argument parsing
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
static void print_usage() {
|
||||
fprintf(stderr,
|
||||
"Usage: data_table_bench [options]\n"
|
||||
" --rows N Number of rows (default: 10000000)\n"
|
||||
" --duration S Seconds per scenario (default: 30)\n"
|
||||
" --threshold F fps_p1 pass threshold (default: 60.0)\n"
|
||||
" --db PATH Persist results to SQLite (default: operations.db)\n"
|
||||
" --no-db Skip persistence\n"
|
||||
" --sha SHA Git commit SHA to tag run\n"
|
||||
" --verbose Extra logging\n"
|
||||
);
|
||||
}
|
||||
|
||||
struct Args {
|
||||
long long rows = 10000000;
|
||||
double duration_s = 30.0;
|
||||
double threshold = 60.0;
|
||||
std::string db_path = "operations.db";
|
||||
std::string commit_sha;
|
||||
bool verbose = false;
|
||||
};
|
||||
|
||||
static Args parse_args(int argc, char** argv) {
|
||||
Args a;
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
if (strcmp(argv[i], "--rows") == 0 && i + 1 < argc)
|
||||
a.rows = atoll(argv[++i]);
|
||||
else if (strcmp(argv[i], "--duration") == 0 && i + 1 < argc)
|
||||
a.duration_s = atof(argv[++i]);
|
||||
else if (strcmp(argv[i], "--threshold") == 0 && i + 1 < argc)
|
||||
a.threshold = atof(argv[++i]);
|
||||
else if (strcmp(argv[i], "--db") == 0 && i + 1 < argc)
|
||||
a.db_path = argv[++i];
|
||||
else if (strcmp(argv[i], "--no-db") == 0)
|
||||
a.db_path = "";
|
||||
else if (strcmp(argv[i], "--sha") == 0 && i + 1 < argc)
|
||||
a.commit_sha = argv[++i];
|
||||
else if (strcmp(argv[i], "--verbose") == 0)
|
||||
a.verbose = true;
|
||||
else if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0) {
|
||||
print_usage();
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// main
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
Args args = parse_args(argc, argv);
|
||||
|
||||
fprintf(stderr, "[bench] rows=%lld duration=%.0fs threshold=%.0f db=%s\n",
|
||||
args.rows, args.duration_s, args.threshold,
|
||||
args.db_path.empty() ? "(none)" : args.db_path.c_str());
|
||||
|
||||
bench::Config cfg;
|
||||
cfg.rows = args.rows;
|
||||
cfg.duration_s = args.duration_s;
|
||||
cfg.fps_threshold = args.threshold;
|
||||
cfg.db_path = args.db_path;
|
||||
cfg.commit_sha = args.commit_sha;
|
||||
cfg.verbose = args.verbose;
|
||||
|
||||
// Seed dataset before opening GL context — can take several seconds for 10M.
|
||||
fprintf(stderr, "[bench] seeding %lld x %d dataset... ", cfg.rows, cfg.cols);
|
||||
fflush(stderr);
|
||||
bench::Runner runner(cfg);
|
||||
fprintf(stderr, "done\n");
|
||||
fflush(stderr);
|
||||
|
||||
// fn::run_app config — headless visual setup.
|
||||
fn::AppConfig app_cfg;
|
||||
app_cfg.title = "data_table_bench";
|
||||
app_cfg.width = 1920;
|
||||
app_cfg.height = 1080;
|
||||
app_cfg.vsync = false; // uncapped FPS for meaningful bench
|
||||
app_cfg.viewports = false; // no floating panels
|
||||
app_cfg.auto_dockspace = false; // no dockspace overhead
|
||||
app_cfg.auto_layouts = false; // no layout DB
|
||||
|
||||
app_cfg.about.name = "data_table_bench";
|
||||
app_cfg.about.version = "0.1.0";
|
||||
app_cfg.about.description = "Headless 10M-row bench for data_table (issue 0133)";
|
||||
app_cfg.log = {"data_table_bench.log", 1};
|
||||
app_cfg.header_badge.enabled = false; // headless — no badge
|
||||
|
||||
static GLFWwindow* g_window = nullptr;
|
||||
bool window_hidden = false;
|
||||
|
||||
int rc = fn::run_app(app_cfg, [&]() {
|
||||
// First frame: grab window handle and hide.
|
||||
if (!g_window) {
|
||||
ImGuiViewport* vp = ImGui::GetMainViewport();
|
||||
if (vp && vp->PlatformHandle) {
|
||||
g_window = (GLFWwindow*)vp->PlatformHandle;
|
||||
glfwHideWindow(g_window);
|
||||
window_hidden = true;
|
||||
}
|
||||
}
|
||||
|
||||
// tick() drives the benchmark state machine, renders the table,
|
||||
// and returns true when all 4 scenarios are complete.
|
||||
bool finished = runner.tick();
|
||||
if (finished && g_window) {
|
||||
glfwSetWindowShouldClose(g_window, GLFW_TRUE);
|
||||
}
|
||||
});
|
||||
|
||||
if (rc != 0) {
|
||||
fprintf(stderr, "[bench] run_app error: %d\n", rc);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Print JSON to stdout.
|
||||
runner.print_json();
|
||||
|
||||
// Persist to SQLite.
|
||||
if (!args.db_path.empty()) {
|
||||
runner.persist(args.db_path);
|
||||
fprintf(stderr, "[bench] results persisted to %s\n", args.db_path.c_str());
|
||||
}
|
||||
|
||||
bool passed = runner.all_passed();
|
||||
fprintf(stderr, "[bench] overall: %s\n", passed ? "PASS" : "FAIL");
|
||||
return passed ? 0 : 1;
|
||||
}
|
||||
Reference in New Issue
Block a user