562172c808935c64b4316e206d1ebfab94a02f00
[platform/upstream/openblas.git] / driver / others / dynamic.c
1 /*********************************************************************/
2 /* Copyright 2009, 2010 The University of Texas at Austin.           */
3 /* All rights reserved.                                              */
4 /*                                                                   */
5 /* Redistribution and use in source and binary forms, with or        */
6 /* without modification, are permitted provided that the following   */
7 /* conditions are met:                                               */
8 /*                                                                   */
9 /*   1. Redistributions of source code must retain the above         */
10 /*      copyright notice, this list of conditions and the following  */
11 /*      disclaimer.                                                  */
12 /*                                                                   */
13 /*   2. Redistributions in binary form must reproduce the above      */
14 /*      copyright notice, this list of conditions and the following  */
15 /*      disclaimer in the documentation and/or other materials       */
16 /*      provided with the distribution.                              */
17 /*                                                                   */
18 /*    THIS  SOFTWARE IS PROVIDED  BY THE  UNIVERSITY OF  TEXAS AT    */
19 /*    AUSTIN  ``AS IS''  AND ANY  EXPRESS OR  IMPLIED WARRANTIES,    */
20 /*    INCLUDING, BUT  NOT LIMITED  TO, THE IMPLIED  WARRANTIES OF    */
21 /*    MERCHANTABILITY  AND FITNESS FOR  A PARTICULAR  PURPOSE ARE    */
22 /*    DISCLAIMED.  IN  NO EVENT SHALL THE UNIVERSITY  OF TEXAS AT    */
23 /*    AUSTIN OR CONTRIBUTORS BE  LIABLE FOR ANY DIRECT, INDIRECT,    */
24 /*    INCIDENTAL,  SPECIAL, EXEMPLARY,  OR  CONSEQUENTIAL DAMAGES    */
25 /*    (INCLUDING, BUT  NOT LIMITED TO,  PROCUREMENT OF SUBSTITUTE    */
26 /*    GOODS  OR  SERVICES; LOSS  OF  USE,  DATA,  OR PROFITS;  OR    */
27 /*    BUSINESS INTERRUPTION) HOWEVER CAUSED  AND ON ANY THEORY OF    */
28 /*    LIABILITY, WHETHER  IN CONTRACT, STRICT  LIABILITY, OR TORT    */
29 /*    (INCLUDING NEGLIGENCE OR OTHERWISE)  ARISING IN ANY WAY OUT    */
30 /*    OF  THE  USE OF  THIS  SOFTWARE,  EVEN  IF ADVISED  OF  THE    */
31 /*    POSSIBILITY OF SUCH DAMAGE.                                    */
32 /*                                                                   */
33 /* The views and conclusions contained in the software and           */
34 /* documentation are those of the authors and should not be          */
35 /* interpreted as representing official policies, either expressed   */
36 /* or implied, of The University of Texas at Austin.                 */
37 /*********************************************************************/
38
39 #include "common.h"
40
41 #ifdef ARCH_X86
42 #define EXTERN extern
43 #else
44 #define EXTERN
45 #endif
46
47 EXTERN gotoblas_t  gotoblas_KATMAI;
48 EXTERN gotoblas_t  gotoblas_COPPERMINE;
49 EXTERN gotoblas_t  gotoblas_NORTHWOOD;
50 EXTERN gotoblas_t  gotoblas_BANIAS;
51 EXTERN gotoblas_t  gotoblas_ATHLON;
52
53 extern gotoblas_t  gotoblas_PRESCOTT;
54 extern gotoblas_t  gotoblas_ATOM;
55 extern gotoblas_t  gotoblas_NANO;
56 extern gotoblas_t  gotoblas_CORE2;
57 extern gotoblas_t  gotoblas_PENRYN;
58 extern gotoblas_t  gotoblas_DUNNINGTON;
59 extern gotoblas_t  gotoblas_NEHALEM;
60 extern gotoblas_t  gotoblas_OPTERON;
61 extern gotoblas_t  gotoblas_OPTERON_SSE3;
62 extern gotoblas_t  gotoblas_BARCELONA;
63 extern gotoblas_t  gotoblas_BOBCAT;
64 #ifndef NO_AVX
65 extern gotoblas_t  gotoblas_SANDYBRIDGE;
66 extern gotoblas_t  gotoblas_BULLDOZER;
67 #else
68 //Use NEHALEM kernels for sandy bridge
69 #define gotoblas_SANDYBRIDGE gotoblas_NEHALEM
70 #define gotoblas_BULLDOZER gotoblas_BARCELONA
71 #endif
72 //Use sandy bridge kernels for haswell.
73 #define gotoblas_HASWELL gotoblas_SANDYBRIDGE
74
75 #define VENDOR_INTEL      1
76 #define VENDOR_AMD        2
77 #define VENDOR_CENTAUR    3
78 #define VENDOR_UNKNOWN   99
79
80 #define BITMASK(a, b, c) ((((a) >> (b)) & (c)))
81
82 #ifndef NO_AVX
83 static inline void xgetbv(int op, int * eax, int * edx){
84   //Use binary code for xgetbv
85   __asm__ __volatile__
86     (".byte 0x0f, 0x01, 0xd0": "=a" (*eax), "=d" (*edx) : "c" (op) : "cc");
87 }
88 #endif
89
90 int support_avx(){
91 #ifndef NO_AVX
92   int eax, ebx, ecx, edx;
93   int ret=0;
94   
95   cpuid(1, &eax, &ebx, &ecx, &edx);
96   if ((ecx & (1 << 28)) != 0 && (ecx & (1 << 27)) != 0 && (ecx & (1 << 26)) != 0){
97     xgetbv(0, &eax, &edx);
98     if((eax & 6) == 6){
99       ret=1;  //OS support AVX
100     }
101   }
102   return ret;
103 #else
104   return 0;
105 #endif
106 }
107
108 static int get_vendor(void){
109   int eax, ebx, ecx, edx;
110   char vendor[13];
111
112   cpuid(0, &eax, &ebx, &ecx, &edx);
113   
114   *(int *)(&vendor[0]) = ebx;
115   *(int *)(&vendor[4]) = edx;
116   *(int *)(&vendor[8]) = ecx;
117   vendor[12] = (char)0;
118
119   if (!strcmp(vendor, "GenuineIntel")) return VENDOR_INTEL;
120   if (!strcmp(vendor, "AuthenticAMD")) return VENDOR_AMD;
121   if (!strcmp(vendor, "CentaurHauls")) return VENDOR_CENTAUR;
122
123   if ((eax == 0) || ((eax & 0x500) != 0)) return VENDOR_INTEL;
124
125   return VENDOR_UNKNOWN;
126 }
127
128 static gotoblas_t *get_coretype(void){
129
130   int eax, ebx, ecx, edx;
131   int family, exfamily, model, vendor, exmodel;
132
133   cpuid(1, &eax, &ebx, &ecx, &edx);
134
135   family   = BITMASK(eax,  8, 0x0f);
136   exfamily = BITMASK(eax, 20, 0xff);
137   model    = BITMASK(eax,  4, 0x0f);
138   exmodel  = BITMASK(eax, 16, 0x0f);
139
140   vendor = get_vendor();
141
142   if (vendor == VENDOR_INTEL){
143     switch (family) {
144     case 0x6:
145       switch (exmodel) {
146       case 0:
147         if (model <= 0x7) return &gotoblas_KATMAI;
148         if ((model == 0x8) || (model == 0xa) || (model == 0xb)) return &gotoblas_COPPERMINE;
149         if ((model == 0x9) || (model == 0xd)) return &gotoblas_BANIAS;
150         if (model == 14) return &gotoblas_BANIAS;
151         if (model == 15) return &gotoblas_CORE2;
152         return NULL;
153
154       case 1:
155         if (model == 6) return &gotoblas_CORE2;
156         if (model == 7) return &gotoblas_PENRYN;
157         if (model == 13) return &gotoblas_DUNNINGTON;
158         if ((model == 10) || (model == 11) || (model == 14) || (model == 15)) return &gotoblas_NEHALEM;
159         if (model == 12) return &gotoblas_ATOM;
160         return NULL;
161
162       case 2:
163         //Intel Core (Clarkdale) / Core (Arrandale)
164         // Pentium (Clarkdale) / Pentium Mobile (Arrandale)
165         // Xeon (Clarkdale), 32nm
166         if (model ==  5) return &gotoblas_NEHALEM;
167                   
168         //Intel Xeon Processor 5600 (Westmere-EP)
169         //Xeon Processor E7 (Westmere-EX)
170         //Xeon E7540
171         if (model == 12 || model == 14 || model == 15) return &gotoblas_NEHALEM;
172
173         //Intel Core i5-2000 /i7-2000 (Sandy Bridge)
174         //Intel Core i7-3000 / Xeon E5
175         if (model == 10 || model == 13) {
176           if(support_avx())
177             return &gotoblas_SANDYBRIDGE;
178           else{
179             fprintf(stderr, "OpenBLAS : Your OS does not support AVX instructions. OpenBLAS is using Nehalem kernels as a fallback, which may give poorer performance.\n");
180             return &gotoblas_NEHALEM; //OS doesn't support AVX. Use old kernels.
181           }
182         }
183         return NULL;
184       case 3:
185         //Intel Sandy Bridge 22nm (Ivy Bridge?)
186         if (model == 10) {
187           if(support_avx())
188             return &gotoblas_SANDYBRIDGE;
189           else{
190             fprintf(stderr, "OpenBLAS : Your OS does not support AVX instructions. OpenBLAS is using Nehalem kernels as a fallback, which may give poorer performance.\n");
191             return &gotoblas_NEHALEM; //OS doesn't support AVX. Use old kernels.
192           }
193         }
194         //Intel Haswell
195         if (model == 12) {
196           if(support_avx())
197             return &gotoblas_HASWELL;
198           else{
199             fprintf(stderr, "OpenBLAS : Your OS does not support AVX instructions. OpenBLAS is using Nehalem kernels as a fallback, which may give poorer performance.\n");
200             return &gotoblas_NEHALEM; //OS doesn't support AVX. Use old kernels.
201           }
202         }
203         return NULL;
204       case 4:
205                 //Intel Haswell
206         if (model == 5) {
207           if(support_avx())
208             return &gotoblas_HASWELL;
209           else{
210             fprintf(stderr, "OpenBLAS : Your OS does not support AVX instructions. OpenBLAS is using Nehalem kernels as a fallback, which may give poorer performance.\n");
211             return &gotoblas_NEHALEM; //OS doesn't support AVX. Use old kernels.
212           }
213         }
214         return NULL;
215       }
216       case 0xf:
217       if (model <= 0x2) return &gotoblas_NORTHWOOD;
218       return &gotoblas_PRESCOTT;
219     }
220   }
221
222   if (vendor == VENDOR_AMD){
223     if (family <= 0xe) return &gotoblas_ATHLON;
224     if (family == 0xf){
225       if ((exfamily == 0) || (exfamily == 2)) {
226         if (ecx & (1 <<  0)) return &gotoblas_OPTERON_SSE3; 
227         else return &gotoblas_OPTERON;
228       }  else if (exfamily == 5) {
229         return &gotoblas_BOBCAT;
230       } else if (exfamily == 6) {
231         //AMD Bulldozer Opteron 6200 / Opteron 4200 / AMD FX-Series
232           if(support_avx())
233             return &gotoblas_BULLDOZER;
234           else{
235             fprintf(stderr, "OpenBLAS : Your OS does not support AVX instructions. OpenBLAS is using Barcelona kernels as a fallback, which may give poorer performance.\n");
236             return &gotoblas_BARCELONA; //OS doesn't support AVX. Use old kernels.
237           }     
238       } else {
239         return &gotoblas_BARCELONA;
240       }
241     }
242   }
243
244   if (vendor == VENDOR_CENTAUR) {
245     switch (family) {
246     case 0x6:
247       return &gotoblas_NANO;
248       break;
249     }
250   }
251   
252   return NULL;
253 }
254
255 static char *corename[] = {
256     "Unknown",
257     "Katmai",
258     "Coppermine",
259     "Northwood",
260     "Prescott",
261     "Banias",
262     "Atom",
263     "Core2",
264     "Penryn",
265     "Dunnington",
266     "Nehalem",
267     "Athlon",
268     "Opteron",
269     "Opteron(SSE3)",
270     "Barcelona",
271     "Nano",
272     "Sandybridge",
273     "Bobcat",
274     "Bulldozer",
275 };
276
277 char *gotoblas_corename(void) {
278
279   if (gotoblas == &gotoblas_KATMAI)       return corename[ 1];
280   if (gotoblas == &gotoblas_COPPERMINE)   return corename[ 2];
281   if (gotoblas == &gotoblas_NORTHWOOD)    return corename[ 3];
282   if (gotoblas == &gotoblas_PRESCOTT)     return corename[ 4];
283   if (gotoblas == &gotoblas_BANIAS)       return corename[ 5];
284   if (gotoblas == &gotoblas_ATOM)         return corename[ 6];
285   if (gotoblas == &gotoblas_CORE2)        return corename[ 7];
286   if (gotoblas == &gotoblas_PENRYN)       return corename[ 8];
287   if (gotoblas == &gotoblas_DUNNINGTON)   return corename[ 9];
288   if (gotoblas == &gotoblas_NEHALEM)      return corename[10];
289   if (gotoblas == &gotoblas_ATHLON)       return corename[11];
290   if (gotoblas == &gotoblas_OPTERON_SSE3) return corename[12]; 
291   if (gotoblas == &gotoblas_OPTERON)      return corename[13];
292   if (gotoblas == &gotoblas_BARCELONA)    return corename[14];
293   if (gotoblas == &gotoblas_NANO)         return corename[15];
294   if (gotoblas == &gotoblas_SANDYBRIDGE)  return corename[16];
295   if (gotoblas == &gotoblas_BOBCAT)       return corename[17];
296   if (gotoblas == &gotoblas_BULLDOZER)    return corename[18];
297
298   return corename[0];
299 }
300
301 void gotoblas_dynamic_init(void) {
302   
303   if (gotoblas) return;
304
305   gotoblas = get_coretype();
306   
307 #ifdef ARCH_X86
308   if (gotoblas == NULL) gotoblas = &gotoblas_KATMAI;
309 #else
310   if (gotoblas == NULL) gotoblas = &gotoblas_PRESCOTT;
311   /* sanity check, if 64bit pointer we can't have a 32 bit cpu */
312   if (sizeof(void*) == 8) {
313       if (gotoblas == &gotoblas_KATMAI ||
314           gotoblas == &gotoblas_COPPERMINE ||
315           gotoblas == &gotoblas_NORTHWOOD ||
316           gotoblas == &gotoblas_BANIAS ||
317           gotoblas == &gotoblas_ATHLON)
318           gotoblas = &gotoblas_PRESCOTT;
319   }
320 #endif
321   
322   if (gotoblas && gotoblas -> init) {
323     gotoblas -> init();
324   } else {
325     fprintf(stderr, "OpenBLAS : Architecture Initialization failed. No initialization function found.\n");
326     exit(1);
327   }
328   
329 }
330
331 void gotoblas_dynamic_quit(void) {
332   
333   gotoblas = NULL;
334
335 }