1 /* Copyright (C) 2010, Matthew E. Cross <matt.cross@gmail.com>
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 /* Code to reproduce the aio lockup.
20 * Make a test file that is at least 4MB long. Something like this:
21 * 'dd if=/dev/zero of=/tmp/testfile bs=1M count=10'
23 * Run this test as './aio_test 0 100 /tmp/testfile' to induce the
26 * Run this test as './aio_test 1 100 /tmp/testfile' to demonstrate an
27 * incomplete workaround (close fd, then wait for all io to complete
28 * on an io context before calling io_destroy()). This still induces
31 * This test was written several years ago by Matt Cross, and he has
32 * graciously allowed me to post it for inclusion in xfstests.
35 * - reduce output and make it consistent for integration into xfstests (JEM)
36 * - run for fixed amount of time instead of indefinitely (JEM)
37 * - change coding style to meet xfstests standards (JEM)
38 * - get rid of unused code (workaround 2 documented above) (JEM)
39 * - use posix_memalign (JEM)
43 #define _GNU_SOURCE /* to get definition of O_DIRECT flag. */
52 #include <sys/types.h>
54 #include <sys/syscall.h>
61 #define dprintf(fmt, args...) printf(fmt, ##args)
63 #define dprintf(fmt, args...)
67 int wait_for_events = 0;
69 pthread_mutex_t count_mutex = PTHREAD_MUTEX_INITIALIZER;
70 unsigned long total_loop_count = 0;
73 #define IOSIZE (1024 * 64)
78 return (pid_t)syscall(SYS_gettid);
82 aio_test_thread(void *data)
88 struct iocb iocbs[NUM_IOS];
90 static unsigned char *buffer;
92 long mycpu = (long)data;
93 pid_t mytid = gettid();
96 dprintf("setting thread %d to run on cpu %ld\n", mytid, mycpu);
99 * Problems have been easier to trigger when spreading the
100 * workload over the available CPUs.
103 CPU_SET(mycpu, &cpuset);
104 if (sched_setaffinity(mytid, sizeof(cpuset), &cpuset)) {
105 printf("FAILED to set thread %d to run on cpu %ld\n",
112 ret = posix_memalign((void **)&buffer, getpagesize(), IOSIZE);
114 printf("%lu: Failed to allocate buffer for IO: %d\n",
115 pthread_self(), ret);
120 fd = open(filename, O_RDONLY | O_DIRECT);
122 printf("%lu: Failed to open file '%s'\n",
123 pthread_self(), filename);
127 memset(&ioctx, 0, sizeof(ioctx));
128 if (io_setup(NUM_IOS, &ioctx)) {
129 printf("%lu: Failed to setup io context\n",
136 for (i = 0; i < NUM_IOS; i++) {
137 struct iocb *iocb = &iocbs[i];
139 memset(iocb, 0, sizeof(*iocb));
140 io_prep_pread(iocb, fd, buffer,
142 if (io_submit(ioctx, 1, &iocb) != 1) {
143 printf("%lu: failed to submit io #%d\n",
144 pthread_self(), i+1);
154 if (wait_for_events && ios_submitted) {
155 struct io_event io_events[NUM_IOS];
157 if (io_getevents(ioctx, NUM_IOS, NUM_IOS,
158 io_events, NULL) != NUM_IOS)
159 printf("io_getevents failed to wait for all IO\n");
168 pthread_mutex_lock(&count_mutex);
170 pthread_mutex_unlock(&count_mutex);
178 main(int argc, char **argv)
180 unsigned num_threads;
184 long ncpus = sysconf(_SC_NPROCESSORS_ONLN);
185 struct timeval start, now, delta = { 0, 0 };
188 printf("Usage: aio_test [wait for events?] [# of threads] "
193 wait_for_events = strtoul(argv[1], NULL, 0);
194 num_threads = strtoul(argv[2], NULL, 0);
197 printf("wait_for_events: %d\n", wait_for_events);
198 printf("num_threads: %u\n", num_threads);
199 printf("filename: '%s'\n", basename(filename));
201 if (num_threads < 1) {
202 printf("Number of threads is invalid, must be at least 1\n");
206 fd = open(filename, O_RDONLY|O_DIRECT);
208 printf("Failed to open filename '%s' for reading\n", filename);
213 threads = malloc(sizeof(pthread_t) * num_threads);
214 if (threads == NULL) {
215 printf("Failed to allocate thread id storage\n");
219 for (i = 0; i < num_threads; i++) {
220 if (pthread_create(&threads[i], NULL,
221 aio_test_thread, (void *)(i % ncpus))) {
222 printf("Failed to create thread #%u\n", i+1);
223 threads[i] = (pthread_t)-1;
227 printf("All threads spawned\n");
228 gettimeofday(&start, NULL);
230 while (delta.tv_sec < 60) {
232 gettimeofday(&now, NULL);
233 timersub(&now, &start, &delta);
234 dprintf("%lu loops completed in %ld seconds\n",
235 total_loop_count, delta.tv_sec);