Skip to content

Commit 5e964e1

Browse files
authored
[6.4][ML] Convert std::shared_ptrs to std::unique_ptrs where possible (#121)
Backport of #115.
1 parent 741c08d commit 5e964e1

File tree

81 files changed

+916
-624
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

81 files changed

+916
-624
lines changed

docs/CHANGELOG.asciidoc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ Secure the ML processes by preventing system calls such as fork and exec. The Li
3232
Seccomp BPF to intercept system calls and is available in kernels since 3.5. On Windows Job Objects prevent
3333
new processes being created and macOS uses the sandbox functionality ({pull}98[#98])
3434

35+
Fix a bug causing us to under estimate the memory used by shared pointers and reduce the memory consumed
36+
by unnecessary reference counting ({pull}108[#108])
37+
3538
=== Bug Fixes
3639

3740
Age seasonal components in proportion to the fraction of values with which they're updated ({pull}88[#88])

include/api/CForecastRunner.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ class API_EXPORT CForecastRunner final : private core::CNonCopyable {
115115
using TForecastModelWrapper = model::CForecastDataSink::SForecastModelWrapper;
116116
using TForecastResultSeries = model::CForecastDataSink::SForecastResultSeries;
117117
using TForecastResultSeriesVec = std::vector<TForecastResultSeries>;
118-
using TMathsModelPtr = std::shared_ptr<maths::CModel>;
118+
using TMathsModelPtr = std::unique_ptr<maths::CModel>;
119119

120120
using TStrUSet = boost::unordered_set<std::string>;
121121

include/core/CMemory.h

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -287,21 +287,25 @@ class CORE_EXPORT CMemory : private CNonInstantiatable {
287287
static std::size_t
288288
dynamicSize(const T& t,
289289
typename boost::enable_if<typename boost::is_pointer<T>>::type* = nullptr) {
290-
if (t == nullptr) {
291-
return 0;
292-
}
293-
return staticSize(*t) + dynamicSize(*t);
290+
return t == nullptr ? 0 : staticSize(*t) + dynamicSize(*t);
294291
}
295292

296293
//! Overload for std::shared_ptr.
297294
template<typename T>
298295
static std::size_t dynamicSize(const std::shared_ptr<T>& t) {
299-
if (!t) {
296+
if (t == nullptr) {
300297
return 0;
301298
}
302299
long uc = t.use_count();
303-
// Round up
304-
return (staticSize(*t) + dynamicSize(*t) + std::size_t(uc - 1)) / uc;
300+
// Note we add on sizeof(long) here to account for the memory
301+
// used by the shared reference count. Also, round up.
302+
return (sizeof(long) + staticSize(*t) + dynamicSize(*t) + std::size_t(uc - 1)) / uc;
303+
}
304+
305+
//! Overload for std::unique_ptr.
306+
template<typename T>
307+
static std::size_t dynamicSize(const std::unique_ptr<T>& t) {
308+
return t == nullptr ? 0 : staticSize(*t) + dynamicSize(*t);
305309
}
306310

307311
//! Overload for boost::array.
@@ -703,25 +707,40 @@ class CORE_EXPORT CMemoryDebug : private CNonInstantiatable {
703707
static void dynamicSize(const char* name,
704708
const std::shared_ptr<T>& t,
705709
CMemoryUsage::TMemoryUsagePtr mem) {
706-
if (t) {
710+
if (t != nullptr) {
707711
long uc = t.use_count();
708712
// If the pointer is shared by multiple users, each one
709713
// might count it, so divide by the number of users.
710714
// However, if only 1 user has it, do a full debug.
711715
if (uc == 1) {
712-
mem->addItem("shared_ptr", CMemory::staticSize(*t));
716+
// Note we add on sizeof(long) here to account for
717+
// the memory used by the shared reference count.
718+
mem->addItem("shared_ptr", sizeof(long) + CMemory::staticSize(*t));
713719
dynamicSize(name, *t, mem);
714720
} else {
715721
std::ostringstream ss;
716722
ss << "shared_ptr (x" << uc << ')';
717-
// Round up
718-
mem->addItem(ss.str(), (CMemory::staticSize(*t) +
723+
// Note we add on sizeof(long) here to account for
724+
// the memory used by the shared reference count.
725+
// Also, round up.
726+
mem->addItem(ss.str(), (sizeof(long) + CMemory::staticSize(*t) +
719727
CMemory::dynamicSize(*t) + std::size_t(uc - 1)) /
720728
uc);
721729
}
722730
}
723731
}
724732

733+
//! Overload for std::unique_ptr.
734+
template<typename T>
735+
static void dynamicSize(const char* name,
736+
const std::unique_ptr<T>& t,
737+
CMemoryUsage::TMemoryUsagePtr mem) {
738+
if (t != nullptr) {
739+
mem->addItem("ptr", CMemory::staticSize(*t));
740+
memory_detail::SDebugMemoryDynamicSize<T>::dispatch(name, *t, mem);
741+
}
742+
}
743+
725744
//! Overload for boost::array.
726745
template<typename T, std::size_t N>
727746
static void dynamicSize(const char* name,

include/maths/CChecksum.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,13 +158,20 @@ class CChecksumImpl<BasicChecksum> {
158158
: CChecksumImpl<typename selector<T>::value>::dispatch(seed, *target);
159159
}
160160

161-
//! Checksum a pointer.
161+
//! Checksum a shared pointer.
162162
template<typename T>
163163
static uint64_t dispatch(uint64_t seed, const std::shared_ptr<T>& target) {
164164
return !target ? seed
165165
: CChecksumImpl<typename selector<T>::value>::dispatch(seed, *target);
166166
}
167167

168+
//! Checksum a unique pointer.
169+
template<typename T>
170+
static uint64_t dispatch(uint64_t seed, const std::unique_ptr<T>& target) {
171+
return !target ? seed
172+
: CChecksumImpl<typename selector<T>::value>::dispatch(seed, *target);
173+
}
174+
168175
//! Checksum a pair.
169176
template<typename U, typename V>
170177
static uint64_t dispatch(uint64_t seed, const std::pair<U, V>& target) {

include/maths/CClusterer.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,6 @@ class MATHS_EXPORT CClustererTypes {
125125
template<typename POINT>
126126
class CClusterer : public CClustererTypes {
127127
public:
128-
using TClustererPtr = std::shared_ptr<CClusterer>;
129128
using TPointVec = std::vector<POINT>;
130129
using TPointPrecise = typename SPromoted<POINT>::Type;
131130
using TPointPreciseVec = std::vector<TPointPrecise>;

include/maths/CClustererStateSerialiser.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ struct SDistributionRestoreParams;
4343
//! to potential competitors.
4444
class MATHS_EXPORT CClustererStateSerialiser {
4545
public:
46-
using TClusterer1dPtr = std::shared_ptr<CClusterer1d>;
46+
using TClusterer1dPtr = std::unique_ptr<CClusterer1d>;
4747

4848
public:
4949
//! Construct the appropriate CClusterer sub-class from its state
@@ -73,7 +73,7 @@ class MATHS_EXPORT CClustererStateSerialiser {
7373
//! \note Sets \p ptr to NULL on failure.
7474
template<typename T, std::size_t N>
7575
bool operator()(const SDistributionRestoreParams& params,
76-
std::shared_ptr<CClusterer<CVectorNx1<T, N>>>& ptr,
76+
std::unique_ptr<CClusterer<CVectorNx1<T, N>>>& ptr,
7777
core::CStateRestoreTraverser& traverser) {
7878
return this->operator()(params, CClustererTypes::CDoNothing(),
7979
CClustererTypes::CDoNothing(), ptr, traverser);
@@ -87,7 +87,7 @@ class MATHS_EXPORT CClustererStateSerialiser {
8787
bool operator()(const SDistributionRestoreParams& params,
8888
const CClustererTypes::TSplitFunc& splitFunc,
8989
const CClustererTypes::TMergeFunc& mergeFunc,
90-
std::shared_ptr<CClusterer<CVectorNx1<T, N>>>& ptr,
90+
std::unique_ptr<CClusterer<CVectorNx1<T, N>>>& ptr,
9191
core::CStateRestoreTraverser& traverser) {
9292
std::size_t numResults(0);
9393

include/maths/CModelStateSerialiser.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ struct SModelRestoreParams;
3434
//! compatibility in the future as the classes evolve.
3535
class MATHS_EXPORT CModelStateSerialiser {
3636
public:
37-
using TModelPtr = std::shared_ptr<CModel>;
37+
using TModelPtr = std::unique_ptr<CModel>;
3838

3939
public:
4040
//! Construct the appropriate CPrior sub-class from its state

include/maths/CMultimodalPrior.h

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -49,11 +49,9 @@ namespace maths {
4949
//! point of view this is the composite pattern.
5050
class MATHS_EXPORT CMultimodalPrior : public CPrior {
5151
public:
52-
using TClustererPtr = std::shared_ptr<CClusterer1d>;
53-
using TPriorPtr = std::shared_ptr<CPrior>;
52+
using TClustererPtr = std::unique_ptr<CClusterer1d>;
53+
using TPriorPtr = std::unique_ptr<CPrior>;
5454
using TPriorPtrVec = std::vector<TPriorPtr>;
55-
using TPriorPtrVecItr = TPriorPtrVec::iterator;
56-
using TPriorPtrVecCItr = TPriorPtrVec::const_iterator;
5755
using TMeanVarAccumulator = CBasicStatistics::SSampleMeanVar<double>::TAccumulator;
5856
using TMeanVarAccumulatorVec = std::vector<TMeanVarAccumulator>;
5957

@@ -80,6 +78,9 @@ class MATHS_EXPORT CMultimodalPrior : public CPrior {
8078
double decayRate = 0.0);
8179

8280
//! Create from a collection of weights and priors.
81+
//!
82+
//! \note The priors are moved into place clearing the values in \p priors.
83+
//! \note This constructor doesn't support subsequent update of the prior.
8384
CMultimodalPrior(maths_t::EDataType dataType, double decayRate, TPriorPtrVec& priors);
8485

8586
//! Construct from part of a state document.
@@ -320,7 +321,7 @@ class MATHS_EXPORT CMultimodalPrior : public CPrior {
320321
CMultimodalPrior* m_Prior;
321322
};
322323

323-
using TMode = SMultimodalPriorMode<std::shared_ptr<CPrior>>;
324+
using TMode = SMultimodalPriorMode<TPriorPtr>;
324325
using TModeVec = std::vector<TMode>;
325326

326327
private:

include/maths/CMultimodalPriorMode.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,16 @@ struct SMultimodalPriorMode {
3636
SMultimodalPriorMode() : s_Index(0), s_Prior() {}
3737
SMultimodalPriorMode(std::size_t index, const PRIOR_PTR& prior)
3838
: s_Index(index), s_Prior(prior->clone()) {}
39+
SMultimodalPriorMode(std::size_t index, PRIOR_PTR&& prior)
40+
: s_Index(index), s_Prior(std::move(prior)) {}
41+
SMultimodalPriorMode(SMultimodalPriorMode&& other)
42+
: s_Index(other.s_Index), s_Prior(std::move(other.s_Prior)) {}
43+
SMultimodalPriorMode& operator=(SMultimodalPriorMode&& other) {
44+
s_Index = other.s_Index;
45+
s_Prior = std::move(other.s_Prior);
46+
return *this;
47+
}
48+
SMultimodalPriorMode& operator=(const SMultimodalPriorMode&) = delete;
3949

4050
//! Get the weight of this sample.
4151
double weight() const { return s_Prior->numberSamples(); }

include/maths/CMultivariateMultimodalPrior.h

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#include <maths/MathsTypes.h>
3333

3434
#include <boost/bind.hpp>
35+
#include <boost/make_unique.hpp>
3536
#include <boost/numeric/conversion/bounds.hpp>
3637
#include <boost/ref.hpp>
3738

@@ -50,10 +51,10 @@ namespace multivariate_multimodal_prior_detail {
5051

5152
using TSizeDoublePr = std::pair<size_t, double>;
5253
using TSizeDoublePr3Vec = core::CSmallVector<TSizeDoublePr, 3>;
53-
using TPriorPtr = std::shared_ptr<CMultivariatePrior>;
5454
using TDouble10Vec1Vec = CMultivariatePrior::TDouble10Vec1Vec;
5555
using TDouble10VecWeightsAry1Vec = CMultivariatePrior::TDouble10VecWeightsAry1Vec;
56-
using TMode = SMultimodalPriorMode<std::shared_ptr<CMultivariatePrior>>;
56+
using TPriorPtr = std::unique_ptr<CMultivariatePrior>;
57+
using TMode = SMultimodalPriorMode<TPriorPtr>;
5758
using TModeVec = std::vector<TMode>;
5859

5960
//! Implementation of a sample joint log marginal likelihood calculation.
@@ -134,7 +135,7 @@ class CMultivariateMultimodalPrior : public CMultivariatePrior {
134135
using TMatrix = CSymmetricMatrixNxN<double, N>;
135136
using TMatrixVec = std::vector<TMatrix>;
136137
using TClusterer = CClusterer<TFloatPoint>;
137-
using TClustererPtr = std::shared_ptr<TClusterer>;
138+
using TClustererPtr = std::unique_ptr<TClusterer>;
138139
using TPriorPtrVec = std::vector<TPriorPtr>;
139140

140141
// Lift all overloads of into scope.
@@ -162,13 +163,13 @@ class CMultivariateMultimodalPrior : public CMultivariatePrior {
162163

163164
//! Create from a collection of priors.
164165
//!
165-
//! \note The priors are shallow copied.
166+
//! \note The priors are moved into place clearing the values in \p priors.
166167
//! \note This constructor doesn't support subsequent update of the prior.
167168
CMultivariateMultimodalPrior(maths_t::EDataType dataType, TPriorPtrVec& priors)
168169
: CMultivariatePrior(dataType, 0.0) {
169170
m_Modes.reserve(priors.size());
170171
for (std::size_t i = 0u; i < priors.size(); ++i) {
171-
m_Modes.emplace_back(i, priors[i]);
172+
m_Modes.emplace_back(i, std::move(priors[i]));
172173
}
173174
}
174175

@@ -425,12 +426,12 @@ class CMultivariateMultimodalPrior : public CMultivariatePrior {
425426
for (const auto& mode : m_Modes) {
426427
TUnivariatePriorPtrDoublePr prior(mode.s_Prior->univariate(marginalize, condition));
427428
if (prior.first == nullptr) {
428-
return TUnivariatePriorPtrDoublePr();
429+
return {};
429430
}
430431
if (prior.first->isNonInformative()) {
431432
continue;
432433
}
433-
modes.push_back(prior.first);
434+
modes.push_back(std::move(prior.first));
434435
weights.push_back(prior.second);
435436
maxWeight.add(weights.back());
436437
}
@@ -444,8 +445,8 @@ class CMultivariateMultimodalPrior : public CMultivariatePrior {
444445
modes[i]->numberSamples(weights[i] / Z * modes[i]->numberSamples());
445446
}
446447

447-
return {TUnivariatePriorPtr(new CMultimodalPrior(this->dataType(),
448-
this->decayRate(), modes)),
448+
return {boost::make_unique<CMultimodalPrior>(this->dataType(),
449+
this->decayRate(), modes),
449450
Z > 0.0 ? maxWeight[0] + std::log(Z) : 0.0};
450451
}
451452

@@ -465,7 +466,7 @@ class CMultivariateMultimodalPrior : public CMultivariatePrior {
465466
const TSizeDoublePr10Vec& condition) const {
466467

467468
if (N == 2) {
468-
return TPriorPtrDoublePr(TPriorPtr(this->clone()), 0.0);
469+
return {TPriorPtr(this->clone()), 0.0};
469470
}
470471

471472
std::size_t n = m_Modes.size();
@@ -484,7 +485,7 @@ class CMultivariateMultimodalPrior : public CMultivariatePrior {
484485
if (prior.first->isNonInformative()) {
485486
continue;
486487
}
487-
modes.push_back(prior.first);
488+
modes.push_back(std::move(prior.first));
488489
weights.push_back(prior.second);
489490
maxWeight.add(weights.back());
490491
}
@@ -498,7 +499,7 @@ class CMultivariateMultimodalPrior : public CMultivariatePrior {
498499
modes[i]->numberSamples(weights[i] / Z * modes[i]->numberSamples());
499500
}
500501

501-
return {TPriorPtr(new CMultivariateMultimodalPrior<2>(this->dataType(), modes)),
502+
return {boost::make_unique<CMultivariateMultimodalPrior<2>>(this->dataType(), modes),
502503
Z > 0.0 ? maxWeight[0] + std::log(Z) : 0.0};
503504
}
504505

@@ -905,7 +906,7 @@ class CMultivariateMultimodalPrior : public CMultivariatePrior {
905906

906907
// Create the child modes.
907908
LOG_TRACE(<< "Creating mode with index " << leftSplitIndex);
908-
modes.emplace_back(leftSplitIndex, m_Prior->m_SeedPrior);
909+
modes.emplace_back(leftSplitIndex, TPriorPtr(m_Prior->m_SeedPrior->clone()));
909910
{
910911
TPointVec samples;
911912
if (!m_Prior->m_Clusterer->sample(
@@ -935,7 +936,7 @@ class CMultivariateMultimodalPrior : public CMultivariatePrior {
935936
}
936937

937938
LOG_TRACE(<< "Creating mode with index " << rightSplitIndex);
938-
modes.emplace_back(rightSplitIndex, m_Prior->m_SeedPrior);
939+
modes.emplace_back(rightSplitIndex, TPriorPtr(m_Prior->m_SeedPrior->clone()));
939940
{
940941
TPointVec samples;
941942
if (!m_Prior->m_Clusterer->sample(
@@ -1025,7 +1026,7 @@ class CMultivariateMultimodalPrior : public CMultivariatePrior {
10251026
MODE_TAG, TMode mode,
10261027
traverser.traverseSubLevel(boost::bind(
10271028
&TMode::acceptRestoreTraverser, &mode, boost::cref(params), _1)),
1028-
m_Modes.push_back(mode))
1029+
m_Modes.push_back(std::move(mode)))
10291030
RESTORE_SETUP_TEARDOWN(
10301031
NUMBER_SAMPLES_TAG, double numberSamples,
10311032
core::CStringUtils::stringToType(traverser.value(), numberSamples),

include/maths/CMultivariateMultimodalPriorFactory.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ struct SDistributionRestoreParams;
2525
//! \brief Factory for multivariate multimodal priors.
2626
class MATHS_EXPORT CMultivariateMultimodalPriorFactory {
2727
public:
28-
using TPriorPtr = std::shared_ptr<CMultivariatePrior>;
28+
using TPriorPtr = std::unique_ptr<CMultivariatePrior>;
2929

3030
public:
3131
//! Create a new non-informative multivariate normal prior.

0 commit comments

Comments
 (0)