source: trunk/lib_ir/AgnerTestP/PMCTest/PMCTestWin.h @ 4221

Last change on this file since 4221 was 4221, checked in by linmengl, 5 years ago

initial checkin of Agner Fog's performance script

File size: 20.0 KB
Line 
1//                       PMCTestWin.h                    2014-09-30 Agner Fog
2//
3//          Multithread PMC Test program
4//          System-specific definitions for Windows
5//
6// See PMCTest.txt for instructions.
7//
8// (c) Copyright 2000-2012 by Agner Fog. GNU General Public License www.gnu.org/licences
9//////////////////////////////////////////////////////////////////////////////
10
11#include <windows.h>
12#include <windef.h>
13#include <winnt.h>
14#include <winsvc.h>
15#include <stdlib.h>
16#include <stdio.h>
17#ifndef __CYGWIN__
18#include <conio.h>
19#endif
20
21// comment out next line if compiler doesn't support intrinsic functions:
22//#include <intrin.h>
23
24#if defined(_WIN64) && !defined (__CYGWIN__)
25//#include <intrin.h>  // intrinsics needed in 64 bit Windows because inline asm not supported by MS compiler
26#include "intrin1.h"   // short version of intrin.h
27#endif
28
29//////////////////////////////////////////////////////////////////////////////
30//
31//  Definitions due to different compiler syntax
32//
33//////////////////////////////////////////////////////////////////////////////
34
35// define 64 bit integer
36typedef __int64 int64;
37typedef unsigned __int64 uint64;
38
39#ifdef __CYGWIN__
40// Define macro for aligned structure, gcc syntax
41#define ALIGNEDSTRUCTURE(Name, Align) struct __attribute__((aligned(Align))) Name
42#else
43// Define macro for aligned structure, MS Visual Studio syntax
44#define ALIGNEDSTRUCTURE(Name, Align) __declspec(align(Align)) struct Name
45#endif
46
47
48// Define low level functions
49#ifdef __INTRIN_H_  // Use intrinsics for low level functions
50
51static inline void Serialize () {
52    // serialize CPU by cpuid function 0
53    int dummy[4];
54    __cpuid(dummy, 0);
55    // Prevent the compiler from optimizing away the whole Serialize function:
56    volatile int DontSkip = dummy[0];
57}
58#define Cpuid __cpuid
59#define Readtsc __rdtsc
60#define Readpmc __readpmc
61
62#elif defined (__CYGWIN__) // use gcc style inline assembly
63// This version is for gas/AT&T syntax
64
65static void Cpuid (int Output[4], int aa) {     
66    int a, b, c, d;
67    __asm("cpuid" : "=a"(a),"=b"(b),"=c"(c),"=d"(d) : "a"(aa),"c"(0) : );
68    Output[0] = a;
69    Output[1] = b;
70    Output[2] = c;
71    Output[3] = d;
72}
73
74static inline void Serialize () {
75    // serialize CPU
76    __asm__ __volatile__ ( "xorl %%eax, %%eax \n cpuid " : : : "%eax","%ebx","%ecx","%edx" );
77}
78
79static inline int Readtsc() {
80    // read time stamp counter
81    int r;
82    __asm__ __volatile__ ( "rdtsc" : "=a"(r) : : "%edx");   
83    return r;
84}
85
86static inline int Readpmc(int nPerfCtr) {
87    // read performance monitor counter number nPerfCtr
88    int r;
89    __asm__ __volatile__ ( "rdpmc" : "=a"(r) : "c"(nPerfCtr) : "%edx");   
90    return r;
91}
92
93#else // Intrinsics not supported, use inline assembly
94// This version is for 32-bit, MASM syntax
95
96static void Cpuid (int output[4], int functionnumber) { 
97    __asm {
98        mov eax, functionnumber;
99        cpuid;
100        mov esi, output;
101        mov [esi],    eax;
102        mov [esi+4],  ebx;
103        mov [esi+8],  ecx;
104        mov [esi+12], edx;
105    }
106}
107
108static inline void Serialize () {
109    // serialize CPU
110    __asm {
111        xor eax, eax
112            cpuid
113    }
114    // Note: ebx is changed by cpuid.
115    // The compiler will save ebx automatically in most cases, but bugs have been observed.
116}
117
118#pragma warning(disable:4035)
119static inline int Readtsc() {
120    // read performance monitor counter number nPerfCtr
121    __asm {
122        rdtsc
123    }
124}
125
126static inline int Readpmc(int nPerfCtr) {
127    // read performance monitor counter number nPerfCtr
128    __asm {
129        mov ecx, nPerfCtr
130            rdpmc
131    }
132}
133
134#pragma warning(default:4035)
135
136#endif  // __INTRIN_H_
137
138//////////////////////////////////////////////////////////////////////////////
139//
140//  Definitions due to different OS calls
141//
142//////////////////////////////////////////////////////////////////////////////
143
144// Function declaration for thread procedure
145#define ThreadProcedureDeclaration(Name) extern "C" DWORD WINAPI Name(LPVOID parm)
146
147ThreadProcedureDeclaration(ThreadProc1);
148
149namespace SyS {  // system-specific process and thread functions
150
151    typedef DWORD_PTR ProcMaskType;          // Type for processor mask
152    //typedef unsigned int ProcMaskType;     // If DWORD_PTR not defined
153
154    // Get mask of possible CPU cores
155    static inline ProcMaskType GetProcessMask() {
156        ProcMaskType ProcessAffMask = 0, SystemAffMask = 0;
157        GetProcessAffinityMask(GetCurrentProcess(), &ProcessAffMask, &SystemAffMask);
158        return ProcessAffMask;
159    }
160
161    // Set CPU to run on specified CPU core number (0-based)
162    static inline void SetProcessMask(int p) {
163        int r = (int)SetThreadAffinityMask(GetCurrentThread(), (ProcMaskType)1 << p);   
164        if (r == 0) {
165            int e = GetLastError();
166            printf("\nFailed to lock thread to processor %i. Error = %i\n", p, e);
167        }
168    }
169
170    // Test if specified CPU core is available
171    static inline int TestProcessMask(int p, ProcMaskType * m) {
172        return ((ProcMaskType)1 << p) & *m;
173    }
174
175    // MainThreadProcNum = GetCurrentProcessorNumber(); // only available in Vista and above
176
177    // Sleep for the rest of current timeslice
178    static inline void Sleep0() {
179        Sleep(0);
180    }
181
182    // Set process (all threads) to high priority
183    static inline void SetProcessPriorityHigh() {
184        SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS);
185    }
186
187    // Set process (all threads) to normal priority
188    static inline void SetProcessPriorityNormal() {
189        SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS);
190    }
191}
192
193//////////////////////////////////////////////////////////////////////
194//
195//        Class ThreadHandler: Create threads
196//
197//////////////////////////////////////////////////////////////////////
198
199#define ThreadStackSize  0x4000    // Stack size for each thread
200
201class ThreadHandler {
202public:
203    ThreadHandler() {       // constructor
204        NumThreads = 0;
205        for (int i = 0; i < MAXTHREADS; i++) {
206            hThreads[i] = 0;
207            ThreadData[i] = 0;
208        }
209    }
210
211    void Start(int Num) { // start threads
212        int t;
213        if (Num > MAXTHREADS) Num = MAXTHREADS;
214        NumThreads = Num;
215        for (t = 0; t < NumThreads-1; t++) {
216            ThreadData[t] = t;
217            // create and start thread
218            hThreads[t] = CreateThread( 
219                NULL,                   // default security attributes
220                ThreadStackSize,        // stack size 
221                ThreadProc1,            // thread function name
222                &ThreadData[t],         // argument to thread function
223                0,                      // use default creation flags
224                NULL); 
225            if (hThreads[t] == 0) {
226                printf("\nFailed to create thread %i", t);
227            }
228        }
229        // last thread = this thread
230        t = NumThreads-1;
231        ThreadData[t] = t;
232        ThreadProc1(&ThreadData[t]);
233    }
234
235    void Stop() {
236        // wait for threads to finish
237        if (NumThreads == 0) return;
238        WaitForMultipleObjects(NumThreads, hThreads, TRUE, INFINITE);
239        for (int t = 0; t < NumThreads; t++) {
240            if (hThreads[t]) CloseHandle(hThreads[t]);
241        }
242        NumThreads = 0;
243    }
244
245    ~ThreadHandler() {  // destructor
246        Stop();
247    }
248
249protected:
250    int NumThreads;
251    HANDLE hThreads[MAXTHREADS];
252    int ThreadData[MAXTHREADS];
253};
254
255
256//////////////////////////////////////////////////////////////////////
257//
258//                         class CMSRDriver
259//
260// Thie class encapsulates the interface to the driver MSRDriver32.sys
261// or MSRDriver64.sys which is needed for privileged access to set up
262// the model specific registers in the CPU.
263// This class loads, unloads and sends commands to MSRDriver
264//
265//////////////////////////////////////////////////////////////////////
266
267class CMSRDriver {
268protected:
269    SC_HANDLE scm;
270    SC_HANDLE service;
271    HANDLE hDriver;
272    const char * DriverFileName;
273    const char * DriverSymbolicName;
274    char DriverFileNameE[MAX_PATH], DriverFilePath[MAX_PATH];
275
276public:
277    CMSRDriver() {  // constructor   
278        // Define Driver filename
279        if (Need64BitDriver()) {
280            DriverFileName = "MSRDriver64";
281        }
282        else {
283            DriverFileName = "MSRDriver32";
284        }   
285        // Define driver symbolic link name
286        DriverSymbolicName = "\\\\.\\slMSRDriver";
287
288        // Get the full path of the driver file name
289        strcpy(DriverFileNameE, DriverFileName);
290        strcat(DriverFileNameE, ".sys");           // append .sys to DriverName
291        ::GetFullPathName(DriverFileNameE, MAX_PATH, DriverFilePath, NULL);
292
293        // Initialize
294        service = NULL;
295        hDriver = NULL;
296        scm     = NULL;
297    }
298
299    ~CMSRDriver() {  // destructor
300        // Unload driver if not already unloaded and close SCM handle
301        //if (hDriver) UnloadDriver();
302        if (service) {
303            ::CloseServiceHandle(service); service = NULL;   
304        }
305        if (scm) {
306            // Optionally unload driver
307            // UnloadDriver();
308            // Don't uninstall driver, you may need reboot before you can install it again
309            // UnInstallDriver();
310            ::CloseServiceHandle(scm); scm = NULL;
311        }
312    }
313
314    const char * GetDriverName() {            // get name of driver
315        return DriverFileName;
316    }
317
318    int LoadDriver() {                        // load MSRDriver
319        int r = 0, e = 0;
320        // open driver service
321        r = OpenDriver();
322        if (r == 1060) {
323            // Driver not installed. Install it
324            e = InstallDriver();
325            if (e) return e;
326            r = OpenDriver();
327        }
328        if (r) {
329            printf("\nError %i loading driver\n");
330            return r;
331        }
332
333        // Start the service
334        r = ::StartService(service, 0, NULL);
335        if (r == 0) {
336            e = ::GetLastError();
337            switch (e) {
338            case ERROR_PATH_NOT_FOUND:
339                printf("\nDriver file %s path not found (please try to uninstall and reinstall)\n", DriverFileNameE);
340                break;
341
342            case ERROR_FILE_NOT_FOUND:  // .sys file not found
343                printf("\nDriver file %s not found\n", DriverFileNameE);
344                break;
345
346            case 577:
347                // driver not signed (Vista and Windows 7)
348                printf("\nThe driver %s is not signed by Microsoft\nPlease press F8 during boot and select 'Disable Driver Signature Enforcement'\n", DriverFileNameE);
349                break;
350
351            case 1056:
352                // Driver already loaded. Ignore
353                //printf("\nDriver already loaded\n");
354                e = 0;
355                break;
356
357            case 1058:
358                printf("\nError: Driver disabled\n");
359                break;
360
361            default:
362                printf("\nCannot load driver %s\nError no. %i", DriverFileNameE, e);
363            }
364        }
365        if (e == 0) {
366            // Get handle to driver
367            hDriver = ::CreateFile(DriverSymbolicName, GENERIC_READ + GENERIC_WRITE,
368                0, NULL, OPEN_EXISTING, 0, NULL);
369
370            if(hDriver == NULL || hDriver == INVALID_HANDLE_VALUE) {
371                hDriver = NULL;
372                e = ::GetLastError();
373                printf("\nCannot load driver\nError no. %i", e);
374            }
375        }
376        return e;
377    }
378
379    int UnloadDriver() {                      // unload MSRDriver
380        int r = 0, e = 0;
381        if(GetScm() == NULL) {
382            return -6;
383        }
384
385        if (hDriver) {
386            r = ::CloseHandle(hDriver); hDriver = NULL;
387            if (r == 0) {
388                e = ::GetLastError();
389                printf("\nCannot close driver handle\nError no. %i", e);
390                return e;
391            }
392            printf("\nUnloading driver");
393        }
394
395        if (service) {
396            SERVICE_STATUS ss;
397            r = ::ControlService(service, SERVICE_CONTROL_STOP, &ss);
398            if (r == 0) {
399                e = ::GetLastError();
400                if (e == 1062) {
401                    printf("\nDriver not active\n");
402                }
403                else {
404                    printf("\nCannot close driver\nError no. %i", e);
405                }
406                return e;
407            }
408        }
409        return 0;
410    }
411
412protected:
413    int InstallDriver() {                     // install MSRDriver
414        // install MSRDriver
415        int e = 0;
416        if(GetScm() == NULL) return -1;
417
418        // Install driver in database
419        service = ::CreateService(scm, DriverFileNameE, "MSR driver",
420            SERVICE_START + SERVICE_STOP + DELETE, SERVICE_KERNEL_DRIVER,
421            SERVICE_DEMAND_START, SERVICE_ERROR_IGNORE, DriverFilePath, 
422            NULL, NULL, NULL, NULL, NULL);
423
424        if(service == NULL) {
425            e = ::GetLastError();
426            printf("\nCannot install driver %s\nError no. %i", DriverFileNameE, e);
427        }
428        else {
429            printf("\nFirst time: Installing driver %s\n", DriverFileNameE);
430        }
431        return e;
432    } 
433
434    int UnInstallDriver() {                   // uninstall MSRDriver
435        // uninstall MSRDriver
436        int r = 0, e = 0;
437        GetScm();
438        if (service == 0) {
439            service = ::OpenService(scm, DriverFileNameE, SERVICE_ALL_ACCESS);
440        }
441        if(service == 0) {
442            e = ::GetLastError();
443            if (e == 1060) {
444                printf("\nDriver %s already uninstalled or never installed\n", DriverFileNameE);
445            }
446            else {
447                printf("\nCannot open service, failed to uninstall driver %s\nError no. %i", DriverFileNameE, e);
448            }
449        }
450        else {
451            r = ::DeleteService(service);
452            if (r == 0) {
453                e = ::GetLastError();
454                printf("\nFailed to uninstall driver %s\nError no. %i", DriverFileNameE, e);
455                if (e == 1072) printf("\nDriver already marked for deletion\n");
456            }
457            else {
458                printf("\nUninstalling driver %s\n", DriverFileNameE);
459            }
460            r = ::CloseServiceHandle(service);
461            if (r == 0) {
462                e = ::GetLastError();
463                printf("\nCannot close service\nError no. %i", e);
464            }
465            service = NULL;
466        }
467        return e;
468    }
469
470    SC_HANDLE GetScm() {                      // Make scm handle
471        // Make scm handle
472        if (scm) return scm;  // handle already made
473
474        // Open connection to Windows Service Control Manager (SCM)
475        scm = ::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
476        if(scm == NULL) {
477            int e = ::GetLastError();
478            if (e == ERROR_ACCESS_DENIED) {
479                printf("\nAccess denied. Please run as administrator\n");
480            }
481            else if (e == 120) {  // function not implemented
482                printf("\nFunction not implemented on this operating system. Windows 2000 or later required.\n");
483            }
484            else {
485                printf("\nCannot load Windows Service Control Manager\nError no. %i", e);
486            }
487        }
488        return scm;
489    }
490
491    int OpenDriver() {                        // open driver service
492        // open driver service
493        int e;
494        // Open a service handle if not already open
495        if (service == 0) {
496            service = ::OpenService(GetScm(), DriverFileNameE, SERVICE_ALL_ACCESS);
497        }
498        if(service == 0) {
499            e = ::GetLastError();
500
501            switch (e) { // Any other error than driver not installed
502            case 1060: // Driver not installed. Install it
503                break;
504            case 6:    // access denied
505                printf("\nAccess denied\n");
506                break;
507            default:  // Any other error
508                printf("\nCannot open service, failed to load driver %s\nError no. %i", DriverFileNameE, e);
509            }
510            return e;
511        }
512        return 0;
513    }
514
515    typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
516
517    int Need64BitDriver() {                   // tell whether we need 32 bit or 64 bit driver
518        // Tell whether we need 32 bit or 64 bit driver.
519        // Return value:
520        // 0: running in 32 bits Windows
521        // 1: running 32 bits mode in 64 bits Windows
522        // 2: running 64 bits mode in 64 bits Windows
523#ifdef _WIN64
524        return 2;
525#else
526        LPFN_ISWOW64PROCESS fnIsWow64Process = 
527            (LPFN_ISWOW64PROCESS)GetProcAddress(
528            GetModuleHandle("kernel32"),"IsWow64Process");   
529        if (fnIsWow64Process) {     
530            BOOL bIsWow64 = FALSE;     
531            if (!fnIsWow64Process(GetCurrentProcess(),&bIsWow64)) {
532                return 0;
533            }
534            return bIsWow64;
535        }
536        return 0;
537#endif
538    }
539
540public:
541    // send commands to driver to read or write MSR registers
542    int AccessRegisters(void * pnIn, int nInLen, void * pnOut, int nOutLen) {
543        if (nInLen <= 0) return 0;
544
545        const int DeviceType = 0x22;        // FILE_DEVICE_UNKNOWN;
546        const int Function = 0x800;
547        const int Method = 0;               // METHOD_BUFFERED;
548        const int Access = 1 | 2;           // FILE_READ_ACCESS | FILE_WRITE_ACCESS;
549        const int IOCTL_MSR_DRIVER = DeviceType << 16 | Access << 14 | Function << 2 | Method;
550
551        DWORD len = 0;
552
553        // This call results in a call to the driver rutine DispatchControl()
554        int res = ::DeviceIoControl(hDriver, IOCTL_MSR_DRIVER, pnIn, nInLen,
555            pnOut, nOutLen, &len, NULL);
556        if (!res) { 
557            // Error
558            int e = GetLastError();
559            printf("\nCan't access driver. error %i", e);
560            return e;
561        }
562
563        // Check return error codes from driver
564        SMSRInOut * outp = (SMSRInOut*)pnOut;
565        for (int i = 0; i < nOutLen/(INT)sizeof(SMSRInOut); i++) {
566            if (outp[i].msr_command == PROC_SET && outp[i].val[0]) {
567                printf("\nSetting processor number in driver failed, error 0x%X", outp[i].val[0]);
568            }
569        }
570        return 0;
571    }
572
573    // send commands to driver to read or write MSR registers
574    int AccessRegisters(CMSRInOutQue & q) {
575        // Number of bytes in/out
576        int n = q.GetSize() * sizeof(SMSRInOut); 
577        if (n <= 0) return 0;
578        return AccessRegisters(q.queue, n, q.queue, n);
579    }
580
581
582    // read performance monitor counter
583    // send command to driver to read one MSR register
584    int64 MSRRead(int r) {
585        SMSRInOut a;
586        a.msr_command = MSR_READ;
587        a.register_number = r;
588        a.value = 0;
589        AccessRegisters(&a,sizeof(a),&a,sizeof(a));
590        return a.val[0];
591    } 
592
593    // send command to driver to write one MSR register
594    int MSRWrite(int r, int64 val) {
595        SMSRInOut a;
596        a.msr_command = MSR_WRITE;
597        a.register_number = r;
598        a.value = val;
599        return AccessRegisters(&a,sizeof(a),&a,sizeof(a));
600    }
601
602    // send command to driver to read one control register, cr0 or cr4
603    size_t CRRead(int r) {
604        if (r != 0 && r != 4) return -11;
605        SMSRInOut a;
606        a.msr_command = CR_READ;
607        a.register_number = r;
608        a.value = 0;
609        AccessRegisters(&a,sizeof(a),&a,sizeof(a));
610        return size_t(a.value);
611    }
612
613    // send command to driver to write one control register, cr0 or cr4
614    int CRWrite(int r, size_t val) {
615        if (r != 0 && r != 4) return -12;
616        SMSRInOut a;
617        a.msr_command = CR_WRITE;
618        a.register_number = r;
619        a.value = val;
620        return AccessRegisters(&a,sizeof(a),&a,sizeof(a));
621    } 
622};
Note: See TracBrowser for help on using the repository browser.