Branch data Line data Source code
1 : : // Copyright 2026 HPActor Contributors
2 : : //
3 : : // Licensed under the Apache License, Version 2.0 (the "License");
4 : : // you may not use this file except in compliance with the License.
5 : : // You may obtain a copy of the License at
6 : : //
7 : : // http://www.apache.org/licenses/LICENSE-2.0
8 : : //
9 : : // Unless required by applicable law or agreed to in writing, software
10 : : // distributed under the License is distributed on an "AS IS" BASIS,
11 : : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : : // See the License for the specific language governing permissions and
13 : : // limitations under the License.
14 : :
15 : : #include <hpactor/mem/memory_tracker.hpp>
16 : :
17 : : namespace hpactor::mem {
18 : :
19 : 1 : MemoryTracker& MemoryTracker::instance() {
20 : 1 : static MemoryTracker mt;
21 : 1 : return mt;
22 : : }
23 : :
24 : 1 : MemoryTracker::MemoryTracker()
25 : 1000001 : : stats_(new ActorMemoryStats[kMaxTrackedActors]),
26 : 1 : capacity_(kMaxTrackedActors) {}
27 : :
28 : 4011 : size_t MemoryTracker::index_for(ActorId actor) const noexcept {
29 : 4011 : return static_cast<size_t>(actor.value() % kMaxTrackedActors);
30 : : }
31 : :
32 : 4003 : bool MemoryTracker::record_alloc(ActorId actor, size_t bytes) noexcept {
33 : 4003 : size_t idx = index_for(actor);
34 : 4003 : if (idx >= capacity_) return false;
35 : :
36 : 4003 : auto& s = stats_[idx];
37 : :
38 : 4003 : uint64_t prev = __atomic_fetch_add(&s.current_bytes, bytes, __ATOMIC_RELAXED);
39 : 4003 : uint64_t curr = prev + bytes;
40 : :
41 : : // Update peak lazily via CAS
42 : 4003 : uint64_t peak = __atomic_load_n(&s.peak_bytes, __ATOMIC_RELAXED);
43 : 4003 : while (curr > peak) {
44 : 4003 : if (__atomic_compare_exchange_n(&s.peak_bytes, &peak, curr,
45 : : /*weak=*/false, __ATOMIC_RELAXED, __ATOMIC_RELAXED)) {
46 : 4003 : break;
47 : : }
48 : : }
49 : :
50 : 4003 : __atomic_fetch_add(&s.alloc_count, 1, __ATOMIC_RELAXED);
51 : 4003 : return true;
52 : : }
53 : :
54 : 1 : void MemoryTracker::record_free(ActorId actor, size_t bytes) noexcept {
55 : 1 : size_t idx = index_for(actor);
56 : 1 : if (idx >= capacity_) return;
57 : :
58 : 1 : auto& s = stats_[idx];
59 : 1 : __atomic_fetch_sub(&s.current_bytes, bytes, __ATOMIC_RELAXED);
60 : 1 : __atomic_fetch_add(&s.free_count, 1, __ATOMIC_RELAXED);
61 : : }
62 : :
63 : 7 : void MemoryTracker::snapshot(ActorId actor, ActorMemoryStats& out) const noexcept {
64 : 7 : size_t idx = index_for(actor);
65 : 7 : if (idx >= capacity_) return;
66 : :
67 : 7 : const auto& s = stats_[idx];
68 : 7 : out.current_bytes = __atomic_load_n(&s.current_bytes, __ATOMIC_RELAXED);
69 : 7 : out.peak_bytes = __atomic_load_n(&s.peak_bytes, __ATOMIC_RELAXED);
70 : 7 : out.alloc_count = __atomic_load_n(&s.alloc_count, __ATOMIC_RELAXED);
71 : 7 : out.free_count = __atomic_load_n(&s.free_count, __ATOMIC_RELAXED);
72 : 7 : out.last_alloc_ns = __atomic_load_n(&s.last_alloc_ns, __ATOMIC_RELAXED);
73 : : }
74 : :
75 : 1 : uint64_t MemoryTracker::total_active_bytes() const noexcept {
76 : 1 : uint64_t total = 0;
77 : 1000001 : for (size_t i = 0; i < capacity_; ++i) {
78 : 1000000 : total += __atomic_load_n(&stats_[i].current_bytes, __ATOMIC_RELAXED);
79 : : }
80 : 1 : return total;
81 : : }
82 : :
83 : 0 : uint64_t MemoryTracker::total_peak_bytes() const noexcept {
84 : 0 : uint64_t total = 0;
85 : 0 : for (size_t i = 0; i < capacity_; ++i) {
86 : 0 : total += __atomic_load_n(&stats_[i].peak_bytes, __ATOMIC_RELAXED);
87 : : }
88 : 0 : return total;
89 : : }
90 : :
91 : 1 : uint64_t MemoryTracker::total_alloc_count() const noexcept {
92 : 1 : uint64_t total = 0;
93 : 1000001 : for (size_t i = 0; i < capacity_; ++i) {
94 : 1000000 : total += __atomic_load_n(&stats_[i].alloc_count, __ATOMIC_RELAXED);
95 : : }
96 : 1 : return total;
97 : : }
98 : :
99 : : } // namespace hpactor::mem
|