Skip to content

Commit 32b5a84

Browse files
committed
add pvt::heapsize and pvt::footprint() to track oiio components memory (image cache)
Signed-off-by: Basile Fraboni <basile.fraboni@gmail.com>
1 parent 8a09888 commit 32b5a84

File tree

13 files changed

+572
-1
lines changed

13 files changed

+572
-1
lines changed

src/include/OpenImageIO/imagecache.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,8 @@ class OIIO_API ImageCache {
257257
/// all files referenced by calls to the ImageCache. (The
258258
/// array is of `ustring` or `char*`.)
259259
///
260+
/// - `int64 stat:cache_footprint` :
261+
/// Total bytes used by image cache.
260262
/// - `int64 stat:cache_memory_used` :
261263
/// Total bytes used by tile cache.
262264
///

src/include/OpenImageIO/imageio.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#include <OpenImageIO/strutil.h>
3737
#include <OpenImageIO/thread.h>
3838
#include <OpenImageIO/typedesc.h>
39+
#include <OpenImageIO/memory.h>
3940

4041
OIIO_NAMESPACE_BEGIN
4142

@@ -1883,6 +1884,9 @@ class OIIO_API ImageInput {
18831884
std::unique_ptr<Impl, decltype(&impl_deleter)> m_impl;
18841885

18851886
void append_error(string_view message) const; // add to error message
1887+
1888+
/// declare a friend heapsize definition
1889+
template <typename T> friend size_t pvt::heapsize(const T&);
18861890
};
18871891

18881892

@@ -2787,10 +2791,26 @@ class OIIO_API ImageOutput {
27872791
std::unique_ptr<Impl, decltype(&impl_deleter)> m_impl;
27882792

27892793
void append_error(string_view message) const; // add to m_errmessage
2794+
2795+
/// declare a friend heapsize definition
2796+
template <typename T> friend size_t pvt::heapsize(const T&);
27902797
};
27912798

27922799

27932800

2801+
/// Memory tracking. Specializes the base memory tracking functions from memory.h.
2802+
2803+
// heapsize specialization for `ImageSpec`
2804+
template <> OIIO_API size_t pvt::heapsize<ImageSpec>(const ImageSpec&);
2805+
2806+
// heapsize specialization for `ImageInput`
2807+
template <> OIIO_API size_t pvt::heapsize<ImageInput>(const ImageInput&);
2808+
2809+
// heapsize specialization for `ImageOutput`
2810+
template <> OIIO_API size_t pvt::heapsize<ImageOutput>(const ImageOutput&);
2811+
2812+
2813+
27942814
// Utility functions
27952815

27962816
/// `OIIO::shutdown` prepares OpenImageIO for shutdown. Before exiting an

src/include/OpenImageIO/memory.h

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
// Copyright Contributors to the OpenImageIO project.
2+
// SPDX-License-Identifier: Apache-2.0
3+
// https://github.com/AcademySoftwareFoundation/OpenImageIO
4+
5+
6+
/////////////////////////////////////////////////////////////////////////
7+
/// @file memory.h
8+
///
9+
/// @brief Utilities for memory tracking.
10+
/////////////////////////////////////////////////////////////////////////
11+
12+
13+
#pragma once
14+
15+
#define OPENIMAGEIO_MEMORY_H
16+
17+
#include <cstring>
18+
#include <memory>
19+
#include <vector>
20+
21+
OIIO_NAMESPACE_BEGIN
22+
23+
namespace pvt {
24+
25+
/// Return the total heap memory allocated by `object`.
26+
/// The template specialization can be used to give improved results for non trivial types
27+
/// that perform heap allocation, and to include members allocations recursively.
28+
template<typename T>
29+
inline size_t
30+
heapsize(const T& t)
31+
{
32+
return 0;
33+
}
34+
35+
/// Return the total memory footprint of `object`. If possible, including any heap
36+
/// allocations done by any constituent parts. The default implementation just reduces
37+
/// to sizeof(object), given that heapsize(object) would return 0.
38+
/// The template specialization can be used to give improved results for non trivial types
39+
/// that perform heap allocation.
40+
template<typename T>
41+
inline size_t
42+
footprint(const T& t)
43+
{
44+
if constexpr (std::is_pointer<T>::value)
45+
return sizeof(T) + (t ? footprint(*t) : 0);
46+
else
47+
return sizeof(T) + heapsize(t);
48+
}
49+
50+
51+
/// Specializations for common STL types
52+
53+
54+
// heapsize specialization for std::string
55+
template<>
56+
inline size_t
57+
heapsize<std::string>(const std::string& s)
58+
{
59+
// accounts for small string optimization that does not
60+
// use any heap allocations
61+
const char* const sbegin = (const char*)&s;
62+
const char* const send = sbegin + sizeof(std::string);
63+
const char* const sdata = s.data();
64+
const bool is_small = sdata >= sbegin && sdata < send;
65+
return is_small ? 0 : s.capacity();
66+
}
67+
68+
// heapsize specialization for std::vector
69+
template<typename T>
70+
inline size_t
71+
heapsize(const std::vector<T>& vec)
72+
{
73+
size_t size = 0;
74+
for (const T& elem : vec)
75+
size += footprint(elem);
76+
return size;
77+
}
78+
79+
// heapsize specialization for std::shared_ptr
80+
template<typename T>
81+
inline size_t
82+
heapsize(const std::shared_ptr<T>& ref)
83+
{
84+
return ref ? footprint(*ref.get()) : 0;
85+
}
86+
87+
// footprint specialization for std::shared_ptr
88+
template<typename T>
89+
inline size_t
90+
footprint(const std::shared_ptr<T>& ref)
91+
{
92+
return sizeof(std::shared_ptr<T>) + heapsize(ref);
93+
}
94+
95+
// heapsize specialization for std::unique_ptr
96+
template<typename T>
97+
inline size_t
98+
heapsize(const std::unique_ptr<T>& ref)
99+
{
100+
return ref ? footprint(*ref.get()) : 0;
101+
}
102+
103+
// footprint specialization for std::unique_ptr
104+
template<typename T>
105+
inline size_t
106+
footprint(const std::unique_ptr<T>& ref)
107+
{
108+
return sizeof(std::unique_ptr<T>) + heapsize(ref);
109+
}
110+
111+
} // namespace pvt
112+
113+
114+
OIIO_NAMESPACE_END

src/include/OpenImageIO/paramlist.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
#include <OpenImageIO/attrdelegate.h>
1818
#include <OpenImageIO/export.h>
19+
#include <OpenImageIO/memory.h>
1920
#include <OpenImageIO/strongparam.h>
2021
#include <OpenImageIO/typedesc.h>
2122
#include <OpenImageIO/ustring.h>
@@ -276,9 +277,15 @@ class OIIO_UTIL_API ParamValue {
276277
Copy _copy = Copy(true),
277278
FromUstring _from_ustring = FromUstring(false)) noexcept;
278279
void clear_value() noexcept;
279-
};
280280

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

285+
/// heapsize specialization for `ParamValue`
286+
template<>
287+
OIIO_API size_t
288+
pvt::heapsize<ParamValue>(const ParamValue&);
282289

283290
/// Factory for a ParamValue that holds a single value of any type supported
284291
/// by a corresponding ParamValue constructor (such as int, float, string).

src/include/OpenImageIO/refcnt.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
#include <OpenImageIO/atomic.h>
1818
#include <OpenImageIO/dassert.h>
19+
#include <OpenImageIO/memory.h>
1920

2021

2122
OIIO_NAMESPACE_BEGIN
@@ -232,4 +233,23 @@ intrusive_ptr_release(T* x)
232233
#define OIIO_REFCNT_HAS_RELEASE 1 /* intrusive_ptr::release() */
233234

234235

236+
/// Memory tracking. Specializes the base memory tracking functions from memory.h.
237+
238+
// heapsize specialization for `intrusive_ptr`
239+
template<typename T>
240+
inline size_t
241+
pvt::heapsize(intrusive_ptr<T> ref)
242+
{
243+
return ref ? pvt::footprint(*ref.get()) : 0;
244+
}
245+
246+
// footprint specialization for `intrusive_ptr`
247+
template<typename T>
248+
inline size_t
249+
pvt::footprint(intrusive_ptr<T> ref)
250+
{
251+
return sizeof(intrusive_ptr<T>) + pvt::heapsize(ref);
252+
}
253+
254+
235255
OIIO_NAMESPACE_END

src/libOpenImageIO/formatspec.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1251,4 +1251,17 @@ ImageSpec::set_colorspace(string_view colorspace)
12511251
}
12521252

12531253

1254+
1255+
template<>
1256+
size_t
1257+
pvt::heapsize<ImageSpec>(const ImageSpec& is)
1258+
{
1259+
size_t size = pvt::heapsize(is.channelformats);
1260+
size += pvt::heapsize(is.channelnames);
1261+
size += pvt::heapsize(is.extra_attribs);
1262+
return size;
1263+
}
1264+
1265+
1266+
12541267
OIIO_NAMESPACE_END

src/libOpenImageIO/imageinput.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1337,4 +1337,17 @@ ImageInput::check_open(const ImageSpec& spec, ROI range, uint64_t /*flags*/)
13371337
return true; // all is ok
13381338
}
13391339

1340+
1341+
1342+
template<>
1343+
size_t
1344+
pvt::heapsize<ImageInput>(const ImageInput& input)
1345+
{
1346+
//! TODO: change ImageInput API to add a virtual heapsize() function
1347+
//! to allow per image input override, and call that function here.
1348+
return pvt::heapsize(input.m_spec);
1349+
}
1350+
1351+
1352+
13401353
OIIO_NAMESPACE_END

src/libOpenImageIO/imageoutput.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1021,4 +1021,15 @@ ImageOutput::check_open(OpenMode mode, const ImageSpec& userspec, ROI range,
10211021

10221022

10231023

1024+
template<>
1025+
size_t
1026+
pvt::heapsize<ImageOutput>(const ImageOutput& output)
1027+
{
1028+
//! TODO: change ImageOutput API to add a virtual heapsize() function
1029+
//! to allow per image output override, and call that function here.
1030+
return pvt::heapsize(output.m_spec);
1031+
}
1032+
1033+
1034+
10241035
OIIO_NAMESPACE_END

src/libtexture/imagecache.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030
#include <OpenImageIO/typedesc.h>
3131
#include <OpenImageIO/ustring.h>
3232

33+
#include "imagecache_memory_print.h"
34+
#include "imagecache_memory_pvt.h"
3335
#include "imagecache_pvt.h"
3436
#include "imageio_pvt.h"
3537

@@ -2004,6 +2006,8 @@ ImageCacheImpl::getstats(int level) const
20042006
" Failure reads followed by unexplained success:"
20052007
" {} files, {} tiles\n",
20062008
stats.file_retry_success, stats.tile_retry_success);
2009+
2010+
printImageCacheMemory(out, *this);
20072011
}
20082012

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

24652469
if (Strutil::starts_with(name, "stat:")) {
24662470
// Stats we can just grab
2471+
ATTR_DECODE("stat:cache_footprint", long long, footprint(*this));
24672472
ATTR_DECODE("stat:cache_memory_used", long long, m_mem_used);
24682473
ATTR_DECODE("stat:tiles_created", int, m_stat_tiles_created);
24692474
ATTR_DECODE("stat:tiles_current", int, m_stat_tiles_current);

0 commit comments

Comments
 (0)