libpromeki 1.0.0-alpha
PROfessional MEdia toolKIt
 
Loading...
Searching...
No Matches
memspace.h
Go to the documentation of this file.
1
8#pragma once
9
10
11#include <promeki/config.h>
12#if PROMEKI_ENABLE_CORE
13#include <promeki/namespace.h>
14#include <promeki/atomic.h>
15#include <promeki/string.h>
16#include <promeki/stringlist.h>
17#include <promeki/list.h>
18#include <promeki/error.h>
19#include <promeki/memdomain.h>
20#include <promeki/datatype.h>
21
22PROMEKI_NAMESPACE_BEGIN
23
24class DataStream;
25
26struct MemAllocation;
27
55class MemSpace {
56 public:
57 PROMEKI_DATATYPE(MemSpace, DataTypeMemSpace, 1)
58
59
60 Error writeToStream(DataStream &s) const;
62 template <uint32_t V> static Result<MemSpace> readFromStream(DataStream &s);
63
83 enum ID {
84 System = 0,
85 SystemSecure = 1,
86 CudaDevice =
87 2,
88 CudaHost =
89 3,
106 SystemCow =
107 4,
130 PinnedHost =
131 5,
152 NumaHost =
153 6,
154 Default = System,
155 UserDefined = 1024
156 };
157
159 using IDList = ::promeki::List<ID>;
160
178 struct Stats {
180 struct Snapshot {
181 uint64_t allocCount = 0;
182 uint64_t allocBytes = 0;
183 uint64_t allocFailCount =
184 0;
185 uint64_t maxAllocBytes =
186 0;
187 uint64_t releaseCount = 0;
188 uint64_t releaseBytes = 0;
189 uint64_t copyCount = 0;
190 uint64_t copyBytes = 0;
191 uint64_t copyFailCount = 0;
192 uint64_t fillCount = 0;
193 uint64_t fillBytes = 0;
194 uint64_t liveCount = 0;
195 uint64_t liveBytes = 0;
196 uint64_t peakCount = 0;
197 uint64_t peakBytes = 0;
210 uint64_t peakResidentBytes = 0;
211 };
212
213 Atomic<uint64_t> allocCount{0};
214 Atomic<uint64_t> allocBytes{0};
215 Atomic<uint64_t> allocFailCount{0};
216 Atomic<uint64_t> maxAllocBytes{0};
217 Atomic<uint64_t> releaseCount{0};
218 Atomic<uint64_t> releaseBytes{0};
219 Atomic<uint64_t> copyCount{0};
220 Atomic<uint64_t> copyBytes{0};
221 Atomic<uint64_t> copyFailCount{0};
222 Atomic<uint64_t> fillCount{0};
223 Atomic<uint64_t> fillBytes{0};
224 Atomic<uint64_t> liveCount{0};
225 Atomic<uint64_t> liveBytes{0};
226 Atomic<uint64_t> peakCount{0};
227 Atomic<uint64_t> peakBytes{0};
228 Atomic<uint64_t> peakResidentBytes{0};
229
230 Stats() = default;
231 Stats(const Stats &) = delete;
232 Stats &operator=(const Stats &) = delete;
233 Stats(Stats &&) = delete;
234 Stats &operator=(Stats &&) = delete;
235
245 Snapshot snapshot() const;
246
248 void reset();
249
256 void recordAlloc(uint64_t bytes);
257
264 void recordRelease(uint64_t bytes);
265
274 void recordResidentBytes(uint64_t bytes);
275 };
276
288 struct Ops {
289 ID id;
290 String name;
291 bool (*isHostAccessible)(
292 const MemAllocation &
293 alloc);
294 void (*alloc)(
295 MemAllocation &
296 alloc);
297 void (*release)(
298 MemAllocation &
299 alloc);
300 Error (*copy)(
301 const MemAllocation &src, const MemAllocation &dst,
302 size_t bytes);
303 Error (*fill)(
304 void *ptr, size_t bytes,
305 char value);
306 Stats *stats =
307 nullptr;
308 MemDomain::ID domainId =
309 MemDomain::Host;
310 };
311
337 static ID registerType();
338
361 static void registerData(Ops &&ops);
362
370 static IDList registeredIDs();
371
376 inline MemSpace(ID id = Default);
377
382 const String &name() const { return d->name; }
383
385 String toString() const { return d->name; }
386
391 ID id() const { return d->id; }
392
403 MemDomain domain() const { return MemDomain(d->domainId); }
404
410 bool isHostAccessible(const MemAllocation &alloc) const { return d->isHostAccessible(alloc); }
411
426 inline MemAllocation alloc(size_t bytes, size_t align) const;
427
432 inline void release(MemAllocation &alloc) const;
433
447 inline Error copy(const MemAllocation &src, const MemAllocation &dst, size_t bytes) const;
448
456 Error fill(void *ptr, size_t bytes, char value) const {
457 if (ptr == nullptr) return Error::Invalid;
458 Error err = d->fill(ptr, bytes, value);
459 if (err.isOk()) {
460 d->stats->fillCount.fetchAndAdd(1);
461 d->stats->fillBytes.fetchAndAdd(bytes);
462 }
463 return err;
464 }
465
476 Stats &stats() const { return *d->stats; }
477
482 Stats::Snapshot statsSnapshot() const { return d->stats->snapshot(); }
483
485 void resetStats() const { d->stats->reset(); }
486
496 StringList statsReport() const;
497
506 static StringList allStatsReport();
507
515 void logStats() const;
516
523 static void logAllStats();
524
526 const Ops *data() const { return d; }
527
529 bool operator==(const MemSpace &o) const { return d == o.d; }
530
532 bool operator!=(const MemSpace &o) const { return d != o.d; }
533
534 private:
535 const Ops *d = nullptr;
536 static const Ops *lookup(ID id);
537};
538
546struct MemAllocation {
547 void *ptr = nullptr;
548 size_t size = 0;
549 size_t align = 0;
550 MemSpace ms;
551 void *priv = nullptr;
552
554 bool isValid() const { return ptr != nullptr; }
555};
556
557inline MemSpace::MemSpace(ID id) : d(lookup(id)) {}
558
559inline Error MemSpace::copy(const MemAllocation &src, const MemAllocation &dst, size_t bytes) const {
560 if (src.ptr == nullptr || dst.ptr == nullptr) {
561 d->stats->copyFailCount.fetchAndAdd(1);
562 return Error::Invalid;
563 }
564 Error err = d->copy(src, dst, bytes);
565 if (err.isOk()) {
566 d->stats->copyCount.fetchAndAdd(1);
567 d->stats->copyBytes.fetchAndAdd(bytes);
568 } else {
569 d->stats->copyFailCount.fetchAndAdd(1);
570 }
571 return err;
572}
573
574inline MemAllocation MemSpace::alloc(size_t bytes, size_t align) const {
575 MemAllocation a;
576 a.size = bytes;
577 a.align = align;
578 a.ms = *this;
579 // A zero-byte allocation is valid (returns a.ptr == nullptr) but
580 // does not count as a failure. Skip stats so counters aren't
581 // polluted by the legitimate empty-buffer case.
582 if (bytes == 0) return a;
583 d->alloc(a);
584 if (a.ptr != nullptr) {
585 d->stats->recordAlloc(static_cast<uint64_t>(bytes));
586 } else {
587 d->stats->allocFailCount.fetchAndAdd(1);
588 }
589 return a;
590}
591
592inline void MemSpace::release(MemAllocation &alloc) const {
593 if (alloc.ptr == nullptr) return;
594 uint64_t bytes = static_cast<uint64_t>(alloc.size);
595 d->release(alloc);
596 d->stats->recordRelease(bytes);
597 alloc.ptr = nullptr;
598 alloc.priv = nullptr;
599}
600
601PROMEKI_NAMESPACE_END
602
603#endif // PROMEKI_ENABLE_CORE