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