From 642049ba7d30b24fb9927a22d44d6b84139668dc Mon Sep 17 00:00:00 2001 From: Bjoern Brandenburg Date: Fri, 11 Jan 2013 10:17:10 +0100 Subject: Make release_ts a bit more userfriendly The -f option required manually *also* setting the -w option. This is no longer required. While at it, simplify the code by using the /proc interface. --- bin/release_ts.c | 28 ++++------------------------ include/litmus.h | 1 + src/kernel_iface.c | 15 ++++++++++----- 3 files changed, 15 insertions(+), 29 deletions(-) diff --git a/bin/release_ts.c b/bin/release_ts.c index 7752097..c2f6d4c 100644 --- a/bin/release_ts.c +++ b/bin/release_ts.c @@ -31,35 +31,14 @@ void usage(char *error) { void wait_until_ready(int expected) { int ready = 0, all = 0; - char buf[100]; int loops = 0; - ssize_t len; - do { if (loops++ > 0) sleep(1); - len = read_file(LITMUS_STATS_FILE, buf, sizeof(buf) - 1); - if (len < 0) { - fprintf(stderr, - "(EE) Error while reading '%s': %m.\n" - "(EE) Ignoring -w option.\n", - LITMUS_STATS_FILE); - break; - } else { - len = sscanf(buf, - "real-time tasks = %d\n" - "ready for release = %d\n", - &all, &ready); - if (len != 2) { - fprintf(stderr, - "(EE) Could not parse '%s'.\n" - "(EE) Ignoring -w option.\n", - LITMUS_STATS_FILE); - break; - } - } - } while (expected > ready || ready < all); + if (!read_litmus_stats(&ready, &all)) + perror("read_litmus_stats"); + } while (expected > ready || (!expected && ready < all)); } int main(int argc, char** argv) @@ -79,6 +58,7 @@ int main(int argc, char** argv) wait = 1; break; case 'f': + wait = 1; expected = atoi(optarg); break; case ':': diff --git a/include/litmus.h b/include/litmus.h index 677f9a9..3777088 100644 --- a/include/litmus.h +++ b/include/litmus.h @@ -121,6 +121,7 @@ int requested_to_preempt(void); int wait_for_ts_release(void); int release_ts(lt_t *delay); int get_nr_ts_release_waiters(void); +int read_litmus_stats(int *ready, int *total); #define __NS_PER_MS 1000000 diff --git a/src/kernel_iface.c b/src/kernel_iface.c index 4cc1af5..e446102 100644 --- a/src/kernel_iface.c +++ b/src/kernel_iface.c @@ -56,9 +56,8 @@ ssize_t read_file(const char* fname, void* buf, size_t maxlen) return got; } -int get_nr_ts_release_waiters(void) +int read_litmus_stats(int *ready, int *all) { - int ready = 0, all = 0; char buf[100]; ssize_t len; @@ -67,11 +66,17 @@ int get_nr_ts_release_waiters(void) len = sscanf(buf, "real-time tasks = %d\n" "ready for release = %d\n", - &all, &ready); - if (len == 2) + all, ready); + return len == 2; +} + +int get_nr_ts_release_waiters(void) +{ + int ready, all; + if (read_litmus_stats(&ready, &all)) return ready; else - return len; + return -1; } /* thread-local pointer to control page */ -- cgit v1.2.2 From 102b50373d656e42abbd1c953ce908e52f6e8706 Mon Sep 17 00:00:00 2001 From: Bjoern Brandenburg Date: Fri, 11 Jan 2013 10:26:33 +0100 Subject: rt_launch: add support for -q This mirrors the option in rtspin. --- bin/rt_launch.c | 18 ++++++++++++------ include/litmus.h | 6 +++--- src/task.c | 10 ++++++---- 3 files changed, 21 insertions(+), 13 deletions(-) diff --git a/bin/rt_launch.c b/bin/rt_launch.c index 3863031..16d6ed7 100644 --- a/bin/rt_launch.c +++ b/bin/rt_launch.c @@ -29,7 +29,7 @@ int launch(void *task_info_p) { } void usage(char *error) { - fprintf(stderr, "%s\nUsage: rt_launch [-w][-v][-p cpu][-c hrt | srt | be] wcet period program [arg1 arg2 ...]\n" + fprintf(stderr, "%s\nUsage: rt_launch [-w][-v][-p cpu][-q prio][-c hrt | srt | be] wcet period program [arg1 arg2 ...]\n" "\t-w\tSynchronous release\n" "\t-v\tVerbose\n" "\t-p\tcpu (or initial cpu)\n" @@ -41,7 +41,7 @@ void usage(char *error) { } -#define OPTSTR "p:c:vw" +#define OPTSTR "p:c:vwq:" int main(int argc, char** argv) { @@ -55,6 +55,7 @@ int main(int argc, char** argv) int wait = 0; startup_info_t info; task_class_t class = RT_CLASS_HARD; + unsigned int priority = LITMUS_LOWEST_PRIORITY; while ((opt = getopt(argc, argv, OPTSTR)) != -1) { switch (opt) { @@ -68,6 +69,11 @@ int main(int argc, char** argv) cpu = atoi(optarg); migrate = 1; break; + case 'q': + priority = atoi(optarg); + if (!litmus_is_valid_fixed_prio(priority)) + usage("Invalid priority."); + break; case 'c': class = str2class(optarg); if (class == -1) @@ -87,7 +93,7 @@ int main(int argc, char** argv) signal(SIGUSR1, SIG_IGN); if (argc - optind < 3) - usage("Arguments missing."); + usage("Arguments missing."); wcet = ms2lt(atoi(argv[optind + 0])); period = ms2lt(atoi(argv[optind + 1])); if (wcet <= 0) @@ -107,13 +113,13 @@ int main(int argc, char** argv) if (ret < 0) bail_out("could not migrate to target partition"); } - ret = __create_rt_task(launch, &info, cpu, wcet, period, class); + ret = __create_rt_task(launch, &info, cpu, wcet, period, priority, class); + - if (ret < 0) bail_out("could not create rt child process"); else if (verbose) printf("%d\n", ret); - return 0; + return 0; } diff --git a/include/litmus.h b/include/litmus.h index 3777088..2b6a1dd 100644 --- a/include/litmus.h +++ b/include/litmus.h @@ -98,9 +98,9 @@ void exit_litmus(void); typedef int (*rt_fn_t)(void*); /* These two functions configure the RT task to use enforced exe budgets */ -int create_rt_task(rt_fn_t rt_prog, void *arg, int cpu, int wcet, int period); -int __create_rt_task(rt_fn_t rt_prog, void *arg, int cpu, int wcet, - int period, task_class_t cls); +int create_rt_task(rt_fn_t rt_prog, void *arg, int cpu, lt_t wcet, lt_t period, unsigned int prio); +int __create_rt_task(rt_fn_t rt_prog, void *arg, int cpu, lt_t wcet, + lt_t period, unsigned int priority, task_class_t cls); /* per-task modes */ enum rt_task_mode_t { diff --git a/src/task.c b/src/task.c index 4d237bd..ed1c6aa 100644 --- a/src/task.c +++ b/src/task.c @@ -40,8 +40,8 @@ int __launch_rt_task(rt_fn_t rt_prog, void *rt_arg, rt_setup_fn_t setup, return rt_task; } -int __create_rt_task(rt_fn_t rt_prog, void *arg, int cpu, int wcet, int period, - task_class_t class) +int __create_rt_task(rt_fn_t rt_prog, void *arg, int cpu, lt_t wcet, lt_t period, + unsigned int priority, task_class_t class) { struct rt_task params; params.cpu = cpu; @@ -49,6 +49,7 @@ int __create_rt_task(rt_fn_t rt_prog, void *arg, int cpu, int wcet, int period, params.exec_cost = wcet; params.cls = class; params.phase = 0; + params.priority = priority; /* enforce budget for tasks that might not use sleep_next_period() */ params.budget_policy = QUANTUM_ENFORCEMENT; @@ -56,8 +57,9 @@ int __create_rt_task(rt_fn_t rt_prog, void *arg, int cpu, int wcet, int period, (rt_setup_fn_t) set_rt_task_param, ¶ms); } -int create_rt_task(rt_fn_t rt_prog, void *arg, int cpu, int wcet, int period) { - return __create_rt_task(rt_prog, arg, cpu, wcet, period, RT_CLASS_HARD); +int create_rt_task(rt_fn_t rt_prog, void *arg, int cpu, lt_t wcet, lt_t period, + unsigned int priority) { + return __create_rt_task(rt_prog, arg, cpu, wcet, period, priority, RT_CLASS_HARD); } -- cgit v1.2.2 From 916c8dfde6a4ee5b86af4d4db882c05c6bb08e9b Mon Sep 17 00:00:00 2001 From: Bjoern Brandenburg Date: Fri, 11 Jan 2013 11:00:30 +0100 Subject: Add tests for PCP/SRP ceiling blocking Context: priority inheritance triggered a BUG_ON() in fp_common.c. While at it, add a similar test for the SRP. --- tests/pcp.c | 208 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 208 insertions(+) diff --git a/tests/pcp.c b/tests/pcp.c index 88d1be3..52ee959 100644 --- a/tests/pcp.c +++ b/tests/pcp.c @@ -1,6 +1,8 @@ #include #include #include +#include /* for waitpid() */ + #include "tests.h" #include "litmus.h" @@ -37,6 +39,212 @@ TESTCASE(lock_pcp, P_FP, SYSCALL( remove(".pcp_locks") ); } +TESTCASE(pcp_inheritance, P_FP, + "PCP priority inheritance") +{ + int fd, od, cpu = 0; + + int child_hi, child_lo, child_middle, status, waiters; + lt_t delay = ms2lt(100); + double start, stop; + + struct rt_task params; + params.cpu = 0; + params.exec_cost = ms2lt(10000); + params.period = ms2lt(100000); + params.relative_deadline = params.period; + params.phase = 0; + params.cls = RT_CLASS_HARD; + params.budget_policy = NO_ENFORCEMENT; + + SYSCALL( fd = open(".pcp_locks", O_RDONLY | O_CREAT) ); + + + child_lo = FORK_TASK( + params.priority = LITMUS_LOWEST_PRIORITY; + params.phase = 0; + SYSCALL( set_rt_task_param(gettid(), ¶ms) ); + SYSCALL( be_migrate_to(params.cpu) ); + SYSCALL( task_mode(LITMUS_RT_TASK) ); + + SYSCALL( od = open_pcp_sem(fd, 0, cpu) ); + + SYSCALL( wait_for_ts_release() ); + + SYSCALL( litmus_lock(od) ); + start = cputime(); + while (cputime() - start < 0.25) + ; + SYSCALL( litmus_unlock(od) ); + + SYSCALL(sleep_next_period() ); + ); + + child_middle = FORK_TASK( + params.priority = LITMUS_HIGHEST_PRIORITY + 1; + params.phase = ms2lt(100); + + SYSCALL( set_rt_task_param(gettid(), ¶ms) ); + SYSCALL( be_migrate_to(params.cpu) ); + SYSCALL( task_mode(LITMUS_RT_TASK) ); + + + SYSCALL( wait_for_ts_release() ); + + start = cputime(); + while (cputime() - start < 5) + ; + SYSCALL( sleep_next_period() ); + ); + + child_hi = FORK_TASK( + params.priority = LITMUS_HIGHEST_PRIORITY; + params.phase = ms2lt(50); + + SYSCALL( set_rt_task_param(gettid(), ¶ms) ); + SYSCALL( be_migrate_to(params.cpu) ); + SYSCALL( task_mode(LITMUS_RT_TASK) ); + + SYSCALL( od = open_pcp_sem(fd, 0, cpu) ); + + SYSCALL( wait_for_ts_release() ); + + start = wctime(); + /* block on semaphore */ + SYSCALL( litmus_lock(od) ); + SYSCALL( litmus_unlock(od) ); + stop = wctime(); + + /* Assert we had some blocking. */ + ASSERT( stop - start > 0.1); + + /* Assert we woke up 'soonish' after the sleep. */ + ASSERT( stop - start < 1 ); + + SYSCALL( kill(child_middle, SIGUSR2) ); + SYSCALL( kill(child_lo, SIGUSR2) ); + ); + + do { + waiters = get_nr_ts_release_waiters(); + ASSERT( waiters >= 0 ); + } while (waiters != 3); + + SYSCALL( be_migrate_to(1) ); + + waiters = release_ts(&delay); + + SYSCALL( waitpid(child_hi, &status, 0) ); + ASSERT( status == 0 ); + + SYSCALL( waitpid(child_lo, &status, 0) ); + ASSERT( status == SIGUSR2); + + SYSCALL( waitpid(child_middle, &status, 0) ); + ASSERT( status == SIGUSR2); +} + +TESTCASE(srp_ceiling_blocking, P_FP | PSN_EDF, + "SRP ceiling blocking") +{ + int fd, od; + + int child_hi, child_lo, child_middle, status, waiters; + lt_t delay = ms2lt(100); + double start, stop; + + struct rt_task params; + params.cpu = 0; + params.exec_cost = ms2lt(10000); + params.period = ms2lt(100000); + params.relative_deadline = params.period; + params.phase = 0; + params.cls = RT_CLASS_HARD; + params.budget_policy = NO_ENFORCEMENT; + + SYSCALL( fd = open(".srp_locks", O_RDONLY | O_CREAT) ); + + + child_lo = FORK_TASK( + params.priority = LITMUS_LOWEST_PRIORITY; + params.phase = 0; + SYSCALL( set_rt_task_param(gettid(), ¶ms) ); + SYSCALL( be_migrate_to(params.cpu) ); + SYSCALL( task_mode(LITMUS_RT_TASK) ); + + SYSCALL( od = open_srp_sem(fd, 0) ); + + SYSCALL( wait_for_ts_release() ); + + SYSCALL( litmus_lock(od) ); + start = cputime(); + while (cputime() - start < 0.25) + ; + SYSCALL( litmus_unlock(od) ); + ); + + child_middle = FORK_TASK( + params.priority = LITMUS_HIGHEST_PRIORITY + 1; + params.phase = ms2lt(100); + params.relative_deadline -= ms2lt(110); + + SYSCALL( set_rt_task_param(gettid(), ¶ms) ); + SYSCALL( be_migrate_to(params.cpu) ); + SYSCALL( task_mode(LITMUS_RT_TASK) ); + + + SYSCALL( wait_for_ts_release() ); + + start = cputime(); + while (cputime() - start < 5) + ; + ); + + child_hi = FORK_TASK( + params.priority = LITMUS_HIGHEST_PRIORITY; + params.phase = ms2lt(50); + params.relative_deadline -= ms2lt(200); + + SYSCALL( set_rt_task_param(gettid(), ¶ms) ); + SYSCALL( be_migrate_to(params.cpu) ); + SYSCALL( task_mode(LITMUS_RT_TASK) ); + + SYSCALL( od = open_srp_sem(fd, 0) ); + + SYSCALL( wait_for_ts_release() ); + + start = wctime(); + /* block on semaphore */ + SYSCALL( litmus_lock(od) ); + SYSCALL( litmus_unlock(od) ); + stop = wctime(); + + /* Assert we had "no" blocking (modulo qemu overheads). */ + ASSERT( stop - start < 0.01); + + SYSCALL( kill(child_middle, SIGUSR2) ); + SYSCALL( kill(child_lo, SIGUSR2) ); + ); + + do { + waiters = get_nr_ts_release_waiters(); + ASSERT( waiters >= 0 ); + } while (waiters != 3); + + SYSCALL( be_migrate_to(1) ); + + waiters = release_ts(&delay); + + SYSCALL( waitpid(child_hi, &status, 0) ); + ASSERT( status == 0 ); + + SYSCALL( waitpid(child_lo, &status, 0) ); + ASSERT( status == SIGUSR2); + + SYSCALL( waitpid(child_middle, &status, 0) ); + ASSERT( status == SIGUSR2); +} + TESTCASE(lock_dpcp, P_FP, "DPCP acquisition and release") { -- cgit v1.2.2 From 176e38bd5876bfe691d09d75de8959801eda9da2 Mon Sep 17 00:00:00 2001 From: Bjoern Brandenburg Date: Mon, 14 Jan 2013 14:35:49 +0100 Subject: Include PID info in test failures Useful for correlating test failures to events in traces. --- include/tests.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/include/tests.h b/include/tests.h index ed2b409..4ca21f8 100644 --- a/include/tests.h +++ b/include/tests.h @@ -7,8 +7,11 @@ #define fail(fmt, args...) \ do { \ - fprintf(stderr, "\n!! TEST FAILURE " fmt "\n at %s:%d (%s)\n", \ - ## args, __FILE__, __LINE__, __FUNCTION__); \ + fprintf(stderr, "\n!! TEST FAILURE " fmt \ + "\n at %s:%d (%s)" \ + "\n in task PID=%d\n", \ + ## args, __FILE__, __LINE__, __FUNCTION__, \ + getpid()); \ fflush(stderr); \ exit(200); \ } while (0) -- cgit v1.2.2 From f308b757af1574632627b727c90e08a65b1dfc96 Mon Sep 17 00:00:00 2001 From: Bjoern Brandenburg Date: Mon, 14 Jan 2013 14:56:17 +0100 Subject: Add basic locking support to rtspin This is useful for testing locking protocol implementations (not intended for benchmarking!), and also serves to document how to use the LITMUS^RT locking API. --- bin/rtspin.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++------ include/litmus.h | 7 ++++++ src/litmus.c | 20 ++++++++++++++++ 3 files changed, 91 insertions(+), 7 deletions(-) diff --git a/bin/rtspin.c b/bin/rtspin.c index f0a477d..5054d0b 100644 --- a/bin/rtspin.c +++ b/bin/rtspin.c @@ -4,6 +4,7 @@ #include #include #include +#include #include @@ -21,8 +22,10 @@ static void usage(char *error) { " rt_spin -l\n" "\n" "COMMON-OPTS = [-w] [-p PARTITION] [-c CLASS] [-s SCALE]\n" + " [-X LOCKING-PROTOCOL] [-L CRITICAL SECTION LENGTH] [-Q RESOURCE-ID]" "\n" - "WCET and PERIOD are milliseconds, DURATION is seconds.\n"); + "WCET and PERIOD are milliseconds, DURATION is seconds.\n" + "CRITICAL SECTION LENGTH is in milliseconds.\n"); exit(EXIT_FAILURE); } @@ -150,18 +153,37 @@ static void debug_delay_loop(void) } } -static int job(double exec_time, double program_end) +static int job(double exec_time, double program_end, int lock_od, double cs_length) { + double chunk1, chunk2; + if (wctime() > program_end) return 0; else { - loop_for(exec_time, program_end + 1); + if (lock_od >= 0) { + /* simulate critical section somewhere in the middle */ + chunk1 = drand48() * (exec_time - cs_length); + chunk2 = exec_time - cs_length - chunk1; + + /* non-critical section */ + loop_for(chunk1, program_end + 1); + + /* critical section */ + litmus_lock(lock_od); + loop_for(cs_length, program_end + 1); + litmus_unlock(lock_od); + + /* non-critical section */ + loop_for(chunk2, program_end + 2); + } else { + loop_for(exec_time, program_end + 1); + } sleep_next_period(); return 1; } } -#define OPTSTR "p:c:wlveo:f:s:q:" +#define OPTSTR "p:c:wlveo:f:s:q:X:L:Q:" int main(int argc, char** argv) { @@ -184,6 +206,13 @@ int main(int argc, char** argv) task_class_t class = RT_CLASS_HARD; int cur_job, num_jobs; + /* locking */ + int lock_od = -1; + int resource_id = 0; + const char *lock_namespace = "./rtspin-locks"; + int protocol = -1; + double cs_length = 1; /* millisecond */ + progname = argv[0]; while ((opt = getopt(argc, argv, OPTSTR)) != -1) { @@ -220,6 +249,21 @@ int main(int argc, char** argv) case 's': scale = atof(optarg); break; + case 'X': + protocol = lock_protocol_for_name(optarg); + if (protocol < 0) + usage("Unknown locking protocol specified."); + break; + case 'L': + cs_length = atof(optarg); + if (cs_length <= 0) + usage("Invalid critical section length."); + break; + case 'Q': + resource_id = atoi(optarg); + if (resource_id <= 0 && strcmp(optarg, "0")) + usage("Invalid resource ID."); + break; case ':': usage("Argument missing."); break; @@ -235,6 +279,8 @@ int main(int argc, char** argv) return 0; } + srand(getpid()); + if (file) { get_exec_times(file, column, &num_jobs, &exec_times); @@ -293,6 +339,15 @@ int main(int argc, char** argv) if (ret != 0) bail_out("could not become RT task"); + if (protocol >= 0) { + /* open reference to semaphore */ + lock_od = litmus_open_lock(protocol, resource_id, lock_namespace, &cpu); + if (lock_od < 0) { + perror("litmus_open_lock"); + usage("Could not open lock."); + } + } + if (wait) { ret = wait_for_ts_release(); if (ret != 0) @@ -306,11 +361,13 @@ int main(int argc, char** argv) for (cur_job = 0; cur_job < num_jobs; ++cur_job) { /* convert job's length to seconds */ job(exec_times[cur_job] * 0.001 * scale, - start + duration); + start + duration, + lock_od, cs_length * 0.001); } } else { - /* conver to seconds and scale */ - while (job(wcet_ms * 0.001 * scale, start + duration)); + /* convert to seconds and scale */ + while (job(wcet_ms * 0.001 * scale, start + duration, + lock_od, cs_length * 0.001)); } ret = task_mode(BACKGROUND_TASK); diff --git a/include/litmus.h b/include/litmus.h index 2b6a1dd..58af6b7 100644 --- a/include/litmus.h +++ b/include/litmus.h @@ -80,6 +80,13 @@ static inline int od_open(int fd, obj_type_t type, int obj_id) return od_openx(fd, type, obj_id, 0); } +int litmus_open_lock( + obj_type_t protocol, /* which locking protocol to use, e.g., FMLP_SEM */ + int lock_id, /* numerical id of the lock, user-specified */ + const char* namespace, /* path to a shared file */ + void *config_param); /* any extra info needed by the protocol (such + * as CPU under SRP and PCP), may be NULL */ + /* real-time locking protocol support */ int litmus_lock(int od); int litmus_unlock(int od); diff --git a/src/litmus.c b/src/litmus.c index b32254b..e0d9253 100644 --- a/src/litmus.c +++ b/src/litmus.c @@ -3,7 +3,10 @@ #include #include #include +#include #include +#include + #include /* for cpu sets */ @@ -49,6 +52,23 @@ const char* name_for_lock_protocol(int id) return ""; } +int litmus_open_lock( + obj_type_t protocol, + int lock_id, + const char* namespace, + void *config_param) +{ + int fd, od; + + fd = open(namespace, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); + if (fd < 0) + return -1; + od = od_openx(fd, protocol, lock_id, config_param); + close(fd); + return od; +} + + void show_rt_param(struct rt_task* tp) { -- cgit v1.2.2 From 7051511d6b059097f2eb5f650294e0ead7d8f488 Mon Sep 17 00:00:00 2001 From: Bjoern Brandenburg Date: Fri, 15 Feb 2013 16:48:59 +0100 Subject: Add test cases that check whether nesting is prohibited The kernel should deny attempts to nest resources in ways that are not supported. --- tests/nesting.c | 468 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 468 insertions(+) create mode 100644 tests/nesting.c diff --git a/tests/nesting.c b/tests/nesting.c new file mode 100644 index 0000000..7b30715 --- /dev/null +++ b/tests/nesting.c @@ -0,0 +1,468 @@ +#include +#include +#include + +#include "tests.h" +#include "litmus.h" + +TESTCASE(lock_fmlp_nesting, PSN_EDF | GSN_EDF | P_FP, + "FMLP no nesting allowed") +{ + int fd, od, od2; + + SYSCALL( fd = open(".fmlp_locks", O_RDONLY | O_CREAT) ); + + SYSCALL( sporadic_partitioned(10, 100, 0) ); + SYSCALL( task_mode(LITMUS_RT_TASK) ); + + SYSCALL( od = open_fmlp_sem(fd, 0) ); + SYSCALL( od2 = open_fmlp_sem(fd, 1) ); + + SYSCALL( litmus_lock(od) ); + SYSCALL( litmus_unlock(od) ); + + SYSCALL( litmus_lock(od2) ); + SYSCALL( litmus_unlock(od2) ); + + SYSCALL( litmus_lock(od) ); + SYSCALL_FAILS(EBUSY, litmus_lock(od2)); + SYSCALL( litmus_unlock(od) ); + + SYSCALL( litmus_lock(od2) ); + SYSCALL_FAILS(EBUSY, litmus_lock(od)); + SYSCALL( litmus_unlock(od2) ); + + SYSCALL( od_close(od) ); + SYSCALL( od_close(od2) ); + + SYSCALL( close(fd) ); + + SYSCALL( remove(".fmlp_locks") ); +} + +TESTCASE(lock_fmlp_srp_nesting, PSN_EDF | P_FP, + "FMLP no nesting with SRP resources allowed") +{ + int fd, od, od2; + + SYSCALL( fd = open(".fmlp_locks", O_RDONLY | O_CREAT) ); + + SYSCALL( sporadic_partitioned(10, 100, 0) ); + SYSCALL( task_mode(LITMUS_RT_TASK) ); + + SYSCALL( od = open_fmlp_sem(fd, 0) ); + SYSCALL( od2 = open_srp_sem(fd, 1) ); + + SYSCALL( litmus_lock(od) ); + SYSCALL( litmus_unlock(od) ); + + SYSCALL( litmus_lock(od2) ); + SYSCALL( litmus_unlock(od2) ); + + SYSCALL( litmus_lock(od) ); + SYSCALL_FAILS(EBUSY, litmus_lock(od2)); + SYSCALL( litmus_unlock(od) ); + + SYSCALL( litmus_lock(od2) ); + SYSCALL_FAILS(EBUSY, litmus_lock(od)); + SYSCALL( litmus_unlock(od2) ); + + SYSCALL( od_close(od) ); + SYSCALL( od_close(od2) ); + + SYSCALL( close(fd) ); + + SYSCALL( remove(".fmlp_locks") ); +} + +TESTCASE(lock_srp_nesting, PSN_EDF | P_FP, + "SRP nesting allowed") +{ + int fd, od, od2; + + SYSCALL( fd = open(".fmlp_locks", O_RDONLY | O_CREAT) ); + + SYSCALL( sporadic_partitioned(10, 100, 0) ); + SYSCALL( task_mode(LITMUS_RT_TASK) ); + + SYSCALL( od = open_srp_sem(fd, 0) ); + SYSCALL( od2 = open_srp_sem(fd, 1) ); + + SYSCALL( litmus_lock(od) ); + SYSCALL( litmus_unlock(od) ); + + SYSCALL( litmus_lock(od2) ); + SYSCALL( litmus_unlock(od2) ); + + SYSCALL( litmus_lock(od) ); + SYSCALL( litmus_lock(od2) ); + SYSCALL( litmus_unlock(od2) ); + SYSCALL( litmus_unlock(od) ); + + SYSCALL( litmus_lock(od2) ); + SYSCALL( litmus_lock(od) ); + SYSCALL( litmus_unlock(od) ); + SYSCALL( litmus_unlock(od2) ); + + SYSCALL( od_close(od) ); + SYSCALL( od_close(od2) ); + + SYSCALL( close(fd) ); + + SYSCALL( remove(".fmlp_locks") ); +} + +TESTCASE(lock_pcp_nesting, P_FP, + "PCP nesting allowed") +{ + int od, od2; + const char* namespace = ".pcp_locks"; + + SYSCALL( sporadic_partitioned(10, 100, 0) ); + SYSCALL( task_mode(LITMUS_RT_TASK) ); + + SYSCALL( od = litmus_open_lock(PCP_SEM, 0, namespace, NULL) ); + SYSCALL( od2 = litmus_open_lock(PCP_SEM, 1, namespace, NULL) ); + + SYSCALL( litmus_lock(od) ); + SYSCALL( litmus_unlock(od) ); + + SYSCALL( litmus_lock(od2) ); + SYSCALL( litmus_unlock(od2) ); + + SYSCALL( litmus_lock(od) ); + SYSCALL( litmus_lock(od2) ); + SYSCALL( litmus_unlock(od2) ); + SYSCALL( litmus_unlock(od) ); + + SYSCALL( litmus_lock(od2) ); + SYSCALL( litmus_lock(od) ); + SYSCALL( litmus_unlock(od) ); + SYSCALL( litmus_unlock(od2) ); + + SYSCALL( od_close(od) ); + SYSCALL( od_close(od2) ); + + SYSCALL( remove(namespace) ); +} + +TESTCASE(lock_mpcp_pcp_no_nesting, P_FP, + "PCP and MPCP nesting not allowed") +{ + int od, od2; + const char* namespace = ".pcp_locks"; + + SYSCALL( sporadic_partitioned(10, 100, 0) ); + SYSCALL( task_mode(LITMUS_RT_TASK) ); + + SYSCALL( od = litmus_open_lock(PCP_SEM, 0, namespace, NULL) ); + SYSCALL( od2 = litmus_open_lock(MPCP_SEM, 1, namespace, NULL) ); + + SYSCALL( litmus_lock(od) ); + SYSCALL( litmus_unlock(od) ); + + SYSCALL( litmus_lock(od2) ); + SYSCALL( litmus_unlock(od2) ); + + SYSCALL( litmus_lock(od) ); + SYSCALL_FAILS(EBUSY, litmus_lock(od2)); + SYSCALL( litmus_unlock(od) ); + + SYSCALL( litmus_lock(od2) ); + SYSCALL_FAILS(EBUSY, litmus_lock(od)); + SYSCALL( litmus_unlock(od2) ); + + SYSCALL( od_close(od) ); + SYSCALL( od_close(od2) ); + + SYSCALL( remove(namespace) ); +} + +TESTCASE(lock_fmlp_pcp_no_nesting, P_FP, + "PCP and FMLP nesting not allowed") +{ + int od, od2; + const char* namespace = ".pcp_locks"; + + SYSCALL( sporadic_partitioned(10, 100, 0) ); + SYSCALL( task_mode(LITMUS_RT_TASK) ); + + SYSCALL( od = litmus_open_lock(PCP_SEM, 0, namespace, NULL) ); + SYSCALL( od2 = litmus_open_lock(FMLP_SEM, 1, namespace, NULL) ); + + SYSCALL( litmus_lock(od) ); + SYSCALL( litmus_unlock(od) ); + + SYSCALL( litmus_lock(od2) ); + SYSCALL( litmus_unlock(od2) ); + + SYSCALL( litmus_lock(od) ); + SYSCALL_FAILS(EBUSY, litmus_lock(od2)); + SYSCALL( litmus_unlock(od) ); + + SYSCALL( litmus_lock(od2) ); + SYSCALL_FAILS(EBUSY, litmus_lock(od)); + SYSCALL( litmus_unlock(od2) ); + + SYSCALL( od_close(od) ); + SYSCALL( od_close(od2) ); + + SYSCALL( remove(namespace) ); +} + +TESTCASE(lock_dpcp_pcp_no_nesting, P_FP, + "PCP and DPCP nesting not allowed") +{ + int od, od2; + int cpu = 0; + const char* namespace = ".pcp_locks"; + + SYSCALL( sporadic_partitioned(10, 100, 0) ); + SYSCALL( task_mode(LITMUS_RT_TASK) ); + + SYSCALL( od = litmus_open_lock(PCP_SEM, 0, namespace, NULL) ); + SYSCALL( od2 = litmus_open_lock(DPCP_SEM, 1, namespace, &cpu) ); + + SYSCALL( litmus_lock(od) ); + SYSCALL( litmus_unlock(od) ); + + SYSCALL( litmus_lock(od2) ); + SYSCALL( litmus_unlock(od2) ); + + SYSCALL( litmus_lock(od) ); + SYSCALL_FAILS(EBUSY, litmus_lock(od2)); + SYSCALL( litmus_unlock(od) ); + + SYSCALL( litmus_lock(od2) ); + SYSCALL_FAILS(EBUSY, litmus_lock(od)); + SYSCALL( litmus_unlock(od2) ); + + SYSCALL( od_close(od) ); + SYSCALL( od_close(od2) ); + + SYSCALL( remove(namespace) ); +} + +TESTCASE(lock_mpcp_srp_no_nesting, P_FP, + "SRP and MPCP nesting not allowed") +{ + int od, od2; + const char* namespace = ".pcp_locks"; + + SYSCALL( sporadic_partitioned(10, 100, 0) ); + SYSCALL( task_mode(LITMUS_RT_TASK) ); + + SYSCALL( od = litmus_open_lock(SRP_SEM, 0, namespace, NULL) ); + SYSCALL( od2 = litmus_open_lock(MPCP_SEM, 1, namespace, NULL) ); + + SYSCALL( litmus_lock(od) ); + SYSCALL( litmus_unlock(od) ); + + SYSCALL( litmus_lock(od2) ); + SYSCALL( litmus_unlock(od2) ); + + SYSCALL( litmus_lock(od) ); + SYSCALL_FAILS(EBUSY, litmus_lock(od2)); + SYSCALL( litmus_unlock(od) ); + + SYSCALL( litmus_lock(od2) ); + SYSCALL_FAILS(EBUSY, litmus_lock(od)); + SYSCALL( litmus_unlock(od2) ); + + SYSCALL( od_close(od) ); + SYSCALL( od_close(od2) ); + + SYSCALL( remove(namespace) ); +} + +TESTCASE(lock_dpcp_srp_no_nesting, P_FP, + "SRP and DPCP nesting not allowed") +{ + int od, od2; + int cpu = 0; + const char* namespace = ".pcp_locks"; + + SYSCALL( sporadic_partitioned(10, 100, 0) ); + SYSCALL( task_mode(LITMUS_RT_TASK) ); + + SYSCALL( od = litmus_open_lock(SRP_SEM, 0, namespace, NULL) ); + SYSCALL( od2 = litmus_open_lock(DPCP_SEM, 1, namespace, &cpu) ); + + SYSCALL( litmus_lock(od) ); + SYSCALL( litmus_unlock(od) ); + + SYSCALL( litmus_lock(od2) ); + SYSCALL( litmus_unlock(od2) ); + + SYSCALL( litmus_lock(od) ); + SYSCALL_FAILS(EBUSY, litmus_lock(od2)); + SYSCALL( litmus_unlock(od) ); + + SYSCALL( litmus_lock(od2) ); + SYSCALL_FAILS(EBUSY, litmus_lock(od)); + SYSCALL( litmus_unlock(od2) ); + + SYSCALL( od_close(od) ); + SYSCALL( od_close(od2) ); + + SYSCALL( remove(namespace) ); +} + +TESTCASE(lock_fmlp_mpcp_no_nesting, P_FP, + "MPCP and FMLP nesting not allowed") +{ + int od, od2; + const char* namespace = ".pcp_locks"; + + SYSCALL( sporadic_partitioned(10, 100, 0) ); + SYSCALL( task_mode(LITMUS_RT_TASK) ); + + SYSCALL( od = litmus_open_lock(MPCP_SEM, 0, namespace, NULL) ); + SYSCALL( od2 = litmus_open_lock(FMLP_SEM, 1, namespace, NULL) ); + + SYSCALL( litmus_lock(od) ); + SYSCALL( litmus_unlock(od) ); + + SYSCALL( litmus_lock(od2) ); + SYSCALL( litmus_unlock(od2) ); + + SYSCALL( litmus_lock(od) ); + SYSCALL_FAILS(EBUSY, litmus_lock(od2)); + SYSCALL( litmus_unlock(od) ); + + SYSCALL( litmus_lock(od2) ); + SYSCALL_FAILS(EBUSY, litmus_lock(od)); + SYSCALL( litmus_unlock(od2) ); + + SYSCALL( od_close(od) ); + SYSCALL( od_close(od2) ); + + SYSCALL( remove(namespace) ); +} + +TESTCASE(lock_fmlp_dpcp_no_nesting, P_FP, + "DPCP and FMLP nesting not allowed") +{ + int od, od2; + const char* namespace = ".pcp_locks"; + int cpu = 0; + + SYSCALL( sporadic_partitioned(10, 100, 0) ); + SYSCALL( task_mode(LITMUS_RT_TASK) ); + + SYSCALL( od = litmus_open_lock(DPCP_SEM, 0, namespace, &cpu) ); + SYSCALL( od2 = litmus_open_lock(FMLP_SEM, 1, namespace, NULL) ); + + SYSCALL( litmus_lock(od) ); + SYSCALL( litmus_unlock(od) ); + + SYSCALL( litmus_lock(od2) ); + SYSCALL( litmus_unlock(od2) ); + + SYSCALL( litmus_lock(od) ); + SYSCALL_FAILS(EBUSY, litmus_lock(od2)); + SYSCALL( litmus_unlock(od) ); + + SYSCALL( litmus_lock(od2) ); + SYSCALL_FAILS(EBUSY, litmus_lock(od)); + SYSCALL( litmus_unlock(od2) ); + + SYSCALL( od_close(od) ); + SYSCALL( od_close(od2) ); + + SYSCALL( remove(namespace) ); +} + +TESTCASE(mpcp_nesting, P_FP, + "MPCP no nesting allowed") +{ + int od, od2; + + SYSCALL( sporadic_partitioned(10, 100, 0) ); + SYSCALL( task_mode(LITMUS_RT_TASK) ); + + SYSCALL( od = litmus_open_lock(MPCP_SEM, 0, ".mpcp_locks", NULL) ); + SYSCALL( od2 = litmus_open_lock(MPCP_SEM, 1, ".mpcp_locks", NULL) ); + + SYSCALL( litmus_lock(od) ); + SYSCALL( litmus_unlock(od) ); + + SYSCALL( litmus_lock(od2) ); + SYSCALL( litmus_unlock(od2) ); + + SYSCALL( litmus_lock(od) ); + SYSCALL_FAILS(EBUSY, litmus_lock(od2)); + SYSCALL( litmus_unlock(od) ); + + SYSCALL( litmus_lock(od2) ); + SYSCALL_FAILS(EBUSY, litmus_lock(od)); + SYSCALL( litmus_unlock(od2) ); + + SYSCALL( od_close(od) ); + SYSCALL( od_close(od2) ); + + SYSCALL( remove(".mpcp_locks") ); +} + +TESTCASE(mpcpvs_nesting, P_FP, + "MPCP-VS no nesting allowed") +{ + int od, od2; + + SYSCALL( sporadic_partitioned(10, 100, 0) ); + SYSCALL( task_mode(LITMUS_RT_TASK) ); + + SYSCALL( od = litmus_open_lock(MPCP_VS_SEM, 0, ".mpcp_locks", NULL) ); + SYSCALL( od2 = litmus_open_lock(MPCP_VS_SEM, 1, ".mpcp_locks", NULL) ); + + SYSCALL( litmus_lock(od) ); + SYSCALL( litmus_unlock(od) ); + + SYSCALL( litmus_lock(od2) ); + SYSCALL( litmus_unlock(od2) ); + + SYSCALL( litmus_lock(od) ); + SYSCALL_FAILS(EBUSY, litmus_lock(od2)); + SYSCALL( litmus_unlock(od) ); + + SYSCALL( litmus_lock(od2) ); + SYSCALL_FAILS(EBUSY, litmus_lock(od)); + SYSCALL( litmus_unlock(od2) ); + + SYSCALL( od_close(od) ); + SYSCALL( od_close(od2) ); + + SYSCALL( remove(".mpcp_locks") ); +} + +TESTCASE(dpcp_nesting, P_FP, + "DPCP no nesting allowed") +{ + int od, od2; + int cpu = 0; + + SYSCALL( sporadic_partitioned(10, 100, 0) ); + SYSCALL( task_mode(LITMUS_RT_TASK) ); + + SYSCALL( od = litmus_open_lock(DPCP_SEM, 0, ".dpcp_locks", &cpu) ); + SYSCALL( od2 = litmus_open_lock(DPCP_SEM, 1, ".dpcp_locks", &cpu) ); + + SYSCALL( litmus_lock(od) ); + SYSCALL( litmus_unlock(od) ); + + SYSCALL( litmus_lock(od2) ); + SYSCALL( litmus_unlock(od2) ); + + SYSCALL( litmus_lock(od) ); + SYSCALL_FAILS(EBUSY, litmus_lock(od2)); + SYSCALL( litmus_unlock(od) ); + + SYSCALL( litmus_lock(od2) ); + SYSCALL_FAILS(EBUSY, litmus_lock(od)); + SYSCALL( litmus_unlock(od2) ); + + SYSCALL( od_close(od) ); + SYSCALL( od_close(od2) ); + + SYSCALL( remove(".dpcp_locks") ); +} -- cgit v1.2.2 From 072b486393ab702eea9ea0a7fef569dbf8be0a32 Mon Sep 17 00:00:00 2001 From: Glenn Elliott Date: Fri, 8 Mar 2013 01:25:35 -0500 Subject: uncachedev: uncache test tool. This adds the uncache test tool (bin/uncache.c). The tool can be used to test Litmus's char device driver for allocating uncacheable CPU memory. The tool runs various checks and gathers basic cache vs. main memory statistics. In the future, uncache could be extended to quantify the benefits of the L1, L2, and L3 caches, instead of treating them as a black box. Note: Uncache works best when compiled with '-O2'. While '-O2' has not been added to the Makefile, other code was updated (code in tests/ and rtspin), to compile with -O2. DEPENDS UPON LITMUS-RT PATCH 888d097deb6d1fdc0c89a4f9667fd81cf416cfc7. --- Makefile | 5 +- bin/rtspin.c | 6 +- bin/uncache.c | 381 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ tests/fdso.c | 4 +- tests/locks.c | 8 +- tests/pcp.c | 8 +- 6 files changed, 398 insertions(+), 14 deletions(-) create mode 100644 bin/uncache.c diff --git a/Makefile b/Makefile index 8195752..5432edd 100644 --- a/Makefile +++ b/Makefile @@ -71,7 +71,7 @@ AR := ${CROSS_COMPILE}${AR} all = lib ${rt-apps} rt-apps = cycles base_task rt_launch rtspin release_ts measure_syscall \ - base_mt_task runtests + base_mt_task uncache runtests .PHONY: all lib clean dump-config TAGS tags cscope help @@ -215,6 +215,9 @@ obj-rt_launch = rt_launch.o common.o obj-rtspin = rtspin.o common.o lib-rtspin = -lrt +obj-uncache = uncache.o +lib-uncache = -lrt + obj-release_ts = release_ts.o obj-measure_syscall = null_call.o diff --git a/bin/rtspin.c b/bin/rtspin.c index 5054d0b..657a94c 100644 --- a/bin/rtspin.c +++ b/bin/rtspin.c @@ -80,7 +80,7 @@ static void get_exec_times(const char *file, const int column, for (cur_col = 1; cur_col < column; ++cur_col) { /* discard input until we get to the column we want */ - fscanf(fstream, "%*s,"); + int unused __attribute__ ((unused)) = fscanf(fstream, "%*s,"); } /* get the desired exec. time */ @@ -200,11 +200,11 @@ int main(int argc, char** argv) int column = 1; const char *file = NULL; int want_enforcement = 0; - double duration = 0, start; + double duration = 0, start = 0; double *exec_times = NULL; double scale = 1.0; task_class_t class = RT_CLASS_HARD; - int cur_job, num_jobs; + int cur_job = 0, num_jobs = 0; /* locking */ int lock_od = -1; diff --git a/bin/uncache.c b/bin/uncache.c new file mode 100644 index 0000000..b6f6913 --- /dev/null +++ b/bin/uncache.c @@ -0,0 +1,381 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Test tool for validating Litmus's uncache device. */ +/* Tool also capable basic cache vs. sysmem statistics. */ +/* Compile with '-O2' for significaintly greater margins */ +/* in performance between cache and sysmem: */ +/* (Intel Xeon X5650) */ +/* -g -> uncache is 30x slower */ +/* -O2 -> uncache is >100x slower */ + +int PAGE_SIZE; +#define NR_PAGES 16 + +#define UNCACHE_DEV "/dev/litmus/uncache" + +/* volatile forces a read from memory (or cache) on every reference. Note + that volatile does not keep data out of the cache! */ +typedef volatile char* pbuf_t; + +/* hit the first byte in each page. + addr must be page aligned. */ +inline int linear_write(pbuf_t addr, int size, char val) +{ + pbuf_t end = addr + size; + pbuf_t step; + int nr_pages = (unsigned long)(end - addr)/PAGE_SIZE; + int times = nr_pages * PAGE_SIZE; + int i; + + for (i = 0; i < times; ++i) + for(step = addr; step < end; step += PAGE_SIZE) + *step = val; + return 0; +} +inline int linear_read(pbuf_t addr, int size, char val) +{ + pbuf_t end = addr + size; + pbuf_t step; + int nr_pages = (unsigned long)(end - addr)/PAGE_SIZE; + int times = nr_pages * PAGE_SIZE; + int i; + + for (i = 0; i < times; ++i) + for(step = addr; step < end; step += PAGE_SIZE) { + if (*step != val) + return -1; + } + return 0; +} + +/* write to *data nr times. */ +inline int hammer_write(pbuf_t data, char val, int nr) +{ + int i; + for (i = 0; i < nr; ++i) + *data = val; + return 0; +} + +/* read from *data nr times. */ +inline int hammer_read(pbuf_t data, char val, int nr) +{ + int i; + for (i = 0; i < nr; ++i) { + if (*data != val) + return -1; + } + return 0; +} + +inline int test(pbuf_t data, int size, int trials) +{ + int HAMMER_TIME = 10000; /* can't cache this! */ + char VAL = 0x55; + int t; + for(t = 0; t < trials; ++t) { + +#if 0 + if (linear_write(data, size, VAL) != 0) { + printf("failed linear_write()\n"); + return -1; + } + if (linear_read(data, size, VAL) != 0) { + printf("failed linear_read()\n"); + return -1; + } +#endif + + /* hammer at the first byte in the array */ + if (hammer_write(data, VAL, HAMMER_TIME) != 0) { + printf("failed hammer_write()\n"); + return -1; + } + if (hammer_read(data, VAL, HAMMER_TIME) != 0) { + printf("failed hammer_read()\n"); + return -1; + } + } + return 0; +} + +inline void timespec_normalize(struct timespec* ts, time_t sec, int64_t nsec) +{ + while(nsec > 1000000000LL) { + asm("" : "+rm"(nsec)); + nsec -= 1000000000LL; + ++sec; + } + while(nsec < 0) { + asm("" : "+rm"(nsec)); + nsec += 1000000000LL; + --sec; + } + + ts->tv_sec = sec; + ts->tv_nsec = nsec; +} + +inline struct timespec timespec_sub(struct timespec lhs, struct timespec rhs) +{ + struct timespec delta; + timespec_normalize(&delta, lhs.tv_sec - rhs.tv_sec, lhs.tv_nsec - rhs.tv_nsec); + return delta; +} + +inline struct timespec timespec_add(struct timespec lhs, struct timespec rhs) +{ + struct timespec delta; + timespec_normalize(&delta, lhs.tv_sec + rhs.tv_sec, lhs.tv_nsec + rhs.tv_nsec); + return delta; +} + +inline int64_t timespec_to_us(struct timespec ts) +{ + int64_t t; + t = ts.tv_sec * 1000000LL; + t += ts.tv_nsec / 1000LL; + return t; +} + +/* hammers away at the first byte in each mmaped page and + times how long it took. */ +int do_data(int do_uncache, int64_t* time) +{ + int size; + int prot = PROT_READ | PROT_WRITE; + int flags = MAP_PRIVATE; + + pbuf_t data; + + struct sched_param fifo_params; + + struct timespec start, end; + int64_t elapsed; + int trials = 1000; + + printf("Running data access test.\n"); + + mlockall(MCL_CURRENT | MCL_FUTURE); + + memset(&fifo_params, 0, sizeof(fifo_params)); + fifo_params.sched_priority = sched_get_priority_max(SCHED_FIFO); + + size = PAGE_SIZE*NR_PAGES; + + printf("Allocating %d %s pages.\n", NR_PAGES, (do_uncache) ? + "uncacheable" : "cacheable"); + if (do_uncache) { + int fd = open(UNCACHE_DEV, O_RDWR); + data = mmap(NULL, size, prot, flags, fd, 0); + close(fd); + } + else { + /* Accessed data will probably fit in L1, so this will go VERY fast. + Code should also have little-to-no pipeline stalls. */ + flags |= MAP_ANONYMOUS; + data = mmap(NULL, size, prot, flags, -1, 0); + } + if (data == MAP_FAILED) { + printf("Failed to alloc data! " + "Are you running Litmus? " + "Is Litmus broken?\n"); + return -1; + } + else { + printf("Data allocated at %p.\n", data); + } + + printf("Beginning tests...\n"); + if (sched_setscheduler(getpid(), SCHED_FIFO, &fifo_params)) { + printf("(Could not become SCHED_FIFO task.) Are you running as root?\n"); + } + + /* observations suggest that no warmup phase is needed. */ + clock_gettime(CLOCK_THREAD_CPUTIME_ID, &start); + if (test(data, size, trials) != 0) { + printf("Test failed!\n"); + munmap((char*)data, size); + return -1; + } + clock_gettime(CLOCK_THREAD_CPUTIME_ID, &end); + elapsed = timespec_to_us(timespec_sub(end, start)); + printf("%s Time: %ldus\n", (do_uncache) ? + "Uncache" : "Cache", elapsed); + + munmap((char*)data, size); + + if(time) + *time = elapsed; + + return 0; +} + +/* compares runtime of cached vs. uncached */ +int do_data_compare() +{ + const double thresh = 1.3; + int ret = 0; + double ratio; + int64_t cache_time = 0, uncache_time = 0; + + printf("Timing cached pages...\n"); + ret = do_data(0, &cache_time); + if (ret != 0) + goto out; + + printf("Timing uncached pages...\n"); + ret = do_data(1, &uncache_time); + if (ret != 0) + goto out; + + ratio = (double)uncache_time/(double)cache_time; + printf("Uncached/Cached Ratio: %f\n", ratio); + + if (ratio < thresh) { + printf("Ratio is unexpectedly small (< %f)! " + " Uncache broken? Are you on kvm?\n", thresh); + ret = -1; + } + +out: + return ret; +} + +/* tries to max out uncache allocations. + under normal conditions (non-mlock), + pages should spill into swap. uncache + pages are not locked in memory. */ +int do_max_alloc(void) +{ + int fd; + int good = 1; + int count = 0; + uint64_t mmap_size = PAGE_SIZE; /* start at one page per mmap */ + + /* half of default limit on ubuntu. (see /proc/sys/vm/max_map_count) */ + int max_mmaps = 32765; + volatile char** maps = calloc(max_mmaps, sizeof(pbuf_t)); + + if (!maps) { + printf("failed to alloc pointers for pages\n"); + return -1; + } + + printf("Testing max amount of uncache data. System may get wonkie (OOM Killer)!\n"); + + fd = open(UNCACHE_DEV, O_RDWR); + do { + int i; + int nr_pages = mmap_size/PAGE_SIZE; + printf("Testing mmaps of %d pages.\n", nr_pages); + + count = 0; + for (i = 0; (i < max_mmaps) && good; ++i) { + pbuf_t data = mmap(NULL, mmap_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_POPULATE, fd, 0); + + if (data != MAP_FAILED) { + maps[i] = data; + ++count; + } + else { + perror(NULL); + good = 0; + } + } + for (i = 0; i < count; ++i) { + if (maps[i]) + munmap((char*)(maps[i]), mmap_size); + } + memset(maps, 0, sizeof(maps[0])*max_mmaps); + + mmap_size *= 2; /* let's do it again with bigger allocations */ + }while(good); + + free(maps); + close(fd); + + printf("Maxed out allocs with %d mmaps of %lu pages in size.\n", + count, mmap_size/PAGE_SIZE); + + return 0; +} + +typedef enum +{ + UNCACHE, + CACHE, + COMPARE, + MAX_ALLOC +} test_t; + +#define OPTSTR "ucxa" +int main(int argc, char** argv) +{ + int ret; + test_t test = UNCACHE; + int opt; + PAGE_SIZE = sysconf(_SC_PAGE_SIZE); + + while((opt = getopt(argc, argv, OPTSTR)) != -1) { + switch(opt) { + case 'c': + test = CACHE; + break; + case 'u': + test = UNCACHE; + break; + case 'x': + test = COMPARE; + break; + case 'a': + test = MAX_ALLOC; + break; + case ':': + printf("missing option\n"); + exit(-1); + case '?': + default: + printf("bad argument\n"); + exit(-1); + } + } + + + printf("Page Size: %d\n", PAGE_SIZE); + + switch(test) + { + case CACHE: + ret = do_data(0, NULL); + break; + case UNCACHE: + ret = do_data(1, NULL); + break; + case COMPARE: + ret = do_data_compare(); + break; + case MAX_ALLOC: + ret = do_max_alloc(); + break; + default: + printf("invalid test\n"); + ret = -1; + break; + } + + if (ret != 0) { + printf("Test failed.\n"); + } + + return ret; +} diff --git a/tests/fdso.c b/tests/fdso.c index 8a2a0d0..fda343f 100644 --- a/tests/fdso.c +++ b/tests/fdso.c @@ -16,7 +16,7 @@ TESTCASE(fmlp_not_active, C_EDF | PFAIR | LINUX, { int fd; - SYSCALL( fd = open(".fmlp_locks", O_RDONLY | O_CREAT) ); + SYSCALL( fd = open(".fmlp_locks", O_RDONLY | O_CREAT, S_IRUSR) ); ASSERT(fd != -1); @@ -57,7 +57,7 @@ TESTCASE(not_inherit_od, GSN_EDF | PSN_EDF, { int fd, od, pid, status; - SYSCALL( fd = open(".fmlp_locks", O_RDONLY | O_CREAT) ); + SYSCALL( fd = open(".fmlp_locks", O_RDONLY | O_CREAT, S_IRUSR) ); SYSCALL( od = open_fmlp_sem(fd, 0) ); diff --git a/tests/locks.c b/tests/locks.c index d7ebfe2..9a928b3 100644 --- a/tests/locks.c +++ b/tests/locks.c @@ -11,7 +11,7 @@ TESTCASE(not_lock_fmlp_be, GSN_EDF | PSN_EDF | P_FP, { int fd, od; - SYSCALL( fd = open(".fmlp_locks", O_RDONLY | O_CREAT) ); + SYSCALL( fd = open(".fmlp_locks", O_RDONLY | O_CREAT, S_IRUSR) ); SYSCALL( od = open_fmlp_sem(fd, 0) ); @@ -34,7 +34,7 @@ TESTCASE(not_lock_srp_be, PSN_EDF | P_FP, { int fd, od; - SYSCALL( fd = open(".srp_locks", O_RDONLY | O_CREAT) ); + SYSCALL( fd = open(".srp_locks", O_RDONLY | O_CREAT, S_IRUSR) ); /* BE tasks may not open SRP semaphores */ @@ -51,7 +51,7 @@ TESTCASE(lock_srp, PSN_EDF | P_FP, { int fd, od; - SYSCALL( fd = open(".srp_locks", O_RDONLY | O_CREAT) ); + SYSCALL( fd = open(".srp_locks", O_RDONLY | O_CREAT, S_IRUSR) ); SYSCALL( sporadic_partitioned(10, 100, 0) ); SYSCALL( task_mode(LITMUS_RT_TASK) ); @@ -83,7 +83,7 @@ TESTCASE(lock_fmlp, PSN_EDF | GSN_EDF | P_FP, { int fd, od; - SYSCALL( fd = open(".fmlp_locks", O_RDONLY | O_CREAT) ); + SYSCALL( fd = open(".fmlp_locks", O_RDONLY | O_CREAT, S_IRUSR) ); SYSCALL( sporadic_partitioned(10, 100, 0) ); SYSCALL( task_mode(LITMUS_RT_TASK) ); diff --git a/tests/pcp.c b/tests/pcp.c index 52ee959..ff4259c 100644 --- a/tests/pcp.c +++ b/tests/pcp.c @@ -13,7 +13,7 @@ TESTCASE(lock_pcp, P_FP, { int fd, od, cpu = 0; - SYSCALL( fd = open(".pcp_locks", O_RDONLY | O_CREAT) ); + SYSCALL( fd = open(".pcp_locks", O_RDONLY | O_CREAT, S_IRUSR) ); SYSCALL( sporadic_partitioned(10, 100, cpu) ); SYSCALL( task_mode(LITMUS_RT_TASK) ); @@ -250,7 +250,7 @@ TESTCASE(lock_dpcp, P_FP, { int fd, od, cpu = 1; - SYSCALL( fd = open(".pcp_locks", O_RDONLY | O_CREAT) ); + SYSCALL( fd = open(".pcp_locks", O_RDONLY | O_CREAT, S_IRUSR) ); SYSCALL( sporadic_partitioned(10, 100, 0) ); SYSCALL( task_mode(LITMUS_RT_TASK) ); @@ -281,7 +281,7 @@ TESTCASE(not_lock_pcp_be, P_FP, { int fd, od; - SYSCALL( fd = open(".pcp_locks", O_RDONLY | O_CREAT) ); + SYSCALL( fd = open(".pcp_locks", O_RDONLY | O_CREAT, S_IRUSR) ); /* BE tasks are not even allowed to open a PCP semaphore */ SYSCALL_FAILS(EPERM, od = open_pcp_sem(fd, 0, 1) ); @@ -303,7 +303,7 @@ TESTCASE(lock_mpcp, P_FP, { int fd, od; - SYSCALL( fd = open(".pcp_locks", O_RDONLY | O_CREAT) ); + SYSCALL( fd = open(".pcp_locks", O_RDONLY | O_CREAT, S_IRUSR) ); SYSCALL( sporadic_partitioned(10, 100, 0) ); SYSCALL( task_mode(LITMUS_RT_TASK) ); -- cgit v1.2.2 From 1ff4fc699f01f0ad1359fad48b00c9d3be1b28b4 Mon Sep 17 00:00:00 2001 From: Glenn Elliott Date: Fri, 8 Mar 2013 01:37:46 -0500 Subject: Make github/staging complatible with -O2. Minor changes to test case code to enable compilation with 'gcc -O2' (gcc v4.7.2). --- Makefile | 2 +- tests/nesting.c | 6 +++--- tests/pcp.c | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index 5432edd..f6b00a0 100644 --- a/Makefile +++ b/Makefile @@ -19,7 +19,7 @@ LITMUS_KERNEL ?= ../litmus-rt # Internal configuration. # compiler flags -flags-debug = -Wall -Werror -g -Wdeclaration-after-statement +flags-debug = -O2 -Wall -Werror -g -Wdeclaration-after-statement flags-api = -D_XOPEN_SOURCE=600 -D_GNU_SOURCE # architecture-specific flags diff --git a/tests/nesting.c b/tests/nesting.c index 7b30715..b294334 100644 --- a/tests/nesting.c +++ b/tests/nesting.c @@ -10,7 +10,7 @@ TESTCASE(lock_fmlp_nesting, PSN_EDF | GSN_EDF | P_FP, { int fd, od, od2; - SYSCALL( fd = open(".fmlp_locks", O_RDONLY | O_CREAT) ); + SYSCALL( fd = open(".fmlp_locks", O_RDONLY | O_CREAT, S_IRUSR) ); SYSCALL( sporadic_partitioned(10, 100, 0) ); SYSCALL( task_mode(LITMUS_RT_TASK) ); @@ -45,7 +45,7 @@ TESTCASE(lock_fmlp_srp_nesting, PSN_EDF | P_FP, { int fd, od, od2; - SYSCALL( fd = open(".fmlp_locks", O_RDONLY | O_CREAT) ); + SYSCALL( fd = open(".fmlp_locks", O_RDONLY | O_CREAT, S_IRUSR) ); SYSCALL( sporadic_partitioned(10, 100, 0) ); SYSCALL( task_mode(LITMUS_RT_TASK) ); @@ -80,7 +80,7 @@ TESTCASE(lock_srp_nesting, PSN_EDF | P_FP, { int fd, od, od2; - SYSCALL( fd = open(".fmlp_locks", O_RDONLY | O_CREAT) ); + SYSCALL( fd = open(".fmlp_locks", O_RDONLY | O_CREAT, S_IRUSR) ); SYSCALL( sporadic_partitioned(10, 100, 0) ); SYSCALL( task_mode(LITMUS_RT_TASK) ); diff --git a/tests/pcp.c b/tests/pcp.c index ff4259c..8e1204f 100644 --- a/tests/pcp.c +++ b/tests/pcp.c @@ -57,7 +57,7 @@ TESTCASE(pcp_inheritance, P_FP, params.cls = RT_CLASS_HARD; params.budget_policy = NO_ENFORCEMENT; - SYSCALL( fd = open(".pcp_locks", O_RDONLY | O_CREAT) ); + SYSCALL( fd = open(".pcp_locks", O_RDONLY | O_CREAT, S_IRUSR) ); child_lo = FORK_TASK( @@ -162,7 +162,7 @@ TESTCASE(srp_ceiling_blocking, P_FP | PSN_EDF, params.cls = RT_CLASS_HARD; params.budget_policy = NO_ENFORCEMENT; - SYSCALL( fd = open(".srp_locks", O_RDONLY | O_CREAT) ); + SYSCALL( fd = open(".srp_locks", O_RDONLY | O_CREAT, S_IRUSR) ); child_lo = FORK_TASK( -- cgit v1.2.2