|
|
/*** ClearMem.C - Win 32 clear memory
* * * Title: * * ClearMem - Win 32 clear memory Main File * * Copyright (c) 1990-1994, Microsoft Corporation. * Russ Blake. * * * Description: * * This is the main part of the clear memory tool. * It takes as a parameter a file to use to flush the memory. * * Usage: clearmem filename [-q] [-d] * * filename: name of file to use to flush the * memory. Should be at least 128kb. * * * The Clear Memory is organized as follows: * * o ClearMem.c ........ Tools main body * o ClearMem.h * * o cmUtl.c ..... clear memory utility routines * o cmUtl.h * * * * * * * Modification History: * * 90.03.08 RussBl -- Created (copy of response probe) * 92.07.24 MarkLea -- Added -t -w -b switches * -- Modified AccessSection algorithm. * 93.05.12 HonWahChan * -- used total physical memory (instead of SECTION_SIZE); * -- used GetTickCount() instead of timer calls. * * */
char *VERSION = "1.17x (93.05.12)";
/* * * * * * * * * * * * * I N C L U D E F I L E S * * * * * * * * * * */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#include <time.h>
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h>
#include "clearmem.h"
#include "cmUtl.h"
/* * * * * * * * * * G L O B A L D E C L A R A T I O N S * * * * * * * * */ /* none */
/* * * * * * * * * * F U N C T I O N P R O T O T Y P E S * * * * * * * * */
__cdecl main (int argc, char *argv[]); STATIC RC Initialize (int argc, char *argv[]); STATIC RC Cleanup (void); STATIC RC FlushCache (void); STATIC RC AccessSection (void); STATIC RC ReadFlushFile (void); void ParseCmdLine (int argc, char *argv[]); void Usage (char *argv[], char *);
/* * * * * * * * * * * G L O B A L V A R I A B L E S * * * * * * * * * */ BOOL bQuiet, bRead = TRUE, bWrite; BOOL bDebugBreakOnEntry; ULONG ulMemSize, ulPageCount, ulTouchCount = 1;
ULONG_PTR ulSectionSize; /* * * * * * E X P O R T E D G L O B A L V A R I A B L E S * * * * * */ /* none */
/********************************* m a i n **********************************
* * main(argc, argv) * * ENTRY argc - number of input arguments * argv - contains command line arguments * * EXIT -none- * * RETURN rc - return code in case of failure * STATUS_SUCCESS - if successful * * WARNING: * -none- * * COMMENT: * -none- * */
__cdecl main (int argc, char *argv[]) { RC rc; DWORD ulFlushTime; // Total time for flushing
ParseCmdLine (argc, argv); if(ulMemSize){ ulSectionSize = ulMemSize * 1024 * 1024; } else { // get total physical memory size in the system
MEMORYSTATUS MemStat;
GlobalMemoryStatus (&MemStat); ulSectionSize = MemStat.dwTotalPhys; }
// ExitProcess(STATUS_SUCCESS);
if (bDebugBreakOnEntry) DebugBreak(); if (!bQuiet) { //
// set initial total flushing time
//
ulFlushTime = GetTickCount() ; }
//
// Do initialization
//
rc = Initialize(argc, argv); if (Failed(rc, __FILE__, __LINE__, "main() - Initialize")) { return(rc); }
//
// Now flush the cache
//
rc = FlushCache();
if (Failed(rc, __FILE__, __LINE__, "main() - FlushCache")) { return(rc); }
if (!bQuiet) { ulFlushTime = GetTickCount() - ulFlushTime; printf("Elapsed Time for Flushing: %lu milliseconds \n", ulFlushTime); } //
// Cleanup
//
rc = Cleanup(); if (Failed(rc, __FILE__, __LINE__, "main() - Cleanup")) { return(rc); }
#ifdef CF_DEBUG_L1
if (!bQuiet) { printf("| ==> Exiting PROCESS: %s \n", CF_EXE ); } #endif
if (bDebugBreakOnEntry) DebugBreak(); ExitProcess(STATUS_SUCCESS);
} /* main() */
/*************************** I n i t i a l i z e ****************************
* * Initialize(argc, argv) - * Performs basic initializations (getting input arguments, * creating semaphores, display debug info, ...) * * ENTRY argc - number of input arguments * argv - list of input arguments * * EXIT -none- * * RETURN rc - return code in case of failure * STATUS_SUCCESS - if successful * * WARNING: * -none- * * COMMENT: * -none- * */
STATIC RC Initialize (int argc, char *argv[]) { int i;
//
// Sign on message
//
if (!bQuiet) { printf("\nNT Win 32 Clear Memory.\n" "Copyright 1990-1993, Microsoft Corporation.\n" "Version %s\n\n", VERSION); }
#ifdef CF_DEBUG_L1
//
// Display debugging info
//
if (!bQuiet) { printf("/-------------------------------\n"); printf("| %s:\n", CF_EXE); printf("|\n"); for (i=0; i<argc; i++) { printf("| o argv[%i]=%s\n", i, argv[i]); } printf("\\-------------------------------\n"); } #else
i; // Prevent compiler from complaining about unreferenced variable
#endif
return(STATUS_SUCCESS);
} /* Initialize() */
/****************************** C l e a n u p *******************************
* * Cleanup(void) - * Basic cleanup. (closing semaphores, freeing memory, ...) * * ENTRY -none- * * EXIT -none- * * RETURN rc - return code in case of failure * STATUS_SUCCESS - if successful * * WARNING: * -none- * * COMMENT: * -none- * */
STATIC RC Cleanup (void) {
return(STATUS_SUCCESS);
} /* Cleanup() */
/************************ F l u s h C a c h e *****************************
* * FlushCache(void) - * Flushes the file cache by createing a large data * segment, and touching every page to shrink the cache * to 128kb, then reading in a 128kb file to clear the * remaining cache * * ENTRY -none- * * EXIT -none- * * RETURN rc - return code in case of failure * STATUS_SUCCESS - if successful * * WARNING: * -none- * * COMMENT: * -none- * */
RC FlushCache (void) {
RC rc;
//
// First touch all the data pages
//
#ifdef CF_DEBUG_L1
if (!bQuiet) { printf("| ==> Start Flushing: Access Section of size: %lu \n", ulSectionSize ); } #endif
rc = AccessSection(); if (Failed(rc, __FILE__, __LINE__, "FlushCache() - AccessSection")) { return(rc); }
//
// Next read the flushing file to what's left of the cache
//
#ifdef CF_DEBUG_L1
if (!bQuiet) { printf("| ==> Start Flushing: Read File: %s \n", "FLUSH1" ); } #endif
// while (ulTouchCount) {
rc = ReadFlushFile(); // --ulTouchCount;
if (Failed(rc, __FILE__, __LINE__, "FlushCache() - Read Flush File")) { return(rc); } // }
return(STATUS_SUCCESS);
} /* FlushCache() */
/************************ A c c e s s S e c t i o n ************************
* * AccessSection(void) - * Touches every page in the data section * * ENTRY -none- * * EXIT -none- * * RETURN rc - return code in case of failure * STATUS_SUCCESS - if successful * * WARNING: * -none- * * COMMENT: * -none- * */
RC AccessSection (void) {
RC rc; ULONG uli, ulj; PULONG puSectionData; //Points to data section for flushing memory
//
// Allocate virtual memory
//
if ( (puSectionData = (PULONG)VirtualAlloc(NULL, // New allocation
ulSectionSize, // Size in bytes
MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE)) == NULL ) { //Changed to READWRITE
rc = GetLastError(); Failed(rc, __FILE__, __LINE__, "AccessSection() - VirtualAlloc"); return(rc); }
//
// Now touch every page of the section
//
if(bWrite){ while (ulTouchCount) { puSectionData = &puSectionData[0]; for ( uli = 0; uli < (ulSectionSize-1); uli+=sizeof(ULONG)) { *puSectionData = 0xFFFFFFFF; ++puSectionData; } --ulTouchCount; } } if(bRead) { // DbgBreakPoint();
ulj = 0; while (ulTouchCount) { for ( uli = 0; uli < ulSectionSize; uli += PAGESIZE ) { ulj += *(puSectionData+(uli/sizeof(ULONG))); } --ulTouchCount; } }
return(STATUS_SUCCESS);
} /* AccessSection() */
/************************ R e a d F l u s h F i l e ************************
* * ReadFlushFile(void) - * Touches every page in the flush file, non-sequentially * * ENTRY -none- * * EXIT -none- * * RETURN rc - return code in case of failure * STATUS_SUCCESS - if successful * * WARNING: * -none- * * COMMENT: * -none- * */
CHAR chBuffer[PAGESIZE];
RC ReadFlushFile (void) { RC rc; SHORT sNewPos; ULONG uli; ULONG ulNumReads, ulNumBytesRead; BOOL bFileCreated; SHORT sFile; // Indicates which of the three
// files is being used to flush
CHAR chFlushFileName1[] = "FLUSH1"; CHAR chFlushFileName2[] = "FLUSH2"; CHAR chFlushFileName3[] = "FLUSH3";
CHAR *pchFlushFileName[3] = { chFlushFileName1, chFlushFileName2, chFlushFileName3 }; FILE *pfFlushFile; // Points to the file used for
// flushing the cache
FILE *pfSaveFile[3]; // Remembers them for the close
CHAR achErrMsg[LINE_LEN];
//
// Assume no file is created: all three already exist
//
bFileCreated = FALSE;
for (sFile = 0; sFile < NUM_FILES; sFile++) {
//
// First attempt to create the file
//
if ( (pfFlushFile = CreateFile(pchFlushFileName[sFile], GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_NEW, 0, 0)) == INVALID_HANDLE_VALUE ) {
//
// Could not create the file
//
rc = GetLastError();
if (!(rc == ERROR_FILE_EXISTS || rc == ERROR_ACCESS_DENIED)) {
//
// Cannot create a new file
//
sprintf(achErrMsg, "ReadFlushFile() - Error creating %s: %lu", pchFlushFileName[sFile], rc); Failed(FILEARG_ERR, __FILE__, __LINE__, achErrMsg); return(FILEARG_ERR); } } else {
//
// New file has been created without difficulty
// Fill it with data
//
bFileCreated = TRUE;
for (uli = 0; uli < FLUSH_FILE_SIZE; uli += PAGESIZE) { if (!WriteFile(pfFlushFile, &chBuffer, PAGESIZE, &ulNumBytesRead, RESERVED_NULL)) { rc = GetLastError(); Failed(rc, __FILE__, __LINE__, "ReadFlushFile() - Write File Record to New File"); return(rc); } }
//
// Now close it for write, so we can open it for read access
//
if (!CloseHandle(pfFlushFile)) { rc = GetLastError(); sprintf(achErrMsg, "ReadFlushFile() - Error closing %s: %lu", pchFlushFileName[sFile], rc); Failed(FILEARG_ERR, __FILE__, __LINE__, achErrMsg); return(FILEARG_ERR); } } }
if (bFileCreated) {
//
// Wrote at least 1 file: wait for lazy writer to flush
// data to disk
//
Sleep(LAZY_DELAY);
}
for (sFile = 0; sFile < NUM_FILES; sFile++) {
if ((pfFlushFile = CreateFile( pchFlushFileName[sFile], GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE) {
//
// Cannot open an existing file
//
rc = GetLastError(); sprintf(achErrMsg, "ReadFlushFile() - Error opening %s: %lu", pchFlushFileName[sFile], rc); Failed(FILEARG_ERR, __FILE__, __LINE__, achErrMsg); return(FILEARG_ERR); }
//
// Remember the handle for the close
//
pfSaveFile[sFile] = pfFlushFile;
//
// Read first record
//
if (!ReadFile( pfFlushFile, &chBuffer, 1, &ulNumBytesRead, RESERVED_NULL)) { rc = GetLastError(); Failed(rc, __FILE__, __LINE__, "ReadFlushFile() - Read First Record"); return(rc); }
ulNumReads = 1;
while (++ulNumReads <= ulPageCount) { if (ulNumReads & 1) {
//
// Read an odd record: read previous record
// Move backward to start of prior record: -1 (start of
// this record) -4096 (start of previous record) = -4097
//
if (SetFilePointer( pfFlushFile, -4097, 0L, FILE_CURRENT) == (DWORD)-1) { rc = GetLastError(); Failed(rc, __FILE__, __LINE__, "ReadFlushFile() - Read Odd Record"); return(rc); }
if (!ReadFile( pfFlushFile, &chBuffer, 1, &ulNumBytesRead, RESERVED_NULL)) { rc = GetLastError(); if (rc == ERROR_HANDLE_EOF) break; Failed(rc, __FILE__, __LINE__, "ReadFlushFile() - SetPos Odd Record"); return(rc); } } else {
//
// Read an even record: read the one after the next record
// Move forward to end of this record (4095) + 2 more
// (8192) = 12287. (But second record is special, 'cause
// can't set file pointer negative initially.)
//
sNewPos = (SHORT) (ulNumReads == 2L ? 8191 : 12287);
if (SetFilePointer( pfFlushFile, sNewPos, 0L, FILE_CURRENT) == (DWORD) -1) { rc = GetLastError(); Failed(rc, __FILE__, __LINE__, "ReadFlushFile() - Read Even Record"); return(rc); }
if (!ReadFile( pfFlushFile, &chBuffer, 1, &ulNumBytesRead, RESERVED_NULL)) { rc = GetLastError(); if (rc == ERROR_HANDLE_EOF) break; Failed(rc, __FILE__, __LINE__, "ReadFlushFile() - SetPos Even Record"); return(rc); } } } }
for (sFile = 0; sFile < NUM_FILES; sFile++) {
//
// Close the files
//
if (!CloseHandle(pfSaveFile[sFile])) { rc = GetLastError(); sprintf(achErrMsg, "ReadFlushFile() - Error closing %s: %lu", pchFlushFileName[sFile], rc); Failed(FILEARG_ERR, __FILE__, __LINE__, achErrMsg); return(FILEARG_ERR); } }
return(STATUS_SUCCESS);
} /* ReadFlushFile() */
/************************ R e a d F l u s h F i l e ************************
* * parseCmdLine(void) - * For Parsing the command line switches * * ENTRY -none- * * EXIT -none- * * RETURN -none- * * WARNING: * -none- * * COMMENT: * -none- * */
VOID ParseCmdLine (int argc, char *argv[]) { char *pchParam; int iParamCount;
for ( iParamCount = 1; iParamCount < argc; iParamCount++) {
if (argv[iParamCount][0] == '-') { /* process options */
pchParam = &(argv[iParamCount][1]);
while (*pchParam) { switch (*pchParam) { case '?': Usage (argv, " "); break;
case 'Q': case 'q': pchParam++; bQuiet = TRUE; break;
case 'd': case 'D': /* print banner */ pchParam++; bDebugBreakOnEntry = TRUE; break;
case 'm': case 'M': ulMemSize = (ULONG)atol(&pchParam[1]); if (ulPageCount > 32) { Usage (argv, "Mem size must be less than the amount of physical memory!"); } pchParam += strlen(pchParam); break;
case 'p': case 'P': ulPageCount = (ULONG)atol(&pchParam[1]); if (ulPageCount > 63) { Usage (argv, "Page Count must be 63 or less!"); } pchParam += strlen(pchParam); break;
case 't': case 'T': ulTouchCount = (ULONG)atol(&pchParam[1]); pchParam += strlen(pchParam); break;
case 'w': case 'W': bWrite = TRUE; bRead = FALSE; break;
case 'b': case 'B': bRead = TRUE; bWrite = TRUE; break;
default: Usage (argv, "unknown flag"); break;
} // end of switch
} // end of while
} // end of if
} // end of for...
if(!ulPageCount){ ulPageCount = NUM_FLUSH_READS; } return; }
/*
* * Usage - generates a usage message and an error message * and terminates program. * * Accepts - argv - char *[] * message - char * - an error message * * Returns - nothing. * */
VOID Usage (char *argv[], char *message) {
printf( "%s\n", message); printf( "usage: "); printf( "%s [-q] [-d] [-mx] [-px] [-w] [-tx]\n", argv[0]); printf( "\t-? : This message\n"); printf( "\t-q : Quiet mode - Nothing printed.\n"); printf( "\t-d : Debug break on Entry into and Exit from app.\n"); printf( "\t-m : Number of megabytes to allocate.\n"); printf( "\t : (default is to use all physical memory.)\n"); printf( "\t-p : Number of pages to read (must be less than 63).\n"); printf( "\t-w : Write to the virtual memory section.\n"); printf( "\t-b : Read and Write the virtual memory section.\n"); printf( "\t-t : Times to touch a page.\n"); printf( "**DEFAULT: clearmem -p63 -t1\n"); exit (1); }
|