36815a39c3c9fd308fbafea38a097a2ad580fc94
[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 }
1077
1078 static void blas_memory_init(){
1079 #if defined(SMP)
1080 #  if defined(OS_WINDOWS)
1081   local_storage_key = TlsAlloc();
1082 #  else
1083   pthread_key_create(&local_storage_key, blas_memory_cleanup);
1084 #  endif /* defined(OS_WINDOWS) */
1085 #endif /* defined(SMP) */
1086 }
1087
1088 void *blas_memory_alloc(int procpos){
1089
1090   int position;
1091
1092   void *map_address;
1093
1094   void *(*memoryalloc[])(void *address) = {
1095 #ifdef ALLOC_DEVICEDRIVER
1096     alloc_devicedirver,
1097 #endif
1098 /* Hugetlb implicitly assumes ALLOC_SHM */
1099 #ifdef ALLOC_SHM
1100     alloc_shm,
1101 #endif
1102 #if ((defined ALLOC_SHM) && (defined OS_LINUX  || defined OS_AIX  || defined __sun__  || defined OS_WINDOWS))
1103     alloc_hugetlb,
1104 #endif
1105 #ifdef ALLOC_MMAP
1106     alloc_mmap,
1107 #endif
1108 #ifdef ALLOC_QALLOC
1109     alloc_qalloc,
1110 #endif
1111 #ifdef ALLOC_WINDOWS
1112     alloc_windows,
1113 #endif
1114 #ifdef ALLOC_MALLOC
1115     alloc_malloc,
1116 #endif
1117     NULL,
1118   };
1119   void *(**func)(void *address);
1120   struct alloc_t * alloc_info;
1121   struct alloc_t ** alloc_table;
1122
1123
1124 #if defined(SMP) && !defined(USE_OPENMP)
1125 int mi;
1126 LOCK_COMMAND(&alloc_lock);
1127 mi=memory_initialized;
1128 UNLOCK_COMMAND(&alloc_lock);
1129   if (!LIKELY_ONE(mi)) {
1130 #else
1131   if (!LIKELY_ONE(memory_initialized)) {
1132 #endif
1133 #if defined(SMP) && !defined(USE_OPENMP)
1134     /* Only allow a single thread to initialize memory system */
1135     LOCK_COMMAND(&alloc_lock);
1136
1137     if (!memory_initialized) {
1138 #endif
1139       blas_memory_init();
1140 #ifdef DYNAMIC_ARCH
1141       gotoblas_dynamic_init();
1142 #endif
1143
1144 #if defined(SMP) && defined(OS_LINUX) && !defined(NO_AFFINITY)
1145       gotoblas_affinity_init();
1146 #endif
1147
1148 #ifdef SMP
1149       if (!blas_num_threads) blas_cpu_number = blas_get_cpu_number();
1150 #endif
1151
1152 #if defined(ARCH_X86) || defined(ARCH_X86_64) || defined(ARCH_IA64) || defined(ARCH_MIPS64) || defined(ARCH_ARM64)
1153 #ifndef DYNAMIC_ARCH
1154       blas_set_parameter();
1155 #endif
1156 #endif
1157
1158       memory_initialized = 1;
1159
1160 #if defined(SMP) && !defined(USE_OPENMP)
1161     }
1162     UNLOCK_COMMAND(&alloc_lock);
1163 #endif
1164   }
1165
1166 #ifdef DEBUG
1167   printf("Alloc Start ...\n");
1168 #endif
1169
1170   position = 0;
1171   alloc_table = get_memory_table();
1172   do {
1173       if (!alloc_table[position] || !alloc_table[position]->used) goto allocation;
1174     position ++;
1175
1176   } while (position < NUM_BUFFERS);
1177
1178   goto error;
1179
1180   allocation :
1181
1182 #ifdef DEBUG
1183   printf("  Position -> %d\n", position);
1184 #endif
1185
1186   alloc_info = alloc_table[position];
1187   if (!alloc_info) {
1188     do {
1189 #ifdef DEBUG
1190       printf("Allocation Start : %lx\n", base_address);
1191 #endif
1192
1193       map_address = (void *)-1;
1194
1195       func = &memoryalloc[0];
1196
1197       while ((func != NULL) && (map_address == (void *) -1)) {
1198
1199   map_address = (*func)((void *)base_address);
1200
1201 #ifdef ALLOC_DEVICEDRIVER
1202         if ((*func ==  alloc_devicedirver) && (map_address == (void *)-1)) {
1203             fprintf(stderr, "OpenBLAS Warning ... Physically contiguous allocation failed.\n");
1204         }
1205 #endif
1206
1207 #ifdef ALLOC_HUGETLBFILE
1208         if ((*func == alloc_hugetlbfile) && (map_address == (void *)-1)) {
1209 #ifndef OS_WINDOWS
1210             fprintf(stderr, "OpenBLAS Warning ... HugeTLB(File) allocation failed.\n");
1211 #endif
1212         }
1213 #endif
1214
1215 #if (defined ALLOC_SHM) && (defined OS_LINUX  || defined OS_AIX  || defined __sun__  || defined OS_WINDOWS)
1216         if ((*func == alloc_hugetlb) && (map_address != (void *)-1)) hugetlb_allocated = 1;
1217 #endif
1218
1219         func ++;
1220       }
1221
1222 #ifdef DEBUG
1223       printf("  Success -> %08lx\n", map_address);
1224 #endif
1225       if (((BLASLONG) map_address) == -1) base_address = 0UL;
1226
1227       if (base_address) base_address += allocation_block_size + FIXED_PAGESIZE;
1228
1229     } while ((BLASLONG)map_address == -1);
1230
1231     alloc_table[position] = alloc_info = map_address;
1232
1233 #ifdef DEBUG
1234     printf("  Mapping Succeeded. %p(%d)\n", (void *)alloc_info, position);
1235 #endif
1236   }
1237
1238 #ifdef DEBUG
1239   printf("Mapped   : %p  %3d\n\n", (void *)alloc_info, position);
1240 #endif
1241
1242   alloc_info->used = 1;
1243
1244   return (void *)(((char *)alloc_info) + sizeof(struct alloc_t));
1245
1246  error:
1247   printf("OpenBLAS : Program will terminate because you tried to allocate too many memory regions.\n");
1248
1249   return NULL;
1250 }
1251
1252 void blas_memory_free(void *buffer){
1253 #ifdef DEBUG
1254   int position;
1255   struct alloc_t ** alloc_table;
1256 #endif
1257   /* Since we passed an offset pointer to the caller, get back to the actual allocation */
1258   struct alloc_t *alloc_info = (void *)(((char *)buffer) - sizeof(struct alloc_t));
1259
1260 #ifdef DEBUG
1261   printf("Unmapped Start : %p ...\n", alloc_info);
1262 #endif
1263
1264   alloc_info->used = 0;
1265
1266 #ifdef DEBUG
1267   printf("Unmap Succeeded.\n\n");
1268 #endif
1269
1270   return;
1271
1272 #ifdef DEBUG
1273   alloc_table = get_memory_table();
1274   for (position = 0; position < NUM_BUFFERS; position++){
1275     if (alloc_table[position]) {
1276       printf("%4ld  %p : %d\n", position, alloc_table[position], alloc_table[position]->used);
1277     }
1278   }
1279 #endif
1280   return;
1281 }
1282
1283 void *blas_memory_alloc_nolock(int unused) {
1284   void *map_address;
1285   map_address = (void *)malloc(BUFFER_SIZE + FIXED_PAGESIZE);
1286   return map_address;
1287 }
1288
1289 void blas_memory_free_nolock(void * map_address) {
1290   free(map_address);
1291 }
1292
1293 void blas_shutdown(void){
1294 #ifdef SMP
1295   BLASFUNC(blas_thread_shutdown)();
1296 #endif
1297
1298 #ifdef SMP
1299   /* Only cleanupIf we were built for threading and TLS was initialized */
1300   if (local_storage_key)
1301 #endif
1302     blas_memory_cleanup((void*)get_memory_table());
1303
1304 #ifdef SEEK_ADDRESS
1305   base_address      = 0UL;
1306 #else
1307   base_address      = BASE_ADDRESS;
1308 #endif
1309
1310   return;
1311 }
1312
1313 #if defined(OS_LINUX) && !defined(NO_WARMUP)
1314
1315 #ifdef SMP
1316 #if   defined(USE_PTHREAD_LOCK)
1317 static pthread_mutex_t    init_lock = PTHREAD_MUTEX_INITIALIZER;
1318 #elif defined(USE_PTHREAD_SPINLOCK)
1319 static pthread_spinlock_t init_lock = 0;
1320 #else
1321 static BLASULONG   init_lock = 0UL;
1322 #endif
1323 #endif
1324
1325 static void _touch_memory(blas_arg_t *arg, BLASLONG *range_m, BLASLONG *range_n,
1326                           void *sa, void *sb, BLASLONG pos) {
1327
1328 #if !defined(ARCH_POWER) && !defined(ARCH_SPARC)
1329
1330   size_t size;
1331   BLASULONG buffer;
1332
1333   size   = allocation_block_size - PAGESIZE;
1334   buffer = (BLASULONG)sa + GEMM_OFFSET_A;
1335
1336 #if defined(OS_LINUX) && !defined(NO_WARMUP)
1337     if (hot_alloc != 2) {
1338 #endif
1339
1340 #ifdef SMP
1341   LOCK_COMMAND(&init_lock);
1342 #endif
1343
1344   while (size > 0) {
1345     *(int *)buffer = size;
1346     buffer  += PAGESIZE;
1347     size    -= PAGESIZE;
1348   }
1349
1350 #ifdef SMP
1351   UNLOCK_COMMAND(&init_lock);
1352 #endif
1353
1354   size = MIN((allocation_block_size - PAGESIZE), L2_SIZE);
1355   buffer = (BLASULONG)sa + GEMM_OFFSET_A;
1356
1357   while (size > 0) {
1358     *(int *)buffer = size;
1359     buffer  += 64;
1360     size    -= 64;
1361   }
1362
1363 #if defined(OS_LINUX) && !defined(NO_WARMUP)
1364     }
1365 #endif
1366
1367 #endif
1368 }
1369
1370 #ifdef SMP
1371
1372 static void _init_thread_memory(void *buffer) {
1373
1374   blas_queue_t queue[MAX_CPU_NUMBER];
1375   int num_cpu;
1376
1377   for (num_cpu = 0; num_cpu < blas_num_threads; num_cpu++) {
1378
1379     blas_queue_init(&queue[num_cpu]);
1380     queue[num_cpu].mode    = BLAS_DOUBLE | BLAS_REAL;
1381     queue[num_cpu].routine = &_touch_memory;
1382     queue[num_cpu].args    = NULL;
1383     queue[num_cpu].next    = &queue[num_cpu + 1];
1384   }
1385
1386   queue[num_cpu - 1].next = NULL;
1387   queue[0].sa = buffer;
1388
1389   exec_blas(num_cpu, queue);
1390
1391 }
1392 #endif
1393
1394 static void gotoblas_memory_init(void) {
1395
1396   void *buffer;
1397
1398   hot_alloc = 1;
1399
1400   buffer = (void *)blas_memory_alloc(0);
1401
1402 #ifdef SMP
1403   if (blas_cpu_number == 0) blas_get_cpu_number();
1404 #ifdef SMP_SERVER
1405   if (blas_server_avail == 0) blas_thread_init();
1406 #endif
1407
1408   _init_thread_memory((void *)((BLASULONG)buffer + GEMM_OFFSET_A));
1409
1410 #else
1411
1412   _touch_memory(NULL, NULL, NULL, (void *)((BLASULONG)buffer + GEMM_OFFSET_A), NULL, 0);
1413
1414 #endif
1415
1416   blas_memory_free(buffer);
1417 }
1418 #endif
1419
1420 /* Initialization for all function; this function should be called before main */
1421
1422 static int gotoblas_initialized = 0;
1423 extern void openblas_read_env();
1424
1425 void CONSTRUCTOR gotoblas_init(void) {
1426
1427   if (gotoblas_initialized) return;
1428
1429 #ifdef SMP
1430   openblas_fork_handler();
1431 #endif
1432
1433   openblas_read_env();
1434
1435 #ifdef PROFILE
1436    moncontrol (0);
1437 #endif
1438
1439 #ifdef DYNAMIC_ARCH
1440    gotoblas_dynamic_init();
1441 #endif
1442
1443 #if defined(SMP) && defined(OS_LINUX) && !defined(NO_AFFINITY)
1444    gotoblas_affinity_init();
1445 #endif
1446
1447 #if defined(OS_LINUX) && !defined(NO_WARMUP)
1448    gotoblas_memory_init();
1449 #endif
1450
1451 //#if defined(OS_LINUX)
1452 #if 0
1453    struct rlimit curlimit;
1454    if ( getrlimit(RLIMIT_STACK, &curlimit ) == 0 )
1455    {
1456         if ( curlimit.rlim_cur != curlimit.rlim_max )
1457         {
1458                 curlimit.rlim_cur = curlimit.rlim_max;
1459                 setrlimit(RLIMIT_STACK, &curlimit);
1460         }
1461    }
1462 #endif
1463
1464 #ifdef SMP
1465   if (blas_cpu_number == 0) blas_get_cpu_number();
1466 #ifdef SMP_SERVER
1467   if (blas_server_avail == 0) blas_thread_init();
1468 #endif
1469 #endif
1470
1471 #ifdef FUNCTION_PROFILE
1472    gotoblas_profile_init();
1473 #endif
1474
1475    gotoblas_initialized = 1;
1476
1477 #ifdef PROFILE
1478    moncontrol (1);
1479 #endif
1480
1481 }
1482
1483 void DESTRUCTOR gotoblas_quit(void) {
1484
1485   if (gotoblas_initialized == 0) return;
1486
1487   blas_shutdown();
1488
1489 #ifdef PROFILE
1490    moncontrol (0);
1491 #endif
1492
1493 #ifdef FUNCTION_PROFILE
1494    gotoblas_profile_quit();
1495 #endif
1496
1497 #if defined(SMP) && defined(OS_LINUX) && !defined(NO_AFFINITY)
1498    gotoblas_affinity_quit();
1499 #endif
1500
1501 #ifdef DYNAMIC_ARCH
1502    gotoblas_dynamic_quit();
1503 #endif
1504
1505    gotoblas_initialized = 0;
1506
1507 #ifdef PROFILE
1508    moncontrol (1);
1509 #endif
1510 }
1511
1512 #if defined(_MSC_VER) && !defined(__clang__)
1513 BOOL APIENTRY DllMain(HMODULE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved)
1514 {
1515   switch (ul_reason_for_call)
1516   {
1517     case DLL_PROCESS_ATTACH:
1518       gotoblas_init();
1519       break;
1520     case DLL_THREAD_ATTACH:
1521       break;
1522     case DLL_THREAD_DETACH:
1523 #if defined(SMP)
1524       blas_memory_cleanup((void*)get_memory_table());
1525 #endif
1526       break;
1527     case DLL_PROCESS_DETACH:
1528       gotoblas_quit();
1529       break;
1530     default:
1531       break;
1532   }
1533   return TRUE;
1534 }
1535
1536 /*
1537   This is to allow static linking.
1538   Code adapted from Google performance tools:
1539   https://gperftools.googlecode.com/git-history/perftools-1.0/src/windows/port.cc
1540   Reference:
1541   https://sourceware.org/ml/pthreads-win32/2008/msg00028.html
1542   http://ci.boost.org/svn-trac/browser/trunk/libs/thread/src/win32/tss_pe.cpp
1543 */
1544 static int on_process_term(void)
1545 {
1546         gotoblas_quit();
1547         return 0;
1548 }
1549 #ifdef _WIN64
1550 #pragma comment(linker, "/INCLUDE:_tls_used")
1551 #else
1552 #pragma comment(linker, "/INCLUDE:__tls_used")
1553 #endif
1554
1555 #ifdef _WIN64
1556 #pragma const_seg(".CRT$XLB")
1557 #else
1558 #pragma data_seg(".CRT$XLB")
1559 #endif
1560 static void (APIENTRY *dll_callback)(HINSTANCE h, DWORD ul_reason_for_call, PVOID pv) = DllMain;
1561 #ifdef _WIN64
1562 #pragma const_seg()
1563 #else
1564 #pragma data_seg()
1565 #endif
1566
1567 #ifdef _WIN64
1568 #pragma const_seg(".CRT$XTU")
1569 #else
1570 #pragma data_seg(".CRT$XTU")
1571 #endif
1572 static int(*p_process_term)(void) = on_process_term;
1573 #ifdef _WIN64
1574 #pragma const_seg()
1575 #else
1576 #pragma data_seg()
1577 #endif
1578 #endif
1579
1580 #if (defined(C_PGI) || (!defined(C_SUN) && defined(F_INTERFACE_SUN))) && (defined(ARCH_X86) || defined(ARCH_X86_64))
1581 /* Don't call me; this is just work around for PGI / Sun bug */
1582 void gotoblas_dummy_for_PGI(void) {
1583
1584   gotoblas_init();
1585   gotoblas_quit();
1586
1587 #if 0
1588   asm ("\t.section\t.ctors,\"aw\",@progbits; .align 8; .quad gotoblas_init; .section .text");
1589   asm ("\t.section\t.dtors,\"aw\",@progbits; .align 8; .quad gotoblas_quit; .section .text");
1590 #else
1591   asm (".section .init,\"ax\"; call gotoblas_init@PLT; .section .text");
1592   asm (".section .fini,\"ax\"; call gotoblas_quit@PLT; .section .text");
1593 #endif
1594 }
1595 #endif
1596
1597 #else
1598 #include <errno.h>
1599
1600 #ifdef OS_WINDOWS
1601 #define ALLOC_WINDOWS
1602 #ifndef MEM_LARGE_PAGES
1603 #define MEM_LARGE_PAGES  0x20000000
1604 #endif
1605 #else
1606 #define ALLOC_MMAP
1607 #define ALLOC_MALLOC
1608 #endif
1609
1610 #include <stdlib.h>
1611 #include <stdio.h>
1612 #include <fcntl.h>
1613
1614 #ifndef OS_WINDOWS
1615 #include <sys/mman.h>
1616 #ifndef NO_SYSV_IPC
1617 #include <sys/shm.h>
1618 #endif
1619 #include <sys/ipc.h>
1620 #endif
1621
1622 #include <sys/types.h>
1623
1624 #ifdef OS_LINUX
1625 #include <sys/sysinfo.h>
1626 #include <sched.h>
1627 #include <errno.h>
1628 #include <linux/unistd.h>
1629 #include <sys/syscall.h>
1630 #include <sys/time.h>
1631 #include <sys/resource.h>
1632 #endif
1633
1634 #if defined(OS_FREEBSD) || defined(OS_DARWIN)
1635 #include <sys/sysctl.h>
1636 #include <sys/resource.h>
1637 #endif
1638
1639 #if defined(OS_WINDOWS) && (defined(__MINGW32__) || defined(__MINGW64__))
1640 #include <conio.h>
1641 #undef  printf
1642 #define printf  _cprintf
1643 #endif
1644
1645 #ifdef OS_LINUX
1646
1647 #ifndef MPOL_PREFERRED
1648 #define MPOL_PREFERRED  1
1649 #endif
1650
1651 #endif
1652
1653 #if (defined(PPC440) || !defined(OS_LINUX) || defined(HPL)) && !defined(NO_WARMUP)
1654 #define NO_WARMUP
1655 #endif
1656
1657 #ifndef SHM_HUGETLB
1658 #define SHM_HUGETLB 04000
1659 #endif
1660
1661 #ifndef FIXED_PAGESIZE
1662 #define FIXED_PAGESIZE 4096
1663 #endif
1664
1665 #define BITMASK(a, b, c) ((((a) >> (b)) & (c)))
1666
1667 #if defined(_MSC_VER) && !defined(__clang__)
1668 #define CONSTRUCTOR __cdecl
1669 #define DESTRUCTOR __cdecl
1670 #elif (defined(OS_DARWIN) || defined(OS_SUNOS)) && defined(C_GCC)
1671 #define CONSTRUCTOR     __attribute__ ((constructor))
1672 #define DESTRUCTOR      __attribute__ ((destructor))
1673 #else
1674 #define CONSTRUCTOR     __attribute__ ((constructor(101)))
1675 #define DESTRUCTOR      __attribute__ ((destructor(101)))
1676 #endif
1677
1678 #ifdef DYNAMIC_ARCH
1679 gotoblas_t *gotoblas = NULL;
1680 #endif
1681 extern void openblas_warning(int verbose, const char * msg);
1682
1683 #ifndef SMP
1684
1685 #define blas_cpu_number 1
1686 #define blas_num_threads 1
1687
1688 /* Dummy Function */
1689 int  goto_get_num_procs  (void) { return 1;};
1690 void goto_set_num_threads(int num_threads) {};
1691
1692 #else
1693
1694 #if defined(OS_LINUX) || defined(OS_SUNOS) || defined(OS_NETBSD)
1695 #ifndef NO_AFFINITY
1696 int get_num_procs(void);
1697 #else
1698 int get_num_procs(void) {
1699   static int nums = 0;
1700 cpu_set_t *cpusetp;
1701 size_t size;
1702 int ret;
1703 int i,n;
1704
1705   if (!nums) nums = sysconf(_SC_NPROCESSORS_CONF);
1706 #if !defined(OS_LINUX)
1707      return nums;
1708 #endif
1709
1710 #if !defined(__GLIBC_PREREQ)
1711    return nums;
1712 #else
1713  #if !__GLIBC_PREREQ(2, 3)
1714    return nums;
1715  #endif
1716
1717  #if !__GLIBC_PREREQ(2, 7)
1718   ret = sched_getaffinity(0,sizeof(cpu_set_t), cpusetp);
1719   if (ret!=0) return nums;
1720   n=0;
1721   #if !__GLIBC_PREREQ(2, 6)
1722   for (i=0;i<nums;i++)
1723      if (CPU_ISSET(i,cpusetp)) n++;
1724   nums=n;
1725   #else
1726   nums = CPU_COUNT(sizeof(cpu_set_t),cpusetp);
1727   #endif
1728   return nums;
1729  #else
1730   cpusetp = CPU_ALLOC(nums);
1731   if (cpusetp == NULL) return nums;
1732   size = CPU_ALLOC_SIZE(nums);
1733   ret = sched_getaffinity(0,size,cpusetp);
1734   if (ret!=0) return nums;
1735   nums = CPU_COUNT_S(size,cpusetp);
1736   CPU_FREE(cpusetp);
1737   return nums;
1738  #endif
1739 #endif
1740 }
1741 #endif
1742 #endif
1743
1744 #ifdef OS_ANDROID
1745 int get_num_procs(void) {
1746   static int nums = 0;
1747   if (!nums) nums = sysconf(_SC_NPROCESSORS_CONF);
1748   return nums;
1749 }
1750 #endif
1751         
1752 #ifdef OS_HAIKU
1753 int get_num_procs(void) {
1754   static int nums = 0;
1755   if (!nums) nums = sysconf(_SC_NPROCESSORS_CONF);
1756   return nums;
1757 }
1758 #endif
1759
1760 #ifdef OS_AIX
1761 int get_num_procs(void) {
1762   static int nums = 0;
1763   if (!nums) nums = sysconf(_SC_NPROCESSORS_CONF);
1764   return nums;
1765 }
1766 #endif
1767
1768 #ifdef OS_WINDOWS
1769
1770 int get_num_procs(void) {
1771
1772   static int nums = 0;
1773
1774   if (nums == 0) {
1775
1776     SYSTEM_INFO sysinfo;
1777
1778     GetSystemInfo(&sysinfo);
1779
1780     nums = sysinfo.dwNumberOfProcessors;
1781   }
1782
1783   return nums;
1784 }
1785
1786 #endif
1787
1788 #if defined(OS_FREEBSD)
1789
1790 int get_num_procs(void) {
1791
1792   static int nums = 0;
1793
1794   int m[2];
1795   size_t len;
1796
1797   if (nums == 0) {
1798     m[0] = CTL_HW;
1799     m[1] = HW_NCPU;
1800     len = sizeof(int);
1801     sysctl(m, 2, &nums, &len, NULL, 0);
1802   }
1803
1804   return nums;
1805 }
1806
1807 #endif
1808
1809 #if defined(OS_DARWIN)
1810 int get_num_procs(void) {
1811   static int nums = 0;
1812   size_t len;
1813   if (nums == 0){
1814     len = sizeof(int);
1815     sysctlbyname("hw.physicalcpu", &nums, &len, NULL, 0);
1816   }
1817   return nums;
1818 }
1819 /*
1820 void set_stack_limit(int limitMB){
1821   int result=0;
1822   struct rlimit rl;
1823   rlim_t StackSize;
1824
1825   StackSize=limitMB*1024*1024;
1826   result=getrlimit(RLIMIT_STACK, &rl);
1827   if(result==0){
1828     if(rl.rlim_cur < StackSize){
1829       rl.rlim_cur=StackSize;
1830       result=setrlimit(RLIMIT_STACK, &rl);
1831       if(result !=0){
1832         fprintf(stderr, "OpenBLAS: set stack limit error =%d\n", result);
1833       }
1834     }
1835   }
1836 }
1837 */
1838 #endif
1839
1840
1841 /*
1842 OpenBLAS uses the numbers of CPU cores in multithreading.
1843 It can be set by openblas_set_num_threads(int num_threads);
1844 */
1845 int blas_cpu_number  = 0;
1846 /*
1847 The numbers of threads in the thread pool.
1848 This value is equal or large than blas_cpu_number. This means some threads are sleep.
1849 */
1850 int blas_num_threads = 0;
1851
1852 int  goto_get_num_procs  (void) {
1853   return blas_cpu_number;
1854 }
1855
1856 void openblas_fork_handler()
1857 {
1858   // This handler shuts down the OpenBLAS-managed PTHREAD pool when OpenBLAS is
1859   // built with "make USE_OPENMP=0".
1860   // Hanging can still happen when OpenBLAS is built against the libgomp
1861   // implementation of OpenMP. The problem is tracked at:
1862   //   http://gcc.gnu.org/bugzilla/show_bug.cgi?id=60035
1863   // In the mean time build with USE_OPENMP=0 or link against another
1864   // implementation of OpenMP.
1865 #if !(defined(OS_WINDOWS) || defined(OS_ANDROID)) && defined(SMP_SERVER)
1866   int err;
1867   err = pthread_atfork ((void (*)(void)) BLASFUNC(blas_thread_shutdown), NULL, NULL);
1868   if(err != 0)
1869     openblas_warning(0, "OpenBLAS Warning ... cannot install fork handler. You may meet hang after fork.\n");
1870 #endif
1871 }
1872
1873 extern int openblas_num_threads_env();
1874 extern int openblas_goto_num_threads_env();
1875 extern int openblas_omp_num_threads_env();
1876
1877 int blas_get_cpu_number(void){
1878 #if defined(OS_LINUX) || defined(OS_WINDOWS) || defined(OS_FREEBSD) || defined(OS_DARWIN) || defined(OS_ANDROID)
1879   int max_num;
1880 #endif
1881   int blas_goto_num   = 0;
1882   int blas_omp_num    = 0;
1883
1884   if (blas_num_threads) return blas_num_threads;
1885
1886 #if defined(OS_LINUX) || defined(OS_WINDOWS) || defined(OS_FREEBSD) || defined(OS_DARWIN) || defined(OS_ANDROID)
1887   max_num = get_num_procs();
1888 #endif
1889
1890   blas_goto_num = 0;
1891 #ifndef USE_OPENMP
1892   blas_goto_num=openblas_num_threads_env();
1893   if (blas_goto_num < 0) blas_goto_num = 0;
1894
1895   if (blas_goto_num == 0) {
1896     blas_goto_num=openblas_goto_num_threads_env();
1897     if (blas_goto_num < 0) blas_goto_num = 0;
1898   }
1899
1900 #endif
1901
1902   blas_omp_num = 0;
1903   blas_omp_num=openblas_omp_num_threads_env();
1904   if (blas_omp_num < 0) blas_omp_num = 0;
1905
1906   if (blas_goto_num > 0) blas_num_threads = blas_goto_num;
1907   else if (blas_omp_num > 0) blas_num_threads = blas_omp_num;
1908   else blas_num_threads = MAX_CPU_NUMBER;
1909
1910 #if defined(OS_LINUX) || defined(OS_WINDOWS) || defined(OS_FREEBSD) || defined(OS_DARWIN) || defined(OS_ANDROID)
1911   if (blas_num_threads > max_num) blas_num_threads = max_num;
1912 #endif
1913
1914   if (blas_num_threads > MAX_CPU_NUMBER) blas_num_threads = MAX_CPU_NUMBER;
1915
1916 #ifdef DEBUG
1917   printf( "Adjusted number of threads : %3d\n", blas_num_threads);
1918 #endif
1919
1920   blas_cpu_number = blas_num_threads;
1921
1922   return blas_num_threads;
1923 }
1924 #endif
1925
1926
1927 int openblas_get_num_procs(void) {
1928 #ifndef SMP
1929   return 1;
1930 #else
1931   return get_num_procs();
1932 #endif
1933 }
1934
1935 int openblas_get_num_threads(void) {
1936 #ifndef SMP
1937   return 1;
1938 #else
1939   // init blas_cpu_number if needed
1940   blas_get_cpu_number();
1941   return blas_cpu_number;
1942 #endif
1943 }
1944
1945 struct release_t {
1946   void *address;
1947   void (*func)(struct release_t *);
1948   long attr;
1949 };
1950
1951 int hugetlb_allocated = 0;
1952
1953 static struct release_t release_info[NUM_BUFFERS];
1954 static int release_pos = 0;
1955
1956 #if defined(OS_LINUX) && !defined(NO_WARMUP)
1957 static int hot_alloc = 0;
1958 #endif
1959
1960 /* Global lock for memory allocation */
1961
1962 #if   defined(USE_PTHREAD_LOCK)
1963 static pthread_mutex_t    alloc_lock = PTHREAD_MUTEX_INITIALIZER;
1964 #elif defined(USE_PTHREAD_SPINLOCK)
1965 static pthread_spinlock_t alloc_lock = 0;
1966 #else
1967 static BLASULONG  alloc_lock = 0UL;
1968 #endif
1969
1970 #ifdef ALLOC_MMAP
1971
1972 static void alloc_mmap_free(struct release_t *release){
1973
1974   if (munmap(release -> address, BUFFER_SIZE)) {
1975     printf("OpenBLAS : munmap failed\n");
1976   }
1977 }
1978
1979
1980
1981 #ifdef NO_WARMUP
1982
1983 static void *alloc_mmap(void *address){
1984   void *map_address;
1985
1986   if (address){
1987     map_address = mmap(address,
1988                        BUFFER_SIZE,
1989                        MMAP_ACCESS, MMAP_POLICY | MAP_FIXED, -1, 0);
1990   } else {
1991     map_address = mmap(address,
1992                        BUFFER_SIZE,
1993                        MMAP_ACCESS, MMAP_POLICY, -1, 0);
1994   }
1995
1996   if (map_address != (void *)-1) {
1997     LOCK_COMMAND(&alloc_lock);
1998     release_info[release_pos].address = map_address;
1999     release_info[release_pos].func    = alloc_mmap_free;
2000     release_pos ++;
2001     UNLOCK_COMMAND(&alloc_lock);
2002   }
2003
2004 #ifdef OS_LINUX
2005   my_mbind(map_address, BUFFER_SIZE, MPOL_PREFERRED, NULL, 0, 0);
2006 #endif
2007
2008   return map_address;
2009 }
2010
2011 #else
2012
2013 #define BENCH_ITERATION 4
2014 #define SCALING         2
2015
2016 static inline BLASULONG run_bench(BLASULONG address, BLASULONG size) {
2017
2018   BLASULONG original, *p;
2019   BLASULONG start, stop, min;
2020   int iter, i, count;
2021
2022   min = (BLASULONG)-1;
2023
2024   original = *(BLASULONG *)(address + size - PAGESIZE);
2025
2026   *(BLASULONG *)(address + size - PAGESIZE) = (BLASULONG)address;
2027
2028   for (iter = 0; iter < BENCH_ITERATION; iter ++ ) {
2029
2030     p = (BLASULONG *)address;
2031
2032     count = size / PAGESIZE;
2033
2034     start = rpcc();
2035
2036     for (i = 0; i < count; i ++) {
2037       p = (BLASULONG *)(*p);
2038     }
2039
2040     stop = rpcc();
2041
2042     if (min > stop - start) min = stop - start;
2043   }
2044
2045   *(BLASULONG *)(address + size - PAGESIZE +  0) = original;
2046   *(BLASULONG *)(address + size - PAGESIZE +  8) = (BLASULONG)p;
2047
2048   return min;
2049 }
2050
2051 static void *alloc_mmap(void *address){
2052   void *map_address, *best_address;
2053   BLASULONG best, start, current;
2054   BLASULONG allocsize;
2055
2056   if (address){
2057     /* Just give up use advanced operation */
2058     map_address = mmap(address, BUFFER_SIZE, MMAP_ACCESS, MMAP_POLICY | MAP_FIXED, -1, 0);
2059
2060 #ifdef OS_LINUX
2061     my_mbind(map_address, BUFFER_SIZE, MPOL_PREFERRED, NULL, 0, 0);
2062 #endif
2063
2064   } else {
2065 #if defined(OS_LINUX) && !defined(NO_WARMUP)
2066     if (hot_alloc == 0) {
2067       map_address = mmap(NULL, BUFFER_SIZE, MMAP_ACCESS, MMAP_POLICY, -1, 0);
2068
2069 #ifdef OS_LINUX
2070       my_mbind(map_address, BUFFER_SIZE, MPOL_PREFERRED, NULL, 0, 0);
2071 #endif
2072
2073     } else {
2074 #endif
2075
2076       map_address = mmap(NULL, BUFFER_SIZE * SCALING,
2077                          MMAP_ACCESS, MMAP_POLICY, -1, 0);
2078
2079       if (map_address != (void *)-1) {
2080
2081 #ifdef OS_LINUX
2082 #ifdef DEBUG
2083                   int ret=0;
2084                   ret=my_mbind(map_address, BUFFER_SIZE * SCALING, MPOL_PREFERRED, NULL, 0, 0);
2085                   if(ret==-1){
2086                           int errsv=errno;
2087                           perror("OpenBLAS alloc_mmap:");
2088                           printf("error code=%d,\tmap_address=%lx\n",errsv,map_address);
2089                   }
2090
2091 #else
2092                   my_mbind(map_address, BUFFER_SIZE * SCALING, MPOL_PREFERRED, NULL, 0, 0);
2093 #endif
2094 #endif
2095
2096
2097         allocsize = DGEMM_P * DGEMM_Q * sizeof(double);
2098
2099         start   = (BLASULONG)map_address;
2100         current = (SCALING - 1) * BUFFER_SIZE;
2101
2102         while(current > 0) {
2103           *(BLASLONG *)start = (BLASLONG)start + PAGESIZE;
2104           start += PAGESIZE;
2105           current -= PAGESIZE;
2106         }
2107
2108         *(BLASLONG *)(start - PAGESIZE) = (BLASULONG)map_address;
2109
2110         start = (BLASULONG)map_address;
2111
2112         best = (BLASULONG)-1;
2113         best_address = map_address;
2114
2115         while ((start + allocsize  < (BLASULONG)map_address + (SCALING - 1) * BUFFER_SIZE)) {
2116
2117           current = run_bench(start, allocsize);
2118
2119           if (best > current) {
2120             best = current;
2121             best_address = (void *)start;
2122           }
2123
2124           start += PAGESIZE;
2125
2126         }
2127
2128       if ((BLASULONG)best_address > (BLASULONG)map_address)
2129         munmap(map_address,  (BLASULONG)best_address - (BLASULONG)map_address);
2130
2131       munmap((void *)((BLASULONG)best_address + BUFFER_SIZE), (SCALING - 1) * BUFFER_SIZE + (BLASULONG)map_address - (BLASULONG)best_address);
2132
2133       map_address = best_address;
2134
2135 #if defined(OS_LINUX) && !defined(NO_WARMUP)
2136       hot_alloc = 2;
2137 #endif
2138       }
2139     }
2140 #if defined(OS_LINUX) && !defined(NO_WARMUP)
2141   }
2142 #endif
2143   LOCK_COMMAND(&alloc_lock);
2144
2145   if (map_address != (void *)-1) {
2146     release_info[release_pos].address = map_address;
2147     release_info[release_pos].func    = alloc_mmap_free;
2148     release_pos ++;
2149   }
2150   UNLOCK_COMMAND(&alloc_lock);
2151
2152   return map_address;
2153 }
2154
2155 #endif
2156
2157 #endif
2158
2159
2160 #ifdef ALLOC_MALLOC
2161
2162 static void alloc_malloc_free(struct release_t *release){
2163
2164   free(release -> address);
2165
2166 }
2167
2168 static void *alloc_malloc(void *address){
2169
2170   void *map_address;
2171
2172   map_address = (void *)malloc(BUFFER_SIZE + FIXED_PAGESIZE);
2173
2174   if (map_address == (void *)NULL) map_address = (void *)-1;
2175
2176   if (map_address != (void *)-1) {
2177     release_info[release_pos].address = map_address;
2178     release_info[release_pos].func    = alloc_malloc_free;
2179     release_pos ++;
2180   }
2181
2182   return map_address;
2183
2184 }
2185
2186 #endif
2187
2188 #ifdef ALLOC_QALLOC
2189
2190 void *qalloc(int flags, size_t bytes);
2191 void *qfree (void *address);
2192
2193 #define QNONCACHE 0x1
2194 #define QCOMMS    0x2
2195 #define QFAST     0x4
2196
2197 static void alloc_qalloc_free(struct release_t *release){
2198
2199   qfree(release -> address);
2200
2201 }
2202
2203 static void *alloc_qalloc(void *address){
2204   void *map_address;
2205
2206   map_address = (void *)qalloc(QCOMMS | QFAST, BUFFER_SIZE + FIXED_PAGESIZE);
2207
2208   if (map_address == (void *)NULL) map_address = (void *)-1;
2209
2210   if (map_address != (void *)-1) {
2211     release_info[release_pos].address = map_address;
2212     release_info[release_pos].func    = alloc_qalloc_free;
2213     release_pos ++;
2214   }
2215
2216   return (void *)(((BLASULONG)map_address + FIXED_PAGESIZE - 1) & ~(FIXED_PAGESIZE - 1));
2217 }
2218
2219 #endif
2220
2221 #ifdef ALLOC_WINDOWS
2222
2223 static void alloc_windows_free(struct release_t *release){
2224
2225   VirtualFree(release -> address, BUFFER_SIZE, MEM_DECOMMIT);
2226
2227 }
2228
2229 static void *alloc_windows(void *address){
2230   void *map_address;
2231
2232   map_address  = VirtualAlloc(address,
2233                               BUFFER_SIZE,
2234                               MEM_RESERVE | MEM_COMMIT,
2235                               PAGE_READWRITE);
2236
2237   if (map_address == (void *)NULL) map_address = (void *)-1;
2238
2239   if (map_address != (void *)-1) {
2240     release_info[release_pos].address = map_address;
2241     release_info[release_pos].func    = alloc_windows_free;
2242     release_pos ++;
2243   }
2244
2245   return map_address;
2246 }
2247
2248 #endif
2249
2250 #ifdef ALLOC_DEVICEDRIVER
2251 #ifndef DEVICEDRIVER_NAME
2252 #define DEVICEDRIVER_NAME "/dev/mapper"
2253 #endif
2254
2255 static void alloc_devicedirver_free(struct release_t *release){
2256
2257   if (munmap(release -> address, BUFFER_SIZE)) {
2258     printf("OpenBLAS : Bugphysarea unmap failed.\n");
2259   }
2260
2261   if (close(release -> attr)) {
2262     printf("OpenBLAS : Bugphysarea close failed.\n");
2263   }
2264
2265 }
2266
2267 static void *alloc_devicedirver(void *address){
2268
2269   int fd;
2270   void *map_address;
2271
2272   if ((fd = open(DEVICEDRIVER_NAME, O_RDWR | O_SYNC)) < 0) {
2273
2274     return (void *)-1;
2275
2276   }
2277
2278   map_address = mmap(address, BUFFER_SIZE,
2279                      PROT_READ | PROT_WRITE,
2280                      MAP_FILE | MAP_SHARED,
2281                      fd, 0);
2282
2283   if (map_address != (void *)-1) {
2284     release_info[release_pos].address = map_address;
2285     release_info[release_pos].attr    = fd;
2286     release_info[release_pos].func    = alloc_devicedirver_free;
2287     release_pos ++;
2288   }
2289
2290   return map_address;
2291 }
2292
2293 #endif
2294
2295 #ifdef ALLOC_SHM
2296
2297 static void alloc_shm_free(struct release_t *release){
2298
2299   if (shmdt(release -> address)) {
2300     printf("OpenBLAS : Shared memory unmap failed.\n");
2301     }
2302 }
2303
2304 static void *alloc_shm(void *address){
2305   void *map_address;
2306   int shmid;
2307
2308   shmid = shmget(IPC_PRIVATE, BUFFER_SIZE,IPC_CREAT | 0600);
2309
2310   map_address = (void *)shmat(shmid, address, 0);
2311
2312   if (map_address != (void *)-1){
2313
2314 #ifdef OS_LINUX
2315     my_mbind(map_address, BUFFER_SIZE, MPOL_PREFERRED, NULL, 0, 0);
2316 #endif
2317
2318     shmctl(shmid, IPC_RMID, 0);
2319
2320     release_info[release_pos].address = map_address;
2321     release_info[release_pos].attr    = shmid;
2322     release_info[release_pos].func    = alloc_shm_free;
2323     release_pos ++;
2324   }
2325
2326   return map_address;
2327 }
2328
2329 #if defined OS_LINUX  || defined OS_AIX  || defined __sun__  || defined OS_WINDOWS
2330
2331 static void alloc_hugetlb_free(struct release_t *release){
2332
2333 #if defined(OS_LINUX) || defined(OS_AIX)
2334   if (shmdt(release -> address)) {
2335     printf("OpenBLAS : Hugepage unmap failed.\n");
2336   }
2337 #endif
2338
2339 #ifdef __sun__
2340
2341   munmap(release -> address, BUFFER_SIZE);
2342
2343 #endif
2344
2345 #ifdef OS_WINDOWS
2346
2347   VirtualFree(release -> address, BUFFER_SIZE, MEM_LARGE_PAGES | MEM_DECOMMIT);
2348
2349 #endif
2350
2351 }
2352
2353 static void *alloc_hugetlb(void *address){
2354
2355   void *map_address = (void *)-1;
2356
2357 #if defined(OS_LINUX) || defined(OS_AIX)
2358   int shmid;
2359
2360   shmid = shmget(IPC_PRIVATE, BUFFER_SIZE,
2361 #ifdef OS_LINUX
2362                  SHM_HUGETLB |
2363 #endif
2364 #ifdef OS_AIX
2365                  SHM_LGPAGE | SHM_PIN |
2366 #endif
2367                  IPC_CREAT | SHM_R | SHM_W);
2368
2369   if (shmid != -1) {
2370     map_address = (void *)shmat(shmid, address, SHM_RND);
2371
2372 #ifdef OS_LINUX
2373     my_mbind(map_address, BUFFER_SIZE, MPOL_PREFERRED, NULL, 0, 0);
2374 #endif
2375
2376     if (map_address != (void *)-1){
2377       shmctl(shmid, IPC_RMID, 0);
2378     }
2379   }
2380 #endif
2381
2382 #ifdef __sun__
2383   struct memcntl_mha mha;
2384
2385   mha.mha_cmd = MHA_MAPSIZE_BSSBRK;
2386   mha.mha_flags = 0;
2387   mha.mha_pagesize = HUGE_PAGESIZE;
2388   memcntl(NULL, 0, MC_HAT_ADVISE, (char *)&mha, 0, 0);
2389
2390   map_address = (BLASULONG)memalign(HUGE_PAGESIZE, BUFFER_SIZE);
2391 #endif
2392
2393 #ifdef OS_WINDOWS
2394
2395   HANDLE hToken;
2396   TOKEN_PRIVILEGES tp;
2397
2398   if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken) != TRUE) return (void *) -1;
2399
2400   tp.PrivilegeCount = 1;
2401   tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
2402   
2403   if (LookupPrivilegeValue(NULL, SE_LOCK_MEMORY_NAME, &tp.Privileges[0].Luid) != TRUE) {
2404       CloseHandle(hToken);
2405       return (void*)-1;
2406   }
2407
2408   if (AdjustTokenPrivileges(hToken, FALSE, &tp, 0, NULL, NULL) != TRUE) {
2409       CloseHandle(hToken);
2410       return (void*)-1;
2411   }
2412
2413   map_address  = (void *)VirtualAlloc(address,
2414                                       BUFFER_SIZE,
2415                                       MEM_LARGE_PAGES | MEM_RESERVE | MEM_COMMIT,
2416                                       PAGE_READWRITE);
2417
2418   tp.Privileges[0].Attributes = 0;
2419   AdjustTokenPrivileges(hToken, FALSE, &tp, 0, NULL, NULL);
2420
2421   if (map_address == (void *)NULL) map_address = (void *)-1;
2422
2423 #endif
2424
2425   if (map_address != (void *)-1){
2426     release_info[release_pos].address = map_address;
2427     release_info[release_pos].func    = alloc_hugetlb_free;
2428     release_pos ++;
2429   }
2430
2431   return map_address;
2432 }
2433 #endif
2434
2435 #endif
2436
2437 #ifdef  ALLOC_HUGETLBFILE
2438
2439 static int hugetlb_pid = 0;
2440
2441 static void alloc_hugetlbfile_free(struct release_t *release){
2442
2443   if (munmap(release -> address, BUFFER_SIZE)) {
2444     printf("OpenBLAS : HugeTLBfs unmap failed.\n");
2445   }
2446
2447   if (close(release -> attr)) {
2448     printf("OpenBLAS : HugeTLBfs close failed.\n");
2449   }
2450 }
2451
2452 static void *alloc_hugetlbfile(void *address){
2453
2454   void *map_address = (void *)-1;
2455   int fd;
2456   char filename[64];
2457
2458   if (!hugetlb_pid) hugetlb_pid = getpid();
2459
2460   sprintf(filename, "%s/gotoblas.%d", HUGETLB_FILE_NAME, hugetlb_pid);
2461
2462   if ((fd = open(filename, O_RDWR | O_CREAT, 0700)) < 0) {
2463     return (void *)-1;
2464   }
2465
2466   unlink(filename);
2467
2468   map_address = mmap(address, BUFFER_SIZE,
2469                      PROT_READ | PROT_WRITE,
2470                      MAP_SHARED,
2471                      fd, 0);
2472
2473   if (map_address != (void *)-1) {
2474     release_info[release_pos].address = map_address;
2475     release_info[release_pos].attr    = fd;
2476     release_info[release_pos].func    = alloc_hugetlbfile_free;
2477     release_pos ++;
2478   }
2479
2480   return map_address;
2481 }
2482 #endif
2483
2484
2485 #ifdef SEEK_ADDRESS
2486 static BLASULONG base_address      = 0UL;
2487 #else
2488 static BLASULONG base_address      = BASE_ADDRESS;
2489 #endif
2490
2491 static volatile struct {
2492   BLASULONG lock;
2493   void *addr;
2494 #if defined(WHEREAMI) && !defined(USE_OPENMP)
2495   int   pos;
2496 #endif
2497   int used;
2498 #ifndef __64BIT__
2499   char dummy[48];
2500 #else
2501   char dummy[40];
2502 #endif
2503
2504 } memory[NUM_BUFFERS];
2505
2506 static int memory_initialized = 0;
2507
2508 /*       Memory allocation routine           */
2509 /* procpos ... indicates where it comes from */
2510 /*                0 : Level 3 functions      */
2511 /*                1 : Level 2 functions      */
2512 /*                2 : Thread                 */
2513
2514 void *blas_memory_alloc(int procpos){
2515
2516   int position;
2517 #if defined(WHEREAMI) && !defined(USE_OPENMP)
2518   int mypos;
2519 #endif
2520
2521   void *map_address;
2522
2523   void *(*memoryalloc[])(void *address) = {
2524 #ifdef ALLOC_DEVICEDRIVER
2525     alloc_devicedirver,
2526 #endif
2527 /* Hugetlb implicitly assumes ALLOC_SHM */
2528 #ifdef ALLOC_SHM
2529     alloc_shm,
2530 #endif
2531 #if ((defined ALLOC_SHM) && (defined OS_LINUX  || defined OS_AIX  || defined __sun__  || defined OS_WINDOWS))
2532     alloc_hugetlb,
2533 #endif
2534 #ifdef ALLOC_MMAP
2535     alloc_mmap,
2536 #endif
2537 #ifdef ALLOC_QALLOC
2538     alloc_qalloc,
2539 #endif
2540 #ifdef ALLOC_WINDOWS
2541     alloc_windows,
2542 #endif
2543 #ifdef ALLOC_MALLOC
2544     alloc_malloc,
2545 #endif
2546     NULL,
2547   };
2548   void *(**func)(void *address);
2549   LOCK_COMMAND(&alloc_lock);
2550
2551   if (!memory_initialized) {
2552
2553 #if defined(WHEREAMI) && !defined(USE_OPENMP)
2554     for (position = 0; position < NUM_BUFFERS; position ++){
2555       memory[position].addr   = (void *)0;
2556       memory[position].pos    = -1;
2557       memory[position].used   = 0;
2558       memory[position].lock   = 0;
2559     }
2560 #endif
2561
2562 #ifdef DYNAMIC_ARCH
2563     gotoblas_dynamic_init();
2564 #endif
2565
2566 #if defined(SMP) && defined(OS_LINUX) && !defined(NO_AFFINITY)
2567     gotoblas_affinity_init();
2568 #endif
2569
2570 #ifdef SMP
2571     if (!blas_num_threads) blas_cpu_number = blas_get_cpu_number();
2572 #endif
2573
2574 #if defined(ARCH_X86) || defined(ARCH_X86_64) || defined(ARCH_IA64) || defined(ARCH_MIPS64) || defined(ARCH_ARM64)
2575 #ifndef DYNAMIC_ARCH
2576     blas_set_parameter();
2577 #endif
2578 #endif
2579
2580     memory_initialized = 1;
2581
2582   }
2583   UNLOCK_COMMAND(&alloc_lock);
2584
2585 #ifdef DEBUG
2586   printf("Alloc Start ...\n");
2587 #endif
2588
2589 /* #if defined(WHEREAMI) && !defined(USE_OPENMP)
2590
2591   mypos = WhereAmI();
2592
2593   position = mypos;
2594   while (position >= NUM_BUFFERS) position >>= 1;
2595
2596   do {
2597     if (!memory[position].used && (memory[position].pos == mypos)) {
2598       LOCK_COMMAND(&alloc_lock);
2599 //      blas_lock(&memory[position].lock);
2600
2601       if (!memory[position].used) goto allocation;
2602
2603       UNLOCK_COMMAND(&alloc_lock);
2604 //      blas_unlock(&memory[position].lock);
2605     }
2606
2607     position ++;
2608
2609   } while (position < NUM_BUFFERS);
2610
2611
2612 #endif */
2613
2614   position = 0;
2615
2616   LOCK_COMMAND(&alloc_lock);
2617   do {
2618 /*    if (!memory[position].used) { */
2619 /*      blas_lock(&memory[position].lock);*/
2620
2621       if (!memory[position].used) goto allocation;
2622       
2623 /*      blas_unlock(&memory[position].lock);*/
2624 /*    } */
2625
2626     position ++;
2627
2628   } while (position < NUM_BUFFERS);
2629   UNLOCK_COMMAND(&alloc_lock);
2630
2631   goto error;
2632
2633   allocation :
2634
2635 #ifdef DEBUG
2636   printf("  Position -> %d\n", position);
2637 #endif
2638
2639   memory[position].used = 1;
2640
2641   UNLOCK_COMMAND(&alloc_lock);
2642 /*  blas_unlock(&memory[position].lock);*/
2643
2644   if (!memory[position].addr) {
2645     do {
2646 #ifdef DEBUG
2647       printf("Allocation Start : %lx\n", base_address);
2648 #endif
2649
2650       map_address = (void *)-1;
2651
2652       func = &memoryalloc[0];
2653
2654       while ((func != NULL) && (map_address == (void *) -1)) {
2655
2656         map_address = (*func)((void *)base_address);
2657
2658 #ifdef ALLOC_DEVICEDRIVER
2659         if ((*func ==  alloc_devicedirver) && (map_address == (void *)-1)) {
2660             fprintf(stderr, "OpenBLAS Warning ... Physically contigous allocation was failed.\n");
2661         }
2662 #endif
2663
2664 #ifdef ALLOC_HUGETLBFILE
2665         if ((*func == alloc_hugetlbfile) && (map_address == (void *)-1)) {
2666 #ifndef OS_WINDOWS
2667             fprintf(stderr, "OpenBLAS Warning ... HugeTLB(File) allocation was failed.\n");
2668 #endif
2669         }
2670 #endif
2671
2672 #if (defined ALLOC_SHM) && (defined OS_LINUX  || defined OS_AIX  || defined __sun__  || defined OS_WINDOWS)
2673         if ((*func == alloc_hugetlb) && (map_address != (void *)-1)) hugetlb_allocated = 1;
2674 #endif
2675
2676         func ++;
2677       }
2678
2679 #ifdef DEBUG
2680       printf("  Success -> %08lx\n", map_address);
2681 #endif
2682       if (((BLASLONG) map_address) == -1) base_address = 0UL;
2683
2684       if (base_address) base_address += BUFFER_SIZE + FIXED_PAGESIZE;
2685
2686     } while ((BLASLONG)map_address == -1);
2687
2688     LOCK_COMMAND(&alloc_lock);
2689     memory[position].addr = map_address;
2690     UNLOCK_COMMAND(&alloc_lock);
2691
2692 #ifdef DEBUG
2693     printf("  Mapping Succeeded. %p(%d)\n", (void *)memory[position].addr, position);
2694 #endif
2695   }
2696
2697 #if defined(WHEREAMI) && !defined(USE_OPENMP)
2698
2699   if (memory[position].pos == -1) memory[position].pos = mypos;
2700
2701 #endif
2702
2703 #ifdef DYNAMIC_ARCH
2704
2705   if (memory_initialized == 1) {
2706
2707     LOCK_COMMAND(&alloc_lock);
2708
2709     if (memory_initialized == 1) {
2710
2711       if (!gotoblas) gotoblas_dynamic_init();
2712
2713       memory_initialized = 2;
2714     }
2715
2716     UNLOCK_COMMAND(&alloc_lock);
2717
2718   }
2719 #endif
2720
2721
2722 #ifdef DEBUG
2723   printf("Mapped   : %p  %3d\n\n",
2724           (void *)memory[position].addr, position);
2725 #endif
2726
2727   return (void *)memory[position].addr;
2728
2729  error:
2730   printf("BLAS : Program is Terminated. Because you tried to allocate too many memory regions.\n");
2731
2732   return NULL;
2733 }
2734
2735 void blas_memory_free(void *free_area){
2736
2737   int position;
2738
2739 #ifdef DEBUG
2740   printf("Unmapped Start : %p ...\n", free_area);
2741 #endif
2742
2743   position = 0;
2744   LOCK_COMMAND(&alloc_lock);
2745
2746   while ((position < NUM_BUFFERS) && (memory[position].addr != free_area))
2747     position++;
2748
2749   if (memory[position].addr != free_area) goto error;
2750
2751 #ifdef DEBUG
2752   printf("  Position : %d\n", position);
2753 #endif
2754
2755   // arm: ensure all writes are finished before other thread takes this memory
2756   WMB;
2757
2758   memory[position].used = 0;
2759   UNLOCK_COMMAND(&alloc_lock);
2760
2761 #ifdef DEBUG
2762   printf("Unmap Succeeded.\n\n");
2763 #endif
2764
2765   return;
2766
2767  error:
2768   printf("BLAS : Bad memory unallocation! : %4d  %p\n", position,  free_area);
2769
2770 #ifdef DEBUG
2771   for (position = 0; position < NUM_BUFFERS; position++)
2772     printf("%4ld  %p : %d\n", position, memory[position].addr, memory[position].used);
2773 #endif
2774   UNLOCK_COMMAND(&alloc_lock);
2775
2776   return;
2777 }
2778
2779 void *blas_memory_alloc_nolock(int unused) {
2780   void *map_address;
2781   map_address = (void *)malloc(BUFFER_SIZE + FIXED_PAGESIZE);
2782   return map_address;
2783 }
2784
2785 void blas_memory_free_nolock(void * map_address) {
2786   free(map_address);
2787 }
2788
2789 void blas_shutdown(void){
2790
2791   int pos;
2792
2793 #ifdef SMP
2794   BLASFUNC(blas_thread_shutdown)();
2795 #endif
2796
2797   LOCK_COMMAND(&alloc_lock);
2798
2799   for (pos = 0; pos < release_pos; pos ++) {
2800     release_info[pos].func(&release_info[pos]);
2801   }
2802
2803 #ifdef SEEK_ADDRESS
2804   base_address      = 0UL;
2805 #else
2806   base_address      = BASE_ADDRESS;
2807 #endif
2808
2809   for (pos = 0; pos < NUM_BUFFERS; pos ++){
2810     memory[pos].addr   = (void *)0;
2811     memory[pos].used   = 0;
2812 #if defined(WHEREAMI) && !defined(USE_OPENMP)
2813     memory[pos].pos    = -1;
2814 #endif
2815     memory[pos].lock   = 0;
2816   }
2817
2818   UNLOCK_COMMAND(&alloc_lock);
2819
2820   return;
2821 }
2822
2823 #if defined(OS_LINUX) && !defined(NO_WARMUP)
2824
2825 #ifdef SMP
2826 #if   defined(USE_PTHREAD_LOCK)
2827 static pthread_mutex_t    init_lock = PTHREAD_MUTEX_INITIALIZER;
2828 #elif defined(USE_PTHREAD_SPINLOCK)
2829 static pthread_spinlock_t init_lock = 0;
2830 #else
2831 static BLASULONG   init_lock = 0UL;
2832 #endif
2833 #endif
2834
2835 static void _touch_memory(blas_arg_t *arg, BLASLONG *range_m, BLASLONG *range_n,
2836                           void *sa, void *sb, BLASLONG pos) {
2837
2838 #if !defined(ARCH_POWER) && !defined(ARCH_SPARC)
2839
2840   size_t size;
2841   BLASULONG buffer;
2842
2843   size   = BUFFER_SIZE - PAGESIZE;
2844   buffer = (BLASULONG)sa + GEMM_OFFSET_A;
2845
2846 #if defined(OS_LINUX) && !defined(NO_WARMUP)
2847     if (hot_alloc != 2) {
2848 #endif
2849
2850 #ifdef SMP
2851   LOCK_COMMAND(&init_lock);
2852 #endif
2853
2854   while (size > 0) {
2855     *(int *)buffer = size;
2856     buffer  += PAGESIZE;
2857     size    -= PAGESIZE;
2858   }
2859
2860 #ifdef SMP
2861   UNLOCK_COMMAND(&init_lock);
2862 #endif
2863
2864   size = MIN((BUFFER_SIZE - PAGESIZE), L2_SIZE);
2865   buffer = (BLASULONG)sa + GEMM_OFFSET_A;
2866
2867   while (size > 0) {
2868     *(int *)buffer = size;
2869     buffer  += 64;
2870     size    -= 64;
2871   }
2872
2873 #if defined(OS_LINUX) && !defined(NO_WARMUP)
2874     }
2875 #endif
2876
2877 #endif
2878 }
2879
2880 #ifdef SMP
2881
2882 static void _init_thread_memory(void *buffer) {
2883
2884   blas_queue_t queue[MAX_CPU_NUMBER];
2885   int num_cpu;
2886
2887   for (num_cpu = 0; num_cpu < blas_num_threads; num_cpu++) {
2888
2889     blas_queue_init(&queue[num_cpu]);
2890     queue[num_cpu].mode    = BLAS_DOUBLE | BLAS_REAL;
2891     queue[num_cpu].routine = &_touch_memory;
2892     queue[num_cpu].args    = NULL;
2893     queue[num_cpu].next    = &queue[num_cpu + 1];
2894   }
2895
2896   queue[num_cpu - 1].next = NULL;
2897   queue[0].sa = buffer;
2898
2899   exec_blas(num_cpu, queue);
2900
2901 }
2902 #endif
2903
2904 static void gotoblas_memory_init(void) {
2905
2906   void *buffer;
2907
2908   hot_alloc = 1;
2909
2910   buffer = (void *)blas_memory_alloc(0);
2911
2912 #ifdef SMP
2913   if (blas_cpu_number == 0) blas_get_cpu_number();
2914 #ifdef SMP_SERVER
2915   if (blas_server_avail == 0) blas_thread_init();
2916 #endif
2917
2918   _init_thread_memory((void *)((BLASULONG)buffer + GEMM_OFFSET_A));
2919
2920 #else
2921
2922   _touch_memory(NULL, NULL, NULL, (void *)((BLASULONG)buffer + GEMM_OFFSET_A), NULL, 0);
2923
2924 #endif
2925
2926   blas_memory_free(buffer);
2927 }
2928 #endif
2929
2930 /* Initialization for all function; this function should be called before main */
2931
2932 static int gotoblas_initialized = 0;
2933 extern void openblas_read_env();
2934
2935 void CONSTRUCTOR gotoblas_init(void) {
2936
2937   if (gotoblas_initialized) return;
2938
2939 #ifdef SMP
2940   openblas_fork_handler();
2941 #endif
2942
2943   openblas_read_env();
2944
2945 #ifdef PROFILE
2946    moncontrol (0);
2947 #endif
2948
2949 #ifdef DYNAMIC_ARCH
2950    gotoblas_dynamic_init();
2951 #endif
2952
2953 #if defined(SMP) && defined(OS_LINUX) && !defined(NO_AFFINITY)
2954    gotoblas_affinity_init();
2955 #endif
2956
2957 #if defined(OS_LINUX) && !defined(NO_WARMUP)
2958    gotoblas_memory_init();
2959 #endif
2960
2961 //#if defined(OS_LINUX)
2962 #if 0
2963    struct rlimit curlimit;
2964    if ( getrlimit(RLIMIT_STACK, &curlimit ) == 0 )
2965    {
2966         if ( curlimit.rlim_cur != curlimit.rlim_max )
2967         {
2968                 curlimit.rlim_cur = curlimit.rlim_max;
2969                 setrlimit(RLIMIT_STACK, &curlimit);
2970         }
2971    }
2972 #endif
2973
2974 #ifdef SMP
2975   if (blas_cpu_number == 0) blas_get_cpu_number();
2976 #ifdef SMP_SERVER
2977   if (blas_server_avail == 0) blas_thread_init();
2978 #endif
2979 #endif
2980
2981 #ifdef FUNCTION_PROFILE
2982    gotoblas_profile_init();
2983 #endif
2984
2985    gotoblas_initialized = 1;
2986
2987 #ifdef PROFILE
2988    moncontrol (1);
2989 #endif
2990
2991 }
2992
2993 void DESTRUCTOR gotoblas_quit(void) {
2994
2995   if (gotoblas_initialized == 0) return;
2996
2997   blas_shutdown();
2998
2999 #ifdef PROFILE
3000    moncontrol (0);
3001 #endif
3002
3003 #ifdef FUNCTION_PROFILE
3004    gotoblas_profile_quit();
3005 #endif
3006
3007 #if defined(SMP) && defined(OS_LINUX) && !defined(NO_AFFINITY)
3008    gotoblas_affinity_quit();
3009 #endif
3010
3011 #ifdef DYNAMIC_ARCH
3012    gotoblas_dynamic_quit();
3013 #endif
3014
3015    gotoblas_initialized = 0;
3016
3017 #ifdef PROFILE
3018    moncontrol (1);
3019 #endif
3020 }
3021
3022 #if defined(_MSC_VER) && !defined(__clang__)
3023 BOOL APIENTRY DllMain(HMODULE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved)
3024 {
3025   switch (ul_reason_for_call)
3026   {
3027     case DLL_PROCESS_ATTACH:
3028       gotoblas_init();
3029       break;
3030     case DLL_THREAD_ATTACH:
3031       break;
3032     case DLL_THREAD_DETACH:
3033       break;
3034     case DLL_PROCESS_DETACH:
3035       gotoblas_quit();
3036       break;
3037     default:
3038       break;
3039   }
3040   return TRUE;
3041 }
3042
3043 /*
3044   This is to allow static linking.
3045   Code adapted from Google performance tools:
3046   https://gperftools.googlecode.com/git-history/perftools-1.0/src/windows/port.cc
3047   Reference:
3048   https://sourceware.org/ml/pthreads-win32/2008/msg00028.html
3049   http://ci.boost.org/svn-trac/browser/trunk/libs/thread/src/win32/tss_pe.cpp
3050 */
3051 static int on_process_term(void)
3052 {
3053         gotoblas_quit();
3054         return 0;
3055 }
3056 #ifdef _WIN64
3057 #pragma comment(linker, "/INCLUDE:_tls_used")
3058 #else
3059 #pragma comment(linker, "/INCLUDE:__tls_used")
3060 #endif
3061
3062 #ifdef _WIN64
3063 #pragma const_seg(".CRT$XLB")
3064 #else
3065 #pragma data_seg(".CRT$XLB")
3066 #endif
3067 static void (APIENTRY *dll_callback)(HINSTANCE h, DWORD ul_reason_for_call, PVOID pv) = DllMain;
3068 #ifdef _WIN64
3069 #pragma const_seg()
3070 #else
3071 #pragma data_seg()
3072 #endif
3073
3074 #ifdef _WIN64
3075 #pragma const_seg(".CRT$XTU")
3076 #else
3077 #pragma data_seg(".CRT$XTU")
3078 #endif
3079 static int(*p_process_term)(void) = on_process_term;
3080 #ifdef _WIN64
3081 #pragma const_seg()
3082 #else
3083 #pragma data_seg()
3084 #endif
3085 #endif
3086
3087 #if (defined(C_PGI) || (!defined(C_SUN) && defined(F_INTERFACE_SUN))) && (defined(ARCH_X86) || defined(ARCH_X86_64))
3088 /* Don't call me; this is just work around for PGI / Sun bug */
3089 void gotoblas_dummy_for_PGI(void) {
3090
3091   gotoblas_init();
3092   gotoblas_quit();
3093
3094 #if 0
3095   asm ("\t.section\t.ctors,\"aw\",@progbits; .align 8; .quad gotoblas_init; .section .text");
3096   asm ("\t.section\t.dtors,\"aw\",@progbits; .align 8; .quad gotoblas_quit; .section .text");
3097 #else
3098   asm (".section .init,\"ax\"; call gotoblas_init@PLT; .section .text");
3099   asm (".section .fini,\"ax\"; call gotoblas_quit@PLT; .section .text");
3100 #endif
3101 }
3102 #endif
3103
3104 #endif