/*++ Copyright (c) 2000 Microsoft Corporation Module Name: pfapp.c Abstract: This module builds a console test program that can be launched to test/stress the application launch prefetcher. The quality of the code for the test programs is as such. Author: Cenk Ergan (cenke) Environment: User Mode --*/ #include #include #include #include #include #include #include DWORD PfAppGetViewOfFile( IN WCHAR *FilePath, OUT PVOID *BasePointer, OUT PULONG FileSize ) /*++ Routine Description: Map the all of the specified file to memory. Arguments: FilePath - NUL terminated path to file to map. BasePointer - Start address of mapping will be returned here. FileSize - Size of the mapping/file will be returned here. Return Value: Win32 error code. --*/ { HANDLE InputHandle; HANDLE InputMappingHandle; DWORD ErrorCode; DWORD SizeL; DWORD SizeH; BOOLEAN OpenedFile; BOOLEAN CreatedFileMapping; // // Initialize locals. // OpenedFile = FALSE; CreatedFileMapping = FALSE; // // Note that we are opening the file exclusively. This guarantees // that for trace files as long as the kernel is not done writing // it we can't open the file, which guarantees we won't have an // incomplete file to worry about. // InputHandle = CreateFile(FilePath, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_SHARE_READ, NULL); if (INVALID_HANDLE_VALUE == InputHandle) { ErrorCode = GetLastError(); goto cleanup; } OpenedFile = TRUE; SizeL = GetFileSize(InputHandle, &SizeH); if (SizeL == -1 && (GetLastError() != NO_ERROR )) { ErrorCode = GetLastError(); goto cleanup; } if (SizeH) { ErrorCode = ERROR_BAD_LENGTH; goto cleanup; } if (FileSize) { *FileSize = SizeL; } InputMappingHandle = CreateFileMapping(InputHandle, 0, PAGE_READONLY, 0, 0, NULL); if (NULL == InputMappingHandle) { ErrorCode = GetLastError(); goto cleanup; } CreatedFileMapping = TRUE; *BasePointer = MapViewOfFile(InputMappingHandle, FILE_MAP_READ, 0, 0, 0); if (NULL == *BasePointer) { ErrorCode = GetLastError(); goto cleanup; } ErrorCode = ERROR_SUCCESS; cleanup: if (OpenedFile) { CloseHandle(InputHandle); } if (CreatedFileMapping) { CloseHandle(InputMappingHandle); } return ErrorCode; } PWCHAR PfAppAnsiToUnicode( PCHAR str ) /*++ Routine Description: This routine converts an ANSI string into an allocated wide character string. The returned string should be freed by free(). Arguments: str - Pointer to string to convert. Return Value: Allocated wide character string or NULL if there is a failure. --*/ { ULONG len; wchar_t *retstr = NULL; len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0); retstr = (wchar_t *)malloc(len * sizeof(wchar_t)); if (!retstr) { return NULL; } MultiByteToWideChar(CP_ACP, 0, str, -1, retstr, len); return retstr; } // // This does not have to be the actual page size on the platform. It is the // granularity with which we will make accesses. // #define MY_PAGE_SIZE 4096 #define PFAPP_MAX_DATA_PAGES 256 char Data[PFAPP_MAX_DATA_PAGES * MY_PAGE_SIZE] = {1}; #define PFAPP_MAX_FUNCS 16 #pragma code_seg("func0") DWORD func0(VOID) {return ERROR_SUCCESS;}; #pragma code_seg("func1") DWORD func1(VOID) {return ERROR_SUCCESS;}; #pragma code_seg("func2") DWORD func2(VOID) {return ERROR_SUCCESS;}; #pragma code_seg("func3") DWORD func3(VOID) {return ERROR_SUCCESS;}; #pragma code_seg("func4") DWORD func4(VOID) {return ERROR_SUCCESS;}; #pragma code_seg("func5") DWORD func5(VOID) {return ERROR_SUCCESS;}; #pragma code_seg("func6") DWORD func6(VOID) {return ERROR_SUCCESS;}; #pragma code_seg("func7") DWORD func7(VOID) {return ERROR_SUCCESS;}; #pragma code_seg("func8") DWORD func8(VOID) {return ERROR_SUCCESS;}; #pragma code_seg("func9") DWORD func9(VOID) {return ERROR_SUCCESS;}; #pragma code_seg("func10") DWORD func10(VOID) {return ERROR_SUCCESS;}; #pragma code_seg("func11") DWORD func11(VOID) {return ERROR_SUCCESS;}; #pragma code_seg("func12") DWORD func12(VOID) {return ERROR_SUCCESS;}; #pragma code_seg("func13") DWORD func13(VOID) {return ERROR_SUCCESS;}; #pragma code_seg("func14") DWORD func14(VOID) {return ERROR_SUCCESS;}; #pragma code_seg("func15") DWORD func15(VOID) {return ERROR_SUCCESS;}; #pragma code_seg() char *PfAppUsage = "pfapp.exe -data datafile\n"; INT __cdecl main( INT argc, PCHAR argv[] ) { WCHAR *CommandLine; WCHAR *Argument; WCHAR *DataFile; PCHAR BasePointer; DWORD FileSize; DWORD FileSizeInMyPages; DWORD ErrorCode; DWORD FuncNo; DWORD NumCalls; DWORD CallIdx; DWORD DataPage; DWORD NumDataAccesses; DWORD DataAccessIdx; DWORD Sum; // // Initialize locals. // CommandLine = GetCommandLine(); DataFile = NULL; BasePointer = NULL; // // Initialize random generator. // srand((unsigned)time(NULL)); // // Check arguments. // if (argc != 3) { printf(PfAppUsage); ErrorCode = ERROR_INVALID_PARAMETER; goto cleanup; } // // Call functions. Each one is on a different page. Basing the number of calls // we will make on number of functions/pages we have leads to more interesting // access patterns and prefetch policy decisions. // NumCalls = rand() % PFAPP_MAX_FUNCS; NumCalls += PFAPP_MAX_FUNCS / 4; for (CallIdx = 0; CallIdx < NumCalls; CallIdx++) { FuncNo = rand() % PFAPP_MAX_FUNCS; switch(FuncNo) { case 0: func0(); break; case 1: func1(); break; case 2: func2(); break; case 3: func3(); break; case 4: func4(); break; case 5: func5(); break; case 6: func6(); break; case 7: func7(); break; case 8: func8(); break; case 9: func9(); break; case 10: func10(); break; case 11: func11(); break; case 12: func12(); break; case 13: func13(); break; case 14: func14(); break; case 15: func15(); break; default: break; } } // // Access pages in the data section. Basing the number of accesses // we will make on number of pages we have adds more regularity to our // accesses so they survive sensitivity based prefetch policy decisions. // NumDataAccesses = rand() % PFAPP_MAX_DATA_PAGES; NumDataAccesses += PFAPP_MAX_DATA_PAGES / 4; Sum = 0; for (DataAccessIdx = 0; DataAccessIdx < NumDataAccesses; DataAccessIdx++) { DataPage = rand() % PFAPP_MAX_DATA_PAGES; Sum += Data[DataPage * MY_PAGE_SIZE]; } printf("Bogus sum1 is %d\n", Sum); // // Map the executable as data. // DataFile = PfAppAnsiToUnicode(argv[2]); if (!DataFile) { ErrorCode = ERROR_NOT_ENOUGH_MEMORY; goto cleanup; } ErrorCode = PfAppGetViewOfFile(DataFile, &BasePointer, &FileSize); if (ErrorCode != ERROR_SUCCESS) { printf("Could not map data file: %x\n", ErrorCode); goto cleanup; } FileSizeInMyPages = FileSize / MY_PAGE_SIZE; // // Touch the pages of the executable as data pages. // NumDataAccesses = rand() % FileSizeInMyPages; NumDataAccesses += FileSizeInMyPages / 4; Sum = 0; for (DataAccessIdx = 0; DataAccessIdx < NumDataAccesses; DataAccessIdx++) { DataPage = rand() % FileSizeInMyPages; Sum += BasePointer[DataPage * MY_PAGE_SIZE]; } printf("Bogus sum2 is %d\n", Sum); ErrorCode = ERROR_SUCCESS; cleanup: if (DataFile) { free(DataFile); } if (BasePointer) { UnmapViewOfFile(BasePointer); } return ErrorCode; }