diff options
Diffstat (limited to 'pintos-progos/tests/threads')
59 files changed, 2865 insertions, 0 deletions
diff --git a/pintos-progos/tests/threads/Grading b/pintos-progos/tests/threads/Grading new file mode 100644 index 0000000..cc235f2 --- /dev/null +++ b/pintos-progos/tests/threads/Grading | |||
| @@ -0,0 +1,11 @@ | |||
| 1 | # Percentage of the testing point total designated for each set of | ||
| 2 | # tests. | ||
| 3 | |||
| 4 | # Priority Scheduling | ||
| 5 | 90.0% tests/threads/Rubric.priority | ||
| 6 | |||
| 7 | # Robustness | ||
| 8 | 10.0% tests/threads/Rubric.alarm | ||
| 9 | |||
| 10 | # Not used in SS 2012 | ||
| 11 | # XX.0% tests/threads/Rubric.mlfqs | ||
diff --git a/pintos-progos/tests/threads/Make.tests b/pintos-progos/tests/threads/Make.tests new file mode 100644 index 0000000..dbdfd0c --- /dev/null +++ b/pintos-progos/tests/threads/Make.tests | |||
| @@ -0,0 +1,56 @@ | |||
| 1 | # -*- makefile -*- | ||
| 2 | |||
| 3 | # Test names. | ||
| 4 | tests/threads_TESTS = $(addprefix tests/threads/,alarm-single \ | ||
| 5 | alarm-multiple alarm-simultaneous alarm-priority alarm-zero \ | ||
| 6 | alarm-negative priority-change priority-donate-one \ | ||
| 7 | priority-donate-multiple priority-donate-multiple2 \ | ||
| 8 | priority-donate-nest priority-donate-sema priority-donate-lower \ | ||
| 9 | priority-fifo priority-preempt priority-sema priority-condvar \ | ||
| 10 | priority-donate-chain) | ||
| 11 | |||
| 12 | |||
| 13 | # Sources for tests. | ||
| 14 | tests/threads_SRC = tests/threads/tests.c | ||
| 15 | tests/threads_SRC += tests/threads/alarm-wait.c | ||
| 16 | tests/threads_SRC += tests/threads/alarm-simultaneous.c | ||
| 17 | tests/threads_SRC += tests/threads/alarm-priority.c | ||
| 18 | tests/threads_SRC += tests/threads/alarm-zero.c | ||
| 19 | tests/threads_SRC += tests/threads/alarm-negative.c | ||
| 20 | tests/threads_SRC += tests/threads/priority-change.c | ||
| 21 | tests/threads_SRC += tests/threads/priority-donate-one.c | ||
| 22 | tests/threads_SRC += tests/threads/priority-donate-multiple.c | ||
| 23 | tests/threads_SRC += tests/threads/priority-donate-multiple2.c | ||
| 24 | tests/threads_SRC += tests/threads/priority-donate-nest.c | ||
| 25 | tests/threads_SRC += tests/threads/priority-donate-sema.c | ||
| 26 | tests/threads_SRC += tests/threads/priority-donate-lower.c | ||
| 27 | tests/threads_SRC += tests/threads/priority-fifo.c | ||
| 28 | tests/threads_SRC += tests/threads/priority-preempt.c | ||
| 29 | tests/threads_SRC += tests/threads/priority-sema.c | ||
| 30 | tests/threads_SRC += tests/threads/priority-condvar.c | ||
| 31 | tests/threads_SRC += tests/threads/priority-donate-chain.c | ||
| 32 | |||
| 33 | # Not used in SS 2012 | ||
| 34 | MLFQS_TESTS = mlfqs-load-1 mlfqs-load-60 mlfqs-load-avg mlfqs-recent-1 \ | ||
| 35 | mlfqs-fair-2 mlfqs-fair-20 mlfqs-nice-2 mlfqs-nice-10 mlfqs-block) | ||
| 36 | |||
| 37 | tests/threads_SRC += tests/threads/mlfqs-load-1.c | ||
| 38 | tests/threads_SRC += tests/threads/mlfqs-load-60.c | ||
| 39 | tests/threads_SRC += tests/threads/mlfqs-load-avg.c | ||
| 40 | tests/threads_SRC += tests/threads/mlfqs-recent-1.c | ||
| 41 | tests/threads_SRC += tests/threads/mlfqs-fair.c | ||
| 42 | tests/threads_SRC += tests/threads/mlfqs-block.c | ||
| 43 | |||
| 44 | MLFQS_OUTPUTS = \ | ||
| 45 | tests/threads/mlfqs-load-1.output \ | ||
| 46 | tests/threads/mlfqs-load-60.output \ | ||
| 47 | tests/threads/mlfqs-load-avg.output \ | ||
| 48 | tests/threads/mlfqs-recent-1.output \ | ||
| 49 | tests/threads/mlfqs-fair-2.output \ | ||
| 50 | tests/threads/mlfqs-fair-20.output \ | ||
| 51 | tests/threads/mlfqs-nice-2.output \ | ||
| 52 | tests/threads/mlfqs-nice-10.output \ | ||
| 53 | tests/threads/mlfqs-block.output | ||
| 54 | |||
| 55 | $(MLFQS_OUTPUTS): KERNELFLAGS += -mlfqs | ||
| 56 | $(MLFQS_OUTPUTS): TIMEOUT = 480 | ||
diff --git a/pintos-progos/tests/threads/Rubric.alarm b/pintos-progos/tests/threads/Rubric.alarm new file mode 100644 index 0000000..61abe85 --- /dev/null +++ b/pintos-progos/tests/threads/Rubric.alarm | |||
| @@ -0,0 +1,8 @@ | |||
| 1 | Functionality and robustness of alarm clock: | ||
| 2 | 4 alarm-single | ||
| 3 | 4 alarm-multiple | ||
| 4 | 4 alarm-simultaneous | ||
| 5 | 4 alarm-priority | ||
| 6 | |||
| 7 | 1 alarm-zero | ||
| 8 | 1 alarm-negative | ||
diff --git a/pintos-progos/tests/threads/Rubric.mlfqs b/pintos-progos/tests/threads/Rubric.mlfqs new file mode 100644 index 0000000..f260091 --- /dev/null +++ b/pintos-progos/tests/threads/Rubric.mlfqs | |||
| @@ -0,0 +1,14 @@ | |||
| 1 | Functionality of advanced scheduler: | ||
| 2 | 5 mlfqs-load-1 | ||
| 3 | 5 mlfqs-load-60 | ||
| 4 | 3 mlfqs-load-avg | ||
| 5 | |||
| 6 | 5 mlfqs-recent-1 | ||
| 7 | |||
| 8 | 5 mlfqs-fair-2 | ||
| 9 | 3 mlfqs-fair-20 | ||
| 10 | |||
| 11 | 4 mlfqs-nice-2 | ||
| 12 | 2 mlfqs-nice-10 | ||
| 13 | |||
| 14 | 5 mlfqs-block | ||
diff --git a/pintos-progos/tests/threads/Rubric.priority b/pintos-progos/tests/threads/Rubric.priority new file mode 100644 index 0000000..652bc99 --- /dev/null +++ b/pintos-progos/tests/threads/Rubric.priority | |||
| @@ -0,0 +1,15 @@ | |||
| 1 | Functionality of priority scheduler: | ||
| 2 | 3 priority-change | ||
| 3 | 3 priority-preempt | ||
| 4 | |||
| 5 | 3 priority-fifo | ||
| 6 | 3 priority-sema | ||
| 7 | 3 priority-condvar | ||
| 8 | |||
| 9 | 3 priority-donate-one | ||
| 10 | 3 priority-donate-multiple | ||
| 11 | 3 priority-donate-multiple2 | ||
| 12 | 3 priority-donate-nest | ||
| 13 | 5 priority-donate-chain | ||
| 14 | 3 priority-donate-sema | ||
| 15 | 3 priority-donate-lower | ||
diff --git a/pintos-progos/tests/threads/alarm-multiple.ck b/pintos-progos/tests/threads/alarm-multiple.ck new file mode 100644 index 0000000..fd83bcd --- /dev/null +++ b/pintos-progos/tests/threads/alarm-multiple.ck | |||
| @@ -0,0 +1,4 @@ | |||
| 1 | # -*- perl -*- | ||
| 2 | use tests::tests; | ||
| 3 | use tests::threads::alarm; | ||
| 4 | check_alarm (7); | ||
diff --git a/pintos-progos/tests/threads/alarm-negative.c b/pintos-progos/tests/threads/alarm-negative.c new file mode 100644 index 0000000..aec52cf --- /dev/null +++ b/pintos-progos/tests/threads/alarm-negative.c | |||
| @@ -0,0 +1,15 @@ | |||
| 1 | /* Tests timer_sleep(-100). Only requirement is that it not crash. */ | ||
| 2 | |||
| 3 | #include <stdio.h> | ||
| 4 | #include "tests/threads/tests.h" | ||
| 5 | #include "threads/malloc.h" | ||
| 6 | #include "threads/synch.h" | ||
| 7 | #include "threads/thread.h" | ||
| 8 | #include "devices/timer.h" | ||
| 9 | |||
| 10 | void | ||
| 11 | test_alarm_negative (void) | ||
| 12 | { | ||
| 13 | timer_sleep (-100); | ||
| 14 | pass (); | ||
| 15 | } | ||
diff --git a/pintos-progos/tests/threads/alarm-negative.ck b/pintos-progos/tests/threads/alarm-negative.ck new file mode 100644 index 0000000..0d2bab0 --- /dev/null +++ b/pintos-progos/tests/threads/alarm-negative.ck | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | # -*- perl -*- | ||
| 2 | use strict; | ||
| 3 | use warnings; | ||
| 4 | use tests::tests; | ||
| 5 | check_expected ([<<'EOF']); | ||
| 6 | (alarm-negative) begin | ||
| 7 | (alarm-negative) PASS | ||
| 8 | (alarm-negative) end | ||
| 9 | EOF | ||
| 10 | pass; | ||
diff --git a/pintos-progos/tests/threads/alarm-priority.c b/pintos-progos/tests/threads/alarm-priority.c new file mode 100644 index 0000000..2288ff6 --- /dev/null +++ b/pintos-progos/tests/threads/alarm-priority.c | |||
| @@ -0,0 +1,58 @@ | |||
| 1 | /* Checks that when the alarm clock wakes up threads, the | ||
| 2 | higher-priority threads run first. */ | ||
| 3 | |||
| 4 | #include <stdio.h> | ||
| 5 | #include "tests/threads/tests.h" | ||
| 6 | #include "threads/init.h" | ||
| 7 | #include "threads/malloc.h" | ||
| 8 | #include "threads/synch.h" | ||
| 9 | #include "threads/thread.h" | ||
| 10 | #include "devices/timer.h" | ||
| 11 | |||
| 12 | static thread_func alarm_priority_thread; | ||
| 13 | static int64_t wake_time; | ||
| 14 | static struct semaphore wait_sema; | ||
| 15 | |||
| 16 | void | ||
| 17 | test_alarm_priority (void) | ||
| 18 | { | ||
| 19 | int i; | ||
| 20 | |||
| 21 | /* This test does not work with the MLFQS. */ | ||
| 22 | ASSERT (!thread_mlfqs); | ||
| 23 | |||
| 24 | wake_time = timer_ticks () + 5 * TIMER_FREQ; | ||
| 25 | sema_init (&wait_sema, 0); | ||
| 26 | |||
| 27 | for (i = 0; i < 10; i++) | ||
| 28 | { | ||
| 29 | int priority = PRI_DEFAULT - (i + 5) % 10 - 1; | ||
| 30 | char name[16]; | ||
| 31 | snprintf (name, sizeof name, "priority %d", priority); | ||
| 32 | thread_create (name, priority, alarm_priority_thread, NULL); | ||
| 33 | } | ||
| 34 | |||
| 35 | thread_set_priority (PRI_MIN); | ||
| 36 | |||
| 37 | for (i = 0; i < 10; i++) | ||
| 38 | sema_down (&wait_sema); | ||
| 39 | } | ||
| 40 | |||
| 41 | static void | ||
| 42 | alarm_priority_thread (void *aux UNUSED) | ||
| 43 | { | ||
| 44 | /* Busy-wait until the current time changes. */ | ||
| 45 | int64_t start_time = timer_ticks (); | ||
| 46 | while (timer_elapsed (start_time) == 0) | ||
| 47 | continue; | ||
| 48 | |||
| 49 | /* Now we know we're at the very beginning of a timer tick, so | ||
| 50 | we can call timer_sleep() without worrying about races | ||
| 51 | between checking the time and a timer interrupt. */ | ||
| 52 | timer_sleep (wake_time - timer_ticks ()); | ||
| 53 | |||
| 54 | /* Print a message on wake-up. */ | ||
| 55 | msg ("Thread %s woke up.", thread_name ()); | ||
| 56 | |||
| 57 | sema_up (&wait_sema); | ||
| 58 | } | ||
diff --git a/pintos-progos/tests/threads/alarm-priority.ck b/pintos-progos/tests/threads/alarm-priority.ck new file mode 100644 index 0000000..b57c78b --- /dev/null +++ b/pintos-progos/tests/threads/alarm-priority.ck | |||
| @@ -0,0 +1,19 @@ | |||
| 1 | # -*- perl -*- | ||
| 2 | use strict; | ||
| 3 | use warnings; | ||
| 4 | use tests::tests; | ||
| 5 | check_expected ([<<'EOF']); | ||
| 6 | (alarm-priority) begin | ||
| 7 | (alarm-priority) Thread priority 30 woke up. | ||
| 8 | (alarm-priority) Thread priority 29 woke up. | ||
| 9 | (alarm-priority) Thread priority 28 woke up. | ||
| 10 | (alarm-priority) Thread priority 27 woke up. | ||
| 11 | (alarm-priority) Thread priority 26 woke up. | ||
| 12 | (alarm-priority) Thread priority 25 woke up. | ||
| 13 | (alarm-priority) Thread priority 24 woke up. | ||
| 14 | (alarm-priority) Thread priority 23 woke up. | ||
| 15 | (alarm-priority) Thread priority 22 woke up. | ||
| 16 | (alarm-priority) Thread priority 21 woke up. | ||
| 17 | (alarm-priority) end | ||
| 18 | EOF | ||
| 19 | pass; | ||
diff --git a/pintos-progos/tests/threads/alarm-simultaneous.c b/pintos-progos/tests/threads/alarm-simultaneous.c new file mode 100644 index 0000000..844eea4 --- /dev/null +++ b/pintos-progos/tests/threads/alarm-simultaneous.c | |||
| @@ -0,0 +1,94 @@ | |||
| 1 | /* Creates N threads, each of which sleeps a different, fixed | ||
| 2 | duration, M times. Records the wake-up order and verifies | ||
| 3 | that it is valid. */ | ||
| 4 | |||
| 5 | #include <stdio.h> | ||
| 6 | #include "tests/threads/tests.h" | ||
| 7 | #include "threads/init.h" | ||
| 8 | #include "threads/malloc.h" | ||
| 9 | #include "threads/synch.h" | ||
| 10 | #include "threads/thread.h" | ||
| 11 | #include "devices/timer.h" | ||
| 12 | |||
| 13 | static void test_sleep (int thread_cnt, int iterations); | ||
| 14 | |||
| 15 | void | ||
| 16 | test_alarm_simultaneous (void) | ||
| 17 | { | ||
| 18 | test_sleep (3, 5); | ||
| 19 | } | ||
| 20 | |||
| 21 | /* Information about the test. */ | ||
| 22 | struct sleep_test | ||
| 23 | { | ||
| 24 | int64_t start; /* Current time at start of test. */ | ||
| 25 | int iterations; /* Number of iterations per thread. */ | ||
| 26 | int *output_pos; /* Current position in output buffer. */ | ||
| 27 | }; | ||
| 28 | |||
| 29 | static void sleeper (void *); | ||
| 30 | |||
| 31 | /* Runs THREAD_CNT threads thread sleep ITERATIONS times each. */ | ||
| 32 | static void | ||
| 33 | test_sleep (int thread_cnt, int iterations) | ||
| 34 | { | ||
| 35 | struct sleep_test test; | ||
| 36 | int *output; | ||
| 37 | int i; | ||
| 38 | |||
| 39 | /* This test does not work with the MLFQS. */ | ||
| 40 | ASSERT (!thread_mlfqs); | ||
| 41 | |||
| 42 | msg ("Creating %d threads to sleep %d times each.", thread_cnt, iterations); | ||
| 43 | msg ("Each thread sleeps 10 ticks each time."); | ||
| 44 | msg ("Within an iteration, all threads should wake up on the same tick."); | ||
| 45 | |||
| 46 | /* Allocate memory. */ | ||
| 47 | output = malloc (sizeof *output * iterations * thread_cnt * 2); | ||
| 48 | if (output == NULL) | ||
| 49 | PANIC ("couldn't allocate memory for test"); | ||
| 50 | |||
| 51 | /* Initialize test. */ | ||
| 52 | test.start = timer_ticks () + 100; | ||
| 53 | test.iterations = iterations; | ||
| 54 | test.output_pos = output; | ||
| 55 | |||
| 56 | /* Start threads. */ | ||
| 57 | ASSERT (output != NULL); | ||
| 58 | for (i = 0; i < thread_cnt; i++) | ||
| 59 | { | ||
| 60 | char name[16]; | ||
| 61 | snprintf (name, sizeof name, "thread %d", i); | ||
| 62 | thread_create (name, PRI_DEFAULT, sleeper, &test); | ||
| 63 | } | ||
| 64 | |||
| 65 | /* Wait long enough for all the threads to finish. */ | ||
| 66 | timer_sleep (100 + iterations * 10 + 100); | ||
| 67 | |||
| 68 | /* Print completion order. */ | ||
| 69 | msg ("iteration 0, thread 0: woke up after %d ticks", output[0]); | ||
| 70 | for (i = 1; i < test.output_pos - output; i++) | ||
| 71 | msg ("iteration %d, thread %d: woke up %d ticks later", | ||
| 72 | i / thread_cnt, i % thread_cnt, output[i] - output[i - 1]); | ||
| 73 | |||
| 74 | free (output); | ||
| 75 | } | ||
| 76 | |||
| 77 | /* Sleeper thread. */ | ||
| 78 | static void | ||
| 79 | sleeper (void *test_) | ||
| 80 | { | ||
| 81 | struct sleep_test *test = test_; | ||
| 82 | int i; | ||
| 83 | |||
| 84 | /* Make sure we're at the beginning of a timer tick. */ | ||
| 85 | timer_sleep (1); | ||
| 86 | |||
| 87 | for (i = 1; i <= test->iterations; i++) | ||
| 88 | { | ||
| 89 | int64_t sleep_until = test->start + i * 10; | ||
| 90 | timer_sleep (sleep_until - timer_ticks ()); | ||
| 91 | *test->output_pos++ = timer_ticks () - test->start; | ||
| 92 | thread_yield (); | ||
| 93 | } | ||
| 94 | } | ||
diff --git a/pintos-progos/tests/threads/alarm-simultaneous.ck b/pintos-progos/tests/threads/alarm-simultaneous.ck new file mode 100644 index 0000000..406b8b0 --- /dev/null +++ b/pintos-progos/tests/threads/alarm-simultaneous.ck | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | # -*- perl -*- | ||
| 2 | use strict; | ||
| 3 | use warnings; | ||
| 4 | use tests::tests; | ||
| 5 | check_expected ([<<'EOF']); | ||
| 6 | (alarm-simultaneous) begin | ||
| 7 | (alarm-simultaneous) Creating 3 threads to sleep 5 times each. | ||
| 8 | (alarm-simultaneous) Each thread sleeps 10 ticks each time. | ||
| 9 | (alarm-simultaneous) Within an iteration, all threads should wake up on the same tick. | ||
| 10 | (alarm-simultaneous) iteration 0, thread 0: woke up after 10 ticks | ||
| 11 | (alarm-simultaneous) iteration 0, thread 1: woke up 0 ticks later | ||
| 12 | (alarm-simultaneous) iteration 0, thread 2: woke up 0 ticks later | ||
| 13 | (alarm-simultaneous) iteration 1, thread 0: woke up 10 ticks later | ||
| 14 | (alarm-simultaneous) iteration 1, thread 1: woke up 0 ticks later | ||
| 15 | (alarm-simultaneous) iteration 1, thread 2: woke up 0 ticks later | ||
| 16 | (alarm-simultaneous) iteration 2, thread 0: woke up 10 ticks later | ||
| 17 | (alarm-simultaneous) iteration 2, thread 1: woke up 0 ticks later | ||
| 18 | (alarm-simultaneous) iteration 2, thread 2: woke up 0 ticks later | ||
| 19 | (alarm-simultaneous) iteration 3, thread 0: woke up 10 ticks later | ||
| 20 | (alarm-simultaneous) iteration 3, thread 1: woke up 0 ticks later | ||
| 21 | (alarm-simultaneous) iteration 3, thread 2: woke up 0 ticks later | ||
| 22 | (alarm-simultaneous) iteration 4, thread 0: woke up 10 ticks later | ||
| 23 | (alarm-simultaneous) iteration 4, thread 1: woke up 0 ticks later | ||
| 24 | (alarm-simultaneous) iteration 4, thread 2: woke up 0 ticks later | ||
| 25 | (alarm-simultaneous) end | ||
| 26 | EOF | ||
| 27 | pass; | ||
diff --git a/pintos-progos/tests/threads/alarm-single.ck b/pintos-progos/tests/threads/alarm-single.ck new file mode 100644 index 0000000..31215df --- /dev/null +++ b/pintos-progos/tests/threads/alarm-single.ck | |||
| @@ -0,0 +1,4 @@ | |||
| 1 | # -*- perl -*- | ||
| 2 | use tests::tests; | ||
| 3 | use tests::threads::alarm; | ||
| 4 | check_alarm (1); | ||
diff --git a/pintos-progos/tests/threads/alarm-wait.c b/pintos-progos/tests/threads/alarm-wait.c new file mode 100644 index 0000000..37d3afc --- /dev/null +++ b/pintos-progos/tests/threads/alarm-wait.c | |||
| @@ -0,0 +1,152 @@ | |||
| 1 | /* Creates N threads, each of which sleeps a different, fixed | ||
| 2 | duration, M times. Records the wake-up order and verifies | ||
| 3 | that it is valid. */ | ||
| 4 | |||
| 5 | #include <stdio.h> | ||
| 6 | #include "tests/threads/tests.h" | ||
| 7 | #include "threads/init.h" | ||
| 8 | #include "threads/malloc.h" | ||
| 9 | #include "threads/synch.h" | ||
| 10 | #include "threads/thread.h" | ||
| 11 | #include "devices/timer.h" | ||
| 12 | |||
| 13 | static void test_sleep (int thread_cnt, int iterations); | ||
| 14 | |||
| 15 | void | ||
| 16 | test_alarm_single (void) | ||
| 17 | { | ||
| 18 | test_sleep (5, 1); | ||
| 19 | } | ||
| 20 | |||
| 21 | void | ||
| 22 | test_alarm_multiple (void) | ||
| 23 | { | ||
| 24 | test_sleep (5, 7); | ||
| 25 | } | ||
| 26 | |||
| 27 | /* Information about the test. */ | ||
| 28 | struct sleep_test | ||
| 29 | { | ||
| 30 | int64_t start; /* Current time at start of test. */ | ||
| 31 | int iterations; /* Number of iterations per thread. */ | ||
| 32 | |||
| 33 | /* Output. */ | ||
| 34 | struct lock output_lock; /* Lock protecting output buffer. */ | ||
| 35 | int *output_pos; /* Current position in output buffer. */ | ||
| 36 | }; | ||
| 37 | |||
| 38 | /* Information about an individual thread in the test. */ | ||
| 39 | struct sleep_thread | ||
| 40 | { | ||
| 41 | struct sleep_test *test; /* Info shared between all threads. */ | ||
| 42 | int id; /* Sleeper ID. */ | ||
| 43 | int duration; /* Number of ticks to sleep. */ | ||
| 44 | int iterations; /* Iterations counted so far. */ | ||
| 45 | }; | ||
| 46 | |||
| 47 | static void sleeper (void *); | ||
| 48 | |||
| 49 | /* Runs THREAD_CNT threads thread sleep ITERATIONS times each. */ | ||
| 50 | static void | ||
| 51 | test_sleep (int thread_cnt, int iterations) | ||
| 52 | { | ||
| 53 | struct sleep_test test; | ||
| 54 | struct sleep_thread *threads; | ||
| 55 | int *output, *op; | ||
| 56 | int product; | ||
| 57 | int i; | ||
| 58 | |||
| 59 | /* This test does not work with the MLFQS. */ | ||
| 60 | ASSERT (!thread_mlfqs); | ||
| 61 | |||
| 62 | msg ("Creating %d threads to sleep %d times each.", thread_cnt, iterations); | ||
| 63 | msg ("Thread 0 sleeps 10 ticks each time,"); | ||
| 64 | msg ("thread 1 sleeps 20 ticks each time, and so on."); | ||
| 65 | msg ("If successful, product of iteration count and"); | ||
| 66 | msg ("sleep duration will appear in nondescending order."); | ||
| 67 | |||
| 68 | /* Allocate memory. */ | ||
| 69 | threads = malloc (sizeof *threads * thread_cnt); | ||
| 70 | output = malloc (sizeof *output * iterations * thread_cnt * 2); | ||
| 71 | if (threads == NULL || output == NULL) | ||
| 72 | PANIC ("couldn't allocate memory for test"); | ||
| 73 | |||
| 74 | /* Initialize test. */ | ||
| 75 | test.start = timer_ticks () + 100; | ||
| 76 | test.iterations = iterations; | ||
| 77 | lock_init (&test.output_lock); | ||
| 78 | test.output_pos = output; | ||
| 79 | |||
| 80 | /* Start threads. */ | ||
| 81 | ASSERT (output != NULL); | ||
| 82 | for (i = 0; i < thread_cnt; i++) | ||
| 83 | { | ||
| 84 | struct sleep_thread *t = threads + i; | ||
| 85 | char name[16]; | ||
| 86 | |||
| 87 | t->test = &test; | ||
| 88 | t->id = i; | ||
| 89 | t->duration = (i + 1) * 10; | ||
| 90 | t->iterations = 0; | ||
| 91 | |||
| 92 | snprintf (name, sizeof name, "thread %d", i); | ||
| 93 | thread_create (name, PRI_DEFAULT, sleeper, t); | ||
| 94 | } | ||
| 95 | |||
| 96 | /* Wait long enough for all the threads to finish. */ | ||
| 97 | timer_sleep (100 + thread_cnt * iterations * 10 + 100); | ||
| 98 | |||
| 99 | /* Acquire the output lock in case some rogue thread is still | ||
| 100 | running. */ | ||
| 101 | lock_acquire (&test.output_lock); | ||
| 102 | |||
| 103 | /* Print completion order. */ | ||
| 104 | product = 0; | ||
| 105 | for (op = output; op < test.output_pos; op++) | ||
| 106 | { | ||
| 107 | struct sleep_thread *t; | ||
| 108 | int new_prod; | ||
| 109 | |||
| 110 | ASSERT (*op >= 0 && *op < thread_cnt); | ||
| 111 | t = threads + *op; | ||
| 112 | |||
| 113 | new_prod = ++t->iterations * t->duration; | ||
| 114 | |||
| 115 | msg ("thread %d: duration=%d, iteration=%d, product=%d", | ||
| 116 | t->id, t->duration, t->iterations, new_prod); | ||
| 117 | |||
| 118 | if (new_prod >= product) | ||
| 119 | product = new_prod; | ||
| 120 | else | ||
| 121 | fail ("thread %d woke up out of order (%d > %d)!", | ||
| 122 | t->id, product, new_prod); | ||
| 123 | } | ||
| 124 | |||
| 125 | /* Verify that we had the proper number of wakeups. */ | ||
| 126 | for (i = 0; i < thread_cnt; i++) | ||
| 127 | if (threads[i].iterations != iterations) | ||
| 128 | fail ("thread %d woke up %d times instead of %d", | ||
| 129 | i, threads[i].iterations, iterations); | ||
| 130 | |||
| 131 | lock_release (&test.output_lock); | ||
| 132 | free (output); | ||
| 133 | free (threads); | ||
| 134 | } | ||
| 135 | |||
| 136 | /* Sleeper thread. */ | ||
| 137 | static void | ||
| 138 | sleeper (void *t_) | ||
| 139 | { | ||
| 140 | struct sleep_thread *t = t_; | ||
| 141 | struct sleep_test *test = t->test; | ||
| 142 | int i; | ||
| 143 | |||
| 144 | for (i = 1; i <= test->iterations; i++) | ||
| 145 | { | ||
| 146 | int64_t sleep_until = test->start + i * t->duration; | ||
| 147 | timer_sleep (sleep_until - timer_ticks ()); | ||
| 148 | lock_acquire (&test->output_lock); | ||
| 149 | *test->output_pos++ = t->id; | ||
| 150 | lock_release (&test->output_lock); | ||
| 151 | } | ||
| 152 | } | ||
diff --git a/pintos-progos/tests/threads/alarm-zero.c b/pintos-progos/tests/threads/alarm-zero.c new file mode 100644 index 0000000..c8a3ee2 --- /dev/null +++ b/pintos-progos/tests/threads/alarm-zero.c | |||
| @@ -0,0 +1,15 @@ | |||
| 1 | /* Tests timer_sleep(0), which should return immediately. */ | ||
| 2 | |||
| 3 | #include <stdio.h> | ||
| 4 | #include "tests/threads/tests.h" | ||
| 5 | #include "threads/malloc.h" | ||
| 6 | #include "threads/synch.h" | ||
| 7 | #include "threads/thread.h" | ||
| 8 | #include "devices/timer.h" | ||
| 9 | |||
| 10 | void | ||
| 11 | test_alarm_zero (void) | ||
| 12 | { | ||
| 13 | timer_sleep (0); | ||
| 14 | pass (); | ||
| 15 | } | ||
diff --git a/pintos-progos/tests/threads/alarm-zero.ck b/pintos-progos/tests/threads/alarm-zero.ck new file mode 100644 index 0000000..a6b1a3c --- /dev/null +++ b/pintos-progos/tests/threads/alarm-zero.ck | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | # -*- perl -*- | ||
| 2 | use strict; | ||
| 3 | use warnings; | ||
| 4 | use tests::tests; | ||
| 5 | check_expected ([<<'EOF']); | ||
| 6 | (alarm-zero) begin | ||
| 7 | (alarm-zero) PASS | ||
| 8 | (alarm-zero) end | ||
| 9 | EOF | ||
| 10 | pass; | ||
diff --git a/pintos-progos/tests/threads/alarm.pm b/pintos-progos/tests/threads/alarm.pm new file mode 100644 index 0000000..84b3b7f --- /dev/null +++ b/pintos-progos/tests/threads/alarm.pm | |||
| @@ -0,0 +1,32 @@ | |||
| 1 | sub check_alarm { | ||
| 2 | my ($iterations) = @_; | ||
| 3 | our ($test); | ||
| 4 | |||
| 5 | @output = read_text_file ("$test.output"); | ||
| 6 | common_checks ("run", @output); | ||
| 7 | |||
| 8 | my (@products); | ||
| 9 | for (my ($i) = 0; $i < $iterations; $i++) { | ||
| 10 | for (my ($t) = 0; $t < 5; $t++) { | ||
| 11 | push (@products, ($i + 1) * ($t + 1) * 10); | ||
| 12 | } | ||
| 13 | } | ||
| 14 | @products = sort {$a <=> $b} @products; | ||
| 15 | |||
| 16 | local ($_); | ||
| 17 | foreach (@output) { | ||
| 18 | fail $_ if /out of order/i; | ||
| 19 | |||
| 20 | my ($p) = /product=(\d+)$/; | ||
| 21 | next if !defined $p; | ||
| 22 | |||
| 23 | my ($q) = shift (@products); | ||
| 24 | fail "Too many wakeups.\n" if !defined $q; | ||
| 25 | fail "Out of order wakeups ($p vs. $q).\n" if $p != $q; # FIXME | ||
| 26 | } | ||
| 27 | fail scalar (@products) . " fewer wakeups than expected.\n" | ||
| 28 | if @products != 0; | ||
| 29 | pass; | ||
| 30 | } | ||
| 31 | |||
| 32 | 1; | ||
diff --git a/pintos-progos/tests/threads/mlfqs-block.c b/pintos-progos/tests/threads/mlfqs-block.c new file mode 100644 index 0000000..6d4992d --- /dev/null +++ b/pintos-progos/tests/threads/mlfqs-block.c | |||
| @@ -0,0 +1,64 @@ | |||
| 1 | /* Checks that recent_cpu and priorities are updated for blocked | ||
| 2 | threads. | ||
| 3 | |||
| 4 | The main thread sleeps for 25 seconds, spins for 5 seconds, | ||
| 5 | then releases a lock. The "block" thread spins for 20 seconds | ||
| 6 | then attempts to acquire the lock, which will block for 10 | ||
| 7 | seconds (until the main thread releases it). If recent_cpu | ||
| 8 | decays properly while the "block" thread sleeps, then the | ||
| 9 | block thread should be immediately scheduled when the main | ||
| 10 | thread releases the lock. */ | ||
| 11 | |||
| 12 | #include <stdio.h> | ||
| 13 | #include "tests/threads/tests.h" | ||
| 14 | #include "threads/init.h" | ||
| 15 | #include "threads/malloc.h" | ||
| 16 | #include "threads/synch.h" | ||
| 17 | #include "threads/thread.h" | ||
| 18 | #include "devices/timer.h" | ||
| 19 | |||
| 20 | static void block_thread (void *lock_); | ||
| 21 | |||
| 22 | void | ||
| 23 | test_mlfqs_block (void) | ||
| 24 | { | ||
| 25 | int64_t start_time; | ||
| 26 | struct lock lock; | ||
| 27 | |||
| 28 | ASSERT (thread_mlfqs); | ||
| 29 | |||
| 30 | msg ("Main thread acquiring lock."); | ||
| 31 | lock_init (&lock); | ||
| 32 | lock_acquire (&lock); | ||
| 33 | |||
| 34 | msg ("Main thread creating block thread, sleeping 25 seconds..."); | ||
| 35 | thread_create ("block", PRI_DEFAULT, block_thread, &lock); | ||
| 36 | timer_sleep (25 * TIMER_FREQ); | ||
| 37 | |||
| 38 | msg ("Main thread spinning for 5 seconds..."); | ||
| 39 | start_time = timer_ticks (); | ||
| 40 | while (timer_elapsed (start_time) < 5 * TIMER_FREQ) | ||
| 41 | continue; | ||
| 42 | |||
| 43 | msg ("Main thread releasing lock."); | ||
| 44 | lock_release (&lock); | ||
| 45 | |||
| 46 | msg ("Block thread should have already acquired lock."); | ||
| 47 | } | ||
| 48 | |||
| 49 | static void | ||
| 50 | block_thread (void *lock_) | ||
| 51 | { | ||
| 52 | struct lock *lock = lock_; | ||
| 53 | int64_t start_time; | ||
| 54 | |||
| 55 | msg ("Block thread spinning for 20 seconds..."); | ||
| 56 | start_time = timer_ticks (); | ||
| 57 | while (timer_elapsed (start_time) < 20 * TIMER_FREQ) | ||
| 58 | continue; | ||
| 59 | |||
| 60 | msg ("Block thread acquiring lock..."); | ||
| 61 | lock_acquire (lock); | ||
| 62 | |||
| 63 | msg ("...got it."); | ||
| 64 | } | ||
diff --git a/pintos-progos/tests/threads/mlfqs-block.ck b/pintos-progos/tests/threads/mlfqs-block.ck new file mode 100644 index 0000000..8833a3a --- /dev/null +++ b/pintos-progos/tests/threads/mlfqs-block.ck | |||
| @@ -0,0 +1,17 @@ | |||
| 1 | # -*- perl -*- | ||
| 2 | use strict; | ||
| 3 | use warnings; | ||
| 4 | use tests::tests; | ||
| 5 | check_expected ([<<'EOF']); | ||
| 6 | (mlfqs-block) begin | ||
| 7 | (mlfqs-block) Main thread acquiring lock. | ||
| 8 | (mlfqs-block) Main thread creating block thread, sleeping 25 seconds... | ||
| 9 | (mlfqs-block) Block thread spinning for 20 seconds... | ||
| 10 | (mlfqs-block) Block thread acquiring lock... | ||
| 11 | (mlfqs-block) Main thread spinning for 5 seconds... | ||
| 12 | (mlfqs-block) Main thread releasing lock. | ||
| 13 | (mlfqs-block) ...got it. | ||
| 14 | (mlfqs-block) Block thread should have already acquired lock. | ||
| 15 | (mlfqs-block) end | ||
| 16 | EOF | ||
| 17 | pass; | ||
diff --git a/pintos-progos/tests/threads/mlfqs-fair-2.ck b/pintos-progos/tests/threads/mlfqs-fair-2.ck new file mode 100644 index 0000000..5b19ff1 --- /dev/null +++ b/pintos-progos/tests/threads/mlfqs-fair-2.ck | |||
| @@ -0,0 +1,7 @@ | |||
| 1 | # -*- perl -*- | ||
| 2 | use strict; | ||
| 3 | use warnings; | ||
| 4 | use tests::tests; | ||
| 5 | use tests::threads::mlfqs; | ||
| 6 | |||
| 7 | check_mlfqs_fair ([0, 0], 50); | ||
diff --git a/pintos-progos/tests/threads/mlfqs-fair-20.ck b/pintos-progos/tests/threads/mlfqs-fair-20.ck new file mode 100644 index 0000000..bb4d051 --- /dev/null +++ b/pintos-progos/tests/threads/mlfqs-fair-20.ck | |||
| @@ -0,0 +1,7 @@ | |||
| 1 | # -*- perl -*- | ||
| 2 | use strict; | ||
| 3 | use warnings; | ||
| 4 | use tests::tests; | ||
| 5 | use tests::threads::mlfqs; | ||
| 6 | |||
| 7 | check_mlfqs_fair ([(0) x 20], 20); | ||
diff --git a/pintos-progos/tests/threads/mlfqs-fair.c b/pintos-progos/tests/threads/mlfqs-fair.c new file mode 100644 index 0000000..3b1bea5 --- /dev/null +++ b/pintos-progos/tests/threads/mlfqs-fair.c | |||
| @@ -0,0 +1,124 @@ | |||
| 1 | /* Measures the correctness of the "nice" implementation. | ||
| 2 | |||
| 3 | The "fair" tests run either 2 or 20 threads all niced to 0. | ||
| 4 | The threads should all receive approximately the same number | ||
| 5 | of ticks. Each test runs for 30 seconds, so the ticks should | ||
| 6 | also sum to approximately 30 * 100 == 3000 ticks. | ||
| 7 | |||
| 8 | The mlfqs-nice-2 test runs 2 threads, one with nice 0, the | ||
| 9 | other with nice 5, which should receive 1,904 and 1,096 ticks, | ||
| 10 | respectively, over 30 seconds. | ||
| 11 | |||
| 12 | The mlfqs-nice-10 test runs 10 threads with nice 0 through 9. | ||
| 13 | They should receive 672, 588, 492, 408, 316, 232, 152, 92, 40, | ||
| 14 | and 8 ticks, respectively, over 30 seconds. | ||
| 15 | |||
| 16 | (The above are computed via simulation in mlfqs.pm.) */ | ||
| 17 | |||
| 18 | #include <stdio.h> | ||
| 19 | #include <inttypes.h> | ||
| 20 | #include "tests/threads/tests.h" | ||
| 21 | #include "threads/init.h" | ||
| 22 | #include "threads/malloc.h" | ||
| 23 | #include "threads/palloc.h" | ||
| 24 | #include "threads/synch.h" | ||
| 25 | #include "threads/thread.h" | ||
| 26 | #include "devices/timer.h" | ||
| 27 | |||
| 28 | static void test_mlfqs_fair (int thread_cnt, int nice_min, int nice_step); | ||
| 29 | |||
| 30 | void | ||
| 31 | test_mlfqs_fair_2 (void) | ||
| 32 | { | ||
| 33 | test_mlfqs_fair (2, 0, 0); | ||
| 34 | } | ||
| 35 | |||
| 36 | void | ||
| 37 | test_mlfqs_fair_20 (void) | ||
| 38 | { | ||
| 39 | test_mlfqs_fair (20, 0, 0); | ||
| 40 | } | ||
| 41 | |||
| 42 | void | ||
| 43 | test_mlfqs_nice_2 (void) | ||
| 44 | { | ||
| 45 | test_mlfqs_fair (2, 0, 5); | ||
| 46 | } | ||
| 47 | |||
| 48 | void | ||
| 49 | test_mlfqs_nice_10 (void) | ||
| 50 | { | ||
| 51 | test_mlfqs_fair (10, 0, 1); | ||
| 52 | } | ||
| 53 | |||
| 54 | #define MAX_THREAD_CNT 20 | ||
| 55 | |||
| 56 | struct thread_info | ||
| 57 | { | ||
| 58 | int64_t start_time; | ||
| 59 | int tick_count; | ||
| 60 | int nice; | ||
| 61 | }; | ||
| 62 | |||
| 63 | static void load_thread (void *aux); | ||
| 64 | |||
| 65 | static void | ||
| 66 | test_mlfqs_fair (int thread_cnt, int nice_min, int nice_step) | ||
| 67 | { | ||
| 68 | struct thread_info info[MAX_THREAD_CNT]; | ||
| 69 | int64_t start_time; | ||
| 70 | int nice; | ||
| 71 | int i; | ||
| 72 | |||
| 73 | ASSERT (thread_mlfqs); | ||
| 74 | ASSERT (thread_cnt <= MAX_THREAD_CNT); | ||
| 75 | ASSERT (nice_min >= -10); | ||
| 76 | ASSERT (nice_step >= 0); | ||
| 77 | ASSERT (nice_min + nice_step * (thread_cnt - 1) <= 20); | ||
| 78 | |||
| 79 | thread_set_nice (-20); | ||
| 80 | |||
| 81 | start_time = timer_ticks (); | ||
| 82 | msg ("Starting %d threads...", thread_cnt); | ||
| 83 | nice = nice_min; | ||
| 84 | for (i = 0; i < thread_cnt; i++) | ||
| 85 | { | ||
| 86 | struct thread_info *ti = &info[i]; | ||
| 87 | char name[16]; | ||
| 88 | |||
| 89 | ti->start_time = start_time; | ||
| 90 | ti->tick_count = 0; | ||
| 91 | ti->nice = nice; | ||
| 92 | |||
| 93 | snprintf(name, sizeof name, "load %d", i); | ||
| 94 | thread_create (name, PRI_DEFAULT, load_thread, ti); | ||
| 95 | |||
| 96 | nice += nice_step; | ||
| 97 | } | ||
| 98 | msg ("Starting threads took %"PRId64" ticks.", timer_elapsed (start_time)); | ||
| 99 | |||
| 100 | msg ("Sleeping 40 seconds to let threads run, please wait..."); | ||
| 101 | timer_sleep (40 * TIMER_FREQ); | ||
| 102 | |||
| 103 | for (i = 0; i < thread_cnt; i++) | ||
| 104 | msg ("Thread %d received %d ticks.", i, info[i].tick_count); | ||
| 105 | } | ||
| 106 | |||
| 107 | static void | ||
| 108 | load_thread (void *ti_) | ||
| 109 | { | ||
| 110 | struct thread_info *ti = ti_; | ||
| 111 | int64_t sleep_time = 5 * TIMER_FREQ; | ||
| 112 | int64_t spin_time = sleep_time + 30 * TIMER_FREQ; | ||
| 113 | int64_t last_time = 0; | ||
| 114 | |||
| 115 | thread_set_nice (ti->nice); | ||
| 116 | timer_sleep (sleep_time - timer_elapsed (ti->start_time)); | ||
| 117 | while (timer_elapsed (ti->start_time) < spin_time) | ||
| 118 | { | ||
| 119 | int64_t cur_time = timer_ticks (); | ||
| 120 | if (cur_time != last_time) | ||
| 121 | ti->tick_count++; | ||
| 122 | last_time = cur_time; | ||
| 123 | } | ||
| 124 | } | ||
diff --git a/pintos-progos/tests/threads/mlfqs-load-1.c b/pintos-progos/tests/threads/mlfqs-load-1.c new file mode 100644 index 0000000..a39eea2 --- /dev/null +++ b/pintos-progos/tests/threads/mlfqs-load-1.c | |||
| @@ -0,0 +1,60 @@ | |||
| 1 | /* Verifies that a single busy thread raises the load average to | ||
| 2 | 0.5 in 38 to 45 seconds. The expected time is 42 seconds, as | ||
| 3 | you can verify: | ||
| 4 | perl -e '$i++,$a=(59*$a+1)/60while$a<=.5;print "$i\n"' | ||
| 5 | |||
| 6 | Then, verifies that 10 seconds of inactivity drop the load | ||
| 7 | average back below 0.5 again. */ | ||
| 8 | |||
| 9 | #include <stdio.h> | ||
| 10 | #include "tests/threads/tests.h" | ||
| 11 | #include "threads/init.h" | ||
| 12 | #include "threads/malloc.h" | ||
| 13 | #include "threads/synch.h" | ||
| 14 | #include "threads/thread.h" | ||
| 15 | #include "devices/timer.h" | ||
| 16 | |||
| 17 | void | ||
| 18 | test_mlfqs_load_1 (void) | ||
| 19 | { | ||
| 20 | int64_t start_time; | ||
| 21 | int elapsed; | ||
| 22 | int load_avg; | ||
| 23 | |||
| 24 | ASSERT (thread_mlfqs); | ||
| 25 | |||
| 26 | msg ("spinning for up to 45 seconds, please wait..."); | ||
| 27 | |||
| 28 | start_time = timer_ticks (); | ||
| 29 | for (;;) | ||
| 30 | { | ||
| 31 | load_avg = thread_get_load_avg (); | ||
| 32 | ASSERT (load_avg >= 0); | ||
| 33 | elapsed = timer_elapsed (start_time) / TIMER_FREQ; | ||
| 34 | if (load_avg > 100) | ||
| 35 | fail ("load average is %d.%02d " | ||
| 36 | "but should be between 0 and 1 (after %d seconds)", | ||
| 37 | load_avg / 100, load_avg % 100, elapsed); | ||
| 38 | else if (load_avg > 50) | ||
| 39 | break; | ||
| 40 | else if (elapsed > 45) | ||
| 41 | fail ("load average stayed below 0.5 for more than 45 seconds"); | ||
| 42 | } | ||
| 43 | |||
| 44 | if (elapsed < 38) | ||
| 45 | fail ("load average took only %d seconds to rise above 0.5", elapsed); | ||
| 46 | msg ("load average rose to 0.5 after %d seconds", elapsed); | ||
| 47 | |||
| 48 | msg ("sleeping for another 10 seconds, please wait..."); | ||
| 49 | timer_sleep (TIMER_FREQ * 10); | ||
| 50 | |||
| 51 | load_avg = thread_get_load_avg (); | ||
| 52 | if (load_avg < 0) | ||
| 53 | fail ("load average fell below 0"); | ||
| 54 | if (load_avg > 50) | ||
| 55 | fail ("load average stayed above 0.5 for more than 10 seconds"); | ||
| 56 | msg ("load average fell back below 0.5 (to %d.%02d)", | ||
| 57 | load_avg / 100, load_avg % 100); | ||
| 58 | |||
| 59 | pass (); | ||
| 60 | } | ||
diff --git a/pintos-progos/tests/threads/mlfqs-load-1.ck b/pintos-progos/tests/threads/mlfqs-load-1.ck new file mode 100644 index 0000000..faf0ffa --- /dev/null +++ b/pintos-progos/tests/threads/mlfqs-load-1.ck | |||
| @@ -0,0 +1,15 @@ | |||
| 1 | # -*- perl -*- | ||
| 2 | use strict; | ||
| 3 | use warnings; | ||
| 4 | use tests::tests; | ||
| 5 | |||
| 6 | our ($test); | ||
| 7 | my (@output) = read_text_file ("$test.output"); | ||
| 8 | |||
| 9 | common_checks ("run", @output); | ||
| 10 | |||
| 11 | @output = get_core_output ("run", @output); | ||
| 12 | fail "missing PASS in output" | ||
| 13 | unless grep ($_ eq '(mlfqs-load-1) PASS', @output); | ||
| 14 | |||
| 15 | pass; | ||
diff --git a/pintos-progos/tests/threads/mlfqs-load-60.c b/pintos-progos/tests/threads/mlfqs-load-60.c new file mode 100644 index 0000000..b6a3eb6 --- /dev/null +++ b/pintos-progos/tests/threads/mlfqs-load-60.c | |||
| @@ -0,0 +1,155 @@ | |||
| 1 | /* Starts 60 threads that each sleep for 10 seconds, then spin in | ||
| 2 | a tight loop for 60 seconds, and sleep for another 60 seconds. | ||
| 3 | Every 2 seconds after the initial sleep, the main thread | ||
| 4 | prints the load average. | ||
| 5 | |||
| 6 | The expected output is this (some margin of error is allowed): | ||
| 7 | |||
| 8 | After 0 seconds, load average=1.00. | ||
| 9 | After 2 seconds, load average=2.95. | ||
| 10 | After 4 seconds, load average=4.84. | ||
| 11 | After 6 seconds, load average=6.66. | ||
| 12 | After 8 seconds, load average=8.42. | ||
| 13 | After 10 seconds, load average=10.13. | ||
| 14 | After 12 seconds, load average=11.78. | ||
| 15 | After 14 seconds, load average=13.37. | ||
| 16 | After 16 seconds, load average=14.91. | ||
| 17 | After 18 seconds, load average=16.40. | ||
| 18 | After 20 seconds, load average=17.84. | ||
| 19 | After 22 seconds, load average=19.24. | ||
| 20 | After 24 seconds, load average=20.58. | ||
| 21 | After 26 seconds, load average=21.89. | ||
| 22 | After 28 seconds, load average=23.15. | ||
| 23 | After 30 seconds, load average=24.37. | ||
| 24 | After 32 seconds, load average=25.54. | ||
| 25 | After 34 seconds, load average=26.68. | ||
| 26 | After 36 seconds, load average=27.78. | ||
| 27 | After 38 seconds, load average=28.85. | ||
| 28 | After 40 seconds, load average=29.88. | ||
| 29 | After 42 seconds, load average=30.87. | ||
| 30 | After 44 seconds, load average=31.84. | ||
| 31 | After 46 seconds, load average=32.77. | ||
| 32 | After 48 seconds, load average=33.67. | ||
| 33 | After 50 seconds, load average=34.54. | ||
| 34 | After 52 seconds, load average=35.38. | ||
| 35 | After 54 seconds, load average=36.19. | ||
| 36 | After 56 seconds, load average=36.98. | ||
| 37 | After 58 seconds, load average=37.74. | ||
| 38 | After 60 seconds, load average=37.48. | ||
| 39 | After 62 seconds, load average=36.24. | ||
| 40 | After 64 seconds, load average=35.04. | ||
| 41 | After 66 seconds, load average=33.88. | ||
| 42 | After 68 seconds, load average=32.76. | ||
| 43 | After 70 seconds, load average=31.68. | ||
| 44 | After 72 seconds, load average=30.63. | ||
| 45 | After 74 seconds, load average=29.62. | ||
| 46 | After 76 seconds, load average=28.64. | ||
| 47 | After 78 seconds, load average=27.69. | ||
| 48 | After 80 seconds, load average=26.78. | ||
| 49 | After 82 seconds, load average=25.89. | ||
| 50 | After 84 seconds, load average=25.04. | ||
| 51 | After 86 seconds, load average=24.21. | ||
| 52 | After 88 seconds, load average=23.41. | ||
| 53 | After 90 seconds, load average=22.64. | ||
| 54 | After 92 seconds, load average=21.89. | ||
| 55 | After 94 seconds, load average=21.16. | ||
| 56 | After 96 seconds, load average=20.46. | ||
| 57 | After 98 seconds, load average=19.79. | ||
| 58 | After 100 seconds, load average=19.13. | ||
| 59 | After 102 seconds, load average=18.50. | ||
| 60 | After 104 seconds, load average=17.89. | ||
| 61 | After 106 seconds, load average=17.30. | ||
| 62 | After 108 seconds, load average=16.73. | ||
| 63 | After 110 seconds, load average=16.17. | ||
| 64 | After 112 seconds, load average=15.64. | ||
| 65 | After 114 seconds, load average=15.12. | ||
| 66 | After 116 seconds, load average=14.62. | ||
| 67 | After 118 seconds, load average=14.14. | ||
| 68 | After 120 seconds, load average=13.67. | ||
| 69 | After 122 seconds, load average=13.22. | ||
| 70 | After 124 seconds, load average=12.78. | ||
| 71 | After 126 seconds, load average=12.36. | ||
| 72 | After 128 seconds, load average=11.95. | ||
| 73 | After 130 seconds, load average=11.56. | ||
| 74 | After 132 seconds, load average=11.17. | ||
| 75 | After 134 seconds, load average=10.80. | ||
| 76 | After 136 seconds, load average=10.45. | ||
| 77 | After 138 seconds, load average=10.10. | ||
| 78 | After 140 seconds, load average=9.77. | ||
| 79 | After 142 seconds, load average=9.45. | ||
| 80 | After 144 seconds, load average=9.13. | ||
| 81 | After 146 seconds, load average=8.83. | ||
| 82 | After 148 seconds, load average=8.54. | ||
| 83 | After 150 seconds, load average=8.26. | ||
| 84 | After 152 seconds, load average=7.98. | ||
| 85 | After 154 seconds, load average=7.72. | ||
| 86 | After 156 seconds, load average=7.47. | ||
| 87 | After 158 seconds, load average=7.22. | ||
| 88 | After 160 seconds, load average=6.98. | ||
| 89 | After 162 seconds, load average=6.75. | ||
| 90 | After 164 seconds, load average=6.53. | ||
| 91 | After 166 seconds, load average=6.31. | ||
| 92 | After 168 seconds, load average=6.10. | ||
| 93 | After 170 seconds, load average=5.90. | ||
| 94 | After 172 seconds, load average=5.70. | ||
| 95 | After 174 seconds, load average=5.52. | ||
| 96 | After 176 seconds, load average=5.33. | ||
| 97 | After 178 seconds, load average=5.16. | ||
| 98 | */ | ||
| 99 | |||
| 100 | #include <stdio.h> | ||
| 101 | #include "tests/threads/tests.h" | ||
| 102 | #include "threads/init.h" | ||
| 103 | #include "threads/malloc.h" | ||
| 104 | #include "threads/synch.h" | ||
| 105 | #include "threads/thread.h" | ||
| 106 | #include "devices/timer.h" | ||
| 107 | |||
| 108 | static int64_t start_time; | ||
| 109 | |||
| 110 | static void load_thread (void *aux); | ||
| 111 | |||
| 112 | #define THREAD_CNT 60 | ||
| 113 | |||
| 114 | void | ||
| 115 | test_mlfqs_load_60 (void) | ||
| 116 | { | ||
| 117 | int i; | ||
| 118 | |||
| 119 | ASSERT (thread_mlfqs); | ||
| 120 | |||
| 121 | start_time = timer_ticks (); | ||
| 122 | msg ("Starting %d niced load threads...", THREAD_CNT); | ||
| 123 | for (i = 0; i < THREAD_CNT; i++) | ||
| 124 | { | ||
| 125 | char name[16]; | ||
| 126 | snprintf(name, sizeof name, "load %d", i); | ||
| 127 | thread_create (name, PRI_DEFAULT, load_thread, NULL); | ||
| 128 | } | ||
| 129 | msg ("Starting threads took %d seconds.", | ||
| 130 | timer_elapsed (start_time) / TIMER_FREQ); | ||
| 131 | |||
| 132 | for (i = 0; i < 90; i++) | ||
| 133 | { | ||
| 134 | int64_t sleep_until = start_time + TIMER_FREQ * (2 * i + 10); | ||
| 135 | int load_avg; | ||
| 136 | timer_sleep (sleep_until - timer_ticks ()); | ||
| 137 | load_avg = thread_get_load_avg (); | ||
| 138 | msg ("After %d seconds, load average=%d.%02d.", | ||
| 139 | i * 2, load_avg / 100, load_avg % 100); | ||
| 140 | } | ||
| 141 | } | ||
| 142 | |||
| 143 | static void | ||
| 144 | load_thread (void *aux UNUSED) | ||
| 145 | { | ||
| 146 | int64_t sleep_time = 10 * TIMER_FREQ; | ||
| 147 | int64_t spin_time = sleep_time + 60 * TIMER_FREQ; | ||
| 148 | int64_t exit_time = spin_time + 60 * TIMER_FREQ; | ||
| 149 | |||
| 150 | thread_set_nice (20); | ||
| 151 | timer_sleep (sleep_time - timer_elapsed (start_time)); | ||
| 152 | while (timer_elapsed (start_time) < spin_time) | ||
| 153 | continue; | ||
| 154 | timer_sleep (exit_time - timer_elapsed (start_time)); | ||
| 155 | } | ||
diff --git a/pintos-progos/tests/threads/mlfqs-load-60.ck b/pintos-progos/tests/threads/mlfqs-load-60.ck new file mode 100644 index 0000000..cb69220 --- /dev/null +++ b/pintos-progos/tests/threads/mlfqs-load-60.ck | |||
| @@ -0,0 +1,36 @@ | |||
| 1 | # -*- perl -*- | ||
| 2 | use strict; | ||
| 3 | use warnings; | ||
| 4 | use tests::tests; | ||
| 5 | use tests::threads::mlfqs; | ||
| 6 | |||
| 7 | our ($test); | ||
| 8 | |||
| 9 | my (@output) = read_text_file ("$test.output"); | ||
| 10 | common_checks ("run", @output); | ||
| 11 | @output = get_core_output ("run", @output); | ||
| 12 | |||
| 13 | # Get actual values. | ||
| 14 | local ($_); | ||
| 15 | my (@actual); | ||
| 16 | foreach (@output) { | ||
| 17 | my ($t, $load_avg) = /After (\d+) seconds, load average=(\d+\.\d+)\./ | ||
| 18 | or next; | ||
| 19 | $actual[$t] = $load_avg; | ||
| 20 | } | ||
| 21 | |||
| 22 | # Calculate expected values. | ||
| 23 | my ($load_avg) = 0; | ||
| 24 | my ($recent) = 0; | ||
| 25 | my (@expected); | ||
| 26 | for (my ($t) = 0; $t < 180; $t++) { | ||
| 27 | my ($ready) = $t < 60 ? 60 : 0; | ||
| 28 | $load_avg = (59/60) * $load_avg + (1/60) * $ready; | ||
| 29 | $expected[$t] = $load_avg; | ||
| 30 | } | ||
| 31 | |||
| 32 | mlfqs_compare ("time", "%.2f", \@actual, \@expected, 3.5, [2, 178, 2], | ||
| 33 | "Some load average values were missing or " | ||
| 34 | . "differed from those expected " | ||
| 35 | . "by more than 3.5."); | ||
| 36 | pass; | ||
diff --git a/pintos-progos/tests/threads/mlfqs-load-avg.c b/pintos-progos/tests/threads/mlfqs-load-avg.c new file mode 100644 index 0000000..50e83e2 --- /dev/null +++ b/pintos-progos/tests/threads/mlfqs-load-avg.c | |||
| @@ -0,0 +1,167 @@ | |||
| 1 | /* Starts 60 threads numbered 0 through 59. Thread #i sleeps for | ||
| 2 | (10+i) seconds, then spins in a loop for 60 seconds, then | ||
| 3 | sleeps until a total of 120 seconds have passed. Every 2 | ||
| 4 | seconds, starting 10 seconds in, the main thread prints the | ||
| 5 | load average. | ||
| 6 | |||
| 7 | The expected output is listed below. Some margin of error is | ||
| 8 | allowed. | ||
| 9 | |||
| 10 | If your implementation fails this test but passes most other | ||
| 11 | tests, then consider whether you are doing too much work in | ||
| 12 | the timer interrupt. If the timer interrupt handler takes too | ||
| 13 | long, then the test's main thread will not have enough time to | ||
| 14 | do its own work (printing a message) and go back to sleep | ||
| 15 | before the next tick arrives. Then the main thread will be | ||
| 16 | ready, instead of sleeping, when the tick arrives, | ||
| 17 | artificially driving up the load average. | ||
| 18 | |||
| 19 | After 0 seconds, load average=0.00. | ||
| 20 | After 2 seconds, load average=0.05. | ||
| 21 | After 4 seconds, load average=0.16. | ||
| 22 | After 6 seconds, load average=0.34. | ||
| 23 | After 8 seconds, load average=0.58. | ||
| 24 | After 10 seconds, load average=0.87. | ||
| 25 | After 12 seconds, load average=1.22. | ||
| 26 | After 14 seconds, load average=1.63. | ||
| 27 | After 16 seconds, load average=2.09. | ||
| 28 | After 18 seconds, load average=2.60. | ||
| 29 | After 20 seconds, load average=3.16. | ||
| 30 | After 22 seconds, load average=3.76. | ||
| 31 | After 24 seconds, load average=4.42. | ||
| 32 | After 26 seconds, load average=5.11. | ||
| 33 | After 28 seconds, load average=5.85. | ||
| 34 | After 30 seconds, load average=6.63. | ||
| 35 | After 32 seconds, load average=7.46. | ||
| 36 | After 34 seconds, load average=8.32. | ||
| 37 | After 36 seconds, load average=9.22. | ||
| 38 | After 38 seconds, load average=10.15. | ||
| 39 | After 40 seconds, load average=11.12. | ||
| 40 | After 42 seconds, load average=12.13. | ||
| 41 | After 44 seconds, load average=13.16. | ||
| 42 | After 46 seconds, load average=14.23. | ||
| 43 | After 48 seconds, load average=15.33. | ||
| 44 | After 50 seconds, load average=16.46. | ||
| 45 | After 52 seconds, load average=17.62. | ||
| 46 | After 54 seconds, load average=18.81. | ||
| 47 | After 56 seconds, load average=20.02. | ||
| 48 | After 58 seconds, load average=21.26. | ||
| 49 | After 60 seconds, load average=22.52. | ||
| 50 | After 62 seconds, load average=23.71. | ||
| 51 | After 64 seconds, load average=24.80. | ||
| 52 | After 66 seconds, load average=25.78. | ||
| 53 | After 68 seconds, load average=26.66. | ||
| 54 | After 70 seconds, load average=27.45. | ||
| 55 | After 72 seconds, load average=28.14. | ||
| 56 | After 74 seconds, load average=28.75. | ||
| 57 | After 76 seconds, load average=29.27. | ||
| 58 | After 78 seconds, load average=29.71. | ||
| 59 | After 80 seconds, load average=30.06. | ||
| 60 | After 82 seconds, load average=30.34. | ||
| 61 | After 84 seconds, load average=30.55. | ||
| 62 | After 86 seconds, load average=30.68. | ||
| 63 | After 88 seconds, load average=30.74. | ||
| 64 | After 90 seconds, load average=30.73. | ||
| 65 | After 92 seconds, load average=30.66. | ||
| 66 | After 94 seconds, load average=30.52. | ||
| 67 | After 96 seconds, load average=30.32. | ||
| 68 | After 98 seconds, load average=30.06. | ||
| 69 | After 100 seconds, load average=29.74. | ||
| 70 | After 102 seconds, load average=29.37. | ||
| 71 | After 104 seconds, load average=28.95. | ||
| 72 | After 106 seconds, load average=28.47. | ||
| 73 | After 108 seconds, load average=27.94. | ||
| 74 | After 110 seconds, load average=27.36. | ||
| 75 | After 112 seconds, load average=26.74. | ||
| 76 | After 114 seconds, load average=26.07. | ||
| 77 | After 116 seconds, load average=25.36. | ||
| 78 | After 118 seconds, load average=24.60. | ||
| 79 | After 120 seconds, load average=23.81. | ||
| 80 | After 122 seconds, load average=23.02. | ||
| 81 | After 124 seconds, load average=22.26. | ||
| 82 | After 126 seconds, load average=21.52. | ||
| 83 | After 128 seconds, load average=20.81. | ||
| 84 | After 130 seconds, load average=20.12. | ||
| 85 | After 132 seconds, load average=19.46. | ||
| 86 | After 134 seconds, load average=18.81. | ||
| 87 | After 136 seconds, load average=18.19. | ||
| 88 | After 138 seconds, load average=17.59. | ||
| 89 | After 140 seconds, load average=17.01. | ||
| 90 | After 142 seconds, load average=16.45. | ||
| 91 | After 144 seconds, load average=15.90. | ||
| 92 | After 146 seconds, load average=15.38. | ||
| 93 | After 148 seconds, load average=14.87. | ||
| 94 | After 150 seconds, load average=14.38. | ||
| 95 | After 152 seconds, load average=13.90. | ||
| 96 | After 154 seconds, load average=13.44. | ||
| 97 | After 156 seconds, load average=13.00. | ||
| 98 | After 158 seconds, load average=12.57. | ||
| 99 | After 160 seconds, load average=12.15. | ||
| 100 | After 162 seconds, load average=11.75. | ||
| 101 | After 164 seconds, load average=11.36. | ||
| 102 | After 166 seconds, load average=10.99. | ||
| 103 | After 168 seconds, load average=10.62. | ||
| 104 | After 170 seconds, load average=10.27. | ||
| 105 | After 172 seconds, load average=9.93. | ||
| 106 | After 174 seconds, load average=9.61. | ||
| 107 | After 176 seconds, load average=9.29. | ||
| 108 | After 178 seconds, load average=8.98. | ||
| 109 | */ | ||
| 110 | |||
| 111 | #include <stdio.h> | ||
| 112 | #include "tests/threads/tests.h" | ||
| 113 | #include "threads/init.h" | ||
| 114 | #include "threads/malloc.h" | ||
| 115 | #include "threads/synch.h" | ||
| 116 | #include "threads/thread.h" | ||
| 117 | #include "devices/timer.h" | ||
| 118 | |||
| 119 | static int64_t start_time; | ||
| 120 | |||
| 121 | static void load_thread (void *seq_no); | ||
| 122 | |||
| 123 | #define THREAD_CNT 60 | ||
| 124 | |||
| 125 | void | ||
| 126 | test_mlfqs_load_avg (void) | ||
| 127 | { | ||
| 128 | int i; | ||
| 129 | |||
| 130 | ASSERT (thread_mlfqs); | ||
| 131 | |||
| 132 | start_time = timer_ticks (); | ||
| 133 | msg ("Starting %d load threads...", THREAD_CNT); | ||
| 134 | for (i = 0; i < THREAD_CNT; i++) | ||
| 135 | { | ||
| 136 | char name[16]; | ||
| 137 | snprintf(name, sizeof name, "load %d", i); | ||
| 138 | thread_create (name, PRI_DEFAULT, load_thread, (void *) i); | ||
| 139 | } | ||
| 140 | msg ("Starting threads took %d seconds.", | ||
| 141 | timer_elapsed (start_time) / TIMER_FREQ); | ||
| 142 | thread_set_nice (-20); | ||
| 143 | |||
| 144 | for (i = 0; i < 90; i++) | ||
| 145 | { | ||
| 146 | int64_t sleep_until = start_time + TIMER_FREQ * (2 * i + 10); | ||
| 147 | int load_avg; | ||
| 148 | timer_sleep (sleep_until - timer_ticks ()); | ||
| 149 | load_avg = thread_get_load_avg (); | ||
| 150 | msg ("After %d seconds, load average=%d.%02d.", | ||
| 151 | i * 2, load_avg / 100, load_avg % 100); | ||
| 152 | } | ||
| 153 | } | ||
| 154 | |||
| 155 | static void | ||
| 156 | load_thread (void *seq_no_) | ||
| 157 | { | ||
| 158 | int seq_no = (int) seq_no_; | ||
| 159 | int sleep_time = TIMER_FREQ * (10 + seq_no); | ||
| 160 | int spin_time = sleep_time + TIMER_FREQ * THREAD_CNT; | ||
| 161 | int exit_time = TIMER_FREQ * (THREAD_CNT * 2); | ||
| 162 | |||
| 163 | timer_sleep (sleep_time - timer_elapsed (start_time)); | ||
| 164 | while (timer_elapsed (start_time) < spin_time) | ||
| 165 | continue; | ||
| 166 | timer_sleep (exit_time - timer_elapsed (start_time)); | ||
| 167 | } | ||
diff --git a/pintos-progos/tests/threads/mlfqs-load-avg.ck b/pintos-progos/tests/threads/mlfqs-load-avg.ck new file mode 100644 index 0000000..2254d05 --- /dev/null +++ b/pintos-progos/tests/threads/mlfqs-load-avg.ck | |||
| @@ -0,0 +1,36 @@ | |||
| 1 | # -*- perl -*- | ||
| 2 | use strict; | ||
| 3 | use warnings; | ||
| 4 | use tests::tests; | ||
| 5 | use tests::threads::mlfqs; | ||
| 6 | |||
| 7 | our ($test); | ||
| 8 | my (@output) = read_text_file ("$test.output"); | ||
| 9 | |||
| 10 | common_checks ("run", @output); | ||
| 11 | @output = get_core_output ("run", @output); | ||
| 12 | |||
| 13 | # Get actual values. | ||
| 14 | local ($_); | ||
| 15 | my (@actual); | ||
| 16 | foreach (@output) { | ||
| 17 | my ($t, $load_avg) = /After (\d+) seconds, load average=(\d+\.\d+)\./ | ||
| 18 | or next; | ||
| 19 | $actual[$t] = $load_avg; | ||
| 20 | } | ||
| 21 | |||
| 22 | # Calculate expected values. | ||
| 23 | my ($load_avg) = 0; | ||
| 24 | my ($recent) = 0; | ||
| 25 | my (@expected); | ||
| 26 | for (my ($t) = 0; $t < 180; $t++) { | ||
| 27 | my ($ready) = $t < 60 ? $t : $t < 120 ? 120 - $t : 0; | ||
| 28 | $load_avg = (59/60) * $load_avg + (1/60) * $ready; | ||
| 29 | $expected[$t] = $load_avg; | ||
| 30 | } | ||
| 31 | |||
| 32 | mlfqs_compare ("time", "%.2f", \@actual, \@expected, 2.5, [2, 178, 2], | ||
| 33 | "Some load average values were missing or " | ||
| 34 | . "differed from those expected " | ||
| 35 | . "by more than 2.5."); | ||
| 36 | pass; | ||
diff --git a/pintos-progos/tests/threads/mlfqs-nice-10.ck b/pintos-progos/tests/threads/mlfqs-nice-10.ck new file mode 100644 index 0000000..53e0abe --- /dev/null +++ b/pintos-progos/tests/threads/mlfqs-nice-10.ck | |||
| @@ -0,0 +1,7 @@ | |||
| 1 | # -*- perl -*- | ||
| 2 | use strict; | ||
| 3 | use warnings; | ||
| 4 | use tests::tests; | ||
| 5 | use tests::threads::mlfqs; | ||
| 6 | |||
| 7 | check_mlfqs_fair ([0...9], 25); | ||
diff --git a/pintos-progos/tests/threads/mlfqs-nice-2.ck b/pintos-progos/tests/threads/mlfqs-nice-2.ck new file mode 100644 index 0000000..ada366b --- /dev/null +++ b/pintos-progos/tests/threads/mlfqs-nice-2.ck | |||
| @@ -0,0 +1,7 @@ | |||
| 1 | # -*- perl -*- | ||
| 2 | use strict; | ||
| 3 | use warnings; | ||
| 4 | use tests::tests; | ||
| 5 | use tests::threads::mlfqs; | ||
| 6 | |||
| 7 | check_mlfqs_fair ([0, 5], 50); | ||
diff --git a/pintos-progos/tests/threads/mlfqs-recent-1.c b/pintos-progos/tests/threads/mlfqs-recent-1.c new file mode 100644 index 0000000..4258671 --- /dev/null +++ b/pintos-progos/tests/threads/mlfqs-recent-1.c | |||
| @@ -0,0 +1,144 @@ | |||
| 1 | /* Checks that recent_cpu is calculated properly for the case of | ||
| 2 | a single ready process. | ||
| 3 | |||
| 4 | The expected output is this (some margin of error is allowed): | ||
| 5 | |||
| 6 | After 2 seconds, recent_cpu is 6.40, load_avg is 0.03. | ||
| 7 | After 4 seconds, recent_cpu is 12.60, load_avg is 0.07. | ||
| 8 | After 6 seconds, recent_cpu is 18.61, load_avg is 0.10. | ||
| 9 | After 8 seconds, recent_cpu is 24.44, load_avg is 0.13. | ||
| 10 | After 10 seconds, recent_cpu is 30.08, load_avg is 0.15. | ||
| 11 | After 12 seconds, recent_cpu is 35.54, load_avg is 0.18. | ||
| 12 | After 14 seconds, recent_cpu is 40.83, load_avg is 0.21. | ||
| 13 | After 16 seconds, recent_cpu is 45.96, load_avg is 0.24. | ||
| 14 | After 18 seconds, recent_cpu is 50.92, load_avg is 0.26. | ||
| 15 | After 20 seconds, recent_cpu is 55.73, load_avg is 0.29. | ||
| 16 | After 22 seconds, recent_cpu is 60.39, load_avg is 0.31. | ||
| 17 | After 24 seconds, recent_cpu is 64.90, load_avg is 0.33. | ||
| 18 | After 26 seconds, recent_cpu is 69.27, load_avg is 0.35. | ||
| 19 | After 28 seconds, recent_cpu is 73.50, load_avg is 0.38. | ||
| 20 | After 30 seconds, recent_cpu is 77.60, load_avg is 0.40. | ||
| 21 | After 32 seconds, recent_cpu is 81.56, load_avg is 0.42. | ||
| 22 | After 34 seconds, recent_cpu is 85.40, load_avg is 0.44. | ||
| 23 | After 36 seconds, recent_cpu is 89.12, load_avg is 0.45. | ||
| 24 | After 38 seconds, recent_cpu is 92.72, load_avg is 0.47. | ||
| 25 | After 40 seconds, recent_cpu is 96.20, load_avg is 0.49. | ||
| 26 | After 42 seconds, recent_cpu is 99.57, load_avg is 0.51. | ||
| 27 | After 44 seconds, recent_cpu is 102.84, load_avg is 0.52. | ||
| 28 | After 46 seconds, recent_cpu is 106.00, load_avg is 0.54. | ||
| 29 | After 48 seconds, recent_cpu is 109.06, load_avg is 0.55. | ||
| 30 | After 50 seconds, recent_cpu is 112.02, load_avg is 0.57. | ||
| 31 | After 52 seconds, recent_cpu is 114.89, load_avg is 0.58. | ||
| 32 | After 54 seconds, recent_cpu is 117.66, load_avg is 0.60. | ||
| 33 | After 56 seconds, recent_cpu is 120.34, load_avg is 0.61. | ||
| 34 | After 58 seconds, recent_cpu is 122.94, load_avg is 0.62. | ||
| 35 | After 60 seconds, recent_cpu is 125.46, load_avg is 0.64. | ||
| 36 | After 62 seconds, recent_cpu is 127.89, load_avg is 0.65. | ||
| 37 | After 64 seconds, recent_cpu is 130.25, load_avg is 0.66. | ||
| 38 | After 66 seconds, recent_cpu is 132.53, load_avg is 0.67. | ||
| 39 | After 68 seconds, recent_cpu is 134.73, load_avg is 0.68. | ||
| 40 | After 70 seconds, recent_cpu is 136.86, load_avg is 0.69. | ||
| 41 | After 72 seconds, recent_cpu is 138.93, load_avg is 0.70. | ||
| 42 | After 74 seconds, recent_cpu is 140.93, load_avg is 0.71. | ||
| 43 | After 76 seconds, recent_cpu is 142.86, load_avg is 0.72. | ||
| 44 | After 78 seconds, recent_cpu is 144.73, load_avg is 0.73. | ||
| 45 | After 80 seconds, recent_cpu is 146.54, load_avg is 0.74. | ||
| 46 | After 82 seconds, recent_cpu is 148.29, load_avg is 0.75. | ||
| 47 | After 84 seconds, recent_cpu is 149.99, load_avg is 0.76. | ||
| 48 | After 86 seconds, recent_cpu is 151.63, load_avg is 0.76. | ||
| 49 | After 88 seconds, recent_cpu is 153.21, load_avg is 0.77. | ||
| 50 | After 90 seconds, recent_cpu is 154.75, load_avg is 0.78. | ||
| 51 | After 92 seconds, recent_cpu is 156.23, load_avg is 0.79. | ||
| 52 | After 94 seconds, recent_cpu is 157.67, load_avg is 0.79. | ||
| 53 | After 96 seconds, recent_cpu is 159.06, load_avg is 0.80. | ||
| 54 | After 98 seconds, recent_cpu is 160.40, load_avg is 0.81. | ||
| 55 | After 100 seconds, recent_cpu is 161.70, load_avg is 0.81. | ||
| 56 | After 102 seconds, recent_cpu is 162.96, load_avg is 0.82. | ||
| 57 | After 104 seconds, recent_cpu is 164.18, load_avg is 0.83. | ||
| 58 | After 106 seconds, recent_cpu is 165.35, load_avg is 0.83. | ||
| 59 | After 108 seconds, recent_cpu is 166.49, load_avg is 0.84. | ||
| 60 | After 110 seconds, recent_cpu is 167.59, load_avg is 0.84. | ||
| 61 | After 112 seconds, recent_cpu is 168.66, load_avg is 0.85. | ||
| 62 | After 114 seconds, recent_cpu is 169.69, load_avg is 0.85. | ||
| 63 | After 116 seconds, recent_cpu is 170.69, load_avg is 0.86. | ||
| 64 | After 118 seconds, recent_cpu is 171.65, load_avg is 0.86. | ||
| 65 | After 120 seconds, recent_cpu is 172.58, load_avg is 0.87. | ||
| 66 | After 122 seconds, recent_cpu is 173.49, load_avg is 0.87. | ||
| 67 | After 124 seconds, recent_cpu is 174.36, load_avg is 0.88. | ||
| 68 | After 126 seconds, recent_cpu is 175.20, load_avg is 0.88. | ||
| 69 | After 128 seconds, recent_cpu is 176.02, load_avg is 0.88. | ||
| 70 | After 130 seconds, recent_cpu is 176.81, load_avg is 0.89. | ||
| 71 | After 132 seconds, recent_cpu is 177.57, load_avg is 0.89. | ||
| 72 | After 134 seconds, recent_cpu is 178.31, load_avg is 0.89. | ||
| 73 | After 136 seconds, recent_cpu is 179.02, load_avg is 0.90. | ||
| 74 | After 138 seconds, recent_cpu is 179.72, load_avg is 0.90. | ||
| 75 | After 140 seconds, recent_cpu is 180.38, load_avg is 0.90. | ||
| 76 | After 142 seconds, recent_cpu is 181.03, load_avg is 0.91. | ||
| 77 | After 144 seconds, recent_cpu is 181.65, load_avg is 0.91. | ||
| 78 | After 146 seconds, recent_cpu is 182.26, load_avg is 0.91. | ||
| 79 | After 148 seconds, recent_cpu is 182.84, load_avg is 0.92. | ||
| 80 | After 150 seconds, recent_cpu is 183.41, load_avg is 0.92. | ||
| 81 | After 152 seconds, recent_cpu is 183.96, load_avg is 0.92. | ||
| 82 | After 154 seconds, recent_cpu is 184.49, load_avg is 0.92. | ||
| 83 | After 156 seconds, recent_cpu is 185.00, load_avg is 0.93. | ||
| 84 | After 158 seconds, recent_cpu is 185.49, load_avg is 0.93. | ||
| 85 | After 160 seconds, recent_cpu is 185.97, load_avg is 0.93. | ||
| 86 | After 162 seconds, recent_cpu is 186.43, load_avg is 0.93. | ||
| 87 | After 164 seconds, recent_cpu is 186.88, load_avg is 0.94. | ||
| 88 | After 166 seconds, recent_cpu is 187.31, load_avg is 0.94. | ||
| 89 | After 168 seconds, recent_cpu is 187.73, load_avg is 0.94. | ||
| 90 | After 170 seconds, recent_cpu is 188.14, load_avg is 0.94. | ||
| 91 | After 172 seconds, recent_cpu is 188.53, load_avg is 0.94. | ||
| 92 | After 174 seconds, recent_cpu is 188.91, load_avg is 0.95. | ||
| 93 | After 176 seconds, recent_cpu is 189.27, load_avg is 0.95. | ||
| 94 | After 178 seconds, recent_cpu is 189.63, load_avg is 0.95. | ||
| 95 | After 180 seconds, recent_cpu is 189.97, load_avg is 0.95. | ||
| 96 | */ | ||
| 97 | |||
| 98 | #include <stdio.h> | ||
| 99 | #include "tests/threads/tests.h" | ||
| 100 | #include "threads/init.h" | ||
| 101 | #include "threads/malloc.h" | ||
| 102 | #include "threads/synch.h" | ||
| 103 | #include "threads/thread.h" | ||
| 104 | #include "devices/timer.h" | ||
| 105 | |||
| 106 | /* Sensitive to assumption that recent_cpu updates happen exactly | ||
| 107 | when timer_ticks() % TIMER_FREQ == 0. */ | ||
| 108 | |||
| 109 | void | ||
| 110 | test_mlfqs_recent_1 (void) | ||
| 111 | { | ||
| 112 | int64_t start_time; | ||
| 113 | int last_elapsed = 0; | ||
| 114 | |||
| 115 | ASSERT (thread_mlfqs); | ||
| 116 | |||
| 117 | do | ||
| 118 | { | ||
| 119 | msg ("Sleeping 10 seconds to allow recent_cpu to decay, please wait..."); | ||
| 120 | start_time = timer_ticks (); | ||
| 121 | timer_sleep (DIV_ROUND_UP (start_time, TIMER_FREQ) - start_time | ||
| 122 | + 10 * TIMER_FREQ); | ||
| 123 | } | ||
| 124 | while (thread_get_recent_cpu () > 700); | ||
| 125 | |||
| 126 | start_time = timer_ticks (); | ||
| 127 | for (;;) | ||
| 128 | { | ||
| 129 | int elapsed = timer_elapsed (start_time); | ||
| 130 | if (elapsed % (TIMER_FREQ * 2) == 0 && elapsed > last_elapsed) | ||
| 131 | { | ||
| 132 | int recent_cpu = thread_get_recent_cpu (); | ||
| 133 | int load_avg = thread_get_load_avg (); | ||
| 134 | int elapsed_seconds = elapsed / TIMER_FREQ; | ||
| 135 | msg ("After %d seconds, recent_cpu is %d.%02d, load_avg is %d.%02d.", | ||
| 136 | elapsed_seconds, | ||
| 137 | recent_cpu / 100, recent_cpu % 100, | ||
| 138 | load_avg / 100, load_avg % 100); | ||
| 139 | if (elapsed_seconds >= 180) | ||
| 140 | break; | ||
| 141 | } | ||
| 142 | last_elapsed = elapsed; | ||
| 143 | } | ||
| 144 | } | ||
diff --git a/pintos-progos/tests/threads/mlfqs-recent-1.ck b/pintos-progos/tests/threads/mlfqs-recent-1.ck new file mode 100644 index 0000000..a2ba44d --- /dev/null +++ b/pintos-progos/tests/threads/mlfqs-recent-1.ck | |||
| @@ -0,0 +1,31 @@ | |||
| 1 | # -*- perl -*- | ||
| 2 | use strict; | ||
| 3 | use warnings; | ||
| 4 | use tests::tests; | ||
| 5 | use tests::threads::mlfqs; | ||
| 6 | |||
| 7 | our ($test); | ||
| 8 | my (@output) = read_text_file ("$test.output"); | ||
| 9 | common_checks ("run", @output); | ||
| 10 | @output = get_core_output ("run", @output); | ||
| 11 | |||
| 12 | # Get actual values. | ||
| 13 | local ($_); | ||
| 14 | my (@actual); | ||
| 15 | foreach (@output) { | ||
| 16 | my ($t, $recent_cpu) = /After (\d+) seconds, recent_cpu is (\d+\.\d+),/ | ||
| 17 | or next; | ||
| 18 | $actual[$t] = $recent_cpu; | ||
| 19 | } | ||
| 20 | |||
| 21 | # Calculate expected values. | ||
| 22 | my ($expected_load_avg, $expected_recent_cpu) | ||
| 23 | = mlfqs_expected_load ([(1) x 180], [(100) x 180]); | ||
| 24 | my (@expected) = @$expected_recent_cpu; | ||
| 25 | |||
| 26 | # Compare actual and expected values. | ||
| 27 | mlfqs_compare ("time", "%.2f", \@actual, \@expected, 2.5, [2, 178, 2], | ||
| 28 | "Some recent_cpu values were missing or " | ||
| 29 | . "differed from those expected " | ||
| 30 | . "by more than 2.5."); | ||
| 31 | pass; | ||
diff --git a/pintos-progos/tests/threads/mlfqs.pm b/pintos-progos/tests/threads/mlfqs.pm new file mode 100644 index 0000000..184ac16 --- /dev/null +++ b/pintos-progos/tests/threads/mlfqs.pm | |||
| @@ -0,0 +1,146 @@ | |||
| 1 | # -*- perl -*- | ||
| 2 | use strict; | ||
| 3 | use warnings; | ||
| 4 | |||
| 5 | sub mlfqs_expected_load { | ||
| 6 | my ($ready, $recent_delta) = @_; | ||
| 7 | my (@load_avg) = 0; | ||
| 8 | my (@recent_cpu) = 0; | ||
| 9 | my ($load_avg) = 0; | ||
| 10 | my ($recent_cpu) = 0; | ||
| 11 | for my $i (0...$#$ready) { | ||
| 12 | $load_avg = (59/60) * $load_avg + (1/60) * $ready->[$i]; | ||
| 13 | push (@load_avg, $load_avg); | ||
| 14 | |||
| 15 | if (defined $recent_delta->[$i]) { | ||
| 16 | my ($twice_load) = $load_avg * 2; | ||
| 17 | my ($load_factor) = $twice_load / ($twice_load + 1); | ||
| 18 | $recent_cpu = ($recent_cpu + $recent_delta->[$i]) * $load_factor; | ||
| 19 | push (@recent_cpu, $recent_cpu); | ||
| 20 | } | ||
| 21 | } | ||
| 22 | return (\@load_avg, \@recent_cpu); | ||
| 23 | } | ||
| 24 | |||
| 25 | sub mlfqs_expected_ticks { | ||
| 26 | my (@nice) = @_; | ||
| 27 | my ($thread_cnt) = scalar (@nice); | ||
| 28 | my (@recent_cpu) = (0) x $thread_cnt; | ||
| 29 | my (@slices) = (0) x $thread_cnt; | ||
| 30 | my (@fifo) = (0) x $thread_cnt; | ||
| 31 | my ($next_fifo) = 1; | ||
| 32 | my ($load_avg) = 0; | ||
| 33 | for my $i (1...750) { | ||
| 34 | if ($i % 25 == 0) { | ||
| 35 | # Update load average. | ||
| 36 | $load_avg = (59/60) * $load_avg + (1/60) * $thread_cnt; | ||
| 37 | |||
| 38 | # Update recent_cpu. | ||
| 39 | my ($twice_load) = $load_avg * 2; | ||
| 40 | my ($load_factor) = $twice_load / ($twice_load + 1); | ||
| 41 | $recent_cpu[$_] = $recent_cpu[$_] * $load_factor + $nice[$_] | ||
| 42 | foreach 0...($thread_cnt - 1); | ||
| 43 | } | ||
| 44 | |||
| 45 | # Update priorities. | ||
| 46 | my (@priority); | ||
| 47 | foreach my $j (0...($thread_cnt - 1)) { | ||
| 48 | my ($priority) = int ($recent_cpu[$j] / 4 + $nice[$j] * 2); | ||
| 49 | $priority = 0 if $priority < 0; | ||
| 50 | $priority = 63 if $priority > 63; | ||
| 51 | push (@priority, $priority); | ||
| 52 | } | ||
| 53 | |||
| 54 | # Choose thread to run. | ||
| 55 | my $max = 0; | ||
| 56 | for my $j (1...$#priority) { | ||
| 57 | if ($priority[$j] < $priority[$max] | ||
| 58 | || ($priority[$j] == $priority[$max] | ||
| 59 | && $fifo[$j] < $fifo[$max])) { | ||
| 60 | $max = $j; | ||
| 61 | } | ||
| 62 | } | ||
| 63 | $fifo[$max] = $next_fifo++; | ||
| 64 | |||
| 65 | # Run thread. | ||
| 66 | $recent_cpu[$max] += 4; | ||
| 67 | $slices[$max] += 4; | ||
| 68 | } | ||
| 69 | return @slices; | ||
| 70 | } | ||
| 71 | |||
| 72 | sub check_mlfqs_fair { | ||
| 73 | my ($nice, $maxdiff) = @_; | ||
| 74 | our ($test); | ||
| 75 | my (@output) = read_text_file ("$test.output"); | ||
| 76 | common_checks ("run", @output); | ||
| 77 | @output = get_core_output ("run", @output); | ||
| 78 | |||
| 79 | my (@actual); | ||
| 80 | local ($_); | ||
| 81 | foreach (@output) { | ||
| 82 | my ($id, $count) = /Thread (\d+) received (\d+) ticks\./ or next; | ||
| 83 | $actual[$id] = $count; | ||
| 84 | } | ||
| 85 | |||
| 86 | my (@expected) = mlfqs_expected_ticks (@$nice); | ||
| 87 | mlfqs_compare ("thread", "%d", | ||
| 88 | \@actual, \@expected, $maxdiff, [0, $#$nice, 1], | ||
| 89 | "Some tick counts were missing or differed from those " | ||
| 90 | . "expected by more than $maxdiff."); | ||
| 91 | pass; | ||
| 92 | } | ||
| 93 | |||
| 94 | sub mlfqs_compare { | ||
| 95 | my ($indep_var, $format, | ||
| 96 | $actual_ref, $expected_ref, $maxdiff, $t_range, $message) = @_; | ||
| 97 | my ($t_min, $t_max, $t_step) = @$t_range; | ||
| 98 | |||
| 99 | my ($ok) = 1; | ||
| 100 | for (my ($t) = $t_min; $t <= $t_max; $t += $t_step) { | ||
| 101 | my ($actual) = $actual_ref->[$t]; | ||
| 102 | my ($expected) = $expected_ref->[$t]; | ||
| 103 | $ok = 0, last | ||
| 104 | if !defined ($actual) || abs ($actual - $expected) > $maxdiff + .01; | ||
| 105 | } | ||
| 106 | return if $ok; | ||
| 107 | |||
| 108 | print "$message\n"; | ||
| 109 | mlfqs_row ($indep_var, "actual", "<->", "expected", "explanation"); | ||
| 110 | mlfqs_row ("------", "--------", "---", "--------", '-' x 40); | ||
| 111 | for (my ($t) = $t_min; $t <= $t_max; $t += $t_step) { | ||
| 112 | my ($actual) = $actual_ref->[$t]; | ||
| 113 | my ($expected) = $expected_ref->[$t]; | ||
| 114 | my ($diff, $rationale); | ||
| 115 | if (!defined $actual) { | ||
| 116 | $actual = 'undef' ; | ||
| 117 | $diff = ''; | ||
| 118 | $rationale = 'Missing value.'; | ||
| 119 | } else { | ||
| 120 | my ($delta) = abs ($actual - $expected); | ||
| 121 | if ($delta > $maxdiff + .01) { | ||
| 122 | my ($excess) = $delta - $maxdiff; | ||
| 123 | if ($actual > $expected) { | ||
| 124 | $diff = '>>>'; | ||
| 125 | $rationale = sprintf "Too big, by $format.", $excess; | ||
| 126 | } else { | ||
| 127 | $diff = '<<<'; | ||
| 128 | $rationale = sprintf "Too small, by $format.", $excess; | ||
| 129 | } | ||
| 130 | } else { | ||
| 131 | $diff = ' = '; | ||
| 132 | $rationale = ''; | ||
| 133 | } | ||
| 134 | $actual = sprintf ($format, $actual); | ||
| 135 | } | ||
| 136 | $expected = sprintf ($format, $expected); | ||
| 137 | mlfqs_row ($t, $actual, $diff, $expected, $rationale); | ||
| 138 | } | ||
| 139 | fail; | ||
| 140 | } | ||
| 141 | |||
| 142 | sub mlfqs_row { | ||
| 143 | printf "%6s %8s %3s %-8s %s\n", @_; | ||
| 144 | } | ||
| 145 | |||
| 146 | 1; | ||
diff --git a/pintos-progos/tests/threads/priority-change.c b/pintos-progos/tests/threads/priority-change.c new file mode 100644 index 0000000..810b05a --- /dev/null +++ b/pintos-progos/tests/threads/priority-change.c | |||
| @@ -0,0 +1,31 @@ | |||
| 1 | /* Verifies that lowering a thread's priority so that it is no | ||
| 2 | longer the highest-priority thread in the system causes it to | ||
| 3 | yield immediately. */ | ||
| 4 | |||
| 5 | #include <stdio.h> | ||
| 6 | #include "tests/threads/tests.h" | ||
| 7 | #include "threads/init.h" | ||
| 8 | #include "threads/thread.h" | ||
| 9 | |||
| 10 | static thread_func changing_thread; | ||
| 11 | |||
| 12 | void | ||
| 13 | test_priority_change (void) | ||
| 14 | { | ||
| 15 | /* This test does not work with the MLFQS. */ | ||
| 16 | ASSERT (!thread_mlfqs); | ||
| 17 | |||
| 18 | msg ("Creating a high-priority thread 2."); | ||
| 19 | thread_create ("thread 2", PRI_DEFAULT + 1, changing_thread, NULL); | ||
| 20 | msg ("Thread 2 should have just lowered its priority."); | ||
| 21 | thread_set_priority (PRI_DEFAULT - 2); | ||
| 22 | msg ("Thread 2 should have just exited."); | ||
| 23 | } | ||
| 24 | |||
| 25 | static void | ||
| 26 | changing_thread (void *aux UNUSED) | ||
| 27 | { | ||
| 28 | msg ("Thread 2 now lowering priority."); | ||
| 29 | thread_set_priority (PRI_DEFAULT - 1); | ||
| 30 | msg ("Thread 2 exiting."); | ||
| 31 | } | ||
diff --git a/pintos-progos/tests/threads/priority-change.ck b/pintos-progos/tests/threads/priority-change.ck new file mode 100644 index 0000000..f4d9b2f --- /dev/null +++ b/pintos-progos/tests/threads/priority-change.ck | |||
| @@ -0,0 +1,14 @@ | |||
| 1 | # -*- perl -*- | ||
| 2 | use strict; | ||
| 3 | use warnings; | ||
| 4 | use tests::tests; | ||
| 5 | check_expected ([<<'EOF']); | ||
| 6 | (priority-change) begin | ||
| 7 | (priority-change) Creating a high-priority thread 2. | ||
| 8 | (priority-change) Thread 2 now lowering priority. | ||
| 9 | (priority-change) Thread 2 should have just lowered its priority. | ||
| 10 | (priority-change) Thread 2 exiting. | ||
| 11 | (priority-change) Thread 2 should have just exited. | ||
| 12 | (priority-change) end | ||
| 13 | EOF | ||
| 14 | pass; | ||
diff --git a/pintos-progos/tests/threads/priority-condvar.c b/pintos-progos/tests/threads/priority-condvar.c new file mode 100644 index 0000000..c1efb1b --- /dev/null +++ b/pintos-progos/tests/threads/priority-condvar.c | |||
| @@ -0,0 +1,53 @@ | |||
| 1 | /* Tests that cond_signal() wakes up the highest-priority thread | ||
| 2 | waiting in cond_wait(). */ | ||
| 3 | |||
| 4 | #include <stdio.h> | ||
| 5 | #include "tests/threads/tests.h" | ||
| 6 | #include "threads/init.h" | ||
| 7 | #include "threads/malloc.h" | ||
| 8 | #include "threads/synch.h" | ||
| 9 | #include "threads/thread.h" | ||
| 10 | #include "devices/timer.h" | ||
| 11 | |||
| 12 | static thread_func priority_condvar_thread; | ||
| 13 | static struct lock lock; | ||
| 14 | static struct condition condition; | ||
| 15 | |||
| 16 | void | ||
| 17 | test_priority_condvar (void) | ||
| 18 | { | ||
| 19 | int i; | ||
| 20 | |||
| 21 | /* This test does not work with the MLFQS. */ | ||
| 22 | ASSERT (!thread_mlfqs); | ||
| 23 | |||
| 24 | lock_init (&lock); | ||
| 25 | cond_init (&condition); | ||
| 26 | |||
| 27 | thread_set_priority (PRI_MIN); | ||
| 28 | for (i = 0; i < 10; i++) | ||
| 29 | { | ||
| 30 | int priority = PRI_DEFAULT - (i + 7) % 10 - 1; | ||
| 31 | char name[16]; | ||
| 32 | snprintf (name, sizeof name, "priority %d", priority); | ||
| 33 | thread_create (name, priority, priority_condvar_thread, NULL); | ||
| 34 | } | ||
| 35 | |||
| 36 | for (i = 0; i < 10; i++) | ||
| 37 | { | ||
| 38 | lock_acquire (&lock); | ||
| 39 | msg ("Signaling..."); | ||
| 40 | cond_signal (&condition, &lock); | ||
| 41 | lock_release (&lock); | ||
| 42 | } | ||
| 43 | } | ||
| 44 | |||
| 45 | static void | ||
| 46 | priority_condvar_thread (void *aux UNUSED) | ||
| 47 | { | ||
| 48 | msg ("Thread %s starting.", thread_name ()); | ||
| 49 | lock_acquire (&lock); | ||
| 50 | cond_wait (&condition, &lock); | ||
| 51 | msg ("Thread %s woke up.", thread_name ()); | ||
| 52 | lock_release (&lock); | ||
| 53 | } | ||
diff --git a/pintos-progos/tests/threads/priority-condvar.ck b/pintos-progos/tests/threads/priority-condvar.ck new file mode 100644 index 0000000..195c1ab --- /dev/null +++ b/pintos-progos/tests/threads/priority-condvar.ck | |||
| @@ -0,0 +1,39 @@ | |||
| 1 | # -*- perl -*- | ||
| 2 | use strict; | ||
| 3 | use warnings; | ||
| 4 | use tests::tests; | ||
| 5 | check_expected ([<<'EOF']); | ||
| 6 | (priority-condvar) begin | ||
| 7 | (priority-condvar) Thread priority 23 starting. | ||
| 8 | (priority-condvar) Thread priority 22 starting. | ||
| 9 | (priority-condvar) Thread priority 21 starting. | ||
| 10 | (priority-condvar) Thread priority 30 starting. | ||
| 11 | (priority-condvar) Thread priority 29 starting. | ||
| 12 | (priority-condvar) Thread priority 28 starting. | ||
| 13 | (priority-condvar) Thread priority 27 starting. | ||
| 14 | (priority-condvar) Thread priority 26 starting. | ||
| 15 | (priority-condvar) Thread priority 25 starting. | ||
| 16 | (priority-condvar) Thread priority 24 starting. | ||
| 17 | (priority-condvar) Signaling... | ||
| 18 | (priority-condvar) Thread priority 30 woke up. | ||
| 19 | (priority-condvar) Signaling... | ||
| 20 | (priority-condvar) Thread priority 29 woke up. | ||
| 21 | (priority-condvar) Signaling... | ||
| 22 | (priority-condvar) Thread priority 28 woke up. | ||
| 23 | (priority-condvar) Signaling... | ||
| 24 | (priority-condvar) Thread priority 27 woke up. | ||
| 25 | (priority-condvar) Signaling... | ||
| 26 | (priority-condvar) Thread priority 26 woke up. | ||
| 27 | (priority-condvar) Signaling... | ||
| 28 | (priority-condvar) Thread priority 25 woke up. | ||
| 29 | (priority-condvar) Signaling... | ||
| 30 | (priority-condvar) Thread priority 24 woke up. | ||
| 31 | (priority-condvar) Signaling... | ||
| 32 | (priority-condvar) Thread priority 23 woke up. | ||
| 33 | (priority-condvar) Signaling... | ||
| 34 | (priority-condvar) Thread priority 22 woke up. | ||
| 35 | (priority-condvar) Signaling... | ||
| 36 | (priority-condvar) Thread priority 21 woke up. | ||
| 37 | (priority-condvar) end | ||
| 38 | EOF | ||
| 39 | pass; | ||
diff --git a/pintos-progos/tests/threads/priority-donate-chain.c b/pintos-progos/tests/threads/priority-donate-chain.c new file mode 100644 index 0000000..3ffabca --- /dev/null +++ b/pintos-progos/tests/threads/priority-donate-chain.c | |||
| @@ -0,0 +1,114 @@ | |||
| 1 | /* The main thread set its priority to PRI_MIN and creates 7 threads | ||
| 2 | (thread 1..7) with priorities PRI_MIN + 3, 6, 9, 12, ... | ||
| 3 | The main thread initializes 8 locks: lock 0..7 and acquires lock 0. | ||
| 4 | |||
| 5 | When thread[i] starts, it first acquires lock[i] (unless i == 7.) | ||
| 6 | Subsequently, thread[i] attempts to acquire lock[i-1], which is held by | ||
| 7 | thread[i-1], except for lock[0], which is held by the main thread. | ||
| 8 | Because the lock is held, thread[i] donates its priority to thread[i-1], | ||
| 9 | which donates to thread[i-2], and so on until the main thread | ||
| 10 | receives the donation. | ||
| 11 | |||
| 12 | After threads[1..7] have been created and are blocked on locks[0..7], | ||
| 13 | the main thread releases lock[0], unblocking thread[1], and being | ||
| 14 | preempted by it. | ||
| 15 | Thread[1] then completes acquiring lock[0], then releases lock[0], | ||
| 16 | then releases lock[1], unblocking thread[2], etc. | ||
| 17 | Thread[7] finally acquires & releases lock[7] and exits, allowing | ||
| 18 | thread[6], then thread[5] etc. to run and exit until finally the | ||
| 19 | main thread exits. | ||
| 20 | |||
| 21 | In addition, interloper threads are created at priority levels | ||
| 22 | p = PRI_MIN + 2, 5, 8, 11, ... which should not be run until the | ||
| 23 | corresponding thread with priority p + 1 has finished. | ||
| 24 | |||
| 25 | Written by Godmar Back <gback@cs.vt.edu> */ | ||
| 26 | |||
| 27 | #include <stdio.h> | ||
| 28 | #include "tests/threads/tests.h" | ||
| 29 | #include "threads/init.h" | ||
| 30 | #include "threads/synch.h" | ||
| 31 | #include "threads/thread.h" | ||
| 32 | |||
| 33 | #define NESTING_DEPTH 8 | ||
| 34 | |||
| 35 | struct lock_pair | ||
| 36 | { | ||
| 37 | struct lock *second; | ||
| 38 | struct lock *first; | ||
| 39 | }; | ||
| 40 | |||
| 41 | static thread_func donor_thread_func; | ||
| 42 | static thread_func interloper_thread_func; | ||
| 43 | |||
| 44 | void | ||
| 45 | test_priority_donate_chain (void) | ||
| 46 | { | ||
| 47 | int i; | ||
| 48 | struct lock locks[NESTING_DEPTH - 1]; | ||
| 49 | struct lock_pair lock_pairs[NESTING_DEPTH]; | ||
| 50 | |||
| 51 | /* This test does not work with the MLFQS. */ | ||
| 52 | ASSERT (!thread_mlfqs); | ||
| 53 | |||
| 54 | thread_set_priority (PRI_MIN); | ||
| 55 | |||
| 56 | for (i = 0; i < NESTING_DEPTH - 1; i++) | ||
| 57 | lock_init (&locks[i]); | ||
| 58 | |||
| 59 | lock_acquire (&locks[0]); | ||
| 60 | msg ("%s got lock.", thread_name ()); | ||
| 61 | |||
| 62 | for (i = 1; i < NESTING_DEPTH; i++) | ||
| 63 | { | ||
| 64 | char name[16]; | ||
| 65 | int thread_priority; | ||
| 66 | |||
| 67 | snprintf (name, sizeof name, "thread %d", i); | ||
| 68 | thread_priority = PRI_MIN + i * 3; | ||
| 69 | lock_pairs[i].first = i < NESTING_DEPTH - 1 ? locks + i: NULL; | ||
| 70 | lock_pairs[i].second = locks + i - 1; | ||
| 71 | |||
| 72 | thread_create (name, thread_priority, donor_thread_func, lock_pairs + i); | ||
| 73 | msg ("%s should have priority %d. Actual priority: %d.", | ||
| 74 | thread_name (), thread_priority, thread_get_priority ()); | ||
| 75 | |||
| 76 | snprintf (name, sizeof name, "interloper %d", i); | ||
| 77 | thread_create (name, thread_priority - 1, interloper_thread_func, NULL); | ||
| 78 | } | ||
| 79 | |||
| 80 | lock_release (&locks[0]); | ||
| 81 | msg ("%s finishing with priority %d.", thread_name (), | ||
| 82 | thread_get_priority ()); | ||
| 83 | } | ||
| 84 | |||
| 85 | static void | ||
| 86 | donor_thread_func (void *locks_) | ||
| 87 | { | ||
| 88 | struct lock_pair *locks = locks_; | ||
| 89 | |||
| 90 | if (locks->first) | ||
| 91 | lock_acquire (locks->first); | ||
| 92 | |||
| 93 | lock_acquire (locks->second); | ||
| 94 | msg ("%s got lock", thread_name ()); | ||
| 95 | |||
| 96 | lock_release (locks->second); | ||
| 97 | msg ("%s should have priority %d. Actual priority: %d", | ||
| 98 | thread_name (), (NESTING_DEPTH - 1) * 3, | ||
| 99 | thread_get_priority ()); | ||
| 100 | |||
| 101 | if (locks->first) | ||
| 102 | lock_release (locks->first); | ||
| 103 | |||
| 104 | msg ("%s finishing with priority %d.", thread_name (), | ||
| 105 | thread_get_priority ()); | ||
| 106 | } | ||
| 107 | |||
| 108 | static void | ||
| 109 | interloper_thread_func (void *arg_ UNUSED) | ||
| 110 | { | ||
| 111 | msg ("%s finished.", thread_name ()); | ||
| 112 | } | ||
| 113 | |||
| 114 | // vim: sw=2 | ||
diff --git a/pintos-progos/tests/threads/priority-donate-chain.ck b/pintos-progos/tests/threads/priority-donate-chain.ck new file mode 100644 index 0000000..213e649 --- /dev/null +++ b/pintos-progos/tests/threads/priority-donate-chain.ck | |||
| @@ -0,0 +1,46 @@ | |||
| 1 | # -*- perl -*- | ||
| 2 | use strict; | ||
| 3 | use warnings; | ||
| 4 | use tests::tests; | ||
| 5 | check_expected ([<<'EOF']); | ||
| 6 | (priority-donate-chain) begin | ||
| 7 | (priority-donate-chain) main got lock. | ||
| 8 | (priority-donate-chain) main should have priority 3. Actual priority: 3. | ||
| 9 | (priority-donate-chain) main should have priority 6. Actual priority: 6. | ||
| 10 | (priority-donate-chain) main should have priority 9. Actual priority: 9. | ||
| 11 | (priority-donate-chain) main should have priority 12. Actual priority: 12. | ||
| 12 | (priority-donate-chain) main should have priority 15. Actual priority: 15. | ||
| 13 | (priority-donate-chain) main should have priority 18. Actual priority: 18. | ||
| 14 | (priority-donate-chain) main should have priority 21. Actual priority: 21. | ||
| 15 | (priority-donate-chain) thread 1 got lock | ||
| 16 | (priority-donate-chain) thread 1 should have priority 21. Actual priority: 21 | ||
| 17 | (priority-donate-chain) thread 2 got lock | ||
| 18 | (priority-donate-chain) thread 2 should have priority 21. Actual priority: 21 | ||
| 19 | (priority-donate-chain) thread 3 got lock | ||
| 20 | (priority-donate-chain) thread 3 should have priority 21. Actual priority: 21 | ||
| 21 | (priority-donate-chain) thread 4 got lock | ||
| 22 | (priority-donate-chain) thread 4 should have priority 21. Actual priority: 21 | ||
| 23 | (priority-donate-chain) thread 5 got lock | ||
| 24 | (priority-donate-chain) thread 5 should have priority 21. Actual priority: 21 | ||
| 25 | (priority-donate-chain) thread 6 got lock | ||
| 26 | (priority-donate-chain) thread 6 should have priority 21. Actual priority: 21 | ||
| 27 | (priority-donate-chain) thread 7 got lock | ||
| 28 | (priority-donate-chain) thread 7 should have priority 21. Actual priority: 21 | ||
| 29 | (priority-donate-chain) thread 7 finishing with priority 21. | ||
| 30 | (priority-donate-chain) interloper 7 finished. | ||
| 31 | (priority-donate-chain) thread 6 finishing with priority 18. | ||
| 32 | (priority-donate-chain) interloper 6 finished. | ||
| 33 | (priority-donate-chain) thread 5 finishing with priority 15. | ||
| 34 | (priority-donate-chain) interloper 5 finished. | ||
| 35 | (priority-donate-chain) thread 4 finishing with priority 12. | ||
| 36 | (priority-donate-chain) interloper 4 finished. | ||
| 37 | (priority-donate-chain) thread 3 finishing with priority 9. | ||
| 38 | (priority-donate-chain) interloper 3 finished. | ||
| 39 | (priority-donate-chain) thread 2 finishing with priority 6. | ||
| 40 | (priority-donate-chain) interloper 2 finished. | ||
| 41 | (priority-donate-chain) thread 1 finishing with priority 3. | ||
| 42 | (priority-donate-chain) interloper 1 finished. | ||
| 43 | (priority-donate-chain) main finishing with priority 0. | ||
| 44 | (priority-donate-chain) end | ||
| 45 | EOF | ||
| 46 | pass; | ||
diff --git a/pintos-progos/tests/threads/priority-donate-lower.c b/pintos-progos/tests/threads/priority-donate-lower.c new file mode 100644 index 0000000..4965d75 --- /dev/null +++ b/pintos-progos/tests/threads/priority-donate-lower.c | |||
| @@ -0,0 +1,51 @@ | |||
| 1 | /* The main thread acquires a lock. Then it creates a | ||
| 2 | higher-priority thread that blocks acquiring the lock, causing | ||
| 3 | it to donate their priorities to the main thread. The main | ||
| 4 | thread attempts to lower its priority, which should not take | ||
| 5 | effect until the donation is released. */ | ||
| 6 | |||
| 7 | #include <stdio.h> | ||
| 8 | #include "tests/threads/tests.h" | ||
| 9 | #include "threads/init.h" | ||
| 10 | #include "threads/synch.h" | ||
| 11 | #include "threads/thread.h" | ||
| 12 | |||
| 13 | static thread_func acquire_thread_func; | ||
| 14 | |||
| 15 | void | ||
| 16 | test_priority_donate_lower (void) | ||
| 17 | { | ||
| 18 | struct lock lock; | ||
| 19 | |||
| 20 | /* This test does not work with the MLFQS. */ | ||
| 21 | ASSERT (!thread_mlfqs); | ||
| 22 | |||
| 23 | /* Make sure our priority is the default. */ | ||
| 24 | ASSERT (thread_get_priority () == PRI_DEFAULT); | ||
| 25 | |||
| 26 | lock_init (&lock); | ||
| 27 | lock_acquire (&lock); | ||
| 28 | thread_create ("acquire", PRI_DEFAULT + 10, acquire_thread_func, &lock); | ||
| 29 | msg ("Main thread should have priority %d. Actual priority: %d.", | ||
| 30 | PRI_DEFAULT + 10, thread_get_priority ()); | ||
| 31 | |||
| 32 | msg ("Lowering base priority..."); | ||
| 33 | thread_set_priority (PRI_DEFAULT - 10); | ||
| 34 | msg ("Main thread should have priority %d. Actual priority: %d.", | ||
| 35 | PRI_DEFAULT + 10, thread_get_priority ()); | ||
| 36 | lock_release (&lock); | ||
| 37 | msg ("acquire must already have finished."); | ||
| 38 | msg ("Main thread should have priority %d. Actual priority: %d.", | ||
| 39 | PRI_DEFAULT - 10, thread_get_priority ()); | ||
| 40 | } | ||
| 41 | |||
| 42 | static void | ||
| 43 | acquire_thread_func (void *lock_) | ||
| 44 | { | ||
| 45 | struct lock *lock = lock_; | ||
| 46 | |||
| 47 | lock_acquire (lock); | ||
| 48 | msg ("acquire: got the lock"); | ||
| 49 | lock_release (lock); | ||
| 50 | msg ("acquire: done"); | ||
| 51 | } | ||
diff --git a/pintos-progos/tests/threads/priority-donate-lower.ck b/pintos-progos/tests/threads/priority-donate-lower.ck new file mode 100644 index 0000000..c9bb61b --- /dev/null +++ b/pintos-progos/tests/threads/priority-donate-lower.ck | |||
| @@ -0,0 +1,16 @@ | |||
| 1 | # -*- perl -*- | ||
| 2 | use strict; | ||
| 3 | use warnings; | ||
| 4 | use tests::tests; | ||
| 5 | check_expected ([<<'EOF']); | ||
| 6 | (priority-donate-lower) begin | ||
| 7 | (priority-donate-lower) Main thread should have priority 41. Actual priority: 41. | ||
| 8 | (priority-donate-lower) Lowering base priority... | ||
| 9 | (priority-donate-lower) Main thread should have priority 41. Actual priority: 41. | ||
| 10 | (priority-donate-lower) acquire: got the lock | ||
| 11 | (priority-donate-lower) acquire: done | ||
| 12 | (priority-donate-lower) acquire must already have finished. | ||
| 13 | (priority-donate-lower) Main thread should have priority 21. Actual priority: 21. | ||
| 14 | (priority-donate-lower) end | ||
| 15 | EOF | ||
| 16 | pass; | ||
diff --git a/pintos-progos/tests/threads/priority-donate-multiple.c b/pintos-progos/tests/threads/priority-donate-multiple.c new file mode 100644 index 0000000..df4689c --- /dev/null +++ b/pintos-progos/tests/threads/priority-donate-multiple.c | |||
| @@ -0,0 +1,77 @@ | |||
| 1 | /* The main thread acquires locks A and B, then it creates two | ||
| 2 | higher-priority threads. Each of these threads blocks | ||
| 3 | acquiring one of the locks and thus donate their priority to | ||
| 4 | the main thread. The main thread releases the locks in turn | ||
| 5 | and relinquishes its donated priorities. | ||
| 6 | |||
| 7 | Based on a test originally submitted for Stanford's CS 140 in | ||
| 8 | winter 1999 by Matt Franklin <startled@leland.stanford.edu>, | ||
| 9 | Greg Hutchins <gmh@leland.stanford.edu>, Yu Ping Hu | ||
| 10 | <yph@cs.stanford.edu>. Modified by arens. */ | ||
| 11 | |||
| 12 | #include <stdio.h> | ||
| 13 | #include "tests/threads/tests.h" | ||
| 14 | #include "threads/init.h" | ||
| 15 | #include "threads/synch.h" | ||
| 16 | #include "threads/thread.h" | ||
| 17 | |||
| 18 | static thread_func a_thread_func; | ||
| 19 | static thread_func b_thread_func; | ||
| 20 | |||
| 21 | void | ||
| 22 | test_priority_donate_multiple (void) | ||
| 23 | { | ||
| 24 | struct lock a, b; | ||
| 25 | |||
| 26 | /* This test does not work with the MLFQS. */ | ||
| 27 | ASSERT (!thread_mlfqs); | ||
| 28 | |||
| 29 | /* Make sure our priority is the default. */ | ||
| 30 | ASSERT (thread_get_priority () == PRI_DEFAULT); | ||
| 31 | |||
| 32 | lock_init (&a); | ||
| 33 | lock_init (&b); | ||
| 34 | |||
| 35 | lock_acquire (&a); | ||
| 36 | lock_acquire (&b); | ||
| 37 | |||
| 38 | thread_create ("a", PRI_DEFAULT + 1, a_thread_func, &a); | ||
| 39 | msg ("Main thread should have priority %d. Actual priority: %d.", | ||
| 40 | PRI_DEFAULT + 1, thread_get_priority ()); | ||
| 41 | |||
| 42 | thread_create ("b", PRI_DEFAULT + 2, b_thread_func, &b); | ||
| 43 | msg ("Main thread should have priority %d. Actual priority: %d.", | ||
| 44 | PRI_DEFAULT + 2, thread_get_priority ()); | ||
| 45 | |||
| 46 | lock_release (&b); | ||
| 47 | msg ("Thread b should have just finished."); | ||
| 48 | msg ("Main thread should have priority %d. Actual priority: %d.", | ||
| 49 | PRI_DEFAULT + 1, thread_get_priority ()); | ||
| 50 | |||
| 51 | lock_release (&a); | ||
| 52 | msg ("Thread a should have just finished."); | ||
| 53 | msg ("Main thread should have priority %d. Actual priority: %d.", | ||
| 54 | PRI_DEFAULT, thread_get_priority ()); | ||
| 55 | } | ||
| 56 | |||
| 57 | static void | ||
| 58 | a_thread_func (void *lock_) | ||
| 59 | { | ||
| 60 | struct lock *lock = lock_; | ||
| 61 | |||
| 62 | lock_acquire (lock); | ||
| 63 | msg ("Thread a acquired lock a."); | ||
| 64 | lock_release (lock); | ||
| 65 | msg ("Thread a finished."); | ||
| 66 | } | ||
| 67 | |||
| 68 | static void | ||
| 69 | b_thread_func (void *lock_) | ||
| 70 | { | ||
| 71 | struct lock *lock = lock_; | ||
| 72 | |||
| 73 | lock_acquire (lock); | ||
| 74 | msg ("Thread b acquired lock b."); | ||
| 75 | lock_release (lock); | ||
| 76 | msg ("Thread b finished."); | ||
| 77 | } | ||
diff --git a/pintos-progos/tests/threads/priority-donate-multiple.ck b/pintos-progos/tests/threads/priority-donate-multiple.ck new file mode 100644 index 0000000..0afd20b --- /dev/null +++ b/pintos-progos/tests/threads/priority-donate-multiple.ck | |||
| @@ -0,0 +1,19 @@ | |||
| 1 | # -*- perl -*- | ||
| 2 | use strict; | ||
| 3 | use warnings; | ||
| 4 | use tests::tests; | ||
| 5 | check_expected ([<<'EOF']); | ||
| 6 | (priority-donate-multiple) begin | ||
| 7 | (priority-donate-multiple) Main thread should have priority 32. Actual priority: 32. | ||
| 8 | (priority-donate-multiple) Main thread should have priority 33. Actual priority: 33. | ||
| 9 | (priority-donate-multiple) Thread b acquired lock b. | ||
| 10 | (priority-donate-multiple) Thread b finished. | ||
| 11 | (priority-donate-multiple) Thread b should have just finished. | ||
| 12 | (priority-donate-multiple) Main thread should have priority 32. Actual priority: 32. | ||
| 13 | (priority-donate-multiple) Thread a acquired lock a. | ||
| 14 | (priority-donate-multiple) Thread a finished. | ||
| 15 | (priority-donate-multiple) Thread a should have just finished. | ||
| 16 | (priority-donate-multiple) Main thread should have priority 31. Actual priority: 31. | ||
| 17 | (priority-donate-multiple) end | ||
| 18 | EOF | ||
| 19 | pass; | ||
diff --git a/pintos-progos/tests/threads/priority-donate-multiple2.c b/pintos-progos/tests/threads/priority-donate-multiple2.c new file mode 100644 index 0000000..7f65fef --- /dev/null +++ b/pintos-progos/tests/threads/priority-donate-multiple2.c | |||
| @@ -0,0 +1,90 @@ | |||
| 1 | /* The main thread acquires locks A and B, then it creates three | ||
| 2 | higher-priority threads. The first two of these threads block | ||
| 3 | acquiring one of the locks and thus donate their priority to | ||
| 4 | the main thread. The main thread releases the locks in turn | ||
| 5 | and relinquishes its donated priorities, allowing the third thread | ||
| 6 | to run. | ||
| 7 | |||
| 8 | In this test, the main thread releases the locks in a different | ||
| 9 | order compared to priority-donate-multiple.c. | ||
| 10 | |||
| 11 | Written by Godmar Back <gback@cs.vt.edu>. | ||
| 12 | Based on a test originally submitted for Stanford's CS 140 in | ||
| 13 | winter 1999 by Matt Franklin <startled@leland.stanford.edu>, | ||
| 14 | Greg Hutchins <gmh@leland.stanford.edu>, Yu Ping Hu | ||
| 15 | <yph@cs.stanford.edu>. Modified by arens. */ | ||
| 16 | |||
| 17 | #include <stdio.h> | ||
| 18 | #include "tests/threads/tests.h" | ||
| 19 | #include "threads/init.h" | ||
| 20 | #include "threads/synch.h" | ||
| 21 | #include "threads/thread.h" | ||
| 22 | |||
| 23 | static thread_func a_thread_func; | ||
| 24 | static thread_func b_thread_func; | ||
| 25 | static thread_func c_thread_func; | ||
| 26 | |||
| 27 | void | ||
| 28 | test_priority_donate_multiple2 (void) | ||
| 29 | { | ||
| 30 | struct lock a, b; | ||
| 31 | |||
| 32 | /* This test does not work with the MLFQS. */ | ||
| 33 | ASSERT (!thread_mlfqs); | ||
| 34 | |||
| 35 | /* Make sure our priority is the default. */ | ||
| 36 | ASSERT (thread_get_priority () == PRI_DEFAULT); | ||
| 37 | |||
| 38 | lock_init (&a); | ||
| 39 | lock_init (&b); | ||
| 40 | |||
| 41 | lock_acquire (&a); | ||
| 42 | lock_acquire (&b); | ||
| 43 | |||
| 44 | thread_create ("a", PRI_DEFAULT + 3, a_thread_func, &a); | ||
| 45 | msg ("Main thread should have priority %d. Actual priority: %d.", | ||
| 46 | PRI_DEFAULT + 3, thread_get_priority ()); | ||
| 47 | |||
| 48 | thread_create ("c", PRI_DEFAULT + 1, c_thread_func, NULL); | ||
| 49 | |||
| 50 | thread_create ("b", PRI_DEFAULT + 5, b_thread_func, &b); | ||
| 51 | msg ("Main thread should have priority %d. Actual priority: %d.", | ||
| 52 | PRI_DEFAULT + 5, thread_get_priority ()); | ||
| 53 | |||
| 54 | lock_release (&a); | ||
| 55 | msg ("Main thread should have priority %d. Actual priority: %d.", | ||
| 56 | PRI_DEFAULT + 5, thread_get_priority ()); | ||
| 57 | |||
| 58 | lock_release (&b); | ||
| 59 | msg ("Threads b, a, c should have just finished, in that order."); | ||
| 60 | msg ("Main thread should have priority %d. Actual priority: %d.", | ||
| 61 | PRI_DEFAULT, thread_get_priority ()); | ||
| 62 | } | ||
| 63 | |||
| 64 | static void | ||
| 65 | a_thread_func (void *lock_) | ||
| 66 | { | ||
| 67 | struct lock *lock = lock_; | ||
| 68 | |||
| 69 | lock_acquire (lock); | ||
| 70 | msg ("Thread a acquired lock a."); | ||
| 71 | lock_release (lock); | ||
| 72 | msg ("Thread a finished."); | ||
| 73 | } | ||
| 74 | |||
| 75 | static void | ||
| 76 | b_thread_func (void *lock_) | ||
| 77 | { | ||
| 78 | struct lock *lock = lock_; | ||
| 79 | |||
| 80 | lock_acquire (lock); | ||
| 81 | msg ("Thread b acquired lock b."); | ||
| 82 | lock_release (lock); | ||
| 83 | msg ("Thread b finished."); | ||
| 84 | } | ||
| 85 | |||
| 86 | static void | ||
| 87 | c_thread_func (void *a_ UNUSED) | ||
| 88 | { | ||
| 89 | msg ("Thread c finished."); | ||
| 90 | } | ||
diff --git a/pintos-progos/tests/threads/priority-donate-multiple2.ck b/pintos-progos/tests/threads/priority-donate-multiple2.ck new file mode 100644 index 0000000..b23533a --- /dev/null +++ b/pintos-progos/tests/threads/priority-donate-multiple2.ck | |||
| @@ -0,0 +1,19 @@ | |||
| 1 | # -*- perl -*- | ||
| 2 | use strict; | ||
| 3 | use warnings; | ||
| 4 | use tests::tests; | ||
| 5 | check_expected ([<<'EOF']); | ||
| 6 | (priority-donate-multiple2) begin | ||
| 7 | (priority-donate-multiple2) Main thread should have priority 34. Actual priority: 34. | ||
| 8 | (priority-donate-multiple2) Main thread should have priority 36. Actual priority: 36. | ||
| 9 | (priority-donate-multiple2) Main thread should have priority 36. Actual priority: 36. | ||
| 10 | (priority-donate-multiple2) Thread b acquired lock b. | ||
| 11 | (priority-donate-multiple2) Thread b finished. | ||
| 12 | (priority-donate-multiple2) Thread a acquired lock a. | ||
| 13 | (priority-donate-multiple2) Thread a finished. | ||
| 14 | (priority-donate-multiple2) Thread c finished. | ||
| 15 | (priority-donate-multiple2) Threads b, a, c should have just finished, in that order. | ||
| 16 | (priority-donate-multiple2) Main thread should have priority 31. Actual priority: 31. | ||
| 17 | (priority-donate-multiple2) end | ||
| 18 | EOF | ||
| 19 | pass; | ||
diff --git a/pintos-progos/tests/threads/priority-donate-nest.c b/pintos-progos/tests/threads/priority-donate-nest.c new file mode 100644 index 0000000..3a3a9a5 --- /dev/null +++ b/pintos-progos/tests/threads/priority-donate-nest.c | |||
| @@ -0,0 +1,94 @@ | |||
| 1 | /* Low-priority main thread L acquires lock A. Medium-priority | ||
| 2 | thread M then acquires lock B then blocks on acquiring lock A. | ||
| 3 | High-priority thread H then blocks on acquiring lock B. Thus, | ||
| 4 | thread H donates its priority to M, which in turn donates it | ||
| 5 | to thread L. | ||
| 6 | |||
| 7 | Based on a test originally submitted for Stanford's CS 140 in | ||
| 8 | winter 1999 by Matt Franklin <startled@leland.stanford.edu>, | ||
| 9 | Greg Hutchins <gmh@leland.stanford.edu>, Yu Ping Hu | ||
| 10 | <yph@cs.stanford.edu>. Modified by arens. */ | ||
| 11 | |||
| 12 | #include <stdio.h> | ||
| 13 | #include "tests/threads/tests.h" | ||
| 14 | #include "threads/init.h" | ||
| 15 | #include "threads/synch.h" | ||
| 16 | #include "threads/thread.h" | ||
| 17 | |||
| 18 | struct locks | ||
| 19 | { | ||
| 20 | struct lock *a; | ||
| 21 | struct lock *b; | ||
| 22 | }; | ||
| 23 | |||
| 24 | static thread_func medium_thread_func; | ||
| 25 | static thread_func high_thread_func; | ||
| 26 | |||
| 27 | void | ||
| 28 | test_priority_donate_nest (void) | ||
| 29 | { | ||
| 30 | struct lock a, b; | ||
| 31 | struct locks locks; | ||
| 32 | |||
| 33 | /* This test does not work with the MLFQS. */ | ||
| 34 | ASSERT (!thread_mlfqs); | ||
| 35 | |||
| 36 | /* Make sure our priority is the default. */ | ||
| 37 | ASSERT (thread_get_priority () == PRI_DEFAULT); | ||
| 38 | |||
| 39 | lock_init (&a); | ||
| 40 | lock_init (&b); | ||
| 41 | |||
| 42 | lock_acquire (&a); | ||
| 43 | |||
| 44 | locks.a = &a; | ||
| 45 | locks.b = &b; | ||
| 46 | thread_create ("medium", PRI_DEFAULT + 1, medium_thread_func, &locks); | ||
| 47 | thread_yield (); | ||
| 48 | msg ("Low thread should have priority %d. Actual priority: %d.", | ||
| 49 | PRI_DEFAULT + 1, thread_get_priority ()); | ||
| 50 | |||
| 51 | thread_create ("high", PRI_DEFAULT + 2, high_thread_func, &b); | ||
| 52 | thread_yield (); | ||
| 53 | msg ("Low thread should have priority %d. Actual priority: %d.", | ||
| 54 | PRI_DEFAULT + 2, thread_get_priority ()); | ||
| 55 | |||
| 56 | lock_release (&a); | ||
| 57 | thread_yield (); | ||
| 58 | msg ("Medium thread should just have finished."); | ||
| 59 | msg ("Low thread should have priority %d. Actual priority: %d.", | ||
| 60 | PRI_DEFAULT, thread_get_priority ()); | ||
| 61 | } | ||
| 62 | |||
| 63 | static void | ||
| 64 | medium_thread_func (void *locks_) | ||
| 65 | { | ||
| 66 | struct locks *locks = locks_; | ||
| 67 | |||
| 68 | lock_acquire (locks->b); | ||
| 69 | lock_acquire (locks->a); | ||
| 70 | |||
| 71 | msg ("Medium thread should have priority %d. Actual priority: %d.", | ||
| 72 | PRI_DEFAULT + 2, thread_get_priority ()); | ||
| 73 | msg ("Medium thread got the lock."); | ||
| 74 | |||
| 75 | lock_release (locks->a); | ||
| 76 | thread_yield (); | ||
| 77 | |||
| 78 | lock_release (locks->b); | ||
| 79 | thread_yield (); | ||
| 80 | |||
| 81 | msg ("High thread should have just finished."); | ||
| 82 | msg ("Middle thread finished."); | ||
| 83 | } | ||
| 84 | |||
| 85 | static void | ||
| 86 | high_thread_func (void *lock_) | ||
| 87 | { | ||
| 88 | struct lock *lock = lock_; | ||
| 89 | |||
| 90 | lock_acquire (lock); | ||
| 91 | msg ("High thread got the lock."); | ||
| 92 | lock_release (lock); | ||
| 93 | msg ("High thread finished."); | ||
| 94 | } | ||
diff --git a/pintos-progos/tests/threads/priority-donate-nest.ck b/pintos-progos/tests/threads/priority-donate-nest.ck new file mode 100644 index 0000000..923460e --- /dev/null +++ b/pintos-progos/tests/threads/priority-donate-nest.ck | |||
| @@ -0,0 +1,19 @@ | |||
| 1 | # -*- perl -*- | ||
| 2 | use strict; | ||
| 3 | use warnings; | ||
| 4 | use tests::tests; | ||
| 5 | check_expected ([<<'EOF']); | ||
| 6 | (priority-donate-nest) begin | ||
| 7 | (priority-donate-nest) Low thread should have priority 32. Actual priority: 32. | ||
| 8 | (priority-donate-nest) Low thread should have priority 33. Actual priority: 33. | ||
| 9 | (priority-donate-nest) Medium thread should have priority 33. Actual priority: 33. | ||
| 10 | (priority-donate-nest) Medium thread got the lock. | ||
| 11 | (priority-donate-nest) High thread got the lock. | ||
| 12 | (priority-donate-nest) High thread finished. | ||
| 13 | (priority-donate-nest) High thread should have just finished. | ||
| 14 | (priority-donate-nest) Middle thread finished. | ||
| 15 | (priority-donate-nest) Medium thread should just have finished. | ||
| 16 | (priority-donate-nest) Low thread should have priority 31. Actual priority: 31. | ||
| 17 | (priority-donate-nest) end | ||
| 18 | EOF | ||
| 19 | pass; | ||
diff --git a/pintos-progos/tests/threads/priority-donate-one.c b/pintos-progos/tests/threads/priority-donate-one.c new file mode 100644 index 0000000..3189f3a --- /dev/null +++ b/pintos-progos/tests/threads/priority-donate-one.c | |||
| @@ -0,0 +1,65 @@ | |||
| 1 | /* The main thread acquires a lock. Then it creates two | ||
| 2 | higher-priority threads that block acquiring the lock, causing | ||
| 3 | them to donate their priorities to the main thread. When the | ||
| 4 | main thread releases the lock, the other threads should | ||
| 5 | acquire it in priority order. | ||
| 6 | |||
| 7 | Based on a test originally submitted for Stanford's CS 140 in | ||
| 8 | winter 1999 by Matt Franklin <startled@leland.stanford.edu>, | ||
| 9 | Greg Hutchins <gmh@leland.stanford.edu>, Yu Ping Hu | ||
| 10 | <yph@cs.stanford.edu>. Modified by arens. */ | ||
| 11 | |||
| 12 | #include <stdio.h> | ||
| 13 | #include "tests/threads/tests.h" | ||
| 14 | #include "threads/init.h" | ||
| 15 | #include "threads/synch.h" | ||
| 16 | #include "threads/thread.h" | ||
| 17 | |||
| 18 | static thread_func acquire1_thread_func; | ||
| 19 | static thread_func acquire2_thread_func; | ||
| 20 | |||
| 21 | void | ||
| 22 | test_priority_donate_one (void) | ||
| 23 | { | ||
| 24 | struct lock lock; | ||
| 25 | |||
| 26 | /* This test does not work with the MLFQS. */ | ||
| 27 | ASSERT (!thread_mlfqs); | ||
| 28 | |||
| 29 | /* Make sure our priority is the default. */ | ||
| 30 | ASSERT (thread_get_priority () == PRI_DEFAULT); | ||
| 31 | |||
| 32 | lock_init (&lock); | ||
| 33 | lock_acquire (&lock); | ||
| 34 | thread_create ("acquire1", PRI_DEFAULT + 1, acquire1_thread_func, &lock); | ||
| 35 | msg ("This thread should have priority %d. Actual priority: %d.", | ||
| 36 | PRI_DEFAULT + 1, thread_get_priority ()); | ||
| 37 | thread_create ("acquire2", PRI_DEFAULT + 2, acquire2_thread_func, &lock); | ||
| 38 | msg ("This thread should have priority %d. Actual priority: %d.", | ||
| 39 | PRI_DEFAULT + 2, thread_get_priority ()); | ||
| 40 | lock_release (&lock); | ||
| 41 | msg ("acquire2, acquire1 must already have finished, in that order."); | ||
| 42 | msg ("This should be the last line before finishing this test."); | ||
| 43 | } | ||
| 44 | |||
| 45 | static void | ||
| 46 | acquire1_thread_func (void *lock_) | ||
| 47 | { | ||
| 48 | struct lock *lock = lock_; | ||
| 49 | |||
| 50 | lock_acquire (lock); | ||
| 51 | msg ("acquire1: got the lock"); | ||
| 52 | lock_release (lock); | ||
| 53 | msg ("acquire1: done"); | ||
| 54 | } | ||
| 55 | |||
| 56 | static void | ||
| 57 | acquire2_thread_func (void *lock_) | ||
| 58 | { | ||
| 59 | struct lock *lock = lock_; | ||
| 60 | |||
| 61 | lock_acquire (lock); | ||
| 62 | msg ("acquire2: got the lock"); | ||
| 63 | lock_release (lock); | ||
| 64 | msg ("acquire2: done"); | ||
| 65 | } | ||
diff --git a/pintos-progos/tests/threads/priority-donate-one.ck b/pintos-progos/tests/threads/priority-donate-one.ck new file mode 100644 index 0000000..b7c8e6f --- /dev/null +++ b/pintos-progos/tests/threads/priority-donate-one.ck | |||
| @@ -0,0 +1,17 @@ | |||
| 1 | # -*- perl -*- | ||
| 2 | use strict; | ||
| 3 | use warnings; | ||
| 4 | use tests::tests; | ||
| 5 | check_expected ([<<'EOF']); | ||
| 6 | (priority-donate-one) begin | ||
| 7 | (priority-donate-one) This thread should have priority 32. Actual priority: 32. | ||
| 8 | (priority-donate-one) This thread should have priority 33. Actual priority: 33. | ||
| 9 | (priority-donate-one) acquire2: got the lock | ||
| 10 | (priority-donate-one) acquire2: done | ||
| 11 | (priority-donate-one) acquire1: got the lock | ||
| 12 | (priority-donate-one) acquire1: done | ||
| 13 | (priority-donate-one) acquire2, acquire1 must already have finished, in that order. | ||
| 14 | (priority-donate-one) This should be the last line before finishing this test. | ||
| 15 | (priority-donate-one) end | ||
| 16 | EOF | ||
| 17 | pass; | ||
diff --git a/pintos-progos/tests/threads/priority-donate-sema.c b/pintos-progos/tests/threads/priority-donate-sema.c new file mode 100644 index 0000000..b33cb72 --- /dev/null +++ b/pintos-progos/tests/threads/priority-donate-sema.c | |||
| @@ -0,0 +1,82 @@ | |||
| 1 | /* Low priority thread L acquires a lock, then blocks downing a | ||
| 2 | semaphore. Medium priority thread M then blocks waiting on | ||
| 3 | the same semaphore. Next, high priority thread H attempts to | ||
| 4 | acquire the lock, donating its priority to L. | ||
| 5 | |||
| 6 | Next, the main thread ups the semaphore, waking up L. L | ||
| 7 | releases the lock, which wakes up H. H "up"s the semaphore, | ||
| 8 | waking up M. H terminates, then M, then L, and finally the | ||
| 9 | main thread. | ||
| 10 | |||
| 11 | Written by Godmar Back <gback@cs.vt.edu>. */ | ||
| 12 | |||
| 13 | #include <stdio.h> | ||
| 14 | #include "tests/threads/tests.h" | ||
| 15 | #include "threads/init.h" | ||
| 16 | #include "threads/synch.h" | ||
| 17 | #include "threads/thread.h" | ||
| 18 | |||
| 19 | struct lock_and_sema | ||
| 20 | { | ||
| 21 | struct lock lock; | ||
| 22 | struct semaphore sema; | ||
| 23 | }; | ||
| 24 | |||
| 25 | static thread_func l_thread_func; | ||
| 26 | static thread_func m_thread_func; | ||
| 27 | static thread_func h_thread_func; | ||
| 28 | |||
| 29 | void | ||
| 30 | test_priority_donate_sema (void) | ||
| 31 | { | ||
| 32 | struct lock_and_sema ls; | ||
| 33 | |||
| 34 | /* This test does not work with the MLFQS. */ | ||
| 35 | ASSERT (!thread_mlfqs); | ||
| 36 | |||
| 37 | /* Make sure our priority is the default. */ | ||
| 38 | ASSERT (thread_get_priority () == PRI_DEFAULT); | ||
| 39 | |||
| 40 | lock_init (&ls.lock); | ||
| 41 | sema_init (&ls.sema, 0); | ||
| 42 | thread_create ("low", PRI_DEFAULT + 1, l_thread_func, &ls); | ||
| 43 | thread_create ("med", PRI_DEFAULT + 3, m_thread_func, &ls); | ||
| 44 | thread_create ("high", PRI_DEFAULT + 5, h_thread_func, &ls); | ||
| 45 | sema_up (&ls.sema); | ||
| 46 | msg ("Main thread finished."); | ||
| 47 | } | ||
| 48 | |||
| 49 | static void | ||
| 50 | l_thread_func (void *ls_) | ||
| 51 | { | ||
| 52 | struct lock_and_sema *ls = ls_; | ||
| 53 | |||
| 54 | lock_acquire (&ls->lock); | ||
| 55 | msg ("Thread L acquired lock."); | ||
| 56 | sema_down (&ls->sema); | ||
| 57 | msg ("Thread L downed semaphore."); | ||
| 58 | lock_release (&ls->lock); | ||
| 59 | msg ("Thread L finished."); | ||
| 60 | } | ||
| 61 | |||
| 62 | static void | ||
| 63 | m_thread_func (void *ls_) | ||
| 64 | { | ||
| 65 | struct lock_and_sema *ls = ls_; | ||
| 66 | |||
| 67 | sema_down (&ls->sema); | ||
| 68 | msg ("Thread M finished."); | ||
| 69 | } | ||
| 70 | |||
| 71 | static void | ||
| 72 | h_thread_func (void *ls_) | ||
| 73 | { | ||
| 74 | struct lock_and_sema *ls = ls_; | ||
| 75 | |||
| 76 | lock_acquire (&ls->lock); | ||
| 77 | msg ("Thread H acquired lock."); | ||
| 78 | |||
| 79 | sema_up (&ls->sema); | ||
| 80 | lock_release (&ls->lock); | ||
| 81 | msg ("Thread H finished."); | ||
| 82 | } | ||
diff --git a/pintos-progos/tests/threads/priority-donate-sema.ck b/pintos-progos/tests/threads/priority-donate-sema.ck new file mode 100644 index 0000000..92b8d07 --- /dev/null +++ b/pintos-progos/tests/threads/priority-donate-sema.ck | |||
| @@ -0,0 +1,16 @@ | |||
| 1 | # -*- perl -*- | ||
| 2 | use strict; | ||
| 3 | use warnings; | ||
| 4 | use tests::tests; | ||
| 5 | check_expected ([<<'EOF']); | ||
| 6 | (priority-donate-sema) begin | ||
| 7 | (priority-donate-sema) Thread L acquired lock. | ||
| 8 | (priority-donate-sema) Thread L downed semaphore. | ||
| 9 | (priority-donate-sema) Thread H acquired lock. | ||
| 10 | (priority-donate-sema) Thread H finished. | ||
| 11 | (priority-donate-sema) Thread M finished. | ||
| 12 | (priority-donate-sema) Thread L finished. | ||
| 13 | (priority-donate-sema) Main thread finished. | ||
| 14 | (priority-donate-sema) end | ||
| 15 | EOF | ||
| 16 | pass; | ||
diff --git a/pintos-progos/tests/threads/priority-fifo.c b/pintos-progos/tests/threads/priority-fifo.c new file mode 100644 index 0000000..3af98a3 --- /dev/null +++ b/pintos-progos/tests/threads/priority-fifo.c | |||
| @@ -0,0 +1,99 @@ | |||
| 1 | /* Creates several threads all at the same priority and ensures | ||
| 2 | that they consistently run in the same round-robin order. | ||
| 3 | |||
| 4 | Based on a test originally submitted for Stanford's CS 140 in | ||
| 5 | winter 1999 by by Matt Franklin | ||
| 6 | <startled@leland.stanford.edu>, Greg Hutchins | ||
| 7 | <gmh@leland.stanford.edu>, Yu Ping Hu <yph@cs.stanford.edu>. | ||
| 8 | Modified by arens. */ | ||
| 9 | |||
| 10 | #include <stdio.h> | ||
| 11 | #include "tests/threads/tests.h" | ||
| 12 | #include "threads/init.h" | ||
| 13 | #include "devices/timer.h" | ||
| 14 | #include "threads/malloc.h" | ||
| 15 | #include "threads/synch.h" | ||
| 16 | #include "threads/thread.h" | ||
| 17 | |||
| 18 | struct simple_thread_data | ||
| 19 | { | ||
| 20 | int id; /* Sleeper ID. */ | ||
| 21 | int iterations; /* Iterations so far. */ | ||
| 22 | struct lock *lock; /* Lock on output. */ | ||
| 23 | int **op; /* Output buffer position. */ | ||
| 24 | }; | ||
| 25 | |||
| 26 | #define THREAD_CNT 16 | ||
| 27 | #define ITER_CNT 16 | ||
| 28 | |||
| 29 | static thread_func simple_thread_func; | ||
| 30 | |||
| 31 | void | ||
| 32 | test_priority_fifo (void) | ||
| 33 | { | ||
| 34 | struct simple_thread_data data[THREAD_CNT]; | ||
| 35 | struct lock lock; | ||
| 36 | int *output, *op; | ||
| 37 | int i, cnt; | ||
| 38 | |||
| 39 | /* This test does not work with the MLFQS. */ | ||
| 40 | ASSERT (!thread_mlfqs); | ||
| 41 | |||
| 42 | /* Make sure our priority is the default. */ | ||
| 43 | ASSERT (thread_get_priority () == PRI_DEFAULT); | ||
| 44 | |||
| 45 | msg ("%d threads will iterate %d times in the same order each time.", | ||
| 46 | THREAD_CNT, ITER_CNT); | ||
| 47 | msg ("If the order varies then there is a bug."); | ||
| 48 | |||
| 49 | output = op = malloc (sizeof *output * THREAD_CNT * ITER_CNT * 2); | ||
| 50 | ASSERT (output != NULL); | ||
| 51 | lock_init (&lock); | ||
| 52 | |||
| 53 | thread_set_priority (PRI_DEFAULT + 2); | ||
| 54 | for (i = 0; i < THREAD_CNT; i++) | ||
| 55 | { | ||
| 56 | char name[16]; | ||
| 57 | struct simple_thread_data *d = data + i; | ||
| 58 | snprintf (name, sizeof name, "%d", i); | ||
| 59 | d->id = i; | ||
| 60 | d->iterations = 0; | ||
| 61 | d->lock = &lock; | ||
| 62 | d->op = &op; | ||
| 63 | thread_create (name, PRI_DEFAULT + 1, simple_thread_func, d); | ||
| 64 | } | ||
| 65 | |||
| 66 | thread_set_priority (PRI_DEFAULT); | ||
| 67 | /* All the other threads now run to termination here. */ | ||
| 68 | ASSERT (lock.holder == NULL); | ||
| 69 | |||
| 70 | cnt = 0; | ||
| 71 | for (; output < op; output++) | ||
| 72 | { | ||
| 73 | struct simple_thread_data *d; | ||
| 74 | |||
| 75 | ASSERT (*output >= 0 && *output < THREAD_CNT); | ||
| 76 | d = data + *output; | ||
| 77 | if (cnt % THREAD_CNT == 0) | ||
| 78 | printf ("(priority-fifo) iteration:"); | ||
| 79 | printf (" %d", d->id); | ||
| 80 | if (++cnt % THREAD_CNT == 0) | ||
| 81 | printf ("\n"); | ||
| 82 | d->iterations++; | ||
| 83 | } | ||
| 84 | } | ||
| 85 | |||
| 86 | static void | ||
| 87 | simple_thread_func (void *data_) | ||
| 88 | { | ||
| 89 | struct simple_thread_data *data = data_; | ||
| 90 | int i; | ||
| 91 | |||
| 92 | for (i = 0; i < ITER_CNT; i++) | ||
| 93 | { | ||
| 94 | lock_acquire (data->lock); | ||
| 95 | *(*data->op)++ = data->id; | ||
| 96 | lock_release (data->lock); | ||
| 97 | thread_yield (); | ||
| 98 | } | ||
| 99 | } | ||
diff --git a/pintos-progos/tests/threads/priority-fifo.ck b/pintos-progos/tests/threads/priority-fifo.ck new file mode 100644 index 0000000..11f1dd3 --- /dev/null +++ b/pintos-progos/tests/threads/priority-fifo.ck | |||
| @@ -0,0 +1,63 @@ | |||
| 1 | # -*- perl -*- | ||
| 2 | |||
| 3 | # The expected output looks like this: | ||
| 4 | # | ||
| 5 | # (priority-fifo) iteration: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | ||
| 6 | # (priority-fifo) iteration: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | ||
| 7 | # (priority-fifo) iteration: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | ||
| 8 | # (priority-fifo) iteration: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | ||
| 9 | # (priority-fifo) iteration: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | ||
| 10 | # (priority-fifo) iteration: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | ||
| 11 | # (priority-fifo) iteration: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | ||
| 12 | # (priority-fifo) iteration: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | ||
| 13 | # (priority-fifo) iteration: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | ||
| 14 | # (priority-fifo) iteration: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | ||
| 15 | # (priority-fifo) iteration: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | ||
| 16 | # (priority-fifo) iteration: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | ||
| 17 | # (priority-fifo) iteration: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | ||
| 18 | # (priority-fifo) iteration: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | ||
| 19 | # (priority-fifo) iteration: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | ||
| 20 | # (priority-fifo) iteration: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | ||
| 21 | # | ||
| 22 | # A different permutation of 0...15 is acceptable, but every line must | ||
| 23 | # be in the same order. | ||
| 24 | |||
| 25 | use strict; | ||
| 26 | use warnings; | ||
| 27 | use tests::tests; | ||
| 28 | |||
| 29 | our ($test); | ||
| 30 | my (@output) = read_text_file ("$test.output"); | ||
| 31 | |||
| 32 | common_checks ("run", @output); | ||
| 33 | |||
| 34 | my ($thread_cnt) = 16; | ||
| 35 | my ($iter_cnt) = 16; | ||
| 36 | my (@order); | ||
| 37 | my (@t) = (-1) x $thread_cnt; | ||
| 38 | |||
| 39 | my (@iterations) = grep (/iteration:/, @output); | ||
| 40 | fail "No iterations found in output.\n" if !@iterations; | ||
| 41 | |||
| 42 | my (@numbering) = $iterations[0] =~ /(\d+)/g; | ||
| 43 | fail "First iteration does not list exactly $thread_cnt threads.\n" | ||
| 44 | if @numbering != $thread_cnt; | ||
| 45 | |||
| 46 | my (@sorted_numbering) = sort { $a <=> $b } @numbering; | ||
| 47 | for my $i (0...$#sorted_numbering) { | ||
| 48 | if ($sorted_numbering[$i] != $i) { | ||
| 49 | fail "First iteration does not list all threads " | ||
| 50 | . "0...$#sorted_numbering\n"; | ||
| 51 | } | ||
| 52 | } | ||
| 53 | |||
| 54 | for my $i (1...$#iterations) { | ||
| 55 | if ($iterations[$i] ne $iterations[0]) { | ||
| 56 | fail "Iteration $i differs from iteration 0\n"; | ||
| 57 | } | ||
| 58 | } | ||
| 59 | |||
| 60 | fail "$iter_cnt iterations expected but " . scalar (@iterations) . " found\n" | ||
| 61 | if $iter_cnt != @iterations; | ||
| 62 | |||
| 63 | pass; | ||
diff --git a/pintos-progos/tests/threads/priority-preempt.c b/pintos-progos/tests/threads/priority-preempt.c new file mode 100644 index 0000000..3c3aacb --- /dev/null +++ b/pintos-progos/tests/threads/priority-preempt.c | |||
| @@ -0,0 +1,41 @@ | |||
| 1 | /* Ensures that a high-priority thread really preempts. | ||
| 2 | |||
| 3 | Based on a test originally submitted for Stanford's CS 140 in | ||
| 4 | winter 1999 by by Matt Franklin | ||
| 5 | <startled@leland.stanford.edu>, Greg Hutchins | ||
| 6 | <gmh@leland.stanford.edu>, Yu Ping Hu <yph@cs.stanford.edu>. | ||
| 7 | Modified by arens. */ | ||
| 8 | |||
| 9 | #include <stdio.h> | ||
| 10 | #include "tests/threads/tests.h" | ||
| 11 | #include "threads/init.h" | ||
| 12 | #include "threads/synch.h" | ||
| 13 | #include "threads/thread.h" | ||
| 14 | |||
| 15 | static thread_func simple_thread_func; | ||
| 16 | |||
| 17 | void | ||
| 18 | test_priority_preempt (void) | ||
| 19 | { | ||
| 20 | /* This test does not work with the MLFQS. */ | ||
| 21 | ASSERT (!thread_mlfqs); | ||
| 22 | |||
| 23 | /* Make sure our priority is the default. */ | ||
| 24 | ASSERT (thread_get_priority () == PRI_DEFAULT); | ||
| 25 | |||
| 26 | thread_create ("high-priority", PRI_DEFAULT + 1, simple_thread_func, NULL); | ||
| 27 | msg ("The high-priority thread should have already completed."); | ||
| 28 | } | ||
| 29 | |||
| 30 | static void | ||
| 31 | simple_thread_func (void *aux UNUSED) | ||
| 32 | { | ||
| 33 | int i; | ||
| 34 | |||
| 35 | for (i = 0; i < 5; i++) | ||
| 36 | { | ||
| 37 | msg ("Thread %s iteration %d", thread_name (), i); | ||
| 38 | thread_yield (); | ||
| 39 | } | ||
| 40 | msg ("Thread %s done!", thread_name ()); | ||
| 41 | } | ||
diff --git a/pintos-progos/tests/threads/priority-preempt.ck b/pintos-progos/tests/threads/priority-preempt.ck new file mode 100644 index 0000000..43a26ee --- /dev/null +++ b/pintos-progos/tests/threads/priority-preempt.ck | |||
| @@ -0,0 +1,16 @@ | |||
| 1 | # -*- perl -*- | ||
| 2 | use strict; | ||
| 3 | use warnings; | ||
| 4 | use tests::tests; | ||
| 5 | check_expected ([<<'EOF']); | ||
| 6 | (priority-preempt) begin | ||
| 7 | (priority-preempt) Thread high-priority iteration 0 | ||
| 8 | (priority-preempt) Thread high-priority iteration 1 | ||
| 9 | (priority-preempt) Thread high-priority iteration 2 | ||
| 10 | (priority-preempt) Thread high-priority iteration 3 | ||
| 11 | (priority-preempt) Thread high-priority iteration 4 | ||
| 12 | (priority-preempt) Thread high-priority done! | ||
| 13 | (priority-preempt) The high-priority thread should have already completed. | ||
| 14 | (priority-preempt) end | ||
| 15 | EOF | ||
| 16 | pass; | ||
diff --git a/pintos-progos/tests/threads/priority-sema.c b/pintos-progos/tests/threads/priority-sema.c new file mode 100644 index 0000000..2834a88 --- /dev/null +++ b/pintos-progos/tests/threads/priority-sema.c | |||
| @@ -0,0 +1,45 @@ | |||
| 1 | /* Tests that the highest-priority thread waiting on a semaphore | ||
| 2 | is the first to wake up. */ | ||
| 3 | |||
| 4 | #include <stdio.h> | ||
| 5 | #include "tests/threads/tests.h" | ||
| 6 | #include "threads/init.h" | ||
| 7 | #include "threads/malloc.h" | ||
| 8 | #include "threads/synch.h" | ||
| 9 | #include "threads/thread.h" | ||
| 10 | #include "devices/timer.h" | ||
| 11 | |||
| 12 | static thread_func priority_sema_thread; | ||
| 13 | static struct semaphore sema; | ||
| 14 | |||
| 15 | void | ||
| 16 | test_priority_sema (void) | ||
| 17 | { | ||
| 18 | int i; | ||
| 19 | |||
| 20 | /* This test does not work with the MLFQS. */ | ||
| 21 | ASSERT (!thread_mlfqs); | ||
| 22 | |||
| 23 | sema_init (&sema, 0); | ||
| 24 | thread_set_priority (PRI_MIN); | ||
| 25 | for (i = 0; i < 10; i++) | ||
| 26 | { | ||
| 27 | int priority = PRI_DEFAULT - (i + 3) % 10 - 1; | ||
| 28 | char name[16]; | ||
| 29 | snprintf (name, sizeof name, "priority %d", priority); | ||
| 30 | thread_create (name, priority, priority_sema_thread, NULL); | ||
| 31 | } | ||
| 32 | |||
| 33 | for (i = 0; i < 10; i++) | ||
| 34 | { | ||
| 35 | sema_up (&sema); | ||
| 36 | msg ("Back in main thread."); | ||
| 37 | } | ||
| 38 | } | ||
| 39 | |||
| 40 | static void | ||
| 41 | priority_sema_thread (void *aux UNUSED) | ||
| 42 | { | ||
| 43 | sema_down (&sema); | ||
| 44 | msg ("Thread %s woke up.", thread_name ()); | ||
| 45 | } | ||
diff --git a/pintos-progos/tests/threads/priority-sema.ck b/pintos-progos/tests/threads/priority-sema.ck new file mode 100644 index 0000000..559988d --- /dev/null +++ b/pintos-progos/tests/threads/priority-sema.ck | |||
| @@ -0,0 +1,29 @@ | |||
| 1 | # -*- perl -*- | ||
| 2 | use strict; | ||
| 3 | use warnings; | ||
| 4 | use tests::tests; | ||
| 5 | check_expected ([<<'EOF']); | ||
| 6 | (priority-sema) begin | ||
| 7 | (priority-sema) Thread priority 30 woke up. | ||
| 8 | (priority-sema) Back in main thread. | ||
| 9 | (priority-sema) Thread priority 29 woke up. | ||
| 10 | (priority-sema) Back in main thread. | ||
| 11 | (priority-sema) Thread priority 28 woke up. | ||
| 12 | (priority-sema) Back in main thread. | ||
| 13 | (priority-sema) Thread priority 27 woke up. | ||
| 14 | (priority-sema) Back in main thread. | ||
| 15 | (priority-sema) Thread priority 26 woke up. | ||
| 16 | (priority-sema) Back in main thread. | ||
| 17 | (priority-sema) Thread priority 25 woke up. | ||
| 18 | (priority-sema) Back in main thread. | ||
| 19 | (priority-sema) Thread priority 24 woke up. | ||
| 20 | (priority-sema) Back in main thread. | ||
| 21 | (priority-sema) Thread priority 23 woke up. | ||
| 22 | (priority-sema) Back in main thread. | ||
| 23 | (priority-sema) Thread priority 22 woke up. | ||
| 24 | (priority-sema) Back in main thread. | ||
| 25 | (priority-sema) Thread priority 21 woke up. | ||
| 26 | (priority-sema) Back in main thread. | ||
| 27 | (priority-sema) end | ||
| 28 | EOF | ||
| 29 | pass; | ||
diff --git a/pintos-progos/tests/threads/tests.c b/pintos-progos/tests/threads/tests.c new file mode 100644 index 0000000..af15aee --- /dev/null +++ b/pintos-progos/tests/threads/tests.c | |||
| @@ -0,0 +1,102 @@ | |||
| 1 | #include "tests/threads/tests.h" | ||
| 2 | #include <debug.h> | ||
| 3 | #include <string.h> | ||
| 4 | #include <stdio.h> | ||
| 5 | |||
| 6 | struct test | ||
| 7 | { | ||
| 8 | const char *name; | ||
| 9 | test_func *function; | ||
| 10 | }; | ||
| 11 | |||
| 12 | static const struct test tests[] = | ||
| 13 | { | ||
| 14 | {"alarm-single", test_alarm_single}, | ||
| 15 | {"alarm-multiple", test_alarm_multiple}, | ||
| 16 | {"alarm-simultaneous", test_alarm_simultaneous}, | ||
| 17 | {"alarm-priority", test_alarm_priority}, | ||
| 18 | {"alarm-zero", test_alarm_zero}, | ||
| 19 | {"alarm-negative", test_alarm_negative}, | ||
| 20 | {"priority-change", test_priority_change}, | ||
| 21 | {"priority-donate-one", test_priority_donate_one}, | ||
| 22 | {"priority-donate-multiple", test_priority_donate_multiple}, | ||
| 23 | {"priority-donate-multiple2", test_priority_donate_multiple2}, | ||
| 24 | {"priority-donate-nest", test_priority_donate_nest}, | ||
| 25 | {"priority-donate-sema", test_priority_donate_sema}, | ||
| 26 | {"priority-donate-lower", test_priority_donate_lower}, | ||
| 27 | {"priority-donate-chain", test_priority_donate_chain}, | ||
| 28 | {"priority-fifo", test_priority_fifo}, | ||
| 29 | {"priority-preempt", test_priority_preempt}, | ||
| 30 | {"priority-sema", test_priority_sema}, | ||
| 31 | {"priority-condvar", test_priority_condvar}, | ||
| 32 | {"mlfqs-load-1", test_mlfqs_load_1}, | ||
| 33 | {"mlfqs-load-60", test_mlfqs_load_60}, | ||
| 34 | {"mlfqs-load-avg", test_mlfqs_load_avg}, | ||
| 35 | {"mlfqs-recent-1", test_mlfqs_recent_1}, | ||
| 36 | {"mlfqs-fair-2", test_mlfqs_fair_2}, | ||
| 37 | {"mlfqs-fair-20", test_mlfqs_fair_20}, | ||
| 38 | {"mlfqs-nice-2", test_mlfqs_nice_2}, | ||
| 39 | {"mlfqs-nice-10", test_mlfqs_nice_10}, | ||
| 40 | {"mlfqs-block", test_mlfqs_block}, | ||
| 41 | }; | ||
| 42 | |||
| 43 | static const char *test_name; | ||
| 44 | |||
| 45 | /* Runs the test named NAME. */ | ||
| 46 | void | ||
| 47 | run_test (const char *name) | ||
| 48 | { | ||
| 49 | const struct test *t; | ||
| 50 | |||
| 51 | for (t = tests; t < tests + sizeof tests / sizeof *tests; t++) | ||
| 52 | if (!strcmp (name, t->name)) | ||
| 53 | { | ||
| 54 | test_name = name; | ||
| 55 | msg ("begin"); | ||
| 56 | t->function (); | ||
| 57 | msg ("end"); | ||
| 58 | return; | ||
| 59 | } | ||
| 60 | PANIC ("no test named \"%s\"", name); | ||
| 61 | } | ||
| 62 | |||
| 63 | /* Prints FORMAT as if with printf(), | ||
| 64 | prefixing the output by the name of the test | ||
| 65 | and following it with a new-line character. */ | ||
| 66 | void | ||
| 67 | msg (const char *format, ...) | ||
| 68 | { | ||
| 69 | va_list args; | ||
| 70 | |||
| 71 | printf ("(%s) ", test_name); | ||
| 72 | va_start (args, format); | ||
| 73 | vprintf (format, args); | ||
| 74 | va_end (args); | ||
| 75 | putchar ('\n'); | ||
| 76 | } | ||
| 77 | |||
| 78 | /* Prints failure message FORMAT as if with printf(), | ||
| 79 | prefixing the output by the name of the test and FAIL: | ||
| 80 | and following it with a new-line character, | ||
| 81 | and then panics the kernel. */ | ||
| 82 | void | ||
| 83 | fail (const char *format, ...) | ||
| 84 | { | ||
| 85 | va_list args; | ||
| 86 | |||
| 87 | printf ("(%s) FAIL: ", test_name); | ||
| 88 | va_start (args, format); | ||
| 89 | vprintf (format, args); | ||
| 90 | va_end (args); | ||
| 91 | putchar ('\n'); | ||
| 92 | |||
| 93 | PANIC ("test failed"); | ||
| 94 | } | ||
| 95 | |||
| 96 | /* Prints a message indicating the current test passed. */ | ||
| 97 | void | ||
| 98 | pass (void) | ||
| 99 | { | ||
| 100 | printf ("(%s) PASS\n", test_name); | ||
| 101 | } | ||
| 102 | |||
diff --git a/pintos-progos/tests/threads/tests.h b/pintos-progos/tests/threads/tests.h new file mode 100644 index 0000000..cd9d489 --- /dev/null +++ b/pintos-progos/tests/threads/tests.h | |||
| @@ -0,0 +1,41 @@ | |||
| 1 | #ifndef TESTS_THREADS_TESTS_H | ||
| 2 | #define TESTS_THREADS_TESTS_H | ||
| 3 | |||
| 4 | void run_test (const char *); | ||
| 5 | |||
| 6 | typedef void test_func (void); | ||
| 7 | |||
| 8 | extern test_func test_alarm_single; | ||
| 9 | extern test_func test_alarm_multiple; | ||
| 10 | extern test_func test_alarm_simultaneous; | ||
| 11 | extern test_func test_alarm_priority; | ||
| 12 | extern test_func test_alarm_zero; | ||
| 13 | extern test_func test_alarm_negative; | ||
| 14 | extern test_func test_priority_change; | ||
| 15 | extern test_func test_priority_donate_one; | ||
| 16 | extern test_func test_priority_donate_multiple; | ||
| 17 | extern test_func test_priority_donate_multiple2; | ||
| 18 | extern test_func test_priority_donate_sema; | ||
| 19 | extern test_func test_priority_donate_nest; | ||
| 20 | extern test_func test_priority_donate_lower; | ||
| 21 | extern test_func test_priority_donate_chain; | ||
| 22 | extern test_func test_priority_fifo; | ||
| 23 | extern test_func test_priority_preempt; | ||
| 24 | extern test_func test_priority_sema; | ||
| 25 | extern test_func test_priority_condvar; | ||
| 26 | extern test_func test_mlfqs_load_1; | ||
| 27 | extern test_func test_mlfqs_load_60; | ||
| 28 | extern test_func test_mlfqs_load_avg; | ||
| 29 | extern test_func test_mlfqs_recent_1; | ||
| 30 | extern test_func test_mlfqs_fair_2; | ||
| 31 | extern test_func test_mlfqs_fair_20; | ||
| 32 | extern test_func test_mlfqs_nice_2; | ||
| 33 | extern test_func test_mlfqs_nice_10; | ||
| 34 | extern test_func test_mlfqs_block; | ||
| 35 | |||
| 36 | void msg (const char *, ...); | ||
| 37 | void fail (const char *, ...); | ||
| 38 | void pass (void); | ||
| 39 | |||
| 40 | #endif /* tests/threads/tests.h */ | ||
| 41 | |||
