OpenBLAS/driver/others/dynamic_zarch.c

155 lines
3.4 KiB
C

#include "common.h"
#include "cpuid_zarch.h"
#include <stdbool.h>
extern gotoblas_t gotoblas_ZARCH_GENERIC;
#ifdef DYN_Z13
extern gotoblas_t gotoblas_Z13;
#endif
#ifdef DYN_Z14
extern gotoblas_t gotoblas_Z14;
#endif
#define NUM_CORETYPES 4
extern int openblas_verbose();
extern void openblas_warning(int verbose, const char* msg);
char* gotoblas_corename(void) {
#ifdef DYN_Z13
if (gotoblas == &gotoblas_Z13) return cpuname[CPU_Z13];
#endif
#ifdef DYN_Z14
if (gotoblas == &gotoblas_Z14) return cpuname[CPU_Z14];
#endif
if (gotoblas == &gotoblas_ZARCH_GENERIC) return cpuname[CPU_GENERIC];
return "unknown";
}
#ifndef HWCAP_S390_VXE
#define HWCAP_S390_VXE 8192
#endif
/**
* Detect the fitting set of kernels by retrieving the CPU features supported by
* OS from the auxiliary value AT_HWCAP and choosing the set of kernels
* ("coretype") that exploits most of the features and can be compiled with the
* available gcc version.
* Note that we cannot use vector registers on a z13 or newer unless supported
* by the OS kernel (which needs to handle them properly during context switch).
*/
static gotoblas_t* get_coretype(void) {
int cpu = detect();
switch(cpu) {
// z14 and z15 systems: exploit Vector Facility (SIMD) and
// Vector-Enhancements Facility 1 (float SIMD instructions), if present.
case CPU_Z14:
#ifdef DYN_Z14
return &gotoblas_Z14;
#endif
// z13: Vector Facility (SIMD for double)
case CPU_Z13:
#ifdef DYN_Z13
return &gotoblas_Z13;
#endif
default:
// fallback in case of missing compiler support, systems before z13, or
// when the OS does not advertise support for the Vector Facility (e.g.,
// missing support in the OS kernel)
return &gotoblas_ZARCH_GENERIC;
}
}
static gotoblas_t* force_coretype(char* coretype) {
int i;
int found = -1;
char message[128];
for (i = 0; i < NUM_CORETYPES; i++)
{
if (!strncasecmp(coretype, cpuname[i], 20))
{
found = i;
break;
}
}
if (found == CPU_Z13) {
#ifdef DYN_Z13
return &gotoblas_Z13;
#else
openblas_warning(1, "Z13 support not compiled in");
return NULL;
#endif
} else if (found == CPU_Z14) {
#ifdef DYN_Z14
return &gotoblas_Z14;
#else
openblas_warning(1, "Z14 support not compiled in");
return NULL;
#endif
} else if (found == CPU_GENERIC) {
return &gotoblas_ZARCH_GENERIC;
}
snprintf(message, 128, "Core not found: %s\n", coretype);
openblas_warning(1, message);
return NULL;
}
void gotoblas_dynamic_init(void) {
char coremsg[128];
char coren[22];
char* p;
if (gotoblas) return;
p = getenv("OPENBLAS_CORETYPE");
if (p)
{
gotoblas = force_coretype(p);
}
else
{
gotoblas = get_coretype();
if (openblas_verbose() >= 2) {
snprintf(coremsg, sizeof(coremsg), "Choosing kernels based on getauxval(AT_HWCAP)=0x%lx\n",
getauxval(AT_HWCAP));
openblas_warning(2, coremsg);
}
}
if (gotoblas == NULL)
{
snprintf(coremsg, 128, "Failed to detect system, falling back to generic z support.\n");
openblas_warning(1, coremsg);
gotoblas = &gotoblas_ZARCH_GENERIC;
}
if (gotoblas && gotoblas->init) {
if (openblas_verbose() >= 2) {
strncpy(coren, gotoblas_corename(), 20);
sprintf(coremsg, "Core: %s\n", coren);
openblas_warning(2, coremsg);
}
gotoblas->init();
}
else {
openblas_warning(0, "OpenBLAS : Architecture Initialization failed. No initialization function found.\n");
exit(1);
}
}
void gotoblas_dynamic_quit(void) {
gotoblas = NULL;
}