d10e70e056451937921c941aa5d113c4dfe40d10
[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 =     5000,
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=sync",
46         "random_generator=lfsr",
47         "runtime=24h",
48         "time_based=1",
49         NULL,
50 };
51 static unsigned int opt_idx = 5;
52 static unsigned int org_idx;
53
54 static void act_add_opt(const char *format, ...) __attribute__ ((__format__ (__printf__, 1, 2)));
55
56 static 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
80 static 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
94 static 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  */
110 static 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
133 static 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
171 static 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
181 static void act_td_exit(struct thread_data *td)
182 {
183         free(td->prof_data);
184         td->prof_data = NULL;
185 }
186
187 static 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
193 static 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
202 static 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
208 static 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 }