Notice to GitKraken users: A vulnerability has been found in the SSH key generation of GitKraken versions 7.6.0 to 8.0.0 (https://www.gitkraken.com/blog/weak-ssh-key-fix). If you use GitKraken and have generated a SSH key using one of these versions, please remove it both from your local workstation and from your LRZ GitLab profile.

21.10.2021, 9:00 - 11:00: Due to updates GitLab may be unavailable for some minutes between 09:00 and 11:00.

Commit ee66aac2 authored by Christian Schulte zu Berge's avatar Christian Schulte zu Berge
Browse files

Merge branch 'memory-pools' into 'development'

Memory pools

See merge request !90
parents cd3297ef 7e1b4414
......@@ -47,27 +47,34 @@ IF (WIN32)
# set debug and release library
IF(CAMPVIS_WIN32)
SET(TBB_LIBRARY_DEBUG "${TbbDirectory}/lib/ia32/${TbbCompilerDirectory}/tbb_debug.lib")
SET(TBB_DLL_DEBUG "${TbbDirectory}/bin/ia32/${TbbCompilerDirectory}/tbb_debug.dll")
SET(TBB_PDB_DEBUG "${TbbDirectory}/bin/ia32/${TbbCompilerDirectory}/tbb_debug.pdb")
SET(TBB_LIBRARY_RELEASE "${TbbDirectory}/lib/ia32/${TbbCompilerDirectory}/tbb.lib")
SET(TBB_DLL_RELEASE "${TbbDirectory}/bin/ia32/${TbbCompilerDirectory}/tbb.dll")
SET(TBB_PDB_RELEASE "${TbbDirectory}/bin/ia32/${TbbCompilerDirectory}/tbb.pdb")
SET(TbbPlatformDirectory "ia32")
ELSEIF(CAMPVIS_WIN64)
SET(TBB_LIBRARY_DEBUG "${TbbDirectory}/lib/intel64/${TbbCompilerDirectory}/tbb_debug.lib")
SET(TBB_DLL_DEBUG "${TbbDirectory}/bin/intel64/${TbbCompilerDirectory}/tbb_debug.dll")
SET(TBB_PDB_DEBUG "${TbbDirectory}/bin/intel64/${TbbCompilerDirectory}/tbb_debug.pdb")
SET(TBB_LIBRARY_RELEASE "${TbbDirectory}/lib/intel64/${TbbCompilerDirectory}/tbb.lib")
SET(TBB_DLL_RELEASE "${TbbDirectory}/bin/intel64/${TbbCompilerDirectory}/tbb.dll")
SET(TBB_PDB_RELEASE "${TbbDirectory}/bin/intel64/${TbbCompilerDirectory}/tbb.pdb")
SET(TbbPlatformDirectory "intel64")
ELSE()
MESSAGE(FATAL_ERROR "Neither CAMPVIS_WIN32 nor CAMPVIS_WIN64 defined!")
ENDIF(CAMPVIS_WIN32)
IF (TBB_LIBRARY_DEBUG AND TBB_LIBRARY_RELEASE)
SET(TBB_LIBRARY_DEBUG "${TbbDirectory}/lib/${TbbPlatformDirectory}/${TbbCompilerDirectory}/tbb_debug.lib")
SET(TBB_DLL_DEBUG "${TbbDirectory}/bin/${TbbPlatformDirectory}/${TbbCompilerDirectory}/tbb_debug.dll")
SET(TBB_PDB_DEBUG "${TbbDirectory}/bin/${TbbPlatformDirectory}/${TbbCompilerDirectory}/tbb_debug.pdb")
SET(TBB_LIBRARY_RELEASE "${TbbDirectory}/lib/${TbbPlatformDirectory}/${TbbCompilerDirectory}/tbb.lib")
SET(TBB_DLL_RELEASE "${TbbDirectory}/bin/${TbbPlatformDirectory}/${TbbCompilerDirectory}/tbb.dll")
SET(TBB_PDB_RELEASE "${TbbDirectory}/bin/${TbbPlatformDirectory}/${TbbCompilerDirectory}/tbb.pdb")
IF(TBB_LIBRARY_DEBUG AND TBB_LIBRARY_RELEASE)
SET(TBB_LIBRARY debug ${TBB_LIBRARY_DEBUG} optimized ${TBB_LIBRARY_RELEASE})
ENDIF(TBB_LIBRARY_DEBUG AND TBB_LIBRARY_RELEASE)
SET(TBB_MALLOC_LIBRARY_DEBUG "${TbbDirectory}/lib/${TbbPlatformDirectory}/${TbbCompilerDirectory}/tbbmalloc_debug.lib")
SET(TBB_MALLOC_DLL_DEBUG "${TbbDirectory}/bin/${TbbPlatformDirectory}/${TbbCompilerDirectory}/tbbmalloc_debug.dll")
SET(TBB_MALLOC_PDB_DEBUG "${TbbDirectory}/bin/${TbbPlatformDirectory}/${TbbCompilerDirectory}/tbbmalloc_debug.pdb")
SET(TBB_MALLOC_LIBRARY_RELEASE "${TbbDirectory}/lib/${TbbPlatformDirectory}/${TbbCompilerDirectory}/tbbmalloc.lib")
SET(TBB_MALLOC_DLL_RELEASE "${TbbDirectory}/bin/${TbbPlatformDirectory}/${TbbCompilerDirectory}/tbbmalloc.dll")
SET(TBB_MALLOC_PDB_RELEASE "${TbbDirectory}/bin/${TbbPlatformDirectory}/${TbbCompilerDirectory}/tbbmalloc.pdb")
IF(TBB_MALLOC_LIBRARY_DEBUG AND TBB_MALLOC_LIBRARY_RELEASE)
SET(TBB_MALLOC_LIBRARY debug ${TBB_MALLOC_LIBRARY_DEBUG} optimized ${TBB_MALLOC_LIBRARY_RELEASE})
ENDIF(TBB_MALLOC_LIBRARY_DEBUG AND TBB_MALLOC_LIBRARY_RELEASE)
SET(TBB_LICENSE_FILE "${TbbDirectory}/COPYING")
ELSE (WIN32)
......@@ -79,10 +86,16 @@ ELSE (WIN32)
)
FIND_LIBRARY(
TBB_LIBRARY
NAMES TBB libtbb.so
NAMES libtbb.so
PATHS ${TbbDirectory}/lib /usr/lib64 /usr/lib /usr/local/lib64 /usr/local/lib /sw/lib /opt/local/lib
DOC "The TBB library"
)
FIND_LIBRARY(
TBB_MALLOC_LIBRARY
NAMES libtbbmalloc.so
PATHS ${TbbDirectory}/lib /usr/lib64 /usr/lib /usr/local/lib64 /usr/local/lib /sw/lib /opt/local/lib
DOC "The TBB malloc library"
)
ENDIF (WIN32)
IF(TBB_INCLUDE_DIR AND TBB_LIBRARY)
......
......@@ -214,9 +214,9 @@ IF(TBB_FOUND)
MESSAGE(STATUS "* Found TBB")
LIST(APPEND CampvisGlobalDefinitions ${TBB_DEFINITIONS})
LIST(APPEND CampvisGlobalIncludeDirs ${TBB_INCLUDE_DIR})
LIST(APPEND CampvisGlobalExternalLibs ${TBB_LIBRARY})
LIST(APPEND CampvisExternalDllsDebug ${TBB_DLL_DEBUG})
LIST(APPEND CampvisExternalDllsRelease ${TBB_DLL_RELEASE})
LIST(APPEND CampvisGlobalExternalLibs ${TBB_LIBRARY} ${TBB_MALLOC_LIBRARY})
LIST(APPEND CampvisExternalDllsDebug ${TBB_DLL_DEBUG} ${TBB_MALLOC_DLL_DEBUG})
LIST(APPEND CampvisExternalDllsRelease ${TBB_DLL_RELEASE} ${TBB_MALLOC_DLL_RELEASE})
LIST(APPEND CampvisExternalLicenseFiles ${TBB_LICENSE_FILE})
ELSE(TBB_FOUND)
MESSAGE(FATAL_ERROR "TBB not found!")
......
// ================================================================================================
//
// This file is part of the CAMPVis Software Framework.
//
// If not explicitly stated otherwise: Copyright (C) 2012-2014, all rights reserved,
// Christian Schulte zu Berge <christian.szb@in.tum.de>
// Chair for Computer Aided Medical Procedures
// Technische Universitaet Muenchen
// Boltzmannstr. 3, 85748 Garching b. Muenchen, Germany
//
// For a full list of authors and contributors, please refer to the file "AUTHORS.txt".
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
// except in compliance with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software distributed under the
// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
// either express or implied. See the License for the specific language governing permissions
// and limitations under the License.
//
// ================================================================================================
#include "job.h"
#include <memory>
#include <new>
#include "core/tools/opengljobprocessor.h"
namespace campvis {
// Implementation inspired by http://stackoverflow.com/questions/7194127/how-should-i-write-iso-c-standard-conformant-custom-new-and-delete-operators/7194149#7194149
void* AbstractJob::operator new(std::size_t size) throw(std::bad_alloc) {
if (size == 0)
size = 1;
while (true) {
void* toReturn = OpenGLJobProcessor::getRef()._signalPool.malloc(size);
if (toReturn != nullptr)
return toReturn;
//allocation was unsuccessful; find out what the current new-handling function is (see below)
std::new_handler globalHandler = std::set_new_handler(0);
std::set_new_handler(globalHandler);
if (globalHandler) //If new_hander is registered call it
(*globalHandler)();
else
throw std::bad_alloc(); //No handler is registered throw an exception
}
}
void AbstractJob::operator delete(void* rawMemory, std::size_t size) throw() {
if (rawMemory == nullptr)
return;
OpenGLJobProcessor::getRef()._signalPool.free(rawMemory);
}
}
......@@ -49,6 +49,20 @@ namespace campvis {
void operator()() {
this->execute();
}
/**
* Overloading the new operator to create signal handles in signal_manager's memory pool.
* \param size Number of bytes to allocate.
*/
static void* operator new(std::size_t size) throw(std::bad_alloc);
/**
* Overloading the delete operator to correctly remove signal handles from signal_manager's memory pool.
* \param rawMemory Pointer to object to delete
* \param size Number of bytes
*/
static void operator delete(void* rawMemory, std::size_t size) throw();
};
// = Specific Jobs ================================================================================
......
......@@ -31,10 +31,12 @@
#include <ext/threading.h>
#define TBB_PREVIEW_MEMORY_POOL 1
#include <tbb/atomic.h>
#include <tbb/concurrent_queue.h>
#include <tbb/concurrent_hash_map.h>
#include <tbb/concurrent_vector.h>
#include <tbb/memory_pool.h>
#include "tgt/glcontextmanager.h"
#include "tgt/singleton.h"
......@@ -70,7 +72,8 @@ namespace campvis {
* This class is to be considered as thread-safe.
*/
class CAMPVIS_CORE_API OpenGLJobProcessor : public tgt::Singleton<OpenGLJobProcessor>, public tgt::Runnable, public sigslot::has_slots {
friend class tgt::Singleton<OpenGLJobProcessor>;
friend class tgt::Singleton<OpenGLJobProcessor>; ///< CRTP
friend class AbstractJob; ///< so the custom new/delete operator can access the memory pool
public:
/**
......@@ -208,6 +211,9 @@ namespace campvis {
tbb::atomic<tgt::GLCanvas*> _currentContext; ///< current active OpenGL context
private:
typedef std::allocator<AbstractJob> pool_allocator_t;
tbb::memory_pool<pool_allocator_t> _signalPool; ///< Memory pool for the signals
static std::thread::id _this_thread_id;
};
......
......@@ -26,6 +26,9 @@
//
// ================================================================================================
#include <memory>
#include <new>
#include "sigslot.h"
namespace sigslot {
......@@ -37,7 +40,7 @@ namespace sigslot {
}
signal_manager::~signal_manager() {
_signalPool.recycle();
}
void signal_manager::triggerSignalImpl(_signal_handle_base* signal) {
......@@ -103,4 +106,35 @@ namespace sigslot {
const std::string signal_manager::loggerCat_;
// Implementation inspired by http://stackoverflow.com/questions/7194127/how-should-i-write-iso-c-standard-conformant-custom-new-and-delete-operators/7194149#7194149
void* _signal_handle_base::operator new(std::size_t size) throw(std::bad_alloc) {
if (size == 0)
size = 1;
while (true) {
void* toReturn = signal_manager::getRef()._signalPool.malloc(size);
if (toReturn != nullptr)
return toReturn;
//allocation was unsuccessful; find out what the current new-handling function is (see below)
std::new_handler globalHandler = std::set_new_handler(0);
std::set_new_handler(globalHandler);
if (globalHandler) //If new_hander is registered call it
(*globalHandler)();
else
throw std::bad_alloc(); //No handler is registered throw an exception
}
}
void _signal_handle_base::operator delete(void* rawMemory, std::size_t size) throw() {
if (rawMemory == nullptr)
return;
signal_manager::getRef()._signalPool.free(rawMemory);
return;
}
}
......@@ -58,8 +58,10 @@
#include "tgt/assert.h"
#include <ext/threading.h>
#define TBB_PREVIEW_MEMORY_POOL 1
#include <tbb/concurrent_queue.h>
#include <tbb/concurrent_vector.h>
#include <tbb/memory_pool.h>
#include <tbb/spin_mutex.h>
#include "ext/tgt/runnable.h"
......@@ -246,13 +248,26 @@ namespace sigslot {
// ================================================================================================
/// Base class for signal handles that provides an interface to emit the signal.
class _signal_handle_base {
class SIGSLOT_API _signal_handle_base {
public:
/// Virtual destructor
virtual ~_signal_handle_base() {};
/// Emits the signal of this signal handle.
virtual void processSignal() const = 0;
/**
* Overloading the new operator to create signal handles in signal_manager's memory pool.
* \param size Number of bytes to allocate.
*/
static void* operator new(std::size_t size) throw(std::bad_alloc);
/**
* Overloading the delete operator to correctly remove signal handles from signal_manager's memory pool.
* \param rawMemory Pointer to object to delete
* \param size Number of bytes
*/
static void operator delete(void* rawMemory, std::size_t size) throw();
#ifdef CAMPVIS_DEBUG
// This is debug information only, automatically removed from release builds
......@@ -277,7 +292,8 @@ namespace sigslot {
* signal_manager can be considered as thread-safe.
*/
class SIGSLOT_API signal_manager : public tgt::Singleton<signal_manager>, public tgt::Runnable {
friend class tgt::Singleton<signal_manager>;
friend class tgt::Singleton<signal_manager>; ///< CRTP
friend class _signal_handle_base; ///< so the custom new/delete operator can access the memory pool
public:
/// Enumeration of signal handling modes for the signal_manager
......@@ -342,6 +358,9 @@ namespace sigslot {
std::thread::id _this_thread_id;
typedef std::allocator<_signal_handle_base> pool_allocator_t;
tbb::memory_pool<pool_allocator_t> _signalPool; ///< Memory pool for the signals
static const std::string loggerCat_;
};
......
// ================================================================================================
//
// This file is part of the CAMPVis Software Framework.
//
// If not explicitly stated otherwise: Copyright (C) 2012-2014, all rights reserved,
// Christian Schulte zu Berge <christian.szb@in.tum.de>
// Chair for Computer Aided Medical Procedures
// Technische Universitaet Muenchen
// Boltzmannstr. 3, 85748 Garching b. Muenchen, Germany
//
// For a full list of authors and contributors, please refer to the file "AUTHORS.txt".
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
// except in compliance with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software distributed under the
// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
// either express or implied. See the License for the specific language governing permissions
// and limitations under the License.
//
// ================================================================================================
#include "gtest/gtest.h"
#include <sigslot/sigslot.h>
#include <tbb/atomic.h>
#include <tbb/tbb.h>
#include <random>
#include <string>
/**
* Test class for StringUtils.
*/
class SigslotTest : public ::testing::Test, public sigslot::has_slots {
protected:
SigslotTest()
: _randomGenerator(42)
{
_countSent0 = 0;
_countSent1 = 0;
_countSent2 = 0;
_countSent3 = 0;
_countSent4 = 0;
_countSent5 = 0;
_countReceived0 = 0;
_countReceived1 = 0;
_countReceived2 = 0;
_countReceived3 = 0;
_countReceived4 = 0;
_countReceived5 = 0;
_isFinished = false;
s_s0.connect(this, &SigslotTest::onS0);
s_s1.connect(this, &SigslotTest::onS1);
s_s2.connect(this, &SigslotTest::onS2);
s_s3.connect(this, &SigslotTest::onS3);
s_s4.connect(this, &SigslotTest::onS4);
s_s5.connect(this, &SigslotTest::onS5);
s_finished.connect(this, &SigslotTest::onFinished);
}
~SigslotTest() {
}
virtual void SetUp() {
}
virtual void TearDown() {
}
void sendRandomSignal() {
unsigned int r = (_randomGenerator() - _randomGenerator.min()) % 6;
switch (r) {
case 0:
sendS0();
break;
case 1:
sendS1();
break;
case 2:
sendS2();
break;
case 3:
sendS3();
break;
case 4:
sendS4();
break;
case 5:
sendS5();
break;
}
}
void sendS0() {
s_s0.emitSignal();
_countSent0++;
}
void sendS1() {
s_s1.emitSignal(6);
_countSent1++;
}
void sendS2() {
s_s2.emitSignal(42, 1337.f);
_countSent2++;
}
void sendS3() {
s_s3.emitSignal(14, -1.f, "Moin");
_countSent3++;
}
void sendS4() {
s_s4.emitSignal(-14, 1.f, "Moin", 12.21);
_countSent4++;
}
void sendS5() {
s_s5.emitSignal(123, 1.f/7.f, "Moin", 10e10, 'a');
_countSent5++;
}
void onS0() {
_countReceived0++;
}
void onS1(int p1) {
_countReceived1++;
}
void onS2(int p1, float p2) {
_countReceived2++;
}
void onS3(int p1, float p2, std::string p3) {
_countReceived3++;
}
void onS4(int p1, float p2, std::string p3, double p4) {
_countReceived4++;
}
void onS5(int p1, float p2, std::string p3, double p4, char p5) {
_countReceived5++;
sendS4();
}
void onFinished() {
_isFinished = true;
}
protected:
std::default_random_engine _randomGenerator;
sigslot::signal0 s_s0;
sigslot::signal1<int> s_s1;
sigslot::signal2<int, float> s_s2;
sigslot::signal3<int, float, std::string> s_s3;
sigslot::signal4<int, float, std::string, double> s_s4;
sigslot::signal5<int, float, std::string, double, char> s_s5;
sigslot::signal0 s_finished;
tbb::atomic<bool> _isFinished;
tbb::atomic<size_t> _countSent0, _countSent1, _countSent2, _countSent3, _countSent4, _countSent5;
tbb::atomic<size_t> _countReceived0, _countReceived1, _countReceived2, _countReceived3, _countReceived4, _countReceived5;
};
/**
* Tests case related functions.
* lowercase()
* uppercase()
*/
TEST_F(SigslotTest, stressTest) {
const int NUM_SIGNALS = 1000000;
sigslot::signal_manager::getRef().setSignalHandlingMode(sigslot::signal_manager::DEFAULT);
tbb::parallel_for(tbb::blocked_range<int>(0, NUM_SIGNALS), [&] (const tbb::blocked_range<int>& range) {
for (int i = range.begin(); i < range.end(); ++i) {
sendRandomSignal();
}
});
s_finished.emitSignal();
while (! _isFinished)
std::this_thread::yield();
sigslot::signal_manager::getRef().setSignalHandlingMode(sigslot::signal_manager::FORCE_DIRECT);
EXPECT_EQ(_countSent0, _countReceived0);
EXPECT_EQ(_countSent1, _countReceived1);
EXPECT_EQ(_countSent2, _countReceived2);
EXPECT_EQ(_countSent3, _countReceived3);
EXPECT_EQ(_countSent4, _countReceived4);
EXPECT_EQ(_countSent5, _countReceived5);
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment