aboutsummaryrefslogtreecommitdiff
path: root/externals/g3dlite/G3D.lib/source/Stopwatch.cpp
blob: e55f689a9e2444c028b77d13c49a84c47610464d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
/**
 @file Stopwatch.cpp
 
 @maintainer Morgan McGuire, matrix@graphics3d.com
  
 @created 2005-10-05
 @edited  2005-10-05

 Copyright 2000-2003, Morgan McGuire.
 All rights reserved.
 */

#include "G3D/Stopwatch.h"
#include "G3D/System.h"

namespace G3D {

Stopwatch::Stopwatch() : inBetween(false), lastTockTime(-1), 
    lastDuration(0), lastCycleCount(0), m_fps(0), emwaFPS(0),
    m_smoothFPS(0), emwaDuration(0) {
    computeOverhead();
}


void Stopwatch::computeOverhead() {
    cycleOverhead = 0;
    tick();
    tock();
    cycleOverhead = elapsedCycles();
}


void Stopwatch::tick() {
    // This is 'alwaysAssert' instead of 'debugAssert'
    // since people rarely profile in debug mode.
    alwaysAssertM(! inBetween, "Stopwatch::tick() called twice in a row.");
    inBetween = true;

    // We read RDTSC twice here, but it is more abstract to implement this
    // way and at least we're reading the cycle count last.
    timeStart = System::time();
    System::beginCycleCount(cycleStart);
}


void Stopwatch::tock() {
    System::endCycleCount(cycleStart);
    RealTime now = System::time();
    lastDuration = now - timeStart;
    if (abs(emwaDuration - lastDuration) > max(emwaDuration, lastDuration) * 0.50) {
        // Off by more than 50%
        emwaDuration = lastDuration;
    } else {
        emwaDuration = lastDuration * 0.05 + emwaDuration * 0.95;
    }

    lastCycleCount = cycleStart - cycleOverhead;
    if (lastCycleCount < 0) {
        lastCycleCount = 0;
    }

    if (lastTockTime != -1.0) {
        m_fps = 1.0 / (now - lastTockTime);

        // Time smooth the average
        emwaFPS = m_fps * 0.01 + emwaFPS * 0.99;

        if (abs(emwaFPS - m_fps) > max(emwaFPS, m_fps) * 0.08) {
            // The difference between emwa and m_fps is way off
            // update emwa directly.
            emwaFPS = m_fps;
        }
        
        // Update m_smoothFPS only when the value varies significantly
        // We round so as to not mislead the user as to the accuracy of 
        // the number.
        if (m_smoothFPS == 0) {
            m_smoothFPS = m_fps;
        } else if (emwaFPS <= 10) {
            if (::fabs(m_smoothFPS - emwaFPS) > .75) {
                m_smoothFPS = floor(emwaFPS * 10.0 + 0.5) / 10.0;
            }
        } else {
            if (::fabs(m_smoothFPS - emwaFPS) > 1.25) {
                m_smoothFPS = floor(emwaFPS + 0.5);
            }
        }
    }
    lastTockTime = now;

    alwaysAssertM(inBetween, "Stopwatch::tock() called without matching tick.");
    inBetween = false;
}

}