Back to Index

Chronometer

Inherits from Task

Contents

The Chronometer class is a utility component in the task framework that provides precise time measurement capabilities. It extends the base Task class to integrate with the signal-slot system, allowing it to notify other components about timing events. The Chronometer provides a simple interface for measuring elapsed time between start and stop operations, making it ideal for performance profiling, operation timing, and benchmarking within the application.

Features

Class Interface

class Chronometer : public Task {
public:
    // Constructor
    Chronometer();

    // Start the timer
    void start();
    
    // Stop the timer and get elapsed time in milliseconds
    int64_t stop();

private:
    std::unique_ptr<std::chrono::system_clock::time_point> m_startTime;
};

Signals

Chronometer emits the following signals:

Signal Type Description Arguments
started Simple Emitted when the timer starts None
finished Simple Emitted when the timer stops None
timing Data Reports elapsed time on stop int64_t (elapsed time in ms)
error Data Reports errors during timing operations std::string (error message)

Usage Examples

Basic Timing Example

Simple Timing Operation
// Create the chronometer
auto timer = std::make_shared<Chronometer>();

// Connect to signals
timer->connectSimple("started", []() {
    std::cout << "Timer started" << std::endl;
});

timer->connectSimple("finished", []() {
    std::cout << "Timer stopped" << std::endl;
});

timer->connectData("timing", [](const ArgumentPack& args) {
    int64_t elapsedMs = args.get<int64_t>(0);
    std::cout << "Elapsed time: " << elapsedMs << " ms" << std::endl;
});

// Start the timer
timer->start();

// Perform the operation to be timed
std::this_thread::sleep_for(std::chrono::milliseconds(500));

// Stop the timer and get the elapsed time
int64_t elapsed = timer->stop();

// Use the elapsed time
if (elapsed > 1000) {
    std::cout << "Operation took more than 1 second!" << std::endl;
}

Benchmarking an Algorithm

Algorithm Performance Measurement
// Create algorithm and chronometer
auto algorithm = std::make_shared<MyAlgorithm>();
auto timer = std::make_shared<Chronometer>();

// Connect chronometer to log timing info
timer->connectData("timing", [](const ArgumentPack& args) {
    int64_t elapsedMs = args.get<int64_t>(0);
    std::cout << "Algorithm execution time: " << elapsedMs << " ms" << std::endl;
});

// Time the algorithm execution
timer->start();
algorithm->exec();
timer->stop();

Timing Multiple Operations

Multiple Timing Measurements
// Create the chronometer
auto timer = std::make_shared<Chronometer>();

// Function to time an operation
auto timeOperation = [&timer](const std::string& name, std::function<void()> operation) {
    std::cout << "Starting " << name << "..." << std::endl;
    timer->start();
    operation();
    int64_t elapsed = timer->stop();
    std::cout << name << " completed in " << elapsed << " ms" << std::endl;
    return elapsed;
};

// Time different operations
timeOperation("Data loading", []() {
    // Simulate data loading
    std::this_thread::sleep_for(std::chrono::milliseconds(300));
});

timeOperation("Calculations", []() {
    // Simulate calculations
    std::this_thread::sleep_for(std::chrono::milliseconds(700));
});

timeOperation("Rendering", []() {
    // Simulate rendering
    std::this_thread::sleep_for(std::chrono::milliseconds(500));
});

Timing Implementation

The Chronometer uses the C++ standard library's chrono facilities for high-precision timing:

Implementation Details
void Chronometer::start() {
    m_startTime = std::make_unique<std::chrono::system_clock::time_point>(
        std::chrono::system_clock::now());
    emit("started");
}

int64_t Chronometer::stop() {
    if (!m_startTime) {
        emitString("error", "Chronometer not started.");
        return 0;
    }

    auto now = std::chrono::system_clock::now();
    auto timeDiff = std::chrono::duration_cast<std::chrono::milliseconds>(
                        now - *m_startTime)
                        .count();

    // Create ArgumentPack with timing information
    ArgumentPack timingArgs;
    timingArgs.add<int64_t>(timeDiff);

    // Emit both signals
    emit("finished");
    emit("timing", timingArgs);

    m_startTime.reset();

    return timeDiff;
}

The implementation follows these steps:

  1. Timer Start: Creates a time point using std::chrono::system_clock::now()
  2. Timer Stop: Calculates duration between start and current time
  3. Duration Calculation: Converts duration to milliseconds using std::chrono::duration_cast
  4. Signal Emission: Emits signals to notify listeners of the timing result
  5. Resource Cleanup: Resets the start time pointer to prepare for next timing operation

Error Handling

The Chronometer includes basic error handling to prevent misuse:

Error Handling Example
// Create the chronometer
auto timer = std::make_shared<Chronometer>();

// Connect to error signal
timer->connectData("error", [](const ArgumentPack& args) {
    std::string errorMsg = args.get<std::string>(0);
    std::cerr << "Chronometer error: " << errorMsg << std::endl;
});

// Error: Stop without start
timer->stop();  // Will emit error: "Chronometer not started."

// Correct usage
timer->start();
// ... operations ...
timer->stop();  // Works correctly

Integration with Other Components

The Chronometer can be integrated with various components in the task framework:

With Algorithm

Time Algorithm Execution
// Time algorithm execution
void timeAlgorithm(std::shared_ptr<Algorithm> algorithm, const ArgumentPack& args) {
    auto timer = std::make_shared<Chronometer>();
    
    // Log the results
    auto logger = std::make_shared<Logger>("Performance");
    timer->connectData("timing", [logger](const ArgumentPack& args) {
        int64_t elapsedMs = args.get<int64_t>(0);
        ArgumentPack logArgs;
        logArgs.add<std::string>("Execution time: " + std::to_string(elapsedMs) + " ms");
        logger->log(logArgs);
    });
    
    // Start timing
    timer->start();
    
    // Run the algorithm
    algorithm->exec(args);
    
    // Stop timing
    timer->stop();
}

With ThreadPool

Time Parallel Task Execution
// Time thread pool execution
void benchmarkThreadPool(std::shared_ptr<ThreadPool> pool) {
    auto timer = std::make_shared<Chronometer>();
    
    // Connect to pool's finished signal to stop the timer
    pool->connectSimple("finished", [timer]() {
        timer->stop();
    });
    
    // Start timing and execute tasks
    timer->start();
    pool->exec();
    
    // Timer will be stopped automatically when pool emits 'finished'
}

Best Practices

Performance Considerations

Note: For extremely high-precision timing requirements (nanosecond level), you may need to use std::chrono::high_resolution_clock instead. The current implementation focuses on simplicity and compatibility for general application timing needs.

Implementation Details