You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

dynamic_zarch.c 4.1 kB

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