xref: /reactos/sdk/lib/ucrt/time/clock.cpp (revision a6a07059)
1 //
2 // clock.cpp
3 //
4 //      Copyright (c) Microsoft Corporation. All rights reserved.
5 //
6 // The clock() function, which calculates the amount of elapsed time since the
7 // process started execution.
8 //
9 #include <corecrt_internal_time.h>
10 #include <sys/timeb.h>
11 #include <sys/types.h>
12 
13 
14 
15 // The source frequency of the performance counter and the counter value at
16 // process startup, in the source frequency.
17 static long long source_frequency;
18 static long long start_count;
19 
20 
21 
22 // Scales a 64-bit counter from the QueryPerformanceCounter frequency to the
23 // clock() frequency defined by CLOCKS_PER_SEC.  This is the same algorithm as
24 // is used internally by QueryPerformanceCounter to deal with frequency changes.
25 static long long scale_count(long long count)
26 {
27     // Convert the count to seconds and multiply this by the destination frequency:
28     long long scaled_count = (count / source_frequency) * CLOCKS_PER_SEC;
29 
30     // To reduce error introduced by scaling using integer division, separately
31     // handle the remainder from the above division by multiplying the left-over
32     // counter by the destination frequency, then diviting by the input frequency:
33     count %= source_frequency;
34 
35     scaled_count += (count * CLOCKS_PER_SEC) / source_frequency;
36 
37     return scaled_count;
38 }
39 
40 
41 
42 // This function initializes the global start_count variable when the CRT is
43 // initialized.  This initializer always runs in the CRT DLL; it only runs in
44 // the static CRT if this object file is linked into the module, which will only
45 // happen if some user code calls clock().
46 extern "C" int __cdecl __acrt_initialize_clock()
47 {
48     LARGE_INTEGER local_frequency;
49     LARGE_INTEGER local_start_count;
50     if (!QueryPerformanceFrequency(&local_frequency) ||
51         !QueryPerformanceCounter(&local_start_count) ||
52         local_frequency.QuadPart == 0)
53     {
54         source_frequency = -1;
55         start_count      = -1;
56         return 0;
57     }
58 
59     source_frequency = local_frequency.QuadPart;
60     start_count      = local_start_count.QuadPart;
61 
62     return 0;
63 }
64 
65 _CRT_LINKER_FORCE_INCLUDE(__acrt_clock_initializer);
66 
67 // Calculates and returns the amount of elapsed time since the process started
68 // execution.  During CRT initialization, the 'start_count' global variable is
69 // initialized to the current tick count; subsequent calls to clock() get the
70 // new tick count and subtract the 'start_count' from it.
71 //
72 // The return value is the number of CLK_TCKs that have elapsed (milliseconds).
73 // On failure, -1 is returned.
74 extern "C" clock_t __cdecl clock()
75 {
76     if (start_count == -1)
77         return -1;
78 
79     LARGE_INTEGER current_count;
80     if (!QueryPerformanceCounter(&current_count))
81         return -1;
82 
83     long long const result = current_count.QuadPart - start_count;
84     if (result < 0)
85         return -1;
86 
87     long long const scaled_result = scale_count(result);
88 
89     // Per C11 7.27.2.1 ("The clock function")/3, "If the processor time used...
90     // cannot be represented, the function returns the value (clock_t)(-1)."
91     if (scaled_result > LONG_MAX)
92         return -1;
93 
94     return static_cast<clock_t>(scaled_result);
95 }
96