Files
SweepStore/cpp/src/Public/sweepstore/utils/timing.h

214 lines
7.1 KiB
C++

#ifndef SWEEPSTORE_TIMING_H
#define SWEEPSTORE_TIMING_H
/**
* @file timing.h
* @brief Hierarchical scope timing system for SweepStore
*
* Provides microsecond-precision performance profiling for arbitrary scopes
* (functions, loops, code blocks) with automatic parent/child relationship
* tracking. Outputs console statistics, CSV data, and Chrome Tracing JSON.
*
* Usage:
* #include "sweepstore/utils/timing.h"
*
* void myFunction() {
* SWEEPSTORE_TIME_FUNCTION(); // Times entire function
*
* {
* SWEEPSTORE_TIME_SCOPE("init"); // Times specific block
* // initialization code...
* }
*
* for (int i = 0; i < n; i++) {
* SWEEPSTORE_TIME_SCOPE("loop_iteration"); // Times each iteration
* // loop body...
* }
* }
*
* Build with timing enabled:
* cmake -DENABLE_TIMING=ON -B build
* cmake --build build
*
* View results:
* 1. Console statistics (automatic at program exit)
* 2. sweepstore_timing.csv (flat aggregated data)
* 3. sweepstore_trace.json (Chrome Tracing format: chrome://tracing)
*
* Performance:
* - Enabled: ~150-300ns overhead per instrumented scope
* - Disabled: Zero overhead (macros compile to nothing)
*
* Thread Safety:
* - Completely lock-free during hot paths
* - Thread-local storage eliminates contention
* - Each thread maintains independent timing tree
*/
#include <cstdint>
#include <string>
#include <chrono>
#include <thread>
/**
* @brief Aggregated timing statistics for a scope
*
* Stores cumulative statistics across all invocations of a scope.
*/
struct ScopeTimingStats {
uint64_t callCount = 0; ///< Total number of scope invocations
uint64_t totalMicros = 0; ///< Cumulative execution time in microseconds
uint64_t minMicros = UINT64_MAX; ///< Fastest single execution in microseconds
uint64_t maxMicros = 0; ///< Slowest single execution in microseconds
};
/**
* @brief Single timing event for Chrome Tracing format
*
* Represents one execution of a scope. Chrome Tracing viewer automatically
* builds hierarchical trees from timestamp overlaps.
*/
struct TimingTraceEvent {
std::string name; ///< Scope name (function name or custom label)
uint64_t startMicros; ///< Absolute timestamp in microseconds since epoch
uint64_t durationMicros; ///< Duration in microseconds
uint64_t threadId; ///< Thread ID (unique per thread)
uint64_t parentEventId; ///< Parent event ID (0 if root scope)
uint64_t eventId; ///< Unique ID for this event
};
/**
* @brief Internal timing functions (do not call directly)
*
* These functions are called automatically by the RAII timer class.
* Use SWEEPSTORE_TIME_FUNCTION() or SWEEPSTORE_TIME_SCOPE() instead.
*/
namespace SweepstoreTiming {
void recordScopeStart(const char* name, uint64_t eventId);
void recordScopeEnd(const char* name, uint64_t eventId, uint64_t startMicros, uint64_t durationMicros, uint64_t threadId);
uint64_t getCurrentEventId();
uint64_t getNextEventId();
uint64_t getParentEventId();
uint64_t getThreadId(); // Get unique sequential thread ID
void initOutputFile(); // Call once at program start
void flushThreadData(); // Call before thread exits to save timing data
void finalizeOutputFile(); // Call once at program end
}
/**
* @brief RAII timer for automatic scope timing
*
* This class implements RAII (Resource Acquisition Is Initialization) pattern
* for timing. Timer starts in constructor, stops in destructor. Automatically
* tracks parent/child relationships via thread-local scope stack.
*
* DO NOT instantiate directly - use the macros instead:
* - SWEEPSTORE_TIME_FUNCTION() for functions
* - SWEEPSTORE_TIME_SCOPE(name) for arbitrary scopes
*
* Thread Safety:
* - Thread-local storage ensures zero contention
* - Each thread maintains independent scope stack
* - Safe for concurrent use across multiple threads
*
* Performance:
* - Constructor: ~5ns
* - Destructor: ~150-300ns (includes stats update and trace event recording)
*/
class SweepstoreScopeTimer {
private:
const char* scopeName;
std::chrono::high_resolution_clock::time_point startTime;
uint64_t myEventId;
uint64_t parentEventId;
public:
explicit SweepstoreScopeTimer(const char* name)
: scopeName(name)
, startTime(std::chrono::high_resolution_clock::now())
, myEventId(SweepstoreTiming::getNextEventId())
, parentEventId(SweepstoreTiming::getParentEventId())
{
SweepstoreTiming::recordScopeStart(scopeName, myEventId);
}
~SweepstoreScopeTimer() {
auto endTime = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::microseconds>(endTime - startTime);
auto startMicros = std::chrono::duration_cast<std::chrono::microseconds>(
startTime.time_since_epoch()
).count();
// Get thread ID (use sequential thread ID instead of hash)
uint64_t threadId = SweepstoreTiming::getThreadId();
SweepstoreTiming::recordScopeEnd(
scopeName,
myEventId,
startMicros,
duration.count(),
threadId
);
}
// Disable copy and move
SweepstoreScopeTimer(const SweepstoreScopeTimer&) = delete;
SweepstoreScopeTimer& operator=(const SweepstoreScopeTimer&) = delete;
SweepstoreScopeTimer(SweepstoreScopeTimer&&) = delete;
SweepstoreScopeTimer& operator=(SweepstoreScopeTimer&&) = delete;
};
/**
* @brief Timing instrumentation macros
*
* These macros provide a simple interface for instrumenting code with timing.
* They compile to nothing when SWEEPSTORE_ENABLE_TIMING is 0 (default).
*
* @def SWEEPSTORE_TIME_FUNCTION()
* Times the entire function. Uses __FUNCTION__ for scope name.
* Place at the start of the function body.
*
* Example:
* void myFunction() {
* SWEEPSTORE_TIME_FUNCTION();
* // function body...
* }
*
* @def SWEEPSTORE_TIME_SCOPE(name)
* Times an arbitrary scope with a custom name. Useful for:
* - Code blocks
* - Loop iterations
* - Lambda functions
* - Critical sections
* - Class methods (use "ClassName::methodName" as the name)
*
* Example:
* for (int i = 0; i < n; i++) {
* SWEEPSTORE_TIME_SCOPE("loop_iteration");
* // loop body...
* }
*
* void MyClass::myMethod() {
* SWEEPSTORE_TIME_SCOPE("MyClass::myMethod");
* // method body...
* }
*
* auto lambda = [&]() {
* SWEEPSTORE_TIME_SCOPE("lambda_processing");
* // lambda body...
* };
*/
#ifndef SWEEPSTORE_ENABLE_TIMING
#define SWEEPSTORE_ENABLE_TIMING 0
#endif
#if SWEEPSTORE_ENABLE_TIMING
#define SWEEPSTORE_TIME_FUNCTION() SweepstoreScopeTimer __sweepstore_timer_##__LINE__(__FUNCTION__)
#define SWEEPSTORE_TIME_SCOPE(name) SweepstoreScopeTimer __sweepstore_timer_##__LINE__(name)
#else
#define SWEEPSTORE_TIME_FUNCTION() ((void)0)
#define SWEEPSTORE_TIME_SCOPE(name) ((void)0)
#endif
#endif // SWEEPSTORE_TIMING_H