Skip to content

Commit

Permalink
api: add pvt::heapsize() and pvt::footprint() methods and image cache…
Browse files Browse the repository at this point in the history
… memory tracking (#4322)

First PR of two, following @lgritz and I discussions on memory tracking
in the OIIO::ImageCache.
- Add two template methods and their specializations for types various
to help memory tracking:
```c++
// return the total heap allocated memory held by the object and its members
template<typename T> inline size_t heapsize(const T& t);
// return the total memory footprint including the size of the structure itself
template<typename T> inline size_t footprint(const T& t);
```
- Specialized for: ParamValue, ParamValueList, ImageSpec, ImageInput,
ImageOutput, std::vector, std::shared_ptr, std::unique_ptr,
oiio::intrusive_ptr, ImageCacheImpl related objects.
- New files: 
- `include/memory.h` : adds base and few types specialization of
heapsize and footprint.
- `libtexture/imagecache_memory_pvt.h` : adds specilializations for
ImageCacheImpl and related objects.
- `libtexture/imagecache_memory_print.h` : adds a helper function that
print a breakdown of the ImageCacheImpl total memory usage as well, as
well as per image format. Note: this is slow, but gives accurate memory
estimation.

Related PR from Larry :
#4317

Signed-off-by: Basile Fraboni <[email protected]>
  • Loading branch information
bfraboni authored Aug 11, 2024
1 parent 64f829f commit af13eb9
Show file tree
Hide file tree
Showing 15 changed files with 609 additions and 24 deletions.
2 changes: 2 additions & 0 deletions src/include/OpenImageIO/imagecache.h
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,8 @@ class OIIO_API ImageCache {
/// all files referenced by calls to the ImageCache. (The
/// array is of `ustring` or `char*`.)
///
/// - `int64 stat:cache_footprint` :
/// Total bytes used by image cache.
/// - `int64 stat:cache_memory_used` :
/// Total bytes used by tile cache.
///
Expand Down
20 changes: 20 additions & 0 deletions src/include/OpenImageIO/imageio.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
#include <OpenImageIO/strutil.h>
#include <OpenImageIO/thread.h>
#include <OpenImageIO/typedesc.h>
#include <OpenImageIO/memory.h>

OIIO_NAMESPACE_BEGIN

Expand Down Expand Up @@ -1884,6 +1885,9 @@ class OIIO_API ImageInput {
std::unique_ptr<Impl, decltype(&impl_deleter)> m_impl;

void append_error(string_view message) const; // add to error message

/// declare a friend heapsize definition
template <typename T> friend size_t pvt::heapsize(const T&);
};


Expand Down Expand Up @@ -2788,10 +2792,26 @@ class OIIO_API ImageOutput {
std::unique_ptr<Impl, decltype(&impl_deleter)> m_impl;

void append_error(string_view message) const; // add to m_errmessage

/// declare a friend heapsize definition
template <typename T> friend size_t pvt::heapsize(const T&);
};



/// Memory tracking. Specializes the base memory tracking functions from memory.h.

// heapsize specialization for `ImageSpec`
template <> OIIO_API size_t pvt::heapsize<ImageSpec>(const ImageSpec&);

// heapsize specialization for `ImageInput`
template <> OIIO_API size_t pvt::heapsize<ImageInput>(const ImageInput&);

// heapsize specialization for `ImageOutput`
template <> OIIO_API size_t pvt::heapsize<ImageOutput>(const ImageOutput&);



// Utility functions

/// `OIIO::shutdown` prepares OpenImageIO for shutdown. Before exiting an
Expand Down
117 changes: 117 additions & 0 deletions src/include/OpenImageIO/memory.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
// Copyright Contributors to the OpenImageIO project.
// SPDX-License-Identifier: Apache-2.0
// https://github.com/AcademySoftwareFoundation/OpenImageIO


/////////////////////////////////////////////////////////////////////////
/// @file memory.h
///
/// @brief Utilities for memory tracking.
/////////////////////////////////////////////////////////////////////////


#pragma once

#define OPENIMAGEIO_MEMORY_H

#include <cstring>
#include <memory>
#include <vector>

OIIO_NAMESPACE_BEGIN

namespace pvt {

/// Return the total heap memory allocated by `object`.
/// The template specialization can be used to give improved results for non trivial types
/// that perform heap allocation, and to include members allocations recursively.
template<typename T>
inline size_t
heapsize(const T& t)
{
return 0;
}

/// Return the total memory footprint of `object`. If possible, including any heap
/// allocations done by any constituent parts. The default implementation just reduces
/// to sizeof(object), given that heapsize(object) would return 0.
/// The template specialization can be used to give improved results for non trivial types
/// that perform heap allocation.
template<typename T>
inline size_t
footprint(const T& t)
{
return sizeof(T) + heapsize(t);
}

template<typename T>
inline size_t
footprint(const T* t)
{
return sizeof(T) + (t ? footprint(*t) : 0);
}

/// Specializations for common STL types


// heapsize specialization for std::string
template<>
inline size_t
heapsize<std::string>(const std::string& s)
{
// accounts for small string optimization that does not
// use any heap allocations
const char* const sbegin = (const char*)&s;
const char* const send = sbegin + sizeof(std::string);
const char* const sdata = s.data();
const bool is_small = sdata >= sbegin && sdata < send;
return is_small ? 0 : s.capacity();
}

// heapsize specialization for std::vector
template<typename T>
inline size_t
heapsize(const std::vector<T>& vec)
{
size_t size = 0;
for (const T& elem : vec)
size += footprint(elem);
return size;
}

// heapsize specialization for std::shared_ptr
template<typename T>
inline size_t
heapsize(const std::shared_ptr<T>& ref)
{
return ref ? footprint(*ref.get()) : 0;
}

// footprint specialization for std::shared_ptr
template<typename T>
inline size_t
footprint(const std::shared_ptr<T>& ref)
{
return sizeof(std::shared_ptr<T>) + heapsize(ref);
}

// heapsize specialization for std::unique_ptr
template<typename T>
inline size_t
heapsize(const std::unique_ptr<T>& ref)
{
return ref ? footprint(*ref.get()) : 0;
}

// footprint specialization for std::unique_ptr
template<typename T>
inline size_t
footprint(const std::unique_ptr<T>& ref)
{
return sizeof(std::unique_ptr<T>) + heapsize(ref);
}

} // namespace pvt


OIIO_NAMESPACE_END
9 changes: 8 additions & 1 deletion src/include/OpenImageIO/paramlist.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

#include <OpenImageIO/attrdelegate.h>
#include <OpenImageIO/export.h>
#include <OpenImageIO/memory.h>
#include <OpenImageIO/strongparam.h>
#include <OpenImageIO/typedesc.h>
#include <OpenImageIO/ustring.h>
Expand Down Expand Up @@ -276,9 +277,15 @@ class OIIO_UTIL_API ParamValue {
Copy _copy = Copy(true),
FromUstring _from_ustring = FromUstring(false)) noexcept;
void clear_value() noexcept;
};

/// declare a friend heapsize definition
template<typename T> friend size_t pvt::heapsize(const T&);
};

/// heapsize specialization for `ParamValue`
template<>
OIIO_API size_t
pvt::heapsize<ParamValue>(const ParamValue&);

/// Factory for a ParamValue that holds a single value of any type supported
/// by a corresponding ParamValue constructor (such as int, float, string).
Expand Down
22 changes: 22 additions & 0 deletions src/include/OpenImageIO/refcnt.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

#include <OpenImageIO/atomic.h>
#include <OpenImageIO/dassert.h>
#include <OpenImageIO/memory.h>


OIIO_NAMESPACE_BEGIN
Expand Down Expand Up @@ -232,4 +233,25 @@ intrusive_ptr_release(T* x)
#define OIIO_REFCNT_HAS_RELEASE 1 /* intrusive_ptr::release() */


/// Memory tracking. Specializes the base memory tracking functions from memory.h.

// heapsize specialization for `intrusive_ptr`
namespace pvt {
template<typename T>
inline size_t
heapsize(const intrusive_ptr<T>& ref)
{
return ref ? footprint(*ref.get()) : 0;
}

// footprint specialization for `intrusive_ptr`
template<typename T>
inline size_t
footprint(const intrusive_ptr<T>& ref)
{
return sizeof(intrusive_ptr<T>) + heapsize(ref);
}
} // namespace pvt


OIIO_NAMESPACE_END
13 changes: 13 additions & 0 deletions src/libOpenImageIO/formatspec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1251,4 +1251,17 @@ ImageSpec::set_colorspace(string_view colorspace)
}



template<>
size_t
pvt::heapsize<ImageSpec>(const ImageSpec& is)
{
size_t size = pvt::heapsize(is.channelformats);
size += pvt::heapsize(is.channelnames);
size += pvt::heapsize(is.extra_attribs);
return size;
}



OIIO_NAMESPACE_END
13 changes: 13 additions & 0 deletions src/libOpenImageIO/imageinput.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1337,4 +1337,17 @@ ImageInput::check_open(const ImageSpec& spec, ROI range, uint64_t /*flags*/)
return true; // all is ok
}



template<>
size_t
pvt::heapsize<ImageInput>(const ImageInput& input)
{
//! TODO: change ImageInput API to add a virtual heapsize() function
//! to allow per image input override, and call that function here.
return pvt::heapsize(input.m_spec);
}



OIIO_NAMESPACE_END
11 changes: 11 additions & 0 deletions src/libOpenImageIO/imageoutput.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1021,4 +1021,15 @@ ImageOutput::check_open(OpenMode mode, const ImageSpec& userspec, ROI range,



template<>
size_t
pvt::heapsize<ImageOutput>(const ImageOutput& output)
{
//! TODO: change ImageOutput API to add a virtual heapsize() function
//! to allow per image output override, and call that function here.
return pvt::heapsize(output.m_spec);
}



OIIO_NAMESPACE_END
4 changes: 4 additions & 0 deletions src/libOpenImageIO/imagespec_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,8 @@ test_imagespec_from_xml()
std::cout << "test_imagespec_from_xml\n";
ImageSpec spec;
spec.from_xml(imagespec_xml_string);
print(" spec heapsize = {}\n", pvt::heapsize(spec));
print(" spec footprint = {}\n", pvt::footprint(spec));

OIIO_CHECK_EQUAL(spec.nchannels, 4);
OIIO_CHECK_EQUAL(spec.width, 1920);
Expand All @@ -331,6 +333,8 @@ test_imagespec_from_xml()
int
main(int /*argc*/, char* /*argv*/[])
{
print("sizeof(ImageSpec) = {}\n", sizeof(ImageSpec));

test_imagespec_pixels();
test_imagespec_metadata_val();
test_imagespec_attribute_from_string();
Expand Down
5 changes: 5 additions & 0 deletions src/libtexture/imagecache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
#include <OpenImageIO/typedesc.h>
#include <OpenImageIO/ustring.h>

#include "imagecache_memory_print.h"
#include "imagecache_memory_pvt.h"
#include "imagecache_pvt.h"
#include "imageio_pvt.h"

Expand Down Expand Up @@ -2004,6 +2006,8 @@ ImageCacheImpl::getstats(int level) const
" Failure reads followed by unexplained success:"
" {} files, {} tiles\n",
stats.file_retry_success, stats.tile_retry_success);

printImageCacheMemory(out, *this);
}

if (level >= 2 && files.size()) {
Expand Down Expand Up @@ -2464,6 +2468,7 @@ ImageCacheImpl::getattribute(string_view name, TypeDesc type, void* val) const

if (Strutil::starts_with(name, "stat:")) {
// Stats we can just grab
ATTR_DECODE("stat:cache_footprint", long long, footprint(*this));
ATTR_DECODE("stat:cache_memory_used", long long, m_mem_used);
ATTR_DECODE("stat:tiles_created", int, m_stat_tiles_created);
ATTR_DECODE("stat:tiles_current", int, m_stat_tiles_current);
Expand Down
Loading

0 comments on commit af13eb9

Please sign in to comment.