LCOV - code coverage report
Current view: top level - core - timer.cpp (source / functions) Coverage Total Hit
Test: hashbrowns Coverage Lines: 96.5 % 143 138
Test Date: 2026-04-10 19:00:18 Functions: 100.0 % 16 16
Legend: Lines: hit not hit

            Line data    Source code
       1              : #include "timer.h"
       2              : #include <iostream>
       3              : #include <iomanip>
       4              : #include <fstream>
       5              : #include <thread>
       6              : 
       7              : namespace hashbrowns {
       8              : 
       9           39 : Timer::Timer(bool remove_outliers, double outlier_threshold)
      10           78 :     : last_duration_(0), is_running_(false), 
      11          117 :       remove_outliers_(remove_outliers), outlier_threshold_(outlier_threshold) {
      12           39 : }
      13              : 
      14          115 : void Timer::start() {
      15          115 :     if (is_running_) {
      16            1 :         throw std::runtime_error("Timer is already running");
      17              :     }
      18          114 :     start_time_ = clock_type::now();
      19          114 :     is_running_ = true;
      20          114 : }
      21              : 
      22          115 : Timer::duration Timer::stop() {
      23          115 :     if (!is_running_) {
      24            1 :         throw std::runtime_error("Timer is not running");
      25              :     }
      26              :     
      27          114 :     auto end_time = clock_type::now();
      28          114 :     last_duration_ = std::chrono::duration_cast<duration>(end_time - start_time_);
      29          114 :     samples_.push_back(last_duration_);
      30          114 :     is_running_ = false;
      31              :     
      32          114 :     return last_duration_;
      33              : }
      34              : 
      35           14 : void Timer::add_sample(duration d) {
      36           14 :     samples_.push_back(d);
      37           14 : }
      38              : 
      39            3 : void Timer::reset() {
      40            3 :     samples_.clear();
      41            3 :     last_duration_ = duration(0);
      42            3 :     is_running_ = false;
      43            3 : }
      44              : 
      45            5 : Timer::Statistics Timer::get_statistics() const {
      46            5 :     if (samples_.empty()) {
      47            1 :         return {0.0, 0.0, 0.0, 0.0, 0.0, 0, 0.0};
      48              :     }
      49              :     
      50              :     // Work with a copy so we can sort without modifying original
      51            4 :     std::vector<duration> data = samples_;
      52              :     
      53              :     // Remove outliers if requested
      54            4 :     size_t original_count = data.size();
      55            4 :     if (remove_outliers_ && data.size() > 3) {
      56            4 :         data = remove_outliers(data);
      57              :     }
      58              :     
      59            4 :     if (data.empty()) {
      60            0 :         return {0.0, 0.0, 0.0, 0.0, 0.0, 0, 1.0}; // All samples were outliers
      61              :     }
      62              :     
      63              :     // Sort for median calculation
      64            4 :     std::sort(data.begin(), data.end());
      65              :     
      66              :     // Calculate basic statistics
      67            4 :     double sum = 0.0;
      68           35 :     for (const auto& d : data) {
      69           31 :         sum += d.count();
      70              :     }
      71              :     
      72            4 :     double mean = sum / data.size();
      73              :     
      74              :     // Median
      75              :     double median;
      76            4 :     size_t n = data.size();
      77            4 :     if (n % 2 == 0) {
      78            1 :         median = (data[n/2 - 1].count() + data[n/2].count()) / 2.0;
      79              :     } else {
      80            3 :         median = data[n/2].count();
      81              :     }
      82              :     
      83              :     // Standard deviation
      84            4 :     double variance_sum = 0.0;
      85           35 :     for (const auto& d : data) {
      86           31 :         double diff = d.count() - mean;
      87           31 :         variance_sum += diff * diff;
      88              :     }
      89            4 :     double std_dev = std::sqrt(variance_sum / data.size());
      90              :     
      91              :     // Min/max
      92            4 :     double min_val = data.front().count();
      93            4 :     double max_val = data.back().count();
      94              :     
      95              :     // Outlier ratio
      96            4 :     double outlier_ratio = static_cast<double>(original_count - data.size()) / original_count;
      97              :     
      98            4 :     return {mean, median, std_dev, min_val, max_val, data.size(), outlier_ratio};
      99            4 : }
     100              : 
     101            4 : std::vector<Timer::duration> Timer::remove_outliers(const std::vector<duration>& data) const {
     102            4 :     if (data.size() <= 3) {
     103            0 :         return data; // Too few samples for outlier detection
     104              :     }
     105              :     
     106              :     // Calculate mean and standard deviation
     107            4 :     double sum = 0.0;
     108           38 :     for (const auto& d : data) {
     109           34 :         sum += d.count();
     110              :     }
     111            4 :     double mean = sum / data.size();
     112              :     
     113            4 :     double variance_sum = 0.0;
     114           38 :     for (const auto& d : data) {
     115           34 :         double diff = d.count() - mean;
     116           34 :         variance_sum += diff * diff;
     117              :     }
     118            4 :     double std_dev = std::sqrt(variance_sum / data.size());
     119              :     
     120              :     // Filter out outliers
     121            4 :     std::vector<duration> filtered;
     122           38 :     for (const auto& d : data) {
     123           34 :         double zscore = calculate_zscore(d.count(), mean, std_dev);
     124           34 :         if (std::abs(zscore) <= outlier_threshold_) {
     125           31 :             filtered.push_back(d);
     126              :         }
     127              :     }
     128              :     
     129            4 :     return filtered.empty() ? data : filtered; // Return original if all were outliers
     130            4 : }
     131              : 
     132           34 : double Timer::calculate_zscore(double value, double mean, double std_dev) const {
     133           34 :     if (std_dev == 0.0) return 0.0;
     134           34 :     return (value - mean) / std_dev;
     135              : }
     136              : 
     137              : // ScopeTimer implementation
     138            2 : ScopeTimer::ScopeTimer(const std::string& name, bool auto_print)
     139            2 :     : operation_name_(name), auto_print_(auto_print), stopped_(false) {
     140            2 :     start_time_ = Timer::clock_type::now();
     141            2 : }
     142              : 
     143            2 : ScopeTimer::~ScopeTimer() {
     144            2 :     if (!stopped_ && auto_print_) {
     145            1 :         auto duration = stop();
     146            1 :         std::cout << "[TIMER] ";
     147            1 :         if (!operation_name_.empty()) {
     148            1 :             std::cout << operation_name_ << ": ";
     149              :         }
     150            1 :         std::cout << std::fixed << std::setprecision(3) 
     151            1 :                   << duration.count() / 1000000.0 << " ms\n";
     152              :     }
     153            2 : }
     154              : 
     155            3 : Timer::duration ScopeTimer::elapsed() const {
     156            3 :     auto now = Timer::clock_type::now();
     157            6 :     return std::chrono::duration_cast<Timer::duration>(now - start_time_);
     158              : }
     159              : 
     160            3 : Timer::duration ScopeTimer::stop() {
     161            3 :     if (!stopped_) {
     162            2 :         stopped_ = true;
     163            2 :         return elapsed();
     164              :     }
     165            1 :     return Timer::duration(0);
     166              : }
     167              : 
     168              : // BenchmarkRunner implementation
     169            1 : void BenchmarkRunner::print_comparison() const {
     170            1 :     if (results_.empty()) {
     171            0 :         std::cout << "No benchmark results to display.\n";
     172            0 :         return;
     173              :     }
     174              :     
     175            1 :     std::cout << "\n=== Benchmark Results ===\n";
     176            1 :     std::cout << std::left << std::setw(20) << "Benchmark"
     177            1 :               << std::right << std::setw(12) << "Mean (ms)"
     178              :               << std::setw(12) << "Median (ms)"
     179              :               << std::setw(12) << "Std Dev (ms)"
     180              :               << std::setw(15) << "Ops/Sec"
     181            1 :               << std::setw(10) << "Samples\n";
     182            3 :     std::cout << std::string(81, '-') << "\n";
     183              :     
     184            3 :     for (const auto& result : results_) {
     185            2 :         std::cout << std::left << std::setw(20) << result.name
     186            2 :                   << std::right << std::fixed << std::setprecision(3)
     187            2 :                   << std::setw(12) << result.stats.mean_ms()
     188            2 :                   << std::setw(12) << result.stats.median_ms()
     189            2 :                   << std::setw(12) << result.stats.std_dev_ms()
     190            2 :                   << std::setw(15) << std::scientific << std::setprecision(2) << result.operations_per_second
     191            2 :                   << std::setw(10) << result.stats.sample_count << "\n";
     192              :     }
     193              :     
     194              :     // Find fastest and slowest
     195            1 :     if (results_.size() > 1) {
     196            1 :         auto fastest = std::min_element(results_.begin(), results_.end(),
     197            1 :             [](const auto& a, const auto& b) { return a.stats.mean_ns < b.stats.mean_ns; });
     198            1 :         auto slowest = std::max_element(results_.begin(), results_.end(),
     199            1 :             [](const auto& a, const auto& b) { return a.stats.mean_ns < b.stats.mean_ns; });
     200              :         
     201            1 :         double speedup = slowest->stats.mean_ns / fastest->stats.mean_ns;
     202              :         
     203            1 :         std::cout << "\n--- Performance Analysis ---\n";
     204            1 :         std::cout << "Fastest: " << fastest->name << "\n";
     205            1 :         std::cout << "Slowest: " << slowest->name << "\n";
     206            1 :         std::cout << "Speedup: " << std::fixed << std::setprecision(2) << speedup << "x\n";
     207              :     }
     208              :     
     209            1 :     std::cout << "========================\n\n";
     210              : }
     211              : 
     212            1 : void BenchmarkRunner::export_csv(const std::string& filename) const {
     213            1 :     std::ofstream file(filename);
     214            1 :     if (!file) {
     215            0 :         throw std::runtime_error("Cannot open file for writing: " + filename);
     216              :     }
     217              :     
     218              :     // CSV header
     219            1 :     file << "Name,Mean_ns,Median_ns,StdDev_ns,Min_ns,Max_ns,Samples,Ops_per_sec,Data_size\n";
     220              :     
     221              :     // Data rows
     222            3 :     for (const auto& result : results_) {
     223            2 :         file << result.name << ","
     224            2 :              << result.stats.mean_ns << ","
     225            2 :              << result.stats.median_ns << ","
     226            2 :              << result.stats.std_dev_ns << ","
     227            2 :              << result.stats.min_ns << ","
     228            2 :              << result.stats.max_ns << ","
     229            2 :              << result.stats.sample_count << ","
     230            2 :              << result.operations_per_second << ","
     231            2 :              << result.data_size << "\n";
     232              :     }
     233              :     
     234            1 :     file.close();
     235            1 :     std::cout << "Benchmark results exported to: " << filename << "\n";
     236            2 : }
     237              : 
     238              : } // namespace hashbrowns
        

Generated by: LCOV version 2.0-1