From: Ben Pfaff Date: Thu, 4 Jan 2007 14:19:25 +0000 (+0000) Subject: New page-merge-mm, page-merge-stk tests. X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7eb9f6e1fa81807ee7cc381047077f8ff98d1d68;p=pintos-anon New page-merge-mm, page-merge-stk tests. Thanks to Godmar Back for suggestion. --- diff --git a/src/tests/vm/Make.tests b/src/tests/vm/Make.tests index a2427a1..04b1b81 100644 --- a/src/tests/vm/Make.tests +++ b/src/tests/vm/Make.tests @@ -3,13 +3,14 @@ tests/vm_TESTS = $(addprefix tests/vm/,pt-grow-stack pt-grow-pusha \ pt-grow-bad pt-big-stk-obj pt-bad-addr pt-bad-read pt-write-code \ pt-write-code2 pt-grow-stk-sc page-linear page-parallel page-merge-seq \ -page-merge-par page-shuffle mmap-read mmap-close mmap-unmap \ -mmap-overlap mmap-twice mmap-write mmap-exit mmap-shuffle mmap-bad-fd \ -mmap-clean mmap-inherit mmap-misalign mmap-null mmap-over-code \ -mmap-over-data mmap-over-stk mmap-remove mmap-zero) +page-merge-par page-merge-stk page-merge-mm page-shuffle mmap-read \ +mmap-close mmap-unmap mmap-overlap mmap-twice mmap-write mmap-exit \ +mmap-shuffle mmap-bad-fd mmap-clean mmap-inherit mmap-misalign \ +mmap-null mmap-over-code mmap-over-data mmap-over-stk mmap-remove \ +mmap-zero) tests/vm_PROGS = $(tests/vm_TESTS) $(addprefix tests/vm/,child-linear \ -child-sort child-mm-wrt child-inherit) +child-sort child-qsort child-qsort-mm child-mm-wrt child-inherit) tests/vm/pt-grow-stack_SRC = tests/vm/pt-grow-stack.c tests/arc4.c \ tests/cksum.c tests/lib.c tests/main.c @@ -28,8 +29,12 @@ tests/lib.c tests/main.c tests/vm/page-parallel_SRC = tests/vm/page-parallel.c tests/lib.c tests/main.c tests/vm/page-merge-seq_SRC = tests/vm/page-merge-seq.c tests/arc4.c \ tests/lib.c tests/main.c -tests/vm/page-merge-par_SRC = tests/vm/page-merge-par.c tests/arc4.c \ -tests/lib.c tests/main.c +tests/vm/page-merge-par_SRC = tests/vm/page-merge-par.c \ +tests/vm/parallel-merge.c tests/arc4.c tests/lib.c tests/main.c +tests/vm/page-merge-stk_SRC = tests/vm/page-merge-stk.c \ +tests/vm/parallel-merge.c tests/arc4.c tests/lib.c tests/main.c +tests/vm/page-merge-mm_SRC = tests/vm/page-merge-mm.c \ +tests/vm/parallel-merge.c tests/arc4.c tests/lib.c tests/main.c tests/vm/page-shuffle_SRC = tests/vm/page-shuffle.c tests/arc4.c \ tests/cksum.c tests/lib.c tests/main.c tests/vm/mmap-read_SRC = tests/vm/mmap-read.c tests/lib.c tests/main.c @@ -56,6 +61,9 @@ tests/vm/mmap-remove_SRC = tests/vm/mmap-remove.c tests/lib.c tests/main.c tests/vm/mmap-zero_SRC = tests/vm/mmap-zero.c tests/lib.c tests/main.c tests/vm/child-linear_SRC = tests/vm/child-linear.c tests/arc4.c tests/lib.c +tests/vm/child-qsort_SRC = tests/vm/child-qsort.c tests/vm/qsort.c tests/lib.c +tests/vm/child-qsort-mm_SRC = tests/vm/child-qsort-mm.c tests/vm/qsort.c \ +tests/lib.c tests/vm/child-sort_SRC = tests/vm/child-sort.c tests/lib.c tests/vm/child-mm-wrt_SRC = tests/vm/child-mm-wrt.c tests/lib.c tests/main.c tests/vm/child-inherit_SRC = tests/vm/child-inherit.c tests/lib.c tests/main.c @@ -71,6 +79,8 @@ tests/vm/mmap-exit_PUTFILES = tests/vm/child-mm-wrt tests/vm/page-parallel_PUTFILES = tests/vm/child-linear tests/vm/page-merge-seq_PUTFILES = tests/vm/child-sort tests/vm/page-merge-par_PUTFILES = tests/vm/child-sort +tests/vm/page-merge-stk_PUTFILES = tests/vm/child-qsort +tests/vm/page-merge-mm_PUTFILES = tests/vm/child-qsort-mm tests/vm/mmap-clean_PUTFILES = tests/vm/sample.txt tests/vm/mmap-inherit_PUTFILES = tests/vm/sample.txt tests/vm/child-inherit tests/vm/mmap-misalign_PUTFILES = tests/vm/sample.txt diff --git a/src/tests/vm/Rubric.functionality b/src/tests/vm/Rubric.functionality index a27ad1a..8338e7f 100644 --- a/src/tests/vm/Rubric.functionality +++ b/src/tests/vm/Rubric.functionality @@ -11,6 +11,8 @@ Functionality of virtual memory subsystem: 3 page-shuffle 5 page-merge-seq 5 page-merge-par +5 page-merge-mm +5 page-merge-stk - Test "mmap" system call. 2 mmap-read diff --git a/src/tests/vm/child-qsort-mm.c b/src/tests/vm/child-qsort-mm.c new file mode 100644 index 0000000..db45499 --- /dev/null +++ b/src/tests/vm/child-qsort-mm.c @@ -0,0 +1,25 @@ +/* Mmaps a 128 kB file "sorts" the bytes in it, using quick sort, + a multi-pass divide and conquer algorithm. */ + +#include +#include +#include "tests/lib.h" +#include "tests/main.h" +#include "tests/vm/qsort.h" + +const char *test_name = "child-qsort-mm"; + +int +main (int argc UNUSED, char *argv[]) +{ + int handle; + unsigned char *p = (unsigned char *) 0x10000000; + + quiet = true; + + CHECK ((handle = open (argv[1])) > 1, "open \"%s\"", argv[1]); + CHECK (mmap (handle, p) != MAP_FAILED, "mmap \"%s\"", argv[1]); + qsort_bytes (p, 1024 * 128); + + return 80; +} diff --git a/src/tests/vm/child-qsort.c b/src/tests/vm/child-qsort.c new file mode 100644 index 0000000..355f4eb --- /dev/null +++ b/src/tests/vm/child-qsort.c @@ -0,0 +1,32 @@ +/* Reads a 128 kB file onto the stack and "sorts" the bytes in + it, using quick sort, a multi-pass divide and conquer + algorithm. The sorted data is written back to the same file + in-place. */ + +#include +#include +#include "tests/lib.h" +#include "tests/main.h" +#include "tests/vm/qsort.h" + +const char *test_name = "child-qsort"; + +int +main (int argc UNUSED, char *argv[]) +{ + int handle; + unsigned char buf[128 * 1024]; + size_t size; + + quiet = true; + + CHECK ((handle = open (argv[1])) > 1, "open \"%s\"", argv[1]); + + size = read (handle, buf, sizeof buf); + qsort_bytes (buf, sizeof buf); + seek (handle, 0); + write (handle, buf, size); + close (handle); + + return 72; +} diff --git a/src/tests/vm/child-sort.c b/src/tests/vm/child-sort.c index d755432..dff2c77 100644 --- a/src/tests/vm/child-sort.c +++ b/src/tests/vm/child-sort.c @@ -1,6 +1,6 @@ -/* Reads a 128 kB file and "sorts" the bytes in it, using - counting sort. The sorted data is written back to the same - file in-place. */ +/* Reads a 128 kB file into static data and "sorts" the bytes in + it, using counting sort, a single-pass algorithm. The sorted + data is written back to the same file in-place. */ #include #include diff --git a/src/tests/vm/page-merge-mm.c b/src/tests/vm/page-merge-mm.c new file mode 100644 index 0000000..908c71c --- /dev/null +++ b/src/tests/vm/page-merge-mm.c @@ -0,0 +1,8 @@ +#include "tests/main.h" +#include "tests/vm/parallel-merge.h" + +void +test_main (void) +{ + parallel_merge ("child-qsort-mm", 80); +} diff --git a/src/tests/vm/page-merge-mm.ck b/src/tests/vm/page-merge-mm.ck new file mode 100644 index 0000000..74fa980 --- /dev/null +++ b/src/tests/vm/page-merge-mm.ck @@ -0,0 +1,29 @@ +# -*- perl -*- +use strict; +use warnings; +use tests::tests; +check_expected (IGNORE_EXIT_CODES => 1, [<<'EOF']); +(page-merge-mm) begin +(page-merge-mm) init +(page-merge-mm) sort chunk 0 +(page-merge-mm) sort chunk 1 +(page-merge-mm) sort chunk 2 +(page-merge-mm) sort chunk 3 +(page-merge-mm) sort chunk 4 +(page-merge-mm) sort chunk 5 +(page-merge-mm) sort chunk 6 +(page-merge-mm) sort chunk 7 +(page-merge-mm) wait for child 0 +(page-merge-mm) wait for child 1 +(page-merge-mm) wait for child 2 +(page-merge-mm) wait for child 3 +(page-merge-mm) wait for child 4 +(page-merge-mm) wait for child 5 +(page-merge-mm) wait for child 6 +(page-merge-mm) wait for child 7 +(page-merge-mm) merge +(page-merge-mm) verify +(page-merge-mm) success, buf_idx=1,048,576 +(page-merge-mm) end +EOF +pass; diff --git a/src/tests/vm/page-merge-par.c b/src/tests/vm/page-merge-par.c index d588bb0..e7e1609 100644 --- a/src/tests/vm/page-merge-par.c +++ b/src/tests/vm/page-merge-par.c @@ -1,147 +1,8 @@ -/* Generates about 1 MB of random data that is then divided into - 16 chunks. A separate subprocess sorts each chunk; the - subprocesses run in parallel. Then we merge the chunks and - verify that the result is what it should be. */ - -#include -#include -#include "tests/arc4.h" -#include "tests/lib.h" #include "tests/main.h" - -#define CHUNK_SIZE (128 * 1024) -#define CHUNK_CNT 8 /* Number of chunks. */ -#define DATA_SIZE (CHUNK_CNT * CHUNK_SIZE) /* Buffer size. */ - -unsigned char buf1[DATA_SIZE], buf2[DATA_SIZE]; -size_t histogram[256]; - -/* Initialize buf1 with random data, - then count the number of instances of each value within it. */ -static void -init (void) -{ - struct arc4 arc4; - size_t i; - - msg ("init"); - - arc4_init (&arc4, "foobar", 6); - arc4_crypt (&arc4, buf1, sizeof buf1); - for (i = 0; i < sizeof buf1; i++) - histogram[buf1[i]]++; -} - -/* Sort each chunk of buf1 using a subprocess. */ -static void -sort_chunks (void) -{ - pid_t children[CHUNK_CNT]; - size_t i; - - for (i = 0; i < CHUNK_CNT; i++) - { - char fn[128]; - char cmd[128]; - int handle; - - msg ("sort chunk %zu", i); - - /* Write this chunk to a file. */ - snprintf (fn, sizeof fn, "buf%zu", i); - create (fn, CHUNK_SIZE); - quiet = true; - CHECK ((handle = open (fn)) > 1, "open \"%s\"", fn); - write (handle, buf1 + CHUNK_SIZE * i, CHUNK_SIZE); - close (handle); - - /* Sort with subprocess. */ - snprintf (cmd, sizeof cmd, "child-sort %s", fn); - CHECK ((children[i] = exec (cmd)) != -1, "exec \"%s\"", cmd); - quiet = false; - } - - for (i = 0; i < CHUNK_CNT; i++) - { - char fn[128]; - int handle; - - CHECK (wait (children[i]) == 123, "wait for child %zu", i); - - /* Read chunk back from file. */ - quiet = true; - snprintf (fn, sizeof fn, "buf%zu", i); - CHECK ((handle = open (fn)) > 1, "open \"%s\"", fn); - read (handle, buf1 + CHUNK_SIZE * i, CHUNK_SIZE); - close (handle); - quiet = false; - } -} - -/* Merge the sorted chunks in buf1 into a fully sorted buf2. */ -static void -merge (void) -{ - unsigned char *mp[CHUNK_CNT]; - size_t mp_left; - unsigned char *op; - size_t i; - - msg ("merge"); - - /* Initialize merge pointers. */ - mp_left = CHUNK_CNT; - for (i = 0; i < CHUNK_CNT; i++) - mp[i] = buf1 + CHUNK_SIZE * i; - - /* Merge. */ - op = buf2; - while (mp_left > 0) - { - /* Find smallest value. */ - size_t min = 0; - for (i = 1; i < mp_left; i++) - if (*mp[i] < *mp[min]) - min = i; - - /* Append value to buf2. */ - *op++ = *mp[min]; - - /* Advance merge pointer. - Delete this chunk from the set if it's emptied. */ - if ((++mp[min] - buf1) % CHUNK_SIZE == 0) - mp[min] = mp[--mp_left]; - } -} - -static void -verify (void) -{ - size_t buf_idx; - size_t hist_idx; - - msg ("verify"); - - buf_idx = 0; - for (hist_idx = 0; hist_idx < sizeof histogram / sizeof *histogram; - hist_idx++) - { - while (histogram[hist_idx]-- > 0) - { - if (buf2[buf_idx] != hist_idx) - fail ("bad value %d in byte %zu", buf2[buf_idx], buf_idx); - buf_idx++; - } - } - - msg ("success, buf_idx=%'zu", buf_idx); -} +#include "tests/vm/parallel-merge.h" void -test_main (void) +test_main (void) { - init (); - sort_chunks (); - merge (); - verify (); + parallel_merge ("child-sort", 123); } diff --git a/src/tests/vm/page-merge-stk.c b/src/tests/vm/page-merge-stk.c new file mode 100644 index 0000000..5eb1069 --- /dev/null +++ b/src/tests/vm/page-merge-stk.c @@ -0,0 +1,8 @@ +#include "tests/main.h" +#include "tests/vm/parallel-merge.h" + +void +test_main (void) +{ + parallel_merge ("child-qsort", 72); +} diff --git a/src/tests/vm/page-merge-stk.ck b/src/tests/vm/page-merge-stk.ck new file mode 100644 index 0000000..c5bc1ae --- /dev/null +++ b/src/tests/vm/page-merge-stk.ck @@ -0,0 +1,29 @@ +# -*- perl -*- +use strict; +use warnings; +use tests::tests; +check_expected (IGNORE_EXIT_CODES => 1, [<<'EOF']); +(page-merge-stk) begin +(page-merge-stk) init +(page-merge-stk) sort chunk 0 +(page-merge-stk) sort chunk 1 +(page-merge-stk) sort chunk 2 +(page-merge-stk) sort chunk 3 +(page-merge-stk) sort chunk 4 +(page-merge-stk) sort chunk 5 +(page-merge-stk) sort chunk 6 +(page-merge-stk) sort chunk 7 +(page-merge-stk) wait for child 0 +(page-merge-stk) wait for child 1 +(page-merge-stk) wait for child 2 +(page-merge-stk) wait for child 3 +(page-merge-stk) wait for child 4 +(page-merge-stk) wait for child 5 +(page-merge-stk) wait for child 6 +(page-merge-stk) wait for child 7 +(page-merge-stk) merge +(page-merge-stk) verify +(page-merge-stk) success, buf_idx=1,048,576 +(page-merge-stk) end +EOF +pass; diff --git a/src/tests/vm/parallel-merge.c b/src/tests/vm/parallel-merge.c new file mode 100644 index 0000000..cc09bb1 --- /dev/null +++ b/src/tests/vm/parallel-merge.c @@ -0,0 +1,149 @@ +/* Generates about 1 MB of random data that is then divided into + 16 chunks. A separate subprocess sorts each chunk; the + subprocesses run in parallel. Then we merge the chunks and + verify that the result is what it should be. */ + +#include "tests/vm/parallel-merge.h" +#include +#include +#include "tests/arc4.h" +#include "tests/lib.h" +#include "tests/main.h" + +#define CHUNK_SIZE (128 * 1024) +#define CHUNK_CNT 8 /* Number of chunks. */ +#define DATA_SIZE (CHUNK_CNT * CHUNK_SIZE) /* Buffer size. */ + +unsigned char buf1[DATA_SIZE], buf2[DATA_SIZE]; +size_t histogram[256]; + +/* Initialize buf1 with random data, + then count the number of instances of each value within it. */ +static void +init (void) +{ + struct arc4 arc4; + size_t i; + + msg ("init"); + + arc4_init (&arc4, "foobar", 6); + arc4_crypt (&arc4, buf1, sizeof buf1); + for (i = 0; i < sizeof buf1; i++) + histogram[buf1[i]]++; +} + +/* Sort each chunk of buf1 using SUBPROCESS, + which is expected to return EXIT_STATUS. */ +static void +sort_chunks (const char *subprocess, int exit_status) +{ + pid_t children[CHUNK_CNT]; + size_t i; + + for (i = 0; i < CHUNK_CNT; i++) + { + char fn[128]; + char cmd[128]; + int handle; + + msg ("sort chunk %zu", i); + + /* Write this chunk to a file. */ + snprintf (fn, sizeof fn, "buf%zu", i); + create (fn, CHUNK_SIZE); + quiet = true; + CHECK ((handle = open (fn)) > 1, "open \"%s\"", fn); + write (handle, buf1 + CHUNK_SIZE * i, CHUNK_SIZE); + close (handle); + + /* Sort with subprocess. */ + snprintf (cmd, sizeof cmd, "%s %s", subprocess, fn); + CHECK ((children[i] = exec (cmd)) != -1, "exec \"%s\"", cmd); + quiet = false; + } + + for (i = 0; i < CHUNK_CNT; i++) + { + char fn[128]; + int handle; + + CHECK (wait (children[i]) == exit_status, "wait for child %zu", i); + + /* Read chunk back from file. */ + quiet = true; + snprintf (fn, sizeof fn, "buf%zu", i); + CHECK ((handle = open (fn)) > 1, "open \"%s\"", fn); + read (handle, buf1 + CHUNK_SIZE * i, CHUNK_SIZE); + close (handle); + quiet = false; + } +} + +/* Merge the sorted chunks in buf1 into a fully sorted buf2. */ +static void +merge (void) +{ + unsigned char *mp[CHUNK_CNT]; + size_t mp_left; + unsigned char *op; + size_t i; + + msg ("merge"); + + /* Initialize merge pointers. */ + mp_left = CHUNK_CNT; + for (i = 0; i < CHUNK_CNT; i++) + mp[i] = buf1 + CHUNK_SIZE * i; + + /* Merge. */ + op = buf2; + while (mp_left > 0) + { + /* Find smallest value. */ + size_t min = 0; + for (i = 1; i < mp_left; i++) + if (*mp[i] < *mp[min]) + min = i; + + /* Append value to buf2. */ + *op++ = *mp[min]; + + /* Advance merge pointer. + Delete this chunk from the set if it's emptied. */ + if ((++mp[min] - buf1) % CHUNK_SIZE == 0) + mp[min] = mp[--mp_left]; + } +} + +static void +verify (void) +{ + size_t buf_idx; + size_t hist_idx; + + msg ("verify"); + + buf_idx = 0; + for (hist_idx = 0; hist_idx < sizeof histogram / sizeof *histogram; + hist_idx++) + { + while (histogram[hist_idx]-- > 0) + { + if (buf2[buf_idx] != hist_idx) + fail ("bad value %d in byte %zu", buf2[buf_idx], buf_idx); + buf_idx++; + } + } + + msg ("success, buf_idx=%'zu", buf_idx); +} + +void +parallel_merge (const char *child_name, int exit_status) +{ + init (); + sort_chunks (child_name, exit_status); + merge (); + verify (); +} diff --git a/src/tests/vm/parallel-merge.h b/src/tests/vm/parallel-merge.h new file mode 100644 index 0000000..a6b6431 --- /dev/null +++ b/src/tests/vm/parallel-merge.h @@ -0,0 +1,6 @@ +#ifndef TESTS_VM_PARALLEL_MERGE +#define TESTS_VM_PARALLEL_MERGE 1 + +void parallel_merge (const char *child_name, int exit_status); + +#endif /* tests/vm/parallel-merge.h */ diff --git a/src/tests/vm/qsort.c b/src/tests/vm/qsort.c new file mode 100644 index 0000000..922572c --- /dev/null +++ b/src/tests/vm/qsort.c @@ -0,0 +1,136 @@ +#include "tests/vm/qsort.h" +#include +#include +#include + +/* Picks a pivot for the quicksort from the SIZE bytes in BUF. */ +static unsigned char +pick_pivot (unsigned char *buf, size_t size) +{ + ASSERT (size >= 1); + return buf[random_ulong () % size]; +} + +/* Checks whether the SIZE bytes in ARRAY are divided into an + initial LEFT_SIZE elements all less than PIVOT followed by + SIZE - LEFT_SIZE elements all greater than or equal to + PIVOT. */ +static bool +is_partitioned (const unsigned char *array, size_t size, + unsigned char pivot, size_t left_size) +{ + size_t i; + + for (i = 0; i < left_size; i++) + if (array[i] >= pivot) + return false; + + for (; i < size; i++) + if (array[i] < pivot) + return false; + + return true; +} + +/* Swaps the bytes at *A and *B. */ +static void +swap (unsigned char *a, unsigned char *b) +{ + unsigned char t = *a; + *a = *b; + *b = t; +} + +/* Partitions ARRAY in-place in an initial run of bytes all less + than PIVOT, followed by a run of bytes all greater than or + equal to PIVOT. Returns the length of the initial run. */ +static size_t +partition (unsigned char *array, size_t size, int pivot) +{ + size_t left_size = size; + unsigned char *first = array; + unsigned char *last = first + left_size; + + for (;;) + { + /* Move FIRST forward to point to first element greater than + PIVOT. */ + for (;;) + { + if (first == last) + { + ASSERT (is_partitioned (array, size, pivot, left_size)); + return left_size; + } + else if (*first >= pivot) + break; + + first++; + } + left_size--; + + /* Move LAST backward to point to last element no bigger + than PIVOT. */ + for (;;) + { + last--; + + if (first == last) + { + ASSERT (is_partitioned (array, size, pivot, left_size)); + return left_size; + } + else if (*last < pivot) + break; + else + left_size--; + } + + /* By swapping FIRST and LAST we extend the starting and + ending sequences that pass and fail, respectively, + PREDICATE. */ + swap (first, last); + first++; + } +} + +/* Returns true if the SIZE bytes in BUF are in nondecreasing + order, false otherwise. */ +static bool +is_sorted (const unsigned char *buf, size_t size) +{ + size_t i; + + for (i = 1; i < size; i++) + if (buf[i - 1] > buf[i]) + return false; + + return true; +} + +/* Sorts the SIZE bytes in BUF into nondecreasing order, using + the quick-sort algorithm. */ +void +qsort_bytes (unsigned char *buf, size_t size) +{ + if (!is_sorted (buf, size)) + { + int pivot = pick_pivot (buf, size); + + unsigned char *left_half = buf; + size_t left_size = partition (buf, size, pivot); + unsigned char *right_half = left_half + left_size; + size_t right_size = size - left_size; + + if (left_size <= right_size) + { + qsort_bytes (left_half, left_size); + qsort_bytes (right_half, right_size); + } + else + { + qsort_bytes (right_half, right_size); + qsort_bytes (left_half, left_size); + } + } +} diff --git a/src/tests/vm/qsort.h b/src/tests/vm/qsort.h new file mode 100644 index 0000000..61b65f3 --- /dev/null +++ b/src/tests/vm/qsort.h @@ -0,0 +1,8 @@ +#ifndef TESTS_VM_QSORT_H +#define TESTS_VM_QSORT_H 1 + +#include + +void qsort_bytes (unsigned char *buf, size_t size); + +#endif /* tests/vm/qsort.h */