// diskspeed.c, Copyright Alexander Grigoriev, alegr@aha.ru // measures disk read/write speed in cached and direct modes // and CPU load percent. #include #include #include static volatile BOOL bRunSecondThread = TRUE; static volatile long nCounter = 0; static long nCyclesPerSecond = 0; char * GetBuffer(size_t size, BOOL bPageAligned) { if ( ! bPageAligned) { return new char[size + 8]; } else { char * buf = (char*)VirtualAlloc(NULL, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); return buf; } } void FreeBuffer(void * buf, BOOL bPageAligned) { if ( ! bPageAligned) { delete [] (char*) buf; } else { VirtualFree(buf, 0, MEM_DECOMMIT | MEM_RELEASE); } } BOOL MeasureWrite(LPCTSTR szFilename, __int64 size, BOOL bCached) { DWORD AuxFlag = 0; if ( ! bCached) AuxFlag = FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH; HANDLE hFile = CreateFile(szFilename, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN | AuxFlag, NULL); if (INVALID_HANDLE_VALUE == hFile) { return FALSE; } int BufferSize = 1024 * 1024; // 1 MB if ( ! bCached) BufferSize = 46 * 1024; // 64 kB char * buf = GetBuffer(BufferSize, ! bCached); if (NULL == buf) { CloseHandle(hFile); return FALSE; } char * pAlignedBuf = (char *) ((int(buf) + 7) & ~7); // fill the buffer for (int i = 0; i < BufferSize; i++) { pAlignedBuf[i] = char(rand()); } long nBeginTime = GetTickCount(); unsigned long nBeginCount = nCounter; for (__int64 position = 0; position < size;) { DWORD dwWritten; if ( ! WriteFile(hFile, pAlignedBuf, BufferSize, & dwWritten, NULL)) { fprintf(stderr, "Error Writing File\n"); FreeBuffer(buf, ! bCached); CloseHandle(hFile); return FALSE; } if (0 == dwWritten) break; position += dwWritten; } FlushFileBuffers(hFile); unsigned long nElapsedCount = nCounter - nBeginCount; long nElapsedTime = GetTickCount() - nBeginTime; double fSpeed = double(position) / nElapsedTime * 1000.; double fPercentage = 100. * (1. - double(nElapsedCount) / double(nElapsedTime) * 1000. / nCyclesPerSecond); printf("Data Transfer:%6.2f MB/s, CPU Load: %4.1f%%\n", fSpeed / (1024 * 1024) + 0.005, fPercentage); FreeBuffer(buf, ! bCached); CloseHandle(hFile); return TRUE; } BOOL MeasureRead(LPCTSTR szFilename, __int64 size, BOOL bCached) { DWORD AuxFlag = 0; if ( ! bCached) AuxFlag = FILE_FLAG_NO_BUFFERING; HANDLE hFile = CreateFile(szFilename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN | AuxFlag, NULL); if (INVALID_HANDLE_VALUE == hFile) { return FALSE; } int BufferSize = 1024 * 1024; // 1 MB if ( ! bCached) BufferSize = 0x10000; // 64 kB char * buf = GetBuffer(BufferSize, ! bCached); if (NULL == buf) { CloseHandle(hFile); return FALSE; } char * pAlignedBuf = (char *) ((int(buf) + 7) & ~7); long nBeginTime = GetTickCount(); unsigned long nBeginCount = nCounter; for (__int64 position = 0; position < size;) { DWORD dwRead; if ( ! ReadFile(hFile, pAlignedBuf, BufferSize, & dwRead, NULL)) { fprintf(stderr, "Error Reading File\n"); FreeBuffer(buf, ! bCached); CloseHandle(hFile); return FALSE; } if (0 == dwRead) break; position += dwRead; } unsigned long nElapsedCount = nCounter - nBeginCount; long nElapsedTime = GetTickCount() - nBeginTime; double fSpeed = double(position) / nElapsedTime * 1000.; double fPercentage = 100. * (1. - double(nElapsedCount) / double(nElapsedTime) * 1000. / nCyclesPerSecond); printf("Data Transfer:%6.2f MB/s, CPU Load: %4.1f%%\n", fSpeed / (1024 * 1024) + 0.005, fPercentage); FreeBuffer(buf, ! bCached); CloseHandle(hFile); return TRUE; } // the counter should not overflow for 1000 seconds on 200 MHz // that is, every round should take at least 50 clocks unsigned int __stdcall IdleThreadProc(void *) { SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_IDLE); while (bRunSecondThread) { __asm { inc eax inc eax inc eax inc eax inc eax inc eax inc eax inc eax inc eax inc eax inc eax inc eax inc eax inc eax inc eax inc eax inc eax inc eax inc eax inc eax inc eax inc eax inc eax inc eax inc eax inc eax inc eax inc eax inc eax inc eax inc eax inc eax inc eax inc eax inc eax inc eax inc eax inc eax inc eax inc eax inc eax inc eax inc eax inc eax inc eax inc eax inc eax inc eax } nCounter++; } return 0; } int main(int argc, char * argv[]) { printf("DISKSPEED (C) Alexander Grigoriev, alegr@aha.ru\n"); __int64 nFileSize = 64 * 1024 * 1024; char filename[MAX_PATH + 1]; // Get File name const char * szFilename = "c:\\$$test$$.tst"; // argv[1] - file size in MB, argv[2] = path if (argc >= 3) { if (argv[2][0] != 0) { strncpy(filename, argv[2], MAX_PATH + 1 - sizeof "\\$$test$$.tst"); filename[MAX_PATH + 1 - sizeof "\\$$test$$.tst"] = 0; int len = strlen(filename); if ('\\' == filename[len-1]) filename[len-1] = 0; if (0 == (FILE_ATTRIBUTE_DIRECTORY & GetFileAttributes(filename))) { fprintf (stderr, "Test file path \"%s\"not found\n", filename); return 255; } strcat(filename, "\\$$test$$.tst"); szFilename = filename; } } printf( "Test File: \"%s\"\n", szFilename); if (argc >= 2) { char * endptr; unsigned long nMbInFile = strtol(argv[1], & endptr, 10); if (0 == *endptr && nMbInFile > 0 && nMbInFile) { nFileSize = __int64(nMbInFile) * (1024 * 1024); } } printf("Test File Size: %d MB\n", int(nFileSize >> 20)); // Get Free Space //GetFree // get desired file size // start secondary (idle) thread unsigned uThreadId; HANDLE hThread = (HANDLE) _beginthreadex(NULL, 0, IdleThreadProc, NULL, 0, & uThreadId); // calibrate processor performance Sleep(500); long nBegin, nEnd; long nBeginTime; do { nBeginTime = GetTickCount(); nBegin = nCounter; Sleep(2000); nEnd = nCounter; } while (GetTickCount() - nBeginTime < 2000); nCyclesPerSecond = unsigned(nCounter - nBegin) / 2; HANDLE hFile = CreateFile(szFilename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (INVALID_HANDLE_VALUE == hFile) { fprintf(stderr, "Unable To Create Test File \"%s\"\n", szFilename); return 255; } CloseHandle(hFile); // printf( "Testing Uncached New File Write Speed....\n"); MeasureWrite(szFilename, nFileSize, FALSE); // fill the file printf( "Testing Uncached Write Speed....\n"); MeasureWrite(szFilename, nFileSize, FALSE); // fill the file printf( "Testing Uncached Read Speed....\n"); MeasureRead(szFilename, nFileSize, FALSE); // read the file in cached mode printf( "Testing Cached Write Speed....\n"); MeasureWrite(szFilename, nFileSize, TRUE); // fill the file in direct mode printf( "Testing Cached Read Speed....\n"); MeasureRead(szFilename, nFileSize, TRUE); // read the file in direct mode // terminate the thread bRunSecondThread = FALSE; WaitForSingleObject(hThread, 1000); CloseHandle(hThread); DeleteFile(szFilename); return 0; }