Skip to content

Commit

Permalink
#123 implement memory footprint mode
Browse files Browse the repository at this point in the history
Implement a function and a mode for measuring total memory footprint of
an object.

- use partial specialization for dispatch
- add implementation and tests for std::unique_ptr, std::string, std::vector
  • Loading branch information
cz4rs committed Sep 8, 2020
1 parent 919bb01 commit 63c2320
Show file tree
Hide file tree
Showing 15 changed files with 448 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,6 @@
build/
CMakeFiles/

*.a
*.cmake
*.tcl
10 changes: 10 additions & 0 deletions src/checkpoint/checkpoint_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,16 @@ std::unique_ptr<T> deserialize(SerializedReturnType&& in);
template <typename T>
std::size_t getSize(T& target);

/**
* \brief Get memory footprint of \c target
*
* \param[in] target reference to \c T to measure footprint
*
* \return memory footprint of the \c target
*/
template <typename T>
std::size_t getMemoryFootprint(T& target);

/**
* \brief Serialize \c T to file with filename \c file
*
Expand Down
5 changes: 5 additions & 0 deletions src/checkpoint/checkpoint_api.impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,11 @@ std::size_t getSize(T& target) {
return dispatch::Standard::size<T, Sizer>(target);
}

template <typename T>
std::size_t getMemoryFootprint(T& target) {
return dispatch::Standard::footprint<T, Footprinter>(target);
}

template <typename T>
void serializeToFile(T& target, std::string const& file) {
auto len = getSize<T>(target);
Expand Down
6 changes: 6 additions & 0 deletions src/checkpoint/container/string_serialize.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,12 @@ void serialize(Serializer& s, std::string& str) {
dispatch::serializeArray(s, str.c_str(), str.size());
}

template <typename Serializer>
void getMemoryFootprint(Serializer& s, std::string& str) {
s.countBytes(str);
dispatch::serializeArray(s, str.c_str(), str.capacity());
}

} /* end namespace checkpoint */

#endif /*INCLUDED_CHECKPOINT_CONTAINER_STRING_SERIALIZE_H*/
19 changes: 19 additions & 0 deletions src/checkpoint/container/unique_ptr_serialize.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,25 @@ void serialize(Serializer& s, std::unique_ptr<T>& ptr) {
}
}

template <typename Serializer, typename T>
void getMemoryFootprint(Serializer& s, std::unique_ptr<T>& ptr) {
s.countBytes(ptr);

if (ptr != nullptr) {
s | *ptr;
}
}

// FIXME - not related to unique_ptr
template <typename Serializer, typename T>
void getMemoryFootprint(Serializer& s, T* ptr) {
s.countBytes(ptr);

if (ptr != nullptr) {
s | *ptr;
}
}

} /* end namespace checkpoint */

#endif /*INCLUDED_CHECKPOINT_CONTAINER_UNIQUE_PTR_SERIALIZE_H*/
6 changes: 6 additions & 0 deletions src/checkpoint/container/vector_serialize.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,12 @@ void serialize(Serializer& s, std::vector<T, VectorAllocator>& vec) {
dispatch::serializeArray(s, &vec[0], vec.size());
}

template <typename Serializer, typename T, typename VectorAllocator>
void getMemoryFootprint(Serializer& s, std::vector<T, VectorAllocator>& vec) {
s.countBytes(vec);
dispatch::serializeArray(s, &vec[0], vec.capacity());
}

template <typename Serializer, typename VectorAllocator>
void serialize(Serializer& s, std::vector<bool, VectorAllocator>& vec) {
serializeVectorMeta(s, vec);
Expand Down
11 changes: 11 additions & 0 deletions src/checkpoint/dispatch/dispatch.h
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,17 @@ struct Standard {
template <typename T, typename SizerT, typename...Args>
static SerialSizeType size(T& target, Args&&... args);

/**
* \brief Recursively get the memory footprint of \c T
*
* \param[in] target the target to measure
* \param[in] args arguments to the footprinter's constructor
*
* \return memory footprint of \c T
*/
template <typename T, typename FootprinterT, typename...Args>
static SerialSizeType footprint(T& target, Args&&... args);

/**
* \brief Pack \c target that requires \c size number of bytes.
*
Expand Down
8 changes: 8 additions & 0 deletions src/checkpoint/dispatch/dispatch.impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,14 @@ SerialSizeType Standard::size(T& target, Args&&... args) {
return sizer.getSize();
}

template <typename T, typename FootprinterT, typename...Args>
SerialSizeType Standard::footprint(T& target, Args&&... args) {
auto footprinter = Traverse::with<T, FootprinterT>(
target, std::forward<Args>(args)...
);
return footprinter.getMemoryFootprint();
}

template <typename T, typename PackerT, typename... Args>
PackerT Standard::pack(T& target, SerialSizeType const& size, Args&&... args) {
return Traverse::with<T, PackerT>(target, size, std::forward<Args>(args)...);
Expand Down
74 changes: 74 additions & 0 deletions src/checkpoint/dispatch/dispatch_serializer_nonbyte.h
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,80 @@ struct SerializerDispatchNonByte {
}
};

#if !HAS_DETECTION_COMPONENT
template <typename SerializerT, typename T>
struct hasGetMemoryFootprint {
template <
typename C,
typename = decltype(std::declval<C>().getMemoryFootprint(std::declval<SerializerT&>()))
>
static std::true_type test(int);

template <typename C>
static std::false_type test(...);

static constexpr bool value = decltype(test<T>(0))::value;
};
#endif

template <typename T>
struct SerializerDispatchNonByte <Footprinter, T, MemoryFootprintDispatch<Footprinter, T>> {
using Dispatcher = MemoryFootprintDispatch<Footprinter, T>;

void operator()(Footprinter& s, T* val, SerialSizeType num);

#if HAS_DETECTION_COMPONENT
template <typename U>
using hasInGetMemoryFootprint =
std::enable_if_t<
SerializableTraits<U>::has_get_memory_footprint_intrusive, T
>;

template <typename U>
using hasNoninGetMemoryFootprint =
std::enable_if_t<
SerializableTraits<U>::has_get_memory_footprint_nonintrusive, T
>;
#else
template <typename U>
using hasInGetMemoryFootprint =
std::enable_if_t<hasGetMemoryFootprint<SerializerT, U>::value, T>;

template <typename U>
using hasNoninGetMemoryFootprint =
std::enable_if_t<!hasGetMemoryFootprint<SerializerT, U>::value, T>;
#endif

template <typename U = T>
void apply(
Footprinter& s, T* val, SerialSizeType num,
hasInGetMemoryFootprint<U>* = nullptr
) {
for (SerialSizeType i = 0; i < num; i++) {
Dispatcher::serializeIntrusive(s, val[i]);
}
}

template <typename U = T>
void apply(
Footprinter& s, T* val, SerialSizeType num,
hasNoninGetMemoryFootprint<U>* = nullptr
) {
for (SerialSizeType i = 0; i < num; i++) {
Dispatcher::serializeNonIntrusive(s, val[i]);
}
}
};

template <typename T>
void SerializerDispatchNonByte<
Footprinter,
T,
MemoryFootprintDispatch<Footprinter, T>
>::operator()(Footprinter& s, T* val, SerialSizeType num) {
apply(s, val, num);
}

}} /* end namespace checkpoint::dispatch */

#endif /*INCLUDED_CHECKPOINT_DISPATCH_DISPATCH_SERIALIZER_NONBYTE_H*/
2 changes: 2 additions & 0 deletions src/checkpoint/serializers/base_serializer.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ enum struct eSerializationMode : int8_t {
Unpacking = 1,
Packing = 2,
Sizing = 3,
Footprinting = 4,
Invalid = -1
};

Expand All @@ -79,6 +80,7 @@ struct Serializer {
bool isSizing() const { return cur_mode_ == ModeType::Sizing; }
bool isPacking() const { return cur_mode_ == ModeType::Packing; }
bool isUnpacking() const { return cur_mode_ == ModeType::Unpacking; }
bool isFootprinting() const { return cur_mode_ == ModeType::Footprinting; }

template <typename SerializerT, typename T>
void contiguousTyped(SerializerT& serdes, T* ptr, SerialSizeType num_elms) {
Expand Down
58 changes: 58 additions & 0 deletions src/checkpoint/serializers/footprinter.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
//@HEADER
// *****************************************************************************
//
// footprinter.cc
// DARMA Toolkit v. 1.0.0
// DARMA/checkpoint => Serialization Library
//
// Copyright 2020 National Technology & Engineering Solutions of Sandia, LLC
// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S.
// Government retains certain rights in this software.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// Questions? Contact darma@sandia.gov
//
// *****************************************************************************
//@HEADER
*/

#include "checkpoint/serializers/footprinter.h"

namespace checkpoint {

SerialSizeType Footprinter::getMemoryFootprint() const {
return num_bytes_;
}

void Footprinter::contiguousBytes(void*, SerialSizeType size, SerialSizeType num_elms) {
//printf("contiguousBytes: size=%zu, num_elms=%zu\n", size, num_elms);
num_bytes_ += size * num_elms;
}

} /* end namespace checkpoint */
84 changes: 84 additions & 0 deletions src/checkpoint/serializers/footprinter.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/*
//@HEADER
// *****************************************************************************
//
// footprinter.h
// DARMA Toolkit v. 1.0.0
// DARMA/checkpoint => Serialization Library
//
// Copyright 2020 National Technology & Engineering Solutions of Sandia, LLC
// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S.
// Government retains certain rights in this software.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// Questions? Contact darma@sandia.gov
//
// *****************************************************************************
//@HEADER
*/

#if !defined INCLUDED_CHECKPOINT_SERIALIZERS_FOOTPRINTER_H
#define INCLUDED_CHECKPOINT_SERIALIZERS_FOOTPRINTER_H

#include "checkpoint/common.h"
#include "checkpoint/serializers/base_serializer.h"

//#include <typeinfo>

namespace checkpoint {

template <typename SerializerT, typename T>
struct MemoryFootprintDispatch {
static void serializeIntrusive(SerializerT& s, T& t) {
//printf("MemoryFootprintDispatch::serializeIntrusive - type is %s\n", typeid(T).name());
t.getMemoryFootprint(s);
}
static void serializeNonIntrusive(SerializerT& s, T& t) {
//printf("MemoryFootprintDispatch::serializeNonIntrusive - type is %s\n", typeid(T).name());
getMemoryFootprint(s, t);
}
};

struct Footprinter : Serializer {
template <typename U, typename V>
using DispatcherType = MemoryFootprintDispatch<U, V>;

Footprinter() : Serializer(ModeType::Footprinting) { }

SerialSizeType getMemoryFootprint() const;
void contiguousBytes(void*, SerialSizeType size, SerialSizeType num_elms);
template<typename T>
void countBytes(const T& t) { num_bytes_ += sizeof t; }

private:
SerialSizeType num_bytes_ = 0;
};

} /* end namespace checkpoint */

#endif /*INCLUDED_CHECKPOINT_SERIALIZERS_FOOTPRINTER_H*/
1 change: 1 addition & 0 deletions src/checkpoint/serializers/serializers_headers.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@

#include "checkpoint/common.h"
#include "checkpoint/serializers/base_serializer.h"
#include "checkpoint/serializers/footprinter.h"
#include "checkpoint/serializers/sizer.h"
#include "checkpoint/serializers/packer.h"
#include "checkpoint/serializers/unpacker.h"
Expand Down
17 changes: 17 additions & 0 deletions src/checkpoint/traits/serializable_traits.h
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,23 @@ struct SerializableTraits {
static constexpr auto const has_serialize_function =
has_serialize_instrusive or has_serialize_noninstrusive;

template <typename U>
using footprint_intrusive_t = decltype(
std::declval<U>().getMemoryFootprint(std::declval<Serializer&>())
);

static constexpr auto const has_get_memory_footprint_intrusive =
detection::is_detected<footprint_intrusive_t, T>::value;

template <typename U>
using footprint_nonintrustive_t = decltype(getMemoryFootprint(
std::declval<Serializer&>(),
std::declval<U&>()
));

static constexpr auto const has_get_memory_footprint_nonintrusive =
detection::is_detected<footprint_nonintrustive_t, T>::value;

// This defines what it means to have parent serializability
static constexpr auto const has_parent_serialize = has_serializeParent::value;

Expand Down
Loading

0 comments on commit 63c2320

Please sign in to comment.