Merge branch 'fixes_1290' of https://github.com/rthardin/fio
[fio.git] / gettime-thread.c
1 #include <sys/time.h>
2 #include <time.h>
3
4 #include "fio.h"
5 #include "lib/seqlock.h"
6 #include "smalloc.h"
7
8 struct fio_ts *fio_ts;
9 int fio_gtod_offload = 0;
10 static pthread_t gtod_thread;
11 static os_cpu_mask_t fio_gtod_cpumask;
12
13 void fio_gtod_init(void)
14 {
15         if (fio_ts)
16                 return;
17
18         fio_ts = smalloc(sizeof(*fio_ts));
19 }
20
21 static void fio_gtod_update(void)
22 {
23         struct timeval __tv;
24
25         if (!fio_ts)
26                 return;
27
28         gettimeofday(&__tv, NULL);
29
30         write_seqlock_begin(&fio_ts->seqlock);
31         fio_ts->ts.tv_sec = __tv.tv_sec;
32         fio_ts->ts.tv_nsec = __tv.tv_usec * 1000;
33         write_seqlock_end(&fio_ts->seqlock);
34 }
35
36 struct gtod_cpu_data {
37         struct fio_sem *sem;
38         unsigned int cpu;
39 };
40
41 static void *gtod_thread_main(void *data)
42 {
43         struct fio_sem *sem = data;
44         int ret;
45
46         ret = fio_setaffinity(gettid(), fio_gtod_cpumask);
47
48         fio_sem_up(sem);
49
50         if (ret == -1) {
51                 log_err("gtod: setaffinity failed\n");
52                 return NULL;
53         }
54
55         /*
56          * As long as we have jobs around, update the clock. It would be nice
57          * to have some way of NOT hammering that CPU with gettimeofday(),
58          * but I'm not sure what to use outside of a simple CPU nop to relax
59          * it - we don't want to lose precision.
60          */
61         while (nr_segments) {
62                 fio_gtod_update();
63                 nop;
64         }
65
66         return NULL;
67 }
68
69 int fio_start_gtod_thread(void)
70 {
71         struct fio_sem *sem;
72         pthread_attr_t attr;
73         int ret;
74
75         sem = fio_sem_init(FIO_SEM_LOCKED);
76         if (!sem)
77                 return 1;
78
79         pthread_attr_init(&attr);
80         pthread_attr_setstacksize(&attr, 2 * PTHREAD_STACK_MIN);
81         ret = pthread_create(&gtod_thread, &attr, gtod_thread_main, sem);
82         pthread_attr_destroy(&attr);
83         if (ret) {
84                 log_err("Can't create gtod thread: %s\n", strerror(ret));
85                 goto err;
86         }
87
88         ret = pthread_detach(gtod_thread);
89         if (ret) {
90                 log_err("Can't detach gtod thread: %s\n", strerror(ret));
91                 goto err;
92         }
93
94         dprint(FD_MUTEX, "wait on startup_sem\n");
95         fio_sem_down(sem);
96         dprint(FD_MUTEX, "done waiting on startup_sem\n");
97 err:
98         fio_sem_remove(sem);
99         return ret;
100 }
101
102 void fio_gtod_set_cpu(unsigned int cpu)
103 {
104 #ifdef FIO_HAVE_CPU_AFFINITY
105         fio_cpu_set(&fio_gtod_cpumask, cpu);
106 #endif
107 }