Delete the pthread key on cleanup in TLS mode
[platform/upstream/openblas.git] / driver / others / memory.c
1 /*****************************************************************************
2 Copyright (c) 2011-2014, The OpenBLAS Project
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are
7 met:
8
9    1. Redistributions of source code must retain the above copyright
10       notice, this list of conditions and the following disclaimer.
11
12    2. Redistributions in binary form must reproduce the above copyright
13       notice, this list of conditions and the following disclaimer in
14       the documentation and/or other materials provided with the
15       distribution.
16    3. Neither the name of the OpenBLAS project nor the names of
17       its contributors may be used to endorse or promote products
18       derived from this software without specific prior written
19       permission.
20
21 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
30 USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
32 **********************************************************************************/
33
34 /*********************************************************************/
35 /* Copyright 2009, 2010 The University of Texas at Austin.           */
36 /* All rights reserved.                                              */
37 /*                                                                   */
38 /* Redistribution and use in source and binary forms, with or        */
39 /* without modification, are permitted provided that the following   */
40 /* conditions are met:                                               */
41 /*                                                                   */
42 /*   1. Redistributions of source code must retain the above         */
43 /*      copyright notice, this list of conditions and the following  */
44 /*      disclaimer.                                                  */
45 /*                                                                   */
46 /*   2. Redistributions in binary form must reproduce the above      */
47 /*      copyright notice, this list of conditions and the following  */
48 /*      disclaimer in the documentation and/or other materials       */
49 /*      provided with the distribution.                              */
50 /*                                                                   */
51 /*    THIS  SOFTWARE IS PROVIDED  BY THE  UNIVERSITY OF  TEXAS AT    */
52 /*    AUSTIN  ``AS IS''  AND ANY  EXPRESS OR  IMPLIED WARRANTIES,    */
53 /*    INCLUDING, BUT  NOT LIMITED  TO, THE IMPLIED  WARRANTIES OF    */
54 /*    MERCHANTABILITY  AND FITNESS FOR  A PARTICULAR  PURPOSE ARE    */
55 /*    DISCLAIMED.  IN  NO EVENT SHALL THE UNIVERSITY  OF TEXAS AT    */
56 /*    AUSTIN OR CONTRIBUTORS BE  LIABLE FOR ANY DIRECT, INDIRECT,    */
57 /*    INCIDENTAL,  SPECIAL, EXEMPLARY,  OR  CONSEQUENTIAL DAMAGES    */
58 /*    (INCLUDING, BUT  NOT LIMITED TO,  PROCUREMENT OF SUBSTITUTE    */
59 /*    GOODS  OR  SERVICES; LOSS  OF  USE,  DATA,  OR PROFITS;  OR    */
60 /*    BUSINESS INTERRUPTION) HOWEVER CAUSED  AND ON ANY THEORY OF    */
61 /*    LIABILITY, WHETHER  IN CONTRACT, STRICT  LIABILITY, OR TORT    */
62 /*    (INCLUDING NEGLIGENCE OR OTHERWISE)  ARISING IN ANY WAY OUT    */
63 /*    OF  THE  USE OF  THIS  SOFTWARE,  EVEN  IF ADVISED  OF  THE    */
64 /*    POSSIBILITY OF SUCH DAMAGE.                                    */
65 /*                                                                   */
66 /* The views and conclusions contained in the software and           */
67 /* documentation are those of the authors and should not be          */
68 /* interpreted as representing official policies, either expressed   */
69 /* or implied, of The University of Texas at Austin.                 */
70 /*********************************************************************/
71
72 //#undef  DEBUG
73
74 #include "common.h"
75
76 #if defined(USE_TLS) && defined(SMP)
77 #define COMPILE_TLS
78
79 #if USE_TLS != 1
80 #undef COMPILE_TLS
81 #endif
82
83 #if defined(__GLIBC_PREREQ) 
84 #if !__GLIBC_PREREQ(2,20)
85 #undef COMPILE_TLS
86 #endif
87 #endif
88 #endif
89
90 #if defined(COMPILE_TLS)
91
92 #include <errno.h>
93
94 #if defined(OS_WINDOWS) && !defined(OS_CYGWIN_NT)
95 #define ALLOC_WINDOWS
96 #ifndef MEM_LARGE_PAGES
97 #define MEM_LARGE_PAGES  0x20000000
98 #endif
99 #else
100 #define ALLOC_MMAP
101 #define ALLOC_MALLOC
102 #endif
103
104 #include <stdlib.h>
105 #include <stdio.h>
106 #include <fcntl.h>
107
108 #if !defined(OS_WINDOWS) || defined(OS_CYGWIN_NT)
109 #include <sys/mman.h>
110 #ifndef NO_SYSV_IPC
111 #include <sys/shm.h>
112 #endif
113 #include <sys/ipc.h>
114 #endif
115
116 #include <sys/types.h>
117
118 #ifdef OS_LINUX
119 #include <sys/sysinfo.h>
120 #include <sched.h>
121 #include <errno.h>
122 #include <linux/unistd.h>
123 #include <sys/syscall.h>
124 #include <sys/time.h>
125 #include <sys/resource.h>
126 #endif
127
128 #ifdef OS_HAIKU
129 #include <unistd.h>
130 #endif
131
132 #if defined(OS_FREEBSD) || defined(OS_OPENBSD) || defined(OS_DRAGONFLY) || defined(OS_DARWIN)
133 #include <sys/sysctl.h>
134 #include <sys/resource.h>
135 #endif
136
137 #if defined(OS_WINDOWS) && (defined(__MINGW32__) || defined(__MINGW64__))
138 #include <conio.h>
139 #undef  printf
140 #define printf  _cprintf
141 #endif
142
143 #ifdef OS_LINUX
144
145 #ifndef MPOL_PREFERRED
146 #define MPOL_PREFERRED  1
147 #endif
148
149 #endif
150
151 #if (defined(PPC440) || !defined(OS_LINUX) || defined(HPL)) && !defined(NO_WARMUP)
152 #define NO_WARMUP
153 #endif
154
155 #ifndef SHM_HUGETLB
156 #define SHM_HUGETLB 04000
157 #endif
158
159 #ifndef FIXED_PAGESIZE
160 #define FIXED_PAGESIZE 4096
161 #endif
162
163 #define BITMASK(a, b, c) ((((a) >> (b)) & (c)))
164
165 #if defined(_MSC_VER) && !defined(__clang__)
166 #define CONSTRUCTOR __cdecl
167 #define DESTRUCTOR __cdecl
168 #elif (defined(OS_DARWIN) || defined(OS_SUNOS)) && defined(C_GCC)
169 #define CONSTRUCTOR     __attribute__ ((constructor))
170 #define DESTRUCTOR      __attribute__ ((destructor))
171 #elif __GNUC__ && INIT_PRIORITY && ((GCC_VERSION >= 40300) || (CLANG_VERSION >= 20900))
172 #define CONSTRUCTOR     __attribute__ ((constructor(101)))
173 #define DESTRUCTOR      __attribute__ ((destructor(101)))
174 #else
175 #define CONSTRUCTOR     __attribute__ ((constructor))
176 #define DESTRUCTOR      __attribute__ ((destructor))
177 #endif
178
179 #ifdef DYNAMIC_ARCH
180 gotoblas_t *gotoblas = NULL;
181 #endif
182 extern void openblas_warning(int verbose, const char * msg);
183
184 #ifndef SMP
185
186 #define blas_cpu_number 1
187 #define blas_num_threads 1
188
189 /* Dummy Function */
190 int  goto_get_num_procs  (void) { return 1;};
191 void goto_set_num_threads(int num_threads) {};
192
193 #else
194
195 #if defined(OS_LINUX) || defined(OS_SUNOS) || defined(OS_NETBSD)
196 #ifndef NO_AFFINITY
197 int get_num_procs(void);
198 #else
199 int get_num_procs(void) {
200   static int nums = 0;
201 cpu_set_t *cpusetp;
202 size_t size;
203 int ret;
204 int i,n;
205
206   if (!nums) nums = sysconf(_SC_NPROCESSORS_CONF);
207 #if !defined(OS_LINUX)
208      return nums;
209 #endif
210
211 #if !defined(__GLIBC_PREREQ)
212    return nums;
213 #else
214  #if !__GLIBC_PREREQ(2, 3)
215    return nums;
216  #endif
217
218  #if !__GLIBC_PREREQ(2, 7)
219   ret = sched_getaffinity(0,sizeof(cpu_set_t), cpusetp);
220   if (ret!=0) return nums;
221   n=0;
222   #if !__GLIBC_PREREQ(2, 6)
223   for (i=0;i<nums;i++)
224      if (CPU_ISSET(i,cpusetp)) n++;
225   nums=n;
226   #else
227   nums = CPU_COUNT(sizeof(cpu_set_t),cpusetp);
228   #endif
229   return nums;
230  #else
231   cpusetp = CPU_ALLOC(nums);
232   if (cpusetp == NULL) return nums;
233   size = CPU_ALLOC_SIZE(nums);
234   ret = sched_getaffinity(0,size,cpusetp);
235   if (ret!=0) return nums;
236   ret = CPU_COUNT_S(size,cpusetp);
237   if (ret > 0 && ret < nums) nums = ret;
238   CPU_FREE(cpusetp);
239   return nums;
240  #endif
241 #endif
242 }
243 #endif
244 #endif
245
246 #ifdef OS_ANDROID
247 int get_num_procs(void) {
248   static int nums = 0;
249   if (!nums) nums = sysconf(_SC_NPROCESSORS_CONF);
250   return nums;
251 }
252 #endif
253
254 #ifdef OS_HAIKU
255 int get_num_procs(void) {
256   static int nums = 0;
257   if (!nums) nums = sysconf(_SC_NPROCESSORS_CONF);
258   return nums;
259 }
260 #endif
261
262 #ifdef OS_AIX
263 int get_num_procs(void) {
264   static int nums = 0;
265   if (!nums) nums = sysconf(_SC_NPROCESSORS_CONF);
266   return nums;
267 }
268 #endif
269
270
271
272 #ifdef OS_WINDOWS
273
274 int get_num_procs(void) {
275
276   static int nums = 0;
277
278   if (nums == 0) {
279
280     SYSTEM_INFO sysinfo;
281
282     GetSystemInfo(&sysinfo);
283
284     nums = sysinfo.dwNumberOfProcessors;
285   }
286
287   return nums;
288 }
289
290 #endif
291
292 #if defined(OS_FREEBSD) || defined(OS_OPENBSD) || defined(OS_DRAGONFLY)
293
294 int get_num_procs(void) {
295
296   static int nums = 0;
297
298   int m[2];
299   size_t len;
300
301   if (nums == 0) {
302     m[0] = CTL_HW;
303     m[1] = HW_NCPU;
304     len = sizeof(int);
305     sysctl(m, 2, &nums, &len, NULL, 0);
306   }
307
308   return nums;
309 }
310
311 #endif
312
313 #if defined(OS_DARWIN)
314 int get_num_procs(void) {
315   static int nums = 0;
316   size_t len;
317   if (nums == 0){
318     len = sizeof(int);
319     sysctlbyname("hw.physicalcpu", &nums, &len, NULL, 0);
320   }
321   return nums;
322 }
323 /*
324 void set_stack_limit(int limitMB){
325   int result=0;
326   struct rlimit rl;
327   rlim_t StackSize;
328
329   StackSize=limitMB*1024*1024;
330   result=getrlimit(RLIMIT_STACK, &rl);
331   if(result==0){
332     if(rl.rlim_cur < StackSize){
333       rl.rlim_cur=StackSize;
334       result=setrlimit(RLIMIT_STACK, &rl);
335       if(result !=0){
336         fprintf(stderr, "OpenBLAS: set stack limit error =%d\n", result);
337       }
338     }
339   }
340 }
341 */
342 #endif
343
344
345 /*
346 OpenBLAS uses the numbers of CPU cores in multithreading.
347 It can be set by openblas_set_num_threads(int num_threads);
348 */
349 int blas_cpu_number  = 0;
350 /*
351 The numbers of threads in the thread pool.
352 This value is equal or large than blas_cpu_number. This means some threads are sleep.
353 */
354 int blas_num_threads = 0;
355
356 int  goto_get_num_procs  (void) {
357   return blas_cpu_number;
358 }
359
360 static void blas_memory_init();
361
362 void openblas_fork_handler()
363 {
364   // This handler shuts down the OpenBLAS-managed PTHREAD pool when OpenBLAS is
365   // built with "make USE_OPENMP=0".
366   // Hanging can still happen when OpenBLAS is built against the libgomp
367   // implementation of OpenMP. The problem is tracked at:
368   //   http://gcc.gnu.org/bugzilla/show_bug.cgi?id=60035
369   // In the mean time build with USE_OPENMP=0 or link against another
370   // implementation of OpenMP.
371 #if !((defined(OS_WINDOWS) && !defined(OS_CYGWIN_NT)) || defined(OS_ANDROID)) && defined(SMP_SERVER)
372   int err;
373   err = pthread_atfork ((void (*)(void)) BLASFUNC(blas_thread_shutdown), NULL, blas_memory_init);
374   if(err != 0)
375     openblas_warning(0, "OpenBLAS Warning ... cannot install fork handler. You may meet hang after fork.\n");
376 #endif
377 }
378
379 extern int openblas_num_threads_env();
380 extern int openblas_goto_num_threads_env();
381 extern int openblas_omp_num_threads_env();
382
383 int blas_get_cpu_number(void){
384 #if defined(OS_LINUX) || defined(OS_WINDOWS) || defined(OS_FREEBSD) || defined(OS_OPENBSD) || defined(OS_DRAGONFLY) || defined(OS_DARWIN) || defined(OS_ANDROID)
385   int max_num;
386 #endif
387   int blas_goto_num   = 0;
388   int blas_omp_num    = 0;
389
390   if (blas_num_threads) return blas_num_threads;
391
392 #if defined(OS_LINUX) || defined(OS_WINDOWS) || defined(OS_FREEBSD) || defined(OS_OPENBSD) || defined(OS_DRAGONFLY) || defined(OS_DARWIN) || defined(OS_ANDROID)
393   max_num = get_num_procs();
394 #endif
395
396   // blas_goto_num = 0;
397 #ifndef USE_OPENMP_UNUSED
398   blas_goto_num=openblas_num_threads_env();
399   if (blas_goto_num < 0) blas_goto_num = 0;
400
401   if (blas_goto_num == 0) {
402     blas_goto_num=openblas_goto_num_threads_env();
403     if (blas_goto_num < 0) blas_goto_num = 0;
404   }
405
406 #endif
407
408   // blas_omp_num = 0;
409   blas_omp_num=openblas_omp_num_threads_env();
410   if (blas_omp_num < 0) blas_omp_num = 0;
411
412   if (blas_goto_num > 0) blas_num_threads = blas_goto_num;
413   else if (blas_omp_num > 0) blas_num_threads = blas_omp_num;
414   else blas_num_threads = MAX_CPU_NUMBER;
415
416 #if defined(OS_LINUX) || defined(OS_WINDOWS) || defined(OS_FREEBSD) || defined(OS_OPENBSD) || defined(OS_DRAGONFLY) || defined(OS_DARWIN) || defined(OS_ANDROID)
417   if (blas_num_threads > max_num) blas_num_threads = max_num;
418 #endif
419
420   if (blas_num_threads > MAX_CPU_NUMBER) blas_num_threads = MAX_CPU_NUMBER;
421
422 #ifdef DEBUG
423   printf( "Adjusted number of threads : %3d\n", blas_num_threads);
424 #endif
425
426   blas_cpu_number = blas_num_threads;
427
428   return blas_num_threads;
429 }
430 #endif
431
432
433 int openblas_get_num_procs(void) {
434 #ifndef SMP
435   return 1;
436 #else
437   return get_num_procs();
438 #endif
439 }
440
441 int openblas_get_num_threads(void) {
442 #ifndef SMP
443   return 1;
444 #else
445   // init blas_cpu_number if needed
446   blas_get_cpu_number();
447   return blas_cpu_number;
448 #endif
449 }
450
451 int hugetlb_allocated = 0;
452
453 #if defined(OS_WINDOWS)
454 #define LIKELY_ONE(x) (x)
455 #else
456 #define LIKELY_ONE(x) (__builtin_expect(x, 1))
457 #endif
458
459 /* Stores information about the allocation and how to release it */
460 struct alloc_t {
461   /* Whether this allocation is being used */
462   int used;
463   /* Any special attributes needed when releasing this allocation */
464   int attr;
465   /* Function that can properly release this memory */
466   void (*release_func)(struct alloc_t *);
467   /* Pad to 64-byte alignment */
468   char pad[64 - 2 * sizeof(int) - sizeof(void(*))];
469 };
470
471 /* Convenience macros for storing release funcs */
472 #define STORE_RELEASE_FUNC(address, func)                   \
473   if (address != (void *)-1) {                              \
474     struct alloc_t *alloc_info = (struct alloc_t *)address; \
475     alloc_info->release_func = func;                        \
476   }
477
478 #define STORE_RELEASE_FUNC_WITH_ATTR(address, func, attr)   \
479   if (address != (void *)-1) {                              \
480     struct alloc_t *alloc_info = (struct alloc_t *)address; \
481     alloc_info->release_func = func;                        \
482     alloc_info->attr = attr;                                \
483   }
484
485 /* The number of bytes that will be allocated for each buffer. When allocating
486    memory, we store an alloc_t followed by the actual buffer memory. This means
487    that each allocation always has its associated alloc_t, without the need
488    for an auxiliary tracking structure. */
489 static const int allocation_block_size = BUFFER_SIZE + sizeof(struct alloc_t);
490
491 #if defined(SMP)
492 #  if defined(OS_WINDOWS)
493 static DWORD local_storage_key = 0;
494 DWORD lsk;
495
496 #  else
497 static pthread_key_t local_storage_key = 0;
498 pthread_key_t lsk;
499 #  endif /* defined(OS_WINDOWS) */
500 #endif /* defined(SMP) */
501
502 #if defined(OS_LINUX) && !defined(NO_WARMUP)
503 static int hot_alloc = 0;
504 #endif
505
506 /* Global lock for memory allocation */
507
508 #if   defined(USE_PTHREAD_LOCK)
509 static pthread_mutex_t    alloc_lock = PTHREAD_MUTEX_INITIALIZER;
510 #elif defined(USE_PTHREAD_SPINLOCK)
511 static pthread_spinlock_t alloc_lock = 0;
512 #else
513 static BLASULONG  alloc_lock = 0UL;
514 #endif
515
516 #if   defined(USE_PTHREAD_LOCK)
517 static pthread_mutex_t    key_lock = PTHREAD_MUTEX_INITIALIZER;
518 #elif defined(USE_PTHREAD_SPINLOCK)
519 static pthread_spinlock_t key_lock = 0;
520 #else
521 static BLASULONG  key_lock = 0UL;
522 #endif
523
524 /* Returns a pointer to the start of the per-thread memory allocation data */
525 static __inline struct alloc_t ** get_memory_table() {
526 #if defined(SMP)
527 LOCK_COMMAND(&key_lock);
528 lsk=local_storage_key;
529 UNLOCK_COMMAND(&key_lock);
530   if (!lsk) {
531     blas_memory_init();
532   }
533 #  if defined(OS_WINDOWS)
534   struct alloc_t ** local_memory_table = (struct alloc_t **)TlsGetValue(local_storage_key);
535 #  else
536   struct alloc_t ** local_memory_table = (struct alloc_t **)pthread_getspecific(local_storage_key);
537 #  endif /* defined(OS_WINDOWS) */
538 #else
539   static struct alloc_t ** local_memory_table = NULL;
540 #endif /* defined(SMP) */
541 #if defined (SMP)
542 LOCK_COMMAND(&key_lock);
543 lsk=local_storage_key;
544 UNLOCK_COMMAND(&key_lock);
545   if (lsk && !local_memory_table) {
546 #else
547  if (!local_memory_table) {
548 #endif /* defined(SMP) */
549     local_memory_table = (struct alloc_t **)malloc(sizeof(struct alloc_t *) * NUM_BUFFERS);
550     memset(local_memory_table, 0, sizeof(struct alloc_t *) * NUM_BUFFERS);
551 #if defined(SMP)
552 #  if defined(OS_WINDOWS)
553 LOCK_COMMAND(&key_lock);
554     TlsSetValue(local_storage_key, (void*)local_memory_table);
555 UNLOCK_COMMAND(&key_lock);
556 #  else
557 LOCK_COMMAND(&key_lock);
558     pthread_setspecific(local_storage_key, (void*)local_memory_table);
559 UNLOCK_COMMAND(&key_lock);
560 #  endif /* defined(OS_WINDOWS) */
561 #endif /* defined(SMP) */
562   }
563   return local_memory_table;
564 }
565
566 #ifdef ALLOC_MMAP
567
568 static void alloc_mmap_free(struct alloc_t *alloc_info){
569
570   if (munmap(alloc_info, allocation_block_size)) {
571     printf("OpenBLAS : munmap failed\n");
572   }
573 }
574
575
576
577 #ifdef NO_WARMUP
578
579 static void *alloc_mmap(void *address){
580   void *map_address;
581
582   if (address){
583     map_address = mmap(address,
584                        allocation_block_size,
585                        MMAP_ACCESS, MMAP_POLICY | MAP_FIXED, -1, 0);
586   } else {
587     map_address = mmap(address,
588                        allocation_block_size,
589                        MMAP_ACCESS, MMAP_POLICY, -1, 0);
590   }
591
592   STORE_RELEASE_FUNC(map_address, alloc_mmap_free);
593
594 #ifdef OS_LINUX
595   my_mbind(map_address, allocation_block_size, MPOL_PREFERRED, NULL, 0, 0);
596 #endif
597
598   return map_address;
599 }
600
601 #else
602
603 #define BENCH_ITERATION 4
604 #define SCALING         2
605
606 static inline BLASULONG run_bench(BLASULONG address, BLASULONG size) {
607
608   BLASULONG original, *p;
609   BLASULONG start, stop, min;
610   int iter, i, count;
611
612   min = (BLASULONG)-1;
613
614   original = *(BLASULONG *)(address + size - PAGESIZE);
615
616   *(BLASULONG *)(address + size - PAGESIZE) = (BLASULONG)address;
617
618   for (iter = 0; iter < BENCH_ITERATION; iter ++ ) {
619
620     p = (BLASULONG *)address;
621
622     count = size / PAGESIZE;
623
624     start = rpcc();
625
626     for (i = 0; i < count; i ++) {
627       p = (BLASULONG *)(*p);
628     }
629
630     stop = rpcc();
631
632     if (min > stop - start) min = stop - start;
633   }
634
635   *(BLASULONG *)(address + size - PAGESIZE +  0) = original;
636   *(BLASULONG *)(address + size - PAGESIZE +  8) = (BLASULONG)p;
637
638   return min;
639 }
640
641 static void *alloc_mmap(void *address){
642   void *map_address, *best_address;
643   BLASULONG best, start, current, original;
644   BLASULONG allocsize;
645
646   if (address){
647     /* Just give up use advanced operation */
648     map_address = mmap(address, allocation_block_size, MMAP_ACCESS, MMAP_POLICY | MAP_FIXED, -1, 0);
649
650 #ifdef OS_LINUX
651     my_mbind(map_address, allocation_block_size, MPOL_PREFERRED, NULL, 0, 0);
652 #endif
653
654   } else {
655 #if defined(OS_LINUX) && !defined(NO_WARMUP)
656     if (hot_alloc == 0) {
657       map_address = mmap(NULL, allocation_block_size, MMAP_ACCESS, MMAP_POLICY, -1, 0);
658
659 #ifdef OS_LINUX
660       my_mbind(map_address, allocation_block_size, MPOL_PREFERRED, NULL, 0, 0);
661 #endif
662
663     } else {
664 #endif
665
666       map_address = mmap(NULL, allocation_block_size * SCALING,
667                          MMAP_ACCESS, MMAP_POLICY, -1, 0);
668
669       if (map_address != (void *)-1) {
670
671 #ifdef OS_LINUX
672 #ifdef DEBUG
673                   int ret=0;
674                   ret=my_mbind(map_address, allocation_block_size * SCALING, MPOL_PREFERRED, NULL, 0, 0);
675                   if(ret==-1){
676                           int errsv=errno;
677                           perror("OpenBLAS alloc_mmap:");
678                           printf("error code=%d,\tmap_address=%lx\n",errsv,map_address);
679                   }
680
681 #else
682                   my_mbind(map_address, allocation_block_size * SCALING, MPOL_PREFERRED, NULL, 0, 0);
683 #endif
684 #endif
685
686
687         allocsize = DGEMM_P * DGEMM_Q * sizeof(double);
688
689         start   = (BLASULONG)map_address;
690         current = (SCALING - 1) * allocation_block_size;
691         original = current;
692
693         while(current > 0 && current <= original) {
694           *(BLASLONG *)start = (BLASLONG)start + PAGESIZE;
695           start += PAGESIZE;
696           current -= PAGESIZE;
697         }
698
699         *(BLASLONG *)(start - PAGESIZE) = (BLASULONG)map_address;
700
701         start = (BLASULONG)map_address;
702
703         best = (BLASULONG)-1;
704         best_address = map_address;
705
706         while ((start + allocsize  < (BLASULONG)map_address + (SCALING - 1) * allocation_block_size)) {
707
708           current = run_bench(start, allocsize);
709
710           if (best > current) {
711             best = current;
712             best_address = (void *)start;
713           }
714
715           start += PAGESIZE;
716
717         }
718
719       if ((BLASULONG)best_address > (BLASULONG)map_address)
720         munmap(map_address,  (BLASULONG)best_address - (BLASULONG)map_address);
721
722       munmap((void *)((BLASULONG)best_address + allocation_block_size), (SCALING - 1) * allocation_block_size + (BLASULONG)map_address - (BLASULONG)best_address);
723
724       map_address = best_address;
725
726 #if defined(OS_LINUX) && !defined(NO_WARMUP)
727       hot_alloc = 2;
728 #endif
729       }
730     }
731 #if defined(OS_LINUX) && !defined(NO_WARMUP)
732   }
733 #endif
734
735   STORE_RELEASE_FUNC(map_address, alloc_mmap_free);
736
737   return map_address;
738 }
739
740 #endif
741
742 #endif
743
744
745 #ifdef ALLOC_MALLOC
746
747 static void alloc_malloc_free(struct alloc_t *alloc_info){
748
749   free(alloc_info);
750
751 }
752
753 static void *alloc_malloc(void *address){
754
755   void *map_address;
756
757   map_address = (void *)malloc(allocation_block_size + FIXED_PAGESIZE);
758
759   if (map_address == (void *)NULL) map_address = (void *)-1;
760
761   STORE_RELEASE_FUNC(map_address, alloc_malloc_free);
762
763   return map_address;
764
765 }
766
767 #endif
768
769 #ifdef ALLOC_QALLOC
770
771 void *qalloc(int flags, size_t bytes);
772 void *qfree (void *address);
773
774 #define QNONCACHE 0x1
775 #define QCOMMS    0x2
776 #define QFAST     0x4
777
778 static void alloc_qalloc_free(struct alloc_t *alloc_info){
779
780   qfree(alloc_info);
781
782 }
783
784 static void *alloc_qalloc(void *address){
785   void *map_address;
786
787   map_address = (void *)qalloc(QCOMMS | QFAST, allocation_block_size + FIXED_PAGESIZE);
788
789   if (map_address == (void *)NULL) map_address = (void *)-1;
790
791   STORE_RELEASE_FUNC(map_address, alloc_qalloc_free);
792
793   return (void *)(((BLASULONG)map_address + FIXED_PAGESIZE - 1) & ~(FIXED_PAGESIZE - 1));
794 }
795
796 #endif
797
798 #ifdef ALLOC_WINDOWS
799
800 static void alloc_windows_free(struct alloc_t *alloc_info){
801
802   VirtualFree(alloc_info, allocation_block_size, MEM_DECOMMIT);
803
804 }
805
806 static void *alloc_windows(void *address){
807   void *map_address;
808
809   map_address  = VirtualAlloc(address,
810                               allocation_block_size,
811                               MEM_RESERVE | MEM_COMMIT,
812                               PAGE_READWRITE);
813
814   if (map_address == (void *)NULL) map_address = (void *)-1;
815
816   STORE_RELEASE_FUNC(map_address, alloc_windows_free);
817
818   return map_address;
819 }
820
821 #endif
822
823 #ifdef ALLOC_DEVICEDRIVER
824 #ifndef DEVICEDRIVER_NAME
825 #define DEVICEDRIVER_NAME "/dev/mapper"
826 #endif
827
828 static void alloc_devicedirver_free(struct alloc_t *alloc_info){
829
830   int attr = alloc_info -> attr;
831   if (munmap(address, allocation_block_size)) {
832     printf("OpenBLAS : Bugphysarea unmap failed.\n");
833   }
834
835   if (close(attr)) {
836     printf("OpenBLAS : Bugphysarea close failed.\n");
837   }
838
839 }
840
841 static void *alloc_devicedirver(void *address){
842
843   int fd;
844   void *map_address;
845
846   if ((fd = open(DEVICEDRIVER_NAME, O_RDWR | O_SYNC)) < 0) {
847
848     return (void *)-1;
849
850   }
851
852   map_address = mmap(address, allocation_block_size,
853                      PROT_READ | PROT_WRITE,
854                      MAP_FILE | MAP_SHARED,
855                      fd, 0);
856
857   STORE_RELEASE_FUNC_WITH_ATTR(map_address, alloc_devicedirver_free, fd);
858
859   return map_address;
860 }
861
862 #endif
863
864 #ifdef ALLOC_SHM
865
866 static void alloc_shm_free(struct alloc_t *alloc_info){
867
868   if (shmdt(alloc_info)) {
869     printf("OpenBLAS : Shared memory unmap failed.\n");
870     }
871 }
872
873 static void *alloc_shm(void *address){
874   void *map_address;
875   int shmid;
876
877   shmid = shmget(IPC_PRIVATE, allocation_block_size,IPC_CREAT | 0600);
878
879   map_address = (void *)shmat(shmid, address, 0);
880
881   if (map_address != (void *)-1){
882
883 #ifdef OS_LINUX
884     my_mbind(map_address, allocation_block_size, MPOL_PREFERRED, NULL, 0, 0);
885 #endif
886
887     shmctl(shmid, IPC_RMID, 0);
888
889     struct alloc_t *alloc_info = (struct alloc_t *)map_address;
890     alloc_info->release_func = alloc_shm_free;
891     alloc_info->attr = shmid;
892   }
893
894   return map_address;
895 }
896
897 #if defined OS_LINUX  || defined OS_AIX  || defined __sun__  || defined OS_WINDOWS
898
899 static void alloc_hugetlb_free(struct alloc_t *alloc_info){
900
901 #if defined(OS_LINUX) || defined(OS_AIX)
902   if (shmdt(alloc_info)) {
903     printf("OpenBLAS : Hugepage unmap failed.\n");
904   }
905 #endif
906
907 #ifdef __sun__
908
909   munmap(alloc_info, allocation_block_size);
910
911 #endif
912
913 #ifdef OS_WINDOWS
914
915   VirtualFree(alloc_info, allocation_block_size, MEM_LARGE_PAGES | MEM_DECOMMIT);
916
917 #endif
918
919 }
920
921 static void *alloc_hugetlb(void *address){
922
923   void *map_address = (void *)-1;
924
925 #if defined(OS_LINUX) || defined(OS_AIX)
926   int shmid;
927
928   shmid = shmget(IPC_PRIVATE, allocation_block_size,
929 #ifdef OS_LINUX
930                  SHM_HUGETLB |
931 #endif
932 #ifdef OS_AIX
933                  SHM_LGPAGE | SHM_PIN |
934 #endif
935                  IPC_CREAT | SHM_R | SHM_W);
936
937   if (shmid != -1) {
938     map_address = (void *)shmat(shmid, address, SHM_RND);
939
940 #ifdef OS_LINUX
941     my_mbind(map_address, allocation_block_size, MPOL_PREFERRED, NULL, 0, 0);
942 #endif
943
944     if (map_address != (void *)-1){
945       shmctl(shmid, IPC_RMID, 0);
946     }
947   }
948 #endif
949
950 #ifdef __sun__
951   struct memcntl_mha mha;
952
953   mha.mha_cmd = MHA_MAPSIZE_BSSBRK;
954   mha.mha_flags = 0;
955   mha.mha_pagesize = HUGE_PAGESIZE;
956   memcntl(NULL, 0, MC_HAT_ADVISE, (char *)&mha, 0, 0);
957
958   map_address = (BLASULONG)memalign(HUGE_PAGESIZE, allocation_block_size);
959 #endif
960
961 #ifdef OS_WINDOWS
962
963   HANDLE hToken;
964   TOKEN_PRIVILEGES tp;
965
966   if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken) != TRUE) return (void *) -1;
967
968   tp.PrivilegeCount = 1;
969   tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
970
971   if (LookupPrivilegeValue(NULL, SE_LOCK_MEMORY_NAME, &tp.Privileges[0].Luid) != TRUE) {
972       CloseHandle(hToken);
973       return (void*)-1;
974   }
975
976   if (AdjustTokenPrivileges(hToken, FALSE, &tp, 0, NULL, NULL) != TRUE) {
977       CloseHandle(hToken);
978       return (void*)-1;
979   }
980
981   map_address  = (void *)VirtualAlloc(address,
982                                       allocation_block_size,
983                                       MEM_LARGE_PAGES | MEM_RESERVE | MEM_COMMIT,
984                                       PAGE_READWRITE);
985
986   tp.Privileges[0].Attributes = 0;
987   AdjustTokenPrivileges(hToken, FALSE, &tp, 0, NULL, NULL);
988
989   if (map_address == (void *)NULL) map_address = (void *)-1;
990
991 #endif
992
993   STORE_RELEASE_FUNC(map_address, alloc_hugetlb_free);
994
995   return map_address;
996 }
997 #endif
998
999 #endif
1000
1001 #ifdef  ALLOC_HUGETLBFILE
1002
1003 static int hugetlb_pid = 0;
1004
1005 static void alloc_hugetlbfile_free(struct alloc_t *alloc_info){
1006
1007   int attr = alloc_info -> attr;
1008   if (munmap(alloc_info, allocation_block_size)) {
1009     printf("OpenBLAS : HugeTLBfs unmap failed.\n");
1010   }
1011
1012   if (close(attr)) {
1013     printf("OpenBLAS : HugeTLBfs close failed.\n");
1014   }
1015 }
1016
1017 static void *alloc_hugetlbfile(void *address){
1018
1019   void *map_address = (void *)-1;
1020   int fd;
1021   char filename[64];
1022
1023   if (!hugetlb_pid) hugetlb_pid = getpid();
1024
1025   sprintf(filename, "%s/gotoblas.%d", HUGETLB_FILE_NAME, hugetlb_pid);
1026
1027   if ((fd = open(filename, O_RDWR | O_CREAT, 0700)) < 0) {
1028     return (void *)-1;
1029   }
1030
1031   unlink(filename);
1032
1033   map_address = mmap(address, allocation_block_size,
1034                      PROT_READ | PROT_WRITE,
1035                      MAP_SHARED,
1036                      fd, 0);
1037
1038   STORE_RELEASE_FUNC_WITH_ATTR(map_address, alloc_hugetlbfile_free, fd);
1039
1040   return map_address;
1041 }
1042 #endif
1043
1044
1045 #ifdef SEEK_ADDRESS
1046 static BLASULONG base_address      = 0UL;
1047 #else
1048 static BLASULONG base_address      = BASE_ADDRESS;
1049 #endif
1050
1051 #if __STDC_VERSION__ >= 201112L
1052 static _Atomic int memory_initialized = 0;
1053 #else
1054 static volatile int memory_initialized = 0;
1055 #endif
1056
1057 /*       Memory allocation routine           */
1058 /* procpos ... indicates where it comes from */
1059 /*                0 : Level 3 functions      */
1060 /*                1 : Level 2 functions      */
1061 /*                2 : Thread                 */
1062
1063         static void blas_memory_cleanup(void* ptr){
1064   if (ptr) {
1065     struct alloc_t ** table = (struct alloc_t **)ptr;
1066     int pos;
1067     for (pos = 0; pos < NUM_BUFFERS; pos ++){
1068       struct alloc_t *alloc_info = table[pos];
1069       if (alloc_info) {
1070         alloc_info->release_func(alloc_info);
1071         table[pos] = (void *)0;
1072       }
1073     }
1074     free(table);
1075   }
1076 #if defined(OS_WINDOWS)
1077   TlsFree(local_storage_key);
1078 #else
1079   pthread_key_delete(local_storage_key);
1080 #endif          
1081 }
1082
1083 static void blas_memory_init(){
1084 #if defined(SMP)
1085 #  if defined(OS_WINDOWS)
1086   local_storage_key = TlsAlloc();
1087 #  else
1088   pthread_key_create(&local_storage_key, blas_memory_cleanup);
1089 #  endif /* defined(OS_WINDOWS) */
1090 #endif /* defined(SMP) */
1091 }
1092
1093 void *blas_memory_alloc(int procpos){
1094
1095   int position;
1096
1097   void *map_address;
1098
1099   void *(*memoryalloc[])(void *address) = {
1100 #ifdef ALLOC_DEVICEDRIVER
1101     alloc_devicedirver,
1102 #endif
1103 /* Hugetlb implicitly assumes ALLOC_SHM */
1104 #ifdef ALLOC_SHM
1105     alloc_shm,
1106 #endif
1107 #if ((defined ALLOC_SHM) && (defined OS_LINUX  || defined OS_AIX  || defined __sun__  || defined OS_WINDOWS))
1108     alloc_hugetlb,
1109 #endif
1110 #ifdef ALLOC_MMAP
1111     alloc_mmap,
1112 #endif
1113 #ifdef ALLOC_QALLOC
1114     alloc_qalloc,
1115 #endif
1116 #ifdef ALLOC_WINDOWS
1117     alloc_windows,
1118 #endif
1119 #ifdef ALLOC_MALLOC
1120     alloc_malloc,
1121 #endif
1122     NULL,
1123   };
1124   void *(**func)(void *address);
1125   struct alloc_t * alloc_info;
1126   struct alloc_t ** alloc_table;
1127
1128
1129 #if defined(SMP) && !defined(USE_OPENMP)
1130 int mi;
1131 LOCK_COMMAND(&alloc_lock);
1132 mi=memory_initialized;
1133 UNLOCK_COMMAND(&alloc_lock);
1134   if (!LIKELY_ONE(mi)) {
1135 #else
1136   if (!LIKELY_ONE(memory_initialized)) {
1137 #endif
1138 #if defined(SMP) && !defined(USE_OPENMP)
1139     /* Only allow a single thread to initialize memory system */
1140     LOCK_COMMAND(&alloc_lock);
1141
1142     if (!memory_initialized) {
1143 #endif
1144       blas_memory_init();
1145 #ifdef DYNAMIC_ARCH
1146       gotoblas_dynamic_init();
1147 #endif
1148
1149 #if defined(SMP) && defined(OS_LINUX) && !defined(NO_AFFINITY)
1150       gotoblas_affinity_init();
1151 #endif
1152
1153 #ifdef SMP
1154       if (!blas_num_threads) blas_cpu_number = blas_get_cpu_number();
1155 #endif
1156
1157 #if defined(ARCH_X86) || defined(ARCH_X86_64) || defined(ARCH_IA64) || defined(ARCH_MIPS64) || defined(ARCH_ARM64)
1158 #ifndef DYNAMIC_ARCH
1159       blas_set_parameter();
1160 #endif
1161 #endif
1162
1163       memory_initialized = 1;
1164
1165 #if defined(SMP) && !defined(USE_OPENMP)
1166     }
1167     UNLOCK_COMMAND(&alloc_lock);
1168 #endif
1169   }
1170
1171 #ifdef DEBUG
1172   printf("Alloc Start ...\n");
1173 #endif
1174
1175   position = 0;
1176   alloc_table = get_memory_table();
1177   do {
1178       if (!alloc_table[position] || !alloc_table[position]->used) goto allocation;
1179     position ++;
1180
1181   } while (position < NUM_BUFFERS);
1182
1183   goto error;
1184
1185   allocation :
1186
1187 #ifdef DEBUG
1188   printf("  Position -> %d\n", position);
1189 #endif
1190
1191   alloc_info = alloc_table[position];
1192   if (!alloc_info) {
1193     do {
1194 #ifdef DEBUG
1195       printf("Allocation Start : %lx\n", base_address);
1196 #endif
1197
1198       map_address = (void *)-1;
1199
1200       func = &memoryalloc[0];
1201
1202       while ((func != NULL) && (map_address == (void *) -1)) {
1203
1204   map_address = (*func)((void *)base_address);
1205
1206 #ifdef ALLOC_DEVICEDRIVER
1207         if ((*func ==  alloc_devicedirver) && (map_address == (void *)-1)) {
1208             fprintf(stderr, "OpenBLAS Warning ... Physically contiguous allocation failed.\n");
1209         }
1210 #endif
1211
1212 #ifdef ALLOC_HUGETLBFILE
1213         if ((*func == alloc_hugetlbfile) && (map_address == (void *)-1)) {
1214 #ifndef OS_WINDOWS
1215             fprintf(stderr, "OpenBLAS Warning ... HugeTLB(File) allocation failed.\n");
1216 #endif
1217         }
1218 #endif
1219
1220 #if (defined ALLOC_SHM) && (defined OS_LINUX  || defined OS_AIX  || defined __sun__  || defined OS_WINDOWS)
1221         if ((*func == alloc_hugetlb) && (map_address != (void *)-1)) hugetlb_allocated = 1;
1222 #endif
1223
1224         func ++;
1225       }
1226
1227 #ifdef DEBUG
1228       printf("  Success -> %08lx\n", map_address);
1229 #endif
1230       if (((BLASLONG) map_address) == -1) base_address = 0UL;
1231
1232       if (base_address) base_address += allocation_block_size + FIXED_PAGESIZE;
1233
1234     } while ((BLASLONG)map_address == -1);
1235
1236     alloc_table[position] = alloc_info = map_address;
1237
1238 #ifdef DEBUG
1239     printf("  Mapping Succeeded. %p(%d)\n", (void *)alloc_info, position);
1240 #endif
1241   }
1242
1243 #ifdef DEBUG
1244   printf("Mapped   : %p  %3d\n\n", (void *)alloc_info, position);
1245 #endif
1246
1247   alloc_info->used = 1;
1248
1249   return (void *)(((char *)alloc_info) + sizeof(struct alloc_t));
1250
1251  error:
1252   printf("OpenBLAS : Program will terminate because you tried to allocate too many memory regions.\n");
1253
1254   return NULL;
1255 }
1256
1257 void blas_memory_free(void *buffer){
1258 #ifdef DEBUG
1259   int position;
1260   struct alloc_t ** alloc_table;
1261 #endif
1262   /* Since we passed an offset pointer to the caller, get back to the actual allocation */
1263   struct alloc_t *alloc_info = (void *)(((char *)buffer) - sizeof(struct alloc_t));
1264
1265 #ifdef DEBUG
1266   printf("Unmapped Start : %p ...\n", alloc_info);
1267 #endif
1268
1269   alloc_info->used = 0;
1270
1271 #ifdef DEBUG
1272   printf("Unmap Succeeded.\n\n");
1273 #endif
1274
1275   return;
1276
1277 #ifdef DEBUG
1278   alloc_table = get_memory_table();
1279   for (position = 0; position < NUM_BUFFERS; position++){
1280     if (alloc_table[position]) {
1281       printf("%4ld  %p : %d\n", position, alloc_table[position], alloc_table[position]->used);
1282     }
1283   }
1284 #endif
1285   return;
1286 }
1287
1288 void *blas_memory_alloc_nolock(int unused) {
1289   void *map_address;
1290   map_address = (void *)malloc(BUFFER_SIZE + FIXED_PAGESIZE);
1291   return map_address;
1292 }
1293
1294 void blas_memory_free_nolock(void * map_address) {
1295   free(map_address);
1296 }
1297
1298 void blas_shutdown(void){
1299 #ifdef SMP
1300   BLASFUNC(blas_thread_shutdown)();
1301 #endif
1302
1303 #ifdef SMP
1304   /* Only cleanupIf we were built for threading and TLS was initialized */
1305   if (local_storage_key)
1306 #endif
1307     blas_memory_cleanup((void*)get_memory_table());
1308
1309 #ifdef SEEK_ADDRESS
1310   base_address      = 0UL;
1311 #else
1312   base_address      = BASE_ADDRESS;
1313 #endif
1314
1315   return;
1316 }
1317
1318 #if defined(OS_LINUX) && !defined(NO_WARMUP)
1319
1320 #ifdef SMP
1321 #if   defined(USE_PTHREAD_LOCK)
1322 static pthread_mutex_t    init_lock = PTHREAD_MUTEX_INITIALIZER;
1323 #elif defined(USE_PTHREAD_SPINLOCK)
1324 static pthread_spinlock_t init_lock = 0;
1325 #else
1326 static BLASULONG   init_lock = 0UL;
1327 #endif
1328 #endif
1329
1330 static void _touch_memory(blas_arg_t *arg, BLASLONG *range_m, BLASLONG *range_n,
1331                           void *sa, void *sb, BLASLONG pos) {
1332
1333 #if !defined(ARCH_POWER) && !defined(ARCH_SPARC)
1334
1335   size_t size;
1336   BLASULONG buffer;
1337
1338   size   = allocation_block_size - PAGESIZE;
1339   buffer = (BLASULONG)sa + GEMM_OFFSET_A;
1340
1341 #if defined(OS_LINUX) && !defined(NO_WARMUP)
1342     if (hot_alloc != 2) {
1343 #endif
1344
1345 #ifdef SMP
1346   LOCK_COMMAND(&init_lock);
1347 #endif
1348
1349   while (size > 0) {
1350     *(int *)buffer = size;
1351     buffer  += PAGESIZE;
1352     size    -= PAGESIZE;
1353   }
1354
1355 #ifdef SMP
1356   UNLOCK_COMMAND(&init_lock);
1357 #endif
1358
1359   size = MIN((allocation_block_size - PAGESIZE), L2_SIZE);
1360   buffer = (BLASULONG)sa + GEMM_OFFSET_A;
1361
1362   while (size > 0) {
1363     *(int *)buffer = size;
1364     buffer  += 64;
1365     size    -= 64;
1366   }
1367
1368 #if defined(OS_LINUX) && !defined(NO_WARMUP)
1369     }
1370 #endif
1371
1372 #endif
1373 }
1374
1375 #ifdef SMP
1376
1377 static void _init_thread_memory(void *buffer) {
1378
1379   blas_queue_t queue[MAX_CPU_NUMBER];
1380   int num_cpu;
1381
1382   for (num_cpu = 0; num_cpu < blas_num_threads; num_cpu++) {
1383
1384     blas_queue_init(&queue[num_cpu]);
1385     queue[num_cpu].mode    = BLAS_DOUBLE | BLAS_REAL;
1386     queue[num_cpu].routine = &_touch_memory;
1387     queue[num_cpu].args    = NULL;
1388     queue[num_cpu].next    = &queue[num_cpu + 1];
1389   }
1390
1391   queue[num_cpu - 1].next = NULL;
1392   queue[0].sa = buffer;
1393
1394   exec_blas(num_cpu, queue);
1395
1396 }
1397 #endif
1398
1399 static void gotoblas_memory_init(void) {
1400
1401   void *buffer;
1402
1403   hot_alloc = 1;
1404
1405   buffer = (void *)blas_memory_alloc(0);
1406
1407 #ifdef SMP
1408   if (blas_cpu_number == 0) blas_get_cpu_number();
1409 #ifdef SMP_SERVER
1410   if (blas_server_avail == 0) blas_thread_init();
1411 #endif
1412
1413   _init_thread_memory((void *)((BLASULONG)buffer + GEMM_OFFSET_A));
1414
1415 #else
1416
1417   _touch_memory(NULL, NULL, NULL, (void *)((BLASULONG)buffer + GEMM_OFFSET_A), NULL, 0);
1418
1419 #endif
1420
1421   blas_memory_free(buffer);
1422 }
1423 #endif
1424
1425 /* Initialization for all function; this function should be called before main */
1426
1427 static int gotoblas_initialized = 0;
1428 extern void openblas_read_env();
1429
1430 void CONSTRUCTOR gotoblas_init(void) {
1431
1432   if (gotoblas_initialized) return;
1433
1434 #ifdef SMP
1435   openblas_fork_handler();
1436 #endif
1437
1438   openblas_read_env();
1439
1440 #ifdef PROFILE
1441    moncontrol (0);
1442 #endif
1443
1444 #ifdef DYNAMIC_ARCH
1445    gotoblas_dynamic_init();
1446 #endif
1447
1448 #if defined(SMP) && defined(OS_LINUX) && !defined(NO_AFFINITY)
1449    gotoblas_affinity_init();
1450 #endif
1451
1452 #if defined(OS_LINUX) && !defined(NO_WARMUP)
1453    gotoblas_memory_init();
1454 #endif
1455
1456 //#if defined(OS_LINUX)
1457 #if 0
1458    struct rlimit curlimit;
1459    if ( getrlimit(RLIMIT_STACK, &curlimit ) == 0 )
1460    {
1461         if ( curlimit.rlim_cur != curlimit.rlim_max )
1462         {
1463                 curlimit.rlim_cur = curlimit.rlim_max;
1464                 setrlimit(RLIMIT_STACK, &curlimit);
1465         }
1466    }
1467 #endif
1468
1469 #ifdef SMP
1470   if (blas_cpu_number == 0) blas_get_cpu_number();
1471 #ifdef SMP_SERVER
1472   if (blas_server_avail == 0) blas_thread_init();
1473 #endif
1474 #endif
1475
1476 #ifdef FUNCTION_PROFILE
1477    gotoblas_profile_init();
1478 #endif
1479
1480    gotoblas_initialized = 1;
1481
1482 #ifdef PROFILE
1483    moncontrol (1);
1484 #endif
1485
1486 }
1487
1488 void DESTRUCTOR gotoblas_quit(void) {
1489
1490   if (gotoblas_initialized == 0) return;
1491
1492   blas_shutdown();
1493
1494 #ifdef PROFILE
1495    moncontrol (0);
1496 #endif
1497
1498 #ifdef FUNCTION_PROFILE
1499    gotoblas_profile_quit();
1500 #endif
1501
1502 #if defined(SMP) && defined(OS_LINUX) && !defined(NO_AFFINITY)
1503    gotoblas_affinity_quit();
1504 #endif
1505
1506 #ifdef DYNAMIC_ARCH
1507    gotoblas_dynamic_quit();
1508 #endif
1509
1510    gotoblas_initialized = 0;
1511
1512 #ifdef PROFILE
1513    moncontrol (1);
1514 #endif
1515 }
1516
1517 #if defined(_MSC_VER) && !defined(__clang__)
1518 BOOL APIENTRY DllMain(HMODULE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved)
1519 {
1520   switch (ul_reason_for_call)
1521   {
1522     case DLL_PROCESS_ATTACH:
1523       gotoblas_init();
1524       break;
1525     case DLL_THREAD_ATTACH:
1526       break;
1527     case DLL_THREAD_DETACH:
1528 #if defined(SMP)
1529       blas_memory_cleanup((void*)get_memory_table());
1530 #endif
1531       break;
1532     case DLL_PROCESS_DETACH:
1533       gotoblas_quit();
1534       break;
1535     default:
1536       break;
1537   }
1538   return TRUE;
1539 }
1540
1541 /*
1542   This is to allow static linking.
1543   Code adapted from Google performance tools:
1544   https://gperftools.googlecode.com/git-history/perftools-1.0/src/windows/port.cc
1545   Reference:
1546   https://sourceware.org/ml/pthreads-win32/2008/msg00028.html
1547   http://ci.boost.org/svn-trac/browser/trunk/libs/thread/src/win32/tss_pe.cpp
1548 */
1549 static int on_process_term(void)
1550 {
1551         gotoblas_quit();
1552         return 0;
1553 }
1554 #ifdef _WIN64
1555 #pragma comment(linker, "/INCLUDE:_tls_used")
1556 #else
1557 #pragma comment(linker, "/INCLUDE:__tls_used")
1558 #endif
1559
1560 #ifdef _WIN64
1561 #pragma const_seg(".CRT$XLB")
1562 #else
1563 #pragma data_seg(".CRT$XLB")
1564 #endif
1565 static void (APIENTRY *dll_callback)(HINSTANCE h, DWORD ul_reason_for_call, PVOID pv) = DllMain;
1566 #ifdef _WIN64
1567 #pragma const_seg()
1568 #else
1569 #pragma data_seg()
1570 #endif
1571
1572 #ifdef _WIN64
1573 #pragma const_seg(".CRT$XTU")
1574 #else
1575 #pragma data_seg(".CRT$XTU")
1576 #endif
1577 static int(*p_process_term)(void) = on_process_term;
1578 #ifdef _WIN64
1579 #pragma const_seg()
1580 #else
1581 #pragma data_seg()
1582 #endif
1583 #endif
1584
1585 #if (defined(C_PGI) || (!defined(C_SUN) && defined(F_INTERFACE_SUN))) && (defined(ARCH_X86) || defined(ARCH_X86_64))
1586 /* Don't call me; this is just work around for PGI / Sun bug */
1587 void gotoblas_dummy_for_PGI(void) {
1588
1589   gotoblas_init();
1590   gotoblas_quit();
1591
1592 #if 0
1593   asm ("\t.section\t.ctors,\"aw\",@progbits; .align 8; .quad gotoblas_init; .section .text");
1594   asm ("\t.section\t.dtors,\"aw\",@progbits; .align 8; .quad gotoblas_quit; .section .text");
1595 #else
1596   asm (".section .init,\"ax\"; call gotoblas_init@PLT; .section .text");
1597   asm (".section .fini,\"ax\"; call gotoblas_quit@PLT; .section .text");
1598 #endif
1599 }
1600 #endif
1601
1602 #else
1603 #include <errno.h>
1604
1605 #ifdef OS_WINDOWS
1606 #define ALLOC_WINDOWS
1607 #ifndef MEM_LARGE_PAGES
1608 #define MEM_LARGE_PAGES  0x20000000
1609 #endif
1610 #else
1611 #define ALLOC_MMAP
1612 #define ALLOC_MALLOC
1613 #endif
1614
1615 #include <stdlib.h>
1616 #include <stdio.h>
1617 #include <fcntl.h>
1618
1619 #ifndef OS_WINDOWS
1620 #include <sys/mman.h>
1621 #ifndef NO_SYSV_IPC
1622 #include <sys/shm.h>
1623 #endif
1624 #include <sys/ipc.h>
1625 #endif
1626
1627 #include <sys/types.h>
1628
1629 #ifdef OS_LINUX
1630 #include <sys/sysinfo.h>
1631 #include <sched.h>
1632 #include <errno.h>
1633 #include <linux/unistd.h>
1634 #include <sys/syscall.h>
1635 #include <sys/time.h>
1636 #include <sys/resource.h>
1637 #endif
1638
1639 #if defined(OS_FREEBSD) || defined(OS_DARWIN)
1640 #include <sys/sysctl.h>
1641 #include <sys/resource.h>
1642 #endif
1643
1644 #if defined(OS_WINDOWS) && (defined(__MINGW32__) || defined(__MINGW64__))
1645 #include <conio.h>
1646 #undef  printf
1647 #define printf  _cprintf
1648 #endif
1649
1650 #ifdef OS_LINUX
1651
1652 #ifndef MPOL_PREFERRED
1653 #define MPOL_PREFERRED  1
1654 #endif
1655
1656 #endif
1657
1658 #if (defined(PPC440) || !defined(OS_LINUX) || defined(HPL)) && !defined(NO_WARMUP)
1659 #define NO_WARMUP
1660 #endif
1661
1662 #ifndef SHM_HUGETLB
1663 #define SHM_HUGETLB 04000
1664 #endif
1665
1666 #ifndef FIXED_PAGESIZE
1667 #define FIXED_PAGESIZE 4096
1668 #endif
1669
1670 #define BITMASK(a, b, c) ((((a) >> (b)) & (c)))
1671
1672 #if defined(_MSC_VER) && !defined(__clang__)
1673 #define CONSTRUCTOR __cdecl
1674 #define DESTRUCTOR __cdecl
1675 #elif (defined(OS_DARWIN) || defined(OS_SUNOS)) && defined(C_GCC)
1676 #define CONSTRUCTOR     __attribute__ ((constructor))
1677 #define DESTRUCTOR      __attribute__ ((destructor))
1678 #else
1679 #define CONSTRUCTOR     __attribute__ ((constructor(101)))
1680 #define DESTRUCTOR      __attribute__ ((destructor(101)))
1681 #endif
1682
1683 #ifdef DYNAMIC_ARCH
1684 gotoblas_t *gotoblas = NULL;
1685 #endif
1686 extern void openblas_warning(int verbose, const char * msg);
1687
1688 #ifndef SMP
1689
1690 #define blas_cpu_number 1
1691 #define blas_num_threads 1
1692
1693 /* Dummy Function */
1694 int  goto_get_num_procs  (void) { return 1;};
1695 void goto_set_num_threads(int num_threads) {};
1696
1697 #else
1698
1699 #if defined(OS_LINUX) || defined(OS_SUNOS) || defined(OS_NETBSD)
1700 #ifndef NO_AFFINITY
1701 int get_num_procs(void);
1702 #else
1703 int get_num_procs(void) {
1704   static int nums = 0;
1705 cpu_set_t *cpusetp;
1706 size_t size;
1707 int ret;
1708 int i,n;
1709
1710   if (!nums) nums = sysconf(_SC_NPROCESSORS_CONF);
1711 #if !defined(OS_LINUX)
1712      return nums;
1713 #endif
1714
1715 #if !defined(__GLIBC_PREREQ)
1716    return nums;
1717 #else
1718  #if !__GLIBC_PREREQ(2, 3)
1719    return nums;
1720  #endif
1721
1722  #if !__GLIBC_PREREQ(2, 7)
1723   ret = sched_getaffinity(0,sizeof(cpu_set_t), cpusetp);
1724   if (ret!=0) return nums;
1725   n=0;
1726   #if !__GLIBC_PREREQ(2, 6)
1727   for (i=0;i<nums;i++)
1728      if (CPU_ISSET(i,cpusetp)) n++;
1729   nums=n;
1730   #else
1731   nums = CPU_COUNT(sizeof(cpu_set_t),cpusetp);
1732   #endif
1733   return nums;
1734  #else
1735   cpusetp = CPU_ALLOC(nums);
1736   if (cpusetp == NULL) return nums;
1737   size = CPU_ALLOC_SIZE(nums);
1738   ret = sched_getaffinity(0,size,cpusetp);
1739   if (ret!=0) return nums;
1740   nums = CPU_COUNT_S(size,cpusetp);
1741   CPU_FREE(cpusetp);
1742   return nums;
1743  #endif
1744 #endif
1745 }
1746 #endif
1747 #endif
1748
1749 #ifdef OS_ANDROID
1750 int get_num_procs(void) {
1751   static int nums = 0;
1752   if (!nums) nums = sysconf(_SC_NPROCESSORS_CONF);
1753   return nums;
1754 }
1755 #endif
1756         
1757 #ifdef OS_HAIKU
1758 int get_num_procs(void) {
1759   static int nums = 0;
1760   if (!nums) nums = sysconf(_SC_NPROCESSORS_CONF);
1761   return nums;
1762 }
1763 #endif
1764
1765 #ifdef OS_AIX
1766 int get_num_procs(void) {
1767   static int nums = 0;
1768   if (!nums) nums = sysconf(_SC_NPROCESSORS_CONF);
1769   return nums;
1770 }
1771 #endif
1772
1773 #ifdef OS_WINDOWS
1774
1775 int get_num_procs(void) {
1776
1777   static int nums = 0;
1778
1779   if (nums == 0) {
1780
1781     SYSTEM_INFO sysinfo;
1782
1783     GetSystemInfo(&sysinfo);
1784
1785     nums = sysinfo.dwNumberOfProcessors;
1786   }
1787
1788   return nums;
1789 }
1790
1791 #endif
1792
1793 #if defined(OS_FREEBSD)
1794
1795 int get_num_procs(void) {
1796
1797   static int nums = 0;
1798
1799   int m[2];
1800   size_t len;
1801
1802   if (nums == 0) {
1803     m[0] = CTL_HW;
1804     m[1] = HW_NCPU;
1805     len = sizeof(int);
1806     sysctl(m, 2, &nums, &len, NULL, 0);
1807   }
1808
1809   return nums;
1810 }
1811
1812 #endif
1813
1814 #if defined(OS_DARWIN)
1815 int get_num_procs(void) {
1816   static int nums = 0;
1817   size_t len;
1818   if (nums == 0){
1819     len = sizeof(int);
1820     sysctlbyname("hw.physicalcpu", &nums, &len, NULL, 0);
1821   }
1822   return nums;
1823 }
1824 /*
1825 void set_stack_limit(int limitMB){
1826   int result=0;
1827   struct rlimit rl;
1828   rlim_t StackSize;
1829
1830   StackSize=limitMB*1024*1024;
1831   result=getrlimit(RLIMIT_STACK, &rl);
1832   if(result==0){
1833     if(rl.rlim_cur < StackSize){
1834       rl.rlim_cur=StackSize;
1835       result=setrlimit(RLIMIT_STACK, &rl);
1836       if(result !=0){
1837         fprintf(stderr, "OpenBLAS: set stack limit error =%d\n", result);
1838       }
1839     }
1840   }
1841 }
1842 */
1843 #endif
1844
1845
1846 /*
1847 OpenBLAS uses the numbers of CPU cores in multithreading.
1848 It can be set by openblas_set_num_threads(int num_threads);
1849 */
1850 int blas_cpu_number  = 0;
1851 /*
1852 The numbers of threads in the thread pool.
1853 This value is equal or large than blas_cpu_number. This means some threads are sleep.
1854 */
1855 int blas_num_threads = 0;
1856
1857 int  goto_get_num_procs  (void) {
1858   return blas_cpu_number;
1859 }
1860
1861 void openblas_fork_handler()
1862 {
1863   // This handler shuts down the OpenBLAS-managed PTHREAD pool when OpenBLAS is
1864   // built with "make USE_OPENMP=0".
1865   // Hanging can still happen when OpenBLAS is built against the libgomp
1866   // implementation of OpenMP. The problem is tracked at:
1867   //   http://gcc.gnu.org/bugzilla/show_bug.cgi?id=60035
1868   // In the mean time build with USE_OPENMP=0 or link against another
1869   // implementation of OpenMP.
1870 #if !(defined(OS_WINDOWS) || defined(OS_ANDROID)) && defined(SMP_SERVER)
1871   int err;
1872   err = pthread_atfork ((void (*)(void)) BLASFUNC(blas_thread_shutdown), NULL, NULL);
1873   if(err != 0)
1874     openblas_warning(0, "OpenBLAS Warning ... cannot install fork handler. You may meet hang after fork.\n");
1875 #endif
1876 }
1877
1878 extern int openblas_num_threads_env();
1879 extern int openblas_goto_num_threads_env();
1880 extern int openblas_omp_num_threads_env();
1881
1882 int blas_get_cpu_number(void){
1883 #if defined(OS_LINUX) || defined(OS_WINDOWS) || defined(OS_FREEBSD) || defined(OS_DARWIN) || defined(OS_ANDROID)
1884   int max_num;
1885 #endif
1886   int blas_goto_num   = 0;
1887   int blas_omp_num    = 0;
1888
1889   if (blas_num_threads) return blas_num_threads;
1890
1891 #if defined(OS_LINUX) || defined(OS_WINDOWS) || defined(OS_FREEBSD) || defined(OS_DARWIN) || defined(OS_ANDROID)
1892   max_num = get_num_procs();
1893 #endif
1894
1895   blas_goto_num = 0;
1896 #ifndef USE_OPENMP
1897   blas_goto_num=openblas_num_threads_env();
1898   if (blas_goto_num < 0) blas_goto_num = 0;
1899
1900   if (blas_goto_num == 0) {
1901     blas_goto_num=openblas_goto_num_threads_env();
1902     if (blas_goto_num < 0) blas_goto_num = 0;
1903   }
1904
1905 #endif
1906
1907   blas_omp_num = 0;
1908   blas_omp_num=openblas_omp_num_threads_env();
1909   if (blas_omp_num < 0) blas_omp_num = 0;
1910
1911   if (blas_goto_num > 0) blas_num_threads = blas_goto_num;
1912   else if (blas_omp_num > 0) blas_num_threads = blas_omp_num;
1913   else blas_num_threads = MAX_CPU_NUMBER;
1914
1915 #if defined(OS_LINUX) || defined(OS_WINDOWS) || defined(OS_FREEBSD) || defined(OS_DARWIN) || defined(OS_ANDROID)
1916   if (blas_num_threads > max_num) blas_num_threads = max_num;
1917 #endif
1918
1919   if (blas_num_threads > MAX_CPU_NUMBER) blas_num_threads = MAX_CPU_NUMBER;
1920
1921 #ifdef DEBUG
1922   printf( "Adjusted number of threads : %3d\n", blas_num_threads);
1923 #endif
1924
1925   blas_cpu_number = blas_num_threads;
1926
1927   return blas_num_threads;
1928 }
1929 #endif
1930
1931
1932 int openblas_get_num_procs(void) {
1933 #ifndef SMP
1934   return 1;
1935 #else
1936   return get_num_procs();
1937 #endif
1938 }
1939
1940 int openblas_get_num_threads(void) {
1941 #ifndef SMP
1942   return 1;
1943 #else
1944   // init blas_cpu_number if needed
1945   blas_get_cpu_number();
1946   return blas_cpu_number;
1947 #endif
1948 }
1949
1950 struct release_t {
1951   void *address;
1952   void (*func)(struct release_t *);
1953   long attr;
1954 };
1955
1956 int hugetlb_allocated = 0;
1957
1958 static struct release_t release_info[NUM_BUFFERS];
1959 static int release_pos = 0;
1960
1961 #if defined(OS_LINUX) && !defined(NO_WARMUP)
1962 static int hot_alloc = 0;
1963 #endif
1964
1965 /* Global lock for memory allocation */
1966
1967 #if   defined(USE_PTHREAD_LOCK)
1968 static pthread_mutex_t    alloc_lock = PTHREAD_MUTEX_INITIALIZER;
1969 #elif defined(USE_PTHREAD_SPINLOCK)
1970 static pthread_spinlock_t alloc_lock = 0;
1971 #else
1972 static BLASULONG  alloc_lock = 0UL;
1973 #endif
1974
1975 #ifdef ALLOC_MMAP
1976
1977 static void alloc_mmap_free(struct release_t *release){
1978
1979   if (munmap(release -> address, BUFFER_SIZE)) {
1980     printf("OpenBLAS : munmap failed\n");
1981   }
1982 }
1983
1984
1985
1986 #ifdef NO_WARMUP
1987
1988 static void *alloc_mmap(void *address){
1989   void *map_address;
1990
1991   if (address){
1992     map_address = mmap(address,
1993                        BUFFER_SIZE,
1994                        MMAP_ACCESS, MMAP_POLICY | MAP_FIXED, -1, 0);
1995   } else {
1996     map_address = mmap(address,
1997                        BUFFER_SIZE,
1998                        MMAP_ACCESS, MMAP_POLICY, -1, 0);
1999   }
2000
2001   if (map_address != (void *)-1) {
2002     LOCK_COMMAND(&alloc_lock);
2003     release_info[release_pos].address = map_address;
2004     release_info[release_pos].func    = alloc_mmap_free;
2005     release_pos ++;
2006     UNLOCK_COMMAND(&alloc_lock);
2007   }
2008
2009 #ifdef OS_LINUX
2010   my_mbind(map_address, BUFFER_SIZE, MPOL_PREFERRED, NULL, 0, 0);
2011 #endif
2012
2013   return map_address;
2014 }
2015
2016 #else
2017
2018 #define BENCH_ITERATION 4
2019 #define SCALING         2
2020
2021 static inline BLASULONG run_bench(BLASULONG address, BLASULONG size) {
2022
2023   BLASULONG original, *p;
2024   BLASULONG start, stop, min;
2025   int iter, i, count;
2026
2027   min = (BLASULONG)-1;
2028
2029   original = *(BLASULONG *)(address + size - PAGESIZE);
2030
2031   *(BLASULONG *)(address + size - PAGESIZE) = (BLASULONG)address;
2032
2033   for (iter = 0; iter < BENCH_ITERATION; iter ++ ) {
2034
2035     p = (BLASULONG *)address;
2036
2037     count = size / PAGESIZE;
2038
2039     start = rpcc();
2040
2041     for (i = 0; i < count; i ++) {
2042       p = (BLASULONG *)(*p);
2043     }
2044
2045     stop = rpcc();
2046
2047     if (min > stop - start) min = stop - start;
2048   }
2049
2050   *(BLASULONG *)(address + size - PAGESIZE +  0) = original;
2051   *(BLASULONG *)(address + size - PAGESIZE +  8) = (BLASULONG)p;
2052
2053   return min;
2054 }
2055
2056 static void *alloc_mmap(void *address){
2057   void *map_address, *best_address;
2058   BLASULONG best, start, current;
2059   BLASULONG allocsize;
2060
2061   if (address){
2062     /* Just give up use advanced operation */
2063     map_address = mmap(address, BUFFER_SIZE, MMAP_ACCESS, MMAP_POLICY | MAP_FIXED, -1, 0);
2064
2065 #ifdef OS_LINUX
2066     my_mbind(map_address, BUFFER_SIZE, MPOL_PREFERRED, NULL, 0, 0);
2067 #endif
2068
2069   } else {
2070 #if defined(OS_LINUX) && !defined(NO_WARMUP)
2071     if (hot_alloc == 0) {
2072       map_address = mmap(NULL, BUFFER_SIZE, MMAP_ACCESS, MMAP_POLICY, -1, 0);
2073
2074 #ifdef OS_LINUX
2075       my_mbind(map_address, BUFFER_SIZE, MPOL_PREFERRED, NULL, 0, 0);
2076 #endif
2077
2078     } else {
2079 #endif
2080
2081       map_address = mmap(NULL, BUFFER_SIZE * SCALING,
2082                          MMAP_ACCESS, MMAP_POLICY, -1, 0);
2083
2084       if (map_address != (void *)-1) {
2085
2086 #ifdef OS_LINUX
2087 #ifdef DEBUG
2088                   int ret=0;
2089                   ret=my_mbind(map_address, BUFFER_SIZE * SCALING, MPOL_PREFERRED, NULL, 0, 0);
2090                   if(ret==-1){
2091                           int errsv=errno;
2092                           perror("OpenBLAS alloc_mmap:");
2093                           printf("error code=%d,\tmap_address=%lx\n",errsv,map_address);
2094                   }
2095
2096 #else
2097                   my_mbind(map_address, BUFFER_SIZE * SCALING, MPOL_PREFERRED, NULL, 0, 0);
2098 #endif
2099 #endif
2100
2101
2102         allocsize = DGEMM_P * DGEMM_Q * sizeof(double);
2103
2104         start   = (BLASULONG)map_address;
2105         current = (SCALING - 1) * BUFFER_SIZE;
2106
2107         while(current > 0) {
2108           *(BLASLONG *)start = (BLASLONG)start + PAGESIZE;
2109           start += PAGESIZE;
2110           current -= PAGESIZE;
2111         }
2112
2113         *(BLASLONG *)(start - PAGESIZE) = (BLASULONG)map_address;
2114
2115         start = (BLASULONG)map_address;
2116
2117         best = (BLASULONG)-1;
2118         best_address = map_address;
2119
2120         while ((start + allocsize  < (BLASULONG)map_address + (SCALING - 1) * BUFFER_SIZE)) {
2121
2122           current = run_bench(start, allocsize);
2123
2124           if (best > current) {
2125             best = current;
2126             best_address = (void *)start;
2127           }
2128
2129           start += PAGESIZE;
2130
2131         }
2132
2133       if ((BLASULONG)best_address > (BLASULONG)map_address)
2134         munmap(map_address,  (BLASULONG)best_address - (BLASULONG)map_address);
2135
2136       munmap((void *)((BLASULONG)best_address + BUFFER_SIZE), (SCALING - 1) * BUFFER_SIZE + (BLASULONG)map_address - (BLASULONG)best_address);
2137
2138       map_address = best_address;
2139
2140 #if defined(OS_LINUX) && !defined(NO_WARMUP)
2141       hot_alloc = 2;
2142 #endif
2143       }
2144     }
2145 #if defined(OS_LINUX) && !defined(NO_WARMUP)
2146   }
2147 #endif
2148   LOCK_COMMAND(&alloc_lock);
2149
2150   if (map_address != (void *)-1) {
2151     release_info[release_pos].address = map_address;
2152     release_info[release_pos].func    = alloc_mmap_free;
2153     release_pos ++;
2154   }
2155   UNLOCK_COMMAND(&alloc_lock);
2156
2157   return map_address;
2158 }
2159
2160 #endif
2161
2162 #endif
2163
2164
2165 #ifdef ALLOC_MALLOC
2166
2167 static void alloc_malloc_free(struct release_t *release){
2168
2169   free(release -> address);
2170
2171 }
2172
2173 static void *alloc_malloc(void *address){
2174
2175   void *map_address;
2176
2177   map_address = (void *)malloc(BUFFER_SIZE + FIXED_PAGESIZE);
2178
2179   if (map_address == (void *)NULL) map_address = (void *)-1;
2180
2181   if (map_address != (void *)-1) {
2182     release_info[release_pos].address = map_address;
2183     release_info[release_pos].func    = alloc_malloc_free;
2184     release_pos ++;
2185   }
2186
2187   return map_address;
2188
2189 }
2190
2191 #endif
2192
2193 #ifdef ALLOC_QALLOC
2194
2195 void *qalloc(int flags, size_t bytes);
2196 void *qfree (void *address);
2197
2198 #define QNONCACHE 0x1
2199 #define QCOMMS    0x2
2200 #define QFAST     0x4
2201
2202 static void alloc_qalloc_free(struct release_t *release){
2203
2204   qfree(release -> address);
2205
2206 }
2207
2208 static void *alloc_qalloc(void *address){
2209   void *map_address;
2210
2211   map_address = (void *)qalloc(QCOMMS | QFAST, BUFFER_SIZE + FIXED_PAGESIZE);
2212
2213   if (map_address == (void *)NULL) map_address = (void *)-1;
2214
2215   if (map_address != (void *)-1) {
2216     release_info[release_pos].address = map_address;
2217     release_info[release_pos].func    = alloc_qalloc_free;
2218     release_pos ++;
2219   }
2220
2221   return (void *)(((BLASULONG)map_address + FIXED_PAGESIZE - 1) & ~(FIXED_PAGESIZE - 1));
2222 }
2223
2224 #endif
2225
2226 #ifdef ALLOC_WINDOWS
2227
2228 static void alloc_windows_free(struct release_t *release){
2229
2230   VirtualFree(release -> address, BUFFER_SIZE, MEM_DECOMMIT);
2231
2232 }
2233
2234 static void *alloc_windows(void *address){
2235   void *map_address;
2236
2237   map_address  = VirtualAlloc(address,
2238                               BUFFER_SIZE,
2239                               MEM_RESERVE | MEM_COMMIT,
2240                               PAGE_READWRITE);
2241
2242   if (map_address == (void *)NULL) map_address = (void *)-1;
2243
2244   if (map_address != (void *)-1) {
2245     release_info[release_pos].address = map_address;
2246     release_info[release_pos].func    = alloc_windows_free;
2247     release_pos ++;
2248   }
2249
2250   return map_address;
2251 }
2252
2253 #endif
2254
2255 #ifdef ALLOC_DEVICEDRIVER
2256 #ifndef DEVICEDRIVER_NAME
2257 #define DEVICEDRIVER_NAME "/dev/mapper"
2258 #endif
2259
2260 static void alloc_devicedirver_free(struct release_t *release){
2261
2262   if (munmap(release -> address, BUFFER_SIZE)) {
2263     printf("OpenBLAS : Bugphysarea unmap failed.\n");
2264   }
2265
2266   if (close(release -> attr)) {
2267     printf("OpenBLAS : Bugphysarea close failed.\n");
2268   }
2269
2270 }
2271
2272 static void *alloc_devicedirver(void *address){
2273
2274   int fd;
2275   void *map_address;
2276
2277   if ((fd = open(DEVICEDRIVER_NAME, O_RDWR | O_SYNC)) < 0) {
2278
2279     return (void *)-1;
2280
2281   }
2282
2283   map_address = mmap(address, BUFFER_SIZE,
2284                      PROT_READ | PROT_WRITE,
2285                      MAP_FILE | MAP_SHARED,
2286                      fd, 0);
2287
2288   if (map_address != (void *)-1) {
2289     release_info[release_pos].address = map_address;
2290     release_info[release_pos].attr    = fd;
2291     release_info[release_pos].func    = alloc_devicedirver_free;
2292     release_pos ++;
2293   }
2294
2295   return map_address;
2296 }
2297
2298 #endif
2299
2300 #ifdef ALLOC_SHM
2301
2302 static void alloc_shm_free(struct release_t *release){
2303
2304   if (shmdt(release -> address)) {
2305     printf("OpenBLAS : Shared memory unmap failed.\n");
2306     }
2307 }
2308
2309 static void *alloc_shm(void *address){
2310   void *map_address;
2311   int shmid;
2312
2313   shmid = shmget(IPC_PRIVATE, BUFFER_SIZE,IPC_CREAT | 0600);
2314
2315   map_address = (void *)shmat(shmid, address, 0);
2316
2317   if (map_address != (void *)-1){
2318
2319 #ifdef OS_LINUX
2320     my_mbind(map_address, BUFFER_SIZE, MPOL_PREFERRED, NULL, 0, 0);
2321 #endif
2322
2323     shmctl(shmid, IPC_RMID, 0);
2324
2325     release_info[release_pos].address = map_address;
2326     release_info[release_pos].attr    = shmid;
2327     release_info[release_pos].func    = alloc_shm_free;
2328     release_pos ++;
2329   }
2330
2331   return map_address;
2332 }
2333
2334 #if defined OS_LINUX  || defined OS_AIX  || defined __sun__  || defined OS_WINDOWS
2335
2336 static void alloc_hugetlb_free(struct release_t *release){
2337
2338 #if defined(OS_LINUX) || defined(OS_AIX)
2339   if (shmdt(release -> address)) {
2340     printf("OpenBLAS : Hugepage unmap failed.\n");
2341   }
2342 #endif
2343
2344 #ifdef __sun__
2345
2346   munmap(release -> address, BUFFER_SIZE);
2347
2348 #endif
2349
2350 #ifdef OS_WINDOWS
2351
2352   VirtualFree(release -> address, BUFFER_SIZE, MEM_LARGE_PAGES | MEM_DECOMMIT);
2353
2354 #endif
2355
2356 }
2357
2358 static void *alloc_hugetlb(void *address){
2359
2360   void *map_address = (void *)-1;
2361
2362 #if defined(OS_LINUX) || defined(OS_AIX)
2363   int shmid;
2364
2365   shmid = shmget(IPC_PRIVATE, BUFFER_SIZE,
2366 #ifdef OS_LINUX
2367                  SHM_HUGETLB |
2368 #endif
2369 #ifdef OS_AIX
2370                  SHM_LGPAGE | SHM_PIN |
2371 #endif
2372                  IPC_CREAT | SHM_R | SHM_W);
2373
2374   if (shmid != -1) {
2375     map_address = (void *)shmat(shmid, address, SHM_RND);
2376
2377 #ifdef OS_LINUX
2378     my_mbind(map_address, BUFFER_SIZE, MPOL_PREFERRED, NULL, 0, 0);
2379 #endif
2380
2381     if (map_address != (void *)-1){
2382       shmctl(shmid, IPC_RMID, 0);
2383     }
2384   }
2385 #endif
2386
2387 #ifdef __sun__
2388   struct memcntl_mha mha;
2389
2390   mha.mha_cmd = MHA_MAPSIZE_BSSBRK;
2391   mha.mha_flags = 0;
2392   mha.mha_pagesize = HUGE_PAGESIZE;
2393   memcntl(NULL, 0, MC_HAT_ADVISE, (char *)&mha, 0, 0);
2394
2395   map_address = (BLASULONG)memalign(HUGE_PAGESIZE, BUFFER_SIZE);
2396 #endif
2397
2398 #ifdef OS_WINDOWS
2399
2400   HANDLE hToken;
2401   TOKEN_PRIVILEGES tp;
2402
2403   if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken) != TRUE) return (void *) -1;
2404
2405   tp.PrivilegeCount = 1;
2406   tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
2407   
2408   if (LookupPrivilegeValue(NULL, SE_LOCK_MEMORY_NAME, &tp.Privileges[0].Luid) != TRUE) {
2409       CloseHandle(hToken);
2410       return (void*)-1;
2411   }
2412
2413   if (AdjustTokenPrivileges(hToken, FALSE, &tp, 0, NULL, NULL) != TRUE) {
2414       CloseHandle(hToken);
2415       return (void*)-1;
2416   }
2417
2418   map_address  = (void *)VirtualAlloc(address,
2419                                       BUFFER_SIZE,
2420                                       MEM_LARGE_PAGES | MEM_RESERVE | MEM_COMMIT,
2421                                       PAGE_READWRITE);
2422
2423   tp.Privileges[0].Attributes = 0;
2424   AdjustTokenPrivileges(hToken, FALSE, &tp, 0, NULL, NULL);
2425
2426   if (map_address == (void *)NULL) map_address = (void *)-1;
2427
2428 #endif
2429
2430   if (map_address != (void *)-1){
2431     release_info[release_pos].address = map_address;
2432     release_info[release_pos].func    = alloc_hugetlb_free;
2433     release_pos ++;
2434   }
2435
2436   return map_address;
2437 }
2438 #endif
2439
2440 #endif
2441
2442 #ifdef  ALLOC_HUGETLBFILE
2443
2444 static int hugetlb_pid = 0;
2445
2446 static void alloc_hugetlbfile_free(struct release_t *release){
2447
2448   if (munmap(release -> address, BUFFER_SIZE)) {
2449     printf("OpenBLAS : HugeTLBfs unmap failed.\n");
2450   }
2451
2452   if (close(release -> attr)) {
2453     printf("OpenBLAS : HugeTLBfs close failed.\n");
2454   }
2455 }
2456
2457 static void *alloc_hugetlbfile(void *address){
2458
2459   void *map_address = (void *)-1;
2460   int fd;
2461   char filename[64];
2462
2463   if (!hugetlb_pid) hugetlb_pid = getpid();
2464
2465   sprintf(filename, "%s/gotoblas.%d", HUGETLB_FILE_NAME, hugetlb_pid);
2466
2467   if ((fd = open(filename, O_RDWR | O_CREAT, 0700)) < 0) {
2468     return (void *)-1;
2469   }
2470
2471   unlink(filename);
2472
2473   map_address = mmap(address, BUFFER_SIZE,
2474                      PROT_READ | PROT_WRITE,
2475                      MAP_SHARED,
2476                      fd, 0);
2477
2478   if (map_address != (void *)-1) {
2479     release_info[release_pos].address = map_address;
2480     release_info[release_pos].attr    = fd;
2481     release_info[release_pos].func    = alloc_hugetlbfile_free;
2482     release_pos ++;
2483   }
2484
2485   return map_address;
2486 }
2487 #endif
2488
2489
2490 #ifdef SEEK_ADDRESS
2491 static BLASULONG base_address      = 0UL;
2492 #else
2493 static BLASULONG base_address      = BASE_ADDRESS;
2494 #endif
2495
2496 static volatile struct {
2497   BLASULONG lock;
2498   void *addr;
2499 #if defined(WHEREAMI) && !defined(USE_OPENMP)
2500   int   pos;
2501 #endif
2502   int used;
2503 #ifndef __64BIT__
2504   char dummy[48];
2505 #else
2506   char dummy[40];
2507 #endif
2508
2509 } memory[NUM_BUFFERS];
2510
2511 static int memory_initialized = 0;
2512
2513 /*       Memory allocation routine           */
2514 /* procpos ... indicates where it comes from */
2515 /*                0 : Level 3 functions      */
2516 /*                1 : Level 2 functions      */
2517 /*                2 : Thread                 */
2518
2519 void *blas_memory_alloc(int procpos){
2520
2521   int position;
2522 #if defined(WHEREAMI) && !defined(USE_OPENMP)
2523   int mypos;
2524 #endif
2525
2526   void *map_address;
2527
2528   void *(*memoryalloc[])(void *address) = {
2529 #ifdef ALLOC_DEVICEDRIVER
2530     alloc_devicedirver,
2531 #endif
2532 /* Hugetlb implicitly assumes ALLOC_SHM */
2533 #ifdef ALLOC_SHM
2534     alloc_shm,
2535 #endif
2536 #if ((defined ALLOC_SHM) && (defined OS_LINUX  || defined OS_AIX  || defined __sun__  || defined OS_WINDOWS))
2537     alloc_hugetlb,
2538 #endif
2539 #ifdef ALLOC_MMAP
2540     alloc_mmap,
2541 #endif
2542 #ifdef ALLOC_QALLOC
2543     alloc_qalloc,
2544 #endif
2545 #ifdef ALLOC_WINDOWS
2546     alloc_windows,
2547 #endif
2548 #ifdef ALLOC_MALLOC
2549     alloc_malloc,
2550 #endif
2551     NULL,
2552   };
2553   void *(**func)(void *address);
2554   LOCK_COMMAND(&alloc_lock);
2555
2556   if (!memory_initialized) {
2557
2558 #if defined(WHEREAMI) && !defined(USE_OPENMP)
2559     for (position = 0; position < NUM_BUFFERS; position ++){
2560       memory[position].addr   = (void *)0;
2561       memory[position].pos    = -1;
2562       memory[position].used   = 0;
2563       memory[position].lock   = 0;
2564     }
2565 #endif
2566
2567 #ifdef DYNAMIC_ARCH
2568     gotoblas_dynamic_init();
2569 #endif
2570
2571 #if defined(SMP) && defined(OS_LINUX) && !defined(NO_AFFINITY)
2572     gotoblas_affinity_init();
2573 #endif
2574
2575 #ifdef SMP
2576     if (!blas_num_threads) blas_cpu_number = blas_get_cpu_number();
2577 #endif
2578
2579 #if defined(ARCH_X86) || defined(ARCH_X86_64) || defined(ARCH_IA64) || defined(ARCH_MIPS64) || defined(ARCH_ARM64)
2580 #ifndef DYNAMIC_ARCH
2581     blas_set_parameter();
2582 #endif
2583 #endif
2584
2585     memory_initialized = 1;
2586
2587   }
2588   UNLOCK_COMMAND(&alloc_lock);
2589
2590 #ifdef DEBUG
2591   printf("Alloc Start ...\n");
2592 #endif
2593
2594 /* #if defined(WHEREAMI) && !defined(USE_OPENMP)
2595
2596   mypos = WhereAmI();
2597
2598   position = mypos;
2599   while (position >= NUM_BUFFERS) position >>= 1;
2600
2601   do {
2602     if (!memory[position].used && (memory[position].pos == mypos)) {
2603       LOCK_COMMAND(&alloc_lock);
2604 //      blas_lock(&memory[position].lock);
2605
2606       if (!memory[position].used) goto allocation;
2607
2608       UNLOCK_COMMAND(&alloc_lock);
2609 //      blas_unlock(&memory[position].lock);
2610     }
2611
2612     position ++;
2613
2614   } while (position < NUM_BUFFERS);
2615
2616
2617 #endif */
2618
2619   position = 0;
2620
2621   LOCK_COMMAND(&alloc_lock);
2622   do {
2623 /*    if (!memory[position].used) { */
2624 /*      blas_lock(&memory[position].lock);*/
2625
2626       if (!memory[position].used) goto allocation;
2627       
2628 /*      blas_unlock(&memory[position].lock);*/
2629 /*    } */
2630
2631     position ++;
2632
2633   } while (position < NUM_BUFFERS);
2634   UNLOCK_COMMAND(&alloc_lock);
2635
2636   goto error;
2637
2638   allocation :
2639
2640 #ifdef DEBUG
2641   printf("  Position -> %d\n", position);
2642 #endif
2643
2644   memory[position].used = 1;
2645
2646   UNLOCK_COMMAND(&alloc_lock);
2647 /*  blas_unlock(&memory[position].lock);*/
2648
2649   if (!memory[position].addr) {
2650     do {
2651 #ifdef DEBUG
2652       printf("Allocation Start : %lx\n", base_address);
2653 #endif
2654
2655       map_address = (void *)-1;
2656
2657       func = &memoryalloc[0];
2658
2659       while ((func != NULL) && (map_address == (void *) -1)) {
2660
2661         map_address = (*func)((void *)base_address);
2662
2663 #ifdef ALLOC_DEVICEDRIVER
2664         if ((*func ==  alloc_devicedirver) && (map_address == (void *)-1)) {
2665             fprintf(stderr, "OpenBLAS Warning ... Physically contigous allocation was failed.\n");
2666         }
2667 #endif
2668
2669 #ifdef ALLOC_HUGETLBFILE
2670         if ((*func == alloc_hugetlbfile) && (map_address == (void *)-1)) {
2671 #ifndef OS_WINDOWS
2672             fprintf(stderr, "OpenBLAS Warning ... HugeTLB(File) allocation was failed.\n");
2673 #endif
2674         }
2675 #endif
2676
2677 #if (defined ALLOC_SHM) && (defined OS_LINUX  || defined OS_AIX  || defined __sun__  || defined OS_WINDOWS)
2678         if ((*func == alloc_hugetlb) && (map_address != (void *)-1)) hugetlb_allocated = 1;
2679 #endif
2680
2681         func ++;
2682       }
2683
2684 #ifdef DEBUG
2685       printf("  Success -> %08lx\n", map_address);
2686 #endif
2687       if (((BLASLONG) map_address) == -1) base_address = 0UL;
2688
2689       if (base_address) base_address += BUFFER_SIZE + FIXED_PAGESIZE;
2690
2691     } while ((BLASLONG)map_address == -1);
2692
2693     LOCK_COMMAND(&alloc_lock);
2694     memory[position].addr = map_address;
2695     UNLOCK_COMMAND(&alloc_lock);
2696
2697 #ifdef DEBUG
2698     printf("  Mapping Succeeded. %p(%d)\n", (void *)memory[position].addr, position);
2699 #endif
2700   }
2701
2702 #if defined(WHEREAMI) && !defined(USE_OPENMP)
2703
2704   if (memory[position].pos == -1) memory[position].pos = mypos;
2705
2706 #endif
2707
2708 #ifdef DYNAMIC_ARCH
2709
2710   if (memory_initialized == 1) {
2711
2712     LOCK_COMMAND(&alloc_lock);
2713
2714     if (memory_initialized == 1) {
2715
2716       if (!gotoblas) gotoblas_dynamic_init();
2717
2718       memory_initialized = 2;
2719     }
2720
2721     UNLOCK_COMMAND(&alloc_lock);
2722
2723   }
2724 #endif
2725
2726
2727 #ifdef DEBUG
2728   printf("Mapped   : %p  %3d\n\n",
2729           (void *)memory[position].addr, position);
2730 #endif
2731
2732   return (void *)memory[position].addr;
2733
2734  error:
2735   printf("BLAS : Program is Terminated. Because you tried to allocate too many memory regions.\n");
2736
2737   return NULL;
2738 }
2739
2740 void blas_memory_free(void *free_area){
2741
2742   int position;
2743
2744 #ifdef DEBUG
2745   printf("Unmapped Start : %p ...\n", free_area);
2746 #endif
2747
2748   position = 0;
2749   LOCK_COMMAND(&alloc_lock);
2750
2751   while ((position < NUM_BUFFERS) && (memory[position].addr != free_area))
2752     position++;
2753
2754   if (memory[position].addr != free_area) goto error;
2755
2756 #ifdef DEBUG
2757   printf("  Position : %d\n", position);
2758 #endif
2759
2760   // arm: ensure all writes are finished before other thread takes this memory
2761   WMB;
2762
2763   memory[position].used = 0;
2764   UNLOCK_COMMAND(&alloc_lock);
2765
2766 #ifdef DEBUG
2767   printf("Unmap Succeeded.\n\n");
2768 #endif
2769
2770   return;
2771
2772  error:
2773   printf("BLAS : Bad memory unallocation! : %4d  %p\n", position,  free_area);
2774
2775 #ifdef DEBUG
2776   for (position = 0; position < NUM_BUFFERS; position++)
2777     printf("%4ld  %p : %d\n", position, memory[position].addr, memory[position].used);
2778 #endif
2779   UNLOCK_COMMAND(&alloc_lock);
2780
2781   return;
2782 }
2783
2784 void *blas_memory_alloc_nolock(int unused) {
2785   void *map_address;
2786   map_address = (void *)malloc(BUFFER_SIZE + FIXED_PAGESIZE);
2787   return map_address;
2788 }
2789
2790 void blas_memory_free_nolock(void * map_address) {
2791   free(map_address);
2792 }
2793
2794 void blas_shutdown(void){
2795
2796   int pos;
2797
2798 #ifdef SMP
2799   BLASFUNC(blas_thread_shutdown)();
2800 #endif
2801
2802   LOCK_COMMAND(&alloc_lock);
2803
2804   for (pos = 0; pos < release_pos; pos ++) {
2805     release_info[pos].func(&release_info[pos]);
2806   }
2807
2808 #ifdef SEEK_ADDRESS
2809   base_address      = 0UL;
2810 #else
2811   base_address      = BASE_ADDRESS;
2812 #endif
2813
2814   for (pos = 0; pos < NUM_BUFFERS; pos ++){
2815     memory[pos].addr   = (void *)0;
2816     memory[pos].used   = 0;
2817 #if defined(WHEREAMI) && !defined(USE_OPENMP)
2818     memory[pos].pos    = -1;
2819 #endif
2820     memory[pos].lock   = 0;
2821   }
2822
2823   UNLOCK_COMMAND(&alloc_lock);
2824
2825   return;
2826 }
2827
2828 #if defined(OS_LINUX) && !defined(NO_WARMUP)
2829
2830 #ifdef SMP
2831 #if   defined(USE_PTHREAD_LOCK)
2832 static pthread_mutex_t    init_lock = PTHREAD_MUTEX_INITIALIZER;
2833 #elif defined(USE_PTHREAD_SPINLOCK)
2834 static pthread_spinlock_t init_lock = 0;
2835 #else
2836 static BLASULONG   init_lock = 0UL;
2837 #endif
2838 #endif
2839
2840 static void _touch_memory(blas_arg_t *arg, BLASLONG *range_m, BLASLONG *range_n,
2841                           void *sa, void *sb, BLASLONG pos) {
2842
2843 #if !defined(ARCH_POWER) && !defined(ARCH_SPARC)
2844
2845   size_t size;
2846   BLASULONG buffer;
2847
2848   size   = BUFFER_SIZE - PAGESIZE;
2849   buffer = (BLASULONG)sa + GEMM_OFFSET_A;
2850
2851 #if defined(OS_LINUX) && !defined(NO_WARMUP)
2852     if (hot_alloc != 2) {
2853 #endif
2854
2855 #ifdef SMP
2856   LOCK_COMMAND(&init_lock);
2857 #endif
2858
2859   while (size > 0) {
2860     *(int *)buffer = size;
2861     buffer  += PAGESIZE;
2862     size    -= PAGESIZE;
2863   }
2864
2865 #ifdef SMP
2866   UNLOCK_COMMAND(&init_lock);
2867 #endif
2868
2869   size = MIN((BUFFER_SIZE - PAGESIZE), L2_SIZE);
2870   buffer = (BLASULONG)sa + GEMM_OFFSET_A;
2871
2872   while (size > 0) {
2873     *(int *)buffer = size;
2874     buffer  += 64;
2875     size    -= 64;
2876   }
2877
2878 #if defined(OS_LINUX) && !defined(NO_WARMUP)
2879     }
2880 #endif
2881
2882 #endif
2883 }
2884
2885 #ifdef SMP
2886
2887 static void _init_thread_memory(void *buffer) {
2888
2889   blas_queue_t queue[MAX_CPU_NUMBER];
2890   int num_cpu;
2891
2892   for (num_cpu = 0; num_cpu < blas_num_threads; num_cpu++) {
2893
2894     blas_queue_init(&queue[num_cpu]);
2895     queue[num_cpu].mode    = BLAS_DOUBLE | BLAS_REAL;
2896     queue[num_cpu].routine = &_touch_memory;
2897     queue[num_cpu].args    = NULL;
2898     queue[num_cpu].next    = &queue[num_cpu + 1];
2899   }
2900
2901   queue[num_cpu - 1].next = NULL;
2902   queue[0].sa = buffer;
2903
2904   exec_blas(num_cpu, queue);
2905
2906 }
2907 #endif
2908
2909 static void gotoblas_memory_init(void) {
2910
2911   void *buffer;
2912
2913   hot_alloc = 1;
2914
2915   buffer = (void *)blas_memory_alloc(0);
2916
2917 #ifdef SMP
2918   if (blas_cpu_number == 0) blas_get_cpu_number();
2919 #ifdef SMP_SERVER
2920   if (blas_server_avail == 0) blas_thread_init();
2921 #endif
2922
2923   _init_thread_memory((void *)((BLASULONG)buffer + GEMM_OFFSET_A));
2924
2925 #else
2926
2927   _touch_memory(NULL, NULL, NULL, (void *)((BLASULONG)buffer + GEMM_OFFSET_A), NULL, 0);
2928
2929 #endif
2930
2931   blas_memory_free(buffer);
2932 }
2933 #endif
2934
2935 /* Initialization for all function; this function should be called before main */
2936
2937 static int gotoblas_initialized = 0;
2938 extern void openblas_read_env();
2939
2940 void CONSTRUCTOR gotoblas_init(void) {
2941
2942   if (gotoblas_initialized) return;
2943
2944 #ifdef SMP
2945   openblas_fork_handler();
2946 #endif
2947
2948   openblas_read_env();
2949
2950 #ifdef PROFILE
2951    moncontrol (0);
2952 #endif
2953
2954 #ifdef DYNAMIC_ARCH
2955    gotoblas_dynamic_init();
2956 #endif
2957
2958 #if defined(SMP) && defined(OS_LINUX) && !defined(NO_AFFINITY)
2959    gotoblas_affinity_init();
2960 #endif
2961
2962 #if defined(OS_LINUX) && !defined(NO_WARMUP)
2963    gotoblas_memory_init();
2964 #endif
2965
2966 //#if defined(OS_LINUX)
2967 #if 0
2968    struct rlimit curlimit;
2969    if ( getrlimit(RLIMIT_STACK, &curlimit ) == 0 )
2970    {
2971         if ( curlimit.rlim_cur != curlimit.rlim_max )
2972         {
2973                 curlimit.rlim_cur = curlimit.rlim_max;
2974                 setrlimit(RLIMIT_STACK, &curlimit);
2975         }
2976    }
2977 #endif
2978
2979 #ifdef SMP
2980   if (blas_cpu_number == 0) blas_get_cpu_number();
2981 #ifdef SMP_SERVER
2982   if (blas_server_avail == 0) blas_thread_init();
2983 #endif
2984 #endif
2985
2986 #ifdef FUNCTION_PROFILE
2987    gotoblas_profile_init();
2988 #endif
2989
2990    gotoblas_initialized = 1;
2991
2992 #ifdef PROFILE
2993    moncontrol (1);
2994 #endif
2995
2996 }
2997
2998 void DESTRUCTOR gotoblas_quit(void) {
2999
3000   if (gotoblas_initialized == 0) return;
3001
3002   blas_shutdown();
3003
3004 #ifdef PROFILE
3005    moncontrol (0);
3006 #endif
3007
3008 #ifdef FUNCTION_PROFILE
3009    gotoblas_profile_quit();
3010 #endif
3011
3012 #if defined(SMP) && defined(OS_LINUX) && !defined(NO_AFFINITY)
3013    gotoblas_affinity_quit();
3014 #endif
3015
3016 #ifdef DYNAMIC_ARCH
3017    gotoblas_dynamic_quit();
3018 #endif
3019
3020    gotoblas_initialized = 0;
3021
3022 #ifdef PROFILE
3023    moncontrol (1);
3024 #endif
3025 }
3026
3027 #if defined(_MSC_VER) && !defined(__clang__)
3028 BOOL APIENTRY DllMain(HMODULE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved)
3029 {
3030   switch (ul_reason_for_call)
3031   {
3032     case DLL_PROCESS_ATTACH:
3033       gotoblas_init();
3034       break;
3035     case DLL_THREAD_ATTACH:
3036       break;
3037     case DLL_THREAD_DETACH:
3038       break;
3039     case DLL_PROCESS_DETACH:
3040       gotoblas_quit();
3041       break;
3042     default:
3043       break;
3044   }
3045   return TRUE;
3046 }
3047
3048 /*
3049   This is to allow static linking.
3050   Code adapted from Google performance tools:
3051   https://gperftools.googlecode.com/git-history/perftools-1.0/src/windows/port.cc
3052   Reference:
3053   https://sourceware.org/ml/pthreads-win32/2008/msg00028.html
3054   http://ci.boost.org/svn-trac/browser/trunk/libs/thread/src/win32/tss_pe.cpp
3055 */
3056 static int on_process_term(void)
3057 {
3058         gotoblas_quit();
3059         return 0;
3060 }
3061 #ifdef _WIN64
3062 #pragma comment(linker, "/INCLUDE:_tls_used")
3063 #else
3064 #pragma comment(linker, "/INCLUDE:__tls_used")
3065 #endif
3066
3067 #ifdef _WIN64
3068 #pragma const_seg(".CRT$XLB")
3069 #else
3070 #pragma data_seg(".CRT$XLB")
3071 #endif
3072 static void (APIENTRY *dll_callback)(HINSTANCE h, DWORD ul_reason_for_call, PVOID pv) = DllMain;
3073 #ifdef _WIN64
3074 #pragma const_seg()
3075 #else
3076 #pragma data_seg()
3077 #endif
3078
3079 #ifdef _WIN64
3080 #pragma const_seg(".CRT$XTU")
3081 #else
3082 #pragma data_seg(".CRT$XTU")
3083 #endif
3084 static int(*p_process_term)(void) = on_process_term;
3085 #ifdef _WIN64
3086 #pragma const_seg()
3087 #else
3088 #pragma data_seg()
3089 #endif
3090 #endif
3091
3092 #if (defined(C_PGI) || (!defined(C_SUN) && defined(F_INTERFACE_SUN))) && (defined(ARCH_X86) || defined(ARCH_X86_64))
3093 /* Don't call me; this is just work around for PGI / Sun bug */
3094 void gotoblas_dummy_for_PGI(void) {
3095
3096   gotoblas_init();
3097   gotoblas_quit();
3098
3099 #if 0
3100   asm ("\t.section\t.ctors,\"aw\",@progbits; .align 8; .quad gotoblas_init; .section .text");
3101   asm ("\t.section\t.dtors,\"aw\",@progbits; .align 8; .quad gotoblas_quit; .section .text");
3102 #else
3103   asm (".section .init,\"ax\"; call gotoblas_init@PLT; .section .text");
3104   asm (".section .fini,\"ax\"; call gotoblas_quit@PLT; .section .text");
3105 #endif
3106 }
3107 #endif
3108
3109 #endif