1 #include "common.h"
2 #include <stdbool.h>
3
4 // Guard the use of getauxval() on glibc version >= 2.16
5 #ifdef __GLIBC__
6 #include <features.h>
7 #if __GLIBC_PREREQ(2, 16)
8 #include <sys/auxv.h>
9 #define HAVE_GETAUXVAL 1
10
get_hwcap(void)11 static unsigned long get_hwcap(void)
12 {
13 unsigned long hwcap = getauxval(AT_HWCAP);
14 char *maskenv;
15
16 // honor requests for not using specific CPU features in LD_HWCAP_MASK
17 maskenv = getenv("LD_HWCAP_MASK");
18 if (maskenv)
19 hwcap &= strtoul(maskenv, NULL, 0);
20
21 return hwcap;
22 // note that a missing auxval is interpreted as no capabilities
23 // available, which is safe.
24 }
25
26 #else // __GLIBC_PREREQ(2, 16)
27 #warn "Cannot detect SIMD support in Z13 or newer architectures since glibc is older than 2.16"
28
get_hwcap(void)29 static unsigned long get_hwcap(void) {
30 // treat missing support for getauxval() as no capabilities available,
31 // which is safe.
32 return 0;
33 }
34 #endif // __GLIBC_PREREQ(2, 16)
35 #endif // __GLIBC
36
37 extern gotoblas_t gotoblas_ZARCH_GENERIC;
38 #ifdef DYN_Z13
39 extern gotoblas_t gotoblas_Z13;
40 #endif
41 #ifdef DYN_Z14
42 extern gotoblas_t gotoblas_Z14;
43 #endif
44
45 #define NUM_CORETYPES 4
46
47 extern void openblas_warning(int verbose, const char* msg);
48
49 static char* corename[] = {
50 "unknown",
51 "Z13",
52 "Z14",
53 "ZARCH_GENERIC",
54 };
55
gotoblas_corename(void)56 char* gotoblas_corename(void) {
57 #ifdef DYN_Z13
58 if (gotoblas == &gotoblas_Z13) return corename[1];
59 #endif
60 #ifdef DYN_Z14
61 if (gotoblas == &gotoblas_Z14) return corename[2];
62 #endif
63 if (gotoblas == &gotoblas_ZARCH_GENERIC) return corename[3];
64
65 return corename[0];
66 }
67
68 #ifndef HWCAP_S390_VXE
69 #define HWCAP_S390_VXE 8192
70 #endif
71
72 /**
73 * Detect the fitting set of kernels by retrieving the CPU features supported by
74 * OS from the auxiliary value AT_HWCAP and choosing the set of kernels
75 * ("coretype") that exploits most of the features and can be compiled with the
76 * available gcc version.
77 * Note that we cannot use vector registers on a z13 or newer unless supported
78 * by the OS kernel (which needs to handle them properly during context switch).
79 */
get_coretype(void)80 static gotoblas_t* get_coretype(void) {
81
82 unsigned long hwcap __attribute__((unused)) = get_hwcap();
83
84 #ifdef DYN_Z14
85 // z14 and z15 systems: exploit Vector Facility (SIMD) and
86 // Vector-Enhancements Facility 1 (float SIMD instructions), if present.
87 if ((hwcap & HWCAP_S390_VX) && (hwcap & HWCAP_S390_VXE))
88 return &gotoblas_Z14;
89 #endif
90
91 #ifdef DYN_Z13
92 // z13: Vector Facility (SIMD for double)
93 if (hwcap & HWCAP_S390_VX)
94 return &gotoblas_Z13;
95 #endif
96
97 // fallback in case of missing compiler support, systems before z13, or
98 // when the OS does not advertise support for the Vector Facility (e.g.,
99 // missing support in the OS kernel)
100 return &gotoblas_ZARCH_GENERIC;
101 }
102
force_coretype(char * coretype)103 static gotoblas_t* force_coretype(char* coretype) {
104
105 int i;
106 int found = -1;
107 char message[128];
108
109 for (i = 0; i < NUM_CORETYPES; i++)
110 {
111 if (!strncasecmp(coretype, corename[i], 20))
112 {
113 found = i;
114 break;
115 }
116 }
117
118 if (found == 1) {
119 #ifdef DYN_Z13
120 return &gotoblas_Z13;
121 #else
122 openblas_warning(1, "Z13 support not compiled in");
123 return NULL;
124 #endif
125 } else if (found == 2) {
126 #ifdef DYN_Z14
127 return &gotoblas_Z14;
128 #else
129 openblas_warning(1, "Z14 support not compiled in");
130 return NULL;
131 #endif
132 } else if (found == 3) {
133 return &gotoblas_ZARCH_GENERIC;
134 }
135
136 snprintf(message, 128, "Core not found: %s\n", coretype);
137 openblas_warning(1, message);
138 return NULL;
139 }
140
gotoblas_dynamic_init(void)141 void gotoblas_dynamic_init(void) {
142
143 char coremsg[128];
144 char coren[22];
145 char* p;
146
147
148 if (gotoblas) return;
149
150 p = getenv("OPENBLAS_CORETYPE");
151 if (p)
152 {
153 gotoblas = force_coretype(p);
154 }
155 else
156 {
157 gotoblas = get_coretype();
158 }
159
160 if (gotoblas == NULL)
161 {
162 snprintf(coremsg, 128, "Failed to detect system, falling back to generic z support.\n");
163 openblas_warning(1, coremsg);
164 gotoblas = &gotoblas_ZARCH_GENERIC;
165 }
166
167 if (gotoblas && gotoblas->init) {
168 strncpy(coren, gotoblas_corename(), 20);
169 sprintf(coremsg, "Core: %s\n", coren);
170 openblas_warning(2, coremsg);
171 gotoblas->init();
172 }
173 else {
174 openblas_warning(0, "OpenBLAS : Architecture Initialization failed. No initialization function found.\n");
175 exit(1);
176 }
177 }
178
gotoblas_dynamic_quit(void)179 void gotoblas_dynamic_quit(void) {
180 gotoblas = NULL;
181 }
182