blob: 80eeaf14bcbb75293a1621382eaa8d765fe2d015 [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 Axboe02bcaa82006-11-24 10:42:00 +01009
10#include "hash.h"
11
Jens Axboe5ec10ea2008-03-06 15:42:00 +010012static int clock_gettime_works;
Jens Axboe3e488922008-11-13 12:07:20 +010013static struct timeval last_tv;
14static int last_tv_valid;
Jens Axboe02bcaa82006-11-24 10:42:00 +010015
16#ifdef FIO_DEBUG_TIME
17
18#define HASH_BITS 8
19#define HASH_SIZE (1 << HASH_BITS)
20
Jens Axboe01743ee2008-06-02 12:19:19 +020021static struct flist_head hash[HASH_SIZE];
Jens Axboe02bcaa82006-11-24 10:42:00 +010022static int gtod_inited;
23
24struct gtod_log {
Jens Axboe01743ee2008-06-02 12:19:19 +020025 struct flist_head list;
Jens Axboe02bcaa82006-11-24 10:42:00 +010026 void *caller;
27 unsigned long calls;
28};
29
30static struct gtod_log *find_hash(void *caller)
31{
32 unsigned long h = hash_ptr(caller, HASH_BITS);
Jens Axboe01743ee2008-06-02 12:19:19 +020033 struct flist_head *entry;
Jens Axboe02bcaa82006-11-24 10:42:00 +010034
Jens Axboe01743ee2008-06-02 12:19:19 +020035 flist_for_each(entry, &hash[h]) {
36 struct gtod_log *log = flist_entry(entry, struct gtod_log,
37 list);
Jens Axboe02bcaa82006-11-24 10:42:00 +010038
39 if (log->caller == caller)
40 return log;
41 }
42
43 return NULL;
44}
45
46static struct gtod_log *find_log(void *caller)
47{
48 struct gtod_log *log = find_hash(caller);
49
50 if (!log) {
51 unsigned long h;
52
53 log = malloc(sizeof(*log));
Jens Axboe01743ee2008-06-02 12:19:19 +020054 INIT_FLIST_HEAD(&log->list);
Jens Axboe02bcaa82006-11-24 10:42:00 +010055 log->caller = caller;
56 log->calls = 0;
57
58 h = hash_ptr(caller, HASH_BITS);
Jens Axboe01743ee2008-06-02 12:19:19 +020059 flist_add_tail(&log->list, &hash[h]);
Jens Axboe02bcaa82006-11-24 10:42:00 +010060 }
61
62 return log;
63}
64
65static void gtod_log_caller(void *caller)
66{
67 if (gtod_inited) {
68 struct gtod_log *log = find_log(caller);
69
70 log->calls++;
71 }
72}
73
74static void fio_exit fio_dump_gtod(void)
75{
76 unsigned long total_calls = 0;
77 int i;
78
79 for (i = 0; i < HASH_SIZE; i++) {
Jens Axboe01743ee2008-06-02 12:19:19 +020080 struct flist_head *entry;
Jens Axboe02bcaa82006-11-24 10:42:00 +010081 struct gtod_log *log;
82
Jens Axboe01743ee2008-06-02 12:19:19 +020083 flist_for_each(entry, &hash[i]) {
84 log = flist_entry(entry, struct gtod_log, list);
Jens Axboe02bcaa82006-11-24 10:42:00 +010085
Jens Axboe5ec10ea2008-03-06 15:42:00 +010086 printf("function %p, calls %lu\n", log->caller,
87 log->calls);
Jens Axboe02bcaa82006-11-24 10:42:00 +010088 total_calls += log->calls;
89 }
90 }
91
92 printf("Total %lu gettimeofday\n", total_calls);
93}
94
95static void fio_init gtod_init(void)
96{
97 int i;
98
99 for (i = 0; i < HASH_SIZE; i++)
Jens Axboe01743ee2008-06-02 12:19:19 +0200100 INIT_FLIST_HEAD(&hash[i]);
Jens Axboe02bcaa82006-11-24 10:42:00 +0100101
102 gtod_inited = 1;
103}
104
105#endif /* FIO_DEBUG_TIME */
106
Jens Axboe1e97cce2006-12-05 11:44:16 +0100107#ifdef FIO_DEBUG_TIME
Jens Axboe02bcaa82006-11-24 10:42:00 +0100108void fio_gettime(struct timeval *tp, void *caller)
Jens Axboe1e97cce2006-12-05 11:44:16 +0100109#else
110void fio_gettime(struct timeval *tp, void fio_unused *caller)
111#endif
Jens Axboe02bcaa82006-11-24 10:42:00 +0100112{
113#ifdef FIO_DEBUG_TIME
114 if (!caller)
115 caller = __builtin_return_address(0);
116
117 gtod_log_caller(caller);
Jens Axboe02bcaa82006-11-24 10:42:00 +0100118#endif
Jens Axboe7e326f32007-01-13 15:17:22 +0100119 if (!clock_gettime_works) {
120gtod:
Jens Axboe02bcaa82006-11-24 10:42:00 +0100121 gettimeofday(tp, NULL);
Jens Axboe7e326f32007-01-13 15:17:22 +0100122 } else {
Jens Axboe02bcaa82006-11-24 10:42:00 +0100123 struct timespec ts;
124
125 if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0) {
126 clock_gettime_works = 0;
Jens Axboe7e326f32007-01-13 15:17:22 +0100127 goto gtod;
Jens Axboe02bcaa82006-11-24 10:42:00 +0100128 }
129
130 tp->tv_sec = ts.tv_sec;
131 tp->tv_usec = ts.tv_nsec / 1000;
132 }
Jens Axboe3e488922008-11-13 12:07:20 +0100133
134 /*
135 * If Linux is using the tsc clock on non-synced processors,
136 * sometimes time can appear to drift backwards. Fix that up.
137 */
138 if (last_tv_valid) {
139 if (tp->tv_sec < last_tv.tv_sec)
140 tp->tv_sec = last_tv.tv_sec;
141 else if (last_tv.tv_sec == tp->tv_sec &&
142 tp->tv_usec < last_tv.tv_usec)
143 tp->tv_usec = last_tv.tv_usec;
144 }
145 last_tv_valid = 1;
146 memcpy(&last_tv, tp, sizeof(*tp));
Jens Axboe02bcaa82006-11-24 10:42:00 +0100147}