e5b31d7d2e1dceb3181a8f90e4e1ca730b07d293
[fio.git] / profiles / act.c
1 #include "../fio.h"
2 #include "../profile.h"
3 #include "../parse.h"
4
5 #define OBJ_SIZE        1536            /* each object */
6 #define W_BUF_SIZE      128 * 1024      /* write coalescing */
7
8 #define R_LOAD          2000
9 #define W_LOAD          1000
10
11 #define SAMPLE_SEC      3600            /* 1h checks */
12
13 struct act_pass_criteria {
14         unsigned int max_usec;
15         unsigned int max_perm;
16 };
17 #define ACT_MAX_CRIT    3
18
19 static struct act_pass_criteria act_pass[ACT_MAX_CRIT] = {
20         {
21                 .max_usec =     1000,
22                 .max_perm =     50,
23         },
24         {
25                 .max_usec =     8000,
26                 .max_perm =     10,
27         },
28         {
29                 .max_usec =     64000,
30                 .max_perm =     1,
31         },
32 };
33
34 struct act_prof_data {
35         struct timeval sample_tv;
36         uint64_t lat_buckets[ACT_MAX_CRIT];
37         uint64_t total_ios;
38 };
39
40 static char *device_names;
41 static unsigned int load = 1;
42
43 static const char *act_opts[128] = {
44         "direct=1",
45         "ioengine=libaio",
46         "iodepth=32",
47         "random_generator=lfsr",
48         "runtime=24h",
49         "time_based=1",
50         NULL,
51 };
52 static unsigned int opt_idx = 6;
53 static unsigned int org_idx;
54
55 static void act_add_opt(const char *format, ...) __attribute__ ((__format__ (__printf__, 1, 2)));
56
57 static struct fio_option options[] = {
58         {
59                 .name   = "device-names",
60                 .lname  = "device-names",
61                 .type   = FIO_OPT_STR_STORE,
62                 .roff1  = &device_names,
63                 .help   = "Devices to use",
64                 .category = FIO_OPT_C_PROFILE,
65                 .group  = FIO_OPT_G_ACT,
66         },
67         {
68                 .name   = "load",
69                 .lname  = "Load multiplier",
70                 .type   = FIO_OPT_INT,
71                 .roff1  = &load,
72                 .help   = "ACT load multipler (default 1x)",
73                 .category = FIO_OPT_C_PROFILE,
74                 .group  = FIO_OPT_G_ACT,
75         },
76         {
77                 .name   = NULL,
78         },
79 };
80
81 static void act_add_opt(const char *str, ...)
82 {
83         char buffer[512];
84         va_list args;
85         size_t len;
86
87         va_start(args, str);
88         len = vsnprintf(buffer, sizeof(buffer), str, args);
89         va_end(args);
90
91         if (len)
92                 act_opts[opt_idx++] = strdup(buffer);
93 }
94
95 static void act_add_dev(const char *dev)
96 {
97         act_add_opt("name=act-read-%s", dev);
98         act_add_opt("filename=%s", dev);
99         act_add_opt("rw=randread");
100         act_add_opt("rate_iops=%u", load * R_LOAD);
101
102         act_add_opt("name=act-write-%s", dev);
103         act_add_opt("filename=%s", dev);
104         act_add_opt("rw=randwrite");
105         act_add_opt("rate_iops=%u", load * W_LOAD);
106 }
107
108 /*
109  * Fill our private options into the command line
110  */
111 static int act_prep_cmdline(void)
112 {
113         if (!device_names) {
114                 log_err("act: need device-names\n");
115                 return 1;
116         }
117
118         org_idx = opt_idx;
119         act_add_opt("bs=%u", OBJ_SIZE);
120
121         do {
122                 char *dev;
123
124                 dev = strsep(&device_names, ",");
125                 if (!dev)
126                         break;
127
128                 act_add_dev(dev);
129         } while (1);
130
131         return 0;
132 }
133
134 static int act_io_u_lat(struct thread_data *td, uint64_t usec)
135 {
136         struct act_prof_data *apd = td->prof_data;
137         int i, ret = 0;
138         double perm;
139
140         apd->total_ios++;
141
142         for (i = ACT_MAX_CRIT - 1; i >= 0; i--) {
143                 if (usec > act_pass[i].max_usec) {
144                         apd->lat_buckets[i]++;
145                         break;
146                 }
147         }
148
149         if (time_since_now(&apd->sample_tv) < SAMPLE_SEC)
150                 return 0;
151
152         /* SAMPLE_SEC has passed, check criteria for pass */
153         for (i = 0; i < ACT_MAX_CRIT; i++) {
154                 perm = (1000.0 * apd->lat_buckets[i]) / apd->total_ios;
155                 if (perm < act_pass[i].max_perm)
156                         continue;
157
158                 log_err("act: %f%% exceeds pass criteria of %f%%\n", perm / 10.0, (double) act_pass[i].max_perm / 10.0);
159                 ret = 1;
160                 break;
161         }
162
163         memset(apd->lat_buckets, 0, sizeof(apd->lat_buckets));
164         apd->total_ios = 0;
165
166         fio_gettime(&apd->sample_tv, NULL);
167         return ret;
168 }
169
170 static int act_td_init(struct thread_data *td)
171 {
172         struct act_prof_data *apd;
173
174         apd = calloc(sizeof(*apd), 1);
175         fio_gettime(&apd->sample_tv, NULL);
176         td->prof_data = apd;
177         return 0;
178 }
179
180 static void act_td_exit(struct thread_data *td)
181 {
182         free(td->prof_data);
183         td->prof_data = NULL;
184 }
185
186 static struct prof_io_ops act_io_ops = {
187         .td_init        = act_td_init,
188         .td_exit        = act_td_exit,
189         .io_u_lat       = act_io_u_lat,
190 };
191
192 static struct profile_ops act_profile = {
193         .name           = "act",
194         .desc           = "ACT Aerospike like benchmark",
195         .options        = options,
196         .prep_cmd       = act_prep_cmdline,
197         .cmdline        = act_opts,
198         .io_ops         = &act_io_ops,
199 };
200
201 static void fio_init act_register(void)
202 {
203         if (register_profile(&act_profile))
204                 log_err("fio: failed to register profile 'act'\n");
205 }
206
207 static void fio_exit act_unregister(void)
208 {
209         while (org_idx && org_idx < opt_idx)
210                 free((void *) act_opts[++org_idx]);
211
212         unregister_profile(&act_profile);
213 }