Skip to content

Commit 022e5e2

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 64f829f commit 022e5e2

File tree

15 files changed

+607
-24
lines changed

15 files changed

+607
-24
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

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

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

18891893

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

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

27932800

27942801

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

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

src/include/OpenImageIO/memory.h

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
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+
return sizeof(T) + heapsize(t);
45+
}
46+
47+
template<typename T>
48+
inline size_t
49+
footprint(const T* t)
50+
{
51+
return sizeof(T) + (t ? footprint(*t) : 0);
52+
}
53+
54+
/// Specializations for common STL types
55+
56+
57+
// heapsize specialization for std::string
58+
template<>
59+
inline size_t
60+
heapsize<std::string>(const std::string& s)
61+
{
62+
// accounts for small string optimization that does not
63+
// use any heap allocations
64+
const char* const sbegin = (const char*)&s;
65+
const char* const send = sbegin + sizeof(std::string);
66+
const char* const sdata = s.data();
67+
const bool is_small = sdata >= sbegin && sdata < send;
68+
return is_small ? 0 : s.capacity();
69+
}
70+
71+
// heapsize specialization for std::vector
72+
template<typename T>
73+
inline size_t
74+
heapsize(const std::vector<T>& vec)
75+
{
76+
size_t size = 0;
77+
for (const T& elem : vec)
78+
size += footprint(elem);
79+
return size;
80+
}
81+
82+
// heapsize specialization for std::shared_ptr
83+
template<typename T>
84+
inline size_t
85+
heapsize(const std::shared_ptr<T>& ref)
86+
{
87+
return ref ? footprint(*ref.get()) : 0;
88+
}
89+
90+
// footprint specialization for std::shared_ptr
91+
template<typename T>
92+
inline size_t
93+
footprint(const std::shared_ptr<T>& ref)
94+
{
95+
return sizeof(std::shared_ptr<T>) + heapsize(ref);
96+
}
97+
98+
// heapsize specialization for std::unique_ptr
99+
template<typename T>
100+
inline size_t
101+
heapsize(const std::unique_ptr<T>& ref)
102+
{
103+
return ref ? footprint(*ref.get()) : 0;
104+
}
105+
106+
// footprint specialization for std::unique_ptr
107+
template<typename T>
108+
inline size_t
109+
footprint(const std::unique_ptr<T>& ref)
110+
{
111+
return sizeof(std::unique_ptr<T>) + heapsize(ref);
112+
}
113+
114+
} // namespace pvt
115+
116+
117+
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: 22 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,25 @@ 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+
namespace pvt {
240+
template<typename T>
241+
inline size_t
242+
heapsize(const intrusive_ptr<T>& ref)
243+
{
244+
return ref ? footprint(*ref.get()) : 0;
245+
}
246+
247+
// footprint specialization for `intrusive_ptr`
248+
template<typename T>
249+
inline size_t
250+
footprint(const intrusive_ptr<T>& ref)
251+
{
252+
return sizeof(intrusive_ptr<T>) + heapsize(ref);
253+
}
254+
} // namespace pvt
255+
256+
235257
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/libOpenImageIO/imagespec_test.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,8 @@ test_imagespec_from_xml()
313313
std::cout << "test_imagespec_from_xml\n";
314314
ImageSpec spec;
315315
spec.from_xml(imagespec_xml_string);
316+
print(" spec heapsize = {}\n", pvt::heapsize(spec));
317+
print(" spec footprint = {}\n", pvt::footprint(spec));
316318

317319
OIIO_CHECK_EQUAL(spec.nchannels, 4);
318320
OIIO_CHECK_EQUAL(spec.width, 1920);
@@ -331,6 +333,8 @@ test_imagespec_from_xml()
331333
int
332334
main(int /*argc*/, char* /*argv*/[])
333335
{
336+
print("sizeof(ImageSpec) = {}\n", sizeof(ImageSpec));
337+
334338
test_imagespec_pixels();
335339
test_imagespec_metadata_val();
336340
test_imagespec_attribute_from_string();

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)