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> | ||