act: fixes
[fio.git] / profiles / act.c
CommitLineData
d4afedfd
JA
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
13struct act_pass_criteria {
14 unsigned int max_usec;
15 unsigned int max_perm;
16};
17#define ACT_MAX_CRIT 3
18
19static struct act_pass_criteria act_pass[ACT_MAX_CRIT] = {
20 {
21 .max_usec = 1000,
22 .max_perm = 50,
23 },
24 {
78a6aad7 25 .max_usec = 8000,
d4afedfd
JA
26 .max_perm = 10,
27 },
28 {
29 .max_usec = 64000,
30 .max_perm = 1,
31 },
32};
33
34struct act_prof_data {
35 struct timeval sample_tv;
36 uint64_t lat_buckets[ACT_MAX_CRIT];
37 uint64_t total_ios;
38};
39
40static char *device_names;
41static unsigned int load = 1;
42
43static const char *act_opts[128] = {
44 "direct=1",
78a6aad7
JA
45 "ioengine=libaio",
46 "iodepth=32",
d4afedfd
JA
47 "random_generator=lfsr",
48 "runtime=24h",
49 "time_based=1",
50 NULL,
51};
78a6aad7 52static unsigned int opt_idx = 6;
d4afedfd
JA
53static unsigned int org_idx;
54
55static void act_add_opt(const char *format, ...) __attribute__ ((__format__ (__printf__, 1, 2)));
56
57static 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
81static 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
95static 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 */
111static 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
134static 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
78a6aad7
JA
142 for (i = ACT_MAX_CRIT - 1; i >= 0; i--) {
143 if (usec > act_pass[i].max_usec) {
d4afedfd
JA
144 apd->lat_buckets[i]++;
145 break;
146 }
147 }
148
d4afedfd
JA
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;
78a6aad7 155 if (perm < act_pass[i].max_perm)
d4afedfd
JA
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
78a6aad7
JA
163 memset(apd->lat_buckets, 0, sizeof(apd->lat_buckets));
164 apd->total_ios = 0;
165
d4afedfd
JA
166 fio_gettime(&apd->sample_tv, NULL);
167 return ret;
168}
169
170static 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
180static void act_td_exit(struct thread_data *td)
181{
182 free(td->prof_data);
183 td->prof_data = NULL;
184}
185
186static 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
192static 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
201static 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
207static 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}