Fix the creation of the dumpdir directory in stress_floppy Makefile
[ltp-debian.git] / testcases / kernel / controllers / io-throttle / iobw.c
blob7c0b1a4ca063fb2cb051a4b6944e8da261e4c671
1 /*
2 * iobw.c - simple I/O bandwidth benchmark
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public
15 * License along with this program; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 021110-1307, USA.
19 * Copyright (C) 2008 Andrea Righi <righi.andrea@gmail.com>
22 #define _GNU_SOURCE
23 #define __USE_GNU
25 #include <errno.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <malloc.h>
29 #include <fcntl.h>
30 #include <signal.h>
31 #include <string.h>
32 #include <unistd.h>
33 #include <limits.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <sys/time.h>
37 #include <sys/wait.h>
39 #ifndef PAGE_SIZE
40 #define PAGE_SIZE sysconf(_SC_PAGE_SIZE)
41 #endif
43 #define align(x,a) __align_mask(x,(typeof(x))(a)-1)
44 #define __align_mask(x,mask) (((x)+(mask))&~(mask))
45 #define kb(x) ((x) >> 10)
47 const char usage[] = "Usage: iobw [-direct] threads chunk_size data_size\n";
48 const char child_fmt[] =
49 "(%s) task %3d: time %4lu.%03lu bw %7lu KiB/s (%s)\n";
50 const char parent_fmt[] =
51 "(%s) parent %d: time %4lu.%03lu bw %7lu KiB/s (%s)\n";
53 static int directio = 0;
54 static size_t data_size = 0;
55 static size_t chunk_size = 0;
57 typedef enum {
58 OP_WRITE,
59 OP_READ,
60 NUM_IOPS,
61 } iops_t;
63 static const char *iops[] = {
64 "WRITE",
65 "READ ",
66 "TOTAL",
69 static int threads;
70 pid_t *children;
72 char *mygroup;
74 static void print_results(int id, iops_t op, size_t bytes, struct timeval *diff)
76 fprintf(stdout, id ? child_fmt : parent_fmt,
77 mygroup, id, diff->tv_sec, diff->tv_usec / 1000,
78 (bytes / (diff->tv_sec * 1000000L + diff->tv_usec))
79 * 1000000L / 1024, iops[op]);
82 static void thread(int id)
84 struct timeval start, stop, diff;
85 int fd, i, ret;
86 size_t n;
87 void *buf;
88 int flags = O_CREAT | O_RDWR | O_LARGEFILE;
89 char filename[32];
91 ret = posix_memalign(&buf, PAGE_SIZE, chunk_size);
92 if (ret < 0) {
93 fprintf(stderr,
94 "ERROR: task %d couldn't allocate %lu bytes (%s)\n",
95 id, chunk_size, strerror(errno));
96 exit(1);
98 memset(buf, 0xaa, chunk_size);
100 snprintf(filename, sizeof(filename), "%s-%d-iobw.tmp", mygroup, id);
101 if (directio)
102 flags |= O_DIRECT;
103 fd = open(filename, flags, 0600);
104 if (fd < 0) {
105 fprintf(stderr, "ERROR: task %d couldn't open %s (%s)\n",
106 id, filename, strerror(errno));
107 free(buf);
108 exit(1);
111 /* Write */
112 lseek(fd, 0, SEEK_SET);
113 n = 0;
114 gettimeofday(&start, NULL);
115 while (n < data_size) {
116 i = write(fd, buf, chunk_size);
117 if (i < 0) {
118 fprintf(stderr, "ERROR: task %d writing to %s (%s)\n",
119 id, filename, strerror(errno));
120 ret = 1;
121 goto out;
123 n += i;
125 gettimeofday(&stop, NULL);
126 timersub(&stop, &start, &diff);
127 print_results(id + 1, OP_WRITE, data_size, &diff);
129 /* Read */
130 lseek(fd, 0, SEEK_SET);
131 n = 0;
132 gettimeofday(&start, NULL);
133 while (n < data_size) {
134 i = read(fd, buf, chunk_size);
135 if (i < 0) {
136 fprintf(stderr, "ERROR: task %d reading to %s (%s)\n",
137 id, filename, strerror(errno));
138 ret = 1;
139 goto out;
141 n += i;
143 gettimeofday(&stop, NULL);
144 timersub(&stop, &start, &diff);
145 print_results(id + 1, OP_READ, data_size, &diff);
146 out:
147 close(fd);
148 unlink(filename);
149 free(buf);
150 exit(ret);
153 static void spawn(int id)
155 pid_t pid;
157 pid = fork();
158 switch (pid) {
159 case -1:
160 fprintf(stderr, "ERROR: couldn't fork thread %d\n", id);
161 exit(1);
162 case 0:
163 thread(id);
164 default:
165 children[id] = pid;
169 void signal_handler(int sig)
171 char filename[32];
172 int i;
174 for (i = 0; i < threads; i++)
175 if (children[i])
176 kill(children[i], SIGKILL);
178 for (i = 0; i < threads; i++) {
179 struct stat mystat;
181 snprintf(filename, sizeof(filename), "%s-%d-iobw.tmp",
182 mygroup,i);
183 if (stat(filename, &mystat) < 0)
184 continue;
185 unlink(filename);
188 fprintf(stdout, "received signal %d, exiting\n", sig);
189 exit(0);
192 unsigned long long memparse(char *ptr, char **retptr)
194 unsigned long long ret = strtoull(ptr, retptr, 0);
196 switch (**retptr) {
197 case 'G':
198 case 'g':
199 ret <<= 10;
200 case 'M':
201 case 'm':
202 ret <<= 10;
203 case 'K':
204 case 'k':
205 ret <<= 10;
206 (*retptr)++;
207 default:
208 break;
210 return ret;
213 int main(int argc, char *argv[])
215 struct timeval start, stop, diff;
216 char *end;
217 int i;
219 if (argv[1] && strcmp(argv[1], "-direct") == 0) {
220 directio = 1;
221 argc--;
222 argv++;
224 if (argc != 4) {
225 fprintf(stderr, usage);
226 exit(1);
228 if ((threads = atoi(argv[1])) == 0) {
229 fprintf(stderr, usage);
230 exit(1);
232 chunk_size = align(memparse(argv[2], &end), PAGE_SIZE);
233 if (*end) {
234 fprintf(stderr, usage);
235 exit(1);
237 data_size = align(memparse(argv[3], &end), PAGE_SIZE);
238 if (*end) {
239 fprintf(stderr, usage);
240 exit(1);
243 /* retrieve group name */
244 mygroup = getenv("MYGROUP");
245 if (!mygroup) {
246 fprintf(stderr,
247 "ERROR: undefined environment variable MYGROUP\n");
248 exit(1);
251 children = malloc(sizeof(pid_t) * threads);
252 if (!children) {
253 fprintf(stderr, "ERROR: not enough memory\n");
254 exit(1);
257 /* handle user interrupt */
258 signal(SIGINT, signal_handler);
259 /* handle kill from shell */
260 signal(SIGTERM, signal_handler);
262 fprintf(stdout, "chunk_size %luKiB, data_size %luKiB\n",
263 kb(chunk_size), kb(data_size));
264 fflush(stdout);
266 gettimeofday(&start, NULL);
267 for (i = 0; i < threads ; i++)
268 spawn(i);
269 for (i = 0; i < threads; i++) {
270 int status;
271 wait(&status);
272 if (!WIFEXITED(status))
273 exit(1);
275 gettimeofday(&stop, NULL);
277 timersub(&stop, &start, &diff);
278 print_results(0, NUM_IOPS, data_size * threads * NUM_IOPS, &diff);
279 fflush(stdout);
280 free(children);
282 exit(0);