blob: c0d27e4cd568fbddaca2600764e01733d01620bc [file] [log] [blame]
Jens Axboe02bcaa82006-11-24 10:42:00 +01001/*
Jens Axboef5cc0242006-11-24 10:47:40 +01002 * Clock functions
Jens Axboe02bcaa82006-11-24 10:42:00 +01003 */
Jens Axboef5cc0242006-11-24 10:47:40 +01004
Jens Axboe02bcaa82006-11-24 10:42:00 +01005#include <unistd.h>
6#include <sys/time.h>
7
8#include "fio.h"
Jens Axboebe4ecfd2008-12-08 14:10:52 +01009#include "smalloc.h"
Jens Axboe02bcaa82006-11-24 10:42:00 +010010
11#include "hash.h"
12
Jens Axboe5ec10ea2008-03-06 15:42:00 +010013static int clock_gettime_works;
Jens Axboe3e488922008-11-13 12:07:20 +010014static struct timeval last_tv;
15static int last_tv_valid;
Jens Axboe02bcaa82006-11-24 10:42:00 +010016
Jens Axboebe4ecfd2008-12-08 14:10:52 +010017static struct timeval *fio_tv;
18int fio_gtod_offload = 0;
19int fio_gtod_cpu = -1;
20
Jens Axboe02bcaa82006-11-24 10:42:00 +010021#ifdef FIO_DEBUG_TIME
22
23#define HASH_BITS 8
24#define HASH_SIZE (1 << HASH_BITS)
25
Jens Axboe01743ee2008-06-02 12:19:19 +020026static struct flist_head hash[HASH_SIZE];
Jens Axboe02bcaa82006-11-24 10:42:00 +010027static int gtod_inited;
28
29struct gtod_log {
Jens Axboe01743ee2008-06-02 12:19:19 +020030 struct flist_head list;
Jens Axboe02bcaa82006-11-24 10:42:00 +010031 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);
Jens Axboe01743ee2008-06-02 12:19:19 +020038 struct flist_head *entry;
Jens Axboe02bcaa82006-11-24 10:42:00 +010039
Jens Axboe01743ee2008-06-02 12:19:19 +020040 flist_for_each(entry, &hash[h]) {
41 struct gtod_log *log = flist_entry(entry, struct gtod_log,
42 list);
Jens Axboe02bcaa82006-11-24 10:42:00 +010043
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));
Jens Axboe01743ee2008-06-02 12:19:19 +020059 INIT_FLIST_HEAD(&log->list);
Jens Axboe02bcaa82006-11-24 10:42:00 +010060 log->caller = caller;
61 log->calls = 0;
62
63 h = hash_ptr(caller, HASH_BITS);
Jens Axboe01743ee2008-06-02 12:19:19 +020064 flist_add_tail(&log->list, &hash[h]);
Jens Axboe02bcaa82006-11-24 10:42:00 +010065 }
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++) {
Jens Axboe01743ee2008-06-02 12:19:19 +020085 struct flist_head *entry;
Jens Axboe02bcaa82006-11-24 10:42:00 +010086 struct gtod_log *log;
87
Jens Axboe01743ee2008-06-02 12:19:19 +020088 flist_for_each(entry, &hash[i]) {
89 log = flist_entry(entry, struct gtod_log, list);
Jens Axboe02bcaa82006-11-24 10:42:00 +010090
Jens Axboe5ec10ea2008-03-06 15:42:00 +010091 printf("function %p, calls %lu\n", log->caller,
92 log->calls);
Jens Axboe02bcaa82006-11-24 10:42:00 +010093 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++)
Jens Axboe01743ee2008-06-02 12:19:19 +0200105 INIT_FLIST_HEAD(&hash[i]);
Jens Axboe02bcaa82006-11-24 10:42:00 +0100106
107 gtod_inited = 1;
108}
109
110#endif /* FIO_DEBUG_TIME */
111
Jens Axboe1e97cce2006-12-05 11:44:16 +0100112#ifdef FIO_DEBUG_TIME
Jens Axboe02bcaa82006-11-24 10:42:00 +0100113void fio_gettime(struct timeval *tp, void *caller)
Jens Axboe1e97cce2006-12-05 11:44:16 +0100114#else
115void fio_gettime(struct timeval *tp, void fio_unused *caller)
116#endif
Jens Axboe02bcaa82006-11-24 10:42:00 +0100117{
118#ifdef FIO_DEBUG_TIME
119 if (!caller)
120 caller = __builtin_return_address(0);
121
122 gtod_log_caller(caller);
Jens Axboe02bcaa82006-11-24 10:42:00 +0100123#endif
Jens Axboebe4ecfd2008-12-08 14:10:52 +0100124 if (fio_tv) {
125 memcpy(tp, fio_tv, sizeof(*tp));
126 return;
127 } else if (!clock_gettime_works) {
Jens Axboe7e326f32007-01-13 15:17:22 +0100128gtod:
Jens Axboe02bcaa82006-11-24 10:42:00 +0100129 gettimeofday(tp, NULL);
Jens Axboe7e326f32007-01-13 15:17:22 +0100130 } else {
Jens Axboe02bcaa82006-11-24 10:42:00 +0100131 struct timespec ts;
132
Jens Axboed481e002009-12-04 09:56:32 +0100133 if (clock_gettime(CLOCK_REALTIME, &ts) < 0) {
Jens Axboe02bcaa82006-11-24 10:42:00 +0100134 clock_gettime_works = 0;
Jens Axboe7e326f32007-01-13 15:17:22 +0100135 goto gtod;
Jens Axboe02bcaa82006-11-24 10:42:00 +0100136 }
137
138 tp->tv_sec = ts.tv_sec;
139 tp->tv_usec = ts.tv_nsec / 1000;
140 }
Jens Axboe3e488922008-11-13 12:07:20 +0100141
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));
Jens Axboe02bcaa82006-11-24 10:42:00 +0100155}
Jens Axboebe4ecfd2008-12-08 14:10:52 +0100156
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}