[Tizen] Unify dnetmemoryenumlib terms to match the codebase (#291)
[platform/upstream/coreclr.git] / src / utilcode / cycletimer.cpp
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4
5 #include "stdafx.h"
6
7 #include "cycletimer.h"
8 #include "winbase.h"
9 #include "winwrap.h"
10 #include "assert.h"
11 #include "utilcode.h"
12
13 bool CycleTimer::GetThreadCyclesS(unsigned __int64* cycles)
14 {
15     BOOL res = FALSE;
16     res = QueryThreadCycleTime(GetCurrentThread(), cycles);
17     return res != FALSE;
18 }
19
20 static const int SampleLoopSize = 1000000;
21
22 // static
23 double CycleTimer::CyclesPerSecond()
24 {
25     // Windows does not provide a way of converting cycles to time -- reasonably enough,
26     // since the frequency of a machine may vary, due, e.g., to power management.
27     // Windows *does* allow you to translate QueryPerformanceCounter counts into time,
28     // however.  So we'll assume that the clock speed stayed constant, and measure both the
29     // QPC counts and cycles of a short loop, to get a conversion factor.
30     LARGE_INTEGER lpFrequency;
31     if (!QueryPerformanceFrequency(&lpFrequency)) return 0.0;
32     // Otherwise...
33     LARGE_INTEGER qpcStart;
34     unsigned __int64 cycleStart;
35     if (!QueryPerformanceCounter(&qpcStart)) return 0.0;
36     if (!GetThreadCyclesS(&cycleStart)) return 0.0;
37     volatile int sum = 0;
38     for (int k = 0; k < SampleLoopSize; k++)
39     {
40         sum += k;
41     }
42     LARGE_INTEGER qpcEnd;
43     if (!QueryPerformanceCounter(&qpcEnd)) return 0.0;
44     unsigned __int64 cycleEnd;
45     if (!GetThreadCyclesS(&cycleEnd)) return 0.0;
46
47     double qpcTicks = ((double)qpcEnd.QuadPart) - ((double)qpcStart.QuadPart);
48     double secs = (qpcTicks / ((double)lpFrequency.QuadPart));
49     double cycles = ((double)cycleEnd) - ((double)cycleStart);
50     return cycles / secs;
51 }
52
53 // static
54 unsigned __int64 CycleTimer::QueryOverhead()
55 {
56     unsigned __int64 tot = 0;
57     unsigned __int64 startCycles;
58     unsigned __int64 endCycles;
59     const int N = 1000;
60     bool b = GetThreadCyclesS(&startCycles); assert(b);
61     for (int i = 0; i < N; i++)
62     {
63         b = GetThreadCyclesS(&endCycles); assert(b);
64         tot += (endCycles-startCycles);
65         startCycles = endCycles;
66     }
67     return tot/N;
68 }
69
70 // static
71 void CycleTimer::InterlockedAddU64(unsigned __int64* loc, unsigned __int64 amount)
72 {
73     volatile __int64* vloc = (volatile __int64*)loc;
74     unsigned __int64 prev = *vloc;
75     for (;;)
76     {
77         unsigned __int64 next = prev + amount;
78         __int64 snext = (__int64)next;
79         __int64 sprev = (__int64)prev;
80         __int64 res = InterlockedCompareExchange64(vloc, snext, sprev);
81         if (res == sprev) return;
82         else prev = (unsigned __int64)res;
83     }
84 }
85