Haiku supporting patches
[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 #include <errno.h>
76
77 #if defined(OS_WINDOWS) && !defined(OS_CYGWIN_NT)
78 #define ALLOC_WINDOWS
79 #ifndef MEM_LARGE_PAGES
80 #define MEM_LARGE_PAGES  0x20000000
81 #endif
82 #else
83 #define ALLOC_MMAP
84 #define ALLOC_MALLOC
85 #endif
86
87 #include <stdlib.h>
88 #include <stdio.h>
89 #include <fcntl.h>
90
91 #if !defined(OS_WINDOWS) || defined(OS_CYGWIN_NT)
92 #include <sys/mman.h>
93 #ifndef NO_SYSV_IPC
94 #include <sys/shm.h>
95 #endif
96 #include <sys/ipc.h>
97 #endif
98
99 #include <sys/types.h>
100
101 #ifdef OS_LINUX
102 #include <sys/sysinfo.h>
103 #include <sched.h>
104 #include <errno.h>
105 #include <linux/unistd.h>
106 #include <sys/syscall.h>
107 #include <sys/time.h>
108 #include <sys/resource.h>
109 #endif
110
111 #ifdef OS_HAIKU
112 #include <unistd.h>
113 #endif
114
115 #if defined(OS_FREEBSD) || defined(OS_OPENBSD) || defined(OS_DRAGONFLY) || defined(OS_DARWIN)
116 #include <sys/sysctl.h>
117 #include <sys/resource.h>
118 #endif
119
120 #if defined(OS_WINDOWS) && (defined(__MINGW32__) || defined(__MINGW64__))
121 #include <conio.h>
122 #undef  printf
123 #define printf  _cprintf
124 #endif
125
126 #ifdef OS_LINUX
127
128 #ifndef MPOL_PREFERRED
129 #define MPOL_PREFERRED  1
130 #endif
131
132 #endif
133
134 #if (defined(PPC440) || !defined(OS_LINUX) || defined(HPL)) && !defined(NO_WARMUP)
135 #define NO_WARMUP
136 #endif
137
138 #ifndef SHM_HUGETLB
139 #define SHM_HUGETLB 04000
140 #endif
141
142 #ifndef FIXED_PAGESIZE
143 #define FIXED_PAGESIZE 4096
144 #endif
145
146 #ifndef BUFFERS_PER_THREAD
147 #ifdef USE_OPENMP_UNUSED
148 #define BUFFERS_PER_THREAD (MAX_CPU_NUMBER * 2 * MAX_PARALLEL_NUMBER)
149 #else
150 #define BUFFERS_PER_THREAD NUM_BUFFERS
151 #endif
152 #endif
153
154 #define BITMASK(a, b, c) ((((a) >> (b)) & (c)))
155
156 #if defined(_MSC_VER) && !defined(__clang__)
157 #define CONSTRUCTOR __cdecl
158 #define DESTRUCTOR __cdecl
159 #elif (defined(OS_DARWIN) || defined(OS_SUNOS)) && defined(C_GCC)
160 #define CONSTRUCTOR     __attribute__ ((constructor))
161 #define DESTRUCTOR      __attribute__ ((destructor))
162 #elif __GNUC__ && INIT_PRIORITY && ((GCC_VERSION >= 40300) || (CLANG_VERSION >= 20900))
163 #define CONSTRUCTOR     __attribute__ ((constructor(101)))
164 #define DESTRUCTOR      __attribute__ ((destructor(101)))
165 #else
166 #define CONSTRUCTOR     __attribute__ ((constructor))
167 #define DESTRUCTOR      __attribute__ ((destructor))
168 #endif
169
170 #ifdef DYNAMIC_ARCH
171 gotoblas_t *gotoblas = NULL;
172 #endif
173 extern void openblas_warning(int verbose, const char * msg);
174
175 #ifndef SMP
176
177 #define blas_cpu_number 1
178 #define blas_num_threads 1
179
180 /* Dummy Function */
181 int  goto_get_num_procs  (void) { return 1;};
182 void goto_set_num_threads(int num_threads) {};
183
184 #else
185
186 #if defined(OS_LINUX) || defined(OS_SUNOS) || defined(OS_NETBSD)
187 #ifndef NO_AFFINITY
188 int get_num_procs(void);
189 #else
190 int get_num_procs(void) {
191   static int nums = 0;
192 cpu_set_t *cpusetp;
193 size_t size;
194 int ret;
195 int i,n;
196
197   if (!nums) nums = sysconf(_SC_NPROCESSORS_CONF);
198 #if !defined(OS_LINUX)
199      return nums;
200 #endif
201
202 #if !defined(__GLIBC_PREREQ)
203    return nums;
204 #else
205  #if !__GLIBC_PREREQ(2, 3)
206    return nums;
207  #endif
208
209  #if !__GLIBC_PREREQ(2, 7)
210   ret = sched_getaffinity(0,sizeof(cpu_set_t), cpusetp);
211   if (ret!=0) return nums;
212   n=0;
213   #if !__GLIBC_PREREQ(2, 6)
214   for (i=0;i<nums;i++)
215      if (CPU_ISSET(i,cpusetp)) n++;
216   nums=n;
217   #else
218   nums = CPU_COUNT(sizeof(cpu_set_t),cpusetp);
219   #endif
220   return nums;
221  #else
222   cpusetp = CPU_ALLOC(nums);
223   if (cpusetp == NULL) return nums;
224   size = CPU_ALLOC_SIZE(nums);
225   ret = sched_getaffinity(0,size,cpusetp);
226   if (ret!=0) return nums;
227   ret = CPU_COUNT_S(size,cpusetp);
228   if (ret > 0 && ret < nums) nums = ret;
229   CPU_FREE(cpusetp);
230   return nums;
231  #endif
232 #endif
233 }
234 #endif
235 #endif
236
237 #ifdef OS_ANDROID
238 int get_num_procs(void) {
239   static int nums = 0;
240   if (!nums) nums = sysconf(_SC_NPROCESSORS_CONF);
241   return nums;
242 }
243 #endif
244
245 #ifdef OS_HAIKU
246 int get_num_procs(void) {
247   static int nums = 0;
248   if (!nums) nums = sysconf(_SC_NPROCESSORS_CONF);
249   return nums;
250 }
251 #endif
252
253 #ifdef OS_WINDOWS
254
255 int get_num_procs(void) {
256
257   static int nums = 0;
258
259   if (nums == 0) {
260
261     SYSTEM_INFO sysinfo;
262
263     GetSystemInfo(&sysinfo);
264
265     nums = sysinfo.dwNumberOfProcessors;
266   }
267
268   return nums;
269 }
270
271 #endif
272
273 #if defined(OS_FREEBSD) || defined(OS_OPENBSD) || defined(OS_DRAGONFLY)
274
275 int get_num_procs(void) {
276
277   static int nums = 0;
278
279   int m[2];
280   size_t len;
281
282   if (nums == 0) {
283     m[0] = CTL_HW;
284     m[1] = HW_NCPU;
285     len = sizeof(int);
286     sysctl(m, 2, &nums, &len, NULL, 0);
287   }
288
289   return nums;
290 }
291
292 #endif
293
294 #if defined(OS_DARWIN)
295 int get_num_procs(void) {
296   static int nums = 0;
297   size_t len;
298   if (nums == 0){
299     len = sizeof(int);
300     sysctlbyname("hw.physicalcpu", &nums, &len, NULL, 0);
301   }
302   return nums;
303 }
304 /*
305 void set_stack_limit(int limitMB){
306   int result=0;
307   struct rlimit rl;
308   rlim_t StackSize;
309
310   StackSize=limitMB*1024*1024;
311   result=getrlimit(RLIMIT_STACK, &rl);
312   if(result==0){
313     if(rl.rlim_cur < StackSize){
314       rl.rlim_cur=StackSize;
315       result=setrlimit(RLIMIT_STACK, &rl);
316       if(result !=0){
317         fprintf(stderr, "OpenBLAS: set stack limit error =%d\n", result);
318       }
319     }
320   }
321 }
322 */
323 #endif
324
325
326 /*
327 OpenBLAS uses the numbers of CPU cores in multithreading.
328 It can be set by openblas_set_num_threads(int num_threads);
329 */
330 int blas_cpu_number  = 0;
331 /*
332 The numbers of threads in the thread pool.
333 This value is equal or large than blas_cpu_number. This means some threads are sleep.
334 */
335 int blas_num_threads = 0;
336
337 int  goto_get_num_procs  (void) {
338   return blas_cpu_number;
339 }
340
341 static void blas_memory_init();
342
343 void openblas_fork_handler()
344 {
345   // This handler shuts down the OpenBLAS-managed PTHREAD pool when OpenBLAS is
346   // built with "make USE_OPENMP=0".
347   // Hanging can still happen when OpenBLAS is built against the libgomp
348   // implementation of OpenMP. The problem is tracked at:
349   //   http://gcc.gnu.org/bugzilla/show_bug.cgi?id=60035
350   // In the mean time build with USE_OPENMP=0 or link against another
351   // implementation of OpenMP.
352 #if !((defined(OS_WINDOWS) && !defined(OS_CYGWIN_NT)) || defined(OS_ANDROID)) && defined(SMP_SERVER)
353   int err;
354   err = pthread_atfork ((void (*)(void)) BLASFUNC(blas_thread_shutdown), NULL, blas_memory_init);
355   if(err != 0)
356     openblas_warning(0, "OpenBLAS Warning ... cannot install fork handler. You may meet hang after fork.\n");
357 #endif
358 }
359
360 extern int openblas_num_threads_env();
361 extern int openblas_goto_num_threads_env();
362 extern int openblas_omp_num_threads_env();
363
364 int blas_get_cpu_number(void){
365 #if defined(OS_LINUX) || defined(OS_WINDOWS) || defined(OS_FREEBSD) || defined(OS_OPENBSD) || defined(OS_DRAGONFLY) || defined(OS_DARWIN) || defined(OS_ANDROID)
366   int max_num;
367 #endif
368   int blas_goto_num   = 0;
369   int blas_omp_num    = 0;
370
371   if (blas_num_threads) return blas_num_threads;
372
373 #if defined(OS_LINUX) || defined(OS_WINDOWS) || defined(OS_FREEBSD) || defined(OS_OPENBSD) || defined(OS_DRAGONFLY) || defined(OS_DARWIN) || defined(OS_ANDROID)
374   max_num = get_num_procs();
375 #endif
376
377   // blas_goto_num = 0;
378 #ifndef USE_OPENMP_UNUSED
379   blas_goto_num=openblas_num_threads_env();
380   if (blas_goto_num < 0) blas_goto_num = 0;
381
382   if (blas_goto_num == 0) {
383     blas_goto_num=openblas_goto_num_threads_env();
384     if (blas_goto_num < 0) blas_goto_num = 0;
385   }
386
387 #endif
388
389   // blas_omp_num = 0;
390   blas_omp_num=openblas_omp_num_threads_env();
391   if (blas_omp_num < 0) blas_omp_num = 0;
392
393   if (blas_goto_num > 0) blas_num_threads = blas_goto_num;
394   else if (blas_omp_num > 0) blas_num_threads = blas_omp_num;
395   else blas_num_threads = MAX_CPU_NUMBER;
396
397 #if defined(OS_LINUX) || defined(OS_WINDOWS) || defined(OS_FREEBSD) || defined(OS_OPENBSD) || defined(OS_DRAGONFLY) || defined(OS_DARWIN) || defined(OS_ANDROID)
398   if (blas_num_threads > max_num) blas_num_threads = max_num;
399 #endif
400
401   if (blas_num_threads > MAX_CPU_NUMBER) blas_num_threads = MAX_CPU_NUMBER;
402
403 #ifdef DEBUG
404   printf( "Adjusted number of threads : %3d\n", blas_num_threads);
405 #endif
406
407   blas_cpu_number = blas_num_threads;
408
409   return blas_num_threads;
410 }
411 #endif
412
413
414 int openblas_get_num_procs(void) {
415 #ifndef SMP
416   return 1;
417 #else
418   return get_num_procs();
419 #endif
420 }
421
422 int openblas_get_num_threads(void) {
423 #ifndef SMP
424   return 1;
425 #else
426   // init blas_cpu_number if needed
427   blas_get_cpu_number();
428   return blas_cpu_number;
429 #endif
430 }
431
432 int hugetlb_allocated = 0;
433
434 #if defined(OS_WINDOWS)
435 #define THREAD_LOCAL __declspec(thread)
436 #define LIKELY_ONE(x) (x)
437 #else
438 #define THREAD_LOCAL __thread
439 #define LIKELY_ONE(x) (__builtin_expect(x, 1))
440 #endif
441
442 /* Stores information about the allocation and how to release it */
443 struct alloc_t {
444   /* Whether this allocation is being used */
445   int used;
446   /* Any special attributes needed when releasing this allocation */
447   int attr;
448   /* Function that can properly release this memory */
449   void (*release_func)(struct alloc_t *);
450   /* Pad to 64-byte alignment */
451   char pad[64 - 2 * sizeof(int) - sizeof(void(*))];
452 };
453
454 /* Convenience macros for storing release funcs */
455 #define STORE_RELEASE_FUNC(address, func)                   \
456   if (address != (void *)-1) {                              \
457     struct alloc_t *alloc_info = (struct alloc_t *)address; \
458     alloc_info->release_func = func;                        \
459   }
460
461 #define STORE_RELEASE_FUNC_WITH_ATTR(address, func, attr)   \
462   if (address != (void *)-1) {                              \
463     struct alloc_t *alloc_info = (struct alloc_t *)address; \
464     alloc_info->release_func = func;                        \
465     alloc_info->attr = attr;                                \
466   }
467
468 /* The number of bytes that will be allocated for each buffer. When allocating
469    memory, we store an alloc_t followed by the actual buffer memory. This means
470    that each allocation always has its associated alloc_t, without the need
471    for an auxiliary tracking structure. */
472 static const int allocation_block_size = BUFFER_SIZE + sizeof(struct alloc_t);
473
474 /* Clang supports TLS from version 2.8 */
475 #if defined(__clang__) && __clang_major__ > 2 || \
476     (__clang_minor__ == 2 || __clang_minor__ == 8)
477 #define HAS_COMPILER_TLS
478 #endif
479
480 /* GCC supports TLS from version 4.1 */
481 #if !defined(__clang__) && defined(__GNUC__) && \
482     (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1))
483 #define HAS_COMPILER_TLS
484 #endif
485
486 /* MSVC supports TLS from version 2005 */
487 #if defined(_MSC_VER) && _MSC_VER >= 1400
488 #define HAS_COMPILER_TLS
489 #endif
490
491 /* Versions of XCode before 8 did not properly support TLS */
492 #if defined(__apple_build_version__) && __apple_build_version__ < 8000042
493 #undef HAS_COMPILER_TLS
494 #endif
495
496 /* Android NDK's before version 12b did not support TLS */
497 #if defined(__ANDROID__) && defined(__clang__)
498 #if __has_include(<android/ndk-version.h>)
499 #include <android/ndk-version.h>
500 #endif
501 #if defined(__ANDROID__) && defined(__clang__) && defined(__NDK_MAJOR__) && \
502     defined(__NDK_MINOR__) &&                                               \
503     ((__NDK_MAJOR__ < 12) || ((__NDK_MAJOR__ == 12) && (__NDK_MINOR__ < 1)))
504 #undef HAS_COMPILER_TLS
505 #endif
506 #endif
507
508 /* Holds pointers to allocated memory */
509 #if defined(SMP) && !defined(USE_OPENMP_UNUSED)
510 /* This is the number of threads than can be spawned by the server, which is the
511    server plus the number of threads in the thread pool */
512 #  define MAX_ALLOCATING_THREADS MAX_CPU_NUMBER * 2 * MAX_PARALLEL_NUMBER * 2
513 static int next_memory_table_pos = 0;
514 #  if defined(HAS_COMPILER_TLS)
515 /* Use compiler generated thread-local-storage */
516 static int THREAD_LOCAL local_memory_table_pos = 0;
517 #  else
518 /* Use system-dependent thread-local-storage */
519 #    if defined(OS_WINDOWS)
520 static DWORD local_storage_key;
521 #    else
522 static pthread_key_t local_storage_key;
523 #    endif /* defined(OS_WINDOWS) */
524 #  endif /* defined(HAS_COMPILER_TLS) */
525 #else
526 /* There is only one allocating thread when in single-threaded mode and when using OpenMP */
527 #  define MAX_ALLOCATING_THREADS 1
528 #endif /* defined(SMP) && !defined(USE_OPENMP) */
529 static struct alloc_t * local_memory_table[MAX_ALLOCATING_THREADS][BUFFERS_PER_THREAD];
530
531 #if defined(OS_LINUX) && !defined(NO_WARMUP)
532 static int hot_alloc = 0;
533 #endif
534
535 /* Global lock for memory allocation */
536
537 #if   defined(USE_PTHREAD_LOCK)
538 static pthread_mutex_t    alloc_lock = PTHREAD_MUTEX_INITIALIZER;
539 #elif defined(USE_PTHREAD_SPINLOCK)
540 static pthread_spinlock_t alloc_lock = 0;
541 #else
542 static BLASULONG  alloc_lock = 0UL;
543 #endif
544
545 /* Returns a pointer to the start of the per-thread memory allocation data */
546 static __inline struct alloc_t ** get_memory_table() {
547 #if defined(SMP) && !defined(USE_OPENMP_UNUSED)
548 #  if !defined(HAS_COMPILER_TLS)
549 #    if defined(OS_WINDOWS)
550   int local_memory_table_pos = (int)::TlsGetValue(local_storage_key);
551 #    else
552   int local_memory_table_pos = (int)pthread_getspecific(local_storage_key);
553 #    endif /* defined(OS_WINDOWS) */
554 #  endif /* !defined(HAS_COMPILER_TLS) */
555   if (!local_memory_table_pos) {
556     LOCK_COMMAND(&alloc_lock);
557     local_memory_table_pos = next_memory_table_pos++;
558     if (next_memory_table_pos > MAX_ALLOCATING_THREADS)
559       printf("OpenBLAS : Program will terminate because you tried to start too many threads.\n");
560     UNLOCK_COMMAND(&alloc_lock);
561 #  if !defined(HAS_COMPILER_TLS)
562 #    if defined(OS_WINDOWS)
563     ::TlsSetValue(local_storage_key, (void*)local_memory_table_pos);
564 #    else
565     pthread_setspecific(local_storage_key, (void*)local_memory_table_pos);
566 #    endif /* defined(OS_WINDOWS) */
567 #  endif /* !defined(HAS_COMPILER_TLS) */
568   }
569   return local_memory_table[local_memory_table_pos];
570 #else
571   return local_memory_table[0];
572 #endif /* defined(SMP) && !defined(USE_OPENMP) */
573 }
574
575 #ifdef ALLOC_MMAP
576
577 static void alloc_mmap_free(struct alloc_t *alloc_info){
578
579   if (munmap(alloc_info, allocation_block_size)) {
580     printf("OpenBLAS : munmap failed\n");
581   }
582 }
583
584
585
586 #ifdef NO_WARMUP
587
588 static void *alloc_mmap(void *address){
589   void *map_address;
590
591   if (address){
592     map_address = mmap(address,
593                        allocation_block_size,
594                        MMAP_ACCESS, MMAP_POLICY | MAP_FIXED, -1, 0);
595   } else {
596     map_address = mmap(address,
597                        allocation_block_size,
598                        MMAP_ACCESS, MMAP_POLICY, -1, 0);
599   }
600
601   STORE_RELEASE_FUNC(map_address, alloc_mmap_free);
602
603 #ifdef OS_LINUX
604   my_mbind(map_address, allocation_block_size, MPOL_PREFERRED, NULL, 0, 0);
605 #endif
606
607   return map_address;
608 }
609
610 #else
611
612 #define BENCH_ITERATION 4
613 #define SCALING         2
614
615 static inline BLASULONG run_bench(BLASULONG address, BLASULONG size) {
616
617   BLASULONG original, *p;
618   BLASULONG start, stop, min;
619   int iter, i, count;
620
621   min = (BLASULONG)-1;
622
623   original = *(BLASULONG *)(address + size - PAGESIZE);
624
625   *(BLASULONG *)(address + size - PAGESIZE) = (BLASULONG)address;
626
627   for (iter = 0; iter < BENCH_ITERATION; iter ++ ) {
628
629     p = (BLASULONG *)address;
630
631     count = size / PAGESIZE;
632
633     start = rpcc();
634
635     for (i = 0; i < count; i ++) {
636       p = (BLASULONG *)(*p);
637     }
638
639     stop = rpcc();
640
641     if (min > stop - start) min = stop - start;
642   }
643
644   *(BLASULONG *)(address + size - PAGESIZE +  0) = original;
645   *(BLASULONG *)(address + size - PAGESIZE +  8) = (BLASULONG)p;
646
647   return min;
648 }
649
650 static void *alloc_mmap(void *address){
651   void *map_address, *best_address;
652   BLASULONG best, start, current, original;
653   BLASULONG allocsize;
654
655   if (address){
656     /* Just give up use advanced operation */
657     map_address = mmap(address, allocation_block_size, MMAP_ACCESS, MMAP_POLICY | MAP_FIXED, -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 #if defined(OS_LINUX) && !defined(NO_WARMUP)
665     if (hot_alloc == 0) {
666       map_address = mmap(NULL, allocation_block_size, MMAP_ACCESS, MMAP_POLICY, -1, 0);
667
668 #ifdef OS_LINUX
669       my_mbind(map_address, allocation_block_size, MPOL_PREFERRED, NULL, 0, 0);
670 #endif
671
672     } else {
673 #endif
674
675       map_address = mmap(NULL, allocation_block_size * SCALING,
676                          MMAP_ACCESS, MMAP_POLICY, -1, 0);
677
678       if (map_address != (void *)-1) {
679
680 #ifdef OS_LINUX
681 #ifdef DEBUG
682                   int ret=0;
683                   ret=my_mbind(map_address, allocation_block_size * SCALING, MPOL_PREFERRED, NULL, 0, 0);
684                   if(ret==-1){
685                           int errsv=errno;
686                           perror("OpenBLAS alloc_mmap:");
687                           printf("error code=%d,\tmap_address=%lx\n",errsv,map_address);
688                   }
689
690 #else
691                   my_mbind(map_address, allocation_block_size * SCALING, MPOL_PREFERRED, NULL, 0, 0);
692 #endif
693 #endif
694
695
696         allocsize = DGEMM_P * DGEMM_Q * sizeof(double);
697
698         start   = (BLASULONG)map_address;
699         current = (SCALING - 1) * allocation_block_size;
700         original = current;
701
702         while(current > 0 && current <= original) {
703           *(BLASLONG *)start = (BLASLONG)start + PAGESIZE;
704           start += PAGESIZE;
705           current -= PAGESIZE;
706         }
707
708         *(BLASLONG *)(start - PAGESIZE) = (BLASULONG)map_address;
709
710         start = (BLASULONG)map_address;
711
712         best = (BLASULONG)-1;
713         best_address = map_address;
714
715         while ((start + allocsize  < (BLASULONG)map_address + (SCALING - 1) * allocation_block_size)) {
716
717           current = run_bench(start, allocsize);
718
719           if (best > current) {
720             best = current;
721             best_address = (void *)start;
722           }
723
724           start += PAGESIZE;
725
726         }
727
728       if ((BLASULONG)best_address > (BLASULONG)map_address)
729         munmap(map_address,  (BLASULONG)best_address - (BLASULONG)map_address);
730
731       munmap((void *)((BLASULONG)best_address + allocation_block_size), (SCALING - 1) * allocation_block_size + (BLASULONG)map_address - (BLASULONG)best_address);
732
733       map_address = best_address;
734
735 #if defined(OS_LINUX) && !defined(NO_WARMUP)
736       hot_alloc = 2;
737 #endif
738       }
739     }
740 #if defined(OS_LINUX) && !defined(NO_WARMUP)
741   }
742 #endif
743
744   STORE_RELEASE_FUNC(map_address, alloc_mmap_free);
745
746   return map_address;
747 }
748
749 #endif
750
751 #endif
752
753
754 #ifdef ALLOC_MALLOC
755
756 static void alloc_malloc_free(struct alloc_t *alloc_info){
757
758   free(alloc_info);
759
760 }
761
762 static void *alloc_malloc(void *address){
763
764   void *map_address;
765
766   map_address = (void *)malloc(allocation_block_size + FIXED_PAGESIZE);
767
768   if (map_address == (void *)NULL) map_address = (void *)-1;
769
770   STORE_RELEASE_FUNC(map_address, alloc_malloc_free);
771
772   return map_address;
773
774 }
775
776 #endif
777
778 #ifdef ALLOC_QALLOC
779
780 void *qalloc(int flags, size_t bytes);
781 void *qfree (void *address);
782
783 #define QNONCACHE 0x1
784 #define QCOMMS    0x2
785 #define QFAST     0x4
786
787 static void alloc_qalloc_free(struct alloc_t *alloc_info){
788
789   qfree(alloc_info);
790
791 }
792
793 static void *alloc_qalloc(void *address){
794   void *map_address;
795
796   map_address = (void *)qalloc(QCOMMS | QFAST, allocation_block_size + FIXED_PAGESIZE);
797
798   if (map_address == (void *)NULL) map_address = (void *)-1;
799
800   STORE_RELEASE_FUNC(map_address, alloc_qalloc_free);
801
802   return (void *)(((BLASULONG)map_address + FIXED_PAGESIZE - 1) & ~(FIXED_PAGESIZE - 1));
803 }
804
805 #endif
806
807 #ifdef ALLOC_WINDOWS
808
809 static void alloc_windows_free(struct alloc_t *alloc_info){
810
811   VirtualFree(alloc_info, allocation_block_size, MEM_DECOMMIT);
812
813 }
814
815 static void *alloc_windows(void *address){
816   void *map_address;
817
818   map_address  = VirtualAlloc(address,
819                               allocation_block_size,
820                               MEM_RESERVE | MEM_COMMIT,
821                               PAGE_READWRITE);
822
823   if (map_address == (void *)NULL) map_address = (void *)-1;
824
825   STORE_RELEASE_FUNC(map_address, alloc_windows_free);
826
827   return map_address;
828 }
829
830 #endif
831
832 #ifdef ALLOC_DEVICEDRIVER
833 #ifndef DEVICEDRIVER_NAME
834 #define DEVICEDRIVER_NAME "/dev/mapper"
835 #endif
836
837 static void alloc_devicedirver_free(struct alloc_t *alloc_info){
838
839   int attr = alloc_info -> attr;
840   if (munmap(address, allocation_block_size)) {
841     printf("OpenBLAS : Bugphysarea unmap failed.\n");
842   }
843
844   if (close(attr)) {
845     printf("OpenBLAS : Bugphysarea close failed.\n");
846   }
847
848 }
849
850 static void *alloc_devicedirver(void *address){
851
852   int fd;
853   void *map_address;
854
855   if ((fd = open(DEVICEDRIVER_NAME, O_RDWR | O_SYNC)) < 0) {
856
857     return (void *)-1;
858
859   }
860
861   map_address = mmap(address, allocation_block_size,
862                      PROT_READ | PROT_WRITE,
863                      MAP_FILE | MAP_SHARED,
864                      fd, 0);
865
866   STORE_RELEASE_FUNC_WITH_ATTR(map_address, alloc_devicedirver_free, fd);
867
868   return map_address;
869 }
870
871 #endif
872
873 #ifdef ALLOC_SHM
874
875 static void alloc_shm_free(struct alloc_t *alloc_info){
876
877   if (shmdt(alloc_info)) {
878     printf("OpenBLAS : Shared memory unmap failed.\n");
879     }
880 }
881
882 static void *alloc_shm(void *address){
883   void *map_address;
884   int shmid;
885
886   shmid = shmget(IPC_PRIVATE, allocation_block_size,IPC_CREAT | 0600);
887
888   map_address = (void *)shmat(shmid, address, 0);
889
890   if (map_address != (void *)-1){
891
892 #ifdef OS_LINUX
893     my_mbind(map_address, allocation_block_size, MPOL_PREFERRED, NULL, 0, 0);
894 #endif
895
896     shmctl(shmid, IPC_RMID, 0);
897
898     struct alloc_t *alloc_info = (struct alloc_t *)map_address;
899     alloc_info->release_func = alloc_shm_free;
900     alloc_info->attr = shmid;
901   }
902
903   return map_address;
904 }
905
906 #if defined OS_LINUX  || defined OS_AIX  || defined __sun__  || defined OS_WINDOWS
907
908 static void alloc_hugetlb_free(struct alloc_t *alloc_info){
909
910 #if defined(OS_LINUX) || defined(OS_AIX)
911   if (shmdt(alloc_info)) {
912     printf("OpenBLAS : Hugepage unmap failed.\n");
913   }
914 #endif
915
916 #ifdef __sun__
917
918   munmap(alloc_info, allocation_block_size);
919
920 #endif
921
922 #ifdef OS_WINDOWS
923
924   VirtualFree(alloc_info, allocation_block_size, MEM_LARGE_PAGES | MEM_DECOMMIT);
925
926 #endif
927
928 }
929
930 static void *alloc_hugetlb(void *address){
931
932   void *map_address = (void *)-1;
933
934 #if defined(OS_LINUX) || defined(OS_AIX)
935   int shmid;
936
937   shmid = shmget(IPC_PRIVATE, allocation_block_size,
938 #ifdef OS_LINUX
939                  SHM_HUGETLB |
940 #endif
941 #ifdef OS_AIX
942                  SHM_LGPAGE | SHM_PIN |
943 #endif
944                  IPC_CREAT | SHM_R | SHM_W);
945
946   if (shmid != -1) {
947     map_address = (void *)shmat(shmid, address, SHM_RND);
948
949 #ifdef OS_LINUX
950     my_mbind(map_address, allocation_block_size, MPOL_PREFERRED, NULL, 0, 0);
951 #endif
952
953     if (map_address != (void *)-1){
954       shmctl(shmid, IPC_RMID, 0);
955     }
956   }
957 #endif
958
959 #ifdef __sun__
960   struct memcntl_mha mha;
961
962   mha.mha_cmd = MHA_MAPSIZE_BSSBRK;
963   mha.mha_flags = 0;
964   mha.mha_pagesize = HUGE_PAGESIZE;
965   memcntl(NULL, 0, MC_HAT_ADVISE, (char *)&mha, 0, 0);
966
967   map_address = (BLASULONG)memalign(HUGE_PAGESIZE, allocation_block_size);
968 #endif
969
970 #ifdef OS_WINDOWS
971
972   HANDLE hToken;
973   TOKEN_PRIVILEGES tp;
974
975   if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken) != TRUE) return (void *) -1;
976
977   tp.PrivilegeCount = 1;
978   tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
979
980   if (LookupPrivilegeValue(NULL, SE_LOCK_MEMORY_NAME, &tp.Privileges[0].Luid) != TRUE) {
981       CloseHandle(hToken);
982       return (void*)-1;
983   }
984
985   if (AdjustTokenPrivileges(hToken, FALSE, &tp, 0, NULL, NULL) != TRUE) {
986       CloseHandle(hToken);
987       return (void*)-1;
988   }
989
990   map_address  = (void *)VirtualAlloc(address,
991                                       allocation_block_size,
992                                       MEM_LARGE_PAGES | MEM_RESERVE | MEM_COMMIT,
993                                       PAGE_READWRITE);
994
995   tp.Privileges[0].Attributes = 0;
996   AdjustTokenPrivileges(hToken, FALSE, &tp, 0, NULL, NULL);
997
998   if (map_address == (void *)NULL) map_address = (void *)-1;
999
1000 #endif
1001
1002   STORE_RELEASE_FUNC(map_address, alloc_hugetlb_free);
1003
1004   return map_address;
1005 }
1006 #endif
1007
1008 #endif
1009
1010 #ifdef  ALLOC_HUGETLBFILE
1011
1012 static int hugetlb_pid = 0;
1013
1014 static void alloc_hugetlbfile_free(struct alloc_t *alloc_info){
1015
1016   int attr = alloc_info -> attr;
1017   if (munmap(alloc_info, allocation_block_size)) {
1018     printf("OpenBLAS : HugeTLBfs unmap failed.\n");
1019   }
1020
1021   if (close(attr)) {
1022     printf("OpenBLAS : HugeTLBfs close failed.\n");
1023   }
1024 }
1025
1026 static void *alloc_hugetlbfile(void *address){
1027
1028   void *map_address = (void *)-1;
1029   int fd;
1030   char filename[64];
1031
1032   if (!hugetlb_pid) hugetlb_pid = getpid();
1033
1034   sprintf(filename, "%s/gotoblas.%d", HUGETLB_FILE_NAME, hugetlb_pid);
1035
1036   if ((fd = open(filename, O_RDWR | O_CREAT, 0700)) < 0) {
1037     return (void *)-1;
1038   }
1039
1040   unlink(filename);
1041
1042   map_address = mmap(address, allocation_block_size,
1043                      PROT_READ | PROT_WRITE,
1044                      MAP_SHARED,
1045                      fd, 0);
1046
1047   STORE_RELEASE_FUNC_WITH_ATTR(map_address, alloc_hugetlbfile_free, fd);
1048
1049   return map_address;
1050 }
1051 #endif
1052
1053
1054 #ifdef SEEK_ADDRESS
1055 static BLASULONG base_address      = 0UL;
1056 #else
1057 static BLASULONG base_address      = BASE_ADDRESS;
1058 #endif
1059
1060 #if __STDC_VERSION__ >= 201112L
1061 static _Atomic int memory_initialized = 0;
1062 #else
1063 static volatile int memory_initialized = 0;
1064 #endif
1065
1066 /*       Memory allocation routine           */
1067 /* procpos ... indicates where it comes from */
1068 /*                0 : Level 3 functions      */
1069 /*                1 : Level 2 functions      */
1070 /*                2 : Thread                 */
1071
1072 static void blas_memory_init(){
1073 #if defined(SMP) && !defined(USE_OPENMP_UNUSED)
1074   next_memory_table_pos = 0;
1075 #  if !defined(HAS_COMPILER_TLS)
1076 #    if defined(OS_WINDOWS)
1077   local_storage_key = ::TlsAlloc();
1078 #    else
1079   pthread_key_create(&local_storage_key, NULL);
1080 #    endif /* defined(OS_WINDOWS) */
1081 #  endif /* defined(HAS_COMPILER_TLS) */
1082 #endif /* defined(SMP) && !defined(USE_OPENMP) */
1083   memset(local_memory_table, 0, sizeof(local_memory_table));
1084 }
1085
1086 void *blas_memory_alloc(int procpos){
1087
1088   int position;
1089
1090   void *map_address;
1091
1092   void *(*memoryalloc[])(void *address) = {
1093 #ifdef ALLOC_DEVICEDRIVER
1094     alloc_devicedirver,
1095 #endif
1096 /* Hugetlb implicitly assumes ALLOC_SHM */
1097 #ifdef ALLOC_SHM
1098     alloc_shm,
1099 #endif
1100 #if ((defined ALLOC_SHM) && (defined OS_LINUX  || defined OS_AIX  || defined __sun__  || defined OS_WINDOWS))
1101     alloc_hugetlb,
1102 #endif
1103 #ifdef ALLOC_MMAP
1104     alloc_mmap,
1105 #endif
1106 #ifdef ALLOC_QALLOC
1107     alloc_qalloc,
1108 #endif
1109 #ifdef ALLOC_WINDOWS
1110     alloc_windows,
1111 #endif
1112 #ifdef ALLOC_MALLOC
1113     alloc_malloc,
1114 #endif
1115     NULL,
1116   };
1117   void *(**func)(void *address);
1118   struct alloc_t * alloc_info;
1119   struct alloc_t ** alloc_table;
1120
1121   if (!LIKELY_ONE(memory_initialized)) {
1122 #if defined(SMP) && !defined(USE_OPENMP)
1123     /* Only allow a single thread to initialize memory system */
1124     LOCK_COMMAND(&alloc_lock);
1125
1126     if (!memory_initialized) {
1127 #endif
1128       blas_memory_init();
1129 #ifdef DYNAMIC_ARCH
1130       gotoblas_dynamic_init();
1131 #endif
1132
1133 #if defined(SMP) && defined(OS_LINUX) && !defined(NO_AFFINITY)
1134       gotoblas_affinity_init();
1135 #endif
1136
1137 #ifdef SMP
1138       if (!blas_num_threads) blas_cpu_number = blas_get_cpu_number();
1139 #endif
1140
1141 #if defined(ARCH_X86) || defined(ARCH_X86_64) || defined(ARCH_IA64) || defined(ARCH_MIPS64) || defined(ARCH_ARM64)
1142 #ifndef DYNAMIC_ARCH
1143       blas_set_parameter();
1144 #endif
1145 #endif
1146
1147       memory_initialized = 1;
1148
1149 #if defined(SMP) && !defined(USE_OPENMP)
1150     }
1151     UNLOCK_COMMAND(&alloc_lock);
1152 #endif
1153   }
1154
1155 #ifdef DEBUG
1156   printf("Alloc Start ...\n");
1157 #endif
1158
1159   position = 0;
1160   alloc_table = get_memory_table();
1161   do {
1162       if (!alloc_table[position] || !alloc_table[position]->used) goto allocation;
1163     position ++;
1164
1165   } while (position < BUFFERS_PER_THREAD);
1166
1167   goto error;
1168
1169   allocation :
1170
1171 #ifdef DEBUG
1172   printf("  Position -> %d\n", position);
1173 #endif
1174
1175   alloc_info = alloc_table[position];
1176   if (!alloc_info) {
1177     do {
1178 #ifdef DEBUG
1179       printf("Allocation Start : %lx\n", base_address);
1180 #endif
1181
1182       map_address = (void *)-1;
1183
1184       func = &memoryalloc[0];
1185
1186       while ((func != NULL) && (map_address == (void *) -1)) {
1187
1188   map_address = (*func)((void *)base_address);
1189
1190 #ifdef ALLOC_DEVICEDRIVER
1191         if ((*func ==  alloc_devicedirver) && (map_address == (void *)-1)) {
1192             fprintf(stderr, "OpenBLAS Warning ... Physically contiguous allocation failed.\n");
1193         }
1194 #endif
1195
1196 #ifdef ALLOC_HUGETLBFILE
1197         if ((*func == alloc_hugetlbfile) && (map_address == (void *)-1)) {
1198 #ifndef OS_WINDOWS
1199             fprintf(stderr, "OpenBLAS Warning ... HugeTLB(File) allocation failed.\n");
1200 #endif
1201         }
1202 #endif
1203
1204 #if (defined ALLOC_SHM) && (defined OS_LINUX  || defined OS_AIX  || defined __sun__  || defined OS_WINDOWS)
1205         if ((*func == alloc_hugetlb) && (map_address != (void *)-1)) hugetlb_allocated = 1;
1206 #endif
1207
1208         func ++;
1209       }
1210
1211 #ifdef DEBUG
1212       printf("  Success -> %08lx\n", map_address);
1213 #endif
1214       if (((BLASLONG) map_address) == -1) base_address = 0UL;
1215
1216       if (base_address) base_address += allocation_block_size + FIXED_PAGESIZE;
1217
1218     } while ((BLASLONG)map_address == -1);
1219
1220     alloc_table[position] = alloc_info = map_address;
1221
1222 #ifdef DEBUG
1223     printf("  Mapping Succeeded. %p(%d)\n", (void *)alloc_info, position);
1224 #endif
1225   }
1226
1227 #ifdef DEBUG
1228   printf("Mapped   : %p  %3d\n\n", (void *)alloc_info, position);
1229 #endif
1230
1231   alloc_info->used = 1;
1232
1233   return (void *)(((char *)alloc_info) + sizeof(struct alloc_t));
1234
1235  error:
1236   printf("OpenBLAS : Program will terminate because you tried to allocate too many memory regions.\n");
1237
1238   return NULL;
1239 }
1240
1241 void blas_memory_free(void *buffer){
1242 #ifdef DEBUG
1243   int position;
1244   struct alloc_t ** alloc_table;
1245 #endif
1246   /* Since we passed an offset pointer to the caller, get back to the actual allocation */
1247   struct alloc_t *alloc_info = (void *)(((char *)buffer) - sizeof(struct alloc_t));
1248
1249 #ifdef DEBUG
1250   printf("Unmapped Start : %p ...\n", alloc_info);
1251 #endif
1252
1253   alloc_info->used = 0;
1254
1255 #ifdef DEBUG
1256   printf("Unmap Succeeded.\n\n");
1257 #endif
1258
1259   return;
1260
1261 #ifdef DEBUG
1262   alloc_table = get_memory_table();
1263   for (position = 0; position < BUFFERS_PER_THREAD; position++){
1264     if (alloc_table[position]) {
1265       printf("%4ld  %p : %d\n", position, alloc_table[position], alloc_table[position]->used);
1266     }
1267   }
1268 #endif
1269   return;
1270 }
1271
1272 void *blas_memory_alloc_nolock(int unused) {
1273   void *map_address;
1274   map_address = (void *)malloc(BUFFER_SIZE + FIXED_PAGESIZE);
1275   return map_address;
1276 }
1277
1278 void blas_memory_free_nolock(void * map_address) {
1279   free(map_address);
1280 }
1281
1282 void blas_shutdown(void){
1283
1284   int pos, thread;
1285
1286 #ifdef SMP
1287   BLASFUNC(blas_thread_shutdown)();
1288 #endif
1289
1290   for (thread = 0; thread < MAX_ALLOCATING_THREADS; thread ++){
1291     for (pos = 0; pos < BUFFERS_PER_THREAD; pos ++){
1292       struct alloc_t *alloc_info = local_memory_table[thread][pos];
1293       if (alloc_info) {
1294         alloc_info->release_func(alloc_info);
1295         local_memory_table[thread][pos] = (void *)0;
1296       }
1297     }
1298   }
1299
1300 #ifdef SEEK_ADDRESS
1301   base_address      = 0UL;
1302 #else
1303   base_address      = BASE_ADDRESS;
1304 #endif
1305
1306   return;
1307 }
1308
1309 #if defined(OS_LINUX) && !defined(NO_WARMUP)
1310
1311 #ifdef SMP
1312 #if   defined(USE_PTHREAD_LOCK)
1313 static pthread_mutex_t    init_lock = PTHREAD_MUTEX_INITIALIZER;
1314 #elif defined(USE_PTHREAD_SPINLOCK)
1315 static pthread_spinlock_t init_lock = 0;
1316 #else
1317 static BLASULONG   init_lock = 0UL;
1318 #endif
1319 #endif
1320
1321 static void _touch_memory(blas_arg_t *arg, BLASLONG *range_m, BLASLONG *range_n,
1322                           void *sa, void *sb, BLASLONG pos) {
1323
1324 #if !defined(ARCH_POWER) && !defined(ARCH_SPARC)
1325
1326   size_t size;
1327   BLASULONG buffer;
1328
1329   size   = allocation_block_size - PAGESIZE;
1330   buffer = (BLASULONG)sa + GEMM_OFFSET_A;
1331
1332 #if defined(OS_LINUX) && !defined(NO_WARMUP)
1333     if (hot_alloc != 2) {
1334 #endif
1335
1336 #ifdef SMP
1337   LOCK_COMMAND(&init_lock);
1338 #endif
1339
1340   while (size > 0) {
1341     *(int *)buffer = size;
1342     buffer  += PAGESIZE;
1343     size    -= PAGESIZE;
1344   }
1345
1346 #ifdef SMP
1347   UNLOCK_COMMAND(&init_lock);
1348 #endif
1349
1350   size = MIN((allocation_block_size - PAGESIZE), L2_SIZE);
1351   buffer = (BLASULONG)sa + GEMM_OFFSET_A;
1352
1353   while (size > 0) {
1354     *(int *)buffer = size;
1355     buffer  += 64;
1356     size    -= 64;
1357   }
1358
1359 #if defined(OS_LINUX) && !defined(NO_WARMUP)
1360     }
1361 #endif
1362
1363 #endif
1364 }
1365
1366 #ifdef SMP
1367
1368 static void _init_thread_memory(void *buffer) {
1369
1370   blas_queue_t queue[MAX_CPU_NUMBER];
1371   int num_cpu;
1372
1373   for (num_cpu = 0; num_cpu < blas_num_threads; num_cpu++) {
1374
1375     blas_queue_init(&queue[num_cpu]);
1376     queue[num_cpu].mode    = BLAS_DOUBLE | BLAS_REAL;
1377     queue[num_cpu].routine = &_touch_memory;
1378     queue[num_cpu].args    = NULL;
1379     queue[num_cpu].next    = &queue[num_cpu + 1];
1380   }
1381
1382   queue[num_cpu - 1].next = NULL;
1383   queue[0].sa = buffer;
1384
1385   exec_blas(num_cpu, queue);
1386
1387 }
1388 #endif
1389
1390 static void gotoblas_memory_init(void) {
1391
1392   void *buffer;
1393
1394   hot_alloc = 1;
1395
1396   buffer = (void *)blas_memory_alloc(0);
1397
1398 #ifdef SMP
1399   if (blas_cpu_number == 0) blas_get_cpu_number();
1400 #ifdef SMP_SERVER
1401   if (blas_server_avail == 0) blas_thread_init();
1402 #endif
1403
1404   _init_thread_memory((void *)((BLASULONG)buffer + GEMM_OFFSET_A));
1405
1406 #else
1407
1408   _touch_memory(NULL, NULL, NULL, (void *)((BLASULONG)buffer + GEMM_OFFSET_A), NULL, 0);
1409
1410 #endif
1411
1412   blas_memory_free(buffer);
1413 }
1414 #endif
1415
1416 /* Initialization for all function; this function should be called before main */
1417
1418 static int gotoblas_initialized = 0;
1419 extern void openblas_read_env();
1420
1421 void CONSTRUCTOR gotoblas_init(void) {
1422
1423   if (gotoblas_initialized) return;
1424
1425 #ifdef SMP
1426   openblas_fork_handler();
1427 #endif
1428
1429   openblas_read_env();
1430
1431 #ifdef PROFILE
1432    moncontrol (0);
1433 #endif
1434
1435 #ifdef DYNAMIC_ARCH
1436    gotoblas_dynamic_init();
1437 #endif
1438
1439 #if defined(SMP) && defined(OS_LINUX) && !defined(NO_AFFINITY)
1440    gotoblas_affinity_init();
1441 #endif
1442
1443 #if defined(OS_LINUX) && !defined(NO_WARMUP)
1444    gotoblas_memory_init();
1445 #endif
1446
1447 //#if defined(OS_LINUX)
1448 #if 0
1449    struct rlimit curlimit;
1450    if ( getrlimit(RLIMIT_STACK, &curlimit ) == 0 )
1451    {
1452         if ( curlimit.rlim_cur != curlimit.rlim_max )
1453         {
1454                 curlimit.rlim_cur = curlimit.rlim_max;
1455                 setrlimit(RLIMIT_STACK, &curlimit);
1456         }
1457    }
1458 #endif
1459
1460 #ifdef SMP
1461   if (blas_cpu_number == 0) blas_get_cpu_number();
1462 #ifdef SMP_SERVER
1463   if (blas_server_avail == 0) blas_thread_init();
1464 #endif
1465 #endif
1466
1467 #ifdef FUNCTION_PROFILE
1468    gotoblas_profile_init();
1469 #endif
1470
1471    gotoblas_initialized = 1;
1472
1473 #ifdef PROFILE
1474    moncontrol (1);
1475 #endif
1476
1477 }
1478
1479 void DESTRUCTOR gotoblas_quit(void) {
1480
1481   if (gotoblas_initialized == 0) return;
1482
1483   blas_shutdown();
1484
1485 #ifdef PROFILE
1486    moncontrol (0);
1487 #endif
1488
1489 #ifdef FUNCTION_PROFILE
1490    gotoblas_profile_quit();
1491 #endif
1492
1493 #if defined(SMP) && defined(OS_LINUX) && !defined(NO_AFFINITY)
1494    gotoblas_affinity_quit();
1495 #endif
1496
1497 #ifdef DYNAMIC_ARCH
1498    gotoblas_dynamic_quit();
1499 #endif
1500
1501    gotoblas_initialized = 0;
1502
1503 #ifdef PROFILE
1504    moncontrol (1);
1505 #endif
1506 }
1507
1508 #if defined(_MSC_VER) && !defined(__clang__)
1509 BOOL APIENTRY DllMain(HMODULE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved)
1510 {
1511   switch (ul_reason_for_call)
1512   {
1513     case DLL_PROCESS_ATTACH:
1514       gotoblas_init();
1515       break;
1516     case DLL_THREAD_ATTACH:
1517       break;
1518     case DLL_THREAD_DETACH:
1519       break;
1520     case DLL_PROCESS_DETACH:
1521       gotoblas_quit();
1522       break;
1523     default:
1524       break;
1525   }
1526   return TRUE;
1527 }
1528
1529 /*
1530   This is to allow static linking.
1531   Code adapted from Google performance tools:
1532   https://gperftools.googlecode.com/git-history/perftools-1.0/src/windows/port.cc
1533   Reference:
1534   https://sourceware.org/ml/pthreads-win32/2008/msg00028.html
1535   http://ci.boost.org/svn-trac/browser/trunk/libs/thread/src/win32/tss_pe.cpp
1536 */
1537 static int on_process_term(void)
1538 {
1539         gotoblas_quit();
1540         return 0;
1541 }
1542 #ifdef _WIN64
1543 #pragma comment(linker, "/INCLUDE:_tls_used")
1544 #else
1545 #pragma comment(linker, "/INCLUDE:__tls_used")
1546 #endif
1547
1548 #ifdef _WIN64
1549 #pragma const_seg(".CRT$XLB")
1550 #else
1551 #pragma data_seg(".CRT$XLB")
1552 #endif
1553 static void (APIENTRY *dll_callback)(HINSTANCE h, DWORD ul_reason_for_call, PVOID pv) = DllMain;
1554 #ifdef _WIN64
1555 #pragma const_seg()
1556 #else
1557 #pragma data_seg()
1558 #endif
1559
1560 #ifdef _WIN64
1561 #pragma const_seg(".CRT$XTU")
1562 #else
1563 #pragma data_seg(".CRT$XTU")
1564 #endif
1565 static int(*p_process_term)(void) = on_process_term;
1566 #ifdef _WIN64
1567 #pragma const_seg()
1568 #else
1569 #pragma data_seg()
1570 #endif
1571 #endif
1572
1573 #if (defined(C_PGI) || (!defined(C_SUN) && defined(F_INTERFACE_SUN))) && (defined(ARCH_X86) || defined(ARCH_X86_64))
1574 /* Don't call me; this is just work around for PGI / Sun bug */
1575 void gotoblas_dummy_for_PGI(void) {
1576
1577   gotoblas_init();
1578   gotoblas_quit();
1579
1580 #if 0
1581   asm ("\t.section\t.ctors,\"aw\",@progbits; .align 8; .quad gotoblas_init; .section .text");
1582   asm ("\t.section\t.dtors,\"aw\",@progbits; .align 8; .quad gotoblas_quit; .section .text");
1583 #else
1584   asm (".section .init,\"ax\"; call gotoblas_init@PLT; .section .text");
1585   asm (".section .fini,\"ax\"; call gotoblas_quit@PLT; .section .text");
1586 #endif
1587 }
1588 #endif