Verifying the absence of page faults in global arrays proof

From RTwiki
Revision as of 09:05, 15 January 2008 by Remy (Talk | contribs)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

Verifying the absence of page faults in global arrays proof

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)

   // This application checks whether mlockall() forces all pages of a
   // 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
   // the first write results in a page fault so a physical page of RAM is
   // mapped to it (and initialised to zero before the write occurs).
   
   #include <stdio.h>
   #include <string.h>
   #include <unistd.h>
   #include <sys/mman.h>
   #include <sys/resource.h>
   
   // Lock the application in memory to avoid page faults
   static void lockApplication(void)
   {
   	if (mlockall(MCL_CURRENT | MCL_FUTURE) != 0 )
   	{
   	    perror( "mlockall() failed" );
   	}
   }
   
   // Dump minor and major page faults that occurred since the previous call
   static bool dumpPageFaults(void)
   {
   	bool l_PageFaultsDetected = false;
   	static bool ls_Init = false;
   	static struct rusage ls_RusagePrevious;
   	struct rusage l_Rusage;
   
   	getrusage(RUSAGE_SELF, &l_Rusage);
   	int a_NewMinorPageFaults = l_Rusage.ru_minflt - ls_RusagePrevious.ru_minflt;
   	int a_NewMajorPageFaults = l_Rusage.ru_majflt - ls_RusagePrevious.ru_majflt;
   	ls_RusagePrevious.ru_minflt = l_Rusage.ru_minflt;
   	ls_RusagePrevious.ru_majflt = l_Rusage.ru_majflt;
   
   	if (ls_Init)
   	{
   		if ((a_NewMinorPageFaults > 0) || (a_NewMajorPageFaults > 0))
   		{
   			printf ("New minor/major page faults: %d/%d\n",
   				a_NewMinorPageFaults,
   				a_NewMajorPageFaults);
   			l_PageFaultsDetected = true;
   		}
   	}
   	ls_Init = true;
   	return l_PageFaultsDetected;
   }
   
   // 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[])
   {
   	bool l_LockMemory = true;
   	int i;
   	for (i=1; i<argc; i++)
   	{
   		if (strncmp (argv[i], "-nolockmem", 10) == 0)
   		{
   			// Results in many page faults!
   			l_LockMemory = false;
   		}
   	}
   
   	if (l_LockMemory)
   	{
   		lockApplication();
   		printf ("Current and future memory locked in RAM\n");
   	}
   	(void)dumpPageFaults(); // Set the baseline
   
   	// printf something so we avoid introducing a page fault simply by performing
   	// the potentially first printf call.
   	const int l_PageSize = sysconf(_SC_PAGESIZE);
   	printf ("Page size = %d\n", l_PageSize);
   	
   	(void)dumpPageFaults();
   
   	// From this point onwards we no longer expect to have any page faults.
   	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())
   		{
   			l_UnexpectedPageFaultsDetected = true;
   		}
   		gs_Buffer[(i*gs_PageSize)+1] = 1;
   		if (dumpPageFaults())
   		{
   			printf ("Writing to page %d of static buffer caused page fault(s)\n", i);
   			l_UnexpectedPageFaultsDetected = true;
   		}
   	}
   
   	printf ("Done, result: %s\n",
   		l_UnexpectedPageFaultsDetected ? "failed":"success");
   	return (l_UnexpectedPageFaultsDetected ? 1:0);
   }


Authors

Alex van der Wal

Personal tools