File: Memory_buffer_thread.h

package info (click to toggle)
ergo 3.8.2-1.1
  • links: PTS, VCS
  • area: main
  • in suites: sid, trixie
  • size: 17,568 kB
  • sloc: cpp: 94,763; ansic: 17,785; sh: 10,701; makefile: 1,403; yacc: 127; lex: 116; awk: 23
file content (133 lines) | stat: -rw-r--r-- 3,810 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
/* Ergo, version 3.8.2, a program for linear scaling electronic structure
 * calculations.
 * Copyright (C) 2023 Elias Rudberg, Emanuel H. Rubensson, Pawel Salek,
 * and Anastasia Kruchinina.
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * Primary academic reference:
 * Ergo: An open-source program for linear-scaling electronic structure
 * calculations,
 * Elias Rudberg, Emanuel H. Rubensson, Pawel Salek, and Anastasia
 * Kruchinina,
 * SoftwareX 7, 107 (2018),
 * <http://dx.doi.org/10.1016/j.softx.2018.03.005>
 * 
 * For further information about Ergo, see <http://www.ergoscf.org>.
 */

/** @file Memory_buffer_thread.h

    \brief Code for managing aligned memory buffers, used if SSE
    intrinsics enabled.
*/

#ifndef MEMORY_BUFFER_THREAD_HEADER
#define MEMORY_BUFFER_THREAD_HEADER

/* We need to include config.h to get the USE_SSE_INTRINSICS flag. */
#include "config.h"

/* This file is only used if USE_SSE_INTRINSICS is defined. */
#ifdef USE_SSE_INTRINSICS

#include <iostream> // for bad_alloc
#include <stdexcept>
#include <vector>
#include <emmintrin.h>
#ifdef __SSE3__
#include <pmmintrin.h>
#endif
#ifdef _OPENMP
#include <omp.h>
#endif

namespace mat{
  
  class Memory_aligned {
  protected:
    inline void * operator new (size_t s) {
      void * p = _mm_malloc (s, 16);
      if (p == NULL)
	throw std::bad_alloc();
      else
	return p;
    }
 
    inline void * operator new[] (size_t s) {
      void * p = _mm_malloc (s, 16);
      if (p == NULL)
	throw std::bad_alloc();
      else
	return p;
    }

    inline void operator delete (void * p) {
      _mm_free(p);
    }

    inline void operator delete[] (void * p) {
      _mm_free(p);
    }
  };

  class Memory_buffer_thread : public Memory_aligned {
    // Hidden stuff
  private:
    static void create();
    static Memory_buffer_thread* ptr_to_instance;
    // All values allowed for char - 
    // may be important for double checked locking pattern in instance()
    static volatile char ptr_to_instance_is_valid; 
    static unsigned int bufSize;
    Memory_buffer_thread(Memory_buffer_thread const &);
  protected:
    Memory_buffer_thread() {} // No instances of Memory_buffer_thread ever!
  
  public:
    static Memory_buffer_thread& instance();
    template<typename T>
      void get_buffer(size_t size, T* & buffer) const {
      if (sizeof(T) * size > bufSize)
	throw std::runtime_error("In Memory_buffer_thread::get_buffer : "
				 "Allocated buffer smaller than requested "
				 "buffer size");
      int threadID = 0;
#ifdef _OPENMP
      for (int ind = 0; ind <= omp_get_level(); ind++) {
	int tmp = omp_get_ancestor_thread_num(ind);
	threadID = threadID > tmp ? threadID : tmp;
      }
#endif
      if (buffers.empty())
	throw std::runtime_error("In Memory_buffer_thread::get_buffer : "
				 "buffers empty!");
      if ((unsigned)threadID >= buffers.size())
	throw std::runtime_error("In Memory_buffer_thread::get_buffer : "
				 "thread id larger than number of buffers");
      buffer = (T*)buffers[threadID];
    }
    void init_buffers(unsigned int const nThreads);
    ~Memory_buffer_thread();
  private:
    std::vector<char*> buffers;
  
  };
 

} // end namespace mat

#endif

#endif