Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions docs/CHANGELOG.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ Secure the ML processes by preventing system calls such as fork and exec. The Li
Seccomp BPF to intercept system calls and is available in kernels since 3.5. On Windows Job Objects prevent
new processes being created and macOS uses the sandbox functionality ({pull}98[#98])

Fix a bug causing us to under estimate the memory used by shared pointers and reduce the memory consumed
by unnecessary reference counting ({pull}108[#108])

=== Bug Fixes

Age seasonal components in proportion to the fraction of values with which they're updated ({pull}88[#88])
Expand Down
2 changes: 1 addition & 1 deletion include/api/CForecastRunner.h
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ class API_EXPORT CForecastRunner final : private core::CNonCopyable {
using TForecastModelWrapper = model::CForecastDataSink::SForecastModelWrapper;
using TForecastResultSeries = model::CForecastDataSink::SForecastResultSeries;
using TForecastResultSeriesVec = std::vector<TForecastResultSeries>;
using TMathsModelPtr = std::shared_ptr<maths::CModel>;
using TMathsModelPtr = std::unique_ptr<maths::CModel>;

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

Expand Down
41 changes: 30 additions & 11 deletions include/core/CMemory.h
Original file line number Diff line number Diff line change
Expand Up @@ -287,21 +287,25 @@ class CORE_EXPORT CMemory : private CNonInstantiatable {
static std::size_t
dynamicSize(const T& t,
typename boost::enable_if<typename boost::is_pointer<T>>::type* = nullptr) {
if (t == nullptr) {
return 0;
}
return staticSize(*t) + dynamicSize(*t);
return t == nullptr ? 0 : staticSize(*t) + dynamicSize(*t);
}

//! Overload for std::shared_ptr.
template<typename T>
static std::size_t dynamicSize(const std::shared_ptr<T>& t) {
if (!t) {
if (t == nullptr) {
return 0;
}
long uc = t.use_count();
// Round up
return (staticSize(*t) + dynamicSize(*t) + std::size_t(uc - 1)) / uc;
// Note we add on sizeof(long) here to account for the memory
// used by the shared reference count. Also, round up.
return (sizeof(long) + staticSize(*t) + dynamicSize(*t) + std::size_t(uc - 1)) / uc;
}

//! Overload for std::unique_ptr.
template<typename T>
static std::size_t dynamicSize(const std::unique_ptr<T>& t) {
return t == nullptr ? 0 : staticSize(*t) + dynamicSize(*t);
}

//! Overload for boost::array.
Expand Down Expand Up @@ -692,25 +696,40 @@ class CORE_EXPORT CMemoryDebug : private CNonInstantiatable {
static void dynamicSize(const char* name,
const std::shared_ptr<T>& t,
CMemoryUsage::TMemoryUsagePtr mem) {
if (t) {
if (t != nullptr) {
long uc = t.use_count();
// If the pointer is shared by multiple users, each one
// might count it, so divide by the number of users.
// However, if only 1 user has it, do a full debug.
if (uc == 1) {
mem->addItem("shared_ptr", CMemory::staticSize(*t));
// Note we add on sizeof(long) here to account for
// the memory used by the shared reference count.
mem->addItem("shared_ptr", sizeof(long) + CMemory::staticSize(*t));
dynamicSize(name, *t, mem);
} else {
std::ostringstream ss;
ss << "shared_ptr (x" << uc << ')';
// Round up
mem->addItem(ss.str(), (CMemory::staticSize(*t) +
// Note we add on sizeof(long) here to account for
// the memory used by the shared reference count.
// Also, round up.
mem->addItem(ss.str(), (sizeof(long) + CMemory::staticSize(*t) +
CMemory::dynamicSize(*t) + std::size_t(uc - 1)) /
uc);
}
}
}

//! Overload for std::unique_ptr.
template<typename T>
static void dynamicSize(const char* name,
const std::unique_ptr<T>& t,
CMemoryUsage::TMemoryUsagePtr mem) {
if (t != nullptr) {
mem->addItem("ptr", CMemory::staticSize(*t));
memory_detail::SDebugMemoryDynamicSize<T>::dispatch(name, *t, mem);
}
}

//! Overload for boost::array.
template<typename T, std::size_t N>
static void dynamicSize(const char* name,
Expand Down
9 changes: 8 additions & 1 deletion include/maths/CChecksum.h
Original file line number Diff line number Diff line change
Expand Up @@ -158,13 +158,20 @@ class CChecksumImpl<BasicChecksum> {
: CChecksumImpl<typename selector<T>::value>::dispatch(seed, *target);
}

//! Checksum a pointer.
//! Checksum a shared pointer.
template<typename T>
static uint64_t dispatch(uint64_t seed, const std::shared_ptr<T>& target) {
return !target ? seed
: CChecksumImpl<typename selector<T>::value>::dispatch(seed, *target);
}

//! Checksum a unique pointer.
template<typename T>
static uint64_t dispatch(uint64_t seed, const std::unique_ptr<T>& target) {
return !target ? seed
: CChecksumImpl<typename selector<T>::value>::dispatch(seed, *target);
}

//! Checksum a pair.
template<typename U, typename V>
static uint64_t dispatch(uint64_t seed, const std::pair<U, V>& target) {
Expand Down
1 change: 0 additions & 1 deletion include/maths/CClusterer.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,6 @@ class MATHS_EXPORT CClustererTypes {
template<typename POINT>
class CClusterer : public CClustererTypes {
public:
using TClustererPtr = std::shared_ptr<CClusterer>;
using TPointVec = std::vector<POINT>;
using TPointPrecise = typename SPromoted<POINT>::Type;
using TPointPreciseVec = std::vector<TPointPrecise>;
Expand Down
6 changes: 3 additions & 3 deletions include/maths/CClustererStateSerialiser.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ struct SDistributionRestoreParams;
//! to potential competitors.
class MATHS_EXPORT CClustererStateSerialiser {
public:
using TClusterer1dPtr = std::shared_ptr<CClusterer1d>;
using TClusterer1dPtr = std::unique_ptr<CClusterer1d>;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

General problem:

In other parts of the code we use UPtr, so TClusterer1dPtr would be TClusterer1dUPtr.

Copy link
Contributor Author

@tveasey tveasey May 29, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought about this. The problem with renaming the type of pointer is that it makes changes like this much more difficult. Everywhere the typedef is referred to suddenly has to change as well. So this change will become a whole lot bigger. Also we don't use SPtr for shared_ptr for example which would be consistent with this pattern.

Whilst we probably don't need to change this type again, I don't like that an "implementation detail" (type of smart pointer) gets mixed up with the name of the type. In some cases we can't avoid this because we have a shared_ptr<T> and a unique_ptr<T> in the same scope but in most cases we can.

Thoughts?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am fine with that, actually I agree more to what you wrote, for me one purpose of a typedef/using is to abstract away the implementation detail, putting it back in the name defeats this.

I just wanted to point it out, if you grep the codebase for UPtr you find a small number of uses but I could not find a rule in our new and old styleguide.

Any other comments on this?

Copy link
Contributor Author

@tveasey tveasey May 30, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes I think our naming of pointer types is not completely consistent. I would propose something like the following rules:

  1. If there are no name collisions, all pointer types should just be suffixed with Ptr
  2. If there would be a name collision then all pointer types should be all qualified: shared_ptr as SPtr, unique_ptr as UPtr, auto_ptr as APtr and weak_ptr as WPtr.

Let's take this discussion offline though. If we get agreement on this we can revisit the codebase and tidy up the naming to conform to this in a separate PR.


public:
//! Construct the appropriate CClusterer sub-class from its state
Expand Down Expand Up @@ -73,7 +73,7 @@ class MATHS_EXPORT CClustererStateSerialiser {
//! \note Sets \p ptr to NULL on failure.
template<typename T, std::size_t N>
bool operator()(const SDistributionRestoreParams& params,
std::shared_ptr<CClusterer<CVectorNx1<T, N>>>& ptr,
std::unique_ptr<CClusterer<CVectorNx1<T, N>>>& ptr,
core::CStateRestoreTraverser& traverser) {
return this->operator()(params, CClustererTypes::CDoNothing(),
CClustererTypes::CDoNothing(), ptr, traverser);
Expand All @@ -87,7 +87,7 @@ class MATHS_EXPORT CClustererStateSerialiser {
bool operator()(const SDistributionRestoreParams& params,
const CClustererTypes::TSplitFunc& splitFunc,
const CClustererTypes::TMergeFunc& mergeFunc,
std::shared_ptr<CClusterer<CVectorNx1<T, N>>>& ptr,
std::unique_ptr<CClusterer<CVectorNx1<T, N>>>& ptr,
core::CStateRestoreTraverser& traverser) {
std::size_t numResults(0);

Expand Down
2 changes: 1 addition & 1 deletion include/maths/CModelStateSerialiser.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ struct SModelRestoreParams;
//! compatibility in the future as the classes evolve.
class MATHS_EXPORT CModelStateSerialiser {
public:
using TModelPtr = std::shared_ptr<CModel>;
using TModelPtr = std::unique_ptr<CModel>;

public:
//! Construct the appropriate CPrior sub-class from its state
Expand Down
11 changes: 6 additions & 5 deletions include/maths/CMultimodalPrior.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,9 @@ namespace maths {
//! point of view this is the composite pattern.
class MATHS_EXPORT CMultimodalPrior : public CPrior {
public:
using TClustererPtr = std::shared_ptr<CClusterer1d>;
using TPriorPtr = std::shared_ptr<CPrior>;
using TClustererPtr = std::unique_ptr<CClusterer1d>;
using TPriorPtr = std::unique_ptr<CPrior>;
using TPriorPtrVec = std::vector<TPriorPtr>;
using TPriorPtrVecItr = TPriorPtrVec::iterator;
using TPriorPtrVecCItr = TPriorPtrVec::const_iterator;
using TMeanVarAccumulator = CBasicStatistics::SSampleMeanVar<double>::TAccumulator;
using TMeanVarAccumulatorVec = std::vector<TMeanVarAccumulator>;

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

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

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

using TMode = SMultimodalPriorMode<std::shared_ptr<CPrior>>;
using TMode = SMultimodalPriorMode<TPriorPtr>;
using TModeVec = std::vector<TMode>;

private:
Expand Down
2 changes: 2 additions & 0 deletions include/maths/CMultimodalPriorMode.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ struct SMultimodalPriorMode {
SMultimodalPriorMode() : s_Index(0), s_Prior() {}
SMultimodalPriorMode(std::size_t index, const PRIOR_PTR& prior)
: s_Index(index), s_Prior(prior->clone()) {}
SMultimodalPriorMode(std::size_t index, PRIOR_PTR&& prior)
: s_Index(index), s_Prior(std::move(prior)) {}

//! Get the weight of this sample.
double weight() const { return s_Prior->numberSamples(); }
Expand Down
31 changes: 16 additions & 15 deletions include/maths/CMultivariateMultimodalPrior.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include <maths/MathsTypes.h>

#include <boost/bind.hpp>
#include <boost/make_unique.hpp>
#include <boost/numeric/conversion/bounds.hpp>
#include <boost/ref.hpp>

Expand All @@ -50,10 +51,10 @@ namespace multivariate_multimodal_prior_detail {

using TSizeDoublePr = std::pair<size_t, double>;
using TSizeDoublePr3Vec = core::CSmallVector<TSizeDoublePr, 3>;
using TPriorPtr = std::shared_ptr<CMultivariatePrior>;
using TDouble10Vec1Vec = CMultivariatePrior::TDouble10Vec1Vec;
using TDouble10VecWeightsAry1Vec = CMultivariatePrior::TDouble10VecWeightsAry1Vec;
using TMode = SMultimodalPriorMode<std::shared_ptr<CMultivariatePrior>>;
using TPriorPtr = std::unique_ptr<CMultivariatePrior>;
using TMode = SMultimodalPriorMode<TPriorPtr>;
using TModeVec = std::vector<TMode>;

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

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

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

Expand Down Expand Up @@ -425,12 +426,12 @@ class CMultivariateMultimodalPrior : public CMultivariatePrior {
for (const auto& mode : m_Modes) {
TUnivariatePriorPtrDoublePr prior(mode.s_Prior->univariate(marginalize, condition));
if (prior.first == nullptr) {
return TUnivariatePriorPtrDoublePr();
return {};
}
if (prior.first->isNonInformative()) {
continue;
}
modes.push_back(prior.first);
modes.push_back(std::move(prior.first));
weights.push_back(prior.second);
maxWeight.add(weights.back());
}
Expand All @@ -444,8 +445,8 @@ class CMultivariateMultimodalPrior : public CMultivariatePrior {
modes[i]->numberSamples(weights[i] / Z * modes[i]->numberSamples());
}

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

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

if (N == 2) {
return TPriorPtrDoublePr(TPriorPtr(this->clone()), 0.0);
return {TPriorPtr(this->clone()), 0.0};
}

std::size_t n = m_Modes.size();
Expand All @@ -484,7 +485,7 @@ class CMultivariateMultimodalPrior : public CMultivariatePrior {
if (prior.first->isNonInformative()) {
continue;
}
modes.push_back(prior.first);
modes.push_back(std::move(prior.first));
weights.push_back(prior.second);
maxWeight.add(weights.back());
}
Expand All @@ -498,7 +499,7 @@ class CMultivariateMultimodalPrior : public CMultivariatePrior {
modes[i]->numberSamples(weights[i] / Z * modes[i]->numberSamples());
}

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

Expand Down Expand Up @@ -905,7 +906,7 @@ class CMultivariateMultimodalPrior : public CMultivariatePrior {

// Create the child modes.
LOG_TRACE(<< "Creating mode with index " << leftSplitIndex);
modes.emplace_back(leftSplitIndex, m_Prior->m_SeedPrior);
modes.emplace_back(leftSplitIndex, TPriorPtr(m_Prior->m_SeedPrior->clone()));
{
TPointVec samples;
if (!m_Prior->m_Clusterer->sample(
Expand Down Expand Up @@ -935,7 +936,7 @@ class CMultivariateMultimodalPrior : public CMultivariatePrior {
}

LOG_TRACE(<< "Creating mode with index " << rightSplitIndex);
modes.emplace_back(rightSplitIndex, m_Prior->m_SeedPrior);
modes.emplace_back(rightSplitIndex, TPriorPtr(m_Prior->m_SeedPrior->clone()));
{
TPointVec samples;
if (!m_Prior->m_Clusterer->sample(
Expand Down Expand Up @@ -1025,7 +1026,7 @@ class CMultivariateMultimodalPrior : public CMultivariatePrior {
MODE_TAG, TMode mode,
traverser.traverseSubLevel(boost::bind(
&TMode::acceptRestoreTraverser, &mode, boost::cref(params), _1)),
m_Modes.push_back(mode))
m_Modes.push_back(std::move(mode)))
RESTORE_SETUP_TEARDOWN(
NUMBER_SAMPLES_TAG, double numberSamples,
core::CStringUtils::stringToType(traverser.value(), numberSamples),
Expand Down
2 changes: 1 addition & 1 deletion include/maths/CMultivariateMultimodalPriorFactory.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ struct SDistributionRestoreParams;
//! \brief Factory for multivariate multimodal priors.
class MATHS_EXPORT CMultivariateMultimodalPriorFactory {
public:
using TPriorPtr = std::shared_ptr<CMultivariatePrior>;
using TPriorPtr = std::unique_ptr<CMultivariatePrior>;

public:
//! Create a new non-informative multivariate normal prior.
Expand Down
Loading