Main Page | Data Structures | Directories | File List | Data Fields | Globals | Related Pages

perfeval.c

Go to the documentation of this file.
00001 /*
00002  *  This program is free software; you can redistribute it and/or
00003  *  modify it under the terms of the GNU General Public License
00004  *  as published by the Free Software Foundation; either version
00005  *  2 of the License, or (at your option) any later version.
00006  *
00007  *  Copyright 2004 Spiro Trikaliotis
00008  *
00009  */
00010 
00020 #include <wdm.h>
00021 
00022 #include "cbm_driver.h"
00023 
00024 #include "../libiec/i_iec.h"
00025 
00026 #ifdef PERFEVAL
00027 
00029 #undef PERFEVAL_DEBUG 
00030 
00033 #undef PERFEVAL_WRITE_TO_MEMORY
00034 
00035 
00036 #ifdef PERFEVAL_DEBUG
00037 
00038     #define DBG_PRINT_REG( _xxx ) DBG_PRINT( _xxx )
00039     #define DBG_PRINT_FILE( _xxx ) DBG_PRINT( _xxx )
00040 
00041 #else /* #ifdef PERFEVAL_DEBUG */
00042 
00043     #define DBG_PRINT_REG( _xxx )
00044     #define DBG_PRINT_FILE( _xxx )
00045 
00046 #endif /* #ifdef PERFEVAL_DEBUG */
00047 
00050 #define MAX_PERFORMANCE_EVAL_ENTRIES 0xffff
00051 
00053 static PPERFORMANCE_EVAL_ENTRY PerformanceEvalEntries = NULL;
00054 
00058 static ULONG CurrentPerformanceEvalEntry = -1;
00059 
00063 static ULONG ProcessorFrequency = -1;
00064 
00081 #pragma warning(push)
00082 #pragma warning(disable:4035)
00083 
00084 __forceinline __int64 RDTSC(void)
00085 {
00086 #ifdef USE_RDTSC
00087     __asm {
00088         // RDTSC
00089         _emit 0x0F
00090         _emit 0x31
00091     }
00092 #else
00093     LARGE_INTEGER li;
00094 
00095     li = KeQueryPerformanceCounter(NULL);
00096 
00097     return li.QuadPart;
00098 #endif
00099 }
00100 #pragma warning(pop)
00101 
00110 VOID
00111 PerfInit(VOID)
00112 {
00113     FUNC_ENTER();
00114 
00115     DBG_ASSERT(PerformanceEvalEntries == NULL);
00116     DBG_ASSERT(CurrentPerformanceEvalEntry == -1);
00117 
00118     // Allocate memory for the entries
00119 
00120     PerformanceEvalEntries = (PPERFORMANCE_EVAL_ENTRY) ExAllocatePoolWithTag(NonPagedPool, 
00121         MAX_PERFORMANCE_EVAL_ENTRIES * sizeof(*PerformanceEvalEntries), MTAG_PERFEVAL);
00122 
00123     if (PerformanceEvalEntries)
00124     {
00125 #ifdef USE_RDTSC
00126 
00127         UNICODE_STRING registryPath;
00128         NTSTATUS ntStatus;
00129         HANDLE handleRegistry;
00130 
00131         // Get the processor frequency from the registry. As Windows
00132         // already tried to calculate the frequency, do not try to
00133         // calculate it on my own, but rely on this.
00134 
00135         RtlInitUnicodeString(&registryPath, 
00136             L"\\REGISTRY\\MACHINE\\HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0");
00137 
00138         DBG_PRINT_REG((DBG_PREFIX "trying to open %wZ", &registryPath));
00139         ntStatus = cbm_registry_open_for_read(&handleRegistry, &registryPath);
00140         DBG_PRINT_REG((DBG_PREFIX "cbm_registry_open() returned %s", DebugNtStatus(ntStatus)));
00141 
00142         if (NT_SUCCESS(ntStatus))
00143         {
00144             ntStatus = cbm_registry_read_ulong(handleRegistry, L"~MHz", &ProcessorFrequency);
00145             DBG_PRINT_REG((DBG_PREFIX "cbm_registry_read() returned %s, value = %u", 
00146                 DebugNtStatus(ntStatus), ProcessorFrequency));
00147 
00148             ntStatus = cbm_registry_close(handleRegistry);
00149             DBG_PRINT_REG((DBG_PREFIX "cbm_registry_close() returned %s", DebugNtStatus(ntStatus)));
00150         }
00151 
00152 #else
00153         LARGE_INTEGER li;
00154 
00155         KeQueryPerformanceCounter(&li);
00156 
00157         DBG_ASSERT(li.HighPart == 0);
00158         ProcessorFrequency = li.LowPart;
00159 
00160 #endif
00161 
00162         {
00163             unsigned int waitPeriod = 100;
00164 
00165             DBG_PRINT((DBG_PREFIX "Measuring time:"));
00166             PERF_EVENT_MEASURE_TIME(0);
00167             cbmiec_udelay(waitPeriod);
00168             PERF_EVENT_MEASURE_TIME(waitPeriod);
00169             DBG_PRINT((DBG_PREFIX "We waited %u us.", waitPeriod));
00170         }
00171     }
00172 
00173     FUNC_LEAVE();
00174 }
00175 
00200 VOID
00201 PerfEvent(IN ULONG_PTR Event, IN ULONG_PTR Data)
00202 {
00203     ULONG currentEntry;
00204 
00205     FUNC_ENTER();
00206 
00207     // only try to write if we successfully allocated a buffer!
00208 
00209     if (PerformanceEvalEntries)
00210     {
00211         // first of all, increment the entry number of the event
00212         // This makes sure that we are multiprocessor-safe, as 
00213         // we only write to the log after we have successfully
00214         // incremented the value.
00215 
00216         currentEntry = InterlockedIncrement(&CurrentPerformanceEvalEntry);
00217 
00218         if (currentEntry < MAX_PERFORMANCE_EVAL_ENTRIES)
00219         {
00220             PerformanceEvalEntries[currentEntry].Timestamp = RDTSC();
00221             PerformanceEvalEntries[currentEntry].Processor = CbmGetCurrentProcessorNumber();
00222             PerformanceEvalEntries[currentEntry].PeThread  = PsGetCurrentThread();
00223             PerformanceEvalEntries[currentEntry].Event = Event;
00224             PerformanceEvalEntries[currentEntry].Data = Data;
00225         }
00226         else
00227         {
00228             // If we incremented "out of the buffer", make sure
00229             // that we decrement the value back to where it was
00230             // before
00231 
00232             InterlockedDecrement(&CurrentPerformanceEvalEntry);
00233         }
00234     }
00235 
00236     FUNC_LEAVE();
00237 }
00238 
00241 typedef 
00242 struct PERFEVAL_FILE_HEADER
00243 {
00245     ULONG FileVersion;
00246 
00249     ULONG ProcessorFrequency;
00250 
00252     ULONG CountEntries;
00253 
00254 } PERFEVAL_FILE_HEADER, *PPERFEVAL_FILE_HEADER;
00255 
00266 VOID
00267 PerfSynchronize(VOID)
00268 {
00269     FUNC_ENTER();
00270 
00271     // Make sure to only output the entries if there are some
00272 
00273     DBG_ASSERT(((LONG)CurrentPerformanceEvalEntry) >= 0);
00274 
00275     if (PerformanceEvalEntries)
00276     {
00277 
00278 #ifdef PERFEVAL_WRITE_TO_MEMORY
00279 
00280         __int64 FirstTimestamp;
00281         __int64 LastTimestamp;
00282         ULONG i;
00283 
00284         FirstTimestamp = PerformanceEvalEntries[0].Timestamp;
00285         LastTimestamp = FirstTimestamp;
00286         
00287         for (i = 0; i < CurrentPerformanceEvalEntry; i++)
00288         {
00289             __int64 tempTimeAbs;
00290             __int64 tempTimeRel;
00291             ULONG usTime;
00292             ULONG msTime;
00293             ULONG sTime;
00294 
00295             tempTimeAbs = (PerformanceEvalEntries[i].Timestamp - FirstTimestamp) / ProcessorFrequency;
00296             tempTimeRel = (PerformanceEvalEntries[i].Timestamp - LastTimestamp) / ProcessorFrequency;
00297 
00298             LastTimestamp = PerformanceEvalEntries[i].Timestamp;
00299 
00300             usTime = (ULONG) (tempTimeAbs % 1000);
00301             msTime = (ULONG) ((tempTimeAbs / 1000) % 1000);
00302             sTime = (ULONG) ((tempTimeAbs / 1000000) % 1000);
00303 
00304             DBG_PRINT((DBG_PREFIX 
00305                 "%6u - Time: %3u.%03u.%03u us (+%7I64u us) - Event = %08x, Data = %08x"
00306                 " on processur %u in thread %p",
00307                 i,
00308                 sTime, msTime, usTime,
00309                 tempTimeRel,
00310                 PerformanceEvalEntries[i].Event,
00311                 PerformanceEvalEntries[i].Data,
00312                 PerformanceEvalEntries[i].Processor,
00313                 PerformanceEvalEntries[i].PeThread));
00314         }
00315 
00316         // make sure we start storing the performance values 
00317         // at the beginning again
00318 
00319         InterlockedExchange(&CurrentPerformanceEvalEntry, -1);
00320 
00321 #else /* #ifdef PERFEVAL_WRITE_TO_MEMORY */
00322 
00323         IO_STATUS_BLOCK ioStatusBlock;
00324         OBJECT_ATTRIBUTES objectAttributes;
00325         UNICODE_STRING fileName;
00326         NTSTATUS ntStatus;
00327         HANDLE fileHandle;
00328 
00329         RtlZeroMemory(&objectAttributes, sizeof(objectAttributes));
00330         RtlInitUnicodeString(&fileName, L"\\??\\c:\\opencbm\\timing\\timing.dat");
00331 
00332         DBG_IRQL( == PASSIVE_LEVEL);
00333         InitializeObjectAttributes(&objectAttributes,
00334             &fileName,
00335             OBJ_CASE_INSENSITIVE ,
00336             NULL,
00337             NULL
00338         );
00339 
00340         ntStatus = ZwCreateFile(
00341                 &fileHandle,
00342                 FILE_APPEND_DATA | SYNCHRONIZE,
00343                 &objectAttributes,
00344                 &ioStatusBlock,
00345                 NULL,
00346                 FILE_ATTRIBUTE_NORMAL,
00347                 0, 
00348                 FILE_OPEN_IF,
00349                 FILE_NON_DIRECTORY_FILE | FILE_SEQUENTIAL_ONLY | FILE_SYNCHRONOUS_IO_NONALERT,
00350                 NULL,
00351                 0
00352             );
00353 
00354         DBG_PRINT_FILE((DBG_PREFIX "ZwCreateFile returned %s", DebugNtStatus(ntStatus)));
00355 
00356         if (NT_SUCCESS(ntStatus))
00357         {
00358             PERFEVAL_FILE_HEADER fileHeader;
00359 
00360             fileHeader.FileVersion = 2
00361 #ifndef _X86_
00362             | (1<<31);
00363 #endif /* #ifndef _X86_ */
00364             ;
00365 
00366             fileHeader.ProcessorFrequency = ProcessorFrequency;
00367             fileHeader.CountEntries = CurrentPerformanceEvalEntry + 1;
00368 
00369             // the file has been opened; now, we can write to it
00370 
00371             ntStatus = ZwWriteFile(fileHandle, 
00372                 NULL, // event
00373                 NULL, // ApcRoutine
00374                 NULL, // ApcContext
00375                 &ioStatusBlock,
00376                 &fileHeader,
00377                 sizeof(fileHeader),
00378                 NULL,
00379                 NULL);
00380 
00381             DBG_PRINT_FILE((DBG_PREFIX "ZwWriteFile (header) returned %s",
00382                 DebugNtStatus(ntStatus)));
00383 
00384             ntStatus = ZwWriteFile(fileHandle, 
00385                 NULL, // event
00386                 NULL, // ApcRoutine
00387                 NULL, // ApcContext
00388                 &ioStatusBlock,
00389                 PerformanceEvalEntries,
00390                 fileHeader.CountEntries * sizeof(*PerformanceEvalEntries),
00391                 NULL,
00392                 NULL);
00393 
00394             DBG_PRINT_FILE((DBG_PREFIX "ZwWriteFile (data) returned %s",
00395                 DebugNtStatus(ntStatus)));
00396 
00397             ntStatus = ZwClose(fileHandle);
00398 
00399             DBG_PRINT_FILE((DBG_PREFIX "ZwCloseFile returned %s",
00400                 DebugNtStatus(ntStatus)));
00401 
00402             // make sure we start storing the performance values 
00403             // at the beginning again
00404 
00405             InterlockedExchange(&CurrentPerformanceEvalEntry, -1);
00406         }
00407 
00408 #endif /* #ifdef PERFEVAL_WRITE_TO_MEMORY */
00409 
00410     }
00411 
00412     FUNC_LEAVE();
00413 }
00414 
00426 VOID
00427 PerfSave(VOID)
00428 {
00429     FUNC_ENTER();
00430 
00431     if (PerformanceEvalEntries)
00432     {
00433         PVOID buffer;
00434 
00435         // write the event logs to where they should be written
00436 
00437         PerfSynchronize();
00438 
00439         // stop the event logging by writing the default values
00440 
00441         buffer = InterlockedExchangePointer(&PerformanceEvalEntries, NULL);
00442         InterlockedExchange(&CurrentPerformanceEvalEntry, -1);
00443 
00444         // free the previously allocated buffer.
00445 
00446         ExFreePool(buffer);
00447     }
00448 
00449     FUNC_LEAVE();
00450 }
00451 
00452 #endif /* #ifdef PERFEVAL */

Generated on Sun Apr 30 18:45:56 2006 for opencbm by  doxygen 1.4.2