Make log writing append
[fio.git] / gettime.c
1 /*
2  * Clock functions
3  */
4
5 #include <unistd.h>
6 #include <sys/time.h>
7
8 #include "fio.h"
9
10 #include "hash.h"
11
12 static int clock_gettime_works;
13 static struct timeval last_tv;
14 static int last_tv_valid;
15
16 #ifdef FIO_DEBUG_TIME
17
18 #define HASH_BITS       8
19 #define HASH_SIZE       (1 << HASH_BITS)
20
21 static struct flist_head hash[HASH_SIZE];
22 static int gtod_inited;
23
24 struct gtod_log {
25         struct flist_head list;
26         void *caller;
27         unsigned long calls;
28 };
29
30 static struct gtod_log *find_hash(void *caller)
31 {
32         unsigned long h = hash_ptr(caller, HASH_BITS);
33         struct flist_head *entry;
34
35         flist_for_each(entry, &hash[h]) {
36                 struct gtod_log *log = flist_entry(entry, struct gtod_log,
37                                                                         list);
38
39                 if (log->caller == caller)
40                         return log;
41         }
42
43         return NULL;
44 }
45
46 static 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));
54                 INIT_FLIST_HEAD(&log->list);
55                 log->caller = caller;
56                 log->calls = 0;
57
58                 h = hash_ptr(caller, HASH_BITS);
59                 flist_add_tail(&log->list, &hash[h]);
60         }
61
62         return log;
63 }
64
65 static 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
74 static 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++) {
80                 struct flist_head *entry;
81                 struct gtod_log *log;
82
83                 flist_for_each(entry, &hash[i]) {
84                         log = flist_entry(entry, struct gtod_log, list);
85
86                         printf("function %p, calls %lu\n", log->caller,
87                                                                 log->calls);
88                         total_calls += log->calls;
89                 }
90         }
91
92         printf("Total %lu gettimeofday\n", total_calls);
93 }
94
95 static void fio_init gtod_init(void)
96 {
97         int i;
98
99         for (i = 0; i < HASH_SIZE; i++)
100                 INIT_FLIST_HEAD(&hash[i]);
101
102         gtod_inited = 1;
103 }
104
105 #endif /* FIO_DEBUG_TIME */
106
107 #ifdef FIO_DEBUG_TIME
108 void fio_gettime(struct timeval *tp, void *caller)
109 #else
110 void fio_gettime(struct timeval *tp, void fio_unused *caller)
111 #endif
112 {
113 #ifdef FIO_DEBUG_TIME
114         if (!caller)
115                 caller = __builtin_return_address(0);
116
117         gtod_log_caller(caller);
118 #endif
119         if (!clock_gettime_works) {
120 gtod:
121                 gettimeofday(tp, NULL);
122         } else {
123                 struct timespec ts;
124
125                 if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0) {
126                         clock_gettime_works = 0;
127                         goto gtod;
128                 }
129
130                 tp->tv_sec = ts.tv_sec;
131                 tp->tv_usec = ts.tv_nsec / 1000;
132         }
133
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));
147 }