818fe0687500c8cc3931853106b65ea39fa2ee86
[u/mrichter/AliRoot.git] / Vc / src / cpuid.cpp
1 /*  This file is part of the Vc library.
2
3     Copyright (C) 2011-2012 Matthias Kretz <kretz@kde.org>
4
5     Vc is free software: you can redistribute it and/or modify
6     it under the terms of the GNU Lesser General Public License as
7     published by the Free Software Foundation, either version 3 of
8     the License, or (at your option) any later version.
9
10     Vc is distributed in the hope that it will be useful, but
11     WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU Lesser General Public License for more details.
14
15     You should have received a copy of the GNU Lesser General Public
16     License along with Vc.  If not, see <http://www.gnu.org/licenses/>.
17
18 */
19
20 #include <Vc/cpuid.h>
21
22 namespace Vc
23 {
24 CpuId::uint   CpuId::s_ecx0 = 0;
25 CpuId::uint   CpuId::s_logicalProcessors = 0;
26 CpuId::uint   CpuId::s_processorFeaturesC = 0;
27 CpuId::uint   CpuId::s_processorFeaturesD = 0;
28 CpuId::uint   CpuId::s_processorFeatures8C = 0;
29 CpuId::uint   CpuId::s_processorFeatures8D = 0;
30 CpuId::uint   CpuId::s_L1Instruction = 0;
31 CpuId::uint   CpuId::s_L1Data = 0;
32 CpuId::uint   CpuId::s_L2Data = 0;
33 CpuId::uint   CpuId::s_L3Data = 0;
34 CpuId::ushort CpuId::s_L1InstructionLineSize = 0;
35 CpuId::ushort CpuId::s_L1DataLineSize = 0;
36 CpuId::ushort CpuId::s_L2DataLineSize = 0;
37 CpuId::ushort CpuId::s_L3DataLineSize = 0;
38 CpuId::uint   CpuId::s_L1Associativity = 0;
39 CpuId::uint   CpuId::s_L2Associativity = 0;
40 CpuId::uint   CpuId::s_L3Associativity = 0;
41 CpuId::ushort CpuId::s_prefetch = 32; // The Intel ORM says that if CPUID(2) doesn't set the prefetch size it is 32
42 CpuId::uchar  CpuId::s_brandIndex = 0;
43 CpuId::uchar  CpuId::s_cacheLineSize = 0;
44 CpuId::uchar  CpuId::s_processorModel = 0;
45 CpuId::uchar  CpuId::s_processorFamily = 0;
46 CpuId::ProcessorType CpuId::s_processorType = CpuId::IntelReserved;
47 bool   CpuId::s_noL2orL3 = false;
48
49 #ifdef _MSC_VER
50 #include <intrin.h>
51 #define CPUID(leaf) \
52     do { \
53         int out[4]; \
54         __cpuid(out, leaf); \
55         eax = out[0]; \
56         ebx = out[1]; \
57         ecx = out[2]; \
58         edx = out[3]; \
59     } while (false)
60 #define CPUID_C(leaf, _ecx_) \
61     do { \
62         int out[4]; \
63         __cpuidex(out, leaf, _ecx_); \
64         eax = out[0]; \
65         ebx = out[1]; \
66         ecx = out[2]; \
67         edx = out[3]; \
68     } while (false)
69 #elif defined(__i386__) && defined(__PIC__)
70 // %ebx may be the PIC register.
71 static inline void _Vc_cpuid(int leaf, unsigned int &eax, unsigned int &ebx, unsigned int &ecx, unsigned int &edx)
72 {
73     int tmpb;
74     asm("mov %%ebx, %[tmpb]\n\t"
75         "cpuid\n\t"
76         "mov %%ebx, %[ebx]\n\t"
77         "mov %[tmpb], %%ebx\n\t"
78         : [tmpb]"=m"(tmpb), "=a"(eax), [ebx] "=m"(ebx), "+c"(ecx), "=d"(edx)
79         : [leaf] "a"(leaf)
80       );
81 }
82 #define CPUID(leaf) \
83     ecx = 0; \
84     _Vc_cpuid(leaf, eax, ebx, ecx, edx)
85 #define CPUID_C(leaf, _ecx_) \
86     ecx = _ecx_; \
87     _Vc_cpuid(leaf, eax, ebx, ecx, edx)
88 #else
89 #define CPUID(leaf) \
90     __asm__("cpuid" : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx) : "a"(leaf))
91 #define CPUID_C(leaf, _ecx_) \
92     __asm__("cpuid" : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx) : "a"(leaf), "c"(_ecx_))
93 #endif
94 static unsigned int CpuIdAmdAssociativityTable(int bits)
95 {
96     switch (bits) {
97     case 0x0: return 0;
98     case 0x1: return 1;
99     case 0x2: return 2;
100     case 0x4: return 4;
101     case 0x6: return 8;
102     case 0x8: return 16;
103     case 0xA: return 32;
104     case 0xB: return 48;
105     case 0xC: return 64;
106     case 0xD: return 96;
107     case 0xE: return 128;
108     case 0xF: return 0xff;
109     }
110     return 0xffffffffu;
111 }
112
113 void CpuId::init()
114 {
115     {
116         static bool done = false;
117         if (done) return;
118         done = true;
119     }
120     uint eax, ebx, ecx, edx;
121
122     CPUID(0);
123     s_ecx0 = ecx;
124
125     CPUID(1);
126     s_processorFeaturesC = ecx;
127     s_processorFeaturesD = edx;
128     s_processorModel  = (eax & 0x000000f0) >> 4;
129     s_processorFamily = (eax & 0x00000f00) >> 8;
130     if (isAmd()) {
131         if (s_processorFamily >= 0xf) {
132             const uchar processorFamilyExt = (eax & 0x0ff00000) >> 20;
133             s_processorFamily += processorFamilyExt;
134             const uchar processorModelExt = (eax & 0x000f0000) >> 12;
135             s_processorModel += processorModelExt;
136         }
137     } else if (s_processorFamily == 0xf) {
138         const uchar processorFamilyExt = (eax & 0x0ff00000) >> 20;
139         s_processorFamily += processorFamilyExt;
140         const uchar processorModelExt = (eax & 0x000f0000) >> 12;
141         s_processorModel += processorModelExt;
142     } else if (s_processorFamily == 0x6) {
143         const uchar processorModelExt = (eax & 0x000f0000) >> 12;
144         s_processorModel += processorModelExt;
145     }
146     s_processorType = static_cast<ProcessorType>((eax & 0x00003000) >> 12);
147
148     s_brandIndex = ebx & 0xff;
149     ebx >>= 8;
150     s_cacheLineSize = ebx & 0xff;
151     ebx >>= 8;
152     s_logicalProcessors = ebx & 0xff;
153
154     CPUID(0x80000001);
155     s_processorFeatures8C = ecx;
156     s_processorFeatures8D = edx;
157
158     if (isAmd()) {
159         s_prefetch = cacheLineSize();
160
161         CPUID(0x80000005);
162         s_L1DataLineSize = ecx & 0xff;
163         s_L1Data = (ecx >> 24) * 1024;
164         s_L1Associativity = (ecx >> 16) & 0xff;
165         s_L1InstructionLineSize = edx & 0xff;
166         s_L1Instruction = (edx >> 24) * 1024;
167
168         CPUID(0x80000006);
169         s_L2DataLineSize = ecx & 0xff;
170         s_L2Data = (ecx >> 16) * 1024;
171         s_L2Associativity = CpuIdAmdAssociativityTable((ecx >> 12) & 0xf);
172         s_L3DataLineSize = edx & 0xff;
173         s_L3Data = (edx >> 18) * 512 * 1024;
174         s_L3Associativity = CpuIdAmdAssociativityTable((ecx >> 12) & 0xf);
175         return;
176     }
177
178     // Intel only
179     int repeat = 0;
180     bool checkLeaf4 = false;
181     do {
182         CPUID(2);
183         if (repeat == 0) {
184             repeat = eax & 0xff;
185         }
186         if (0 == (0x80000000u & eax)) {
187             for (int i = 0; i < 3; ++i) {
188                 eax >>= 8;
189                 interpret(eax & 0xff, &checkLeaf4);
190             }
191         }
192         if (0 == (0x80000000u & ebx)) {
193             for (int i = 0; i < 4; ++i) {
194                 interpret(ebx & 0xff, &checkLeaf4);
195                 ebx >>= 8;
196             }
197         }
198         if (0 == (0x80000000u & ecx)) {
199             for (int i = 0; i < 4; ++i) {
200                 interpret(ecx & 0xff, &checkLeaf4);
201                 ecx >>= 8;
202             }
203         }
204         if (0 == (0x80000000u & edx)) {
205             for (int i = 0; i < 4; ++i) {
206                 interpret(edx & 0xff, &checkLeaf4);
207                 edx >>= 8;
208             }
209         }
210     } while (--repeat > 0);
211     if (checkLeaf4) {
212         s_prefetch = cacheLineSize();
213         if (s_prefetch == 0) {
214             s_prefetch = 64;
215         }
216         eax = 1;
217         for (int i = 0; eax & 0x1f; ++i) {
218             CPUID_C(4, i);
219             const int cacheLevel = (eax >> 5) & 7;
220             //const int sharedBy = 1 + ((eax >> 14) & 0xfff);
221             const int linesize = 1 + (ebx & 0xfff);   ebx >>= 12;
222             const int partitions = 1 + (ebx & 0x3ff); ebx >>= 10;
223             const int ways = 1 + (ebx & 0x3ff);
224             const int sets = 1 + ecx;
225             const int size = ways * partitions * linesize * sets;
226             switch (eax & 0x1f) {
227                 case 1: // data cache
228                     switch (cacheLevel) {
229                         case 1:
230                             s_L1Data = size;
231                             s_L1DataLineSize = linesize;
232                             s_L1Associativity = ways;
233                             break;
234                         case 2:
235                             s_L2Data = size;
236                             s_L2DataLineSize = linesize;
237                             s_L2Associativity = ways;
238                             break;
239                         case 3:
240                             s_L3Data = size;
241                             s_L3DataLineSize = linesize;
242                             s_L3Associativity = ways;
243                             break;
244                     }
245                     break;
246                 case 2: // instruction cache
247                     switch (cacheLevel) {
248                         case 1:
249                             s_L1Instruction = size;
250                             s_L1InstructionLineSize = linesize;
251                             break;
252                     }
253                     break;
254                 case 3: // unified cache
255                     switch (cacheLevel) {
256                         case 1:
257                             s_L1Data = size;// / sharedBy;
258                             s_L1DataLineSize = linesize;
259                             s_L1Associativity = ways;
260                             break;
261                         case 2:
262                             s_L2Data = size;// / sharedBy;
263                             s_L2DataLineSize = linesize;
264                             s_L2Associativity = ways;
265                             break;
266                         case 3:
267                             s_L3Data = size;// / sharedBy;
268                             s_L3DataLineSize = linesize;
269                             s_L3Associativity = ways;
270                             break;
271                     }
272                     break;
273                 case 0: // no more caches
274                     break;
275                 default: // reserved
276                     break;
277             }
278         }
279     }
280 }
281
282 void CpuId::interpret(uchar byte, bool *checkLeaf4)
283 {
284     switch (byte) {
285     case 0x06:
286         s_L1Instruction = 8 * 1024;
287         s_L1InstructionLineSize = 32;
288         s_L1Associativity = 4;
289         break;
290     case 0x08:
291         s_L1Instruction = 16 * 1024;
292         s_L1InstructionLineSize = 32;
293         s_L1Associativity = 4;
294         break;
295     case 0x09:
296         s_L1Instruction = 32 * 1024;
297         s_L1InstructionLineSize = 64;
298         s_L1Associativity = 4;
299         break;
300     case 0x0A:
301         s_L1Data = 8 * 1024;
302         s_L1DataLineSize = 32;
303         s_L1Associativity = 2;
304         break;
305     case 0x0C:
306         s_L1Data = 16 * 1024;
307         s_L1DataLineSize = 32;
308         s_L1Associativity = 4;
309         break;
310     case 0x0D:
311         s_L1Data = 16 * 1024;
312         s_L1DataLineSize = 64;
313         s_L1Associativity = 4;
314         break;
315     case 0x0E:
316         s_L1Data = 24 * 1024;
317         s_L1DataLineSize = 64;
318         s_L1Associativity = 6;
319         break;
320     case 0x21:
321         s_L2Data = 256 * 1024;
322         s_L2DataLineSize = 64;
323         s_L2Associativity = 8;
324         break;
325     case 0x22:
326         s_L3Data = 512 * 1024;
327         s_L3DataLineSize = 64;
328         s_L3Associativity = 4;
329         break;
330     case 0x23:
331         s_L3Data = 1024 * 1024;
332         s_L3DataLineSize = 64;
333         s_L3Associativity = 8;
334         break;
335     case 0x25:
336         s_L3Data = 2 * 1024 * 1024;
337         s_L3DataLineSize = 64;
338         s_L3Associativity = 8;
339         break;
340     case 0x29:
341         s_L3Data = 4 * 1024 * 1024;
342         s_L3DataLineSize = 64;
343         s_L3Associativity = 8;
344         break;
345     case 0x2C:
346         s_L1Data = 32 * 1024;
347         s_L1DataLineSize = 64;
348         s_L1Associativity = 8;
349         break;
350     case 0x30:
351         s_L1Data = 32 * 1024;
352         s_L1DataLineSize = 64;
353         s_L1Associativity = 8;
354         break;
355     case 0x40:
356         s_noL2orL3 = true;
357         break;
358     case 0x41:
359         s_L2Data = 128 * 1024;
360         s_L2DataLineSize = 32;
361         s_L2Associativity = 4;
362         break;
363     case 0x42:
364         s_L2Data = 256 * 1024;
365         s_L2DataLineSize = 32;
366         s_L2Associativity = 4;
367         break;
368     case 0x43:
369         s_L2Data = 512 * 1024;
370         s_L2DataLineSize = 32;
371         s_L2Associativity = 4;
372         break;
373     case 0x44:
374         s_L2Data = 1024 * 1024;
375         s_L2DataLineSize = 32;
376         s_L2Associativity = 4;
377         break;
378     case 0x45:
379         s_L2Data = 2 * 1024 * 1024;
380         s_L2DataLineSize = 32;
381         s_L2Associativity = 4;
382         break;
383     case 0x46:
384         s_L3Data = 4 * 1024 * 1024;
385         s_L3DataLineSize = 64;
386         s_L3Associativity = 4;
387         break;
388     case 0x47:
389         s_L3Data = 8 * 1024 * 1024;
390         s_L3DataLineSize = 64;
391         s_L3Associativity = 8;
392         break;
393     case 0x48:
394         s_L2Data = 3 * 1024 * 1024;
395         s_L2DataLineSize = 64;
396         s_L2Associativity = 12;
397         break;
398     case 0x49:
399         if (s_processorFamily == 0xf && s_processorModel == 0x6) {
400             s_L3Data = 4 * 1024 * 1024;
401             s_L3DataLineSize = 64;
402             s_L3Associativity = 16;
403         } else {
404             s_L2Data = 4 * 1024 * 1024;
405             s_L2DataLineSize = 64;
406             s_L2Associativity = 16;
407         }
408         break;
409     case 0x4A:
410         s_L3Data = 6 * 1024 * 1024;
411         s_L3DataLineSize = 64;
412         s_L3Associativity = 12;
413         break;
414     case 0x4B:
415         s_L3Data = 8 * 1024 * 1024;
416         s_L3DataLineSize = 64;
417         s_L3Associativity = 16;
418         break;
419     case 0x4C:
420         s_L3Data = 12 * 1024 * 1024;
421         s_L3DataLineSize = 64;
422         s_L3Associativity = 12;
423         break;
424     case 0x4D:
425         s_L3Data = 16 * 1024 * 1024;
426         s_L3DataLineSize = 64;
427         s_L3Associativity = 16;
428         break;
429     case 0x4E:
430         s_L2Data = 6 * 1024 * 1024;
431         s_L2DataLineSize = 64;
432         s_L2Associativity = 24;
433         break;
434     case 0x60:
435         s_L1Data = 16 * 1024;
436         s_L1DataLineSize = 64;
437         s_L1Associativity = 8;
438         break;
439     case 0x66:
440         s_L1Data = 8 * 1024;
441         s_L1DataLineSize = 64;
442         s_L1Associativity = 4;
443         break;
444     case 0x67:
445         s_L1Data = 16 * 1024;
446         s_L1DataLineSize = 64;
447         s_L1Associativity = 4;
448         break;
449     case 0x68:
450         s_L1Data = 32 * 1024;
451         s_L1DataLineSize = 64;
452         s_L1Associativity = 4;
453         break;
454     case 0x78:
455         s_L2Data = 1024 * 1024;
456         s_L2DataLineSize = 64;
457         s_L2Associativity = 4;
458         break;
459     case 0x79:
460         s_L2Data = 128 * 1024;
461         s_L2DataLineSize = 64;
462         s_L2Associativity = 8;
463         break;
464     case 0x7A:
465         s_L2Data = 256 * 1024;
466         s_L2DataLineSize = 64;
467         s_L2Associativity = 8;
468         break;
469     case 0x7B:
470         s_L2Data = 512 * 1024;
471         s_L2DataLineSize = 64;
472         s_L2Associativity = 8;
473         break;
474     case 0x7C:
475         s_L2Data = 1024 * 1024;
476         s_L2DataLineSize = 64;
477         s_L2Associativity = 8;
478         break;
479     case 0x7D:
480         s_L2Data = 2 * 1024 * 1024;
481         s_L2DataLineSize = 64;
482         s_L2Associativity = 8;
483         break;
484     case 0x7F:
485         s_L2Data = 512 * 1024;
486         s_L2DataLineSize = 64;
487         s_L2Associativity = 2;
488         break;
489     case 0x80:
490         s_L2Data = 512 * 1024;
491         s_L2DataLineSize = 64;
492         s_L2Associativity = 8;
493         break;
494     case 0x82:
495         s_L2Data = 256 * 1024;
496         s_L2DataLineSize = 32;
497         s_L2Associativity = 8;
498         break;
499     case 0x83:
500         s_L2Data = 512 * 1024;
501         s_L2DataLineSize = 32;
502         s_L2Associativity = 8;
503         break;
504     case 0x84:
505         s_L2Data = 1024 * 1024;
506         s_L2DataLineSize = 32;
507         s_L2Associativity = 8;
508         break;
509     case 0x85:
510         s_L2Data = 2 * 1024 * 1024;
511         s_L2DataLineSize = 32;
512         s_L2Associativity = 8;
513         break;
514     case 0x86:
515         s_L2Data = 512 * 1024;
516         s_L2DataLineSize = 64;
517         s_L2Associativity = 4;
518         break;
519     case 0x87:
520         s_L2Data = 1024 * 1024;
521         s_L2DataLineSize = 64;
522         s_L2Associativity = 8;
523         break;
524     case 0xD0:
525         s_L3Data = 512 * 1024;
526         s_L3DataLineSize = 64;
527         s_L3Associativity = 4;
528         break;
529     case 0xD1:
530         s_L3Data = 1024 * 1024;
531         s_L3DataLineSize = 64;
532         s_L3Associativity = 4;
533         break;
534     case 0xD2:
535         s_L3Data = 2 * 1024 * 1024;
536         s_L3DataLineSize = 64;
537         s_L3Associativity = 4;
538         break;
539     case 0xD6:
540         s_L3Data = 1024 * 1024;
541         s_L3DataLineSize = 64;
542         s_L3Associativity = 8;
543         break;
544     case 0xD7:
545         s_L3Data = 2 * 1024 * 1024;
546         s_L3DataLineSize = 64;
547         s_L3Associativity = 8;
548         break;
549     case 0xD8:
550         s_L3Data = 4 * 1024 * 1024;
551         s_L3DataLineSize = 64;
552         s_L3Associativity = 8;
553         break;
554     case 0xDC:
555         s_L3Data = 3 * 512 * 1024;
556         s_L3DataLineSize = 64;
557         s_L3Associativity = 12;
558         break;
559     case 0xDD:
560         s_L3Data = 3 * 1024 * 1024;
561         s_L3DataLineSize = 64;
562         s_L3Associativity = 12;
563         break;
564     case 0xDE:
565         s_L3Data = 6 * 1024 * 1024;
566         s_L3DataLineSize = 64;
567         s_L3Associativity = 12;
568         break;
569     case 0xE2:
570         s_L3Data = 2 * 1024 * 1024;
571         s_L3DataLineSize = 64;
572         s_L3Associativity = 16;
573         break;
574     case 0xE3:
575         s_L3Data = 4 * 1024 * 1024;
576         s_L3DataLineSize = 64;
577         s_L3Associativity = 16;
578         break;
579     case 0xE4:
580         s_L3Data = 8 * 1024 * 1024;
581         s_L3DataLineSize = 64;
582         s_L3Associativity = 16;
583         break;
584     case 0xEA:
585         s_L3Data = 12 * 1024 * 1024;
586         s_L3DataLineSize = 64;
587         s_L3Associativity = 24;
588         break;
589     case 0xEB:
590         s_L3Data = 18 * 1024 * 1024;
591         s_L3DataLineSize = 64;
592         s_L3Associativity = 24;
593         break;
594     case 0xEC:
595         s_L3Data = 24 * 1024 * 1024;
596         s_L3DataLineSize = 64;
597         s_L3Associativity = 24;
598         break;
599     case 0xF0:
600         s_prefetch = 64;
601         break;
602     case 0xF1:
603         s_prefetch = 128;
604         break;
605     case 0xFF:
606         // we have to use CPUID(4) to find out
607         *checkLeaf4 = true;
608         break;
609     default:
610         break;
611     }
612 }
613 } // namespace Vc
614
615 // vim: sw=4 sts=4 et tw=100