Files
whetstone_DSL/editor/src/AllocationOwnershipTraceHooks.h

151 lines
5.2 KiB
C++

#pragma once
// Step 566: Allocation/Ownership Trace Hooks
#include "DebugValidationUtil.h"
#include <algorithm>
#include <cstdint>
#include <map>
#include <string>
#include <vector>
enum class AllocationTraceEventType {
Alloc,
Transfer,
Free
};
struct AllocationTraceEvent {
std::string eventId;
std::string sessionId;
std::string allocationId;
AllocationTraceEventType type = AllocationTraceEventType::Alloc;
std::uint64_t timestamp = 0;
std::uint64_t address = 0;
std::uint64_t sizeBytes = 0;
std::string ownerFrom;
std::string ownerTo;
};
class AllocationOwnershipTraceHooks {
public:
bool recordAllocation(const std::string& sessionId,
const std::string& allocationId,
std::uint64_t address,
std::uint64_t sizeBytes,
const std::string& owner,
std::uint64_t timestamp,
std::string* error) {
if (!error) return false;
error->clear();
if (!hasRequiredDebugIds(allocationId, sessionId)) return fail(error, "allocation_or_session_missing");
if (!isNonZeroU64(address)) return fail(error, "allocation_address_invalid");
if (!isNonZeroU64(sizeBytes)) return fail(error, "allocation_size_invalid");
if (owner.empty()) return fail(error, "allocation_owner_missing");
if (activeOwners_.count(allocationId) != 0) return fail(error, "allocation_id_active_duplicate");
activeOwners_[allocationId] = owner;
AllocationTraceEvent event;
event.eventId = nextEventId();
event.sessionId = sessionId;
event.allocationId = allocationId;
event.type = AllocationTraceEventType::Alloc;
event.timestamp = timestamp;
event.address = address;
event.sizeBytes = sizeBytes;
event.ownerTo = owner;
appendEvent(event);
return true;
}
bool transferOwnership(const std::string& sessionId,
const std::string& allocationId,
const std::string& newOwner,
std::uint64_t timestamp,
std::string* error) {
if (!error) return false;
error->clear();
if (!hasRequiredDebugIds(allocationId, sessionId)) return fail(error, "allocation_or_session_missing");
if (newOwner.empty()) return fail(error, "transfer_owner_missing");
auto it = activeOwners_.find(allocationId);
if (it == activeOwners_.end()) return fail(error, "allocation_not_active");
if (it->second == newOwner) return fail(error, "transfer_owner_unchanged");
AllocationTraceEvent event;
event.eventId = nextEventId();
event.sessionId = sessionId;
event.allocationId = allocationId;
event.type = AllocationTraceEventType::Transfer;
event.timestamp = timestamp;
event.ownerFrom = it->second;
event.ownerTo = newOwner;
it->second = newOwner;
appendEvent(event);
return true;
}
bool recordFree(const std::string& sessionId,
const std::string& allocationId,
std::uint64_t timestamp,
std::string* error) {
if (!error) return false;
error->clear();
if (!hasRequiredDebugIds(allocationId, sessionId)) return fail(error, "allocation_or_session_missing");
auto it = activeOwners_.find(allocationId);
if (it == activeOwners_.end()) return fail(error, "allocation_not_active");
AllocationTraceEvent event;
event.eventId = nextEventId();
event.sessionId = sessionId;
event.allocationId = allocationId;
event.type = AllocationTraceEventType::Free;
event.timestamp = timestamp;
event.ownerFrom = it->second;
activeOwners_.erase(it);
appendEvent(event);
return true;
}
std::string ownerFor(const std::string& allocationId) const {
auto it = activeOwners_.find(allocationId);
if (it == activeOwners_.end()) return "";
return it->second;
}
std::size_t activeAllocationCount() const {
return activeOwners_.size();
}
std::vector<AllocationTraceEvent> timelineForSession(const std::string& sessionId) const {
std::vector<AllocationTraceEvent> filtered;
for (const auto& event : events_) {
if (sessionId.empty() || event.sessionId == sessionId) filtered.push_back(event);
}
return filtered;
}
private:
std::vector<AllocationTraceEvent> events_;
std::map<std::string, std::string> activeOwners_;
std::uint64_t nextId_ = 1;
static bool fail(std::string* error, const char* code) {
*error = code;
return false;
}
std::string nextEventId() {
return "alloc-event-" + std::to_string(nextId_++);
}
void appendEvent(const AllocationTraceEvent& event) {
events_.push_back(event);
std::stable_sort(events_.begin(), events_.end(), [](const AllocationTraceEvent& a, const AllocationTraceEvent& b) {
if (a.timestamp != b.timestamp) return a.timestamp < b.timestamp;
return a.eventId < b.eventId;
});
}
};