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>
34 #include <sys/types.h>
40 #define PAGE_SIZE sysconf(_SC_PAGE_SIZE)
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;
63 static const char *iops
[] = {
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
;
88 int flags
= O_CREAT
| O_RDWR
| O_LARGEFILE
;
91 ret
= posix_memalign(&buf
, PAGE_SIZE
, chunk_size
);
94 "ERROR: task %d couldn't allocate %lu bytes (%s)\n",
95 id
, chunk_size
, strerror(errno
));
98 memset(buf
, 0xaa, chunk_size
);
100 snprintf(filename
, sizeof(filename
), "%s-%d-iobw.tmp", mygroup
, id
);
103 fd
= open(filename
, flags
, 0600);
105 fprintf(stderr
, "ERROR: task %d couldn't open %s (%s)\n",
106 id
, filename
, strerror(errno
));
112 lseek(fd
, 0, SEEK_SET
);
114 gettimeofday(&start
, NULL
);
115 while (n
< data_size
) {
116 i
= write(fd
, buf
, chunk_size
);
118 fprintf(stderr
, "ERROR: task %d writing to %s (%s)\n",
119 id
, filename
, strerror(errno
));
125 gettimeofday(&stop
, NULL
);
126 timersub(&stop
, &start
, &diff
);
127 print_results(id
+ 1, OP_WRITE
, data_size
, &diff
);
130 lseek(fd
, 0, SEEK_SET
);
132 gettimeofday(&start
, NULL
);
133 while (n
< data_size
) {
134 i
= read(fd
, buf
, chunk_size
);
136 fprintf(stderr
, "ERROR: task %d reading to %s (%s)\n",
137 id
, filename
, strerror(errno
));
143 gettimeofday(&stop
, NULL
);
144 timersub(&stop
, &start
, &diff
);
145 print_results(id
+ 1, OP_READ
, data_size
, &diff
);
153 static void spawn(int id
)
160 fprintf(stderr
, "ERROR: couldn't fork thread %d\n", id
);
169 void signal_handler(int sig
)
174 for (i
= 0; i
< threads
; i
++)
176 kill(children
[i
], SIGKILL
);
178 for (i
= 0; i
< threads
; i
++) {
181 snprintf(filename
, sizeof(filename
), "%s-%d-iobw.tmp",
183 if (stat(filename
, &mystat
) < 0)
188 fprintf(stdout
, "received signal %d, exiting\n", sig
);
192 unsigned long long memparse(char *ptr
, char **retptr
)
194 unsigned long long ret
= strtoull(ptr
, retptr
, 0);
213 int main(int argc
, char *argv
[])
215 struct timeval start
, stop
, diff
;
219 if (argv
[1] && strcmp(argv
[1], "-direct") == 0) {
225 fprintf(stderr
, usage
);
228 if ((threads
= atoi(argv
[1])) == 0) {
229 fprintf(stderr
, usage
);
232 chunk_size
= align(memparse(argv
[2], &end
), PAGE_SIZE
);
234 fprintf(stderr
, usage
);
237 data_size
= align(memparse(argv
[3], &end
), PAGE_SIZE
);
239 fprintf(stderr
, usage
);
243 /* retrieve group name */
244 mygroup
= getenv("MYGROUP");
247 "ERROR: undefined environment variable MYGROUP\n");
251 children
= malloc(sizeof(pid_t
) * threads
);
253 fprintf(stderr
, "ERROR: not enough memory\n");
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
));
266 gettimeofday(&start
, NULL
);
267 for (i
= 0; i
< threads
; i
++)
269 for (i
= 0; i
< threads
; i
++) {
272 if (!WIFEXITED(status
))
275 gettimeofday(&stop
, NULL
);
277 timersub(&stop
, &start
, &diff
);
278 print_results(0, NUM_IOPS
, data_size
* threads
* NUM_IOPS
, &diff
);