source: trunk/lib_ir/AgnerTestP/PMCTest/PMCTestLinux.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: 9.2 KB
Line 
1//                     PMCTestLinux.h                    © 2012-03-02 Agner Fog
2//
3//          Multithread PMC Test program
4//          System-specific definitions for Linux
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 <sched.h>
12#include <unistd.h>
13#include <sys/time.h>
14#include <sys/resource.h>
15#include <sys/types.h>
16#include <fcntl.h>
17#include <sys/ioctl.h>
18#include <pthread.h>
19#include <linux/unistd.h>  // __NR_gettid
20#include <string.h>
21#include <stdlib.h>
22#include <stdio.h>
23
24#include "MSRdrvL.h" // shared with driver
25
26// comment out next line if compiler doesn't support intrinsic functions:
27//#include <intrin.h>
28
29
30//////////////////////////////////////////////////////////////////////////////
31//
32//  Definitions due to different compiler syntax
33//
34//////////////////////////////////////////////////////////////////////////////
35
36// define 64 bit integer
37typedef long long int64;
38typedef unsigned long long uint64;
39
40// Define macro for aligned structure, gcc syntax
41#define ALIGNEDSTRUCTURE(Name, Align) struct __attribute__((aligned(Align))) Name
42
43
44// Define low level functions
45#ifdef __INTRIN_H_  // Use intrinsics for low level functions
46
47static inline void Serialize () {
48    // serialize CPU by cpuid function 0
49    int dummy[4];
50    __cpuid(dummy, 0);
51    // Prevent the compiler from optimizing away the whole Serialize function:
52    volatile int DontSkip = dummy[0];
53}
54#define Cpuid __cpuid
55#define Readtsc __rdtsc
56#define Readpmc __readpmc
57
58#else // Intrinsics not supported, use inline assembly
59// This version is for gas/AT&T syntax
60
61static void Cpuid (int Output[4], int aa) {     
62    int a, b, c, d;
63    __asm("cpuid" : "=a"(a),"=b"(b),"=c"(c),"=d"(d) : "a"(aa),"c"(0) : );
64    Output[0] = a;
65    Output[1] = b;
66    Output[2] = c;
67    Output[3] = d;
68}
69
70static inline void Serialize () {
71    // serialize CPU
72    __asm__ __volatile__ ( "xorl %%eax, %%eax \n cpuid " : : : "%eax","%ebx","%ecx","%edx" );
73}
74
75static inline int Readtsc() {
76    // read time stamp counter
77    int r;
78    __asm__ __volatile__ ( "rdtsc" : "=a"(r) : : "%edx");   
79    return r;
80}
81
82static inline int Readpmc(int nPerfCtr) {
83    // read performance monitor counter number nPerfCtr
84    int r;
85    __asm__ __volatile__ ( "rdpmc" : "=a"(r) : "c"(nPerfCtr) : "%edx");   
86    return r;
87}
88#endif  // __INTRIN_H_
89
90//////////////////////////////////////////////////////////////////////////////
91//
92//  Definitions due to different OS calls
93//
94//////////////////////////////////////////////////////////////////////////////
95
96// Declare the gettid syscall.
97//_syscall0(pid_t, gettid);
98static inline pid_t gettid(void) { return syscall(__NR_gettid); }
99
100
101// Function declaration for thread procedure
102#define ThreadProcedureDeclaration(Name) void* Name(void * parm)
103ThreadProcedureDeclaration(ThreadProc1);
104
105namespace SyS {  // system-specific interface functions
106
107    typedef cpu_set_t ProcMaskType;          // Type for processor mask
108
109    // Get mask of possible CPU cores
110    static inline ProcMaskType GetProcessMask() {
111        ProcMaskType ProcessAffMask;
112        CPU_ZERO(&ProcessAffMask);
113        int e = sched_getaffinity(0, sizeof(ProcMaskType), &ProcessAffMask);
114        if (e) printf("\nsched_getaffinity failed");
115        return ProcessAffMask;
116    }
117
118    // Set CPU to run on specified CPU core (0 based number)
119    static inline void SetProcessMask(int p) {
120        ProcMaskType mask;
121        CPU_ZERO(&mask);
122        CPU_SET(p, &mask);
123        int e = sched_setaffinity(gettid(), sizeof(ProcMaskType), &mask);
124        if (e) {
125            printf("\nFailed to lock thread to processor %i\n", p);
126        }
127    }
128
129    // Test if specified CPU core is available
130    static inline int TestProcessMask(int p, ProcMaskType * m) {
131        return CPU_ISSET(p, m);
132    }
133
134    // Sleep for the rest of current timeslice
135    static inline void Sleep0() {
136        sched_yield();
137    }
138
139    // Set process (all threads) to high priority
140    static inline void SetProcessPriorityHigh() {
141        setpriority(PRIO_PROCESS, 0, PRIO_MIN);
142    }
143
144    // Set process (all threads) to normal priority
145    static inline void SetProcessPriorityNormal() {
146        setpriority(PRIO_PROCESS, 0, 0);
147    } 
148
149}
150
151
152//////////////////////////////////////////////////////////////////////
153//
154//        Class ThreadHandler: Create threads
155//
156//////////////////////////////////////////////////////////////////////
157
158#define ThreadStackSize  0x4000    // Stack size for each thread
159
160
161class ThreadHandler {
162public:
163    ThreadHandler() {       // constructor
164        NumThreads = 0;
165        for (int i = 0; i < MAXTHREADS; i++) {
166            //hThreads[i] = 0;
167            ThreadData[i] = 0;
168        }
169    }
170
171    void Start(int Num) { // start threads
172        if (Num > MAXTHREADS) Num = MAXTHREADS;
173        NumThreads = Num;
174        int t;
175        for (t = 0; t < NumThreads-1; t++) {
176            ThreadData[t] = t;
177            // create and start thread
178            int e = pthread_create(&hThreads[t], NULL, &ThreadProc1, &ThreadData[t]);
179            if (e) printf("\nFailed to create thread %i", t);
180        }
181        // last thread = this thread
182        t = NumThreads-1;
183        ThreadData[t] = t;
184        ThreadProc1(&ThreadData[t]);
185    }
186
187    void Stop() {
188        // wait for threads to finish
189        if (NumThreads == 0) return;
190        for (int t = 0; t < NumThreads - 1; t++) {
191            int e = pthread_join(hThreads[t], NULL);
192            if (e) printf("\nFailed to terminate thread %i", t);
193        }
194        NumThreads = 0;
195    }
196
197    ~ThreadHandler() {  // destructor
198        Stop();
199    }
200
201protected:
202    int NumThreads;
203    pthread_t hThreads[MAXTHREADS];
204    int ThreadData[MAXTHREADS];
205};
206
207
208//////////////////////////////////////////////////////////////////////
209//
210//                         class CMSRDriver
211//
212// Thie class encapsulates the interface to the driver MSRDriver32.sys
213// or MSRDriver64.sys which is needed for privileged access to set up
214// the model specific registers in the CPU.
215// This class loads, unloads and sends commands to MSRDriver
216//
217//////////////////////////////////////////////////////////////////////
218
219class CMSRDriver {
220public:
221    CMSRDriver() {             // constructor
222        DriverFileName = "/dev/MSRdrv";
223        DriverHandle = 0;
224    }
225
226    ~CMSRDriver() {            // destructor
227        UnloadDriver();
228    }
229
230    int LoadDriver() {         // load MSRDriver
231        DriverHandle = open(DriverFileName, 0);
232        if (DriverHandle == -1) {
233            printf("\nCannot open device %s\n", DriverFileName);
234            DriverHandle = 0;
235            return 1;
236        }
237        return 0;
238    }
239
240    int UnloadDriver() {       // unload MSRDriver
241        if (DriverHandle) {
242            close(DriverHandle);
243            DriverHandle = 0;
244        }
245        return 0;
246    }
247
248    const char* GetDriverName() {  // get name of driver
249        return DriverFileName;
250    }
251
252    // send commands to driver to read or write MSR registers
253    int AccessRegisters(void * pnIn, int nInLen, void * pnOut, int nOutLen) {
254        if (!DriverHandle) return -1;
255
256        // pnIn and pnOut must be the same
257        if (pnIn != pnOut) printf("\nError: driver must use same buffer for input and output");
258
259        // nInLen and nOutLen are ignored. Rely on queue ending with MSR_STOP command
260        return ioctl(DriverHandle, IOCTL_PROCESS_LIST, pnIn);
261    }
262
263    // send commands to driver to read or write MSR registers
264    int AccessRegisters(CMSRInOutQue & q) {
265        // Number of bytes in/out
266        int n = q.GetSize() * sizeof(SMSRInOut); 
267        if (n <= 0) return 0;
268        return AccessRegisters(q.queue, n, q.queue, n);
269    }
270
271    // read performance monitor counter
272    // send command to driver to read one MSR register
273    int64 MSRRead(int r) {
274        SMSRInOut a;
275        a.msr_command = MSR_READ;
276        a.register_number = r;
277        a.value = 0;
278        AccessRegisters(&a,sizeof(a),&a,sizeof(a));
279        return a.val[0];
280    } 
281
282    // send command to driver to write one MSR register
283    int MSRWrite(int r, int64 val) {
284        SMSRInOut a;
285        a.msr_command = MSR_WRITE;
286        a.register_number = r;
287        a.value = val;
288        return AccessRegisters(&a,sizeof(a),&a,sizeof(a));
289    }
290
291    // send command to driver to read one control register, cr0 or cr4
292    size_t CRRead(int r) {
293        if (r != 0 && r != 4) return -11;
294        SMSRInOut a;
295        a.msr_command = CR_READ;
296        a.register_number = r;
297        a.value = 0;
298        AccessRegisters(&a,sizeof(a),&a,sizeof(a));
299        return size_t(a.value);
300    }
301
302    // send command to driver to write one control register, cr0 or cr4
303    int CRWrite(int r, size_t val) {
304        if (r != 0 && r != 4) return -12;
305        SMSRInOut a;
306        a.msr_command = CR_WRITE;
307        a.register_number = r;
308        a.value = val;
309        return AccessRegisters(&a,sizeof(a),&a,sizeof(a));
310    } 
311
312protected:
313    const char* DriverFileName;
314    int DriverHandle;
315};
Note: See TracBrowser for help on using the repository browser.