Fix garbling of clat/slat logs if a shared log file is used
[fio.git] / gettime.c
CommitLineData
02bcaa8c 1/*
f5cc024a 2 * Clock functions
02bcaa8c 3 */
f5cc024a 4
02bcaa8c
JA
5#include <unistd.h>
6#include <sys/time.h>
7
8#include "fio.h"
be4ecfdf 9#include "smalloc.h"
02bcaa8c
JA
10
11#include "hash.h"
12
5ec10eaa 13static int clock_gettime_works;
3e488920
JA
14static struct timeval last_tv;
15static int last_tv_valid;
02bcaa8c 16
be4ecfdf
JA
17static struct timeval *fio_tv;
18int fio_gtod_offload = 0;
19int fio_gtod_cpu = -1;
20
02bcaa8c
JA
21#ifdef FIO_DEBUG_TIME
22
23#define HASH_BITS 8
24#define HASH_SIZE (1 << HASH_BITS)
25
01743ee1 26static struct flist_head hash[HASH_SIZE];
02bcaa8c
JA
27static int gtod_inited;
28
29struct gtod_log {
01743ee1 30 struct flist_head list;
02bcaa8c
JA
31 void *caller;
32 unsigned long calls;
33};
34
35static struct gtod_log *find_hash(void *caller)
36{
37 unsigned long h = hash_ptr(caller, HASH_BITS);
01743ee1 38 struct flist_head *entry;
02bcaa8c 39
01743ee1
JA
40 flist_for_each(entry, &hash[h]) {
41 struct gtod_log *log = flist_entry(entry, struct gtod_log,
42 list);
02bcaa8c
JA
43
44 if (log->caller == caller)
45 return log;
46 }
47
48 return NULL;
49}
50
51static struct gtod_log *find_log(void *caller)
52{
53 struct gtod_log *log = find_hash(caller);
54
55 if (!log) {
56 unsigned long h;
57
58 log = malloc(sizeof(*log));
01743ee1 59 INIT_FLIST_HEAD(&log->list);
02bcaa8c
JA
60 log->caller = caller;
61 log->calls = 0;
62
63 h = hash_ptr(caller, HASH_BITS);
01743ee1 64 flist_add_tail(&log->list, &hash[h]);
02bcaa8c
JA
65 }
66
67 return log;
68}
69
70static void gtod_log_caller(void *caller)
71{
72 if (gtod_inited) {
73 struct gtod_log *log = find_log(caller);
74
75 log->calls++;
76 }
77}
78
79static void fio_exit fio_dump_gtod(void)
80{
81 unsigned long total_calls = 0;
82 int i;
83
84 for (i = 0; i < HASH_SIZE; i++) {
01743ee1 85 struct flist_head *entry;
02bcaa8c
JA
86 struct gtod_log *log;
87
01743ee1
JA
88 flist_for_each(entry, &hash[i]) {
89 log = flist_entry(entry, struct gtod_log, list);
02bcaa8c 90
5ec10eaa
JA
91 printf("function %p, calls %lu\n", log->caller,
92 log->calls);
02bcaa8c
JA
93 total_calls += log->calls;
94 }
95 }
96
97 printf("Total %lu gettimeofday\n", total_calls);
98}
99
100static void fio_init gtod_init(void)
101{
102 int i;
103
104 for (i = 0; i < HASH_SIZE; i++)
01743ee1 105 INIT_FLIST_HEAD(&hash[i]);
02bcaa8c
JA
106
107 gtod_inited = 1;
108}
109
110#endif /* FIO_DEBUG_TIME */
111
1e97cce9 112#ifdef FIO_DEBUG_TIME
02bcaa8c 113void fio_gettime(struct timeval *tp, void *caller)
1e97cce9
JA
114#else
115void fio_gettime(struct timeval *tp, void fio_unused *caller)
116#endif
02bcaa8c
JA
117{
118#ifdef FIO_DEBUG_TIME
119 if (!caller)
120 caller = __builtin_return_address(0);
121
122 gtod_log_caller(caller);
02bcaa8c 123#endif
be4ecfdf
JA
124 if (fio_tv) {
125 memcpy(tp, fio_tv, sizeof(*tp));
126 return;
127 } else if (!clock_gettime_works) {
7e326f3b 128gtod:
02bcaa8c 129 gettimeofday(tp, NULL);
7e326f3b 130 } else {
02bcaa8c
JA
131 struct timespec ts;
132
133 if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0) {
134 clock_gettime_works = 0;
7e326f3b 135 goto gtod;
02bcaa8c
JA
136 }
137
138 tp->tv_sec = ts.tv_sec;
139 tp->tv_usec = ts.tv_nsec / 1000;
140 }
3e488920
JA
141
142 /*
143 * If Linux is using the tsc clock on non-synced processors,
144 * sometimes time can appear to drift backwards. Fix that up.
145 */
146 if (last_tv_valid) {
147 if (tp->tv_sec < last_tv.tv_sec)
148 tp->tv_sec = last_tv.tv_sec;
149 else if (last_tv.tv_sec == tp->tv_sec &&
150 tp->tv_usec < last_tv.tv_usec)
151 tp->tv_usec = last_tv.tv_usec;
152 }
153 last_tv_valid = 1;
154 memcpy(&last_tv, tp, sizeof(*tp));
02bcaa8c 155}
be4ecfdf
JA
156
157void fio_gtod_init(void)
158{
159 fio_tv = smalloc(sizeof(struct timeval));
160 assert(fio_tv);
161}
162
163void fio_gtod_update(void)
164{
165 gettimeofday(fio_tv, NULL);
166}