Import Geant4 11.3.0 source tree

This commit is contained in:
Gabriele Cosmo
2024-12-06 11:11:40 +01:00
parent e58e650b32
commit 32390e802b
1984 changed files with 98713 additions and 83996 deletions
+28
View File
@@ -6,6 +6,34 @@ It must **not** be used as a substitute for writing good git commit messages!
-------------------------------------------------------------------------------
## 2024-10-24 Guy Barrand (g4tools-V11-02-05)
- wroot/file: in compress_buffer(): to fix bugzilla-2625: arrange to have a greater
output buffer size when using deflate(), and check at end, that in case of some
compressions being done, "a_klen<a_buffer.length()" to comply to the ROOT/IO specification
that the overall output size should be stricly lower than the input size.
(A "specification" encoded in ROOT/TKey.cxx/TKey::ReadObj() method in the form
of a "if (fObjlen > fNbytes-fKeylen) {}"). In case "a_klen>=a_buffer.length()", the
input buffer is returned.
- wroot/basket: in write_on_file(): suppress the test "if(klen>m_object_size)" now done
in file::compress_buffer().
- tools/version: pass to 6.3.3.
## 2024-09-26 Ben Morgan (g4tools-V11-02-04)
- Fix typo in member name that is picked up by clang19 compilation on Linux
- Discovered/fixed by ATLAS (Johannes Elmsheuser) in Geant4 10.6.3(!) (ATLASSIM-7265),
but remains in current version.
## 2024-09-04 Guy Barrand (g4tools-V11-02-03)
- streamers: in TH_read_1D(), fix a "std::move" minor Coverity issue.
- axis: in avoid_labels_overlap(), fix a "divide by zero" medium Coverity issue.
- tools/version: pass to 6.3.2.
## 2024-07-11 Guy Barrand (g4tools-V11-02-02)
- fix twenty "std::move" Coverity issues.
- wroot/buffer: have argument of write_array[2](std::vector) passed as a const reference.
- tess_contour: have argument of getFilledArea(std::vector) passed as a const reference.
- tools/version: pass to 6.3.1.
## 2024-03-13 Gabriele Cosmo (g4tools-V11-02-01)
- Fixed string assignments in 'window' and 'pixwin', to support either UNICODE
or UTF-16 encoding on Windows. Addressing problem report #2599.
+26
View File
@@ -1,3 +1,29 @@
6.3.3:
- wroot/file: in compress_buffer(): to fix bugzilla-2625: arrange to have a greater
output buffer size when using deflate(), and check at end, that in case of some
compressions being done, "a_klen<a_buffer.length()" to comply to the ROOT/IO specification
that the overall output size should be stricly lower than the input size.
(A "specification" encoded in ROOT/TKey.cxx/TKey::ReadObj() method in the form
of a "if (fObjlen > fNbytes-fKeylen) {}"). In case "a_klen>=a_buffer.length()", the
input buffer is returned.
- wroot/basket: in write_on_file(): suppress the test "if(klen>m_object_size)" now done
in file::compress_buffer().
- tools/version: pass to 6.3.3.
6.3.2:
- streamers: in TH_read_1D(), fix a "std::move" minor Coverity issue.
- axis: in avoid_labels_overlap(), fix a "divide by zero" medium Coverity issue.
- tools/version: pass to 6.3.2.
6.3.1:
- fix twenty "std::move" Coverity issues.
- wroot/buffer: have argument of write_array[2](std::vector) passed as a const reference.
- tess_contour: have argument of getFilledArea(std::vector) passed as a const reference.
- Fixed string assignments in 'window' and 'pixwin', to support either UNICODE
or UTF-16 encoding on Windows. Addressing problem report #2599.
- Fixed compilation warnings in ccontour and gl2ps on gcc when LTO settings are enabled.
- tools/version: pass to 6.3.1.
6.3.0:
- tools/wroot/file: in the constructor, for the streaming of the root directory, take into account the streaming of what would be
the fUUID (a TUUID in ROOT) field of the TDirectory version 4. This permits to fix the "G4AnalysisManager creates ROOT files
+2 -1
View File
@@ -5,6 +5,7 @@
#define tools_path
#include <string>
#include <utility>
namespace tools {
@@ -28,7 +29,7 @@ inline void nosuffix(const std::string& a_string,std::string& a_value,bool a_bac
std::string _s = a_string.substr(pos,a_string.size()-pos);
std::string::size_type dot_pos = a_back?_s.rfind('.'):_s.find('.');
if(dot_pos==std::string::npos) {
a_value = _s;
a_value = std::move(_s);
} else {
a_value = _s.substr(0,dot_pos);
}
+9 -8
View File
@@ -22,6 +22,7 @@
#endif
#include <istream>
#include <utility>
namespace tools {
namespace rcsv {
@@ -196,7 +197,7 @@ public:
}
planes.push_back(value);
}
hdata.m_in_range_plane_Sxyw = planes;
hdata.m_in_range_plane_Sxyw = std::move(planes);
} else if(_words[0]=="#bin_number") {
if(_words.size()!=2) {
@@ -335,8 +336,8 @@ public:
tools::histo::profile_data<double,unsigned int,unsigned int,double,double> pdata(hdata); //to be filled correctly.
if(is_profile) {
pdata.m_is_profile = true;
pdata.m_bin_Svw = _bin_Svw;
pdata.m_bin_Sv2w = _bin_Sv2w;
pdata.m_bin_Svw = std::move(_bin_Svw);
pdata.m_bin_Sv2w = std::move(_bin_Sv2w);
pdata.m_cut_v = _cut_v;
pdata.m_min_v = _min_v;
pdata.m_max_v = _max_v;
@@ -359,7 +360,7 @@ public:
<< ", mean " << h->mean() << ", rms " << h->rms()
<< std::endl;
}
a_class = _class;
a_class = std::move(_class);
a_obj = h;
} else if(_class==tools::histo::h2d::s_class()) {
@@ -380,7 +381,7 @@ public:
<< ", mean_y " << h->mean_y() << ", rms_y " << h->rms_y()
<< std::endl;
}
a_class = _class;
a_class = std::move(_class);
a_obj = h;
} else if(_class==tools::histo::h3d::s_class()) {
@@ -402,7 +403,7 @@ public:
<< ", mean_z " << h->mean_z() << ", rms_z " << h->rms_z()
<< std::endl;
}
a_class = _class;
a_class = std::move(_class);
a_obj = h;
} else if(_class==tools::histo::p1d::s_class()) {
@@ -422,7 +423,7 @@ public:
<< ", mean " << h->mean() << ", rms " << h->rms()
<< std::endl;
}
a_class = _class;
a_class = std::move(_class);
a_obj = h;
} else if(_class==tools::histo::p2d::s_class()) {
@@ -443,7 +444,7 @@ public:
<< ", mean_y " << h->mean_y() << ", rms_y " << h->rms_y()
<< std::endl;
}
a_class = _class;
a_class = std::move(_class);
a_obj = h;
/*
+3 -1
View File
@@ -36,6 +36,8 @@
#include "mem"
#endif
#include <utility>
namespace tools {
namespace rcsv {
@@ -599,7 +601,7 @@ public:
if(!read_commented_header(a_out,m_reader,_title,_sep,_vec_sep,_cols)) return false;
m_sep = _sep;
m_title = _title;
m_title = std::move(_title);
tools_vforcit(col_desc,_cols,it) {
const std::string& type = (*it).first;
+2 -1
View File
@@ -16,6 +16,7 @@
#include <string>
#include <vector>
#include <ostream>
#include <utility>
// in TOOLS_STL, we don't have (yet) a performant map.
@@ -242,7 +243,7 @@ protected:
return false;
}
a_class = scls;
a_class = std::move(scls);
a_bcnt = (first_int & ~kByteCountMask());
if(m_verbose) {
+5 -5
View File
@@ -28,7 +28,7 @@
#include <list>
#include <cmath> //::log10, ::fabs.
//#include "../rtausmed"
#include <utility>
namespace tools {
namespace rroot {
@@ -155,7 +155,7 @@ inline bool TH_read_1D(buffer& a_buffer,hd_data& a_data,
std::string title;
if(!Named_stream(a_buffer,name,title)) return false;
a_data.m_title = title;
a_data.m_title = std::move(title);
{short color,style,width;
if(!AttLine_stream(a_buffer,color,style,width)) return false;}
@@ -436,7 +436,7 @@ inline histo::h1d* TH1D_stream(buffer& a_buffer){
if(!a_buffer.check_byte_count(_s,_c,"TH1D")) return 0;
unsigned int binn = data.m_bin_number;
data.m_bin_Sw = bins;
data.m_bin_Sw = std::move(bins);
data.m_bin_entries.resize(binn,0);
{std::vector<double> empty;
@@ -555,7 +555,7 @@ inline histo::h2d* TH2D_stream(buffer& a_buffer){
if(!a_buffer.check_byte_count(_s,_c,"TH2D")) return 0;
unsigned int binn = data.m_bin_number;
data.m_bin_Sw = bins;
data.m_bin_Sw = std::move(bins);
data.m_bin_entries.resize(binn,0);
{std::vector<double> empty;
@@ -614,7 +614,7 @@ inline histo::h3d* TH3D_stream(buffer& a_buffer){
if(!a_buffer.check_byte_count(_s,_c,"TH3D")) return 0;
unsigned int binn = data.m_bin_number;
data.m_bin_Sw = bins;
data.m_bin_Sw = std::move(bins);
data.m_bin_entries.resize(binn,0);
{std::vector<double> empty;
+1 -1
View File
@@ -845,7 +845,7 @@ protected:
float b = first_overlap-a*first_scale;
//float wanted_scale = -b/a; //zero overlap.
float wanted_gap = width.value()*labels_gap.value();
float wanted_scale = (-wanted_gap-b)/a;
float wanted_scale = (a==0.0f) ? 1 : (-wanted_gap-b)/a; //a==0.0f should not happen.
if(wanted_scale<=0) wanted_scale = 1; // this if() should not happen.
wanted_scale /= second_scale;
{tools_vforcit(matrix*,m_labels_mtxs,it) {
+4 -2
View File
@@ -39,6 +39,8 @@
#include "../sys/atime"
#endif
#include <utility>
namespace tools {
namespace sg {
@@ -5348,7 +5350,7 @@ protected: //vis bins
_ws.push_back(value);
}
}
ws = _ws;
ws = std::move(_ws);
linen = ws.size()/2;
}
@@ -7181,7 +7183,7 @@ protected: //rep
yy = verify_log(yy,ymin,dy,ylog);
v.push_back(vec3f(xx,yy,a_zz+zz));
}
contourVector.push_back(v);
contourVector.push_back(std::move(v));
}
}
+3 -1
View File
@@ -19,6 +19,8 @@
#include "../colorf"
#include "../S_STRING"
#include <utility>
namespace tools {
namespace sg {
@@ -558,7 +560,7 @@ public:
tools_vforcit(std::string,strings.values(),it) {
std::string scut;
m_base_text->truncate(*it,th,fw,scut);
labcut.push_back(scut);
labcut.push_back(std::move(scut));
}
m_base_text->strings = labcut;}
}
+2 -1
View File
@@ -6,6 +6,7 @@
#include <string>
#include <vector>
#include <utility>
#include "forit"
@@ -37,7 +38,7 @@ inline bool replace(std::string& a_string,const std::string& a_old,const std::st
status = true;
}
}
a_string = snew;
a_string = std::move(snew);
return status;
}
+1 -1
View File
@@ -27,7 +27,7 @@ protected:
tess_contour(const tess_contour& a_from):m_out(a_from.m_out),m_triangles(a_from.m_triangles){}
tess_contour& operator=(const tess_contour&){return *this;}
public:
void getFilledArea(const std::vector<std::vector<vec3f> > aContour) {
void getFilledArea(const std::vector<std::vector<vec3f> >& aContour) {
m_triangles.clear();
m_combine_tmps.clear();
m_error = false;
+4 -4
View File
@@ -6,12 +6,12 @@
#define TOOLS_MAJOR_VERSION 6
#define TOOLS_MINOR_VERSION 3
#define TOOLS_PATCH_VERSION 0
#define TOOLS_VERSION "6.3.0"
#define TOOLS_VERSION_VRP "v6r3p0"
#define TOOLS_PATCH_VERSION 3
#define TOOLS_VERSION "6.3.3"
#define TOOLS_VERSION_VRP "v6r3p3"
namespace tools {
inline unsigned int version() {return 60300;}
inline unsigned int version() {return 60303;}
}
#endif
+1 -10
View File
@@ -183,6 +183,7 @@ public:
uint32 last() const {return m_last;}
void set_nev(uint32 a_last,uint32 a_nev_buf_size,uint32 a_nev,const int* a_entry_offset,const int* a_displacement) {
//used in mpi_create_basket.
m_last = a_last;
m_nev_buf_size = a_nev_buf_size;
m_nev = a_nev;
@@ -306,16 +307,6 @@ public:
bool kdelete = false;
a_file.compress_buffer(m_data,kbuf,klen,kdelete);
if(klen>m_object_size) {
m_out << "tools::wroot::basket::write_on_file :"
<< " compression anomaly "
<< " m_object_size " << m_object_size
<< " klen " << klen
<< std::endl;
if(kdelete) delete [] kbuf;
return false;
}
if(!initialize(a_file,klen)) { //it will do a m_seek_key = a_file.END() and then a_file.set_END(...)
m_out << "tools::wroot::basket::write_on_file :"
<< " initialize() failed."
+2 -2
View File
@@ -151,13 +151,13 @@ public:
}
template <class T>
bool write_array(const std::vector<T> a_v) {
bool write_array(const std::vector<T>& a_v) {
if(!write((uint32)a_v.size())) return false;
return write_fast_array(a_v);
}
template <class T>
bool write_array2(const std::vector< std::vector<T> > a_v) {
bool write_array2(const std::vector< std::vector<T> >& a_v) {
if(!write((uint32)a_v.size())) return false;
for(unsigned int index=0;index<a_v.size();index++) {
if(!write_array(a_v[index])) return false;
+1 -1
View File
@@ -399,7 +399,7 @@
protected:
std_vector_column_ref(const std_vector_column_ref& a_from)
:icol(a_from)
,m_branch(a_from.m_barnch)
,m_branch(a_from.m_branch)
,m_ref(a_from.m_ref)
,m_leaf(0)
,m_leaf_count(0)
+23 -10
View File
@@ -167,7 +167,7 @@ public: //ifile
}
virtual uint32 compression() const {return m_compress;}
virtual void compress_buffer(const buffer& a_buffer,char*& a_kbuf,uint32& a_klen,bool& a_kdel) {
//NOTE : if(kdelete) delete [] kbuf;
//NOTE: if(kdelete) delete [] kbuf;
a_kbuf = 0;
a_klen = 0;
@@ -178,7 +178,7 @@ public: //ifile
if(cxlevel && (nbytes>256)) {
compress_func func;
if(!ziper('Z',func)) {
//m_out << "tools::wroot::directory::write_object :"
//m_out << "tools::wroot::file::compress_buffer :"
// << " zlib ziper not found."
// << std::endl;
a_kbuf = (char*)a_buffer.buf();
@@ -188,7 +188,8 @@ public: //ifile
const uint32 kMAXBUF = 0xffffff;
const uint32 HDRSIZE = 9;
uint32 nbuffers = nbytes/kMAXBUF;
uint32 buflen = nbytes+HDRSIZE*(nbuffers+1);
uint32 buf_out_size = kMAXBUF+HDRSIZE+kMAXBUF/2;
uint32 buflen = (nbuffers+1)*buf_out_size;
a_kbuf = new char[buflen];
a_kdel = true;
char* src = (char*)a_buffer.buf();
@@ -197,19 +198,30 @@ public: //ifile
for(uint32 i=0;i<=nbuffers;i++) {
uint32 bufmax = ((i == nbuffers) ? nbytes - nzip : kMAXBUF);
uint32 nout;
if(!zip(m_out,func,cxlevel,bufmax,src,bufmax,tgt,nout)) {
if(!zip(m_out,func,cxlevel,bufmax,src,buf_out_size,tgt,nout)) {
delete [] a_kbuf;
a_kbuf = (char*)a_buffer.buf();
a_klen = a_buffer.length();
a_kdel = false;
break;
return;
}
tgt += nout; //nout includes HDRSIZE
a_klen += nout;
src += kMAXBUF;
nzip += kMAXBUF;
}
//::printf("debug : compress : end : %u %u\n",nbytes,klen);
if(a_klen>=a_buffer.length()) {
//NOTE: It is in the ROOT/IO specification (see ROOT/TKey.cxx/TKey::ReadObj() code) that some data compressions
// are detected at read time by checking that "fObjlen > fNbytes-fKeylen", that is to say that
// the overall output size (fNbytes-fKeylen) is stricly lower than the input size (fObjlen).
// By using the zlib-ng compression library, we saw that we may fall on cases where the overall
// output size (a_klen here at this point) may be equal to the input size (a_buffer.lengt()) which
// induces problem when reading back the data with ROOT. Then the upper test checks and protects against that.
delete [] a_kbuf;
a_kbuf = (char*)a_buffer.buf();
a_klen = a_buffer.length();
a_kdel = false;
}
}
} else {
a_kbuf = (char*)a_buffer.buf();
@@ -714,14 +726,14 @@ protected:
const uint32 HDRSIZE = 9;
if(a_tgtsize<HDRSIZE) {
a_out << "tools::wroot::directory::zip :"
a_out << "tools::wroot::file::zip :"
<< " target buffer too small."
<< std::endl;
a_irep = 0;
return false;
}
if(a_srcsize>0xffffff) {
a_out << "tools::wroot::directory::zip :"
a_out << "tools::wroot::file::zip :"
<< " source buffer too big."
<< std::endl;
a_irep = 0;
@@ -733,14 +745,15 @@ protected:
a_srcsize,a_src,
a_tgtsize,a_tgt+HDRSIZE,
out_size)) {
a_out << "tools::wroot::directory::zip :"
a_out << "tools::wroot::file::zip :"
<< " zipper failed."
<< std::endl;
a_irep = 0;
return false;
}
if((HDRSIZE+out_size)>a_tgtsize) {
a_out << "tools::wroot::directory::zip :"
a_out << "tools::wroot::file::zip :"
<< " target buffer overflow."
<< std::endl;
a_irep = 0;
+2 -1
View File
@@ -24,6 +24,7 @@
#include <vector>
#include <map>
#include <utility>
namespace tools {
namespace xml {
@@ -301,7 +302,7 @@ public: //used in BatchLab::XML_DataReader.
bins[iaxis] = num;
mns[iaxis] = mn;
mxs[iaxis] = mx;
edges[iaxis] = borders;
edges[iaxis] = std::move(borders);
if(variableBins) isVariableBins = true;
found++;
}
+1 -1
View File
@@ -1,7 +1,7 @@
# -------------------------------------------------------------------------------------- #
# cmake settings
#
cmake_minimum_required(VERSION 3.8...3.23)
cmake_minimum_required(VERSION 3.8...3.26)
if(${CMAKE_VERSION} VERSION_LESS 3.12)
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
endif()
+17
View File
@@ -6,6 +6,23 @@ It must **not** be used as a substitute for writing good git commit messages!
-------------------------------------------------------------------------------
## 2024-11-14 Ben Morgan (ptl-V11-02-03)
- Add max CMake version in PTLConfig.cmake.in to suppress warnings in latest
CMake versions about support for 3.10 being dropped.
## 2024-11-01 Ben Morgan (ptl-V11-02-02)
- Fix Coverity warnings:
- 105693: use std:move to avoid direct copy
- 105524: remove structurally dead code
## 2024-05-14 Ben Morgan (ptl-V11-02-01)
- Import latest PTL master (f892a93d) from GitHub, patched for Geant4 source layout
- Local changes since ptl-V11-00-03 retained
- Includes upstream changes since ptl-V11-00-03:
- 44: Simplification and refactor of main API
- 45: Removal of env vars for ThreadPool config
- 46: Bump version to 3.0.0
## 2024-04-24 Pere Mato (ptl-V11-02-00)
- Changed Windows.h to windows.h since for MinGW always seems to be lower case, not relevant for native builds.
+1 -1
View File
@@ -1 +1 @@
2.3.3
3.0.0
+1 -1
View File
@@ -3,7 +3,7 @@
#
@PACKAGE_INIT@
cmake_minimum_required(VERSION 3.8)
cmake_minimum_required(VERSION 3.8...3.27)
# -------------------------------------------------------------------------------------- #
# basic paths
+2 -2
View File
@@ -243,8 +243,8 @@ int main()
#pragma once
#include "PTL/Threading.hh"
#include "PTL/Utility.hh"
#include "PTL/ConsumeParameters.hh"
#include "PTL/Types.hh"
#include <chrono>
#include <iostream>
-802
View File
@@ -1,802 +0,0 @@
//
// MIT License
// Copyright (c) 2020 Jonathan R. Madsen
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED
// "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
// Backtrace
//
// Description:
//
// Prints backtraces after signals are caught. Available on Unix.
//
// Usage:
// A standard set of signals are enabled by default:
//
// SIGQUIT, SIGILL, SIGABRT, SIGKILL, SIGBUS, SIGSEGV
//
// These should not interfere with debuggers and/or FPEDetection.
// In order to turn off handling for one or more signals, one can do:
//
// BackTrace::DefaultSignals() = std::set<int>{};
// BackTrace::DefaultSignals() = std::set<int>{ SIGSEGV };
//
// and so on, *before* creating the run-manager. After the run-manager
// has been created, one should disable the signals:
//
// BackTrace::Disable(BackTrace::DefaultSignals());
//
// Additionally, at runtime, the environment variable "BACKTRACE" can
// be set to select a specific set of signals or none, e.g. in bash:
//
// export BACKTRACE="SIGQUIT,SIGSEGV"
// export BACKTRACE="none"
//
// The environment variable is case-insensitive and can use any of the
// following delimiters: space, comma, semi-colon, colon
//
// Author: J.Madsen, 19 October 2020
// --------------------------------------------------------------------
#ifndef PTL_Backtrace_hh
#define PTL_Backtrace_hh 1
#include "Threading.hh"
#include "Types.hh"
#if defined(PTL_UNIX)
# include <cxxabi.h>
# include <execinfo.h>
# include <unistd.h>
#endif
#if defined(PTL_LINUX)
# include <features.h>
#endif
#include <cfenv>
#include <cmath>
#include <csignal>
#include <cstring>
#include <type_traits>
namespace PTL
{
template <typename FuncT, typename... ArgTypes>
#if __cpp_lib_is_invocable >= 201703
using ResultOf_t = std::invoke_result_t<FuncT, ArgTypes...>;
#else
using ResultOf_t = typename std::result_of<FuncT(ArgTypes...)>::type;
#endif
} // namespace PTL
// compatible OS and compiler
#if defined(PTL_UNIX) && \
(defined(__GNUC__) || defined(__clang__) || defined(_INTEL_COMPILER))
# if !defined(PTL_SIGNAL_AVAILABLE)
# define PTL_SIGNAL_AVAILABLE
# endif
# if !defined(PTL_DEMANGLE_AVAILABLE)
# define PTL_DEMANGLE_AVAILABLE
# endif
#endif
#if !defined(PTL_PSIGINFO_AVAILABLE)
# if _XOPEN_SOURCE >= 700 || _POSIX_C_SOURCE >= 200809L
# define PTL_PSIGINFO_AVAILABLE 1
# else
# define PTL_PSIGINFO_AVAILABLE 0
# endif
#endif
//----------------------------------------------------------------------------//
namespace PTL
{
inline std::string
Demangle(const char* _str)
{
#if defined(PTL_DEMANGLE_AVAILABLE)
// demangling a string when delimiting
int _status = 0;
char* _ret = ::abi::__cxa_demangle(_str, nullptr, nullptr, &_status);
if(_ret && _status == 0)
return std::string(const_cast<const char*>(_ret));
return _str;
#else
return _str;
#endif
}
//----------------------------------------------------------------------------//
inline std::string
Demangle(const std::string& _str)
{
return Demangle(_str.c_str());
}
//----------------------------------------------------------------------------//
template <typename Tp>
inline std::string
Demangle()
{
return Demangle(typeid(Tp).name());
}
} // namespace PTL
//----------------------------------------------------------------------------//
//
// ONLY IF SIGNAL_AVAILABLE
//
//----------------------------------------------------------------------------//
//
#if defined(PTL_SIGNAL_AVAILABLE)
//
// these are not in the original POSIX.1-1990 standard so we are defining
// them in case the OS hasn't
// POSIX-1.2001
# ifndef SIGTRAP
# define SIGTRAP 5
# endif
// not specified in POSIX.1-2001, but nevertheless appears on most other
// UNIX systems, where its default action is typically to terminate the
// process with a core dump.
# ifndef SIGEMT
# define SIGEMT 7
# endif
// POSIX-1.2001
# ifndef SIGURG
# define SIGURG 16
# endif
// POSIX-1.2001
# ifndef SIGXCPU
# define SIGXCPU 24
# endif
// POSIX-1.2001
# ifndef SIGXFSZ
# define SIGXFSZ 25
# endif
// POSIX-1.2001
# ifndef SIGVTALRM
# define SIGVTALRM 26
# endif
// POSIX-1.2001
# ifndef SIGPROF
# define SIGPROF 27
# endif
// POSIX-1.2001
# ifndef SIGINFO
# define SIGINFO 29
# endif
//----------------------------------------------------------------------------//
# include <algorithm>
# include <array>
# include <cstdio>
# include <cstdlib>
# include <functional>
# include <iomanip>
# include <iostream>
# include <map>
# include <regex>
# include <set>
# include <sstream>
# include <string>
# include <tuple>
# include <vector>
// PTL header
# include "Threading.hh"
//----------------------------------------------------------------------------//
namespace PTL
{
class Backtrace
{
public:
using sigaction_t = struct sigaction;
using exit_action_t = std::function<void(int)>;
using frame_func_t = std::function<std::string(const char*)>;
using signal_set_t = std::set<int>;
public:
struct actions
{
using id_entry_t = std::tuple<std::string, int, std::string>;
using id_list_t = std::vector<id_entry_t>;
std::map<int, bool> is_active = {};
std::map<int, sigaction_t> current = {};
std::map<int, sigaction_t> previous = {};
std::vector<exit_action_t> exit_actions = {};
const id_list_t identifiers = {
id_entry_t("SIGHUP", SIGHUP, "terminal line hangup"),
id_entry_t("SIGINT", SIGINT, "interrupt program"),
id_entry_t("SIGQUIT", SIGQUIT, "quit program"),
id_entry_t("SIGILL", SIGILL, "illegal instruction"),
id_entry_t("SIGTRAP", SIGTRAP, "trace trap"),
id_entry_t("SIGABRT", SIGABRT, "abort program (formerly SIGIOT)"),
id_entry_t("SIGEMT", SIGEMT, "emulate instruction executed"),
id_entry_t("SIGFPE", SIGFPE, "floating-point exception"),
id_entry_t("SIGKILL", SIGKILL, "kill program"),
id_entry_t("SIGBUS", SIGBUS, "bus error"),
id_entry_t("SIGSEGV", SIGSEGV, "segmentation violation"),
id_entry_t("SIGSYS", SIGSYS, "non-existent system call invoked"),
id_entry_t("SIGPIPE", SIGPIPE, "write on a pipe with no reader"),
id_entry_t("SIGALRM", SIGALRM, "real-time timer expired"),
id_entry_t("SIGTERM", SIGTERM, "software termination signal"),
id_entry_t("SIGURG", SIGURG, "urgent condition present on socket"),
id_entry_t("SIGSTOP", SIGSTOP, "stop (cannot be caught or ignored)"),
id_entry_t("SIGTSTP", SIGTSTP, "stop signal generated from keyboard"),
id_entry_t("SIGCONT", SIGCONT, "continue after stop"),
id_entry_t("SIGCHLD", SIGCHLD, "child status has changed"),
id_entry_t("SIGTTIN", SIGTTIN,
"background read attempted from control terminal"),
id_entry_t("SIGTTOU", SIGTTOU,
"background write attempted to control terminal"),
id_entry_t("SIGIO ", SIGIO, "I/O is possible on a descriptor"),
id_entry_t("SIGXCPU", SIGXCPU, "cpu time limit exceeded"),
id_entry_t("SIGXFSZ", SIGXFSZ, "file size limit exceeded"),
id_entry_t("SIGVTALRM", SIGVTALRM, "virtual time alarm"),
id_entry_t("SIGPROF", SIGPROF, "profiling timer alarm"),
id_entry_t("SIGWINCH", SIGWINCH, "Window size change"),
id_entry_t("SIGINFO", SIGINFO, "status request from keyboard"),
id_entry_t("SIGUSR1", SIGUSR1, "User defined signal 1"),
id_entry_t("SIGUSR2", SIGUSR2, "User defined signal 2")
};
};
public:
// a functor called for each frame in the backtrace
static frame_func_t& FrameFunctor();
// default set of signals
static signal_set_t& DefaultSignals();
// the signal handler
static void Handler(int sig, siginfo_t* sinfo, void* context);
// information message about the signal, performs exit-actions
// and prints back-trace
static void Message(int sig, siginfo_t* sinfo, std::ostream&);
// calls user-provided functions after signal is caught but before abort
static void ExitAction(int sig);
// enable signals via a string (which is tokenized)
static int Enable(const std::string&);
// enable signals via set of integers, anything less than zero is ignored
static int Enable(const signal_set_t& _signals = DefaultSignals());
// disable signals
static int Disable(signal_set_t _signals = {});
// gets the numeric value for a signal name
static int GetSignal(const std::string&);
// provides a description of the signal
static std::string Description(int sig);
// adds an exit action
template <typename FuncT>
static void AddExitAction(FuncT&& func);
// gets a backtrace of "Depth" frames. The offset parameter is used
// to ignore initial frames (such as this function). A callback
// can be provided to inspect and/or tweak the frame string
template <size_t Depth, size_t Offset = 0, typename FuncT = frame_func_t>
static std::array<ResultOf_t<FuncT, const char*>, Depth> GetMangled(
FuncT&& func = FrameFunctor());
// gets a demangled backtrace of "Depth" frames. The offset parameter is
// used to ignore initial frames (such as this function). A callback
// can be provided to inspect and/or tweak the frame string
template <size_t Depth, size_t Offset = 0, typename FuncT = frame_func_t>
static std::array<ResultOf_t<FuncT, const char*>, Depth> GetDemangled(
FuncT&& func = FrameFunctor());
private:
static actions& GetData()
{
static auto _instance = actions{};
return _instance;
}
};
//----------------------------------------------------------------------------//
// a functor called for each frame in the backtrace
inline Backtrace::frame_func_t&
Backtrace::FrameFunctor()
{
static frame_func_t _instance = [](const char* inp) { return std::string(inp); };
return _instance;
}
//----------------------------------------------------------------------------//
// default set of signals
inline Backtrace::signal_set_t&
Backtrace::DefaultSignals()
{
static signal_set_t _instance = {
SIGQUIT, SIGILL, SIGABRT, SIGKILL, SIGBUS, SIGSEGV
};
return _instance;
}
//----------------------------------------------------------------------------//
template <typename FuncT>
inline void
Backtrace::AddExitAction(FuncT&& func)
{
GetData().exit_actions.emplace_back(std::forward<FuncT>(func));
}
//----------------------------------------------------------------------------//
inline void
Backtrace::ExitAction(int sig)
{
for(auto& itr : GetData().exit_actions)
itr(sig);
}
//----------------------------------------------------------------------------//
template <size_t Depth, size_t Offset, typename FuncT>
inline std::array<ResultOf_t<FuncT, const char*>, Depth>
Backtrace::GetMangled(FuncT&& func)
{
static_assert((Depth - Offset) >= 1, "Error Depth - Offset should be >= 1");
using type = ResultOf_t<FuncT, const char*>;
// destination
std::array<type, Depth> btrace;
btrace.fill((std::is_pointer<type>::value) ? nullptr : type{});
// plus one for this stack-frame
std::array<void*, Depth + Offset> buffer;
// size of returned buffer
auto sz = backtrace(buffer.data(), Depth + Offset);
// size of relevant data
auto n = sz - Offset;
// skip ahead (Offset + 1) stack frames
char** bsym = backtrace_symbols(buffer.data() + Offset, n);
// report errors
if(bsym == nullptr)
perror("backtrace_symbols");
else
{
for(decltype(n) i = 0; i < n; ++i)
btrace[i] = func(bsym[i]);
free(bsym);
}
return btrace;
}
//----------------------------------------------------------------------------//
template <size_t Depth, size_t Offset, typename FuncT>
inline std::array<ResultOf_t<FuncT, const char*>, Depth>
Backtrace::GetDemangled(FuncT&& func)
{
auto demangle_bt = [&](const char* cstr) {
auto _trim = [](std::string& _sub, size_t& _len) {
size_t _pos = 0;
while((_pos = _sub.find_first_of(' ')) == 0)
{
_sub = _sub.erase(_pos, 1);
--_len;
}
while((_pos = _sub.find_last_of(' ')) == _sub.length() - 1)
{
_sub = _sub.substr(0, _sub.length() - 1);
--_len;
}
return _sub;
};
auto str = Demangle(std::string(cstr));
auto beg = str.find("(");
if(beg == std::string::npos)
{
beg = str.find("_Z");
if(beg != std::string::npos)
beg -= 1;
}
auto end = str.find("+", beg);
if(beg != std::string::npos && end != std::string::npos)
{
auto len = end - (beg + 1);
auto sub = str.substr(beg + 1, len);
auto dem = Demangle(_trim(sub, len));
str = str.replace(beg + 1, len, dem);
}
else if(beg != std::string::npos)
{
auto len = str.length() - (beg + 1);
auto sub = str.substr(beg + 1, len);
auto dem = Demangle(_trim(sub, len));
str = str.replace(beg + 1, len, dem);
}
else if(end != std::string::npos)
{
auto len = end;
auto sub = str.substr(beg, len);
auto dem = Demangle(_trim(sub, len));
str = str.replace(beg, len, dem);
}
return func(str.c_str());
};
return GetMangled<Depth, Offset>(demangle_bt);
}
//----------------------------------------------------------------------------//
inline void
Backtrace::Message(int sig, siginfo_t* sinfo, std::ostream& os)
{
// try to avoid as many dynamic allocations as possible here to avoid
// overflowing the signal stack
// ignore future signals of this type
signal(sig, SIG_IGN);
os << "\n### CAUGHT SIGNAL: " << sig << " ### ";
if(sinfo)
os << "address: " << sinfo->si_addr << ", ";
os << Description(sig) << ". ";
if(sig == SIGSEGV)
{
if(sinfo)
{
switch(sinfo->si_code)
{
case SEGV_MAPERR: os << "Address not mapped to object."; break;
case SEGV_ACCERR: os << "Invalid permissions for mapped object."; break;
default:
os << "Unknown segmentation fault error: " << sinfo->si_code << ".";
break;
}
}
else
{
os << "Segmentation fault (unknown).";
}
}
else if(sig == SIGFPE)
{
if(sinfo)
{
switch(sinfo->si_code)
{
case FE_DIVBYZERO: os << "Floating point divide by zero."; break;
case FE_OVERFLOW: os << "Floating point overflow."; break;
case FE_UNDERFLOW: os << "Floating point underflow."; break;
case FE_INEXACT: os << "Floating point inexact result."; break;
case FE_INVALID: os << "Floating point invalid operation."; break;
default:
os << "Unknown floating point exception error: " << sinfo->si_code
<< ".";
break;
}
}
else
{
os << "Unknown floating point exception";
if(sinfo)
os << ": " << sinfo->si_code;
os << ". ";
}
}
os << '\n';
auto bt = GetMangled<256, 3>([](const char* _s) { return _s; });
char prefix[64];
snprintf(prefix, 64, "[PID=%i, TID=%i]", (int) getpid(),
(int) Threading::GetThreadId());
size_t sz = 0;
for(auto& itr : bt)
{
if(!itr)
break;
if(strlen(itr) == 0)
break;
++sz;
}
os << "\nBacktrace:\n";
auto _w = std::log10(sz) + 1;
for(size_t i = 0; i < sz; ++i)
{
os << prefix << "[" << std::setw(_w) << std::right << i << '/' << std::setw(_w)
<< std::right << sz << "]> " << std::left << bt.at(i) << '\n';
}
os << std::flush;
// exit action could cause more signals to be raise so make sure this is done
// after the message has been printed
try
{
ExitAction(sig);
} catch(std::exception& e)
{
std::cerr << "ExitAction(" << sig << ") threw an exception" << std::endl;
std::cerr << e.what() << std::endl;
}
}
//----------------------------------------------------------------------------//
inline void
Backtrace::Handler(int sig, siginfo_t* sinfo, void*)
{
Message(sig, sinfo, std::cerr);
char msg[1024];
snprintf(msg, 1024, "%s", "\n");
if(sinfo && PTL_PSIGINFO_AVAILABLE > 0)
{
# if PTL_PSIGINFO_AVAILABLE > 0
psiginfo(sinfo, msg);
fflush(stdout);
fflush(stderr);
# endif
}
else
{
std::cerr << msg << std::flush;
}
// ignore any termination signals
for(auto itr : { SIGKILL, SIGTERM, SIGABRT })
signal(itr, SIG_IGN);
abort();
}
//----------------------------------------------------------------------------//
inline int
Backtrace::Enable(const signal_set_t& _signals)
{
static bool _first = true;
if(_first)
{
std::string _msg = "!!! Backtrace is activated !!!";
std::stringstream _filler;
std::stringstream _spacer;
_filler.fill('#');
_filler << std::setw(_msg.length()) << "";
_spacer << std::setw(10) << "";
std::cout << "\n\n"
<< _spacer.str() << _filler.str() << "\n"
<< _spacer.str() << _msg << "\n"
<< _spacer.str() << _filler.str() << "\n\n"
<< std::flush;
}
_first = false;
int cnt = 0;
for(const auto& itr : _signals)
{
if(itr < 0)
continue;
if(GetData().is_active[itr])
continue;
++cnt;
sigfillset(&(GetData().current[itr].sa_mask));
sigdelset(&(GetData().current[itr].sa_mask), itr);
GetData().current[itr].sa_sigaction = &Handler;
GetData().current[itr].sa_flags = SA_SIGINFO;
sigaction(itr, &(GetData().current[itr]), &(GetData().previous[itr]));
}
return cnt;
}
//----------------------------------------------------------------------------//
inline int
Backtrace::Enable(const std::string& _signals)
{
if(_signals.empty())
return 0;
auto _add_signal = [](std::string sig, signal_set_t& _targ) {
if(!sig.empty())
{
for(auto& itr : sig)
itr = toupper(itr);
_targ.insert(Backtrace::GetSignal(sig));
}
};
const std::regex wsp_re("[ ,;:\t\n]+");
auto _maxid = GetData().identifiers.size();
auto _result = std::vector<std::string>(_maxid, "");
std::copy(std::sregex_token_iterator(_signals.begin(), _signals.end(), wsp_re, -1),
std::sregex_token_iterator(), _result.begin());
signal_set_t _sigset{};
for(auto& itr : _result)
_add_signal(itr, _sigset);
return Enable(_sigset);
}
//----------------------------------------------------------------------------//
inline int
Backtrace::Disable(signal_set_t _signals)
{
if(_signals.empty())
{
for(auto& itr : GetData().is_active)
_signals.insert(itr.first);
}
int cnt = 0;
for(const auto& itr : _signals)
{
if(itr < 0)
continue;
if(!GetData().is_active[itr])
continue;
++cnt;
sigaction(itr, &(GetData().previous[itr]), nullptr);
GetData().current.erase(itr);
GetData().is_active[itr] = false;
}
return cnt;
}
//----------------------------------------------------------------------------//
inline int
Backtrace::GetSignal(const std::string& sid)
{
for(auto&& itr : GetData().identifiers)
{
if(std::get<0>(itr) == sid)
return std::get<1>(itr);
}
return -1;
}
//----------------------------------------------------------------------------//
inline std::string
Backtrace::Description(int sig)
{
for(auto&& itr : GetData().identifiers)
{
if(std::get<1>(itr) == sig)
{
std::stringstream ss;
ss << " signal = " << std::setw(8) << std::get<0>(itr)
<< ", value = " << std::setw(4) << std::get<1>(itr)
<< ", description = " << std::get<2>(itr);
return ss.str();
}
}
std::stringstream ss;
ss << " signal = " << std::setw(8) << "unknown"
<< ", value = " << std::setw(4) << sig;
return ss.str();
}
//----------------------------------------------------------------------------//
} // namespace PTL
#else
# include <array>
# include <functional>
# include <map>
# include <set>
# include <string>
# include <tuple>
# include <vector>
namespace PTL
{
// dummy implementation
class Backtrace
{
public:
struct fake_siginfo
{};
struct fake_sigaction
{};
using siginfo_t = fake_siginfo;
using sigaction_t = fake_sigaction;
using exit_action_t = std::function<void(int)>;
using frame_func_t = std::function<std::string(const char*)>;
using signal_set_t = std::set<int>;
public:
struct actions
{
using id_entry_t = std::tuple<std::string, int, std::string>;
using id_list_t = std::vector<id_entry_t>;
std::map<int, bool> is_active = {};
std::map<int, sigaction_t> current = {};
std::map<int, sigaction_t> previous = {};
std::vector<exit_action_t> exit_actions = {};
const id_list_t identifiers = {};
};
public:
static void Handler(int, siginfo_t*, void*) {}
static void Message(int, siginfo_t*, std::ostream&) {}
static void ExitAction(int) {}
static int Enable(const std::string&) { return 0; }
static int Enable(const signal_set_t& = DefaultSignals()) { return 0; }
static int Disable(signal_set_t = {}) { return 0; }
static int GetSignal(const std::string&) { return -1; }
static std::string Description(int) { return std::string{}; }
template <typename FuncT>
static void AddExitAction(FuncT&&)
{}
template <size_t Depth, size_t Offset = 0, typename FuncT = frame_func_t>
static std::array<ResultOf_t<FuncT, const char*>, Depth> GetMangled(
FuncT&& func = FrameFunctor())
{
using type = ResultOf_t<FuncT, const char*>;
auto ret = std::array<type, Depth>{};
ret.fill(func(""));
return ret;
}
template <size_t Depth, size_t Offset = 0, typename FuncT = frame_func_t>
static std::array<ResultOf_t<FuncT, const char*>, Depth> GetDemangled(
FuncT&& func = FrameFunctor())
{
using type = ResultOf_t<FuncT, const char*>;
auto ret = std::array<type, Depth>{};
ret.fill(func(""));
return ret;
}
// a functor called for each frame in the backtrace
static frame_func_t& FrameFunctor()
{
static frame_func_t _instance = [](const char* _s) { return std::string(_s); };
return _instance;
}
// default set of signals
static signal_set_t& DefaultSignals()
{
static signal_set_t _instance = {};
return _instance;
}
static actions& GetData()
{
static auto _instance = actions{};
return _instance;
}
};
//----------------------------------------------------------------------------//
} // namespace PTL
#endif // SIGNAL_AVAILABLE
#endif // Backtrace_hh
@@ -16,25 +16,16 @@
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
// ---------------------------------------------------------------
// Tasking class header file
//
// Class Description:
//
// This file wraps a TBB task_group into a TaskGroup
//
// ---------------------------------------------------------------
// Author: Jonathan Madsen (Jun 21st 2018)
// ---------------------------------------------------------------
#pragma once
#include "PTL/TaskGroup.hh"
namespace PTL
{
// in new version, TaskGroup handles TBB
template <typename Tp, typename Arg = Tp>
using TBBTaskGroup = TaskGroup<Tp, Arg>;
//--------------------------------------------------------------------------------------//
// use this function to get rid of "unused parameter" warnings
//
template <typename... Args>
void
ConsumeParameters(Args&&...)
{}
} // namespace PTL
+93
View File
@@ -0,0 +1,93 @@
//
// MIT License
// Copyright (c) 2020 Jonathan R. Madsen
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED
// "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//
#pragma once
#include <cctype>
#include <cstdlib>
#include <functional>
#include <iomanip>
#include <iostream>
#include <map>
#include <mutex>
#include <set>
#include <sstream> // IWYU pragma: keep
#include <string>
#include <tuple>
#include <utility>
namespace PTL
{
//--------------------------------------------------------------------------------------//
// use this function to get an environment variable setting +
// a default if not defined, e.g.
// int num_threads =
// GetEnv<int>("FORCENUMBEROFTHREADS",
// std::thread::hardware_concurrency());
//
template <typename Tp>
Tp
GetEnv(const std::string& env_id, Tp _default = Tp())
{
char* env_var = std::getenv(env_id.c_str());
if(env_var)
{
std::string str_var = std::string(env_var);
std::istringstream iss(str_var);
Tp var = Tp();
iss >> var;
return var;
}
// return default if not specified in environment
return _default;
}
//--------------------------------------------------------------------------------------//
// overload for boolean
//
template <>
inline bool
GetEnv(const std::string& env_id, bool _default)
{
char* env_var = std::getenv(env_id.c_str());
if(env_var)
{
std::string var = std::string(env_var);
bool val = true;
if(var.find_first_not_of("0123456789") == std::string::npos)
val = (bool) atoi(var.c_str());
else
{
for(auto& itr : var)
itr = tolower(itr);
if(var == "off" || var == "false")
val = false;
}
return val;
}
// return default if not specified in environment
return _default;
}
//--------------------------------------------------------------------------------------//
} // namespace PTL
+1 -1
View File
@@ -30,7 +30,7 @@
#pragma once
#include "PTL/Types.hh"
#include "PTL/Macros.hh"
#include <functional>
#include <utility>
+107
View File
@@ -0,0 +1,107 @@
//
// MIT License
// Copyright (c) 2020 Jonathan R. Madsen
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED
// "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
#pragma once
#if defined(__APPLE__) || defined(__MACH__)
# if !defined(PTL_MACOS)
# define PTL_MACOS 1
# endif
# if !defined(PTL_UNIX)
# define PTL_UNIX 1
# endif
#endif
#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)
# if !defined(PTL_WINDOWS)
# define PTL_WINDOWS 1
# endif
#endif
#if defined(__linux__) || defined(__linux) || defined(linux) || defined(__gnu_linux__)
# if !defined(PTL_LINUX)
# define PTL_LINUX 1
# endif
# if !defined(PTL_UNIX)
# define PTL_UNIX 1
# endif
#endif
#if defined(__unix__) || defined(__unix) || defined(unix)
# if !defined(PTL_UNIX)
# define PTL_UNIX 1
# endif
#endif
#if defined(PTL_WINDOWS)
// Disable warning C4786 on WIN32 architectures:
// identifier was truncated to '255' characters
// in the debug information
//
# pragma warning(disable : 4786)
//
// Define DLL export macro for WIN32 systems for
// importing/exporting external symbols to DLLs
//
# if defined PTL_BUILD_DLL
# define DLLEXPORT __declspec(dllexport)
# define DLLIMPORT __declspec(dllimport)
# else
# define DLLEXPORT
# define DLLIMPORT
# endif
//
// Unique identifier for global module
//
# if defined PTL_ALLOC_EXPORT
# define PTL_DLL DLLEXPORT
# else
# define PTL_DLL DLLIMPORT
# endif
#else
# define DLLEXPORT
# define DLLIMPORT
# define PTL_DLL
#endif
#if !defined(PTL_DEFAULT_OBJECT)
# define PTL_DEFAULT_OBJECT(NAME) \
NAME() = default; \
~NAME() = default; \
NAME(const NAME&) = default; \
NAME(NAME&&) = default; \
NAME& operator=(const NAME&) = default; \
NAME& operator=(NAME&&) = default;
#endif
#if !defined(PTL_NO_SANITIZE_THREAD)
// expect that sanitizer is from compiler which supports __has_attribute
# if defined(__has_attribute)
# if __has_attribute(no_sanitize)
# define PTL_NO_SANITIZE_THREAD __attribute__((no_sanitize("thread")))
# else
# define PTL_NO_SANITIZE_THREAD
# endif
# elif defined(__clang__) || defined(__GNUC__)
# define PTL_NO_SANITIZE_THREAD __attribute__((no_sanitize("thread")))
# else
// otherwise, make blank
# define PTL_NO_SANITIZE_THREAD
# endif
#endif
-5
View File
@@ -20,9 +20,6 @@
#pragma once
#include "PTL/AutoLock.hh"
#include "PTL/Backtrace.hh"
#include "PTL/Globals.hh"
#include "PTL/TBBTaskGroup.hh"
#include "PTL/Task.hh"
#include "PTL/TaskGroup.hh"
#include "PTL/TaskManager.hh"
@@ -30,9 +27,7 @@
#include "PTL/ThreadData.hh"
#include "PTL/ThreadPool.hh"
#include "PTL/Threading.hh"
#include "PTL/Timer.hh"
#include "PTL/Types.hh"
#include "PTL/UserTaskQueue.hh"
#include "PTL/Utility.hh"
#include "PTL/VTask.hh"
#include "PTL/VUserTaskQueue.hh"
+61
View File
@@ -0,0 +1,61 @@
//
// MIT License
// Copyright (c) 2020 Jonathan R. Madsen
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED
// "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
#pragma once
#include <functional>
#include <utility>
namespace PTL
{
struct ScopeDestructor
{
template <typename FuncT>
ScopeDestructor(FuncT&& _func)
: m_functor(std::forward<FuncT>(_func))
{}
// delete copy operations
ScopeDestructor(const ScopeDestructor&) = delete;
ScopeDestructor& operator=(const ScopeDestructor&) = delete;
// allow move operations
ScopeDestructor(ScopeDestructor&& rhs) noexcept
: m_functor(std::move(rhs.m_functor))
{
rhs.m_functor = []() {};
}
ScopeDestructor& operator=(ScopeDestructor&& rhs) noexcept
{
if(this != &rhs)
{
m_functor = std::move(rhs.m_functor);
rhs.m_functor = []() {};
}
return *this;
}
~ScopeDestructor() { m_functor(); }
private:
std::function<void()> m_functor = []() {};
};
} // namespace PTL
-405
View File
@@ -1,405 +0,0 @@
// MIT License
//
// Copyright (c) 2020 Jonathan R. Madsen
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
//
#pragma once
#include <atomic>
#include <functional>
#include <memory>
#include <mutex>
#include <set>
#include <thread>
#include <type_traits>
namespace PTL
{
/// \class PTL::Singleton
/// \brief Singleton object that allows a deleter class to be specified
///
template <typename Type,
typename PointerT = std::unique_ptr<Type, std::default_delete<Type>>>
class Singleton
{
public:
using this_type = Singleton<Type, PointerT>;
using thread_id_t = std::thread::id;
using mutex_t = std::recursive_mutex;
using auto_lock_t = std::unique_lock<mutex_t>;
using pointer = Type*;
using list_t = std::set<pointer>;
using smart_pointer = PointerT;
using deleter_t = std::function<void(PointerT&)>;
template <bool B, typename T = int>
using enable_if_t = typename std::enable_if<B, T>::type;
public:
// Constructor and Destructors
Singleton();
Singleton(pointer);
~Singleton();
Singleton(const Singleton&) = delete;
Singleton(Singleton&&) = delete;
Singleton& operator=(const Singleton&) = delete;
Singleton& operator=(Singleton&&) = delete;
public:
// public static functions
static pointer GetInstance();
static pointer GetMasterInstance();
static thread_id_t GetMasterThreadID() { return f_master_thread(); }
static list_t Children() { return f_children(); }
static bool IsMaster(pointer ptr) { return ptr == GetRawMasterInstance(); }
static bool IsMasterThread();
static void Insert(pointer);
static void Remove(pointer);
static mutex_t& GetMutex() { return f_mutex(); }
public:
// public member function
void Initialize();
void Initialize(pointer);
void Destroy();
void Reset(pointer);
void Reset();
// since we are overloading delete we overload new
void* operator new(size_t)
{
this_type* ptr = ::new this_type();
return static_cast<void*>(ptr);
}
// overload delete so that f_master_instance is guaranteed to be
// a nullptr after deletion
void operator delete(void* ptr)
{
this_type* _instance = (this_type*) (ptr);
::delete _instance;
if(std::this_thread::get_id() == f_master_thread())
f_master_instance() = nullptr;
}
protected:
friend class Type;
// instance functions that do not Initialize
smart_pointer& GetSmartInstance() { return _local_instance(); }
static smart_pointer& GetSmartMasterInstance() { return _master_instance(); }
// for checking but not allocating
pointer GetRawInstance()
{
return IsMasterThread() ? f_master_instance() : _local_instance().get();
}
static pointer GetRawMasterInstance() { return f_master_instance(); }
private:
// Private functions
static smart_pointer& _local_instance()
{
static thread_local smart_pointer _instance = smart_pointer();
return _instance;
}
static smart_pointer& _master_instance()
{
static smart_pointer _instance = smart_pointer();
return _instance;
}
void* operator new[](std::size_t) noexcept { return nullptr; }
void operator delete[](void*) noexcept {}
template <typename Tp = Type, typename PtrT = PointerT,
enable_if_t<(std::is_same<PtrT, std::shared_ptr<Tp>>::value)> = 0>
deleter_t& GetDeleter()
{
static deleter_t _instance = [](PointerT&) {};
return _instance;
}
template <typename Tp = Type, typename PtrT = PointerT,
enable_if_t<!(std::is_same<PtrT, std::shared_ptr<Tp>>::value)> = 0>
deleter_t& GetDeleter()
{
static deleter_t _instance = [](PointerT& _master) {
auto& del = _master.get_deleter();
del(_master.get());
_master.reset(nullptr);
};
return _instance;
}
private:
// Private variables
struct persistent_data
{
thread_id_t m_master_thread = std::this_thread::get_id();
mutex_t m_mutex;
pointer m_master_instance = nullptr;
list_t m_children = {};
persistent_data() = default;
~persistent_data() = default;
persistent_data(const persistent_data&) = delete;
persistent_data(persistent_data&&) = delete;
persistent_data& operator=(const persistent_data&) = delete;
persistent_data& operator=(persistent_data&&) = delete;
persistent_data(pointer _master, std::thread::id _tid)
: m_master_thread(_tid)
, m_master_instance(_master)
{}
void reset()
{
m_master_instance = nullptr;
m_children.clear();
}
};
bool m_IsMaster = false;
static thread_id_t& f_master_thread();
static mutex_t& f_mutex();
static pointer& f_master_instance();
static list_t& f_children();
static persistent_data& f_persistent_data()
{
static persistent_data _instance;
return _instance;
}
};
//======================================================================================//
template <typename Type, typename PointerT>
typename Singleton<Type, PointerT>::thread_id_t&
Singleton<Type, PointerT>::f_master_thread()
{
return f_persistent_data().m_master_thread;
}
//--------------------------------------------------------------------------------------//
template <typename Type, typename PointerT>
typename Singleton<Type, PointerT>::pointer&
Singleton<Type, PointerT>::f_master_instance()
{
return f_persistent_data().m_master_instance;
}
//--------------------------------------------------------------------------------------//
template <typename Type, typename PointerT>
typename Singleton<Type, PointerT>::mutex_t&
Singleton<Type, PointerT>::f_mutex()
{
return f_persistent_data().m_mutex;
}
//--------------------------------------------------------------------------------------//
template <typename Type, typename PointerT>
typename Singleton<Type, PointerT>::list_t&
Singleton<Type, PointerT>::f_children()
{
return f_persistent_data().m_children;
}
//--------------------------------------------------------------------------------------//
template <typename Type, typename PointerT>
Singleton<Type, PointerT>::Singleton()
{
Initialize();
}
//--------------------------------------------------------------------------------------//
template <typename Type, typename PointerT>
Singleton<Type, PointerT>::Singleton(pointer ptr)
{
Initialize(ptr);
}
//--------------------------------------------------------------------------------------//
template <typename Type, typename PointerT>
Singleton<Type, PointerT>::~Singleton()
{
auto& del = GetDeleter();
del(_master_instance());
}
//--------------------------------------------------------------------------------------//
template <typename Type, typename PointerT>
void
Singleton<Type, PointerT>::Initialize()
{
if(!f_master_instance())
{
f_master_thread() = std::this_thread::get_id();
f_master_instance() = new Type();
}
}
//--------------------------------------------------------------------------------------//
template <typename Type, typename PointerT>
void
Singleton<Type, PointerT>::Initialize(pointer ptr)
{
if(!f_master_instance())
{
f_master_thread() = std::this_thread::get_id();
f_master_instance() = ptr;
}
}
//--------------------------------------------------------------------------------------//
template <typename Type, typename PointerT>
void
Singleton<Type, PointerT>::Destroy()
{
if(std::this_thread::get_id() == f_master_thread() && f_master_instance())
{
delete f_master_instance();
f_master_instance() = nullptr;
}
else
{
remove(_local_instance().get());
}
}
//--------------------------------------------------------------------------------------//
template <typename Type, typename PointerT>
typename Singleton<Type, PointerT>::pointer
Singleton<Type, PointerT>::GetInstance()
{
if(std::this_thread::get_id() == f_master_thread())
return GetMasterInstance();
else if(!_local_instance().get())
{
_local_instance().reset(new Type());
Insert(_local_instance().get());
}
return _local_instance().get();
}
//--------------------------------------------------------------------------------------//
template <typename Type, typename PointerT>
typename Singleton<Type, PointerT>::pointer
Singleton<Type, PointerT>::GetMasterInstance()
{
if(!f_master_instance())
{
f_master_thread() = std::this_thread::get_id();
f_master_instance() = new Type();
}
return f_master_instance();
}
//--------------------------------------------------------------------------------------//
template <typename Type, typename PointerT>
void
Singleton<Type, PointerT>::Reset(pointer ptr)
{
if(IsMaster(ptr))
{
if(_master_instance().get())
_master_instance().reset();
else if(f_master_instance())
{
auto& del = GetDeleter();
del(_master_instance());
f_master_instance() = nullptr;
}
f_persistent_data().reset();
}
else
{
_local_instance().reset();
}
}
//--------------------------------------------------------------------------------------//
template <typename Type, typename PointerT>
void
Singleton<Type, PointerT>::Reset()
{
if(IsMasterThread())
_master_instance().reset();
_local_instance().reset();
f_persistent_data().reset();
}
//--------------------------------------------------------------------------------------//
template <typename Type, typename PointerT>
bool
Singleton<Type, PointerT>::IsMasterThread()
{
return std::this_thread::get_id() == f_master_thread();
}
//--------------------------------------------------------------------------------------//
template <typename Type, typename PointerT>
void
Singleton<Type, PointerT>::Insert(pointer itr)
{
auto_lock_t l(f_mutex());
f_children().insert(itr);
}
//--------------------------------------------------------------------------------------//
template <typename Type, typename PointerT>
void
Singleton<Type, PointerT>::Remove(pointer itr)
{
auto_lock_t l(f_mutex());
for(auto litr = f_children().begin(); litr != f_children().end(); ++litr)
{
if(*litr == itr)
{
f_children().erase(litr);
break;
}
}
}
//--------------------------------------------------------------------------------------//
} // namespace PTL
+3 -3
View File
@@ -30,8 +30,8 @@
#pragma once
#include "PTL/Globals.hh"
#include "PTL/VTask.hh"
#include "PTL/detail/CxxBackports.hh"
#include <cstdint>
#include <future>
@@ -113,7 +113,7 @@ public:
public:
// execution operator
void operator()() final { mpl::apply(std::move(m_ptask), std::move(m_args)); }
void operator()() final { PTL::apply(std::move(m_ptask), std::move(m_args)); }
future_type get_future() final { return m_ptask.get_future(); }
void wait() final { return m_ptask.get_future().wait(); }
RetT get() final { return m_ptask.get_future().get(); }
@@ -165,7 +165,7 @@ public:
void operator()() final
{
if(m_ptask.valid())
mpl::apply(std::move(m_ptask), std::move(m_args));
PTL::apply(std::move(m_ptask), std::move(m_args));
}
future_type get_future() final { return m_ptask.get_future(); }
void wait() final { return m_ptask.get_future().wait(); }
+6 -5
View File
@@ -35,15 +35,15 @@
#ifndef G4GMAKE
#include "PTL/Config.hh"
#endif
#include "PTL/Globals.hh"
#include "PTL/JoinFunction.hh"
#include "PTL/ScopeDestructor.hh"
#include "PTL/Task.hh"
#include "PTL/ThreadData.hh"
#include "PTL/ThreadPool.hh"
#include "PTL/Threading.hh"
#include "PTL/Utility.hh"
#include "PTL/Types.hh"
#include "PTL/VTask.hh"
#include "PTL/VUserTaskQueue.hh"
#include "PTL/detail/CxxBackports.hh"
#include <atomic>
#include <chrono>
@@ -54,6 +54,7 @@
#include <iostream>
#include <memory>
#include <mutex>
#include <sstream> // IWYU pragma: keep
#include <stdexcept>
#include <thread>
#include <type_traits>
@@ -61,7 +62,7 @@
#include <vector>
#if defined(PTL_USE_TBB)
# include <tbb/task_group.h>
# include <tbb/task_group.h> // IWYU pragma: keep
#endif
namespace PTL
@@ -733,6 +734,6 @@ TaskGroup<Tp, Arg, MaxDepth>::internal_update()
}
template <typename Tp, typename Arg, intmax_t MaxDepth>
int TaskGroup<Tp, Arg, MaxDepth>::f_verbose = GetEnv<int>("PTL_VERBOSE", 0);
int TaskGroup<Tp, Arg, MaxDepth>::f_verbose = 0;
} // namespace PTL
+1 -1
View File
@@ -30,7 +30,7 @@
#pragma once
#include "PTL/Globals.hh"
#include "PTL/Macros.hh"
#include "PTL/Task.hh"
#include "PTL/TaskGroup.hh"
#include "PTL/ThreadPool.hh"
+2 -4
View File
@@ -26,7 +26,6 @@
#pragma once
#include "PTL/ThreadPool.hh"
#include "PTL/VUserTaskQueue.hh"
#include <cstddef>
#include <cstdint>
@@ -35,6 +34,7 @@
namespace PTL
{
class TaskManager;
class VUserTaskQueue;
//======================================================================================//
@@ -68,8 +68,6 @@ public:
ThreadPool* GetThreadPool() const { return m_thread_pool; }
TaskManager* GetTaskManager() const { return m_task_manager; }
bool IsInitialized() const { return m_is_initialized; }
int GetVerbose() const { return m_verbose; }
void SetVerbose(int val) { m_verbose = val; }
public: // with description
// Singleton implementing master thread behavior
@@ -83,8 +81,8 @@ private:
protected:
// Barriers: synch points between master and workers
bool m_is_initialized = false;
int m_verbose = 0;
uint64_t m_workers = 0;
bool m_use_tbb = false;
VUserTaskQueue* m_task_queue = nullptr;
ThreadPool* m_thread_pool = nullptr;
TaskManager* m_task_manager = nullptr;
+1 -1
View File
@@ -20,7 +20,7 @@
#ifndef G4GMAKE
#include "PTL/Config.hh" // IWYU pragma: keep
#endif
#include "PTL/Globals.hh"
#include "PTL/Macros.hh"
#include "PTL/VTask.hh"
#if defined(PTL_USE_LOCKS)
# include "PTL/AutoLock.hh"
+11 -50
View File
@@ -138,16 +138,11 @@ public:
struct Config
{
PTL_DEFAULT_OBJECT(Config)
Config(bool, bool, bool, int, int, size_type, VUserTaskQueue*, affinity_func_t,
initialize_func_t, finalize_func_t);
bool init = true;
bool use_tbb = f_use_tbb();
bool use_affinity = f_use_cpu_affinity();
int verbose = f_verbose();
int priority = f_thread_priority();
bool use_tbb = false;
bool use_affinity = false;
int verbose = 0;
int priority = 0;
size_type pool_size = f_default_pool_size();
VUserTaskQueue* task_queue = nullptr;
affinity_func_t set_affinity = affinity_functor();
@@ -158,16 +153,7 @@ public:
public:
// Constructor and Destructors
explicit ThreadPool(const Config&);
ThreadPool(const size_type& pool_size, VUserTaskQueue* task_queue = nullptr,
bool _use_affinity = f_use_cpu_affinity(),
affinity_func_t = affinity_functor(),
initialize_func_t = initialization_functor(),
finalize_func_t = finalization_functor());
ThreadPool(const size_type& pool_size, initialize_func_t, finalize_func_t,
bool _use_affinity = f_use_cpu_affinity(),
affinity_func_t = affinity_functor(),
VUserTaskQueue* task_queue = nullptr);
virtual ~ThreadPool();
~ThreadPool();
ThreadPool(const ThreadPool&) = delete;
ThreadPool(ThreadPool&&) = default;
ThreadPool& operator=(const ThreadPool&) = delete;
@@ -192,30 +178,9 @@ public:
bool is_tbb_threadpool() const { return m_tbb_tp; }
public:
// Public functions related to TBB
static bool using_tbb();
// enable using TBB if available - semi-deprecated
static void set_use_tbb(bool _v);
/// set the default use of tbb
static void set_default_use_tbb(bool _v) { set_use_tbb(_v); }
/// set the default use of cpu affinity
static void set_default_use_cpu_affinity(bool _v);
/// set the default scheduling priority of threads in thread-pool
static void set_default_scheduling_priority(int _v) { f_thread_priority() = _v; }
/// set the default verbosity
static void set_default_verbose(int _v) { f_verbose() = _v; }
/// set the default pool size
static void set_default_size(size_type _v) { f_default_pool_size() = _v; }
/// get the default use of tbb
static bool get_default_use_tbb() { return f_use_tbb(); }
/// get the default use of cpu affinity
static bool get_default_use_cpu_affinity() { return f_use_cpu_affinity(); }
/// get the default scheduling priority of threads in thread-pool
static int get_default_scheduling_priority() { return f_thread_priority(); }
/// get the default verbosity
static int get_default_verbose() { return f_verbose(); }
/// get the default pool size
static size_type get_default_size() { return f_default_pool_size(); }
@@ -278,12 +243,12 @@ public:
static uintmax_t get_this_thread_id();
static uintmax_t add_thread_id(ThreadId = ThisThread::get_id());
protected:
private:
void execute_thread(VUserTaskQueue*); // function thread sits in
int insert(task_pointer&&, int = -1);
int run_on_this(task_pointer&&);
protected:
private:
// called in THREAD INIT
static void start_thread(ThreadPool*, thread_data_t*, intmax_t = -1);
@@ -296,8 +261,8 @@ private:
bool m_use_affinity = false;
bool m_tbb_tp = false;
bool m_delete_task_queue = false;
int m_verbose = f_verbose();
int m_priority = f_thread_priority();
int m_verbose = 0;
int m_priority = 0;
size_type m_pool_size = 0;
ThreadId m_main_tid = ThisThread::get_id();
atomic_bool_type m_alive_flag = std::make_shared<std::atomic_bool>(false);
@@ -329,10 +294,6 @@ private:
affinity_func_t m_affinity_func = affinity_functor();
private:
static bool& f_use_tbb();
static bool& f_use_cpu_affinity();
static int& f_thread_priority();
static int& f_verbose();
static size_type& f_default_pool_size();
static thread_id_map_t& f_thread_ids();
};
@@ -531,7 +492,7 @@ ThreadPool::execute_on_all_threads(FuncT&& _func)
// size of the thread-pool
size_t _sz = size();
// number of cores
size_t _ncore = Threading::GetNumberOfCores();
size_t _ncore = GetNumberOfCores();
// maximum depth for recursion
size_t _dmax = std::max<size_t>(_ncore, 8);
// how many threads we need to initialize
@@ -643,7 +604,7 @@ ThreadPool::execute_on_specific_threads(const std::set<std::thread::id>& _tids,
// executed the _exec function above
std::atomic<size_t> _total_exec{ 0 };
// number of cores
size_t _ncore = Threading::GetNumberOfCores();
size_t _ncore = GetNumberOfCores();
// maximum depth for recursion
size_t _dmax = std::max<size_t>(_ncore, 8);
// how many threads we need to initialize
+7 -56
View File
@@ -21,64 +21,15 @@
//
// Class Description:
//
// This file defines types and macros used to expose Tasking threading model.
#pragma once
#include <array>
#include <cstddef>
#include <future>
#include <mutex>
#include <thread>
namespace PTL
{
// global thread types
using Thread = std::thread;
using NativeThread = std::thread::native_handle_type;
// std::thread::id does not cast to integer
using Pid_t = std::thread::id;
// Condition
using Condition = std::condition_variable;
// Thread identifier
using ThreadId = Thread::id;
// will be used in the future when migrating threading to task-based style
template <typename Tp>
using Future = std::future<Tp>;
template <typename Tp>
using SharedFuture = std::shared_future<Tp>;
template <typename Tp>
using Promise = std::promise<Tp>;
// global mutex types
using Mutex = std::mutex;
using RecursiveMutex = std::recursive_mutex;
// static functions: get_id(), sleep_for(...), sleep_until(...), yield(),
namespace ThisThread
{
using namespace std::this_thread;
}
// Helper function for getting a unique static mutex for a specific
// class or type
// Usage example:
// a template class "Cache<T>" that required a static
// mutex for specific to type T:
// AutoLock l(TypeMutex<Cache<T>>());
template <typename Tp, typename MutexTp = Mutex, size_t N = 4>
MutexTp&
TypeMutex(const unsigned int& _n = 0)
{
static std::array<MutexTp, N> _mutex_array{};
return _mutex_array[_n % N];
}
//======================================================================================//
#pragma once
#include "PTL/Types.hh"
namespace PTL
{
namespace Threading
{
enum
@@ -88,6 +39,7 @@ enum
WORKER_ID = 0,
GENERICTHREAD_ID = -1000
};
}
Pid_t
GetPidId();
@@ -116,5 +68,4 @@ SetPinAffinity(int idx, NativeThread& _t);
bool
SetThreadPriority(int _v, NativeThread& _t);
} // namespace Threading
} // namespace PTL
-194
View File
@@ -1,194 +0,0 @@
//
// MIT License
// Copyright (c) 2019 Jonathan R. Madsen
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED
// "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
// ----------------------------------------------------------------------
// Class Timer
//
// Class description:
//
// Class for timer objects, able to measure elasped user/system process time.
//
// Note: Uses <sys/times.h> & <unistd.h> - POSIX.1 defined
// If used, this header must be included in the source (.cc) file and it
// must be the first header file to be included!
//
// Member functions:
//
// Timer()
// Construct a timer object
// Start()
// Start timing
// Stop()
// Stop timing
// bool IsValid()
// Return true if have a valid time (ie start() and stop() called)
// double GetRealElapsed()
// Return the elapsed real time between last calling start() and stop()
// double GetSystemElapsed()
// Return the elapsed system time between last calling start() and stop()
// double GetUserElapsed()
// Return the elapsed user time between last calling start() and stop()
//
// Operators:
//
// std::ostream& operator << (std::ostream& os, const Timer& t);
// Print the elapsed real,system and usertimes on os. Prints **s for times
// if !IsValid
//
// Member data:
//
// bool fValidTimes
// True after start and stop have both been called more than once and
// an equal number of times
// clock_t fStartRealTime,fEndRealTime
// Real times (arbitrary time 0)
// tms fStartTimes,fEndTimes
// Timing structures (see times(2)) for start and end times
// History:
// 23.08.96 P.Kent Updated to also computed real elapsed time
// 21.08.95 P.Kent
// 29.04.97 G.Cosmo Added timings for Windows/NT
#pragma once
#include "PTL/Types.hh"
#include <chrono>
#include <iomanip>
#include <sstream>
#if !(defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64))
# include <sys/times.h>
# include <time.h>
#else
# include <ctime>
# define _SC_CLK_TCK 1
extern "C"
{
int sysconf(int);
};
// Structure returned by times()
struct tms
{
clock_t tms_utime; /* user time */
clock_t tms_stime; /* system time */
clock_t tms_cutime; /* user time, children */
clock_t tms_cstime; /* system time, children */
};
extern "C"
{
extern clock_t times(struct tms*);
};
#endif /* WIN32 */
namespace PTL
{
class Timer
{
public:
PTL_DEFAULT_OBJECT(Timer)
public:
void Start();
void Stop();
bool IsValid() const;
double GetRealElapsed() const;
double GetSystemElapsed() const;
double GetUserElapsed() const;
static const char* GetClockTime();
private:
bool fValidTimes{ false };
using clock_type = std::chrono::high_resolution_clock;
std::chrono::time_point<clock_type> fStartRealTime, fEndRealTime;
tms fStartTimes, fEndTimes;
};
// ------------------------------------------------------------
// class inline implementation
// ------------------------------------------------------------
inline void
Timer::Start()
{
fValidTimes = false;
times(&fStartTimes);
fStartRealTime = clock_type::now();
}
inline void
Timer::Stop()
{
times(&fEndTimes);
fEndRealTime = clock_type::now();
fValidTimes = true;
}
inline bool
Timer::IsValid() const
{
return fValidTimes;
}
inline const char*
Timer::GetClockTime()
{
time_t rawtime;
struct tm* timeinfo;
time(&rawtime);
timeinfo = localtime(&rawtime);
return asctime(timeinfo);
}
inline std::ostream&
operator<<(std::ostream& os, const Timer& t)
{
// so fixed doesn't propagate
std::stringstream ss;
ss << std::fixed;
if(t.IsValid())
{
ss << "Real=" << t.GetRealElapsed() << "s User=" << t.GetUserElapsed()
<< "s Sys=" << t.GetSystemElapsed() << "s";
// avoid possible FPE error
if(t.GetRealElapsed() > 1.0e-6)
{
double cpu_util =
(t.GetUserElapsed() + t.GetSystemElapsed()) / t.GetRealElapsed() * 100.0;
ss << std::setprecision(1);
ss << " [Cpu=" << std::setprecision(1) << cpu_util << "%]";
}
}
else
{
ss << "Real=****s User=****s Sys=****s";
}
os << ss.str();
return os;
}
} // namespace PTL
+52 -65
View File
@@ -21,73 +21,60 @@
#pragma once
#if defined(__APPLE__) || defined(__MACH__)
# if !defined(PTL_MACOS)
# define PTL_MACOS 1
# endif
# if !defined(PTL_UNIX)
# define PTL_UNIX 1
# endif
#endif
// This file defines types used to expose Tasking threading model.
#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)
# if !defined(PTL_WINDOWS)
# define PTL_WINDOWS 1
# endif
#endif
#pragma once
#if defined(__linux__) || defined(__linux) || defined(linux) || defined(__gnu_linux__)
# if !defined(PTL_LINUX)
# define PTL_LINUX 1
# endif
# if !defined(PTL_UNIX)
# define PTL_UNIX 1
# endif
#endif
#include <array>
#include <cstddef>
#include <future>
#include <mutex>
#include <thread>
#if defined(__unix__) || defined(__unix) || defined(unix)
# if !defined(PTL_UNIX)
# define PTL_UNIX 1
# endif
#endif
namespace PTL
{
// global thread types
using Thread = std::thread;
using NativeThread = std::thread::native_handle_type;
// std::thread::id does not cast to integer
using Pid_t = std::thread::id;
#if defined(PTL_WINDOWS)
// Disable warning C4786 on WIN32 architectures:
// identifier was truncated to '255' characters
// in the debug information
//
# pragma warning(disable : 4786)
//
// Define DLL export macro for WIN32 systems for
// importing/exporting external symbols to DLLs
//
# if defined PTL_BUILD_DLL
# define DLLEXPORT __declspec(dllexport)
# define DLLIMPORT __declspec(dllimport)
# else
# define DLLEXPORT
# define DLLIMPORT
# endif
//
// Unique identifier for global module
//
# if defined PTL_ALLOC_EXPORT
# define PTL_DLL DLLEXPORT
# else
# define PTL_DLL DLLIMPORT
# endif
#else
# define DLLEXPORT
# define DLLIMPORT
# define PTL_DLL
#endif
// Condition
using Condition = std::condition_variable;
#if !defined(PTL_DEFAULT_OBJECT)
# define PTL_DEFAULT_OBJECT(NAME) \
NAME() = default; \
~NAME() = default; \
NAME(const NAME&) = default; \
NAME(NAME&&) = default; \
NAME& operator=(const NAME&) = default; \
NAME& operator=(NAME&&) = default;
#endif
// Thread identifier
using ThreadId = Thread::id;
// will be used in the future when migrating threading to task-based style
template <typename Tp>
using Future = std::future<Tp>;
template <typename Tp>
using SharedFuture = std::shared_future<Tp>;
template <typename Tp>
using Promise = std::promise<Tp>;
// global mutex types
using Mutex = std::mutex;
using RecursiveMutex = std::recursive_mutex;
// static functions: get_id(), sleep_for(...), sleep_until(...), yield(),
namespace ThisThread
{
using namespace std::this_thread;
}
// Helper function for getting a unique static mutex for a specific
// class or type
// Usage example:
// a template class "Cache<T>" that required a static
// mutex for specific to type T:
// AutoLock l(TypeMutex<Cache<T>>());
template <typename Tp, typename MutexTp = Mutex, size_t N = 4>
MutexTp&
TypeMutex(const unsigned int& _n = 0)
{
static std::array<MutexTp, N> _mutex_array{};
return _mutex_array[_n % N];
}
} // namespace PTL
+6 -3
View File
@@ -25,10 +25,9 @@
#pragma once
#include "PTL/Globals.hh"
#include "PTL/Macros.hh"
#include "PTL/TaskSubQueue.hh"
#include "PTL/Threading.hh"
#include "PTL/VTask.hh"
#include "PTL/Types.hh"
#include "PTL/VUserTaskQueue.hh"
#include <atomic>
@@ -39,6 +38,10 @@
namespace PTL
{
class ThreadData;
class ThreadPool;
class VTask;
class UserTaskQueue : public VUserTaskQueue
{
public:
-402
View File
@@ -1,402 +0,0 @@
//
// MIT License
// Copyright (c) 2020 Jonathan R. Madsen
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED
// "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
// Global utility functions
//
#pragma once
#include <cctype>
#include <cstdlib>
#include <functional>
#include <iomanip>
#include <iostream>
#include <map>
#include <mutex>
#include <set>
#include <sstream> // IWYU pragma: keep
#include <string>
#include <tuple>
#include <utility>
namespace PTL
{
//--------------------------------------------------------------------------------------//
// use this function to get rid of "unused parameter" warnings
//
template <typename... Args>
void
ConsumeParameters(Args&&...)
{}
//--------------------------------------------------------------------------------------//
// a non-string environment option with a string identifier
template <typename Tp>
using EnvChoice = std::tuple<Tp, std::string, std::string>;
//--------------------------------------------------------------------------------------//
// list of environment choices with non-string and string identifiers
template <typename Tp>
using EnvChoiceList = std::set<EnvChoice<Tp>>;
//--------------------------------------------------------------------------------------//
class EnvSettings
{
public:
using mutex_t = std::mutex;
using string_t = std::string;
using env_map_t = std::multimap<string_t, string_t>;
using env_pair_t = std::pair<string_t, string_t>;
public:
static EnvSettings* GetInstance()
{
static EnvSettings* _instance = new EnvSettings();
return _instance;
}
public:
template <typename Tp>
void insert(const std::string& env_id, Tp val)
{
std::stringstream ss;
ss << std::boolalpha << val;
m_mutex.lock();
if(m_env.find(env_id) != m_env.end())
{
for(const auto& itr : m_env)
if(itr.first == env_id && itr.second == ss.str())
{
m_mutex.unlock();
return;
}
}
m_env.insert(env_pair_t(env_id, ss.str()));
m_mutex.unlock();
}
template <typename Tp>
void insert(const std::string& env_id, EnvChoice<Tp> choice)
{
Tp& val = std::get<0>(choice);
std::string& str_val = std::get<1>(choice);
std::string& descript = std::get<2>(choice);
std::stringstream ss, ss_long;
ss << std::boolalpha << val;
ss_long << std::boolalpha << std::setw(8) << std::left << val << " # (\""
<< str_val << "\") " << descript;
m_mutex.lock();
if(m_env.find(env_id) != m_env.end())
{
for(const auto& itr : m_env)
if(itr.first == env_id && itr.second == ss.str())
{
m_mutex.unlock();
return;
}
}
m_env.insert(env_pair_t(env_id, ss_long.str()));
m_mutex.unlock();
}
const env_map_t& get() const { return m_env; }
mutex_t& mutex() const { return m_mutex; }
friend std::ostream& operator<<(std::ostream& os, const EnvSettings& env)
{
std::stringstream filler;
filler.fill('#');
filler << std::setw(90) << "";
std::stringstream ss;
ss << filler.str() << "\n# Environment settings:\n";
env.mutex().lock();
for(const auto& itr : env.get())
{
ss << "# " << std::setw(35) << std::right << itr.first << "\t = \t"
<< std::left << itr.second << "\n";
}
env.mutex().unlock();
ss << filler.str();
os << ss.str() << std::endl;
return os;
}
private:
env_map_t m_env;
mutable mutex_t m_mutex;
};
//--------------------------------------------------------------------------------------//
// use this function to get an environment variable setting +
// a default if not defined, e.g.
// int num_threads =
// GetEnv<int>("FORCENUMBEROFTHREADS",
// std::thread::hardware_concurrency());
//
template <typename Tp>
Tp
GetEnv(const std::string& env_id, Tp _default = Tp())
{
char* env_var = std::getenv(env_id.c_str());
if(env_var)
{
std::string str_var = std::string(env_var);
std::istringstream iss(str_var);
Tp var = Tp();
iss >> var;
// record value defined by environment
EnvSettings::GetInstance()->insert<Tp>(env_id, var);
return var;
}
// record default value
EnvSettings::GetInstance()->insert<Tp>(env_id, _default);
// return default if not specified in environment
return _default;
}
//--------------------------------------------------------------------------------------//
// overload for boolean
//
template <>
inline bool
GetEnv(const std::string& env_id, bool _default)
{
char* env_var = std::getenv(env_id.c_str());
if(env_var)
{
std::string var = std::string(env_var);
bool val = true;
if(var.find_first_not_of("0123456789") == std::string::npos)
val = (bool) atoi(var.c_str());
else
{
for(auto& itr : var)
itr = (char)std::tolower(itr);
if(var == "off" || var == "false")
val = false;
}
// record value defined by environment
EnvSettings::GetInstance()->insert<bool>(env_id, val);
return val;
}
// record default value
EnvSettings::GetInstance()->insert<bool>(env_id, false);
// return default if not specified in environment
return _default;
}
//--------------------------------------------------------------------------------------//
// overload for GetEnv + message when set
//
template <typename Tp>
Tp
GetEnv(const std::string& env_id, Tp _default, const std::string& msg)
{
char* env_var = std::getenv(env_id.c_str());
if(env_var)
{
std::string str_var = std::string(env_var);
std::istringstream iss(str_var);
Tp var = Tp();
iss >> var;
std::cout << "Environment variable \"" << env_id << "\" enabled with "
<< "value == " << var << ". " << msg << std::endl;
// record value defined by environment
EnvSettings::GetInstance()->insert<Tp>(env_id, var);
return var;
}
// record default value
EnvSettings::GetInstance()->insert<Tp>(env_id, _default);
// return default if not specified in environment
return _default;
}
//--------------------------------------------------------------------------------------//
// use this function to get an environment variable setting from set of choices
//
// EnvChoiceList<int> choices =
// { EnvChoice<int>(NN, "NN", "nearest neighbor interpolation"),
// EnvChoice<int>(LINEAR, "LINEAR", "bilinear interpolation"),
// EnvChoice<int>(CUBIC, "CUBIC", "bicubic interpolation") };
//
// int eInterp = GetEnv<int>("INTERPOLATION", choices, CUBIC);
//
template <typename Tp>
Tp
GetEnv(const std::string& env_id, const EnvChoiceList<Tp>& _choices, Tp _default)
{
auto asupper = [](std::string var) {
for(auto& itr : var)
itr = (char)std::toupper(itr);
return var;
};
char* env_var = std::getenv(env_id.c_str());
if(env_var)
{
std::string str_var = std::string(env_var);
std::string upp_var = asupper(str_var);
Tp var = Tp();
// check to see if string matches a choice
for(const auto& itr : _choices)
{
if(asupper(std::get<1>(itr)) == upp_var)
{
// record value defined by environment
EnvSettings::GetInstance()->insert(env_id, itr);
return std::get<0>(itr);
}
}
std::istringstream iss(str_var);
iss >> var;
// check to see if string matches a choice
for(const auto& itr : _choices)
{
if(var == std::get<0>(itr))
{
// record value defined by environment
EnvSettings::GetInstance()->insert(env_id, itr);
return var;
}
}
// the value set in env did not match any choices
std::stringstream ss;
ss << "\n### Environment setting error @ " << __FUNCTION__ << " (line "
<< __LINE__ << ")! Invalid selection for \"" << env_id
<< "\". Valid choices are:\n";
for(const auto& itr : _choices)
ss << "\t\"" << std::get<0>(itr) << "\" or \"" << std::get<1>(itr) << "\" ("
<< std::get<2>(itr) << ")\n";
std::cerr << ss.str() << std::endl;
abort();
}
std::string _name = "???";
std::string _desc = "description not provided";
for(const auto& itr : _choices)
if(std::get<0>(itr) == _default)
{
_name = std::get<1>(itr);
_desc = std::get<2>(itr);
break;
}
// record default value
EnvSettings::GetInstance()->insert(env_id, EnvChoice<Tp>(_default, _name, _desc));
// return default if not specified in environment
return _default;
}
//--------------------------------------------------------------------------------------//
template <typename Tp>
Tp
GetChoice(const EnvChoiceList<Tp>& _choices, const std::string& str_var)
{
auto asupper = [](std::string var) {
for(auto& itr : var)
itr = (char)std::toupper(itr);
return var;
};
std::string upp_var = asupper(str_var);
Tp var = Tp();
// check to see if string matches a choice
for(const auto& itr : _choices)
{
if(asupper(std::get<1>(itr)) == upp_var)
{
// record value defined by environment
return std::get<0>(itr);
}
}
std::istringstream iss(str_var);
iss >> var;
// check to see if string matches a choice
for(const auto& itr : _choices)
{
if(var == std::get<0>(itr))
{
// record value defined by environment
return var;
}
}
// the value set in env did not match any choices
std::stringstream ss;
ss << "\n### Environment setting error @ " << __FUNCTION__ << " (line " << __LINE__
<< ")! Invalid selection \"" << str_var << "\". Valid choices are:\n";
for(const auto& itr : _choices)
ss << "\t\"" << std::get<0>(itr) << "\" or \"" << std::get<1>(itr) << "\" ("
<< std::get<2>(itr) << ")\n";
std::cerr << ss.str() << std::endl;
abort();
}
//--------------------------------------------------------------------------------------//
inline void
PrintEnv(std::ostream& os = std::cout)
{
os << (*EnvSettings::GetInstance());
}
//--------------------------------------------------------------------------------------//
struct ScopeDestructor
{
template <typename FuncT>
ScopeDestructor(FuncT&& _func)
: m_functor(std::forward<FuncT>(_func))
{}
// delete copy operations
ScopeDestructor(const ScopeDestructor&) = delete;
ScopeDestructor& operator=(const ScopeDestructor&) = delete;
// allow move operations
ScopeDestructor(ScopeDestructor&& rhs) noexcept
: m_functor(std::move(rhs.m_functor))
{
rhs.m_functor = []() {};
}
ScopeDestructor& operator=(ScopeDestructor&& rhs) noexcept
{
if(this != &rhs)
{
m_functor = std::move(rhs.m_functor);
rhs.m_functor = []() {};
}
return *this;
}
~ScopeDestructor() { m_functor(); }
private:
std::function<void()> m_functor = []() {};
};
//--------------------------------------------------------------------------------------//
} // namespace PTL
+2 -2
View File
@@ -27,8 +27,8 @@
#pragma once
#include "PTL/Globals.hh"
#include "PTL/Threading.hh"
#include "PTL/Macros.hh"
#include "PTL/Types.hh"
#include <atomic>
#include <cstdint>
@@ -19,48 +19,25 @@
#pragma once
#include <algorithm> // Retrieve definitions of min/max
#include "PTL/ConsumeParameters.hh"
// Include base types
#include "PTL/Types.hh"
// Global utility functions
#include "PTL/Utility.hh"
#include <initializer_list>
#include <cstddef>
#include <tuple>
#include <type_traits>
#include <utility>
#if !defined(PTL_NO_SANITIZE_THREAD)
// expect that sanitizer is from compiler which supports __has_attribute
# if defined(__has_attribute)
# if __has_attribute(no_sanitize)
# define PTL_NO_SANITIZE_THREAD __attribute__((no_sanitize("thread")))
# else
# define PTL_NO_SANITIZE_THREAD
# endif
# elif defined(__clang__) || defined(__GNUC__)
# define PTL_NO_SANITIZE_THREAD __attribute__((no_sanitize("thread")))
# else
// otherwise, make blank
# define PTL_NO_SANITIZE_THREAD
# endif
#endif
/// Backports of C++ language features for use with C++11 compilers
namespace PTL
{
// Convenience wrappers
template <typename T>
using decay_t = typename std::decay<T>::type;
template <bool B, typename T = void>
using enable_if_t = typename std::enable_if<B, T>::type;
// for pre-C++14 tuple expansion to arguments
namespace mpl
{
//--------------------------------------------------------------------------------------//
/// Provision of tuple expansion to arguments
namespace impl
{
//--------------------------------------------------------------------------------------//
@@ -130,13 +107,6 @@ using index_sequence = integer_sequence<size_t, Idx...>;
template <size_t NumT>
using make_index_sequence = make_integer_sequence<size_t, NumT>;
/// Alias template index_sequence_for
template <typename... Types>
using index_sequence_for = make_index_sequence<sizeof...(Types)>;
template <size_t Idx, typename Tup>
using index_type_t = decay_t<decltype(std::get<Idx>(std::declval<Tup>()))>;
template <typename FnT, typename TupleT, size_t... Idx>
static inline auto
apply(FnT&& _func, TupleT _args, impl::index_sequence<Idx...>)
@@ -158,30 +128,14 @@ apply(FnT&& _func, TupleT _args, impl::index_sequence<Idx...>)
//--------------------------------------------------------------------------------------//
/// Alias template index_sequence
template <size_t... Idx>
using index_sequence = impl::integer_sequence<size_t, Idx...>;
/// Alias template make_index_sequence
template <size_t NumT>
using make_index_sequence = impl::make_integer_sequence<size_t, NumT>;
/// Alias template index_sequence_for
template <typename... Types>
using index_sequence_for = impl::make_index_sequence<sizeof...(Types)>;
template <typename FnT, typename TupleT>
static inline void
apply(FnT&& _func, TupleT&& _args)
{
using tuple_type = typename std::decay<TupleT>::type;
using tuple_type = decay_t<TupleT>;
constexpr auto N = std::tuple_size<tuple_type>::value;
impl::apply(std::forward<FnT>(_func), std::forward<TupleT>(_args),
impl::make_index_sequence<N>{});
}
//--------------------------------------------------------------------------------------//
} // namespace mpl
} // namespace PTL
+7 -2
View File
@@ -4,22 +4,25 @@
# Locate sources and headers for this project - headers are included so they will show up
# in IDEs
file(GLOB_RECURSE ptl_headers ${PROJECT_SOURCE_DIR}/include/PTL/*.hh
${PROJECT_SOURCE_DIR}/include/PTL/*.icc)
${PROJECT_SOURCE_DIR}/include/PTL/detail/*.hh)
file(GLOB_RECURSE ptl_sources ${CMAKE_CURRENT_LIST_DIR}/*.cc)
# -------------------------------------------------------------------------------------- #
# Config, Version
# -------------------------------------------------------------------------------------- #
set(ptl_generated_headers)
configure_file(${PROJECT_SOURCE_DIR}/cmake/Templates/Config.hh.in
${CMAKE_CURRENT_BINARY_DIR}/PTL/Config.hh @ONLY)
list(APPEND ptl_headers ${CMAKE_CURRENT_BINARY_DIR}/PTL/Config.hh)
list(APPEND ptl_generated_headers ${CMAKE_CURRENT_BINARY_DIR}/PTL/Config.hh)
configure_file(${PROJECT_SOURCE_DIR}/cmake/Templates/Version.hh.in
${CMAKE_CURRENT_BINARY_DIR}/PTL/Version.hh @ONLY)
list(APPEND ptl_headers ${CMAKE_CURRENT_BINARY_DIR}/PTL/Version.hh)
list(APPEND ptl_generated_headers ${CMAKE_CURRENT_BINARY_DIR}/PTL/Version.hh)
# -------------------------------------------------------------------------------------- #
# PTL Library
@@ -116,8 +119,10 @@ endif()
if(PTL_INSTALL_HEADERS)
# headers
install(DIRECTORY ${PROJECT_SOURCE_DIR}/include/PTL
DESTINATION ${PTL_INSTALL_INCLUDEDIR})
install(
FILES ${ptl_headers}
FILES ${ptl_generated_headers}
DESTINATION ${PTL_INSTALL_INCLUDEDIR}/PTL
COMPONENT Development)
endif()
-1
View File
@@ -32,7 +32,6 @@
#include "PTL/TaskRunManager.hh"
#include "PTL/ThreadData.hh"
#include "PTL/ThreadPool.hh"
//======================================================================================//
+10 -44
View File
@@ -20,18 +20,11 @@
// Tasking class implementation
#include "PTL/TaskRunManager.hh"
#ifndef G4GMAKE
#include "PTL/Config.hh"
#endif
#include "PTL/TaskManager.hh"
#include "PTL/ThreadPool.hh"
#include "PTL/Threading.hh"
#include "PTL/Utility.hh"
#include <iostream>
using namespace PTL;
namespace PTL
{
//======================================================================================//
TaskRunManager::pointer&
@@ -75,19 +68,10 @@ TaskRunManager::GetInstance(bool useTBB)
TaskRunManager::TaskRunManager(bool useTBB)
: m_workers(std::thread::hardware_concurrency())
, m_use_tbb(useTBB)
{
if(!GetPrivateMasterRunManager())
GetPrivateMasterRunManager() = this;
#if defined(PTL_USE_TBB)
auto _useTBB = GetEnv<bool>("PTL_FORCE_TBB", GetEnv<bool>("FORCE_TBB", useTBB));
if(_useTBB)
useTBB = true;
#endif
// handle TBB
ThreadPool::set_use_tbb(useTBB);
m_workers = GetEnv<uint64_t>("PTL_NUM_THREADS", m_workers);
}
//======================================================================================//
@@ -108,40 +92,20 @@ TaskRunManager::Initialize(uint64_t n)
// create threadpool if needed + task manager
if(!m_thread_pool)
{
if(m_verbose > 0)
std::cout << "TaskRunManager :: Creating thread pool..." << std::endl;
m_thread_pool = new ThreadPool(m_workers, m_task_queue);
if(m_verbose > 0)
std::cout << "TaskRunManager :: Creating task manager..." << std::endl;
ThreadPool::Config cfg;
cfg.pool_size = m_workers;
cfg.task_queue = m_task_queue;
cfg.use_tbb = m_use_tbb;
m_thread_pool = new ThreadPool(cfg);
m_task_manager = new TaskManager(m_thread_pool);
}
// or resize
else if(m_workers != m_thread_pool->size())
{
if(m_verbose > 0)
{
std::cout << "TaskRunManager :: Resizing thread pool from "
<< m_thread_pool->size() << " to " << m_workers << " threads ..."
<< std::endl;
}
m_thread_pool->resize(m_workers);
}
// create the joiners
if(ThreadPool::using_tbb())
{
if(m_verbose > 0)
std::cout << "TaskRunManager :: Using TBB..." << std::endl;
}
else
{
if(m_verbose > 0)
std::cout << "TaskRunManager :: Using ThreadPool..." << std::endl;
}
m_is_initialized = true;
if(m_verbose > 0)
std::cout << "TaskRunManager :: initialized..." << std::endl;
}
//======================================================================================//
@@ -159,3 +123,5 @@ TaskRunManager::Terminate()
}
//======================================================================================//
} // namespace PTL
+4 -3
View File
@@ -22,10 +22,9 @@
#include "PTL/ThreadData.hh"
#include "PTL/ThreadPool.hh"
#include "PTL/VUserTaskQueue.hh"
using namespace PTL;
namespace PTL
{
//======================================================================================//
ThreadData*&
@@ -56,3 +55,5 @@ ThreadData::update()
}
//======================================================================================//
} // namespace PTL
+12 -117
View File
@@ -29,10 +29,11 @@
// ---------------------------------------------------------------
#include "PTL/ThreadPool.hh"
#include "PTL/GetEnv.hh"
#include "PTL/ScopeDestructor.hh"
#include "PTL/ThreadData.hh"
#include "PTL/Threading.hh"
#include "PTL/UserTaskQueue.hh"
#include "PTL/Utility.hh"
#include "PTL/VUserTaskQueue.hh"
#include <cassert>
@@ -41,19 +42,19 @@
#include <stdexcept>
#include <thread>
using namespace PTL;
//======================================================================================//
namespace
{
ThreadData*&
PTL::ThreadData*&
thread_data()
{
return ThreadData::GetInstance();
return PTL::ThreadData::GetInstance();
}
} // namespace
namespace PTL
{
//======================================================================================//
ThreadPool::thread_id_map_t&
@@ -65,42 +66,6 @@ ThreadPool::f_thread_ids()
//======================================================================================//
bool&
ThreadPool::f_use_tbb()
{
static bool _v = GetEnv<bool>("PTL_USE_TBB", false);
return _v;
}
//======================================================================================//
bool&
ThreadPool::f_use_cpu_affinity()
{
static bool _v = GetEnv<bool>("PTL_CPU_AFFINITY", false);
return _v;
}
//======================================================================================//
int&
ThreadPool::f_thread_priority()
{
static int _v = GetEnv<int>("PTL_THREAD_PRIORITY", 0);
return _v;
}
//======================================================================================//
int&
ThreadPool::f_verbose()
{
static int _v = GetEnv<int>("PTL_VERBOSE", 0);
return _v;
}
//======================================================================================//
ThreadPool::size_type&
ThreadPool::f_default_pool_size()
{
@@ -129,7 +94,7 @@ ThreadPool::start_thread(ThreadPool* tp, thread_data_t* _data, intmax_t _idx)
if(_idx < 0)
_idx = f_thread_ids().size();
f_thread_ids()[std::this_thread::get_id()] = _idx;
Threading::SetThreadId((int)_idx);
SetThreadId((int)_idx);
_data->emplace_back(_thr_data);
}
thread_data() = _thr_data.get();
@@ -145,38 +110,6 @@ ThreadPool::start_thread(ThreadPool* tp, thread_data_t* _data, intmax_t _idx)
}
}
//======================================================================================//
// static member function that checks enabling of tbb library
bool
ThreadPool::using_tbb()
{
return f_use_tbb();
}
//======================================================================================//
// static member function that initialized tbb library
void
ThreadPool::set_use_tbb(bool enable)
{
#if defined(PTL_USE_TBB)
f_use_tbb() = enable;
#else
ConsumeParameters(enable);
#endif
}
//======================================================================================//
// static member function that initialized tbb library
void
ThreadPool::set_default_use_cpu_affinity(bool enable)
{
#if defined(PTL_USE_TBB)
f_use_cpu_affinity() = enable;
#else
ConsumeParameters(enable);
#endif
}
//======================================================================================//
const ThreadPool::thread_id_map_t&
@@ -229,31 +162,13 @@ ThreadPool::add_thread_id(ThreadId _tid)
{
auto _idx = f_thread_ids().size();
f_thread_ids()[_tid] = _idx;
Threading::SetThreadId((int)_idx);
SetThreadId((int)_idx);
}
return f_thread_ids().at(_tid);
}
//======================================================================================//
ThreadPool::Config::Config(bool _init, bool _use_tbb, bool _use_affinity, int _verbose,
int _prio, size_type _size, VUserTaskQueue* _task_queue,
affinity_func_t _affinity_func, initialize_func_t _init_func,
finalize_func_t _fini_func)
: init{ _init }
, use_tbb{ _use_tbb }
, use_affinity{ _use_affinity }
, verbose{ _verbose }
, priority{ _prio }
, pool_size{ _size }
, task_queue{ _task_queue }
, set_affinity{ std::move(_affinity_func) }
, initializer{ std::move(_init_func) }
, finalizer{ std::move(_fini_func) }
{}
//======================================================================================//
ThreadPool::ThreadPool(const Config& _cfg)
: m_use_affinity{ _cfg.use_affinity }
, m_tbb_tp{ _cfg.use_tbb }
@@ -279,25 +194,6 @@ ThreadPool::ThreadPool(const Config& _cfg)
this->initialize_threadpool(_cfg.pool_size);
}
ThreadPool::ThreadPool(const size_type& _pool_size, VUserTaskQueue* _task_queue,
bool _use_affinity, affinity_func_t _affinity_func,
initialize_func_t _init_func, finalize_func_t _fini_func)
: ThreadPool{ Config{ true, f_use_tbb(), _use_affinity, f_verbose(), f_thread_priority(),
_pool_size, _task_queue, std::move(_affinity_func),
std::move(_init_func), std::move(_fini_func) } }
{}
ThreadPool::ThreadPool(const size_type& pool_size, initialize_func_t _init_func,
finalize_func_t _fini_func, bool _use_affinity,
affinity_func_t _affinity_func, VUserTaskQueue* task_queue)
: ThreadPool{ pool_size,
task_queue,
_use_affinity,
std::move(_affinity_func),
std::move(_init_func),
std::move(_fini_func) }
{}
//======================================================================================//
ThreadPool::~ThreadPool()
@@ -364,7 +260,7 @@ ThreadPool::set_affinity(intmax_t i, Thread& _thread) const
std::cerr << "[PTL::ThreadPool] Setting pin affinity for thread "
<< get_thread_id(_thread.get_id()) << " to " << _pin << std::endl;
}
Threading::SetPinAffinity((int)_pin, native_thread);
SetPinAffinity((int)_pin, native_thread);
} catch(std::runtime_error& e)
{
std::cerr << "[PTL::ThreadPool] Error setting pin affinity: " << e.what()
@@ -387,7 +283,7 @@ ThreadPool::set_priority(int _prio, Thread& _thread) const
<< get_thread_id(_thread.get_id()) << " priority to " << _prio
<< std::endl;
}
Threading::SetThreadPriority(_prio, native_thread);
SetThreadPriority(_prio, native_thread);
} catch(std::runtime_error& e)
{
AutoLock lock(TypeMutex<decltype(std::cerr)>());
@@ -771,9 +667,6 @@ ThreadPool::get_valid_queue(task_queue_t*& _queue) const
void
ThreadPool::execute_thread(VUserTaskQueue* _task_queue)
{
// how long the thread waits on condition variable
// static int wait_time = GetEnv<int>("PTL_POOL_WAIT_TIME", 5);
++(*m_thread_awake);
// initialization function
@@ -937,3 +830,5 @@ ThreadPool::execute_thread(VUserTaskQueue* _task_queue)
}
//======================================================================================//
} // namespace PTL
+21 -15
View File
@@ -23,8 +23,9 @@
//
#include "PTL/Threading.hh"
#include "PTL/Types.hh"
#include "PTL/Utility.hh"
#include "PTL/ConsumeParameters.hh"
#include "PTL/Macros.hh"
#if defined(PTL_WINDOWS)
# include <windows.h>
@@ -36,22 +37,25 @@
#if defined(PTL_LINUX)
# include <fstream>
# include <set>
#endif
using namespace PTL;
#include <cstddef>
#include <thread>
//======================================================================================//
namespace
{
thread_local int ThreadID = Threading::MASTER_ID;
thread_local int ThreadID = PTL::Threading::MASTER_ID;
} // namespace
//======================================================================================//
namespace PTL
{
Pid_t
Threading::GetPidId()
GetPidId()
{
// In multithreaded mode return Thread ID
return std::this_thread::get_id();
@@ -60,7 +64,7 @@ Threading::GetPidId()
//======================================================================================//
unsigned
Threading::GetNumberOfCores()
GetNumberOfCores()
{
return std::thread::hardware_concurrency();
}
@@ -68,7 +72,7 @@ Threading::GetNumberOfCores()
//======================================================================================//
unsigned
Threading::GetNumberOfPhysicalCpus()
GetNumberOfPhysicalCpus()
{
#if defined(PTL_MACOS)
int count;
@@ -96,7 +100,7 @@ Threading::GetNumberOfPhysicalCpus()
while((_pos = line.find(itr)) != _npos)
line = line.replace(_pos, itr.length(), "");
}
core_ids.insert(line);
core_ids.insert(std::move(line));
}
}
core_id_count = static_cast<unsigned>(core_ids.size());
@@ -112,13 +116,13 @@ Threading::GetNumberOfPhysicalCpus()
//======================================================================================//
void
Threading::SetThreadId(int value)
SetThreadId(int value)
{
ThreadID = value;
}
int
Threading::GetThreadId()
GetThreadId()
{
return ThreadID;
}
@@ -126,7 +130,7 @@ Threading::GetThreadId()
//======================================================================================//
bool
Threading::SetPinAffinity(int _cpu)
SetPinAffinity(int _cpu)
{
#if defined(__linux__) || defined(_AIX)
cpu_set_t _cpu_set{};
@@ -143,7 +147,7 @@ Threading::SetPinAffinity(int _cpu)
//======================================================================================//
bool
Threading::SetThreadPriority(int _prio)
SetThreadPriority(int _prio)
{
#if defined(__linux__) || defined(_AIX)
return (pthread_setschedprio(pthread_self(), _prio) == 0);
@@ -156,7 +160,7 @@ Threading::SetThreadPriority(int _prio)
//======================================================================================//
bool
Threading::SetPinAffinity(int _cpu, NativeThread& _t)
SetPinAffinity(int _cpu, NativeThread& _t)
{
#if defined(__linux__) || defined(_AIX)
cpu_set_t _cpu_set{};
@@ -173,7 +177,7 @@ Threading::SetPinAffinity(int _cpu, NativeThread& _t)
//======================================================================================//
bool
Threading::SetThreadPriority(int _prio, NativeThread& _t)
SetThreadPriority(int _prio, NativeThread& _t)
{
#if defined(__linux__) || defined(_AIX)
return (pthread_setschedprio(static_cast<pthread_t>(_t), _prio) == 0);
@@ -184,3 +188,5 @@ Threading::SetThreadPriority(int _prio, NativeThread& _t)
}
//======================================================================================//
} // namespace PTL
-124
View File
@@ -1,124 +0,0 @@
//
// MIT License
// Copyright (c) 2019 Jonathan R. Madsen
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED
// "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
// ----------------------------------------------------------------------
// class Timer
//
// Implementation
// 29.04.97 G.Cosmo Added timings for Windows systems
#include "PTL/Timer.hh"
#include <stdexcept>
using namespace PTL;
#if !(defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64))
# include <unistd.h>
#else
# include <sys/types.h>
# include <windows.h>
//======================================================================================//
// extract milliseconds time unit
int
sysconf(int a)
{
if(a == _SC_CLK_TCK)
return 1000;
else
return 0;
}
//======================================================================================//
static clock_t
filetime2msec(FILETIME* t)
{
return (clock_t)((((float) t->dwHighDateTime) * 429496.7296) +
(((float) t->dwLowDateTime) * .0001));
}
//======================================================================================//
clock_t
times(struct tms* t)
{
FILETIME ct = { 0, 0 }, et = { 0, 0 }, st = { 0, 0 }, ut = { 0, 0 }, rt = { 0, 0 };
SYSTEMTIME realtime;
GetSystemTime(&realtime);
SystemTimeToFileTime(&realtime, &rt); // get real time in 10^-9 sec
if(t != 0)
{
GetProcessTimes(GetCurrentProcess(), &ct, &et, &st,
&ut); // get process time in 10^-9 sec
t->tms_utime = t->tms_cutime = filetime2msec(&ut);
t->tms_stime = t->tms_cstime = filetime2msec(&st);
}
return filetime2msec(&rt);
}
//======================================================================================//
#endif /* WIN32 */
//======================================================================================//
double
Timer::GetRealElapsed() const
{
if(!fValidTimes)
{
throw std::runtime_error("Timer::GetRealElapsed() - "
"Timer not stopped or times not recorded!");
}
std::chrono::duration<double> diff = fEndRealTime - fStartRealTime;
return diff.count();
}
//======================================================================================//
double
Timer::GetSystemElapsed() const
{
if(!fValidTimes)
{
throw std::runtime_error("Timer::GetSystemElapsed() - "
"Timer not stopped or times not recorded!");
}
double diff = fEndTimes.tms_stime - fStartTimes.tms_stime;
return diff / sysconf(_SC_CLK_TCK);
}
//======================================================================================//
double
Timer::GetUserElapsed() const
{
if(!fValidTimes)
{
throw std::runtime_error("Timer::GetUserElapsed() - "
"Timer not stopped or times not recorded!");
}
double diff = fEndTimes.tms_utime - fStartTimes.tms_utime;
return diff / sysconf(_SC_CLK_TCK);
}
//======================================================================================//
+5 -25
View File
@@ -26,10 +26,10 @@
#include "PTL/UserTaskQueue.hh"
#include "PTL/AutoLock.hh"
#include "PTL/ScopeDestructor.hh"
#include "PTL/TaskGroup.hh"
#include "PTL/ThreadData.hh"
#include "PTL/ThreadPool.hh"
#include "PTL/Utility.hh"
#include <cassert>
#include <chrono>
@@ -37,12 +37,11 @@
#include <iostream>
#include <map>
#include <stdexcept>
#include <system_error>
#include <thread>
#include <utility>
using namespace PTL;
namespace PTL
{
//======================================================================================//
UserTaskQueue::UserTaskQueue(intmax_t nworkers, UserTaskQueue* parent)
@@ -61,26 +60,6 @@ UserTaskQueue::UserTaskQueue(intmax_t nworkers, UserTaskQueue* parent)
for(intmax_t i = 0; i < nworkers + 1; ++i)
m_subqueues->emplace_back(new TaskSubQueue(m_ntasks));
}
#if defined(DEBUG)
if(GetEnv<int>("PTL_VERBOSE", 0) > 3)
{
RecursiveAutoLock l(TypeMutex<decltype(std::cout), RecursiveMutex>());
std::stringstream ss;
ss << ThreadPool::get_this_thread_id() << "> " << ThisThread::get_id() << " ["
<< __FUNCTION__ << ":" << __LINE__ << "] "
<< "this = " << this << ", "
<< "clone = " << std::boolalpha << m_is_clone << ", "
<< "thread = " << m_thread_bin << ", "
<< "insert = " << m_insert_bin << ", "
<< "hold = " << m_hold->load() << " @ " << m_hold << ", "
<< "tasks = " << m_ntasks->load() << " @ " << m_ntasks << ", "
<< "subqueue = " << m_subqueues << ", "
<< "size = " << true_size() << ", "
<< "empty = " << true_empty();
std::cout << ss.str() << std::endl;
}
#endif
}
//======================================================================================//
@@ -311,7 +290,6 @@ UserTaskQueue::InsertTask(task_pointer&& task, ThreadData* data, intmax_t subq)
if(insert_task(_n))
return _n;
}
return GetThreadBin();
}
//======================================================================================//
@@ -470,3 +448,5 @@ UserTaskQueue::ReleaseHold()
}
//======================================================================================//
} // namespace PTL
+6 -5
View File
@@ -27,12 +27,11 @@
#include "PTL/VUserTaskQueue.hh"
#include "PTL/TaskRunManager.hh"
#include "PTL/Utility.hh" // for PTL
#include <cstdint> // for intmax_t
#include <thread> // for thread
using namespace PTL;
#include <cstdint> // for intmax_t
#include <thread> // for thread
namespace PTL
{
//======================================================================================//
VUserTaskQueue::VUserTaskQueue(intmax_t nworkers)
@@ -48,3 +47,5 @@ VUserTaskQueue::VUserTaskQueue(intmax_t nworkers)
}
//======================================================================================//
} // namespace PTL