This shows you the differences between two versions of the page.
Both sides previous revision Previous revision Next revision | Previous revision | ||
realtime:documentation:howto:applications:memory:mlockall_globals_sample [2017/06/08 17:24] jithu modified comment style - this code Alex van der Wal's from RT wiki |
realtime:documentation:howto:applications:memory:mlockall_globals_sample [2017/06/10 00:28] (current) jithu |
||
---|---|---|---|
Line 1: | Line 1: | ||
====== Sample to verify the effect of mlockall() on globals ====== | ====== Sample to verify the effect of mlockall() on globals ====== | ||
- | Global variables and arrays are not part of the binary, but are allocated by the OS at process startup. The virtual memory pages associated to this data is not immediately mapped to physical pages of RAM, meaning that page faults occur on access. It turns out that the mlockall() call forces all global variables and arrays into RAM, meaning that subsequent access to this memory does not result in page faults. As such, using global variables and arrays does not introduce any additional problems for real time applications. You can verify this behavior using the following program (run as 'root' to allow the mlockall() operation) | + | Global variables and arrays are not part of the binary, but are allocated by the OS at application startup. The virtual memory pages associated to this data is not immediately mapped to physical pages of RAM, meaning that page faults occur on access. It turns out that the mlockall() call forces all global variables and arrays into RAM, meaning that subsequent access to this memory does not result in page faults. As such, using global variables and arrays does not introduce any additional problems for real time applications. You can verify this behavior using the following program (run as 'root' to allow the mlockall() operation) |
<code c> | <code c> | ||
- | /* This application checks whether mlockall() forces all pages of a | + | /* |
+ | * # gcc -o check_global check_global.c -Wall -O3 | ||
+ | * # ./check_global | ||
+ | * # ./check_global -nolockmem (will cause faults) | ||
+ | * This application checks whether mlockall() forces all pages of a | ||
* global array into RAM. Normally, the OS maps a 'copy on write' MMU page | * global array into RAM. Normally, the OS maps a 'copy on write' MMU page | ||
* to such arrays meaning that reading from the array returns only zeros and | * to such arrays meaning that reading from the array returns only zeros and | ||
Line 10: | Line 14: | ||
*/ | */ | ||
#include <stdio.h> | #include <stdio.h> | ||
+ | #include <stdlib.h> | ||
#include <string.h> | #include <string.h> | ||
- | #include <unistd.h> | ||
#include <sys/mman.h> | #include <sys/mman.h> | ||
#include <sys/resource.h> | #include <sys/resource.h> | ||
- | + | #include <unistd.h> | |
+ | |||
+ | /* Define the global array*/ | ||
+ | #define NUM_PAGES 5000 | ||
+ | #define PAGE_SZ (1024 * 4) /* Assume 4kb pages*/ | ||
+ | char glob_buffer[NUM_PAGES * PAGE_SZ]; | ||
/* Lock the application in memory to avoid page faults*/ | /* Lock the application in memory to avoid page faults*/ | ||
- | static void lockApplication(void) | + | static void lock_application(void) |
{ | { | ||
- | if (mlockall(MCL_CURRENT | MCL_FUTURE) != 0 ) | + | if (mlockall(MCL_CURRENT | MCL_FUTURE) != 0) { |
- | { | + | perror("mlockall() failed - root ?"); |
- | perror( "mlockall() failed" ); | + | exit(-1); |
} | } | ||
} | } | ||
- | + | ||
- | /* Dump minor and major page faults that occurred since the previous call*/ | + | /* Dump minor and major page faults that occurred since the previous call */ |
- | static bool dumpPageFaults(void) | + | static int dump_page_faults(void) |
{ | { | ||
- | bool l_PageFaultsDetected = false; | + | int new_minor_page_faults, new_major_page_faults; |
- | static bool ls_Init = false; | + | int page_faults_detected = 0; |
- | static struct rusage ls_RusagePrevious; | + | static struct rusage rusage_prev; |
- | struct rusage l_Rusage; | + | static int init; |
- | + | struct rusage rusage; | |
- | getrusage(RUSAGE_SELF, &l_Rusage); | + | |
- | int a_NewMinorPageFaults = l_Rusage.ru_minflt - ls_RusagePrevious.ru_minflt; | + | getrusage(RUSAGE_SELF, &rusage); |
- | int a_NewMajorPageFaults = l_Rusage.ru_majflt - ls_RusagePrevious.ru_majflt; | + | new_minor_page_faults = rusage.ru_minflt - rusage_prev.ru_minflt; |
- | ls_RusagePrevious.ru_minflt = l_Rusage.ru_minflt; | + | new_major_page_faults = rusage.ru_majflt - rusage_prev.ru_majflt; |
- | ls_RusagePrevious.ru_majflt = l_Rusage.ru_majflt; | + | rusage_prev.ru_minflt = rusage.ru_minflt; |
- | + | rusage_prev.ru_majflt = rusage.ru_majflt; | |
- | if (ls_Init) | + | |
- | { | + | if (init) { |
- | if ((a_NewMinorPageFaults > 0) || (a_NewMajorPageFaults > 0)) | + | if ((new_minor_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", |
- | a_NewMinorPageFaults, | + | new_minor_page_faults, new_major_page_faults); |
- | a_NewMajorPageFaults); | + | page_faults_detected = 1; |
- | l_PageFaultsDetected = true; | + | |
} | } | ||
} | } | ||
- | ls_Init = true; | + | init = 1; |
- | return l_PageFaultsDetected; | + | return page_faults_detected; |
} | } | ||
- | + | ||
- | /* Define the global array*/ | + | |
- | const static int gs_BufferPages = 5000; | + | |
- | const static int gs_PageSize = 1024*4; /* Assume 4kb pages*/ | + | |
- | static char gs_Buffer[gs_BufferPages*gs_PageSize]; | + | |
- | + | ||
int main(int argc, char *argv[]) | int main(int argc, char *argv[]) | ||
{ | { | ||
- | bool l_LockMemory = true; | + | int unexpected_pagefaults_detected; |
+ | int lock_memory = 1; | ||
+ | int buff_value; | ||
int i; | int i; | ||
- | 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) { |
- | { | + | |
/* Results in many page faults! */ | /* Results in many page faults! */ | ||
- | l_LockMemory = false; | + | lock_memory = 0; |
} | } | ||
} | } | ||
- | + | ||
- | if (l_LockMemory) | + | if (lock_memory) { |
- | { | + | lock_application(); |
- | lockApplication(); | + | printf("Current and future memory locked in RAM\n"); |
- | printf ("Current and future memory locked in RAM\n"); | + | |
} | } | ||
- | (void)dumpPageFaults(); /* Set the baseline*/ | + | (void)dump_page_faults(); /* Set the baseline*/ |
- | + | ||
- | /* printf something so we avoid introducing a page fault simply by performing | + | /* From this point onwards we no longer expect any page faults */ |
- | * the potentially first printf call. | + | unexpected_pagefaults_detected = 0; |
- | */ | + | |
- | const int l_PageSize = sysconf(_SC_PAGESIZE); | + | for (i = 0; i < NUM_PAGES; i++) { |
- | printf ("Page size = %d\n", l_PageSize); | + | buff_value = (int) (glob_buffer[i * PAGE_SZ]); |
- | + | ||
- | (void)dumpPageFaults(); | + | if (buff_value != 0) { |
- | + | printf("Reading unexpected value %d on page %d of global buffer.\n", | |
- | /* From this point onwards we no longer expect to have any page faults.*/ | + | buff_value, i); |
- | bool l_UnexpectedPageFaultsDetected = false; | + | |
- | for (i=0; i<gs_BufferPages; i++) | + | |
- | { | + | |
- | int l_Value = static_cast<int>(gs_Buffer[i*gs_PageSize]); | + | |
- | if (l_Value != 0) | + | |
- | { | + | |
- | printf ("Reading unexpected value %d on page %d of static buffer.\n", | + | |
- | l_Value, | + | |
- | i); | + | |
} | } | ||
- | if (dumpPageFaults()) | + | if (dump_page_faults()) |
- | { | + | unexpected_pagefaults_detected = 1; |
- | l_UnexpectedPageFaultsDetected = true; | + | |
- | } | + | glob_buffer[(i * PAGE_SZ) + 1] = 1; |
- | gs_Buffer[(i*gs_PageSize)+1] = 1; | + | if (dump_page_faults()) { |
- | if (dumpPageFaults()) | + | printf("Writing to page %d of global buffer caused page fault(s)\n", |
- | { | + | i); |
- | printf ("Writing to page %d of static buffer caused page fault(s)\n", i); | + | unexpected_pagefaults_detected = 1; |
- | l_UnexpectedPageFaultsDetected = true; | + | |
} | } | ||
} | } | ||
- | + | ||
- | printf ("Done, result: %s\n", | + | printf("Done, result: %s\n", |
- | l_UnexpectedPageFaultsDetected ? "failed":"success"); | + | unexpected_pagefaults_detected ? "failed" : "success"); |
- | return (l_UnexpectedPageFaultsDetected ? 1:0); | + | return unexpected_pagefaults_detected ? 1 : 0; |
} | } | ||
</code> | </code> |