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
|