#include "mhlsrvp.h" int _CRTAPI1 main( int argc, char *argv[], char *envp[] ) { char chChar, *pchChar; DWORD tc, lc; INT i; BOOL b; int WriteCount; // // try to get timing more accurate... Avoid context // switch that could occur when threads are released // SetThreadPriority(GetCurrentThread(),THREAD_PRIORITY_TIME_CRITICAL); // // Figure out how many processors we have to size the minimum // number of worker threads and concurrency // GetSystemInfo(&SystemInfo); fVerbose = FALSE; dwNumberOfClients = 1; dwNumberOfWorkers = 2 * SystemInfo.dwNumberOfProcessors; dwConcurrency = SystemInfo.dwNumberOfProcessors; fTcp = TRUE; dwWorkIndex = 4; while (--argc) { pchChar = *++argv; if (*pchChar == '/' || *pchChar == '-') { while (chChar = *++pchChar) { ParseSwitch( chChar, &argc, &argv ); } } } // // If we are doing file I/O, then create a large file that clients // can randomly seek and read from // srand(1); // // Create a new file and make it the correct size // DeleteFile("mhlsrv.dat"); hFile = CreateFile( "mhlsrv.dat", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE | FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL ); if ( hFile == INVALID_HANDLE_VALUE ) { fprintf(stderr, "MHLSRV: Error opening file %d\n",GetLastError()); exit(1); } // // Initialize the file with random data // ClientData[0].Overlapped.Offset = 0; for (WriteCount = 0; WriteCount < NUMBER_OF_WRITES; WriteCount++){ for(lc=0;lc ClientData[i].IoBuffer.u.IAmDone.TotalTicks ) { LowestTicks = ClientData[i].IoBuffer.u.IAmDone.TotalTicks; } // // find slowest client // if ( HighestTicks < ClientData[i].IoBuffer.u.IAmDone.TotalTicks ) { HighestTicks = ClientData[i].IoBuffer.u.IAmDone.TotalTicks; } } fprintf( stdout, "\nMHLSRV:TPS, %ld (Fastest Client %dms Slowest Client %dms)\n", (TotalIterations*1000) / TotalTicks, LowestTicks, HighestTicks ); if ( fVerbose ) { fprintf( stdout, "\n%ld bytes transferred in %ld iterations, time = %ld ms\n", TotalBytesTransferred, TotalIterations, TotalTicks ); for(i=0;iIoBuffer.MessageType ) { case CLIENT_IO_MT_RETURN_DATA: // // Determine how long a response was desired by the client. // ResponseLength = CurrentClient->IoBuffer.u.ReturnData.ByteCount; if ( ResponseLength > CLIENT_OUTBOUND_BUFFER_MAX ) { ResponseLength = CLIENT_OUTBOUND_BUFFER_MAX; } // // If we are running in I/O mode, do a random read // Otherwise, use fill memory to supply the data // if ( hFile ) { CurrentClient->Overlapped.Offset = Random(FILE_SIZE/CLIENT_OUTBOUND_BUFFER_MAX)*CLIENT_OUTBOUND_BUFFER_MAX; CurrentClient->Overlapped.hEvent = CurrentClient->hEvent; b = ReadFile( hFile, ReadBuffer, ResponseLength, &nbytes, &CurrentClient->Overlapped ); if ( !b && GetLastError() != ERROR_IO_PENDING ) { fprintf(stderr, "MHLSRV: Error in client read %d\n",GetLastError()); exit(1); } b = GetOverlappedResult( hFile, &CurrentClient->Overlapped, &nbytes, TRUE ); if ( !b ) { fprintf(stderr, "MHLSRV: Wait for pre-write failed %d\n",GetLastError()); exit(1); } CurrentClient->Overlapped.hEvent = NULL; } else { FillMemory(CurrentClient->OutboundBuffer,ResponseLength,0xfe); } // // Simulate a small compute bound workload // SortTheBuffer((LPDWORD)CurrentClient->OutboundBuffer,ReadBuffer,nbytes>>2); // // Send a response and post another asynchronous read on the // socket. // err = send( CurrentClient->Socket, CurrentClient->OutboundBuffer, ResponseLength, 0 ); if ( err == SOCKET_ERROR ) { fprintf( stdout,"Send Failed\n"); exit(1); } Me->TotalTransactions++; Me->TotalBytesTransferred += ResponseLength; // // reprime this client by posting another asynch read // b = ReadFile( (HANDLE)CurrentClient->Socket, &CurrentClient->IoBuffer, sizeof(CLIENT_IO_BUFFER), &nbytes, &CurrentClient->Overlapped ); if ( !b && GetLastError( ) != ERROR_IO_PENDING ) { fprintf( stdout,"ReadFile Failed\n"); exit(1); } break; case CLIENT_IO_MT_I_AM_DONE: CurrentClient->Flags |= CLIENT_DONE; if ( fVerbose ) { fprintf( stdout,"Client Has Completed\n"); } if ( !InterlockedDecrement(&dwActiveClientCount) ) { SetEvent(hBenchmarkComplete); } break; default: fprintf( stdout,"Invalid MessageType %x\n",CurrentClient->IoBuffer.MessageType); exit(1); } } } else { fprintf( stdout, "WorkThread Wait Failed\n"); exit(1); } } return 1; } VOID WINAPI ShowUsage( VOID ) { fputs( "usage: MHLSRV [switches]\n" " [-?] show this message\n" " [-v] verbose output\n" " [-t number-of-threads] specify the number of worker threads\n" " [-c number-of-clients] specify the number of clients\n" " [-p concurrency-value] specify the concurrency\n" " [-i ] use IPX instead of TCP\n" " [-w work-index] specify how much compute to do\n" ,stderr ); exit( 1 ); } VOID WINAPI ParseSwitch( CHAR chSwitch, int *pArgc, char **pArgv[] ) { switch (toupper( chSwitch )) { case '?': ShowUsage(); break; case 'T': if (!--(*pArgc)) { ShowUsage(); } (*pArgv)++; dwNumberOfWorkers = strtoul( *(*pArgv), NULL, 10 ); if ( dwNumberOfWorkers > MAXIMUM_NUMBER_OF_WORKERS ) { dwNumberOfWorkers = MAXIMUM_NUMBER_OF_WORKERS; } break; case 'C': if (!--(*pArgc)) { ShowUsage(); } (*pArgv)++; dwNumberOfClients = strtoul( *(*pArgv), NULL, 10 ); if ( dwNumberOfClients > MAXIMUM_NUMBER_OF_CLIENTS ) { dwNumberOfClients = MAXIMUM_NUMBER_OF_CLIENTS; } break; case 'P': if (!--(*pArgc)) { ShowUsage(); } (*pArgv)++; dwConcurrency = strtoul( *(*pArgv), NULL, 10 ); break; case 'W': if (!--(*pArgc)) { ShowUsage(); } (*pArgv)++; dwWorkIndex = strtoul( *(*pArgv), NULL, 10 ); break; case 'V': fVerbose = TRUE; break; case 'I': fTcp = FALSE; break; default: fprintf( stderr, "MHLSRV: Invalid switch - /%c\n", chSwitch ); ShowUsage(); break; } } DWORD WINAPI Random ( DWORD nMaxValue ) { return(((2 * rand() * nMaxValue + RAND_MAX) / RAND_MAX - 1) / 2); } int _CRTAPI1 DwordComp(const void *e1,const void *e2) { PULONG p1; PULONG p2; p1 = (PULONG)e1; p2 = (PULONG)e2; return (*p1 - *p2); } VOID WINAPI SortTheBuffer( LPDWORD Destination, LPDWORD Source, int DwordCount ) { DWORD i; for(i=0;i<2*dwWorkIndex;i++){ CopyMemory(Destination,Source,DwordCount<<2); qsort((void *)Destination,(size_t)DwordCount,(size_t)sizeof(DWORD),DwordComp); } }