Import Geant4 11.3.0 source tree
This commit is contained in:
Vendored
+28
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
@@ -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++;
|
||||
}
|
||||
|
||||
Vendored
+1
-1
@@ -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()
|
||||
|
||||
Vendored
+17
@@ -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.
|
||||
|
||||
|
||||
Vendored
+1
-1
@@ -1 +1 @@
|
||||
2.3.3
|
||||
3.0.0
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
#
|
||||
@PACKAGE_INIT@
|
||||
|
||||
cmake_minimum_required(VERSION 3.8)
|
||||
cmake_minimum_required(VERSION 3.8...3.27)
|
||||
|
||||
# -------------------------------------------------------------------------------------- #
|
||||
# basic paths
|
||||
|
||||
+2
-2
@@ -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
@@ -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
|
||||
+7
-16
@@ -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
@@ -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
@@ -30,7 +30,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "PTL/Types.hh"
|
||||
#include "PTL/Macros.hh"
|
||||
|
||||
#include <functional>
|
||||
#include <utility>
|
||||
|
||||
+107
@@ -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
@@ -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"
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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>
|
||||
|
||||
+6
-52
@@ -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
@@ -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
@@ -32,7 +32,6 @@
|
||||
|
||||
#include "PTL/TaskRunManager.hh"
|
||||
#include "PTL/ThreadData.hh"
|
||||
#include "PTL/ThreadPool.hh"
|
||||
|
||||
//======================================================================================//
|
||||
|
||||
|
||||
+10
-44
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
Vendored
-124
@@ -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
@@ -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
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user