source: trunk/lib_ir/AgnerTestP/PMCTest/PMCTestA.cpp @ 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: 62.1 KB
Line 
1//                       PMCTestA.cpp                2014-10-03 Agner Fog
2//
3//          Multithread PMC Test program for Windows and Linux
4//
5//
6// This program is intended for testing the performance of a little piece of
7// code written in C, C++ or assembly.
8// The code to test is inserted at the place marked "Test code start" in
9// PMCTestB.cpp, PMCTestB32.asm or PMCTestB64.asm.
10//
11// In 64-bit Windows: Run as administrator, with driver signature enforcement
12// off.
13//
14// See PMCTest.txt for further instructions.
15//
16// To turn on counters for use in another program, run with command line option
17//     startcounters
18// To turn counters off again, use command line option
19//     stopcounters
20//
21// © 2000-2014 GNU General Public License www.gnu.org/licenses
22//////////////////////////////////////////////////////////////////////////////
23
24#include "PMCTest.h"
25
26
27//////////////////////////////////////////////////////////////////////
28//
29//        Thread synchronizer
30//
31//////////////////////////////////////////////////////////////////////
32
33union USync {
34#if MAXTHREADS > 4
35    int64 allflags;                     // for MAXTHREADS = 8
36#else
37    int allflags;                       // for MAXTHREADS = 4
38#endif
39    char flag[MAXTHREADS];
40};
41volatile USync TSync = {0};
42
43// processornumber for each thread
44int ProcNum[64] = {0};
45
46// number of repetitions in each thread
47int repetitions;
48
49// Create CCounters instance
50CCounters MSRCounters;
51
52
53//////////////////////////////////////////////////////////////////////
54//
55//        Thread procedure
56//
57//////////////////////////////////////////////////////////////////////
58
59ThreadProcedureDeclaration(ThreadProc1) {
60    //DWORD WINAPI ThreadProc1(LPVOID parm) {
61    // check thread number
62    unsigned int threadnum = *(unsigned int*)parm;
63
64    if (threadnum >= (unsigned int)NumThreads) {
65        printf("\nThread number out of range %i", threadnum);
66        return 0;
67    }
68
69    // get desired processornumber
70    int ProcessorNumber = ProcNum[threadnum];
71
72    // Lock process to this processor number
73    SyS::SetProcessMask(ProcessorNumber);
74
75    // Start MSR counters
76    MSRCounters.StartCounters(threadnum);
77
78    // Wait for rest of timeslice
79    SyS::Sleep0();
80
81    // wait for other threads
82    // Initialize synchronizer
83    USync WaitTo;
84    WaitTo.allflags = 0;
85    for (int t = 0; t < NumThreads; t++) WaitTo.flag[t] = 1;
86    // flag for this thead ready
87    TSync.flag[threadnum] = 1;
88    // wait for other threads to be ready
89    while (TSync.allflags != WaitTo.allflags) {} // Note: will wait forever if a thread is not created
90
91    // Run the test code
92    repetitions = TestLoop(threadnum);
93
94    // Wait for rest of timeslice
95    SyS::Sleep0();
96
97    // Start MSR counters
98    MSRCounters.StopCounters(threadnum);
99
100    return 0;
101};
102
103//////////////////////////////////////////////////////////////////////
104//
105//        Start counters and leave them on, or stop counters
106//
107//////////////////////////////////////////////////////////////////////
108int setcounters(int argc, char* argv[]) {
109    int i, cnt, thread;
110    int countthreads = 0;
111    int command = 0;                 // 1: start counters, 2: stop counters
112
113    if (strstr(argv[1], "startcounters")) command = 1;
114    else if (strstr(argv[1], "stopcounters")) command = 2;
115    else {
116        printf("\nUnknown command line parameter %s\n", argv[1]);
117        return 1;
118    }
119
120    // find counter definitions on command line, if any
121    if (argc > 2) {
122        for (i = 0; i < MAXCOUNTERS; i++) {
123            cnt = 0;
124            if (command == 2) cnt = 100;  // dummy value that is valid for all CPUs
125            if (i + 2 < argc) cnt = atoi(argv[i+2]);
126            CounterTypesDesired[i] = cnt;
127        }
128    }           
129
130    // Get mask of possible CPU cores
131    SyS::ProcMaskType ProcessAffMask = SyS::GetProcessMask();
132
133    // find all possible CPU cores
134    NumThreads = (int)sizeof(void*)*8;
135    if (NumThreads > 64) NumThreads = 64;
136
137    for (thread = 0; thread < NumThreads; thread++) {
138        if (SyS::TestProcessMask(thread, &ProcessAffMask)) {
139            ProcNum[thread] = thread;
140            countthreads++;
141        }
142        else {
143            ProcNum[thread] = -1;
144        }
145    }
146
147    // Lock processor number for each thread
148    MSRCounters.LockProcessor();
149
150    // Find counter defitions and put them in queue for driver
151    MSRCounters.QueueCounters();
152
153    // Install and load driver
154    int e = MSRCounters.StartDriver();
155    if (e) return e;
156
157    // Start MSR counters
158    for (thread = 0; thread < NumThreads; thread++) {
159        if (ProcNum[thread] >= 0) {
160
161#if defined(__unix__) || defined(__linux__)
162            // get desired processornumber
163            int ProcessorNumber = ProcNum[thread];
164            // Lock process to this processor number
165            SyS::SetProcessMask(ProcessorNumber);
166#else
167            // In Windows, the thread number needs only be fixed inside the driver
168#endif
169
170            if (command == 1) {
171                MSRCounters.StartCounters(thread);
172            }
173            else  {
174                MSRCounters.StopCounters(thread);
175            }
176        }
177    }
178
179    // Clean up driver
180    MSRCounters.CleanUp();
181
182    // print output
183    if (command == 1) {
184        printf("\nEnabled %i counters in each of %i CPU cores", NumCounters, countthreads);
185        printf("\n\nPMC number:   Counter name:");
186        for (i = 0; i < NumCounters; i++) {               
187            printf("\n0x%08X    %-10s ", Counters[i], MSRCounters.CounterNames[i]);
188        }
189    }
190    else {
191        printf("\nDisabled %i counters in each of %i CPU cores", NumCounters, countthreads);
192    }
193    printf("\n");
194    return 0;
195}
196
197
198//////////////////////////////////////////////////////////////////////
199//
200//        Main
201//
202//////////////////////////////////////////////////////////////////////
203int main(int argc, char* argv[]) {
204    int repi;                           // repetition counter
205    int i;                              // loop counter
206    int t;                              // thread counter
207    int e;                              // error number
208    int procthreads;                    // number of threads supported by processor
209
210    if (argc > 1) {
211        // not testing. setting or resetting PMC counters       
212        return setcounters(argc, argv);
213    }
214
215    // Limit number of threads
216    if (NumThreads > MAXTHREADS) {
217        NumThreads = MAXTHREADS;
218        printf("\nToo many threads");
219    }
220    if (NumThreads < 1) NumThreads = 1;
221
222    // Get mask of possible CPU cores
223    SyS::ProcMaskType ProcessAffMask = SyS::GetProcessMask();
224    // Count possible threads
225    for (procthreads = i = 0; i < MAXTHREADS; i++) {
226        if (SyS::TestProcessMask(i, &ProcessAffMask)) procthreads++;
227    }
228
229    // Fix a processornumber for each thread
230    for (t = 0, i = NumThreads-1; t < NumThreads; t++, i--) {
231        // make processornumbers different, and last thread = MainThreadProcNum:
232        // ProcNum[t] = MainThreadProcNum ^ i;
233        if (procthreads < 4) {       
234            ProcNum[t] = i;
235        }
236        else {       
237            ProcNum[t] = (i % 2) * (procthreads/2) + i / 2;
238        }
239        if (!SyS::TestProcessMask(ProcNum[t], &ProcessAffMask)) {
240            // this processor core is not available
241            printf("\nProcessor %i not available. Processors available:\n", ProcNum[t]);
242            for (int p = 0; p < MAXTHREADS; p++) {
243                if (SyS::TestProcessMask(p, &ProcessAffMask)) printf("%i  ", p);
244            }
245            printf("\n");
246            return 1;
247        }
248    }
249
250    // Make program and driver use the same processor number
251    MSRCounters.LockProcessor();
252
253    // Find counter defitions and put them in queue for driver
254    MSRCounters.QueueCounters();
255
256    // Install and load driver
257    e = MSRCounters.StartDriver();
258    if (e) return e;
259
260    // Set high priority to minimize risk of interrupts during test
261    SyS::SetProcessPriorityHigh();
262
263    // Make multiple threads
264    ThreadHandler Threads;
265    Threads.Start(NumThreads);
266
267    // Stop threads
268    Threads.Stop();
269
270    // Set priority back normal
271    SyS::SetProcessPriorityNormal();
272
273    // Clean up
274    MSRCounters.CleanUp();
275
276    // Print results
277    for (t = 0; t < NumThreads; t++) {
278        // calculate offsets into ThreadData[]
279        int TOffset = t * (ThreadDataSize / sizeof(int));
280        int ClockOS = ClockResultsOS / sizeof(int);
281        int PMCOS   = PMCResultsOS / sizeof(int);
282
283        // print column headings
284        printf("\nProcessor %i", ProcNum[t]);
285        printf("\n     Clock ");
286        if (UsePMC) {
287            for (i = 0; i < NumCounters; i++) {
288                printf("%10s ", MSRCounters.CounterNames[i]);
289            }
290        }
291        if (RatioOut[0]) printf("%10s ", RatioOutTitle ? RatioOutTitle : "Ratio");
292        if (TempOut) printf("%10s ", TempOutTitle ? TempOutTitle : "Extra out");
293
294        // print counter outputs
295        for (repi = 0; repi < repetitions; repi++) {
296            printf("\n%10i ", PThreadData[repi+TOffset+ClockOS]);
297            if (UsePMC) {
298                for (i = 0; i < NumCounters; i++) {         
299                    printf("%10i ", PThreadData[repi+i*repetitions+TOffset+PMCOS]);
300                }
301            }
302            // optional ratio output
303            if (RatioOut[0]) {
304                union {
305                    int i;
306                    float f;
307                } factor;
308                factor.i = RatioOut[3];
309                int a, b;
310                if (RatioOut[1] == 0) {
311                    a = PThreadData[repi+TOffset+ClockOS];
312                }
313                else if ((unsigned int)RatioOut[1] <= (unsigned int)NumCounters) {
314                    a = PThreadData[repi+(RatioOut[1]-1)*repetitions+TOffset+PMCOS];
315                }
316                else {
317                    a = 1;
318                }
319                if (RatioOut[2] == 0) {
320                    b = PThreadData[repi+TOffset+ClockOS];
321                }
322                else if ((unsigned int)RatioOut[2] <= (unsigned int)NumCounters) {
323                    b = PThreadData[repi+(RatioOut[2]-1)*repetitions+TOffset+PMCOS];
324                }
325                else {
326                    b = 1;
327                }
328                if (b == 0) {
329                    printf("%10s", "inf");
330                }
331                else if (RatioOut[0] == 1) {
332                    printf("%10i ", factor.i * a / b);
333                }
334                else {
335                    printf("%10.6f ", factor.f * (double)a / (double)b);
336                }
337            }
338            // optional arbitrary output
339            if (TempOut) {
340                union {
341                    int * pi;
342                    int64 * pl;
343                    float * pf;
344                    double * pd;
345                } pu;
346                pu.pi = PThreadData + repi + TOffset;      // pointer to CountTemp
347                if (TempOut & 1) pu.pi += repi;            // double size
348                switch (TempOut) {
349                case 2:    // int
350                    printf("%10i", *pu.pi);  break;
351                case 3:    // 64 bit int
352                    printf("%10lli", *pu.pl);  break;
353                case 4:    // hexadecimal int
354                    printf("0x%08X", *pu.pi);  break;
355                case 5:    // hexadecimal 64-bit int
356                    printf("0x%08X%08X", pu.pi[1], pu.pi[0]);  break;
357                case 6:    // float
358                    printf("%10.6f", *pu.pf);  break;
359                case 7:    // double
360                    printf("%10.6f", *pu.pd);  break;
361                default:
362                    printf("unknown TempOut %i", TempOut);
363                }
364            }
365        }
366    }
367
368    printf("\n");
369    // Optional: wait for key press
370    //printf("\npress any key");
371    //getch();
372
373    // Exit
374    return 0;
375}
376
377
378//////////////////////////////////////////////////////////////////////////////
379//
380//        CMSRInOutQue class member functions
381//
382//////////////////////////////////////////////////////////////////////////////
383
384// Constructor
385CMSRInOutQue::CMSRInOutQue() {
386    n = 0;
387    for (int i = 0; i < MAX_QUE_ENTRIES+1; i++) {
388        queue[i].msr_command = MSR_STOP;
389    }
390}
391
392// Put data record in queue
393int CMSRInOutQue::put (EMSR_COMMAND msr_command, unsigned int register_number,
394                       unsigned int value_lo, unsigned int value_hi) {
395
396                           if (n >= MAX_QUE_ENTRIES) return -10;
397
398                           queue[n].msr_command = msr_command;
399                           queue[n].register_number = register_number;
400                           queue[n].val[0] = value_lo;
401                           queue[n].val[1] = value_hi;
402                           n++;
403                           return 0;
404}
405
406
407//////////////////////////////////////////////////////////////////////////////
408//
409//        CCounters class member functions
410//
411//////////////////////////////////////////////////////////////////////////////
412
413// Constructor
414CCounters::CCounters() {
415    // Set everything to zero
416    MVendor = VENDOR_UNKNOWN;
417    MFamily = PRUNKNOWN;
418    MScheme = S_UNKNOWN;
419    NumPMCs = 0;
420    NumFixedPMCs = 0;
421    ProcessorNumber = 0;
422    for (int i = 0; i < MAXCOUNTERS; i++) CounterNames[i] = 0;
423}
424
425void CCounters::QueueCounters() {
426    // Put counter definitions in queue
427    int n = 0, CounterType; 
428    const char * err;
429    while (CounterDefinitions[n].ProcessorFamily || CounterDefinitions[n].CounterType) n++;
430    NumCounterDefinitions = n;
431
432    // Get processor information
433    GetProcessorVendor();               // get microprocessor vendor
434    GetProcessorFamily();               // get microprocessor family
435    GetPMCScheme();                     // get PMC scheme
436
437    if (UsePMC) {   
438        // Get all counter requests
439        for (int i = 0; i < MaxNumCounters; i++) {
440            CounterType = CounterTypesDesired[i];
441            err = DefineCounter(CounterType);
442            if (err) {
443                printf("\nCannot make counter %i. %s\n", i+1, err);
444            }
445        } 
446    }
447}
448
449void CCounters::LockProcessor() {
450    // Make program and driver use the same processor number if multiple processors
451    // Enable RDMSR instruction
452    int thread, procnum;
453
454    // We must lock the driver call to the desired processor number
455    for (thread = 0; thread < NumThreads; thread++) {
456        procnum = ProcNum[thread];
457        if (procnum >= 0) {
458            // lock driver to the same processor number as thread
459            queue1[thread].put(PROC_SET, 0, procnum);
460            queue2[thread].put(PROC_SET, 0, procnum);
461            // enable readpmc instruction (for this processor number)
462            queue1[thread].put(PMC_ENABLE, 0, 0);
463            // disable readpmc instruction after run
464            queue2[thread].put(PMC_DISABLE, 0, 0);
465        }
466    }
467}
468
469int CCounters::StartDriver() {
470    // Install and load driver
471    // return error code
472    int ErrNo = 0;
473
474    if (UsePMC) {
475        // Load driver
476        ErrNo = msr.LoadDriver();
477    }
478
479    return ErrNo;
480}
481
482void CCounters::CleanUp() {
483    // Any required cleanup of driver etc
484    // Optionally unload driver
485    //msr.UnloadDriver();
486    //msr.UnInstallDriver();
487}
488
489// put record into multiple start queues
490void CCounters::Put1 (int num_threads,
491    EMSR_COMMAND msr_command, unsigned int register_number,
492    unsigned int value_lo, unsigned int value_hi) {
493    for (int t = 0; t < num_threads; t++) {
494        queue1[t].put(msr_command, register_number, value_lo, value_hi);
495    }
496}
497
498// put record into multiple stop queues
499void CCounters::Put2 (int num_threads,
500    EMSR_COMMAND msr_command, unsigned int register_number,
501    unsigned int value_lo, unsigned int value_hi) {
502    for (int t = 0; t < num_threads; t++) {
503        queue2[t].put(msr_command, register_number, value_lo, value_hi);
504    }
505}
506
507// Start counting
508void CCounters::StartCounters(int ThreadNum) {
509    if (UsePMC) {
510        msr.AccessRegisters(queue1[ThreadNum]);
511    }
512}
513
514// Stop and reset counters
515void CCounters::StopCounters(int ThreadNum) {
516    if (UsePMC) {
517        msr.AccessRegisters(queue2[ThreadNum]);
518    }
519}
520
521void CCounters::GetProcessorVendor() {
522    // get microprocessor vendor
523    int CpuIdOutput[4];
524
525    // Call cpuid function 0
526    Cpuid(CpuIdOutput, 0);
527
528    // Interpret vendor string
529    MVendor = VENDOR_UNKNOWN;
530    if (CpuIdOutput[2] == 0x6C65746E) MVendor = INTEL;  // Intel "GenuineIntel"
531    if (CpuIdOutput[2] == 0x444D4163) MVendor = AMD;    // AMD   "AuthenticAMD"
532    if (CpuIdOutput[1] == 0x746E6543) MVendor = VIA;    // VIA   "CentaurHauls"
533}
534
535void CCounters::GetProcessorFamily() {
536    // get microprocessor family
537    int CpuIdOutput[4];
538    int Family, Model;
539
540    MFamily = PRUNKNOWN;                // default = unknown
541
542    // Call cpuid function 0
543    Cpuid(CpuIdOutput, 0);
544    if (CpuIdOutput[0] == 0) return;     // cpuid function 1 not supported
545
546    // call cpuid function 1 to get family and model number
547    Cpuid(CpuIdOutput, 1);
548    Family = ((CpuIdOutput[0] >> 8) & 0x0F) + ((CpuIdOutput[0] >> 20) & 0xFF);   // family code
549    Model  = ((CpuIdOutput[0] >> 4) & 0x0F) | ((CpuIdOutput[0] >> 12) & 0xF0);   // model code
550    // printf("\nCPU family 0x%X, model 0x%X\n", Family, Model);
551
552    if (MVendor == INTEL)  {
553        // Intel processor
554        if (Family <  5)    MFamily = PRUNKNOWN;           // less than Pentium
555        if (Family == 5)    MFamily = INTEL_P1MMX;         // pentium 1 or mmx
556        if (Family == 0x0F) MFamily = INTEL_P4;            // pentium 4 or other netburst
557        if (Family == 6) {
558            switch(Model) {  // list of known Intel families with different performance monitoring event tables
559            case 0x09case 0x0D:
560                MFamily = INTEL_PM;  break;                // Pentium M
561            case 0x0E:
562                MFamily = INTEL_CORE;  break;              // Core 1
563            case 0x0F: case 0x16:
564                MFamily = INTEL_CORE2;  break;             // Core 2, 65 nm
565            case 0x17: case 0x1D:
566                MFamily = INTEL_CORE2;  break;             // Core 2, 45 nm
567            case 0x1A: case 0x1E: case 0x1F: case 0x2E:
568                MFamily = INTEL_7;  break;                 // Nehalem
569            case 0x25: case 0x2C: case 0x2F:
570                MFamily = INTEL_7;  break;                 // Westmere
571            case 0x2A: case 0x2D:
572                MFamily = INTEL_IVY;  break;               // Sandy Bridge
573            case 0x3A: case 0x3E:
574                MFamily = INTEL_IVY;  break;               // Ivy Bridge
575            case 0x3C: case 0x3F: case 0x45: case 0x46:
576                MFamily = INTEL_HASW;  break;              // Haswell
577            case 0x3D: case 0x4F: case 0x56:
578                MFamily = INTEL_HASW;  break;              // Broadwell
579            // low power processors:
580            case 0x1C: case 0x26: case 0x27: case 0x35: case 0x36:
581                MFamily = INTEL_ATOM;  break;              // Atom
582            case 0x37: case 0x4A: case 0x4D:
583                MFamily = INTEL_SILV;  break;              // Silvermont
584            // unknown and future
585            default:
586                MFamily = INTEL_P23;                       // Pentium 2 or 3
587                if (Model >= 0x3C) MFamily = INTEL_HASW;   // Haswell
588            }
589        }
590    }
591
592    if (MVendor == AMD)  {
593        // AMD processor
594        MFamily = PRUNKNOWN;                               // old or unknown AMD
595        if (Family == 6)    MFamily = AMD_ATHLON;          // AMD Athlon
596        if (Family >= 0x0F && Family <= 0x14) {
597            MFamily = AMD_ATHLON64;                        // Athlon 64, Opteron, etc
598        }
599        if (Family >= 0x15) MFamily = AMD_BULLD;           // Family 15h
600    }
601
602    if (MVendor == VIA)  {
603        // VIA processor
604        if (Family == 6 && Model >= 0x0F) MFamily = VIA_NANO; // VIA Nano
605    }
606}
607
608void CCounters::GetPMCScheme() {
609    // get PMC scheme
610    // Default values
611    MScheme = S_UNKNOWN;
612    NumPMCs = 2;
613    NumFixedPMCs = 0;
614
615    if (MVendor == AMD)  {
616        // AMD processor
617        MScheme = S_AMD;
618        NumPMCs = 4;
619    }
620
621    if (MVendor == VIA)  {
622        // VIA processor
623        MScheme = S_VIA;
624    }
625
626    if (MVendor == INTEL)  {
627        // Intel processor
628        int CpuIdOutput[4];
629
630        // Call cpuid function 0
631        Cpuid(CpuIdOutput, 0);
632        if (CpuIdOutput[0] >= 0x0A) {
633            // PMC scheme defined by cpuid function A
634            Cpuid(CpuIdOutput, 0x0A);
635            if (CpuIdOutput[0] & 0xFF) {
636                MScheme = EPMCScheme(S_ID1 << ((CpuIdOutput[0] & 0xFF) - 1));
637                NumPMCs = (CpuIdOutput[0] >> 8) & 0xFF;
638                //NumFixedPMCs = CpuIdOutput[0] & 0x1F;
639                NumFixedPMCs = CpuIdOutput[3] & 0x1F;
640                // printf("\nCounters:\nMScheme = 0x%X, NumPMCs = %i, NumFixedPMCs = %i\n\n", MScheme, NumPMCs, NumFixedPMCs);
641            }
642        }
643
644        if (MScheme == S_UNKNOWN) {
645            // PMC scheme not defined by cpuid
646            switch (MFamily) {
647            case INTEL_P1MMX:
648                MScheme = S_P1; break;
649            case INTEL_P23: case INTEL_PM:
650                MScheme = S_P2; break;
651            case INTEL_P4:
652                MScheme = S_P4; break;
653            case INTEL_CORE:
654                MScheme = S_ID1; break;
655            case INTEL_CORE2:
656                MScheme = S_ID2; break;
657            case INTEL_7: case INTEL_ATOM: case INTEL_SILV:
658                MScheme = S_ID3; break;
659            }
660        }
661    }
662}
663
664// Request a counter setup
665// (return value is error message)
666const char * CCounters::DefineCounter(int CounterType) {
667    if (CounterType == 0) return NULL;
668    int i;
669    SCounterDefinition * p;
670
671    // Search for matching counter definition
672    for (i=0, p = CounterDefinitions; i < NumCounterDefinitions; i++, p++) {
673        if (p->CounterType == CounterType && (p->PMCScheme & MScheme) && (p->ProcessorFamily & MFamily)) {
674            // Match found
675            break;
676        }
677    }
678    if (i >= NumCounterDefinitions) return "No matching counter definition found"; // not found in list
679    return DefineCounter(*p);
680}
681
682// Request a counter setup
683// (return value is error message)
684const char * CCounters::DefineCounter(SCounterDefinition & CDef) {
685    int i, counternr, a, b, reg, eventreg, tag;
686    static int CountersEnabled = 0, FixedCountersEnabled = 0;
687
688    if ( !(CDef.ProcessorFamily & MFamily)) return "Counter not defined for present microprocessor family";
689    if (NumCounters >= MaxNumCounters) return "Too many counters";
690
691    if (CDef.CounterFirst & 0x40000000) { 
692        // Fixed function counter
693        counternr = CDef.CounterFirst;
694    }
695    else {
696        // check CounterLast
697        if (CDef.CounterLast < CDef.CounterFirst) {
698            CDef.CounterLast = CDef.CounterFirst;
699        }
700        if (CDef.CounterLast >= NumPMCs && (MScheme & S_INTL)) {
701        }   
702
703        // Find vacant counter
704        for (counternr = CDef.CounterFirst; counternr <= CDef.CounterLast; counternr++) {
705            // Check if this counter register is already in use
706            for (i = 0; i < NumCounters; i++) {
707                if (counternr == Counters[i]) {
708                    // This counter is already in use, find another
709                    goto USED;
710                }
711            }
712            if (MFamily == INTEL_P4) {
713                // Check if the corresponding event register ESCR is already in use
714                eventreg = GetP4EventSelectRegAddress(counternr, CDef.EventSelectReg); 
715                for (i = 0; i < NumCounters; i++) {
716                    if (EventRegistersUsed[i] == eventreg) {
717                        goto USED;
718                    }
719                }
720            }
721
722            // Vacant counter found. stop searching
723            break;
724
725        USED:;
726            // This counter is occupied. keep searching
727        }
728
729        if (counternr > CDef.CounterLast) {
730            // No vacant counter found
731            return "Counter registers are already in use";
732        }
733    }
734
735    // Vacant counter found. Save name   
736    CounterNames[NumCounters] = CDef.Description;
737
738    // Put MSR commands for this counter in queues
739    switch (MScheme) {
740
741    case S_P1:
742        // Pentium 1 and Pentium MMX
743        a = CDef.Event | (CDef.EventMask << 6);
744        if (counternr == 1) a = EventRegistersUsed[0] | (a << 16);
745        Put1(NumThreads, MSR_WRITE, 0x11, a);
746        Put2(NumThreads, MSR_WRITE, 0x11, 0);
747        Put1(NumThreads, MSR_WRITE, 0x12+counternr, 0);
748        Put2(NumThreads, MSR_WRITE, 0x12+counternr, 0);
749        EventRegistersUsed[0] = a;
750        break;
751
752    case S_ID2: case S_ID3:
753        // Intel Core 2 and later
754        if (counternr & 0x40000000) {
755            // This is a fixed function counter
756            if (!(FixedCountersEnabled++)) {
757                // Enable fixed function counters
758                for (a = i = 0; i < NumFixedPMCs; i++) {
759                    b = 2;  // 1=privileged level, 2=user level, 4=any thread
760                    a |= b << (4*i);
761                }
762                // Set MSR_PERF_FIXED_CTR_CTRL
763                Put1(NumThreads, MSR_WRITE, 0x38D, a); 
764                Put2(NumThreads, MSR_WRITE, 0x38D, 0);
765            }
766            break;
767        }
768        if (!(CountersEnabled++)) {
769            // Enable counters
770            a = (1 << NumPMCs) - 1;      // one bit for each pmc counter
771            b = (1 << NumFixedPMCs) - 1; // one bit for each fixed counter
772            // set MSR_PERF_GLOBAL_CTRL
773            Put1(NumThreads, MSR_WRITE, 0x38F, a, b);
774            Put2(NumThreads, MSR_WRITE, 0x38F, 0);
775        }
776        // All other counters continue in next case:
777
778    case S_P2: case S_ID1:
779        // Pentium Pro, Pentium II, Pentium III, Pentium M, Core 1, (Core 2 continued):
780
781
782        a = CDef.Event | (CDef.EventMask << 8) | (1 << 16) | (1 << 22);
783        if (MScheme == S_ID1) a |= (1 << 14);  // Means this core only
784        //if (MScheme == S_ID3) a |= (1 << 22);  // Means any thread in this core!
785
786        eventreg = 0x186 + counternr;             // IA32_PERFEVTSEL0,1,..
787        reg = 0xc1 + counternr;                   // IA32_PMC0,1,..
788        Put1(NumThreads, MSR_WRITE, eventreg, a);
789        Put2(NumThreads, MSR_WRITE, eventreg, 0);
790        Put1(NumThreads, MSR_WRITE, reg, 0);
791        Put2(NumThreads, MSR_WRITE, reg, 0);
792        break;
793
794    case S_P4:
795        // Pentium 4 and Pentium 4 with EM64T
796        // ESCR register
797        eventreg = GetP4EventSelectRegAddress(counternr, CDef.EventSelectReg); 
798        tag = 1;
799        a = 0x1C | (tag << 5) | (CDef.EventMask << 9) | (CDef.Event << 25);
800        Put1(NumThreads, MSR_WRITE, eventreg, a);
801        Put2(NumThreads, MSR_WRITE, eventreg, 0);
802        // Remember this event register is used
803        EventRegistersUsed[NumCounters] = eventreg;
804        // CCCR register
805        reg = counternr + 0x360;
806        a = (1 << 12) | (3 << 16) | (CDef.EventSelectReg << 13);
807        Put1(NumThreads, MSR_WRITE, reg, a);
808        Put2(NumThreads, MSR_WRITE, reg, 0);
809        // Reset counter register
810        reg = counternr + 0x300;
811        Put1(NumThreads, MSR_WRITE, reg, 0);
812        Put2(NumThreads, MSR_WRITE, reg, 0);
813        // Set high bit for fast readpmc
814        counternr |= 0x80000000;
815        break;
816
817    case S_AMD:
818        // AMD Athlon, Athlon 64, Opteron
819        a = CDef.Event | (CDef.EventMask << 8) | (1 << 16) | (1 << 22);
820        eventreg = 0xc0010000 + counternr;
821        reg = 0xc0010004 + counternr;
822        Put1(NumThreads, MSR_WRITE, eventreg, a);
823        Put2(NumThreads, MSR_WRITE, eventreg, 0);
824        Put1(NumThreads, MSR_WRITE, reg, 0);
825        Put2(NumThreads, MSR_WRITE, reg, 0);
826        break;
827
828    case S_VIA:
829        // VIA Nano. Undocumented!
830        a = CDef.Event | (1 << 16) | (1 << 22);
831        eventreg = 0x186 + counternr;
832        reg = 0xc1 + counternr;
833        Put1(NumThreads, MSR_WRITE, eventreg, a);
834        Put2(NumThreads, MSR_WRITE, eventreg, 0);
835        Put1(NumThreads, MSR_WRITE, reg, 0);
836        Put2(NumThreads, MSR_WRITE, reg, 0);
837        break;
838
839    default:
840        return "No counters defined for present microprocessor family";
841    }
842
843    // Save counter register number in Counters list
844    Counters[NumCounters++] = counternr;
845
846    return NULL; // NULL = success
847}
848
849
850// Translate event select register number to register address for P4 processor
851int CCounters::GetP4EventSelectRegAddress(int CounterNr, int EventSelectNo) {
852    // On Pentium 4 processors, the Event Select Control Registers (ESCR) are
853    // identified in a very confusing way. Each ESCR has both an ESCRx-number which
854    // is part of its name, an event select number to specify in the Counter
855    // Configuration Control Register (CCCR), and a register address to specify
856    // in the WRMSR instruction.
857    // This function gets the register address based on table 15-6 in Intel manual
858    // 25366815, IA-32 Intel Architecture Software Developer's Manual Volume 3:
859    // System Programming Guide, 2005.
860    // Returns -1 if error.
861    static int TranslationTables[4][8] = {
862        {0x3B2, 0x3B4, 0x3AA, 0x3B6, 0x3AC, 0x3C8, 0x3A2, 0x3A0}, // counter 0-3
863        {0x3C0, 0x3C4, 0x3C2,    -1,    -1,    -1,    -1,    -1}, // counter 4-7
864        {0x3A6, 0x3A4, 0x3AE, 0x3B0,    -1, 0x3A8,    -1,    -1}, // counter 8-11
865        {0x3BA, 0x3CA, 0x3BC, 0x3BE, 0x3B8, 0x3CC, 0x3E0,    -1}};// counter 12-17
866
867        unsigned int n = CounterNr;
868        if (n > 17) return -1;
869        if (n > 15) n -= 3;
870        if ((unsigned int)EventSelectNo > 7) return -1;
871
872        int a = TranslationTables[n/4][EventSelectNo];
873        if (a < 0) return a;
874        if (n & 2) a++;
875        return a;
876}
877
878
879//////////////////////////////////////////////////////////////////////////////
880//
881//             list of counter definitions
882//
883//////////////////////////////////////////////////////////////////////////////
884// How to add new entries to this list:
885//
886// Warning: Be sure to save backup copies of your files before you make any
887// changes here. A wrong register number can result in a crash in the driver.
888// This results in a blue screen and possibly loss of your most recently
889// modified file.
890//
891// Set CounterType to any vacant id number. Use the same id for similar events
892// in different processor families. The other fields depend on the processor
893// family as follows:
894//
895// Pentium 1 and Pentium MMX:
896//    Set ProcessorFamily = INTEL_P1MMX.
897//    CounterFirst = 0, CounterLast = 1, Event = Event number,
898//    EventMask = Counter control code.
899//
900// Pentium Pro, Pentium II, Pentium III, Pentium M, Core Solo/Duo
901//    Set ProcessorFamily = INTEL_P23M for events that are valid for all these
902//    processors or INTEL_PM or INTEL_CORE for events that only apply to
903//    one processor.
904//    CounterFirst = 0, CounterLast = 1,
905//    Event = Event number, EventMask = Unit mask.
906//
907// Core 2
908//    Set ProcessorFamily = INTEL_CORE2.
909//    Fixed function counters:
910//    CounterFirst = 0x40000000 + MSR Address - 0x309. (Intel manual Oct. 2006 is wrong)
911//    All other counters:
912//    CounterFirst = 0, CounterLast = 1,
913//    Event = Event number, EventMask = Unit mask.
914//
915// Pentium 4 and Pentium 4 with EM64T (Netburst):
916//    Set ProcessorFamily = INTEL_P4.
917//    Look in Software Developer's Manual vol. 3 appendix A, table of
918//    Performance Monitoring Events.
919//    Set CounterFirst and CounterLast to the range of possible counter
920//    registers listed under "Counter numbers per ESCR".
921//    Set EventSelectReg to the value listed for "CCCR Select".
922//    Set Event to the value indicated for "ESCR Event Select".
923//    Set EventMask to a combination of the relevant bits for "ESCR Event Mask".
924//    You don't need the table named "Performance Counter MSRs and Associated
925//    CCCR and ESCR MSRs". This table is already implemented in the function
926//    CCounters::GetP4EventSelectRegAddress.
927//
928// AMD Athlon 64, Opteron
929//    Set ProcessorFamily = AMD_ATHLON64.
930//    CounterFirst = 0, CounterLast = 3, Event = Event mask,
931//    EventMask = Unit mask.
932//
933
934SCounterDefinition CounterDefinitions[] = {
935    //  id   scheme cpu    countregs eventreg event  mask   name
936    {100,  S_P4, PRALL,  4,   7,     0,      9,      7,  "Uops"     }, // uops from any source
937    {101,  S_P4, PRALL,  4,   7,     0,      9,      2,  "UopsTC"   }, // uops from trace cache
938    {102,  S_P4, PRALL,  4,   7,     0,      9,      1,  "UopsDec"  }, // uops directly from decoder
939    {103,  S_P4, PRALL,  4,   7,     0,      9,      4,  "UopsMCode"}, // uops from microcode ROM
940    {110,  S_P4, PRALL, 12,  17,     4,      1,      1,  "UopsNB"   }, // uops non-bogus
941    {111,  S_P4, PRALL, 12,  17,     4,      2,   0x0c,  "UopsBogus"}, // uops bogus
942    {150,  S_P4, PRALL,  8,  11,     1,      4, 0x8000,  "UopsFP"   }, // uops floating point, except move etc.
943    {151,  S_P4, PRALL,  8,  11,     1,   0x2e,      8,  "UopsFPMov"}, // uops floating point and SIMD move
944    {152,  S_P4, PRALL,  8,  11,     1,   0x2e,   0x10,  "UopsFPLd" }, // uops floating point and SIMD load
945    {160,  S_P4, PRALL,  8,  11,     1,      2, 0x8000,  "UopsMMX"  }, // uops 64-bit MMX
946    {170,  S_P4, PRALL,  8,  11,     1,   0x1a, 0x8000,  "UopsXMM"  }, // uops 128-bit integer XMM
947    {200,  S_P4, PRALL, 12,  17,     5,      6,   0x0f,  "Branch"   }, // branches
948    {201,  S_P4, PRALL, 12,  17,     5,      6,   0x0c,  "BrTaken"  }, // branches taken
949    {202,  S_P4, PRALL, 12,  17,     5,      6,   0x03,  "BrNTaken" }, // branches not taken
950    {203,  S_P4, PRALL, 12,  17,     5,      6,   0x05,  "BrPredict"}, // branches predicted
951    {204,  S_P4, PRALL, 12,  17,     4,      3,   0x01,  "BrMispred"}, // branches mispredicted
952    {210,  S_P4, PRALL,  4,   7,     2,      5,   0x02,  "CondJMisp"}, // conditional jumps mispredicted
953    {211,  S_P4, PRALL,  4,   7,     2,      5,   0x04,  "CallMisp" }, // indirect call mispredicted
954    {212,  S_P4, PRALL,  4,   7,     2,      5,   0x08,  "RetMisp"  }, // return mispredicted
955    {220,  S_P4, PRALL,  4,   7,     2,      5,   0x10,  "IndirMisp"}, // indirect calls, jumps and returns mispredicted
956    {310,  S_P4, PRALL,  0,   3,     0,      3,   0x01,  "TCMiss"   }, // trace cache miss
957    {320,  S_P4, PRALL,  0,   3,     7,   0x0c,  0x100,  "Cach2Miss"}, // level 2 cache miss
958    {321,  S_P4, PRALL,  0,   3,     7,   0x0c,  0x200,  "Cach3Miss"}, // level 3 cache miss
959    {330,  S_P4, PRALL,  0,   3,     3,   0x18,   0x02,  "ITLBMiss" }, // instructions TLB Miss
960    {340,  S_P4, PRALL,  0,   3,     2,      3,   0x3a,  "LdReplay" }, // memory load replay
961
962
963    //  id   scheme cpu    countregs eventreg event  mask   name
964    {  9,  S_P1, PRALL,  0,   1,     0,   0x16,        2,  "Instruct" }, // instructions executed
965    { 11,  S_P1, PRALL,  0,   1,     0,   0x17,        2,  "InstVpipe"}, // instructions executed in V-pipe
966    {202,  S_P1, PRALL,  0,   1,     0,   0x15,        2,  "Flush"    }, // pipeline flush due to branch misprediction or serializing event   
967    {310,  S_P1, PRALL,  0,   1,     0,   0x0e,        2,  "CodeMiss" }, // code cache miss
968    {311,  S_P1, PRALL,  0,   1,     0,   0x29,        2,  "DataMiss" }, // data cache miss
969
970
971    //  id   scheme  cpu     countregs eventreg event  mask   name
972    {  9, S_P2MC, PRALL,    0,   1,     0,   0xc0,     0,  "Instruct" }, // instructions executed
973    { 10, S_P2MC, PRALL,    0,   1,     0,   0xd0,     0,  "IDecode"  }, // instructions decoded
974    { 20, S_P2MC, PRALL,    0,   1,     0,   0x80,     0,  "IFetch"   }, // instruction fetches
975    { 21, S_P2MC, PRALL,    0,   1,     0,   0x86,     0,  "IFetchStl"}, // instruction fetch stall
976    { 22, S_P2MC, PRALL,    0,   1,     0,   0x87,     0,  "ILenStal" }, // instruction length decoder stalls
977    {100, S_P2MC, INTEL_PM, 0,   1,     0,   0xc2,     0,  "Uops(F)"  }, // microoperations in fused domain
978    {100, S_P2MC, PRALL,    0,   1,     0,   0xc2,     0,  "Uops"     }, // microoperations
979    {110, S_P2MC, INTEL_PM, 0,   1,     0,   0xa0,     0,  "Uops(UF)" }, // unfused microoperations submitted to execution units (Undocumented counter!)
980    {104, S_P2MC, INTEL_PM, 0,   1,     0,   0xda,     0,  "UopsFused"}, // fused uops
981    {115, S_P2MC, INTEL_PM, 0,   1,     0,   0xd3,     0,  "SynchUops"}, // stack synchronization uops
982    {121, S_P2MC, PRALL,    0,   1,     0,   0xd2,     0,  "PartRStl" }, // partial register access stall
983    {130, S_P2MC, PRALL,    0,   1,     0,   0xa2,     0,  "Rs Stall" }, // all resource stalls
984    {201, S_P2MC, PRALL,    0,   1,     0,   0xc9,     0,  "BrTaken"  }, // branches taken
985    {204, S_P2MC, PRALL,    0,   1,     0,   0xc5,     0,  "BrMispred"}, // mispredicted branches
986    {205, S_P2MC, PRALL,    0,   1,     0,   0xe6,     0,  "BTBMiss"  }, // static branch prediction made
987    {310, S_P2MC, PRALL,    0,   1,     0,   0x28,  0x0f,  "CodeMiss" }, // level 2 cache code fetch
988    {311, S_P2MC, INTEL_P23,0,   1,     0,   0x29,  0x0f,  "L1D Miss" }, // level 2 cache data fetch
989
990    // Core 2:
991    // The first three counters are fixed-function counters having their own register,
992    // The rest of the counters are competing for the same two counter registers.
993    //  id   scheme cpu      countregs eventreg event  mask   name
994    {1,   S_ID2, PRALL,   0x40000001,  0,0,   0,      0,   "Core cyc"  }, // core clock cycles
995    {2,   S_ID2, PRALL,   0x40000002,  0,0,   0,      0,   "Ref cyc"   }, // Reference clock cycles
996    {9,   S_ID2, PRALL,   0x40000000,  0,0,   0,      0,   "Instruct"  }, // Instructions (reference counter)
997    {10,  S_ID2, PRALL,   0,   1,     0,   0xc0,     0x0f, "Instruct"  }, // Instructions
998    {11,  S_ID2, PRALL,   0,   1,     0,   0xc0,     0x01, "Read inst" }, // Instructions involving read, fused count as one
999    {12,  S_ID2, PRALL,   0,   1,     0,   0xc0,     0x02, "Write ins" }, // Instructions involving write, fused count as one
1000    {13,  S_ID2, PRALL,   0,   1,     0,   0xc0,     0x04, "NonMem in" }, // Instructions without memory
1001    {20,  S_ID2, PRALL,   0,   1,     0,   0x80,      0,   "Insfetch"  }, // instruction fetches. < instructions ?
1002    {21,  S_ID2, PRALL,   0,   1,     0,   0x86,      0,   "IFetchStl" }, // instruction fetch stall
1003    {22,  S_ID2, PRALL,   0,   1,     0,   0x87,      0,   "ILenStal"  }, // instruction length decoder stalls (length changing prefix)
1004    {23,  S_ID2, PRALL,   0,   1,     0,   0x83,      0,   "IQue ful"  }, // instruction queue full
1005    {100, S_ID2, PRALL,   0,   1,     0,   0xc2,     0x0f, "Uops"      }, // uops retired, fused domain
1006    {101, S_ID2, PRALL,   0,   1,     0,   0xc2,     0x01, "Fused Rd"  }, // fused read uops
1007    {102, S_ID2, PRALL,   0,   1,     0,   0xc2,     0x02, "Fused Wrt" }, // fused write uops
1008    {103, S_ID2, PRALL,   0,   1,     0,   0xc2,     0x04, "Macrofus"  }, // macrofused uops
1009    {104, S_ID2, PRALL,   0,   1,     0,   0xc2,     0x07, "FusedUop"  }, // fused uops, all kinds
1010    {105, S_ID2, PRALL,   0,   1,     0,   0xc2,     0x08, "NotFusUop" }, // uops, not fused
1011    {110, S_ID2, PRALL,   0,   1,     0,   0xa0,        0, "Uops UFD"  }, // uops dispatched, unfused domain. Imprecise
1012    {111, S_ID2, PRALL,   0,   1,     0,   0xa2,        0, "res.stl."  }, // any resource stall
1013    {115, S_ID2, PRALL,   0,   1,     0,   0xab,     0x01, "SP synch"  }, // Stack synchronization uops
1014    {116, S_ID2, PRALL,   0,   1,     0,   0xab,     0x02, "SP engine" }, // Stack engine additions
1015    {121, S_ID2, PRALL,   0,   1,     0,   0xd2,     0x02, "Part.reg"  }, // Partial register synchronization, clock cycles
1016    {122, S_ID2, PRALL,   0,   1,     0,   0xd2,     0x04, "part.flag" }, // partial flags stall, clock cycles
1017    {123, S_ID2, PRALL,   0,   1,     0,   0xd2,     0x08, "FP SW stl" }, // floating point status word stall
1018    {130, S_ID2, PRALL,   0,   1,     0,   0xd2,     0x01, "R Rd stal" }, // ROB register read stall
1019    {140, S_ID2, PRALL,   0,   1,     0,   0x19,     0x00, "I2FP pass" }, // bypass delay to FP unit from int unit
1020    {141, S_ID2, PRALL,   0,   1,     0,   0x19,     0x01, "FP2I pass" }, // bypass delay to SIMD/int unit from fp unit (These counters cannot be used simultaneously)
1021    {150, S_ID2, PRALL,   0,   0,     0,   0xa1,     0x01, "uop p0"    }, // uops port 0. Can only use first counter
1022    {151, S_ID2, PRALL,   0,   0,     0,   0xa1,     0x02, "uop p1"    }, // uops port 1. Can only use first counter
1023    {152, S_ID2, PRALL,   0,   0,     0,   0xa1,     0x04, "uop p2"    }, // uops port 2. Can only use first counter
1024    {153, S_ID2, PRALL,   0,   0,     0,   0xa1,     0x08, "uop p3"    }, // uops port 3. Can only use first counter
1025    {154, S_ID2, PRALL,   0,   0,     0,   0xa1,     0x10, "uop p4"    }, // uops port 4. Can only use first counter
1026    {155, S_ID2, PRALL,   0,   0,     0,   0xa1,     0x20, "uop p5"    }, // uops port 5. Can only use first counter
1027    {201, S_ID2, PRALL,   0,   1,     0,   0xc4,     0x0c, "BrTaken"   }, // branches taken. (Mask: 1=pred.not taken, 2=mispred not taken, 4=pred.taken, 8=mispred taken)
1028    {204, S_ID2, PRALL,   0,   1,     0,   0xc4,     0x0a, "BrMispred" }, // mispredicted branches
1029    {205, S_ID2, PRALL,   0,   1,     0,   0xe6,      0,   "BTBMiss"   }, // static branch prediction made
1030    {210, S_ID2, PRALL,   0,   1,     0,   0x97,      0,   "BranchBu1" }, // branch taken bubble 1
1031    {211, S_ID2, PRALL,   0,   1,     0,   0x98,      0,   "BranchBu2" }, // branch taken bubble 2 (these two values must be added)
1032    {310, S_ID2, PRALL,   0,   1,     0,   0x28,     0x0f, "CodeMiss"  }, // level 2 cache code fetch
1033    {311, S_ID2, PRALL,   0,   1,     0,   0x29,     0x0f, "L1D Miss"  }, // level 2 cache data fetch
1034    {320, S_ID2, PRALL,   0,   1,     0,   0x24,     0x00, "L2 Miss"   }, // level 2 cache miss
1035
1036    // Nehalem, Sandy Bridge, Ivy Bridge
1037    // The first three counters are fixed-function counters having their own register,
1038    // The rest of the counters are competing for the same counter registers.
1039    // id   scheme  cpu       countregs eventreg event  mask   name
1040    {1,   S_ID3,  INTEL_7I,  0x40000001,  0,0,   0,      0,   "Core cyc"   }, // core clock cycles
1041    {2,   S_ID3,  INTEL_7I,  0x40000002,  0,0,   0,      0,   "Ref cyc"    }, // Reference clock cycles
1042    {9,   S_ID3,  INTEL_7I,  0x40000000,  0,0,   0,      0,   "Instruct"   }, // Instructions (reference counter)
1043    {10,  S_ID3,  INTEL_7I,  0,   3,     0,   0xc0,     0x01, "Instruct"   }, // Instructions
1044    {22,  S_ID3,  INTEL_7I,  0,   3,     0,   0x87,      0,   "ILenStal"   }, // instruction length decoder stalls (length changing prefix)
1045    {24,  S_ID3,  INTEL_7I,  0,   3,     0,   0xA8,     0x01, "Loop uops"  }, // uops from loop stream detector
1046    {25,  S_ID3,  INTEL_7I,  0,   3,     0,   0x79,     0x04, "Dec uops"   }, // uops from decoders. (MITE = Micro-instruction Translation Engine)
1047    {26,  S_ID3,  INTEL_7I,  0,   3,     0,   0x79,     0x08, "Cach uops"  }, // uops from uop cache. (DSB = Decoded Stream Buffer)
1048    {100, S_ID3,  INTEL_7I,  0,   3,     0,   0xc2,     0x01, "Uops"       }, // uops retired, unfused domain
1049    {103, S_ID3,  INTEL_7I,  0,   3,     0,   0xc2,     0x04, "Macrofus"   }, // macrofused uops, Sandy Bridge
1050    {104, S_ID3,  INTEL_7I,  0,   3,     0,   0x0E,     0x01, "Uops F.D."  }, // uops, fused domain, Sandy Bridge
1051    {105, S_ID3,  INTEL_7,   0,   3,     0,   0x0E,     0x02, "fused uop"  }, // microfused uops
1052    {110, S_ID3,  INTEL_7,   0,   3,     0,   0xa0,        0, "Uops UFD?"  }, // uops dispatched, unfused domain. Imprecise, Sandy Bridge
1053    {111, S_ID3,  INTEL_7I,  0,   3,     0,   0xa2,        1, "res.stl."   }, // any resource stall
1054    {121, S_ID3,  INTEL_7,   0,   3,     0,   0xd2,     0x02, "Part.reg"   }, // Partial register synchronization, clock cycles, Sandy Bridge
1055    {122, S_ID3,  INTEL_7,   0,   3,     0,   0xd2,     0x01, "part.flag"  }, // partial flags stall, clock cycles, Sandy Bridge
1056    {123, S_ID3,  INTEL_7,   0,   3,     0,   0xd2,     0x04, "R Rd stal"  }, // ROB register read stall, Sandy Bridge
1057    {124, S_ID3,  INTEL_7,   0,   3,     0,   0xd2,     0x0F, "RAT stal"   }, // RAT stall, any, Sandy Bridge
1058    {150, S_ID3,  INTEL_7,   0,   3,     0,   0xb1,     0x01, "uop p0"     }, // uops port 0.
1059    {151, S_ID3,  INTEL_7,   0,   3,     0,   0xb1,     0x02, "uop p1"     }, // uops port 1.
1060    {152, S_ID3,  INTEL_7,   0,   3,     0,   0xb1,     0x04, "uop p2"     }, // uops port 2.
1061    {153, S_ID3,  INTEL_7,   0,   3,     0,   0xb1,     0x08, "uop p3"     }, // uops port 3.
1062    {154, S_ID3,  INTEL_7,   0,   3,     0,   0xb1,     0x10, "uop p4"     }, // uops port 4.
1063    {155, S_ID3,  INTEL_7,   0,   3,     0,   0xb1,     0x20, "uop p5"     }, // uops port 5.
1064    {156, S_ID3,  INTEL_7,   0,   3,     0,   0xb1,     0x40, "uop p015"   }, // uops port 0,1,5.
1065    {157, S_ID3,  INTEL_7,   0,   3,     0,   0xb1,     0x80, "uop p234"   }, // uops port 2,3,4.
1066    {201, S_ID2,  INTEL_IVY, 0,   1,     0,   0xc4,     0x20, "BrTaken"    }, // branches taken. (Mask: 1=pred.not taken, 2=mispred not taken, 4=pred.taken, 8=mispred taken)
1067    {204, S_ID3,  INTEL_7,   0,   3,     0,   0xc5,     0x0a, "BrMispred"  }, // mispredicted branches
1068    {207, S_ID3,  INTEL_7I,  0,   3,     0,   0xc5,     0x0,  "BrMispred"  }, // mispredicted branches
1069    {205, S_ID3,  INTEL_7,   0,   3,     0,   0xe6,      2,   "BTBMiss"    }, // static branch prediction made, Sandy Bridge
1070    {220, S_ID3,  INTEL_IVY, 0,   3,     0,   0x58,     0x03, "Mov elim"   }, // register moves eliminated
1071    {221, S_ID3,  INTEL_IVY, 0,   3,     0,   0x58,     0x0C, "Mov elim-"  }, // register moves elimination unsuccessful
1072    {311, S_ID3,  INTEL_7I,  0,   3,     0,   0x28,     0x0f, "L1D Miss"   }, // level 1 data cache miss
1073    {312, S_ID3,  INTEL_7,   0,   3,     0,   0x24,     0x0f, "L1 Miss"    }, // level 2 cache requests
1074    {150, S_ID3,  INTEL_IVY, 0,   3,     0,   0xa1,     0x01, "uop p0"     }, // uops port 0
1075    {151, S_ID3,  INTEL_IVY, 0,   3,     0,   0xa1,     0x02, "uop p1"     }, // uops port 1
1076    {152, S_ID3,  INTEL_IVY, 0,   3,     0,   0xa1,     0x0c, "uop p2"     }, // uops port 2
1077    {153, S_ID3,  INTEL_IVY, 0,   3,     0,   0xa1,     0x30, "uop p3"     }, // uops port 3
1078    {154, S_ID3,  INTEL_IVY, 0,   3,     0,   0xa1,     0x40, "uop p4"     }, // uops port 4
1079    {155, S_ID3,  INTEL_IVY, 0,   3,     0,   0xa1,     0x80, "uop p5"     }, // uops port 5
1080    {160, S_ID3,  INTEL_IVY, 0,   3,     0,   0xa1,     0xFF, "uop p05"    }, // uops port 0-5
1081
1082    // Haswell
1083    // The first three counters are fixed-function counters having their own register,
1084    // The rest of the counters are competing for the same four counter registers.
1085    // id   scheme  cpu       countregs eventreg event  mask   name
1086    {1,   S_ID3,  INTEL_HASW, 0x40000001,  0,0,   0,     0,   "Core cyc"   }, // core clock cycles
1087    {2,   S_ID3,  INTEL_HASW, 0x40000002,  0,0,   0,     0,   "Ref cyc"    }, // Reference clock cycles
1088    {9,   S_ID3,  INTEL_HASW, 0x40000000,  0,0,   0,     0,   "Instruct"   }, // Instructions (reference counter)
1089    {10,  S_ID3,  INTEL_HASW, 0,  3,     0,   0xc0,     0x01, "Instruct"   }, // Instructions
1090    {22,  S_ID3,  INTEL_HASW, 0,  3,     0,   0x87,     0x01, "ILenStal"   }, // instruction length decoder stall due to length changing prefix
1091    {24,  S_ID3,  INTEL_HASW, 0,  3,     0,   0xA8,     0x01, "Loop uops"  }, // uops from loop stream detector
1092    {25,  S_ID3,  INTEL_HASW, 0,  3,     0,   0x79,     0x04, "Dec uops"   }, // uops from decoders. (MITE = Micro-instruction Translation Engine)
1093    {26,  S_ID3,  INTEL_HASW, 0,  3,     0,   0x79,     0x08, "Cach uops"  }, // uops from uop cache. (DSB = Decoded Stream Buffer)
1094    {100, S_ID3,  INTEL_HASW, 0,  3,     0,   0xc2,     0x01, "Uops"       }, // uops retired, unfused domain
1095    {104, S_ID3,  INTEL_HASW, 0,  3,     0,   0x0e,     0x01, "uops RAT"   }, // uops from RAT to RS
1096    {111, S_ID3,  INTEL_HASW, 0,  3,     0,   0xa2,     0x01, "res.stl."   }, // any resource stall
1097    {131, S_ID3,  INTEL_HASW, 0,  3,     0,   0xC1,     0x18, "AVX trans"  }, // VEX - non-VEX transition penalties
1098    {201, S_ID3,  INTEL_HASW, 0,  3,     0,   0xC4,     0x20, "BrTaken"    }, // branches taken
1099    {207, S_ID3,  INTEL_HASW, 0,  3,     0,   0xc5,     0x00, "BrMispred"  }, // mispredicted branches
1100    {220, S_ID3,  INTEL_HASW, 0,  3,     0,   0x58,     0x03, "Mov elim"   }, // register moves eliminated
1101    {221, S_ID3,  INTEL_HASW, 0,  3,     0,   0x58,     0x0C, "Mov elim-"  }, // register moves elimination unsuccessful
1102    {310, S_ID2,  INTEL_HASW, 0,  3,     0,   0x80,     0x02, "CodeMiss"   }, // code cache misses
1103    {311, S_ID3,  INTEL_HASW, 0,  3,     0,   0x24,     0xe1, "L1D Miss"   }, // level 1 data cache miss
1104    {320, S_ID3,  INTEL_HASW, 0,  3,     0,   0x24,     0x27, "L2 Miss"    }, // level 2 cache misses
1105    {150, S_ID3,  INTEL_HASW, 0,  3,     0,   0xa1,     0x01, "uop p0"     }, // uops port 0.
1106    {151, S_ID3,  INTEL_HASW, 0,  3,     0,   0xa1,     0x02, "uop p1"     }, // uops port 1.
1107    {152, S_ID3,  INTEL_HASW, 0,  3,     0,   0xa1,     0x04, "uop p2"     }, // uops port 2.
1108    {153, S_ID3,  INTEL_HASW, 0,  3,     0,   0xa1,     0x08, "uop p3"     }, // uops port 3.
1109    {154, S_ID3,  INTEL_HASW, 0,  3,     0,   0xa1,     0x10, "uop p4"     }, // uops port 4.
1110    {155, S_ID3,  INTEL_HASW, 0,  3,     0,   0xa1,     0x20, "uop p5"     }, // uops port 5.
1111    {156, S_ID3,  INTEL_HASW, 0,  3,     0,   0xa1,     0x40, "uop p6"     }, // uops port 6.
1112    {157, S_ID3,  INTEL_HASW, 0,  3,     0,   0xa1,     0x80, "uop p7"     }, // uops port 7.
1113    {160, S_ID3,  INTEL_HASW, 0,  3,     0,   0xa1,     0xFF, "uop p07"    }, // uops port 0-7
1114
1115    // Intel Atom:
1116    // The first counter is fixed-function counter having its own register,
1117    // The rest of the counters are competing for the same two counter registers.
1118    //  id   scheme  cpu         countregs eventreg event  mask   name
1119    {9,   S_ID3, INTEL_ATOM,  0x40000000, 0,0,    0,      0,   "Instruct"   }, // Instructions (reference counter)
1120    {10,  S_ID3, INTEL_ATOM,  0,   1,     0,   0xc0,     0x00, "Instr"      }, // Instructions retired
1121    {20,  S_ID3, INTEL_ATOM,  0,   1,     0,   0x80,     0x03, "Insfetch"   }, // instruction fetches
1122    {21,  S_ID3, INTEL_ATOM,  0,   1,     0,   0x80,     0x02, "I miss"     }, // instruction cache miss
1123    {30,  S_ID3, INTEL_ATOM,  0,   1,     0,   0x40,     0x21, "L1 read"    }, // L1 data cache read
1124    {31,  S_ID3, INTEL_ATOM,  0,   1,     0,   0x40,     0x22, "L1 write"   }, // L1 data cache write
1125    {100, S_ID3, INTEL_ATOM,  0,   1,     0,   0xc2,     0x10, "Uops"       }, // uops retired
1126    {200, S_ID3, INTEL_ATOM,  0,   1,     0,   0xc4,     0x00, "Branch"     }, // branches
1127    {201, S_ID3, INTEL_ATOM,  0,   1,     0,   0xc4,     0x0c, "BrTaken"    }, // branches taken. (Mask: 1=pred.not taken, 2=mispred not taken, 4=pred.taken, 8=mispred taken)
1128    {204, S_ID3, INTEL_ATOM,  0,   1,     0,   0xc4,     0x0a, "BrMispred"  }, // mispredicted branches
1129    {205, S_ID3, INTEL_ATOM,  0,   1,     0,   0xe6,     0x01, "BTBMiss"    }, // Baclear
1130    {310, S_ID3, INTEL_ATOM,  0,   1,     0,   0x28,     0x4f, "CodeMiss"   }, // level 2 cache code fetch
1131    {311, S_ID3, INTEL_ATOM,  0,   1,     0,   0x29,     0x4f, "L1D Miss"   }, // level 2 cache data fetch
1132    {320, S_ID3, INTEL_ATOM,  0,   1,     0,   0x24,     0x00, "L2 Miss"    }, // level 2 cache miss
1133    {501, S_ID3, INTEL_ATOM,  0,   1,     0,   0xC0,     0x00, "inst re"    }, // instructions retired
1134    {505, S_ID3, INTEL_ATOM,  0,   1,     0,   0xAA,     0x02, "CISC"       }, // CISC macro instructions decoded
1135    {506, S_ID3, INTEL_ATOM,  0,   1,     0,   0xAA,     0x03, "decoded"    }, // all instructions decoded
1136    {601, S_ID3, INTEL_ATOM,  0,   1,     0,   0x02,     0x81, "st.forw"    }, // Successful store forwards
1137    {640, S_ID3, INTEL_ATOM,  0,   1,     0,   0x12,     0x81, "mul"        }, // Int and FP multiply operations
1138    {641, S_ID3, INTEL_ATOM,  0,   1,     0,   0x13,     0x81, "div"        }, // Int and FP divide and sqrt operations
1139    {651, S_ID3, INTEL_ATOM,  0,   1,     0,   0x10,     0x81, "fp uop"     }, // Floating point uops
1140
1141    // Silvermont
1142    // The first three counters are fixed-function counters having their own register,
1143    // The rest of the counters are competing for the same two counter registers.
1144    //id  scheme  cpu       countregs eventreg event  mask   name
1145    {1,   S_ID3,  INTEL_SILV, 0x40000001,  0,0,   0,     0,   "Core cyc"   }, // core clock cycles
1146    {2,   S_ID3,  INTEL_SILV, 0x40000002,  0,0,   0,     0,   "Ref cyc"    }, // Reference clock cycles
1147    {9,   S_ID3,  INTEL_SILV, 0x40000000,  0,0,   0,     0,   "Instruct"   }, // Instructions (reference counter)
1148    {100, S_ID3,  INTEL_SILV, 0,  1,     0,   0xc2,     0x10, "Uops"       }, // uops retired
1149    {103, S_ID3,  INTEL_SILV, 0,  1,     0,   0xc2,     0x01, "Uop micr"   }, // uops from microcode rom
1150    {111, S_ID3,  INTEL_SILV, 0,  1,     0,   0xc3,     0x08, "stall"      }, // any stall
1151    {150, S_ID3,  INTEL_SILV, 0,  1,     0,   0xCB,     0x02, "p0i full"   }, // port 0 integer pipe full
1152    {151, S_ID3,  INTEL_SILV, 0,  1,     0,   0xCB,     0x04, "p1i full"   }, // port 1 integer pipe full
1153    {152, S_ID3,  INTEL_SILV, 0,  1,     0,   0xCB,     0x08, "p0f full"   }, // port 0 f.p. pipe full
1154    {153, S_ID3,  INTEL_SILV, 0,  1,     0,   0xCB,     0x10, "p1f full"   }, // port 1 f.p. pipe full
1155    {158, S_ID3,  INTEL_SILV, 0,  1,     0,   0xCB,     0x01, "mec full"   }, // memory execution cluster pipe full
1156    {201, S_ID3,  INTEL_SILV, 0,  1,     0,   0xC4,     0xFE, "BrPrTak"    }, // branches predicted taken
1157    {202, S_ID3,  INTEL_SILV, 0,  1,     0,   0xC5,     0xFE, "BrMprNT"    }, // branches not taken mispredicted
1158    {207, S_ID3,  INTEL_SILV, 0,  1,     0,   0xc5,     0x00, "BrMispred"  }, // mispredicted branches
1159    {209, S_ID3,  INTEL_SILV, 0,  1,     0,   0xe6,     0x01, "BACLEAR"    }, // early prediction corrected by later prediction
1160    {310, S_ID2,  INTEL_SILV, 0,  1,     0,   0x80,     0x02, "CodeMiss"   }, // code cache misses
1161    {311, S_ID3,  INTEL_SILV, 0,  1,     0,   0x04,     0x01, "L1D LMis"   }, // level 1 data cache load miss
1162    {320, S_ID3,  INTEL_SILV, 0,  1,     0,   0x2E,     0x41, "L2 Miss"    }, // level 2 cache misses
1163
1164
1165    //  id   scheme  cpu         countregs eventreg event  mask   name
1166    {  9, S_AMD, AMD_ALL,      0,   3,     0,   0xc0,      0,  "Instruct" }, // x86 instructions executed
1167    {100, S_AMD, AMD_ALL,      0,   3,     0,   0xc1,      0,  "Uops"     }, // microoperations
1168    {204, S_AMD, AMD_ALL,      0,   3,     0,   0xc3,      0,  "BrMispred"}, // mispredicted branches
1169    {201, S_AMD, AMD_BULLD,    0,   3,     0,   0xc4,   0x00,  "BrTaken"  }, // branches taken
1170    {209, S_AMD, AMD_BULLD,    0,   3,     0,   0xc2,   0x00,  "RSBovfl"  }, // return stack buffer overflow
1171    {310, S_AMD, AMD_ALL,      0,   3,     0,   0x81,      0,  "CodeMiss" }, // instruction cache misses
1172    {311, S_AMD, AMD_ALL,      0,   3,     0,   0x41,      0,  "L1D Miss" }, // L1 data cache misses
1173    {320, S_AMD, AMD_ALL,      0,   3,     0,   0x43,   0x1f,  "L2 Miss"  }, // L2 cache misses
1174    {150, S_AMD, AMD_ATHLON64, 0,   3,     0,   0x00,   0x3f,  "UopsFP"   }, // microoperations in FP pipe
1175    {151, S_AMD, AMD_ATHLON64, 0,   3,     0,   0x00,   0x09,  "FPADD"    }, // microoperations in FP ADD unit
1176    {152, S_AMD, AMD_ATHLON64, 0,   3,     0,   0x00,   0x12,  "FPMUL"    }, // microoperations in FP MUL unit
1177    {153, S_AMD, AMD_ATHLON64, 0,   3,     0,   0x00,   0x24,  "FPMISC"   }, // microoperations in FP Store unit
1178    {150, S_AMD, AMD_BULLD,    3,   3,     0,   0x00,   0x01,  "UopsFP0"  }, // microoperations in FP pipe 0
1179    {151, S_AMD, AMD_BULLD,    3,   3,     0,   0x00,   0x02,  "UopsFP1"  }, // microoperations in FP pipe 1
1180    {152, S_AMD, AMD_BULLD,    3,   3,     0,   0x00,   0x04,  "UopsFP2"  }, // microoperations in FP pipe 2
1181    {153, S_AMD, AMD_BULLD,    3,   3,     0,   0x00,   0x08,  "UopsFP3"  }, // microoperations in FP pipe 3
1182    {110, S_AMD, AMD_BULLD,    0,   3,     0,   0x04,   0x0a,  "UopsElim" }, // move eliminations and scalar op optimizations
1183    {120, S_AMD, AMD_BULLD,    0,   3,     0,   0x2A,   0x01,  "Forwfail" }, // load-to-store forwarding failed
1184    {160, S_AMD, AMD_BULLD,    0,   3,     0,   0xCB,   0x01,  "x87"      }, // FP x87 instructions
1185    {161, S_AMD, AMD_BULLD,    0,   3,     0,   0xCB,   0x02,  "MMX"      }, // MMX instructions
1186    {162, S_AMD, AMD_BULLD,    0,   3,     0,   0xCB,   0x04,  "XMM"      }, // XMM and YMM instructions
1187
1188    // VIA Nano counters are undocumented
1189    // These are the ones I have found that counts. Most have unknown purpose
1190    //  id      scheme cpu    countregs eventreg event  mask   name
1191    {0x1000, S_VIA, PRALL,   0,   1,     0,   0x000,    0,  "Instr" }, // Instructions
1192    {0x0001, S_VIA, PRALL,   0,   1,     0,   0x001,    0,  "uops"  }, // micro-ops?
1193    {0x0002, S_VIA, PRALL,   0,   1,     0,   0x002,    0,  "2"     }, //
1194    {0x0003, S_VIA, PRALL,   0,   1,     0,   0x003,    0,  "3"     }, //
1195    {0x0004, S_VIA, PRALL,   0,   1,     0,   0x004,    0,  "bubble"}, // Branch bubble clock cycles?
1196    {0x0005, S_VIA, PRALL,   0,   1,     0,   0x005,    0,  "5"     }, //
1197    {0x0006, S_VIA, PRALL,   0,   1,     0,   0x006,    0,  "6"     }, //
1198    {0x0007, S_VIA, PRALL,   0,   1,     0,   0x007,    0,  "7"     }, //
1199    {0x0008, S_VIA, PRALL,   0,   1,     0,   0x008,    0,  "8"     }, //
1200    {0x0009, S_VIA, PRALL,   0,   1,     0,   0x000,    0,  "Instr" }, // Instructions
1201    {0x0010, S_VIA, PRALL,   0,   1,     0,   0x010,    0,  "10"    }, //
1202    {0x0014, S_VIA, PRALL,   0,   1,     0,   0x014,    0,  "14"    }, //
1203    {0x0020, S_VIA, PRALL,   0,   1,     0,   0x020,    0,  "Br NT" }, // Branch not taken
1204    {0x0021, S_VIA, PRALL,   0,   1,     0,   0x021,    0,  "Br NT Pr"}, // Branch not taken, predicted
1205    {0x0022, S_VIA, PRALL,   0,   1,     0,   0x022,    0,  "Br Tk"   }, // Branch taken
1206    {0x0023, S_VIA, PRALL,   0,   1,     0,   0x023,    0,  "Br Tk Pr"}, // Branch taken, predicted
1207    {0x0024, S_VIA, PRALL,   0,   1,     0,   0x024,    0,  "Jmp"    }, // Jump or call
1208    {0x0025, S_VIA, PRALL,   0,   1,     0,   0x025,    0,  "Jmp"    }, // Jump or call, predicted
1209    {0x0026, S_VIA, PRALL,   0,   1,     0,   0x026,    0,  "Ind.Jmp"}, // Indirect jump or return
1210    {0x0027, S_VIA, PRALL,   0,   1,     0,   0x027,    0,  "Ind.J. Pr"}, // Indirect jump or return, predicted
1211    {0x0034, S_VIA, PRALL,   0,   1,     0,   0x034,    0,  "34"    }, //
1212    {0x0040, S_VIA, PRALL,   0,   1,     0,   0x040,    0,  "40"    }, //
1213    {0x0041, S_VIA, PRALL,   0,   1,     0,   0x040,    0,  "41"    }, //
1214    {0x0042, S_VIA, PRALL,   0,   1,     0,   0x040,    0,  "42"    }, //
1215    {0x0043, S_VIA, PRALL,   0,   1,     0,   0x040,    0,  "43"    }, //
1216    {0x0044, S_VIA, PRALL,   0,   1,     0,   0x040,    0,  "44"    }, //
1217    {0x0046, S_VIA, PRALL,   0,   1,     0,   0x040,    0,  "46"    }, //
1218    {0x0048, S_VIA, PRALL,   0,   1,     0,   0x040,    0,  "48"    }, //
1219    {0x0082, S_VIA, PRALL,   0,   1,     0,   0x082,    0,  "82"    }, //
1220    {0x0083, S_VIA, PRALL,   0,   1,     0,   0x083,    0,  "83"    }, //
1221    {0x0084, S_VIA, PRALL,   0,   1,     0,   0x084,    0,  "84"    }, //
1222    {0x00B4, S_VIA, PRALL,   0,   1,     0,   0x0B4,    0,  "B4"    }, //
1223    {0x00C0, S_VIA, PRALL,   0,   1,     0,   0x0C0,    0,  "C0"    }, //
1224    {0x00C4, S_VIA, PRALL,   0,   1,     0,   0x0C4,    0,  "C4"    }, //
1225    {0x0104, S_VIA, PRALL,   0,   1,     0,   0x104,    0, "104"    }, //
1226    {0x0105, S_VIA, PRALL,   0,   1,     0,   0x105,    0, "105"    }, //
1227    {0x0106, S_VIA, PRALL,   0,   1,     0,   0x106,    0, "106"    }, //
1228    {0x0107, S_VIA, PRALL,   0,   1,     0,   0x107,    0, "107"    }, //
1229    {0x0109, S_VIA, PRALL,   0,   1,     0,   0x109,    0, "109"    }, //
1230    {0x010A, S_VIA, PRALL,   0,   1,     0,   0x10A,    0, "10A"    }, //
1231    {0x010B, S_VIA, PRALL,   0,   1,     0,   0x10B,    0, "10B"    }, //
1232    {0x010C, S_VIA, PRALL,   0,   1,     0,   0x10C,    0, "10C"    }, //
1233    {0x0110, S_VIA, PRALL,   0,   1,     0,   0x110,    0, "110"    }, //
1234    {0x0111, S_VIA, PRALL,   0,   1,     0,   0x111,    0, "111"    }, //
1235    {0x0116, S_VIA, PRALL,   0,   1,     0,   0x116,    0, "116"    }, //
1236    {0x0120, S_VIA, PRALL,   0,   1,     0,   0x120,    0, "120"    }, //
1237    {0x0121, S_VIA, PRALL,   0,   1,     0,   0x121,    0, "121"    }, //
1238    {0x013C, S_VIA, PRALL,   0,   1,     0,   0x13C,    0, "13C"    }, //
1239    {0x0200, S_VIA, PRALL,   0,   1,     0,   0x200,    0, "200"    }, //
1240    {0x0201, S_VIA, PRALL,   0,   1,     0,   0x201,    0, "201"    }, //
1241    {0x0206, S_VIA, PRALL,   0,   1,     0,   0x206,    0, "206"    }, //
1242    {0x0207, S_VIA, PRALL,   0,   1,     0,   0x207,    0, "207"    }, //
1243    {0x0301, S_VIA, PRALL,   0,   1,     0,   0x301,    0, "301"    }, //
1244    {0x0302, S_VIA, PRALL,   0,   1,     0,   0x302,    0, "302"    }, //
1245    {0x0303, S_VIA, PRALL,   0,   1,     0,   0x303,    0, "303"    }, //
1246    {0x0304, S_VIA, PRALL,   0,   1,     0,   0x304,    0, "304"    }, //
1247    {0x0305, S_VIA, PRALL,   0,   1,     0,   0x305,    0, "305"    }, //
1248    {0x0306, S_VIA, PRALL,   0,   1,     0,   0x306,    0, "306"    }, //
1249    {0x0502, S_VIA, PRALL,   0,   1,     0,   0x502,    0, "502"    }, //
1250    {0x0507, S_VIA, PRALL,   0,   1,     0,   0x507,    0, "507"    }, //
1251    {0x0508, S_VIA, PRALL,   0,   1,     0,   0x508,    0, "508"    }, //
1252    {0x050D, S_VIA, PRALL,   0,   1,     0,   0x50D,    0, "50D"    }, //
1253    {0x0600, S_VIA, PRALL,   0,   1,     0,   0x600,    0, "600"    }, //
1254    {0x0605, S_VIA, PRALL,   0,   1,     0,   0x605,    0, "605"    }, //
1255    {0x0607, S_VIA, PRALL,   0,   1,     0,   0x607,    0, "607"    }, //
1256
1257    //  end of list   
1258    {0, S_UNKNOWN, PRUNKNOWN, 0,  0,     0,      0,     0,    0     }  // list must end with a record of all 0
1259};
Note: See TracBrowser for help on using the repository browser.