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.

memory.c 33 kB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444
  1. /*****************************************************************************
  2. Copyright (c) 2011-2014, The OpenBLAS Project
  3. All rights reserved.
  4. Redistribution and use in source and binary forms, with or without
  5. modification, are permitted provided that the following conditions are
  6. met:
  7. 1. Redistributions of source code must retain the above copyright
  8. notice, this list of conditions and the following disclaimer.
  9. 2. Redistributions in binary form must reproduce the above copyright
  10. notice, this list of conditions and the following disclaimer in
  11. the documentation and/or other materials provided with the
  12. distribution.
  13. 3. Neither the name of the OpenBLAS project nor the names of
  14. its contributors may be used to endorse or promote products
  15. derived from this software without specific prior written
  16. permission.
  17. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  18. AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  19. IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  20. ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  21. LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  22. DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  23. SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  24. CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  25. OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
  26. USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  27. **********************************************************************************/
  28. /*********************************************************************/
  29. /* Copyright 2009, 2010 The University of Texas at Austin. */
  30. /* All rights reserved. */
  31. /* */
  32. /* Redistribution and use in source and binary forms, with or */
  33. /* without modification, are permitted provided that the following */
  34. /* conditions are met: */
  35. /* */
  36. /* 1. Redistributions of source code must retain the above */
  37. /* copyright notice, this list of conditions and the following */
  38. /* disclaimer. */
  39. /* */
  40. /* 2. Redistributions in binary form must reproduce the above */
  41. /* copyright notice, this list of conditions and the following */
  42. /* disclaimer in the documentation and/or other materials */
  43. /* provided with the distribution. */
  44. /* */
  45. /* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY OF TEXAS AT */
  46. /* AUSTIN ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, */
  47. /* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF */
  48. /* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE */
  49. /* DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OF TEXAS AT */
  50. /* AUSTIN OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, */
  51. /* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES */
  52. /* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE */
  53. /* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR */
  54. /* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF */
  55. /* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */
  56. /* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT */
  57. /* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE */
  58. /* POSSIBILITY OF SUCH DAMAGE. */
  59. /* */
  60. /* The views and conclusions contained in the software and */
  61. /* documentation are those of the authors and should not be */
  62. /* interpreted as representing official policies, either expressed */
  63. /* or implied, of The University of Texas at Austin. */
  64. /*********************************************************************/
  65. //#undef DEBUG
  66. #include "common.h"
  67. #include <errno.h>
  68. #ifdef OS_WINDOWS
  69. #define ALLOC_WINDOWS
  70. #ifndef MEM_LARGE_PAGES
  71. #define MEM_LARGE_PAGES 0x20000000
  72. #endif
  73. #else
  74. #define ALLOC_MMAP
  75. #define ALLOC_MALLOC
  76. #endif
  77. #include <stdlib.h>
  78. #include <stdio.h>
  79. #include <fcntl.h>
  80. #ifndef OS_WINDOWS
  81. #include <sys/mman.h>
  82. #ifndef NO_SYSV_IPC
  83. #include <sys/shm.h>
  84. #endif
  85. #include <sys/ipc.h>
  86. #endif
  87. #include <sys/types.h>
  88. #ifdef OS_LINUX
  89. #include <sys/sysinfo.h>
  90. #include <sched.h>
  91. #include <errno.h>
  92. #include <linux/unistd.h>
  93. #include <sys/syscall.h>
  94. #endif
  95. #if defined(OS_FREEBSD) || defined(OS_DARWIN)
  96. #include <sys/sysctl.h>
  97. #include <sys/resource.h>
  98. #endif
  99. #if defined(OS_WINDOWS) && (defined(__MINGW32__) || defined(__MINGW64__))
  100. #include <conio.h>
  101. #undef printf
  102. #define printf _cprintf
  103. #endif
  104. #ifdef OS_LINUX
  105. #ifndef MPOL_PREFERRED
  106. #define MPOL_PREFERRED 1
  107. #endif
  108. #endif
  109. #if (defined(PPC440) || !defined(OS_LINUX) || defined(HPL)) && !defined(NO_WARMUP)
  110. #define NO_WARMUP
  111. #endif
  112. #ifndef SHM_HUGETLB
  113. #define SHM_HUGETLB 04000
  114. #endif
  115. #ifndef FIXED_PAGESIZE
  116. #define FIXED_PAGESIZE 4096
  117. #endif
  118. #define BITMASK(a, b, c) ((((a) >> (b)) & (c)))
  119. #if defined(_MSC_VER) && !defined(__clang__)
  120. #define CONSTRUCTOR __cdecl
  121. #define DESTRUCTOR __cdecl
  122. #else
  123. #define CONSTRUCTOR __attribute__ ((constructor))
  124. #define DESTRUCTOR __attribute__ ((destructor))
  125. #endif
  126. #ifdef DYNAMIC_ARCH
  127. gotoblas_t *gotoblas = NULL;
  128. #endif
  129. extern void openblas_warning(int verbose, const char * msg);
  130. #ifndef SMP
  131. #define blas_cpu_number 1
  132. #define blas_num_threads 1
  133. /* Dummy Function */
  134. int goto_get_num_procs (void) { return 1;};
  135. void goto_set_num_threads(int num_threads) {};
  136. #else
  137. #ifdef OS_LINUX
  138. #ifndef NO_AFFINITY
  139. int get_num_procs(void);
  140. #else
  141. int get_num_procs(void) {
  142. static int nums = 0;
  143. if (!nums) nums = sysconf(_SC_NPROCESSORS_ONLN);
  144. return nums;
  145. }
  146. #endif
  147. #endif
  148. #ifdef OS_ANDROID
  149. int get_num_procs(void) {
  150. static int nums = 0;
  151. if (!nums) nums = sysconf(_SC_NPROCESSORS_ONLN);
  152. return nums;
  153. }
  154. #endif
  155. #ifdef OS_WINDOWS
  156. int get_num_procs(void) {
  157. static int nums = 0;
  158. if (nums == 0) {
  159. SYSTEM_INFO sysinfo;
  160. GetSystemInfo(&sysinfo);
  161. nums = sysinfo.dwNumberOfProcessors;
  162. }
  163. return nums;
  164. }
  165. #endif
  166. #if defined(OS_FREEBSD)
  167. int get_num_procs(void) {
  168. static int nums = 0;
  169. int m[2];
  170. size_t len;
  171. if (nums == 0) {
  172. m[0] = CTL_HW;
  173. m[1] = HW_NCPU;
  174. len = sizeof(int);
  175. sysctl(m, 2, &nums, &len, NULL, 0);
  176. }
  177. return nums;
  178. }
  179. #endif
  180. #if defined(OS_DARWIN)
  181. int get_num_procs(void) {
  182. static int nums = 0;
  183. size_t len;
  184. if (nums == 0){
  185. len = sizeof(int);
  186. sysctlbyname("hw.physicalcpu", &nums, &len, NULL, 0);
  187. }
  188. return nums;
  189. }
  190. /*
  191. void set_stack_limit(int limitMB){
  192. int result=0;
  193. struct rlimit rl;
  194. rlim_t StackSize;
  195. StackSize=limitMB*1024*1024;
  196. result=getrlimit(RLIMIT_STACK, &rl);
  197. if(result==0){
  198. if(rl.rlim_cur < StackSize){
  199. rl.rlim_cur=StackSize;
  200. result=setrlimit(RLIMIT_STACK, &rl);
  201. if(result !=0){
  202. fprintf(stderr, "OpenBLAS: set stack limit error =%d\n", result);
  203. }
  204. }
  205. }
  206. }
  207. */
  208. #endif
  209. /*
  210. OpenBLAS uses the numbers of CPU cores in multithreading.
  211. It can be set by openblas_set_num_threads(int num_threads);
  212. */
  213. int blas_cpu_number = 0;
  214. /*
  215. The numbers of threads in the thread pool.
  216. This value is equal or large than blas_cpu_number. This means some threads are sleep.
  217. */
  218. int blas_num_threads = 0;
  219. int goto_get_num_procs (void) {
  220. return blas_cpu_number;
  221. }
  222. void openblas_fork_handler()
  223. {
  224. // This handler shuts down the OpenBLAS-managed PTHREAD pool when OpenBLAS is
  225. // built with "make USE_OPENMP=0".
  226. // Hanging can still happen when OpenBLAS is built against the libgomp
  227. // implementation of OpenMP. The problem is tracked at:
  228. // http://gcc.gnu.org/bugzilla/show_bug.cgi?id=60035
  229. // In the mean time build with USE_OPENMP=0 or link against another
  230. // implementation of OpenMP.
  231. #if !(defined(OS_WINDOWS) || defined(OS_ANDROID)) && defined(SMP_SERVER)
  232. int err;
  233. err = pthread_atfork ((void (*)(void)) BLASFUNC(blas_thread_shutdown), NULL, NULL);
  234. if(err != 0)
  235. openblas_warning(0, "OpenBLAS Warning ... cannot install fork handler. You may meet hang after fork.\n");
  236. #endif
  237. }
  238. int blas_get_cpu_number(void){
  239. env_var_t p;
  240. #if defined(OS_LINUX) || defined(OS_WINDOWS) || defined(OS_FREEBSD) || defined(OS_DARWIN) || defined(OS_ANDROID)
  241. int max_num;
  242. #endif
  243. int blas_goto_num = 0;
  244. int blas_omp_num = 0;
  245. if (blas_num_threads) return blas_num_threads;
  246. #if defined(OS_LINUX) || defined(OS_WINDOWS) || defined(OS_FREEBSD) || defined(OS_DARWIN) || defined(OS_ANDROID)
  247. max_num = get_num_procs();
  248. #endif
  249. blas_goto_num = 0;
  250. #ifndef USE_OPENMP
  251. if (readenv(p,"OPENBLAS_NUM_THREADS")) blas_goto_num = atoi(p);
  252. if (blas_goto_num < 0) blas_goto_num = 0;
  253. if (blas_goto_num == 0) {
  254. if (readenv(p,"GOTO_NUM_THREADS")) blas_goto_num = atoi(p);
  255. if (blas_goto_num < 0) blas_goto_num = 0;
  256. }
  257. #endif
  258. blas_omp_num = 0;
  259. if (readenv(p,"OMP_NUM_THREADS")) blas_omp_num = atoi(p);
  260. if (blas_omp_num < 0) blas_omp_num = 0;
  261. if (blas_goto_num > 0) blas_num_threads = blas_goto_num;
  262. else if (blas_omp_num > 0) blas_num_threads = blas_omp_num;
  263. else blas_num_threads = MAX_CPU_NUMBER;
  264. #if defined(OS_LINUX) || defined(OS_WINDOWS) || defined(OS_FREEBSD) || defined(OS_DARWIN) || defined(OS_ANDROID)
  265. if (blas_num_threads > max_num) blas_num_threads = max_num;
  266. #endif
  267. if (blas_num_threads > MAX_CPU_NUMBER) blas_num_threads = MAX_CPU_NUMBER;
  268. #ifdef DEBUG
  269. printf( "Adjusted number of threads : %3d\n", blas_num_threads);
  270. #endif
  271. blas_cpu_number = blas_num_threads;
  272. return blas_num_threads;
  273. }
  274. #endif
  275. int openblas_get_num_procs(void) {
  276. #ifndef SMP
  277. return 1;
  278. #else
  279. return get_num_procs();
  280. #endif
  281. }
  282. int openblas_get_num_threads(void) {
  283. #ifndef SMP
  284. return 1;
  285. #else
  286. return blas_get_cpu_number();
  287. #endif
  288. }
  289. struct release_t {
  290. void *address;
  291. void (*func)(struct release_t *);
  292. long attr;
  293. };
  294. int hugetlb_allocated = 0;
  295. static struct release_t release_info[NUM_BUFFERS];
  296. static int release_pos = 0;
  297. #if defined(OS_LINUX) && !defined(NO_WARMUP)
  298. static int hot_alloc = 0;
  299. #endif
  300. #ifdef ALLOC_MMAP
  301. static void alloc_mmap_free(struct release_t *release){
  302. if (munmap(release -> address, BUFFER_SIZE)) {
  303. printf("OpenBLAS : munmap failed\n");
  304. }
  305. }
  306. #ifdef NO_WARMUP
  307. static void *alloc_mmap(void *address){
  308. void *map_address;
  309. if (address){
  310. map_address = mmap(address,
  311. BUFFER_SIZE,
  312. MMAP_ACCESS, MMAP_POLICY | MAP_FIXED, -1, 0);
  313. } else {
  314. map_address = mmap(address,
  315. BUFFER_SIZE,
  316. MMAP_ACCESS, MMAP_POLICY, -1, 0);
  317. }
  318. if (map_address != (void *)-1) {
  319. release_info[release_pos].address = map_address;
  320. release_info[release_pos].func = alloc_mmap_free;
  321. release_pos ++;
  322. }
  323. #ifdef OS_LINUX
  324. my_mbind(map_address, BUFFER_SIZE, MPOL_PREFERRED, NULL, 0, 0);
  325. #endif
  326. return map_address;
  327. }
  328. #else
  329. #define BENCH_ITERATION 4
  330. #define SCALING 2
  331. static inline BLASULONG run_bench(BLASULONG address, BLASULONG size) {
  332. BLASULONG original, *p;
  333. BLASULONG start, stop, min;
  334. int iter, i, count;
  335. min = (BLASULONG)-1;
  336. original = *(BLASULONG *)(address + size - PAGESIZE);
  337. *(BLASULONG *)(address + size - PAGESIZE) = (BLASULONG)address;
  338. for (iter = 0; iter < BENCH_ITERATION; iter ++ ) {
  339. p = (BLASULONG *)address;
  340. count = size / PAGESIZE;
  341. start = rpcc();
  342. for (i = 0; i < count; i ++) {
  343. p = (BLASULONG *)(*p);
  344. }
  345. stop = rpcc();
  346. if (min > stop - start) min = stop - start;
  347. }
  348. *(BLASULONG *)(address + size - PAGESIZE + 0) = original;
  349. *(BLASULONG *)(address + size - PAGESIZE + 8) = (BLASULONG)p;
  350. return min;
  351. }
  352. static void *alloc_mmap(void *address){
  353. void *map_address, *best_address;
  354. BLASULONG best, start, current;
  355. BLASULONG allocsize;
  356. if (address){
  357. /* Just give up use advanced operation */
  358. map_address = mmap(address, BUFFER_SIZE, MMAP_ACCESS, MMAP_POLICY | MAP_FIXED, -1, 0);
  359. #ifdef OS_LINUX
  360. my_mbind(map_address, BUFFER_SIZE, MPOL_PREFERRED, NULL, 0, 0);
  361. #endif
  362. } else {
  363. #if defined(OS_LINUX) && !defined(NO_WARMUP)
  364. if (hot_alloc == 0) {
  365. map_address = mmap(NULL, BUFFER_SIZE, MMAP_ACCESS, MMAP_POLICY, -1, 0);
  366. #ifdef OS_LINUX
  367. my_mbind(map_address, BUFFER_SIZE, MPOL_PREFERRED, NULL, 0, 0);
  368. #endif
  369. } else {
  370. #endif
  371. map_address = mmap(NULL, BUFFER_SIZE * SCALING,
  372. MMAP_ACCESS, MMAP_POLICY, -1, 0);
  373. if (map_address != (void *)-1) {
  374. #ifdef OS_LINUX
  375. #ifdef DEBUG
  376. int ret=0;
  377. ret=my_mbind(map_address, BUFFER_SIZE * SCALING, MPOL_PREFERRED, NULL, 0, 0);
  378. if(ret==-1){
  379. int errsv=errno;
  380. perror("OpenBLAS alloc_mmap:");
  381. printf("error code=%d,\tmap_address=%lx\n",errsv,map_address);
  382. }
  383. #else
  384. my_mbind(map_address, BUFFER_SIZE * SCALING, MPOL_PREFERRED, NULL, 0, 0);
  385. #endif
  386. #endif
  387. allocsize = DGEMM_P * DGEMM_Q * sizeof(double);
  388. start = (BLASULONG)map_address;
  389. current = (SCALING - 1) * BUFFER_SIZE;
  390. while(current > 0) {
  391. *(BLASLONG *)start = (BLASLONG)start + PAGESIZE;
  392. start += PAGESIZE;
  393. current -= PAGESIZE;
  394. }
  395. *(BLASLONG *)(start - PAGESIZE) = (BLASULONG)map_address;
  396. start = (BLASULONG)map_address;
  397. best = (BLASULONG)-1;
  398. best_address = map_address;
  399. while ((start + allocsize < (BLASULONG)map_address + (SCALING - 1) * BUFFER_SIZE)) {
  400. current = run_bench(start, allocsize);
  401. if (best > current) {
  402. best = current;
  403. best_address = (void *)start;
  404. }
  405. start += PAGESIZE;
  406. }
  407. if ((BLASULONG)best_address > (BLASULONG)map_address)
  408. munmap(map_address, (BLASULONG)best_address - (BLASULONG)map_address);
  409. munmap((void *)((BLASULONG)best_address + BUFFER_SIZE), (SCALING - 1) * BUFFER_SIZE + (BLASULONG)map_address - (BLASULONG)best_address);
  410. map_address = best_address;
  411. #if defined(OS_LINUX) && !defined(NO_WARMUP)
  412. hot_alloc = 2;
  413. #endif
  414. }
  415. }
  416. #if defined(OS_LINUX) && !defined(NO_WARMUP)
  417. }
  418. #endif
  419. if (map_address != (void *)-1) {
  420. release_info[release_pos].address = map_address;
  421. release_info[release_pos].func = alloc_mmap_free;
  422. release_pos ++;
  423. }
  424. return map_address;
  425. }
  426. #endif
  427. #endif
  428. #ifdef ALLOC_MALLOC
  429. static void alloc_malloc_free(struct release_t *release){
  430. free(release -> address);
  431. }
  432. static void *alloc_malloc(void *address){
  433. void *map_address;
  434. map_address = (void *)malloc(BUFFER_SIZE + FIXED_PAGESIZE);
  435. if (map_address == (void *)NULL) map_address = (void *)-1;
  436. if (map_address != (void *)-1) {
  437. release_info[release_pos].address = map_address;
  438. release_info[release_pos].func = alloc_malloc_free;
  439. release_pos ++;
  440. }
  441. return map_address;
  442. }
  443. #endif
  444. #ifdef ALLOC_QALLOC
  445. void *qalloc(int flags, size_t bytes);
  446. void *qfree (void *address);
  447. #define QNONCACHE 0x1
  448. #define QCOMMS 0x2
  449. #define QFAST 0x4
  450. static void alloc_qalloc_free(struct release_t *release){
  451. qfree(release -> address);
  452. }
  453. static void *alloc_qalloc(void *address){
  454. void *map_address;
  455. map_address = (void *)qalloc(QCOMMS | QFAST, BUFFER_SIZE + FIXED_PAGESIZE);
  456. if (map_address == (void *)NULL) map_address = (void *)-1;
  457. if (map_address != (void *)-1) {
  458. release_info[release_pos].address = map_address;
  459. release_info[release_pos].func = alloc_qalloc_free;
  460. release_pos ++;
  461. }
  462. return (void *)(((BLASULONG)map_address + FIXED_PAGESIZE - 1) & ~(FIXED_PAGESIZE - 1));
  463. }
  464. #endif
  465. #ifdef ALLOC_WINDOWS
  466. static void alloc_windows_free(struct release_t *release){
  467. VirtualFree(release -> address, BUFFER_SIZE, MEM_DECOMMIT);
  468. }
  469. static void *alloc_windows(void *address){
  470. void *map_address;
  471. map_address = VirtualAlloc(address,
  472. BUFFER_SIZE,
  473. MEM_RESERVE | MEM_COMMIT,
  474. PAGE_READWRITE);
  475. if (map_address == (void *)NULL) map_address = (void *)-1;
  476. if (map_address != (void *)-1) {
  477. release_info[release_pos].address = map_address;
  478. release_info[release_pos].func = alloc_windows_free;
  479. release_pos ++;
  480. }
  481. return map_address;
  482. }
  483. #endif
  484. #ifdef ALLOC_DEVICEDRIVER
  485. #ifndef DEVICEDRIVER_NAME
  486. #define DEVICEDRIVER_NAME "/dev/mapper"
  487. #endif
  488. static void alloc_devicedirver_free(struct release_t *release){
  489. if (munmap(release -> address, BUFFER_SIZE)) {
  490. printf("OpenBLAS : Bugphysarea unmap failed.\n");
  491. }
  492. if (close(release -> attr)) {
  493. printf("OpenBLAS : Bugphysarea close failed.\n");
  494. }
  495. }
  496. static void *alloc_devicedirver(void *address){
  497. int fd;
  498. void *map_address;
  499. if ((fd = open(DEVICEDRIVER_NAME, O_RDWR | O_SYNC)) < 0) {
  500. return (void *)-1;
  501. }
  502. map_address = mmap(address, BUFFER_SIZE,
  503. PROT_READ | PROT_WRITE,
  504. MAP_FILE | MAP_SHARED,
  505. fd, 0);
  506. if (map_address != (void *)-1) {
  507. release_info[release_pos].address = map_address;
  508. release_info[release_pos].attr = fd;
  509. release_info[release_pos].func = alloc_devicedirver_free;
  510. release_pos ++;
  511. }
  512. return map_address;
  513. }
  514. #endif
  515. #ifdef ALLOC_SHM
  516. static void alloc_shm_free(struct release_t *release){
  517. if (shmdt(release -> address)) {
  518. printf("OpenBLAS : Shared memory unmap failed.\n");
  519. }
  520. }
  521. static void *alloc_shm(void *address){
  522. void *map_address;
  523. int shmid;
  524. shmid = shmget(IPC_PRIVATE, BUFFER_SIZE,IPC_CREAT | 0600);
  525. map_address = (void *)shmat(shmid, address, 0);
  526. if (map_address != (void *)-1){
  527. #ifdef OS_LINUX
  528. my_mbind(map_address, BUFFER_SIZE, MPOL_PREFERRED, NULL, 0, 0);
  529. #endif
  530. shmctl(shmid, IPC_RMID, 0);
  531. release_info[release_pos].address = map_address;
  532. release_info[release_pos].attr = shmid;
  533. release_info[release_pos].func = alloc_shm_free;
  534. release_pos ++;
  535. }
  536. return map_address;
  537. }
  538. #if defined OS_LINUX || defined OS_AIX || defined __sun__ || defined OS_WINDOWS
  539. static void alloc_hugetlb_free(struct release_t *release){
  540. #if defined(OS_LINUX) || defined(OS_AIX)
  541. if (shmdt(release -> address)) {
  542. printf("OpenBLAS : Hugepage unmap failed.\n");
  543. }
  544. #endif
  545. #ifdef __sun__
  546. munmap(release -> address, BUFFER_SIZE);
  547. #endif
  548. #ifdef OS_WINDOWS
  549. VirtualFree(release -> address, BUFFER_SIZE, MEM_LARGE_PAGES | MEM_DECOMMIT);
  550. #endif
  551. }
  552. static void *alloc_hugetlb(void *address){
  553. void *map_address = (void *)-1;
  554. #if defined(OS_LINUX) || defined(OS_AIX)
  555. int shmid;
  556. shmid = shmget(IPC_PRIVATE, BUFFER_SIZE,
  557. #ifdef OS_LINUX
  558. SHM_HUGETLB |
  559. #endif
  560. #ifdef OS_AIX
  561. SHM_LGPAGE | SHM_PIN |
  562. #endif
  563. IPC_CREAT | SHM_R | SHM_W);
  564. if (shmid != -1) {
  565. map_address = (void *)shmat(shmid, address, SHM_RND);
  566. #ifdef OS_LINUX
  567. my_mbind(map_address, BUFFER_SIZE, MPOL_PREFERRED, NULL, 0, 0);
  568. #endif
  569. if (map_address != (void *)-1){
  570. shmctl(shmid, IPC_RMID, 0);
  571. }
  572. }
  573. #endif
  574. #ifdef __sun__
  575. struct memcntl_mha mha;
  576. mha.mha_cmd = MHA_MAPSIZE_BSSBRK;
  577. mha.mha_flags = 0;
  578. mha.mha_pagesize = HUGE_PAGESIZE;
  579. memcntl(NULL, 0, MC_HAT_ADVISE, (char *)&mha, 0, 0);
  580. map_address = (BLASULONG)memalign(HUGE_PAGESIZE, BUFFER_SIZE);
  581. #endif
  582. #ifdef OS_WINDOWS
  583. HANDLE hToken;
  584. TOKEN_PRIVILEGES tp;
  585. if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken) != TRUE) return (void *) -1;
  586. tp.PrivilegeCount = 1;
  587. tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  588. if (LookupPrivilegeValue(NULL, SE_LOCK_MEMORY_NAME, &tp.Privileges[0].Luid) != TRUE) {
  589. CloseHandle(hToken);
  590. return (void*)-1;
  591. }
  592. if (AdjustTokenPrivileges(hToken, FALSE, &tp, 0, NULL, NULL) != TRUE) {
  593. CloseHandle(hToken);
  594. return (void*)-1;
  595. }
  596. map_address = (void *)VirtualAlloc(address,
  597. BUFFER_SIZE,
  598. MEM_LARGE_PAGES | MEM_RESERVE | MEM_COMMIT,
  599. PAGE_READWRITE);
  600. tp.Privileges[0].Attributes = 0;
  601. AdjustTokenPrivileges(hToken, FALSE, &tp, 0, NULL, NULL);
  602. if (map_address == (void *)NULL) map_address = (void *)-1;
  603. #endif
  604. if (map_address != (void *)-1){
  605. release_info[release_pos].address = map_address;
  606. release_info[release_pos].func = alloc_hugetlb_free;
  607. release_pos ++;
  608. }
  609. return map_address;
  610. }
  611. #endif
  612. #endif
  613. #ifdef ALLOC_HUGETLBFILE
  614. static int hugetlb_pid = 0;
  615. static void alloc_hugetlbfile_free(struct release_t *release){
  616. if (munmap(release -> address, BUFFER_SIZE)) {
  617. printf("OpenBLAS : HugeTLBfs unmap failed.\n");
  618. }
  619. if (close(release -> attr)) {
  620. printf("OpenBLAS : HugeTLBfs close failed.\n");
  621. }
  622. }
  623. static void *alloc_hugetlbfile(void *address){
  624. void *map_address = (void *)-1;
  625. int fd;
  626. char filename[64];
  627. if (!hugetlb_pid) hugetlb_pid = getpid();
  628. sprintf(filename, "%s/gotoblas.%d", HUGETLB_FILE_NAME, hugetlb_pid);
  629. if ((fd = open(filename, O_RDWR | O_CREAT, 0700)) < 0) {
  630. return (void *)-1;
  631. }
  632. unlink(filename);
  633. map_address = mmap(address, BUFFER_SIZE,
  634. PROT_READ | PROT_WRITE,
  635. MAP_SHARED,
  636. fd, 0);
  637. if (map_address != (void *)-1) {
  638. release_info[release_pos].address = map_address;
  639. release_info[release_pos].attr = fd;
  640. release_info[release_pos].func = alloc_hugetlbfile_free;
  641. release_pos ++;
  642. }
  643. return map_address;
  644. }
  645. #endif
  646. /* Global lock for memory allocation */
  647. #if defined(USE_PTHREAD_LOCK)
  648. static pthread_mutex_t alloc_lock = PTHREAD_MUTEX_INITIALIZER;
  649. #elif defined(USE_PTHREAD_SPINLOCK)
  650. static pthread_spinlock_t alloc_lock = 0;
  651. #else
  652. static BLASULONG alloc_lock = 0UL;
  653. #endif
  654. #ifdef SEEK_ADDRESS
  655. static BLASULONG base_address = 0UL;
  656. #else
  657. static BLASULONG base_address = BASE_ADDRESS;
  658. #endif
  659. static volatile struct {
  660. BLASULONG lock;
  661. void *addr;
  662. #if defined(WHEREAMI) && !defined(USE_OPENMP)
  663. int pos;
  664. #endif
  665. int used;
  666. #ifndef __64BIT__
  667. char dummy[48];
  668. #else
  669. char dummy[40];
  670. #endif
  671. } memory[NUM_BUFFERS];
  672. static int memory_initialized = 0;
  673. static void gotoblas_memory_init(void);
  674. /* Memory allocation routine */
  675. /* procpos ... indicates where it comes from */
  676. /* 0 : Level 3 functions */
  677. /* 1 : Level 2 functions */
  678. /* 2 : Thread */
  679. void *blas_memory_alloc(int procpos){
  680. int position;
  681. #if defined(WHEREAMI) && !defined(USE_OPENMP)
  682. int mypos;
  683. #endif
  684. void *map_address;
  685. void *(*memoryalloc[])(void *address) = {
  686. #ifdef ALLOC_DEVICEDRIVER
  687. alloc_devicedirver,
  688. #endif
  689. /* Hugetlb implicitly assumes ALLOC_SHM */
  690. #ifdef ALLOC_SHM
  691. alloc_shm,
  692. #endif
  693. #if ((defined ALLOC_SHM) && (defined OS_LINUX || defined OS_AIX || defined __sun__ || defined OS_WINDOWS))
  694. alloc_hugetlb,
  695. #endif
  696. #ifdef ALLOC_MMAP
  697. alloc_mmap,
  698. #endif
  699. #ifdef ALLOC_QALLOC
  700. alloc_qalloc,
  701. #endif
  702. #ifdef ALLOC_WINDOWS
  703. alloc_windows,
  704. #endif
  705. #ifdef ALLOC_MALLOC
  706. alloc_malloc,
  707. #endif
  708. NULL,
  709. };
  710. void *(**func)(void *address);
  711. if (!memory_initialized) {
  712. LOCK_COMMAND(&alloc_lock);
  713. if (!memory_initialized) {
  714. #if defined(WHEREAMI) && !defined(USE_OPENMP)
  715. for (position = 0; position < NUM_BUFFERS; position ++){
  716. memory[position].addr = (void *)0;
  717. memory[position].pos = -1;
  718. memory[position].used = 0;
  719. memory[position].lock = 0;
  720. }
  721. #endif
  722. #ifdef DYNAMIC_ARCH
  723. gotoblas_dynamic_init();
  724. #endif
  725. #if defined(SMP) && defined(OS_LINUX) && !defined(NO_AFFINITY)
  726. gotoblas_affinity_init();
  727. #endif
  728. #ifdef SMP
  729. if (!blas_num_threads) blas_cpu_number = blas_get_cpu_number();
  730. #endif
  731. #if defined(ARCH_X86) || defined(ARCH_X86_64) || defined(ARCH_IA64) || defined(ARCH_MIPS64)
  732. #ifndef DYNAMIC_ARCH
  733. blas_set_parameter();
  734. #endif
  735. #endif
  736. memory_initialized = 1;
  737. }
  738. UNLOCK_COMMAND(&alloc_lock);
  739. }
  740. #ifdef DEBUG
  741. printf("Alloc Start ...\n");
  742. #endif
  743. #if defined(WHEREAMI) && !defined(USE_OPENMP)
  744. mypos = WhereAmI();
  745. position = mypos;
  746. while (position > NUM_BUFFERS) position >>= 1;
  747. do {
  748. if (!memory[position].used && (memory[position].pos == mypos)) {
  749. blas_lock(&memory[position].lock);
  750. if (!memory[position].used) goto allocation;
  751. blas_unlock(&memory[position].lock);
  752. }
  753. position ++;
  754. } while (position < NUM_BUFFERS);
  755. #endif
  756. position = 0;
  757. do {
  758. if (!memory[position].used) {
  759. blas_lock(&memory[position].lock);
  760. if (!memory[position].used) goto allocation;
  761. blas_unlock(&memory[position].lock);
  762. }
  763. position ++;
  764. } while (position < NUM_BUFFERS);
  765. goto error;
  766. allocation :
  767. #ifdef DEBUG
  768. printf(" Position -> %d\n", position);
  769. #endif
  770. memory[position].used = 1;
  771. blas_unlock(&memory[position].lock);
  772. if (!memory[position].addr) {
  773. do {
  774. #ifdef DEBUG
  775. printf("Allocation Start : %lx\n", base_address);
  776. #endif
  777. map_address = (void *)-1;
  778. func = &memoryalloc[0];
  779. while ((func != NULL) && (map_address == (void *) -1)) {
  780. map_address = (*func)((void *)base_address);
  781. #ifdef ALLOC_DEVICEDRIVER
  782. if ((*func == alloc_devicedirver) && (map_address == (void *)-1)) {
  783. fprintf(stderr, "OpenBLAS Warning ... Physically contigous allocation was failed.\n");
  784. }
  785. #endif
  786. #ifdef ALLOC_HUGETLBFILE
  787. if ((*func == alloc_hugetlbfile) && (map_address == (void *)-1)) {
  788. #ifndef OS_WINDOWS
  789. fprintf(stderr, "OpenBLAS Warning ... HugeTLB(File) allocation was failed.\n");
  790. #endif
  791. }
  792. #endif
  793. #if (defined ALLOC_SHM) && (defined OS_LINUX || defined OS_AIX || defined __sun__ || defined OS_WINDOWS)
  794. if ((*func == alloc_hugetlb) && (map_address != (void *)-1)) hugetlb_allocated = 1;
  795. #endif
  796. func ++;
  797. }
  798. #ifdef DEBUG
  799. printf(" Success -> %08lx\n", map_address);
  800. #endif
  801. if (((BLASLONG) map_address) == -1) base_address = 0UL;
  802. if (base_address) base_address += BUFFER_SIZE + FIXED_PAGESIZE;
  803. } while ((BLASLONG)map_address == -1);
  804. memory[position].addr = map_address;
  805. #ifdef DEBUG
  806. printf(" Mapping Succeeded. %p(%d)\n", (void *)memory[position].addr, position);
  807. #endif
  808. }
  809. #if defined(WHEREAMI) && !defined(USE_OPENMP)
  810. if (memory[position].pos == -1) memory[position].pos = mypos;
  811. #endif
  812. #ifdef DYNAMIC_ARCH
  813. if (memory_initialized == 1) {
  814. LOCK_COMMAND(&alloc_lock);
  815. if (memory_initialized == 1) {
  816. if (!gotoblas) gotoblas_dynamic_init();
  817. memory_initialized = 2;
  818. }
  819. UNLOCK_COMMAND(&alloc_lock);
  820. }
  821. #endif
  822. #ifdef DEBUG
  823. printf("Mapped : %p %3d\n\n",
  824. (void *)memory[position].addr, position);
  825. #endif
  826. return (void *)memory[position].addr;
  827. error:
  828. printf("BLAS : Program is Terminated. Because you tried to allocate too many memory regions.\n");
  829. return NULL;
  830. }
  831. void blas_memory_free(void *free_area){
  832. int position;
  833. #ifdef DEBUG
  834. printf("Unmapped Start : %p ...\n", free_area);
  835. #endif
  836. position = 0;
  837. while ((memory[position].addr != free_area)
  838. && (position < NUM_BUFFERS)) position++;
  839. if (memory[position].addr != free_area) goto error;
  840. #ifdef DEBUG
  841. printf(" Position : %d\n", position);
  842. #endif
  843. memory[position].used = 0;
  844. #ifdef DEBUG
  845. printf("Unmap Succeeded.\n\n");
  846. #endif
  847. return;
  848. error:
  849. printf("BLAS : Bad memory unallocation! : %4d %p\n", position, free_area);
  850. #ifdef DEBUG
  851. for (position = 0; position < NUM_BUFFERS; position++)
  852. printf("%4ld %p : %d\n", position, memory[position].addr, memory[position].used);
  853. #endif
  854. return;
  855. }
  856. void *blas_memory_alloc_nolock(int unused) {
  857. void *map_address;
  858. map_address = (void *)malloc(BUFFER_SIZE + FIXED_PAGESIZE);
  859. return map_address;
  860. }
  861. void blas_memory_free_nolock(void * map_address) {
  862. free(map_address);
  863. }
  864. void blas_shutdown(void){
  865. int pos;
  866. #ifdef SMP
  867. BLASFUNC(blas_thread_shutdown)();
  868. #endif
  869. LOCK_COMMAND(&alloc_lock);
  870. for (pos = 0; pos < release_pos; pos ++) {
  871. release_info[pos].func(&release_info[pos]);
  872. }
  873. #ifdef SEEK_ADDRESS
  874. base_address = 0UL;
  875. #else
  876. base_address = BASE_ADDRESS;
  877. #endif
  878. for (pos = 0; pos < NUM_BUFFERS; pos ++){
  879. memory[pos].addr = (void *)0;
  880. memory[pos].used = 0;
  881. #if defined(WHEREAMI) && !defined(USE_OPENMP)
  882. memory[pos].pos = -1;
  883. #endif
  884. memory[pos].lock = 0;
  885. }
  886. UNLOCK_COMMAND(&alloc_lock);
  887. return;
  888. }
  889. #if defined(OS_LINUX) && !defined(NO_WARMUP)
  890. #ifdef SMP
  891. #if defined(USE_PTHREAD_LOCK)
  892. static pthread_mutex_t init_lock = PTHREAD_MUTEX_INITIALIZER;
  893. #elif defined(USE_PTHREAD_SPINLOCK)
  894. static pthread_spinlock_t init_lock = 0;
  895. #else
  896. static BLASULONG init_lock = 0UL;
  897. #endif
  898. #endif
  899. static void _touch_memory(blas_arg_t *arg, BLASLONG *range_m, BLASLONG *range_n,
  900. void *sa, void *sb, BLASLONG pos) {
  901. #if !defined(ARCH_POWER) && !defined(ARCH_SPARC)
  902. size_t size;
  903. BLASULONG buffer;
  904. size = BUFFER_SIZE - PAGESIZE;
  905. buffer = (BLASULONG)sa + GEMM_OFFSET_A;
  906. #if defined(OS_LINUX) && !defined(NO_WARMUP)
  907. if (hot_alloc != 2) {
  908. #endif
  909. #ifdef SMP
  910. LOCK_COMMAND(&init_lock);
  911. #endif
  912. while (size > 0) {
  913. *(int *)buffer = size;
  914. buffer += PAGESIZE;
  915. size -= PAGESIZE;
  916. }
  917. #ifdef SMP
  918. UNLOCK_COMMAND(&init_lock);
  919. #endif
  920. size = MIN((BUFFER_SIZE - PAGESIZE), L2_SIZE);
  921. buffer = (BLASULONG)sa + GEMM_OFFSET_A;
  922. while (size > 0) {
  923. *(int *)buffer = size;
  924. buffer += 64;
  925. size -= 64;
  926. }
  927. #if defined(OS_LINUX) && !defined(NO_WARMUP)
  928. }
  929. #endif
  930. #endif
  931. }
  932. #ifdef SMP
  933. static void _init_thread_memory(void *buffer) {
  934. blas_queue_t queue[MAX_CPU_NUMBER];
  935. int num_cpu;
  936. for (num_cpu = 0; num_cpu < blas_num_threads; num_cpu++) {
  937. blas_queue_init(&queue[num_cpu]);
  938. queue[num_cpu].mode = BLAS_DOUBLE | BLAS_REAL;
  939. queue[num_cpu].routine = &_touch_memory;
  940. queue[num_cpu].args = NULL;
  941. queue[num_cpu].next = &queue[num_cpu + 1];
  942. }
  943. queue[num_cpu - 1].next = NULL;
  944. queue[0].sa = buffer;
  945. exec_blas(num_cpu, queue);
  946. }
  947. #endif
  948. static void gotoblas_memory_init(void) {
  949. void *buffer;
  950. hot_alloc = 1;
  951. buffer = (void *)blas_memory_alloc(0);
  952. #ifdef SMP
  953. if (blas_cpu_number == 0) blas_get_cpu_number();
  954. #ifdef SMP_SERVER
  955. if (blas_server_avail == 0) blas_thread_init();
  956. #endif
  957. _init_thread_memory((void *)((BLASULONG)buffer + GEMM_OFFSET_A));
  958. #else
  959. _touch_memory(NULL, NULL, NULL, (void *)((BLASULONG)buffer + GEMM_OFFSET_A), NULL, 0);
  960. #endif
  961. blas_memory_free(buffer);
  962. }
  963. #endif
  964. /* Initialization for all function; this function should be called before main */
  965. static int gotoblas_initialized = 0;
  966. void CONSTRUCTOR gotoblas_init(void) {
  967. if (gotoblas_initialized) return;
  968. #ifdef SMP
  969. openblas_fork_handler();
  970. #endif
  971. #ifdef PROFILE
  972. moncontrol (0);
  973. #endif
  974. #ifdef DYNAMIC_ARCH
  975. gotoblas_dynamic_init();
  976. #endif
  977. #if defined(SMP) && defined(OS_LINUX) && !defined(NO_AFFINITY)
  978. gotoblas_affinity_init();
  979. #endif
  980. #if defined(OS_LINUX) && !defined(NO_WARMUP)
  981. gotoblas_memory_init();
  982. #endif
  983. #ifdef SMP
  984. if (blas_cpu_number == 0) blas_get_cpu_number();
  985. #ifdef SMP_SERVER
  986. if (blas_server_avail == 0) blas_thread_init();
  987. #endif
  988. #endif
  989. #ifdef FUNCTION_PROFILE
  990. gotoblas_profile_init();
  991. #endif
  992. gotoblas_initialized = 1;
  993. #ifdef PROFILE
  994. moncontrol (1);
  995. #endif
  996. }
  997. void DESTRUCTOR gotoblas_quit(void) {
  998. if (gotoblas_initialized == 0) return;
  999. blas_shutdown();
  1000. #ifdef PROFILE
  1001. moncontrol (0);
  1002. #endif
  1003. #ifdef FUNCTION_PROFILE
  1004. gotoblas_profile_quit();
  1005. #endif
  1006. #if defined(SMP) && defined(OS_LINUX) && !defined(NO_AFFINITY)
  1007. gotoblas_affinity_quit();
  1008. #endif
  1009. #ifdef DYNAMIC_ARCH
  1010. gotoblas_dynamic_quit();
  1011. #endif
  1012. gotoblas_initialized = 0;
  1013. #ifdef PROFILE
  1014. moncontrol (1);
  1015. #endif
  1016. }
  1017. #if defined(_MSC_VER) && !defined(__clang__)
  1018. BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
  1019. {
  1020. switch (ul_reason_for_call)
  1021. {
  1022. case DLL_PROCESS_ATTACH:
  1023. gotoblas_init();
  1024. break;
  1025. case DLL_THREAD_ATTACH:
  1026. break;
  1027. case DLL_THREAD_DETACH:
  1028. break;
  1029. case DLL_PROCESS_DETACH:
  1030. gotoblas_quit();
  1031. break;
  1032. default:
  1033. break;
  1034. }
  1035. return TRUE;
  1036. }
  1037. #endif
  1038. #if (defined(C_PGI) || (!defined(C_SUN) && defined(F_INTERFACE_SUN))) && (defined(ARCH_X86) || defined(ARCH_X86_64))
  1039. /* Don't call me; this is just work around for PGI / Sun bug */
  1040. void gotoblas_dummy_for_PGI(void) {
  1041. gotoblas_init();
  1042. gotoblas_quit();
  1043. #if 0
  1044. asm ("\t.section\t.ctors,\"aw\",@progbits; .align 8; .quad gotoblas_init; .section .text");
  1045. asm ("\t.section\t.dtors,\"aw\",@progbits; .align 8; .quad gotoblas_quit; .section .text");
  1046. #else
  1047. asm (".section .init,\"ax\"; call gotoblas_init@PLT; .section .text");
  1048. asm (".section .fini,\"ax\"; call gotoblas_quit@PLT; .section .text");
  1049. #endif
  1050. }
  1051. #endif