#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 #include #include #include /** * @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(endTime - startTime); auto startMicros = std::chrono::duration_cast( 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