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,
173 Dmabuf =
174 7,
175 Default = System,
176 UserDefined = 1024
177 };
178
180 using IDList = ::promeki::List<ID>;
181
199 struct Stats {
201 struct Snapshot {
202 uint64_t allocCount = 0;
203 uint64_t allocBytes = 0;
204 uint64_t allocFailCount =
205 0;
206 uint64_t maxAllocBytes =
207 0;
208 uint64_t releaseCount = 0;
209 uint64_t releaseBytes = 0;
210 uint64_t copyCount = 0;
211 uint64_t copyBytes = 0;
212 uint64_t copyFailCount = 0;
213 uint64_t fillCount = 0;
214 uint64_t fillBytes = 0;
215 uint64_t liveCount = 0;
216 uint64_t liveBytes = 0;
217 uint64_t peakCount = 0;
218 uint64_t peakBytes = 0;
231 uint64_t peakResidentBytes = 0;
232 };
233
234 Atomic<uint64_t> allocCount{0};
235 Atomic<uint64_t> allocBytes{0};
236 Atomic<uint64_t> allocFailCount{0};
237 Atomic<uint64_t> maxAllocBytes{0};
238 Atomic<uint64_t> releaseCount{0};
239 Atomic<uint64_t> releaseBytes{0};
240 Atomic<uint64_t> copyCount{0};
241 Atomic<uint64_t> copyBytes{0};
242 Atomic<uint64_t> copyFailCount{0};
243 Atomic<uint64_t> fillCount{0};
244 Atomic<uint64_t> fillBytes{0};
245 Atomic<uint64_t> liveCount{0};
246 Atomic<uint64_t> liveBytes{0};
247 Atomic<uint64_t> peakCount{0};
248 Atomic<uint64_t> peakBytes{0};
249 Atomic<uint64_t> peakResidentBytes{0};
250
251 Stats() = default;
252 Stats(const Stats &) = delete;
253 Stats &operator=(const Stats &) = delete;
254 Stats(Stats &&) = delete;
255 Stats &operator=(Stats &&) = delete;
256
266 Snapshot snapshot() const;
267
269 void reset();
270
277 void recordAlloc(uint64_t bytes);
278
285 void recordRelease(uint64_t bytes);
286
295 void recordResidentBytes(uint64_t bytes);
296 };
297
309 struct Ops {
310 ID id;
311 String name;
312 bool (*isHostAccessible)(
313 const MemAllocation &
314 alloc);
315 void (*alloc)(
316 MemAllocation &
317 alloc);
318 void (*release)(
319 MemAllocation &
320 alloc);
321 Error (*copy)(
322 const MemAllocation &src, const MemAllocation &dst,
323 size_t bytes);
324 Error (*fill)(
325 void *ptr, size_t bytes,
326 char value);
327 Stats *stats =
328 nullptr;
329 MemDomain::ID domainId =
330 MemDomain::Host;
331 };
332
358 static ID registerType();
359
382 static void registerData(Ops &&ops);
383
391 static IDList registeredIDs();
392
397 inline MemSpace(ID id = Default);
398
403 const String &name() const { return d->name; }
404
406 String toString() const { return d->name; }
407
412 ID id() const { return d->id; }
413
424 MemDomain domain() const { return MemDomain(d->domainId); }
425
431 bool isHostAccessible(const MemAllocation &alloc) const { return d->isHostAccessible(alloc); }
432
447 inline MemAllocation alloc(size_t bytes, size_t align) const;
448
453 inline void release(MemAllocation &alloc) const;
454
468 inline Error copy(const MemAllocation &src, const MemAllocation &dst, size_t bytes) const;
469
477 Error fill(void *ptr, size_t bytes, char value) const {
478 if (ptr == nullptr) return Error::Invalid;
479 Error err = d->fill(ptr, bytes, value);
480 if (err.isOk()) {
481 d->stats->fillCount.fetchAndAdd(1);
482 d->stats->fillBytes.fetchAndAdd(bytes);
483 }
484 return err;
485 }
486
497 Stats &stats() const { return *d->stats; }
498
503 Stats::Snapshot statsSnapshot() const { return d->stats->snapshot(); }
504
506 void resetStats() const { d->stats->reset(); }
507
517 StringList statsReport() const;
518
527 static StringList allStatsReport();
528
536 void logStats() const;
537
544 static void logAllStats();
545
547 const Ops *data() const { return d; }
548
550 bool operator==(const MemSpace &o) const { return d == o.d; }
551
553 bool operator!=(const MemSpace &o) const { return d != o.d; }
554
555 private:
556 const Ops *d = nullptr;
557 static const Ops *lookup(ID id);
558};
559
567struct MemAllocation {
568 void *ptr = nullptr;
569 size_t size = 0;
570 size_t align = 0;
571 MemSpace ms;
572 void *priv = nullptr;
573
575 bool isValid() const { return ptr != nullptr; }
576};
577
578inline MemSpace::MemSpace(ID id) : d(lookup(id)) {}
579
580inline Error MemSpace::copy(const MemAllocation &src, const MemAllocation &dst, size_t bytes) const {
581 if (src.ptr == nullptr || dst.ptr == nullptr) {
582 d->stats->copyFailCount.fetchAndAdd(1);
583 return Error::Invalid;
584 }
585 Error err = d->copy(src, dst, bytes);
586 if (err.isOk()) {
587 d->stats->copyCount.fetchAndAdd(1);
588 d->stats->copyBytes.fetchAndAdd(bytes);
589 } else {
590 d->stats->copyFailCount.fetchAndAdd(1);
591 }
592 return err;
593}
594
595inline MemAllocation MemSpace::alloc(size_t bytes, size_t align) const {
596 MemAllocation a;
597 a.size = bytes;
598 a.align = align;
599 a.ms = *this;
600 // A zero-byte allocation is valid (returns a.ptr == nullptr) but
601 // does not count as a failure. Skip stats so counters aren't
602 // polluted by the legitimate empty-buffer case.
603 if (bytes == 0) return a;
604 d->alloc(a);
605 if (a.ptr != nullptr) {
606 d->stats->recordAlloc(static_cast<uint64_t>(bytes));
607 } else {
608 d->stats->allocFailCount.fetchAndAdd(1);
609 }
610 return a;
611}
612
613inline void MemSpace::release(MemAllocation &alloc) const {
614 if (alloc.ptr == nullptr) return;
615 uint64_t bytes = static_cast<uint64_t>(alloc.size);
616 d->release(alloc);
617 d->stats->recordRelease(bytes);
618 alloc.ptr = nullptr;
619 alloc.priv = nullptr;
620}
621
622PROMEKI_NAMESPACE_END
623
624#endif // PROMEKI_ENABLE_CORE