//-----------------------------------------------------------------------------
// NastBenchmark.cpp
//-----------------------------------------------------------------------------

#include "NastBenchmark.h"
#include "NastDebug.h"

#include <string.h>
#include <signal.h>		// Workaround fuer einen Bug in HP-Includefiles
#include <time.h>		// CLOCKS_PER_SEC

#ifdef _MSC_VER
#include <sys/timeb.h>
#else
#include <sys/times.h>			// times
#include <sys/time.h>			// gettimeofday
#endif

//-----------------------------------------------------------------------------
//                    Konstruktor + Destruktor
//-----------------------------------------------------------------------------


//  Defaultconstr.
CNastBenchmark::CNastBenchmark()
   :m_stampUser  ( 0.0 ),
    m_stampSystem( 0.0 ),
    m_stampReal  ( 0.0 ),
    m_sumUser    ( 0.0 ),
    m_sumSystem  ( 0.0 ),
    m_sumReal    ( 0.0 ),
    m_bIsActive  (false)
{}

//  Destruktor
CNastBenchmark::~CNastBenchmark()
{}

// ----------------------------------------------------------------------------
//                             Memberfunktionen
// ----------------------------------------------------------------------------

void 
CNastBenchmark::start()
{
    NAST_ASSERT_VALID( this );

#ifndef _MSC_VER
    struct tms tm;
    timeval tv;

    // Achtung ! fuer die Bestimmung der echten Zeit kann nicht clocks()
    // verwendet werden, da dort nur die Summme von User- und Systemzeit
    // steht.

    gettimeofday( &tv, DST_NONE );// nach SVr4 BSD 4.3
    times( &tm );		  // nach Posix

    //  die aktuellen Werte merken
    m_stampUser   = tm.tms_utime;
    m_stampSystem = tm.tms_stime;
    m_stampReal   = tv.tv_sec + tv.tv_usec /1000000.0;
#else
    // QueryPerformanceCounter
    clock_t time_clock = clock(); 
    struct _timeb timebuffer;
    _ftime( &timebuffer );

    //  die aktuellen Werte merken
    m_stampUser     = time_clock;
    m_stampSystem   = 0;
    m_stampReal     = timebuffer.time + timebuffer.millitm / 1000;
#endif

    NAST_ASSERT_WARNING( !m_bIsActive, "Benchmark mehrmals gestartet" );
    m_bIsActive = true;
}


void 
CNastBenchmark::stop()
{
    NAST_ASSERT_VALID( this );

#ifndef _MSC_VER
    struct tms tm;
    timeval tv;

    gettimeofday(&tv, DST_NONE);// nach SVr4 BSD 4.3
    times(&tm);			// nach Posix

    // Aenderungen seit dem letzten Start addieren
    m_sumUser     += tm.tms_utime  - m_stampUser;    
    m_sumSystem   += tm.tms_stime  - m_stampSystem;
    m_sumReal     += tv.tv_sec + tv.tv_usec / 1000000.0 - m_stampReal;
#else
    clock_t time_clock = clock(); 
    struct _timeb timebuffer;
    _ftime( &timebuffer );

    //  die aktuellen Werte merken
    m_sumUser     += time_clock - m_stampUser;
    m_sumSystem   += 0.0;
    m_sumReal     += timebuffer.time + timebuffer.millitm / 10000.0 - m_stampReal;

//    NAST_DUMP_VARIABLE( m_stampUser );
//    NAST_DUMP_VARIABLE( m_stampSystem );
//    NAST_DUMP_VARIABLE( m_stampReal   );
#endif
    //  und wieder zuruecksetzen
    m_stampUser    = 0;
    m_stampSystem  = 0;
    m_stampReal    = 0;

    NAST_ASSERT_WARNING( m_bIsActive, "Benchmark mehrmals angehalten oder noch nicht gestartet" );
    m_bIsActive = false;
}

void 
CNastBenchmark::reset()
{
    NAST_ASSERT_VALID( this );

    // alle Summen zuruecksetzen
    m_sumUser     = 0.0;
    m_sumSystem   = 0.0;
    m_sumReal     = 0.0;

    // alle Summen zuruecksetzen
    m_stampUser    = 0.0;
    m_stampSystem  = 0.0;
    m_stampReal    = 0.0;

    NAST_ASSERT_WARNING( !m_bIsActive, "Benchmark zurueckgesetzt obwohl der gerade laeuft" );
}

double 
CNastBenchmark::timeUser() const
{
    NAST_ASSERT_VALID( this );
    return m_sumUser / (double)(CLOCKS_PER_SEC);
}

double 
CNastBenchmark::timeSystem() const
{
    NAST_ASSERT_VALID( this );
    return m_sumSystem / (double)(CLOCKS_PER_SEC);
}

double 
CNastBenchmark::timeReal() const
{
    NAST_ASSERT_VALID( this );
    return m_sumReal;
}


// ----------------------------------------------------------------------------
//                                    Debug
// ----------------------------------------------------------------------------

void 
CNastBenchmark::debugDump( CNastDumpContext &dumpContext ) const
{
    CNastObject::debugDump( dumpContext );

    dumpContext << "\t" << "CNastBenchmark \n";
    dumpContext << "\t" << "m_bIsActive          = " << m_bIsActive        << "\n";

    dumpContext << "\t" << "m_stampUser     = " << m_stampUser   << "\n";
    dumpContext << "\t" << "m_stampSystem   = " << m_stampSystem << "\n";
    dumpContext << "\t" << "m_stampReal     = " << m_stampReal   << "\n";

    dumpContext << "\t" << "m_sumUser   = " << m_sumUser   << "\n";
    dumpContext << "\t" << "m_sumSystem = " << m_sumSystem << "\n";
    dumpContext << "\t" << "m_sumReal   = " << m_sumReal   << "\n";
}

void 
CNastBenchmark::assertValid() const
{
    CNastObject::assertValid(); 
}


