-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathclock.c
More file actions
137 lines (113 loc) · 3.16 KB
/
clock.c
File metadata and controls
137 lines (113 loc) · 3.16 KB
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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
/* clock.c
* Retrofitted to use thread-specific timers
* and to get clock information from /proc/cpuinfo
* (C) R. E. Bryant, 2010
*
*/
/* When this constant is not defined, uses time stamp counter */
#define USE_POSIX 0
/* Choice to use cpu_gettime call or Intel time stamp counter directly */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef USE_POSIX
#include <time.h>
#endif
#include "clock.h"
int gverbose = 1;
/* Keep track of clock speed */
double cpu_ghz = 0.0;
/* Get megahertz from /etc/proc */
#define MAXBUF 512
double core_mhz(int verbose) {
static char buf[MAXBUF];
FILE *fp = fopen("/proc/cpuinfo", "r");
cpu_ghz = 0.0;
if (!fp) {
fprintf(stderr, "Can't open /proc/cpuinfo to get clock information\n");
cpu_ghz = 1.0;
return cpu_ghz * 1000.0;
}
while (fgets(buf, MAXBUF, fp)) {
if (strstr(buf, "cpu MHz")) {
double cpu_mhz = 0.0;
sscanf(buf, "cpu MHz\t: %lf", &cpu_mhz);
cpu_ghz = cpu_mhz / 1000.0;
break;
}
}
fclose(fp);
if (cpu_ghz == 0.0) {
fprintf(stderr, "Can't open /proc/cpuinfo to get clock information\n");
cpu_ghz = 1.0;
return cpu_ghz * 1000.0;
}
if (verbose) {
printf("Processor Clock Rate ~= %.4f GHz (extracted from file)\n", cpu_ghz);
}
return cpu_ghz * 1000;
}
double mhz(int verbose) {
double val = core_mhz(verbose);
return val;
}
#ifdef USE_POSIX
/* Simulate counters by using nanosecond timers and then converting to clock cycles */
struct timespec last_time;
/* Use thread clock */
#define CLKT CLOCK_THREAD_CPUTIME_ID
void start_counter()
{
if (cpu_ghz == 0.0)
mhz(gverbose);
if (clock_gettime(CLKT, &last_time) != 0) {
fprintf(stderr, "Couldn't get time\n");
exit(1);
}
}
double get_counter()
{
struct timespec new_time;
double delta_nsecs = 0.0;
if (clock_gettime(CLKT, &new_time) != 0) {
fprintf(stderr, "Couldn't get time\n");
exit(1);
}
delta_nsecs = 1e9 * (new_time.tv_sec - last_time.tv_sec) + (new_time.tv_nsec - last_time.tv_nsec);
return delta_nsecs * cpu_ghz;
}
#else /* !USE_POSIX */
/* Use x86 cycle counter */
/* Initialize the cycle counter */
static unsigned cyc_hi = 0;
static unsigned cyc_lo = 0;
/* Set *hi and *lo to the high and low order bits of the cycle counter.
Implementation requires assembly code to use the rdtsc instruction. */
void access_counter(unsigned *hi, unsigned *lo)
{
asm("rdtsc; movl %%edx,%0; movl %%eax,%1" /* Read cycle counter */
: "=r" (*hi), "=r" (*lo) /* and move results to */
: /* No input */ /* the two outputs */
: "%edx", "%eax");
}
/* Record the current value of the cycle counter. */
void start_counter()
{
access_counter(&cyc_hi, &cyc_lo);
}
/* Return the number of cycles since the last call to start_counter. */
double get_counter()
{
unsigned ncyc_hi, ncyc_lo;
unsigned hi, lo, borrow;
double result;
/* Get cycle counter */
access_counter(&ncyc_hi, &ncyc_lo);
/* Do double precision subtraction */
lo = ncyc_lo - cyc_lo;
borrow = cyc_lo > ncyc_lo;
hi = ncyc_hi - cyc_hi - borrow;
result = (double) hi * (1 << 30) * 4 + lo;
return result;
}
#endif /* USE_POSIX */