TestTimer.h

// TestTimer.h
//
// Author David Barrett-Lennard
// (C)opyright Cedanet Pty Ltd 2005

#pragma once
#ifndef Ceda_cxUtils_TestTimer_H
#define Ceda_cxUtils_TestTimer_H

#include "xstring.h"
#include "HPTime.h"
#include <functional>

namespace ceda
{
///////////////////////////////////////////////////////////////////////////////////////////////////
// TestTimer

struct ITestTimerInfo
{
    virtual void WriteInfo(xostream& os) = 0;
};

class cxUtils_API TestTimer
{
public:
    TestTimer(ITestTimerInfo& info, double timeForTestInSecs, double timeToPrintLine);

    bool Next();

    int GetCount() const { return m_count; }
    double GetElapsedTimeInSeconds() const { return m_timer.GetElapsedTimeInSeconds(); }

private:
    ITestTimerInfo& m_info;
    double m_timeForTestInSecs;
    double m_timeToPrintLine;

    int m_count;
    int m_numSecs;
    HPTimer m_timer;
};

///////////////////////////////////////////////////////////////////////////////////////////////////
// RateTimer

class cxUtils_API RateTimer
{
public:
    RateTimer(bool bytesPerSec = false, bool traceWhenDestruct = true);
    RateTimer(ConstStringZ description, double count, bool bytesPerSec = false, bool traceWhenDestruct = true);
    ~RateTimer();
    
    // Start timing from now (until it destructs)
    void Reset();
    
    void SetDescription(ConstStringZ description);

    void AddToCount(double count);
    void SetCount(double count) { m_count = count; }

    void BeginSkip() { m_timer.BeginSkip(); }
    void EndSkip() { m_timer.EndSkip(); }
    
    double GetElapsedTimeInSeconds() const
    {
        return m_timer.GetElapsedTimeInSeconds();
    }

    double GetCount() const { return m_count; } 
    
    double GetRate() const
    {
        return m_count / m_timer.GetElapsedTimeInSeconds();
    }

    void TraceRate(double rate) const;

    // Calculate and trace the rate.
    void TraceRate() const;
    
    bool UseBytesPerSec() const { return m_bytesPerSec; }

    const xstring& Description() const { return m_description; }

private:
    xstring m_description;
    double m_count;
    bool m_bytesPerSec;
    bool m_traceWhenDestruct;
    HPTimer m_timer;
};

///////////////////////////////////////////////////////////////////////////////////////////////////
// MaxRateTimer

enum ERateTimerTrace
{
    RT_TRACE_NONE,
    RT_TRACE_MAX,
    RT_TRACE_AVG,
    RT_TRACE_ALL
};

class cxUtils_API MaxRateTimer
{
public:
    explicit MaxRateTimer(bool bytesPerSec = false, ERateTimerTrace rtt = RT_TRACE_AVG) :
        m_traceWhenDestruct(false),
        m_timer(bytesPerSec,false),
        m_rtt(rtt),
        m_maxRate(0),
        m_sumRate(0),
        m_num(0)
    {
    }                
    MaxRateTimer(ConstStringZ description, double count, bool bytesPerSec = false, ERateTimerTrace rtt = RT_TRACE_AVG) :
        m_traceWhenDestruct(true),
        m_timer(description,count,bytesPerSec,false),
        m_rtt(rtt),
        m_maxRate(0),
        m_sumRate(0),
        m_num(0)
    {
    }
    ~MaxRateTimer();

    void SetDescription(ConstStringZ description)
    {
        m_traceWhenDestruct = true;
        m_timer.SetDescription(description);
    }
    
    double GetElapsedTimeInSeconds() const { return m_timer.GetElapsedTimeInSeconds(); }

    void BeginSkip() { m_timer.BeginSkip(); }
    void EndSkip() { m_timer.EndSkip(); }
    
    void Begin()
    {
        m_timer.Reset();
    }
    void AddToCount(double count) { m_timer.AddToCount(count); }
    void SetCount(double count) { m_timer.SetCount(count); }
    void End()
    {
        double r = m_timer.GetRate();
        if (m_rtt == RT_TRACE_ALL) m_timer.TraceRate(r);
        if (r > m_maxRate) m_maxRate = r;
        m_sumRate += r;
        ++m_num;
    }
    double GetMaxRate() const { return m_maxRate; }
    double GetAvgRate() const { return m_sumRate / m_num; }
    double GetCount() const { return m_timer.GetCount(); } 
    double GetNum() const { return m_num; }

private:
    bool m_traceWhenDestruct;
    RateTimer m_timer;
    ERateTimerTrace m_rtt;
    double m_maxRate;
    double m_sumRate;
    int m_num;
};

inline int CalculateTestCountFromRate(double timeForTestInSecs, double rate, int maxCount = 1000000)
{
    int n = maxCount;
    while(n/rate > timeForTestInSecs) n /= 10;
    if (n==0) n=1;
    return n;
}

inline void TimeCode(const char* description, double timeForTestInSecs, double rate, int maxCount, std::function<void(int n)> code)
{
    int n = CalculateTestCountFromRate(timeForTestInSecs, rate, maxCount);
    ceda::MaxRateTimer t(description,n);
    ceda::HPTimer timeTaken;
    while(timeTaken.GetElapsedTimeInSeconds() < timeForTestInSecs)
    {
        t.Begin();
        code(n);
        t.End();
    }
}

} // namespace ceda

#endif // include guard