Skip to content

Commit e31b7f9

Browse files
committed
Added a new chunkAllocator class that pre-allocates blocks of memory that are some fixed multiple of the object size, with pool-style reuse
Used the above in HistogramVBW to avoid overheads associated with repeated allocations and frees
1 parent 5354a6c commit e31b7f9

6 files changed

Lines changed: 142 additions & 36 deletions

File tree

include/Makefile.am

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
nobase_include_HEADERS = chimbuko/chimbuko.hpp chimbuko/ad/FuncAnomalyMetrics.hpp chimbuko/ad/ADOutlier.hpp chimbuko/ad/ADLocalAnomalyMetrics.hpp chimbuko/ad/ADNetClient.hpp chimbuko/ad/FuncStats.hpp chimbuko/ad/ADAnomalyProvenance.hpp chimbuko/ad/ADParser.hpp chimbuko/ad/ADProvenanceDBengine.hpp chimbuko/ad/ADMonitoring.hpp chimbuko/ad/ADNormalEventProvenance.hpp chimbuko/ad/ADLocalFuncStatistics.hpp chimbuko/ad/ADMetadataParser.hpp chimbuko/ad/AnomalyData.hpp chimbuko/ad/ADDefine.hpp chimbuko/ad/ADglobalFunctionIndexMap.hpp chimbuko/ad/ADProvenanceDBclient.hpp chimbuko/ad/ADcombinedPSdata.hpp chimbuko/ad/ADEvent.hpp chimbuko/ad/ADCounter.hpp chimbuko/ad/ADLocalCounterStatistics.hpp chimbuko/ad/ExecData.hpp chimbuko/ad/utils.hpp chimbuko/ad/ADio.hpp chimbuko/provdb/setup.hpp chimbuko/verbose.hpp chimbuko/pserver/PSProvenanceDBclient.hpp chimbuko/pserver/GlobalAnomalyStats.hpp chimbuko/pserver/AggregateFuncAnomalyMetrics.hpp chimbuko/pserver/PSglobalFunctionIndexMap.hpp chimbuko/pserver/AggregateFuncStats.hpp chimbuko/pserver/AggregateAnomalyData.hpp chimbuko/pserver/NetPayloadRecvCombinedADdata.hpp chimbuko/pserver/FunctionProfile.hpp chimbuko/pserver/PSparamManager.hpp chimbuko/pserver/PSstatSender.hpp chimbuko/pserver/GlobalAnomalyMetrics.hpp chimbuko/pserver/AggregateFuncAnomalyMetricsAllRanks.hpp chimbuko/pserver/GlobalCounterStats.hpp chimbuko/pserver/PSfunctions.hpp chimbuko/param/sstd_param.hpp chimbuko/param/copod_param.hpp chimbuko/param/hbos_param.hpp chimbuko/AD.hpp chimbuko/message.hpp chimbuko/net.hpp chimbuko/pserver.hpp chimbuko/provdb.hpp chimbuko/param.hpp chimbuko/net/zmqme_net.hpp chimbuko/net/mpi_net.hpp chimbuko/net/zmq_net.hpp chimbuko/net/local_net.hpp chimbuko/util/RunStats.hpp chimbuko/util/ADIOS2parseUtils.hpp chimbuko/util/environment.hpp chimbuko/util/pointerRegistry.hpp chimbuko/util/time.hpp chimbuko/util/map.hpp chimbuko/util/error.hpp chimbuko/util/string.hpp chimbuko/util/DispatchQueue.hpp chimbuko/util/PerfStats.hpp chimbuko/util/curlJsonSender.hpp chimbuko/util/RunMetric.hpp chimbuko/util/memutils.hpp chimbuko/util/Anomalies.hpp chimbuko/util/Histogram.hpp chimbuko/util/barrier.hpp chimbuko/util/threadPool.hpp chimbuko/util/hash.hpp chimbuko/util/mtQueue.hpp chimbuko/util/serialize.hpp chimbuko/util/commandLineParser.hpp
1+
nobase_include_HEADERS = chimbuko/chimbuko.hpp chimbuko/ad/FuncAnomalyMetrics.hpp chimbuko/ad/ADOutlier.hpp chimbuko/ad/ADLocalAnomalyMetrics.hpp chimbuko/ad/ADNetClient.hpp chimbuko/ad/FuncStats.hpp chimbuko/ad/ADAnomalyProvenance.hpp chimbuko/ad/ADParser.hpp chimbuko/ad/ADProvenanceDBengine.hpp chimbuko/ad/ADMonitoring.hpp chimbuko/ad/ADNormalEventProvenance.hpp chimbuko/ad/ADLocalFuncStatistics.hpp chimbuko/ad/ADMetadataParser.hpp chimbuko/ad/AnomalyData.hpp chimbuko/ad/ADDefine.hpp chimbuko/ad/ADglobalFunctionIndexMap.hpp chimbuko/ad/ADProvenanceDBclient.hpp chimbuko/ad/ADcombinedPSdata.hpp chimbuko/ad/ADEvent.hpp chimbuko/ad/ADCounter.hpp chimbuko/ad/ADLocalCounterStatistics.hpp chimbuko/ad/ExecData.hpp chimbuko/ad/utils.hpp chimbuko/ad/ADio.hpp chimbuko/provdb/setup.hpp chimbuko/verbose.hpp chimbuko/pserver/PSProvenanceDBclient.hpp chimbuko/pserver/GlobalAnomalyStats.hpp chimbuko/pserver/AggregateFuncAnomalyMetrics.hpp chimbuko/pserver/PSglobalFunctionIndexMap.hpp chimbuko/pserver/AggregateFuncStats.hpp chimbuko/pserver/AggregateAnomalyData.hpp chimbuko/pserver/NetPayloadRecvCombinedADdata.hpp chimbuko/pserver/FunctionProfile.hpp chimbuko/pserver/PSparamManager.hpp chimbuko/pserver/PSstatSender.hpp chimbuko/pserver/GlobalAnomalyMetrics.hpp chimbuko/pserver/AggregateFuncAnomalyMetricsAllRanks.hpp chimbuko/pserver/GlobalCounterStats.hpp chimbuko/pserver/PSfunctions.hpp chimbuko/param/sstd_param.hpp chimbuko/param/copod_param.hpp chimbuko/param/hbos_param.hpp chimbuko/AD.hpp chimbuko/message.hpp chimbuko/net.hpp chimbuko/pserver.hpp chimbuko/provdb.hpp chimbuko/param.hpp chimbuko/net/zmqme_net.hpp chimbuko/net/mpi_net.hpp chimbuko/net/zmq_net.hpp chimbuko/net/local_net.hpp chimbuko/util/RunStats.hpp chimbuko/util/ADIOS2parseUtils.hpp chimbuko/util/environment.hpp chimbuko/util/pointerRegistry.hpp chimbuko/util/time.hpp chimbuko/util/map.hpp chimbuko/util/error.hpp chimbuko/util/string.hpp chimbuko/util/DispatchQueue.hpp chimbuko/util/PerfStats.hpp chimbuko/util/curlJsonSender.hpp chimbuko/util/RunMetric.hpp chimbuko/util/memutils.hpp chimbuko/util/Anomalies.hpp chimbuko/util/Histogram.hpp chimbuko/util/barrier.hpp chimbuko/util/threadPool.hpp chimbuko/util/hash.hpp chimbuko/util/mtQueue.hpp chimbuko/util/serialize.hpp chimbuko/util/commandLineParser.hpp chimbuko/util/chunkAllocator.hpp

include/chimbuko/util/Histogram.hpp

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#pragma once
2-
3-
#include<vector>
2+
#include <chimbuko/util/chunkAllocator.hpp>
3+
#include <vector>
44
#include <nlohmann/json.hpp>
55

66
namespace chimbuko{
@@ -372,12 +372,12 @@ namespace chimbuko{
372372

373373
Bin(double l, double u, double c): l(l), u(u), c(c), left(nullptr), right(nullptr), is_end(false){}
374374

375-
static std::pair<Bin*,Bin*> insertFirst(Bin* toins);
376-
static Bin* insertRight(Bin* of, Bin* toins);
377-
static Bin* insertLeft(Bin* of, Bin* toins);
378-
static void deleteChain(Bin* leftmost);
379-
static Bin* getBin(Bin* leftmost, double v);
380-
static std::pair<Bin*,Bin*> split(Bin* bin, double about);
375+
static std::pair<Bin*,Bin*> insertFirst(Bin* toins, chunkAllocator<Bin> &alloc);
376+
inline static Bin* insertRight(Bin* of, Bin* toins);
377+
inline static Bin* insertLeft(Bin* of, Bin* toins);
378+
static void deleteChain(Bin* leftmost, chunkAllocator<Bin> &alloc);
379+
inline static Bin* getBin(Bin* leftmost, double v);
380+
inline static std::pair<Bin*,Bin*> split(Bin* bin, double about, chunkAllocator<Bin> &alloc);
381381
static size_t size(Bin* leftmost);
382382
/**
383383
* @brief Return bin information as a string
@@ -392,7 +392,7 @@ namespace chimbuko{
392392
static std::string getChainInfo(Bin* any_bin);
393393
};
394394

395-
HistogramVBW(): first(nullptr), end(nullptr), m_min(0), m_max(0){}
395+
HistogramVBW(): first(nullptr), end(nullptr), m_min(0), m_max(0), allocator(100){}
396396

397397
~HistogramVBW();
398398

@@ -401,7 +401,7 @@ namespace chimbuko{
401401
/**
402402
* @brief Construct from a fixed binwidth histogram
403403
*/
404-
explicit HistogramVBW(const Histogram &h): HistogramVBW(){ import(h); }
404+
explicit HistogramVBW(const Histogram &h): first(nullptr), end(nullptr), m_min(0), m_max(0), allocator(h.Nbin()){ import(h); }
405405

406406
/**
407407
* @brief Get the bin containing value 'v'
@@ -455,6 +455,7 @@ namespace chimbuko{
455455
Bin *end;
456456
double m_min;
457457
double m_max;
458+
chunkAllocator<Bin> allocator;
458459
};
459460

460461
std::ostream & operator<<(std::ostream &os, const HistogramVBW::Bin &b);
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
#pragma once
2+
#include <chimbuko_config.h>
3+
#include <chimbuko/util/error.hpp>
4+
#include<cstdlib>
5+
#include<vector>
6+
7+
namespace chimbuko{
8+
9+
//A local (not thread safe) fast pool reallocator
10+
template<typename T>
11+
class chunkAllocator{
12+
protected:
13+
std::vector<T*> m_chunks;
14+
std::vector<T*> m_reuse;
15+
size_t m_chunk_count;
16+
size_t m_off;
17+
void allocChunk(){
18+
m_chunks.push_back( (T*)malloc(m_chunk_count*sizeof(T)) );
19+
}
20+
public:
21+
T* get(){
22+
if(m_reuse.size()){ //reuse existing pointer if available
23+
T *ret = m_reuse.back();
24+
m_reuse.pop_back();
25+
return ret;
26+
}else if(m_off == m_chunk_count){ //no space left in chunk, allocate a new one
27+
allocChunk();
28+
m_off = 1;
29+
return m_chunks.back();
30+
}else{
31+
++m_off;
32+
return m_chunks.back()+m_off-1;
33+
}
34+
}
35+
void free(T* p){
36+
m_reuse.push_back(p);
37+
}
38+
39+
chunkAllocator(size_t chunk_count = 100): m_chunk_count(chunk_count), m_off(0){
40+
allocChunk();
41+
}
42+
43+
~chunkAllocator(){
44+
for(T* p: m_chunks)
45+
::free(p);
46+
}
47+
};
48+
49+
}

src/util/Histogram.cpp

Lines changed: 23 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -703,35 +703,37 @@ HistogramVBW::Bin* HistogramVBW::Bin::insertLeft(HistogramVBW::Bin* of, Histogra
703703
return toins;
704704
}
705705

706-
HistogramVBW::Bin* create_end(){
707-
HistogramVBW::Bin* end = new HistogramVBW::Bin(0,0,0);
706+
HistogramVBW::Bin* create_end(chunkAllocator<HistogramVBW::Bin> &alloc){
707+
HistogramVBW::Bin* end = new (alloc.get()) HistogramVBW::Bin(0,0,0);
708708
end->is_end = true;
709709
return end;
710710
}
711711

712712

713-
std::pair<HistogramVBW::Bin*,HistogramVBW::Bin*> HistogramVBW::Bin::insertFirst(HistogramVBW::Bin* toins){
713+
std::pair<HistogramVBW::Bin*,HistogramVBW::Bin*> HistogramVBW::Bin::insertFirst(HistogramVBW::Bin* toins, chunkAllocator<Bin> &alloc){
714714
if(toins == nullptr) fatal_error("Nullptr exception");
715-
Bin* end = create_end();
715+
Bin* end = create_end(alloc);
716716
insertLeft(end, toins);
717717
return {toins,end};
718718
}
719719

720720

721721

722-
void HistogramVBW::Bin::deleteChain(HistogramVBW::Bin* first){
722+
void HistogramVBW::Bin::deleteChain(HistogramVBW::Bin* first, chunkAllocator<Bin> &alloc){
723723
if(first == nullptr) fatal_error("Nullptr exception");
724724
if(first->left != nullptr) fatal_error("Deleting must start at the beginning of the chain");
725725

726726
Bin* cur = first;
727727
Bin* next = cur->right;
728728
while(next != nullptr){
729-
delete cur;
729+
cur->~Bin();
730+
alloc.free(cur);
730731
cur = next;
731732
next = cur->right;
732733
}
733734
if(!cur->is_end) fatal_error("Chain is broken");
734-
delete cur;
735+
cur->~Bin();
736+
alloc.free(cur);
735737
}
736738

737739
HistogramVBW::Bin* HistogramVBW::Bin::getBin(HistogramVBW::Bin* start, double v){
@@ -756,7 +758,7 @@ HistogramVBW::Bin* HistogramVBW::Bin::getBin(HistogramVBW::Bin* start, double v)
756758
}
757759

758760

759-
std::pair<HistogramVBW::Bin*,HistogramVBW::Bin*> HistogramVBW::Bin::split(HistogramVBW::Bin* bin, double about){
761+
std::pair<HistogramVBW::Bin*,HistogramVBW::Bin*> HistogramVBW::Bin::split(HistogramVBW::Bin* bin, double about, chunkAllocator<Bin> &alloc){
760762
if(bin == nullptr || bin->is_end) fatal_error("Invalid bin");
761763
if(about <= bin->l || about > bin->u){
762764
std::ostringstream os;
@@ -777,22 +779,19 @@ std::pair<HistogramVBW::Bin*,HistogramVBW::Bin*> HistogramVBW::Bin::split(Histog
777779
double fracs[2] = { (about - bin->l)/bw, 0 };
778780
fracs[1] = 1. - fracs[0];
779781
double count = bin->c;
780-
781-
int lrg = 0;
782-
double debt = count;
783-
for(int i=0;i<2;i++){
784-
o[i] = floor(fracs[i] * count + 0.5);
785-
debt -= o[i];
786-
if(fracs[i] > fracs[lrg]) lrg = i;
787-
}
782+
783+
o[0] = floor(fracs[0] * count + 0.5);
784+
o[1] = floor(fracs[1] * count + 0.5);
785+
double debt = count - o[0] - o[1];
786+
int lrg = fracs[1] > fracs[0] ? 1 : 0;
788787

789788
//Assign debt to largest fraction with preference from left
790789
o[lrg] += debt;
791790
double bu_prev = bin->u;
792791
bin->u = about;
793792
bin->c = o[0];
794793

795-
insertRight(bin, new Bin(about, bu_prev, o[1]));
794+
insertRight(bin, new (alloc.get()) Bin(about, bu_prev, o[1]));
796795

797796
verboseStream << "Split bin into " << *bin << " and " << *bin->right << std::endl;
798797
return {bin, bin->right};
@@ -860,7 +859,7 @@ void HistogramVBW::import(const Histogram &h){
860859
if(h.Nbin() == 0) return;
861860

862861
auto be = h.binEdges(0);
863-
auto fe = Bin::insertFirst(new Bin(be.first, be.second, h.binCount(0)) );
862+
auto fe = Bin::insertFirst(new (allocator.get()) Bin(be.first, be.second, h.binCount(0)), allocator);
864863
first = fe.first;
865864
end = fe.second;
866865

@@ -877,15 +876,15 @@ void HistogramVBW::import(const Histogram &h){
877876
fatal_error(of.str());
878877
}
879878

880-
hp = Bin::insertRight(hp, new Bin(prev_upper, be.second, h.binCount(b)) );
879+
hp = Bin::insertRight(hp, new (allocator.get()) Bin(prev_upper, be.second, h.binCount(b)) );
881880
prev_upper = be.second;
882881
}
883882
m_min = h.getMin();
884883
m_max = h.getMax();
885884
}
886885

887886
HistogramVBW::~HistogramVBW(){
888-
if(first != nullptr) Bin::deleteChain(first);
887+
if(first != nullptr) Bin::deleteChain(first,allocator);
889888
}
890889

891890
double HistogramVBW::totalCount() const{
@@ -927,7 +926,7 @@ double HistogramVBW::extractUniformCountInRangeInt(double l, double u){
927926

928927
if(bl != nullptr){
929928
verboseStream << "Lower edge " << l << " in bin " << *bl << std::endl;
930-
bl = Bin::split(bl,l).second;
929+
bl = Bin::split(bl,l,allocator).second;
931930
if(bl->is_end){
932931
verboseStream << "Right of split point is end" << std::endl;
933932
//If the split point matches the upper edge of the last bin, the .second pointer is END
@@ -946,7 +945,7 @@ double HistogramVBW::extractUniformCountInRangeInt(double l, double u){
946945

947946
Bin* bu = Bin::getBin(bl, u);
948947
if(bu != nullptr){
949-
bu = Bin::split(bu,u).first;
948+
bu = Bin::split(bu,u,allocator).first;
950949
}else if(u <= first->l){ //right edge is left of histogram
951950
return 0;
952951
}else if(u > last->u){ //right edge is right of histogram
@@ -1009,7 +1008,7 @@ std::vector<double> HistogramVBW::extractUniformCountInRangesInt(const std::vect
10091008

10101009
if(bl != nullptr){
10111010
verboseStream << "Lower edge " << l << " in bin " << *bl << std::endl;
1012-
bl = Bin::split(bl,l).second;
1011+
bl = Bin::split(bl,l, allocator).second;
10131012
if(bl->is_end){
10141013
verboseStream << "Right of split point is end" << std::endl;
10151014
//If the split point matches the upper edge of the last bin, the .second pointer is END and the entry is 0
@@ -1029,7 +1028,7 @@ std::vector<double> HistogramVBW::extractUniformCountInRangesInt(const std::vect
10291028

10301029
Bin* bu = Bin::getBin(bl, u);
10311030
if(bu != nullptr){
1032-
bu = Bin::split(bu,u).first;
1031+
bu = Bin::split(bu,u, allocator).first;
10331032
}else if(u <= first->l){ //right edge is left of histogram
10341033
continue;
10351034
}else if(u > last->u){ //right edge is right of histogram

test/unit_tests/util/Makefile.am

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/3rdparty @PS_FLAGS@
22
LDADD = $(top_builddir)/src/libchimbuko.la -lgtest -lstdc++fs
33

44
testdir = $(prefix)/test/unit_tests/util
5-
test_PROGRAMS = DispatchQueue commandLineParser RunStats error memutils PerfStats environment Histogram pointerRegistry Anomalies
5+
test_PROGRAMS = DispatchQueue commandLineParser RunStats error memutils PerfStats environment Histogram pointerRegistry Anomalies chunkAllocator
66

77
DispatchQueue_SOURCES = DispatchQueue.cpp ../unit_test_main.cpp
88
DispatchQueue_LDADD = $(LDADD)
@@ -33,3 +33,6 @@ pointerRegistry_LDADD = $(LDADD)
3333

3434
Anomalies_SOURCES = Anomalies.cpp ../unit_test_main.cpp
3535
Anomalies_LDADD = $(LDADD)
36+
37+
chunkAllocator_SOURCES = chunkAllocator.cpp ../unit_test_main.cpp
38+
chunkAllocator_LDADD = $(LDADD)
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
#include<chimbuko/util/chunkAllocator.hpp>
2+
#include "gtest/gtest.h"
3+
#include <sstream>
4+
#include "../unit_test_common.hpp"
5+
6+
using namespace chimbuko;
7+
8+
9+
template<typename T>
10+
class testChunkAllocator: public chunkAllocator<T>{
11+
public:
12+
testChunkAllocator(size_t chunk_count): chunkAllocator<T>(chunk_count){}
13+
14+
const std::vector<T*> & get_m_chunks(){ return this->m_chunks; }
15+
const std::vector<T*> & get_m_reuse(){ return this->m_reuse; }
16+
size_t get_m_off(){ return this->m_off; }
17+
size_t get_m_chunk_count(){ return this->m_chunk_count; }
18+
};
19+
20+
21+
TEST(TestChunkAllocator, testIt){
22+
testChunkAllocator<double> c(2);
23+
EXPECT_EQ(c.get_m_chunks().size(),1);
24+
EXPECT_EQ(c.get_m_chunk_count(),2);
25+
26+
double* p = c.get();
27+
double* p1 = p;
28+
EXPECT_EQ(c.get_m_off(),1);
29+
EXPECT_EQ(p, c.get_m_chunks()[0]);
30+
31+
p = c.get();
32+
EXPECT_EQ(p, c.get_m_chunks()[0]+1);
33+
EXPECT_EQ(c.get_m_off(),2);
34+
35+
p = c.get();
36+
EXPECT_EQ(c.get_m_chunks().size(),2);
37+
EXPECT_EQ(c.get_m_off(),1);
38+
EXPECT_EQ(p, c.get_m_chunks()[1]);
39+
40+
p = c.get();
41+
EXPECT_EQ(c.get_m_off(),2);
42+
EXPECT_EQ(p, c.get_m_chunks()[1]+1);
43+
44+
p = c.get();
45+
EXPECT_EQ(c.get_m_chunks().size(),3);
46+
EXPECT_EQ(c.get_m_off(),1);
47+
EXPECT_EQ(p, c.get_m_chunks()[2]);
48+
49+
//Check reuse
50+
c.free(p1);
51+
p = c.get();
52+
EXPECT_EQ(c.get_m_off(),1);
53+
EXPECT_EQ(p,p1);
54+
}

0 commit comments

Comments
 (0)