1818#include < algorithm>
1919#include < cstddef>
2020#include < cstdint>
21+ #include < chrono>
2122#include < filesystem>
2223#include < fstream>
2324#include < iostream>
@@ -357,7 +358,9 @@ class DBPALocalTestApp {
357358 int scenario_number,
358359 Type::type datatype,
359360 const std::string& values_file_path,
360- std::optional<size_t > max_rows) {
361+ std::optional<size_t > max_rows,
362+ size_t iterations,
363+ size_t warmup_rounds) {
361364 std::cout << " Starting DBPA Local Performance Test..." << std::endl;
362365 std::cout << std::endl;
363366 std::cout << " \n --- Local DBPA Scenario ---" << std::endl;
@@ -390,19 +393,79 @@ class DBPALocalTestApp {
390393 return ;
391394 }
392395
393- bool local_dbpa_ok = TestLocalDbpaAgentScenarios (
394- scenario_number,
395- datatype,
396- value_bytes,
397- num_values,
398- std::nullopt );
396+ bool local_dbpa_ok = true ;
397+ std::vector<double > timings_ms;
398+ size_t total_loops = warmup_rounds + iterations;
399+ timings_ms.reserve (total_loops);
400+ for (size_t i = 0 ; i < total_loops; ++i) {
401+ auto start = std::chrono::steady_clock::now ();
402+ bool ok = TestLocalDbpaAgentScenarios (
403+ scenario_number,
404+ datatype,
405+ value_bytes,
406+ num_values,
407+ std::nullopt );
408+ auto end = std::chrono::steady_clock::now ();
409+ auto elapsed_ms = std::chrono::duration<double , std::milli>(end - start).count ();
410+ timings_ms.push_back (elapsed_ms);
411+ if (i >= warmup_rounds && !ok) {
412+ local_dbpa_ok = false ;
413+ }
414+ }
399415
400416 std::cout << " \n === Demo Summary ===" << std::endl;
401417 const auto & scenario = kScenarios [static_cast <size_t >(scenario_number - 1 )];
402418 std::cout << " Scenario: " << scenario.name << " (#" << scenario_number << " )" << std::endl;
403419 std::cout << " Datatype: " << to_string (datatype) << std::endl;
404420 std::cout << " Values file: " << values_file_path << std::endl;
405421 std::cout << " Rows read: " << num_values << std::endl;
422+ std::cout << " Iterations: " << iterations << std::endl;
423+ std::cout << " Warmup: " << warmup_rounds << std::endl;
424+ std::cout << " Total loops: " << total_loops << std::endl;
425+ if (!timings_ms.empty ()) {
426+ size_t warmup_clamped = std::min (warmup_rounds, timings_ms.size ());
427+ size_t measured_count = timings_ms.size () - warmup_clamped;
428+ if (measured_count == 0 ) {
429+ std::cout << " Timing: no measured iterations after warmup" << std::endl;
430+ } else {
431+ double sum_ms = 0.0 ;
432+ double min_ms = timings_ms[warmup_clamped];
433+ double max_ms = timings_ms[warmup_clamped];
434+ for (size_t i = warmup_clamped; i < timings_ms.size (); ++i) {
435+ double v = timings_ms[i];
436+ sum_ms += v;
437+ min_ms = std::min (min_ms, v);
438+ max_ms = std::max (max_ms, v);
439+ }
440+ double avg_ms = sum_ms / static_cast <double >(measured_count);
441+ std::cout << " Timing (milliseconds): avg=" << avg_ms
442+ << " min=" << min_ms
443+ << " max=" << max_ms
444+ << " measured=" << measured_count << std::endl;
445+
446+ std::vector<double > measured_timings (timings_ms.begin () + static_cast <std::ptrdiff_t >(warmup_clamped),
447+ timings_ms.end ());
448+ std::sort (measured_timings.begin (), measured_timings.end ());
449+ size_t sample_count = std::min<size_t >(5 , measured_timings.size ());
450+ std::cout << " Lowest " << sample_count << " (ms): " ;
451+ for (size_t i = 0 ; i < sample_count; ++i) {
452+ if (i > 0 ) {
453+ std::cout << " , " ;
454+ }
455+ std::cout << measured_timings[i];
456+ }
457+ std::cout << std::endl;
458+
459+ std::cout << " Highest " << sample_count << " (ms): " ;
460+ for (size_t i = 0 ; i < sample_count; ++i) {
461+ if (i > 0 ) {
462+ std::cout << " , " ;
463+ }
464+ std::cout << measured_timings[measured_timings.size () - sample_count + i];
465+ }
466+ std::cout << std::endl;
467+ }
468+ }
406469 std::cout << " Local DBPA Scenarios: " << (local_dbpa_ok ? " PASS" : " FAIL" ) << std::endl;
407470 }
408471};
@@ -419,6 +482,10 @@ int main(int argc, char* argv[]) {
419482 cxxopts::value<std::string>())
420483 (" max_rows" , " Maximum number of rows to read from values_file (0 = no limit)." ,
421484 cxxopts::value<size_t >()->default_value (" 0" ))
485+ (" iterations" , " Number of iterations to run." ,
486+ cxxopts::value<size_t >()->default_value (" 20" ))
487+ (" warmup" , " Warmup iterations to discard from timing." ,
488+ cxxopts::value<size_t >()->default_value (" 3" ))
422489 (" h,help" , " Display this help message" );
423490
424491 try {
@@ -432,6 +499,8 @@ int main(int argc, char* argv[]) {
432499 std::string datatype_arg = result[" datatype" ].as <std::string>();
433500 std::string values_file_path = result[" values_file" ].as <std::string>();
434501 size_t max_rows_raw = result[" max_rows" ].as <size_t >();
502+ size_t iterations = result[" iterations" ].as <size_t >();
503+ size_t warmup = result[" warmup" ].as <size_t >();
435504
436505 if (values_file_path.empty ()) {
437506 std::cout << " Error: --values_file is required." << std::endl;
@@ -445,14 +514,19 @@ int main(int argc, char* argv[]) {
445514 std::cout << options.help () << std::endl;
446515 return 1 ;
447516 }
517+ if (iterations <= 0 ) {
518+ std::cout << " Error: --iterations must be > 0." << std::endl;
519+ std::cout << options.help () << std::endl;
520+ return 1 ;
521+ }
448522
449523 std::optional<size_t > max_rows;
450524 if (max_rows_raw > 0 ) {
451525 max_rows = max_rows_raw;
452526 }
453527
454528 DBPALocalTestApp demo;
455- demo.RunDemo (scenario_number, datatype_opt.value (), values_file_path, max_rows);
529+ demo.RunDemo (scenario_number, datatype_opt.value (), values_file_path, max_rows, iterations, warmup );
456530 return 0 ;
457531 } catch (const std::exception& e) {
458532 std::cerr << " Error: " << e.what () << std::endl;
0 commit comments