Merge remote-tracking branch 'qemu/master'
[qemu/ar7.git] / qemu-test.c
blobe4a2d3d0d650985a6077cdb418a4e84e9dc0070d
1 /*
2 * Copyright (c) 2010-2011 IBM
4 * Authors:
5 * Chunqiang Tang <ctang@us.ibm.com>
7 * This work is licensed under the terms of the GNU GPL, version 2.
8 * See the COPYING file in the top-level directory.
9 */
11 /*=============================================================================
12 * A short description: this module implements a fully automated testing tool
13 * for block device drivers. It works with block/sim.c.
14 *=============================================================================
17 #include "qemu/osdep.h"
18 #include <getopt.h>
20 #include "qemu-common.h"
21 #include "qemu/timer.h"
22 #include "block/block_int.h"
23 #include "block/fvd-ext.h"
24 #include "block/blksim.h"
26 #define die(format,...) \
27 do { \
28 fprintf (stderr, "%s:%d --- ", __FILE__, __LINE__); \
29 fprintf (stderr, format, ##__VA_ARGS__); \
30 exit (-1);\
31 } while(0)
33 typedef enum { OP_NULL = 0, OP_READ, OP_WRITE, OP_FLUSH } op_type_t;
34 const char *op_type_str[] = { "NULL ", "READ ", "WRITE", "FLUSH" };
36 typedef struct CompareFullCB {
37 QEMUIOVector qiov;
38 struct iovec iov;
39 int64_t sector_num;
40 int nb_sectors;
41 int max_nb_sectors;
42 uint8_t *truth_buf;
43 } CompareFullCB;
45 typedef struct RandomIO {
46 QEMUIOVector qiov;
47 int64_t sector_num;
48 int nb_sectors;
49 uint8_t *truth_buf;
50 uint8_t *test_buf;
51 op_type_t type;
52 int tester;
53 int64_t uuid;
54 int allow_cancel;
55 BlockDriverAIOCB *acb;
56 } RandomIO;
58 static char *progname;
59 static BlockDriverState *bs;
60 static int fd;
61 static int64_t total_sectors;
62 static int64_t io_size = 262144;
63 static int verify_write = TRUE;
64 static int parallel = 1;
65 static int max_iov = 10;
66 static int64_t round = 10;
67 static int64_t finished_round = 0;
68 static RandomIO *testers = NULL;
69 static double fail_prob = 0;
70 static double cancel_prob = 0;
71 static double flush_prob = 0;
72 static int64_t rand_time = 1000;
73 static int64_t test_uuid = 0;
74 static int instant_qemubh = FALSE;
76 static void rand_io_cb (void *opaque, int ret);
77 static void perform_next_io (RandomIO * r);
79 int64_t qemu_get_clock (QEMUClock * clock)
81 return sim_get_time ();
84 void timer_mod(QEMUTimer *ts, int64_t expire_time)
86 sim_mod_timer (ts, expire_time);
89 QEMUTimer *qemu_new_timer (QEMUClock * clock, QEMUTimerCB * cb, void *opaque)
91 return sim_new_timer (cb, opaque);
94 void timer_free(QEMUTimer *ts)
96 sim_free_timer (ts);
99 void timer_del(QEMUTimer *ts)
101 sim_del_timer (ts);
104 QEMUBH *qemu_bh_new (QEMUBHFunc * cb, void *opaque)
106 return sim_new_timer (cb, opaque);
109 int qemu_bh_poll (void)
111 return 0;
114 void qemu_bh_schedule (QEMUBH * bh)
116 if (instant_qemubh) {
117 sim_mod_timer (bh, -1); /* Run this bh next. */
118 } else {
119 sim_mod_timer (bh, sim_get_time ());
123 void qemu_bh_cancel (QEMUBH * bh)
125 sim_del_timer (bh);
128 void qemu_bh_delete (QEMUBH * bh)
130 sim_free_timer (bh);
133 static void usage (void)
135 printf ("%s [--help]\n"
136 "\t--truth=<truth_img>\n"
137 "\t--test=<img_to_test>\n"
138 "\t[--format=<test_img_fmt>]\n"
139 "\t[--round=<#d>]\n"
140 "\t[--instant_qemubh=<true|false>]\n"
141 "\t[--fail_prob=<#f>]\n"
142 "\t[--cancel_prob=<#f>]\n"
143 "\t[--flush_prob=<#f>]\n"
144 "\t[--io_size=<#d>]\n"
145 "\t[--verify_write=[true|false]]\n"
146 "\t[--parallel=[#d]\n"
147 "\t[--max_iov=[#d]\n"
148 "\t[--compare_before=[true|false]]\n"
149 "\t[--compare_after=[true|false]]\n" "\n", progname);
150 exit (1);
153 static int truth_io (void *buf, int64_t sector_num, int nb_sectors, int do_read)
155 off_t offset = sector_num * 512;
156 size_t size = nb_sectors * 512;
158 while (size > 0) {
159 int r;
160 if (do_read) {
161 r = pread (fd, buf, size, offset);
162 } else {
163 r = pwrite (fd, buf, size, offset);
165 if (r >= 0) {
166 size -= r;
167 offset += r;
168 buf = (void *) (((char *) buf) + r);
169 } else if (errno != EINTR) {
170 perror ("io");
171 die ("I/O error on the truth file.\n");
172 return -1;
176 return 0;
179 static int verify (uint8_t * truth_buf, uint8_t * test_buf,
180 int64_t sector_num, int nb_sectors)
182 int i;
183 for (i = 0; i < nb_sectors; i++) {
184 int64_t offset = i * 512;
185 if (memcmp (&truth_buf[offset], &test_buf[offset], 512) != 0) {
186 int j;
187 printf ("Sector %" PRId64 " differs\n", sector_num + i);
188 QDEBUG ("Sector %" PRId64 " differs\n", sector_num + i);
189 for (j = 0; j < 512; j++) {
190 if (truth_buf[offset + j] == test_buf[offset + j]) {
191 QDEBUG ("%02d: %02X %02X\n", j, truth_buf[offset + j],
192 test_buf[offset + j]);
193 } else {
194 QDEBUG ("%02d: %02X %02X ***\n", j,
195 truth_buf[offset + j], test_buf[offset + j]);
199 fprintf (stderr, "Pause process %d for debugging...\n", getpid ());
200 fgetc (stdin);
202 return -1;
206 return 0;
209 static void compare_full_images_cb (void *opaque, int ret)
211 CompareFullCB *cf = opaque;
213 if (ret) {
214 /* Failed. Retry the operation. */
215 bdrv_aio_readv (bs, cf->sector_num, &cf->qiov, cf->nb_sectors,
216 compare_full_images_cb, cf);
217 return;
220 truth_io (cf->truth_buf, cf->sector_num, cf->nb_sectors, TRUE);
221 verify (cf->truth_buf, cf->iov.iov_base, cf->sector_num, cf->nb_sectors);
223 cf->sector_num += cf->nb_sectors;
224 if (cf->sector_num >= total_sectors) {
225 /* Finished. */
226 free (cf->truth_buf);
227 qemu_vfree (cf->iov.iov_base);
228 g_free(cf);
229 return;
232 /* Read more data to compare. */
233 if (cf->sector_num + cf->max_nb_sectors > total_sectors) {
234 cf->nb_sectors = total_sectors - cf->sector_num;
235 } else {
236 cf->nb_sectors = cf->max_nb_sectors;
238 cf->iov.iov_len = cf->nb_sectors * 512;
239 qemu_iovec_init_external (&cf->qiov, &cf->iov, 1);
240 if (!bdrv_aio_readv (bs, cf->sector_num, &cf->qiov,
241 cf->nb_sectors, compare_full_images_cb, cf)) {
242 die ("bdrv_aio_readv\n");
246 static int compare_full_images (void)
248 CompareFullCB *cf;
249 int old_copy_on_read = FALSE;
251 printf ("Performing a full comparison of the truth image and "
252 "the test image...\n");
254 if (!strncmp (bs->drv->format_name, "fvd", 3)) {
255 /* Disable copy-on-read when scanning through the entire image. */
256 old_copy_on_read = fvd_get_copy_on_read (bs);
257 fvd_set_copy_on_read (bs, FALSE);
260 cf = g_malloc(sizeof(CompareFullCB));
261 cf->max_nb_sectors = 1048576L / 512;
262 cf->nb_sectors = MIN (cf->max_nb_sectors, total_sectors);
263 if (posix_memalign ((void **) &cf->truth_buf, 512,
264 cf->max_nb_sectors * 512) != 0) {
265 die ("posix_memalign");
267 cf->iov.iov_base = qemu_blockalign (bs, cf->max_nb_sectors * 512);
268 cf->iov.iov_len = cf->nb_sectors * 512;
269 cf->sector_num = 0;
270 qemu_iovec_init_external (&cf->qiov, &cf->iov, 1);
271 if (!bdrv_aio_readv (bs, cf->sector_num, &cf->qiov,
272 cf->nb_sectors, compare_full_images_cb, cf)) {
273 die ("bdrv_aio_readv\n");
276 sim_all_tasks ();
278 if (!strncmp (bs->drv->format_name, "fvd", 3)) {
279 fvd_set_copy_on_read (bs, old_copy_on_read);
282 return 0;
285 static inline int64_t rand64 (void)
287 int64_t f1 = random ();
288 int64_t f2 = random ();
289 int64_t f3 = (f1 << 32) | f2;
290 return f3 >= 0 ? f3 : -f3;
293 static int check_conflict (RandomIO * r)
295 int i;
297 for (i = 0; i < parallel; i++) {
298 RandomIO *s = &testers[i];
299 if (s == r || s->type == OP_FLUSH ||
300 (r->type == OP_READ && s->type == OP_READ)) {
301 continue;
304 if ((r->sector_num <= s->sector_num &&
305 s->sector_num < r->sector_num + r->nb_sectors) ||
306 (s->sector_num <= r->sector_num &&
307 r->sector_num < s->sector_num + s->nb_sectors)) {
308 return 1; /* Conflict. */
312 return 0; /* No confict. */
315 /* Return FALSE if the submitted request is cancelled. */
316 static int submit_rand_io (RandomIO * r)
318 BlockDriverAIOCB *acb = NULL;
320 QDEBUG ("TESTER %03d: %s test%" PRIX64 " sector_num=%" PRId64
321 " nb_sectors=%d niov=%d\n", r->tester, op_type_str[r->type],
322 r->uuid, r->sector_num, r->nb_sectors, r->qiov.niov);
323 printf ("TESTER %03d: %s sector_num=%" PRId64 " nb_sectors=%d niov=%d\n",
324 r->tester, op_type_str[r->type], r->sector_num, r->nb_sectors,
325 r->qiov.niov);
327 int ret;
328 if (fail_prob <= 0) {
329 ret = 0;
330 } else if (random () / (double) RAND_MAX <= fail_prob) {
331 ret = -EIO;
332 } else {
333 ret = 0;
336 /* This affects whether this request will fail or not. */
337 sim_set_disk_io_return_code (ret);
339 switch (r->type) {
340 case OP_READ:
341 if (!(acb = bdrv_aio_readv (bs, r->sector_num, &r->qiov, r->nb_sectors,
342 rand_io_cb, r))) {
343 die ("bdrv_aio_readv\n");
345 break;
346 case OP_WRITE:
347 if (!(acb = bdrv_aio_writev (bs, r->sector_num, &r->qiov, r->nb_sectors,
348 rand_io_cb, r))) {
349 die ("bdrv_aio_writev\n");
351 break;
352 case OP_FLUSH:
353 if (!(acb = bdrv_aio_flush (bs, rand_io_cb, r))) {
354 die ("bdrv_aio_flush\n");
356 break;
357 case OP_NULL:
358 die ("OP_NULL");
359 break;
362 sim_set_disk_io_return_code (0); /* Reset to no failure state. */
364 if (r->allow_cancel && cancel_prob > 0 &&
365 random () / (double) RAND_MAX <= cancel_prob) {
366 QDEBUG ("TESTER %03d: cancel %s test%" PRIX64 " sector_num=%" PRId64
367 " nb_sectors=%d niov=%d\n", r->tester, op_type_str[r->type],
368 r->uuid, r->sector_num, r->nb_sectors, r->qiov.niov);
369 printf ("TESTER %03d: cancel %s sector_num=%" PRId64
370 " nb_sectors=%d niov=%d\n", r->tester, op_type_str[r->type],
371 r->sector_num, r->nb_sectors, r->qiov.niov);
372 bdrv_aio_cancel (acb);
373 return FALSE;
374 } else {
375 return TRUE;
379 static void prepare_read_write (RandomIO * r)
381 /* Do a READ or WRITE? */
382 if (random () % 2) {
383 r->type = OP_READ;
384 } else {
385 r->type = OP_WRITE;
388 /* Find the next region to perform io. */
389 do {
390 if (parallel <= 1 || (random () % 2 == 0)) {
391 /* Perform a random I/O. */
392 r->sector_num = rand64 () % total_sectors;
393 } else {
394 /* Perform an I/O next to a currently ongoing I/O. */
395 int id;
396 do {
397 id = random () % parallel;
398 } while (id == r->tester);
400 RandomIO *p = &testers[id];
401 r->sector_num =
402 p->sector_num + 2 * io_size - rand64 () % (4 * io_size);
403 if (r->sector_num < 0) {
404 r->sector_num = 0;
405 } else if (r->sector_num >= total_sectors) {
406 r->sector_num = total_sectors - 1;
410 r->nb_sectors = 1 + rand64 () % io_size;
411 if (r->sector_num + r->nb_sectors > total_sectors) {
412 r->nb_sectors = total_sectors - r->sector_num;
414 } while (check_conflict (r));
416 if (r->type == OP_WRITE) {
417 /* Fill test_buf with random data. */
418 int i, j;
419 for (i = 0; i < r->nb_sectors; i++) {
420 const uint64_t TEST_MAGIC = 0x0123456789ABCDEFULL;
421 /* This first 8 bytes of the sector stores the current testing
422 * round. The next 8 bytes store a magic number. This info helps
423 * debugging. */
424 uint64_t *p = (uint64_t *) & r->test_buf[i * 512];
425 *p = r->uuid;
426 cpu_to_be64s (p);
427 p++;
428 *p = TEST_MAGIC;
429 cpu_to_be64s (p);
431 /* The rest of the sector are filled with random data. */
432 uint32_t *q = (uint32_t *) (p + 1);
433 int n = (512 - 2 * sizeof (uint64_t)) / sizeof (uint32_t);
434 for (j = 0; j < n; j++) {
435 *q++ = random ();
440 /* Determine the number of iov. */
441 int niov = 0;
442 uint8_t *p = r->test_buf;
443 int left = r->nb_sectors;
444 do {
445 if (niov == max_iov - 1) {
446 r->qiov.iov[niov].iov_len = left * 512;
447 r->qiov.iov[niov].iov_base = p;
448 niov++;
449 break;
452 int nb = 1 + random () % left;
453 r->qiov.iov[niov].iov_len = nb * 512;
454 r->qiov.iov[niov].iov_base = p;
455 p += r->qiov.iov[niov].iov_len;
456 left -= nb;
457 niov++;
458 } while (left > 0);
460 qemu_iovec_init_external (&r->qiov, r->qiov.iov, niov);
463 static void perform_next_io (RandomIO * r)
465 if (finished_round >= round) {
466 return;
469 finished_round++;
470 r->allow_cancel = TRUE;
472 do {
473 r->uuid = test_uuid++;
475 if (flush_prob > 0 && random () / (double) RAND_MAX < flush_prob) {
476 r->type = OP_FLUSH;
477 } else {
478 prepare_read_write (r);
480 } while (!submit_rand_io (r));
483 static void rand_io_cb (void *opaque, int ret)
485 RandomIO *r = opaque;
487 if (ret) {
488 if (fail_prob <= 0) {
489 fprintf (stderr, "Request %s sector_num=%" PRId64
490 " nb_sectors=%d failed while fail_prob=0. "
491 "Pause for debugging...\n",
492 op_type_str[r->type], r->sector_num, r->nb_sectors);
493 fgetc (stdin);
494 } else {
495 /* Failed. Retry the operation. */
496 QDEBUG ("TESTER %03d: retry %s test%" PRIX64 " sector_num=%"
497 PRId64 " nb_sectors=%d niov=%d\n",
498 r->tester, op_type_str[r->type], r->uuid,
499 r->sector_num, r->nb_sectors, r->qiov.niov);
500 if (!submit_rand_io (r)) {
501 perform_next_io (r);
503 return;
505 } else {
506 QDEBUG ("TESTER %03d: finished %s test%" PRIX64 " sector_num=%"PRId64
507 " nb_sectors=%d niov=%d\n", r->tester, op_type_str[r->type],
508 r->uuid, r->sector_num, r->nb_sectors, r->qiov.niov);
511 switch (r->type) {
512 case OP_FLUSH:
513 perform_next_io (r);
514 return;
516 case OP_READ:
517 truth_io (r->truth_buf, r->sector_num, r->nb_sectors, TRUE);
518 verify (r->truth_buf, r->test_buf, r->sector_num, r->nb_sectors);
519 perform_next_io (r);
520 return;
522 case OP_WRITE:
523 truth_io (r->test_buf, r->sector_num, r->nb_sectors, FALSE);
524 if (verify_write) {
525 /* Perform a read for the same data. */
526 r->type = OP_READ;
528 /* To verify the write, this read cannot be cancelled. */
529 r->allow_cancel = FALSE;
530 r->qiov.niov = 1;
531 r->qiov.iov[0].iov_len = r->qiov.size;
532 memset (r->test_buf, 0xA5, r->qiov.size); /* Fill in garbage. */
533 submit_rand_io (r);
534 } else {
535 perform_next_io (r);
537 return;
539 case OP_NULL:
540 die ("OP_NULL");
541 return;
545 static int read_bool (const char *arg)
547 int val = TRUE;
548 if (strcmp (optarg, "true") == 0) {
549 val = TRUE;
550 } else if (strcmp (optarg, "false") == 0) {
551 val = FALSE;
552 } else {
553 printf ("%s is neither 'true' nor 'false'\n", arg);
554 usage ();
557 return val;
561 static void perform_test(const char *truth_file, const char *test_file,
562 const char *format, int compare_before,
563 int compare_after)
565 int flags, i;
567 bs = bdrv_new ("hda");
568 if (!bs) {
569 die ("bdrv_new failed\n");
572 BlockDriver *drv = NULL;
573 if (format) {
574 drv = bdrv_find_format (format);
575 if (!drv) {
576 die ("Found no driver for format '%s'.\n", format);
580 flags = BDRV_O_RDWR | BDRV_O_CACHE_WB;
582 if (bdrv_open (bs, test_file, flags, drv) < 0) {
583 die ("Failed to open '%s'\n", test_file);
586 fd = open (truth_file, O_RDWR | O_LARGEFILE, 0);
587 if (fd < 0) {
588 perror ("open");
589 die ("Failed to open '%s'\n", truth_file);
592 int64_t l0 = lseek (fd, 0, SEEK_END);
593 int64_t l1 = bdrv_getlength (bs);
594 if (l0 < 0 || l1 < 0 || l0 < l1) {
595 die ("Mismatch: truth image %s length %" PRId64 ", test image %s "
596 "length %" PRId64 "\n", truth_file, l0, test_file, l1);
599 total_sectors = l1 / 512;
600 if (total_sectors <= 1) {
601 die ("Total sectors: %" PRId64 "\n", total_sectors);
604 io_size /= 512;
605 if (io_size <= 0) {
606 io_size = 1;
607 } else if (io_size > total_sectors / 2) {
608 io_size = total_sectors / 2;
611 if (compare_before) {
612 if (compare_full_images ()) {
613 die ("The original two files do not match.\n");
617 if (round > 0) {
618 /* Create testers. */
619 testers = g_malloc(sizeof(RandomIO) * parallel);
620 for (i = 0; i < parallel; i++) {
621 RandomIO *r = &testers[i];
622 r->test_buf = qemu_blockalign (bs, io_size * 512);
623 if (posix_memalign ((void **) &r->truth_buf, 512, io_size * 512)) {
624 die ("posix_memalign");
626 r->qiov.iov = g_malloc(sizeof(struct iovec) * max_iov);
627 r->sector_num = 0;
628 r->nb_sectors = 0;
629 r->type = OP_READ;
630 r->tester = i;
632 for (i = 0; i < parallel; i++) {
633 perform_next_io (&testers[i]);
637 sim_all_tasks (); /* Run tests. */
639 if (round > 0) {
640 /* Create testers. */
641 if (compare_after) {
642 if (compare_full_images ()) {
643 die ("The two files do not match after I/O operations.\n");
647 for (i = 0; i < parallel; i++) {
648 RandomIO *r = &testers[i];
649 qemu_vfree (r->test_buf);
650 free (r->truth_buf);
651 g_free(r->qiov.iov);
653 g_free(testers);
656 printf ("Test process %d finished successfully\n", getpid ());
658 int fvd = (strncmp (bs->drv->format_name, "fvd", 3) == 0);
659 bdrv_delete (bs);
660 if (fvd) {
661 fvd_check_memory_usage ();
663 close (fd);
666 int main (int argc, char **argv)
668 int c;
669 const char *truth_file = NULL;
670 const char *test_file = NULL;
671 const char *format = NULL;
672 int compare_before = FALSE;
673 int compare_after = TRUE;
674 int seed = 0;
676 const struct option lopt[] = {
677 {"help", 0, 0, 'h'},
678 {"seed", 1, 0, 'd'},
679 {"truth", 1, 0, 'b'},
680 {"test", 1, 0, 't'},
681 {"format", 1, 0, 'f'},
682 {"rand_time", 1, 0, 'n'},
683 {"fail_prob", 1, 0, 'u'},
684 {"cancel_prob", 1, 0, 'c'},
685 {"flush_prob", 1, 0, 'w'},
686 {"round", 1, 0, 'r'},
687 {"parallel", 1, 0, 'p'},
688 {"compare_before", 1, 0, 'm'},
689 {"verify_write", 1, 0, 'v'},
690 {"compare_after", 1, 0, 'a'},
691 {"max_iov", 1, 0, 'i'},
692 {"io_size", 1, 0, 's'},
693 {"instant_qemubh", 1, 0, 'q'},
694 {NULL, 0, NULL, 0}
697 progname = basename (argv[0]);
699 while ((c = getopt_long (argc, argv, "hc:u:p:q:i:f:d:b:t:r:m:v:a:s:",
700 lopt, NULL)) != -1) {
701 switch (c) {
702 case 'h':
703 usage ();
704 return 0;
706 case 'q':
707 instant_qemubh = read_bool (optarg);
708 break;
710 case 'w':
711 flush_prob = atof (optarg);
712 break;
714 case 'c':
715 cancel_prob = atof (optarg);
716 break;
718 case 'u':
719 fail_prob = atof (optarg);
720 break;
722 case 'n':
723 rand_time = atoll (optarg);
724 break;
726 case 'i':
727 max_iov = atoi (optarg);
728 break;
730 case 'p':
731 parallel = atoi (optarg);
732 break;
734 case 'v':
735 verify_write = read_bool (optarg);
736 break;
738 case 'm':
739 compare_before = read_bool (optarg);
740 break;
742 case 'a':
743 compare_after = read_bool (optarg);
744 break;
746 case 'd':
747 seed = atoll (optarg);
748 break;
750 case 'f':
751 format = optarg;
752 break;
754 case 'b':
755 truth_file = optarg;
756 break;
758 case 't':
759 test_file = optarg;
760 break;
762 case 's':
763 io_size = atoll (optarg);
764 break;
766 case 'r':
767 round = atoll (optarg);
768 break;
770 default:
771 usage ();
772 return 1;
776 if (!truth_file || !test_file) {
777 usage ();
778 return 1;
781 if (parallel <= 0) {
782 parallel = 1;
784 srandom (seed);
785 /* Convince FVD this is not in a qemu-tool. */
786 in_qemu_tool = false;
787 enable_block_sim (FALSE /*no print */ , rand_time);
788 fvd_enable_host_crash_test ();
789 bdrv_init ();
790 perform_test (truth_file, test_file, format, compare_before, compare_after);
791 return 0;