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
13bool CycleTimer::GetThreadCyclesS(unsigned __int64* cycles)
14{
15 BOOL res = FALSE;
16 res = QueryThreadCycleTime(GetCurrentThread(), cycles);
17 return res != FALSE;
18}
19
20static const int SampleLoopSize = 1000000;
21
22// static
23double 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
54unsigned __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
71void 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
86