Files
stupidsimcpp/util/timing_decorator.hpp
Yggdrasil75 5a0d81134e init
2025-11-05 11:56:56 -05:00

101 lines
3.2 KiB
C++

#pragma once
#include <chrono>
#include <unordered_map>
#include <string>
#include <vector>
#include <algorithm>
#include <iostream>
#include <iomanip>
#include <sstream>
#include <memory>
#include <functional>
class FunctionTimer {
public:
enum class Mode { BASIC, ENHANCED };
struct TimingStats {
size_t call_count = 0;
double total_time = 0.0;
std::vector<double> timings;
double avg_time() const {
return call_count > 0 ? total_time / call_count : 0.0;
}
};
struct PercentileStats {
double p99_9 = 0.0;
double p99 = 0.0;
double p95 = 0.0;
double p90 = 0.0;
double max = 0.0;
double min = 0.0;
double median = 0.0;
};
// Record timing for a function
static void recordTiming(const std::string& func_name, double elapsed_seconds);
// Get statistics
static std::unordered_map<std::string, TimingStats> getStats(Mode mode = Mode::BASIC);
// Print statistics
static void printStats(Mode mode = Mode::ENHANCED);
// Clear all statistics
static void clearStats();
private:
static std::unordered_map<std::string, TimingStats> stats_;
static PercentileStats calculatePercentiles(const std::vector<double>& timings);
};
// Macro to easily time functions - similar to Python decorator
#define TIME_FUNCTION auto function_timer_scoped_ = ScopedFunctionTimer(__func__)
// Scoped timer for RAII-style timing
class ScopedFunctionTimer {
public:
ScopedFunctionTimer(const std::string& func_name)
: func_name_(func_name), start_(std::chrono::steady_clock::now()) {}
~ScopedFunctionTimer() {
auto end = std::chrono::steady_clock::now();
auto elapsed = std::chrono::duration_cast<std::chrono::microseconds>(end - start_);
FunctionTimer::recordTiming(func_name_, elapsed.count() / 1000000.0);
}
private:
std::string func_name_;
std::chrono::steady_clock::time_point start_;
};
// Template decorator for functions (similar to Python)
template<typename Func, typename... Args>
auto time_function_decorator(const std::string& func_name, Func&& func, Args&&... args) {
auto start = std::chrono::steady_clock::now();
if constexpr (std::is_void_v<std::invoke_result_t<Func, Args...>>) {
// Void return type
std::invoke(std::forward<Func>(func), std::forward<Args>(args)...);
auto end = std::chrono::steady_clock::now();
auto elapsed = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
FunctionTimer::recordTiming(func_name, elapsed.count() / 1000000.0);
} else {
// Non-void return type
auto result = std::invoke(std::forward<Func>(func), std::forward<Args>(args)...);
auto end = std::chrono::steady_clock::now();
auto elapsed = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
FunctionTimer::recordTiming(func_name, elapsed.count() / 1000000.0);
return result;
}
}
// Macro to create decorated functions
#define DECORATE_FUNCTION(func) [&](auto&&... args) { \
return time_function_decorator(#func, func, std::forward<decltype(args)>(args)...); \
}