This shows you the differences between two versions of the page.
Next revision | Previous revision | ||
realtime:documentation:howto:applications:memory:mlockall_stack_sample [2017/06/01 01:30] jithu created |
realtime:documentation:howto:applications:memory:mlockall_stack_sample [2017/06/10 00:41] (current) jithu |
||
---|---|---|---|
Line 4: | Line 4: | ||
<code c> | <code c> | ||
- | /* | + | /* |
- | gcc -o check_stack_page_faults check_stack_page_faults.c -Wall -O3 -lpthread | + | * gcc -o check_stack_page_faults check_stack_page_faults.c -Wall -O3 -lpthread |
- | This application checks whether mlockall() forces all pages of a | + | * This application checks whether mlockall() forces all pages of a |
- | stack into RAM. | + | * stack into RAM. |
- | */ | + | */ |
- | #include <stdio.h> | + | |
- | #include <string.h> | + | #include <limits.h> |
#include <pthread.h> | #include <pthread.h> | ||
- | #include <semaphore.h> | ||
#include <sched.h> | #include <sched.h> | ||
- | #include <unistd.h> | + | #include <semaphore.h> |
+ | #include <stdio.h> | ||
+ | #include <stdlib.h> | ||
+ | #include <string.h> | ||
#include <sys/mman.h> | #include <sys/mman.h> | ||
#include <sys/resource.h> | #include <sys/resource.h> | ||
- | #include <limits.h> | + | #include <unistd.h> |
/* struct thread_data communicates data to our threads */ | /* struct thread_data communicates data to our threads */ | ||
Line 31: | Line 33: | ||
if (mlockall(MCL_CURRENT | MCL_FUTURE) != 0) { | if (mlockall(MCL_CURRENT | MCL_FUTURE) != 0) { | ||
perror("mlockall() failed"); | perror("mlockall() failed"); | ||
+ | exit(-1); | ||
} | } | ||
} | } | ||
Line 37: | Line 40: | ||
static int dump_page_faults(void) | static int dump_page_faults(void) | ||
{ | { | ||
+ | int new_minor_page_faults, new_major_page_faults; | ||
int page_faults_detected = 0; | int page_faults_detected = 0; | ||
- | static int init = 0; | ||
static struct rusage rusage_prev; | static struct rusage rusage_prev; | ||
struct rusage rusage; | struct rusage rusage; | ||
- | int new_minor_page_faults, new_major_page_faults; | + | static int init; |
getrusage(RUSAGE_SELF, &rusage); | getrusage(RUSAGE_SELF, &rusage); | ||
Line 50: | Line 53: | ||
if (init) { | if (init) { | ||
- | if ((new_minor_page_faults > 0) || | + | if ((new_minor_page_faults > 0) || |
(new_major_page_faults > 0)) { | (new_major_page_faults > 0)) { | ||
printf("New minor/major page faults: %d/%d\n", | printf("New minor/major page faults: %d/%d\n", | ||
Line 63: | Line 66: | ||
/* Start a thread */ | /* Start a thread */ | ||
static pthread_t startThread(int prio, int stack_size, | static pthread_t startThread(int prio, int stack_size, | ||
- | void *(*thread_run) (void *), void *args) | + | void *(*thread_run)(void *), void *args) |
{ | { | ||
+ | int min_stack_size = 16384; | ||
+ | struct sched_param sched; | ||
const char *failure; | const char *failure; | ||
pthread_attr_t attr; | pthread_attr_t attr; | ||
- | pthread_t tid; | ||
- | struct sched_param sched; | ||
- | int policy; | ||
int priority_min; | int priority_min; | ||
int priority_max; | int priority_max; | ||
- | int min_stack_size = 16384; | + | pthread_t tid; |
+ | int policy; | ||
for (;;) { | for (;;) { | ||
- | if ((policy = sched_getscheduler(0)) == -1) { | + | policy = sched_getscheduler(0); |
+ | if (policy == -1) { | ||
failure = "sched_getscheduler"; | failure = "sched_getscheduler"; | ||
break; | break; | ||
} | } | ||
- | if ((priority_min = sched_get_priority_min(policy)) == -1) { | + | priority_min = sched_get_priority_min(policy); |
+ | if (priority_min == -1) { | ||
failure = "sched_get_priority_min"; | failure = "sched_get_priority_min"; | ||
break; | break; | ||
Line 88: | Line 93: | ||
prio = priority_min; | prio = priority_min; | ||
- | if ((priority_max = sched_get_priority_max(policy)) == -1) { | + | priority_max = sched_get_priority_max(policy); |
+ | if (priority_max == -1) { | ||
failure = "sched_get_priority_max"; | failure = "sched_get_priority_max"; | ||
break; | break; | ||
Line 156: | Line 162: | ||
} | } | ||
- | return tid; | + | printf("FAILURE while %s in startThread\n", failure); |
+ | return -1; | ||
} | } | ||
Line 175: | Line 182: | ||
{ /* Limit the scope */ | { /* Limit the scope */ | ||
char stack_filler[pthread_data->stack_filler_size]; | char stack_filler[pthread_data->stack_filler_size]; | ||
- | + | ||
printf("%s performing checks\n", pthread_data->name); | printf("%s performing checks\n", pthread_data->name); | ||
- | for (i = 0; | + | for (i = 0; |
i < (int)pthread_data->stack_filler_size; | i < (int)pthread_data->stack_filler_size; | ||
i += sysconf(_SC_PAGESIZE)) { | i += sysconf(_SC_PAGESIZE)) { | ||
stack_filler[i] = 42; | stack_filler[i] = 42; | ||
} | } | ||
- | printf("%s done\n", pthread_data->name); | + | /* dummy read of stack_filler[52] to prevent unused warning */ |
+ | printf("%s done %d\n", pthread_data->name, stack_filler[52]); | ||
} | } | ||
Line 194: | Line 202: | ||
int main(int argc, char *argv[]) | int main(int argc, char *argv[]) | ||
{ | { | ||
- | int lock_memory = 1; | + | const int page_size = sysconf(_SC_PAGESIZE); |
- | int i; | + | |
- | const int page_size = sysconf(_SC_PAGESIZE); | + | |
int page_faults_detected_in_thread1; | int page_faults_detected_in_thread1; | ||
int page_faults_detected_in_thread2; | int page_faults_detected_in_thread2; | ||
- | /* Thread data */ | + | int lock_memory = 1; |
+ | struct thread_data thread_data[2]; | ||
pthread_t thread_ids[2]; | pthread_t thread_ids[2]; | ||
- | struct thread_data thread_data[2]; | + | int i; |
/* Start a thread prior to locking memory. */ | /* Start a thread prior to locking memory. */ | ||
Line 209: | Line 216: | ||
thread_ids[0] = startThread(0, stack_size, check_stack_thread, | thread_ids[0] = startThread(0, stack_size, check_stack_thread, | ||
(void *)&thread_data[0]); | (void *)&thread_data[0]); | ||
+ | if (thread_ids[0] == -1) { | ||
+ | printf("Exiting - Unexpected failure while creating thread1\n"); | ||
+ | exit(-1); | ||
+ | } | ||
/* Give it 1 second to start */ | /* Give it 1 second to start */ | ||
sleep(1); | sleep(1); | ||
for (i = 1; i < argc; i++) { | for (i = 1; i < argc; i++) { | ||
- | if (strncmp(argv[i], "-nolockmem", 10) == 0) { | + | if (strncmp(argv[i], "-nolockmem", 10) == 0) |
lock_memory = 0; | lock_memory = 0; | ||
- | } | ||
} | } | ||
Line 222: | Line 232: | ||
printf("Current and future memory locked in RAM\n"); | printf("Current and future memory locked in RAM\n"); | ||
} | } | ||
- | /* printf something so we avoid introducing a page fault simply by | ||
- | performing the potentially first printf call. */ | ||
- | printf("Page size = %d\n", page_size); | ||
(void)dump_page_faults(); /* Set the baseline */ | (void)dump_page_faults(); /* Set the baseline */ | ||
- | /* From this point onwards we no longer expect to have any | + | /* |
- | page faults for currently allocated memory. */ | + | * From this point onwards we no longer expect to have any |
+ | * page faults for currently allocated memory. | ||
+ | */ | ||
/* Make the first thread fill the stack. */ | /* Make the first thread fill the stack. */ | ||
Line 244: | Line 253: | ||
"thread 1. This is expected.\n"); | "thread 1. This is expected.\n"); | ||
else | else | ||
- | printf ("After locking memory, new page faults have " \ | + | printf("After locking memory, new page faults have " \ |
"been generated during during stack access " \ | "been generated during during stack access " \ | ||
"of thread 1. This is unexpected!\n"); | "of thread 1. This is unexpected!\n"); | ||
} | } | ||
- | /* Thread 1 has not yet terminated, meaning that thread 2 will not | + | /* |
- | reuse the same (locked) stack region. */ | + | * Thread 1 has not yet terminated, meaning that thread 2 will not |
+ | * reuse the same (locked) stack region. | ||
+ | */ | ||
/* Start the second thread and make it fill the stack. */ | /* Start the second thread and make it fill the stack. */ | ||
Line 257: | Line 268: | ||
thread_ids[1] = startThread(0, stack_size, check_stack_thread, | thread_ids[1] = startThread(0, stack_size, check_stack_thread, | ||
(void *)&thread_data[1]); | (void *)&thread_data[1]); | ||
+ | if (thread_ids[1] == -1) { | ||
+ | printf("Exiting - Unexpected failure while creating thread2\n"); | ||
+ | exit(-1); | ||
+ | } | ||
/* Give it 1 second to start */ | /* Give it 1 second to start */ | ||
sleep(1); | sleep(1); | ||
Line 279: | Line 294: | ||
/* Check whether page faults have been detected. */ | /* Check whether page faults have been detected. */ | ||
int exit_code = 0; | int exit_code = 0; | ||
+ | |||
if ((page_faults_detected_in_thread1) || | if ((page_faults_detected_in_thread1) || | ||
(page_faults_detected_in_thread2)) { | (page_faults_detected_in_thread2)) { | ||
Line 293: | Line 309: | ||
return exit_code; | return exit_code; | ||
} | } | ||
+ | |||
</code> | </code> | ||