Add arena debug visualization tool
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <new>
|
||||
@@ -369,6 +370,181 @@ public:
|
||||
return current_block_ ? current_block_->block_count : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Debug function to find all intra-arena pointers.
|
||||
*
|
||||
* Scans all used memory in the arena for 64-bit aligned values that could be
|
||||
* pointers to locations within the arena itself. This is useful for
|
||||
* understanding memory references and potential data structures.
|
||||
*
|
||||
* @return Vector of PointerInfo structs containing source and target
|
||||
* addresses
|
||||
*/
|
||||
struct PointerInfo {
|
||||
const void *source_addr; ///< Address where the pointer was found
|
||||
size_t source_block_number; ///< Block number containing the source
|
||||
size_t source_offset; ///< Offset within the source block
|
||||
const void *target_addr; ///< Address the pointer points to
|
||||
size_t target_block_number; ///< Block number containing the target
|
||||
size_t target_offset; ///< Offset within the target block
|
||||
|
||||
PointerInfo(const void *src, size_t src_block, size_t src_offset,
|
||||
const void *target, size_t target_block, size_t target_offset)
|
||||
: source_addr(src), source_block_number(src_block),
|
||||
source_offset(src_offset), target_addr(target),
|
||||
target_block_number(target_block), target_offset(target_offset) {}
|
||||
};
|
||||
|
||||
std::vector<PointerInfo> find_intra_arena_pointers() const {
|
||||
std::vector<PointerInfo> pointers;
|
||||
|
||||
if (!current_block_) {
|
||||
return pointers;
|
||||
}
|
||||
|
||||
// Build list of blocks from current to first
|
||||
std::vector<Block *> blocks;
|
||||
Block *block = current_block_;
|
||||
while (block) {
|
||||
blocks.push_back(block);
|
||||
block = block->prev;
|
||||
}
|
||||
|
||||
// Helper function to check if a pointer value points within the used area
|
||||
// of any block
|
||||
auto is_intra_arena_pointer = [&blocks,
|
||||
this](uint64_t pointer_value) -> bool {
|
||||
for (size_t block_idx = 0; block_idx < blocks.size(); ++block_idx) {
|
||||
Block *b = blocks[block_idx];
|
||||
uintptr_t block_start = reinterpret_cast<uintptr_t>(b->data());
|
||||
|
||||
// Calculate used bytes in this specific block
|
||||
size_t block_used;
|
||||
if (block_idx == 0) {
|
||||
// Current block - use current_offset_
|
||||
block_used = current_offset_;
|
||||
} else {
|
||||
// Previous blocks are fully used
|
||||
block_used = b->size;
|
||||
}
|
||||
|
||||
uintptr_t block_used_end = block_start + block_used;
|
||||
|
||||
// Check if pointer falls within the used area of this block
|
||||
if (pointer_value >= block_start && pointer_value < block_used_end) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
// Scan each block for pointers
|
||||
for (size_t block_idx = 0; block_idx < blocks.size(); ++block_idx) {
|
||||
Block *b = blocks[block_idx];
|
||||
const char *data = b->data();
|
||||
|
||||
// Calculate used bytes in this specific block
|
||||
size_t block_used;
|
||||
if (block_idx == 0) {
|
||||
// Current block - use current_offset_
|
||||
block_used = current_offset_;
|
||||
} else {
|
||||
// Previous blocks are fully used
|
||||
block_used = b->size;
|
||||
}
|
||||
|
||||
// Scan for 64-bit aligned pointers
|
||||
for (size_t offset = 0; offset + sizeof(uint64_t) <= block_used;
|
||||
offset += sizeof(uint64_t)) {
|
||||
uint64_t potential_pointer;
|
||||
std::memcpy(&potential_pointer, data + offset,
|
||||
sizeof(potential_pointer));
|
||||
|
||||
// Check if this value points within the used area of any block
|
||||
if (is_intra_arena_pointer(potential_pointer)) {
|
||||
// Find target location within arena
|
||||
auto target_location = find_address_location(
|
||||
reinterpret_cast<const void *>(potential_pointer));
|
||||
|
||||
pointers.emplace_back(
|
||||
data + offset, // source address
|
||||
blocks.size() - block_idx, // source block number (1-based)
|
||||
offset, // source offset in block
|
||||
reinterpret_cast<const void *>(
|
||||
potential_pointer), // target address
|
||||
target_location.found ? target_location.block_number
|
||||
: 0, // target block number
|
||||
target_location.found ? target_location.offset_in_block
|
||||
: 0 // target offset
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return pointers;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Find which block and offset a given address belongs to.
|
||||
*
|
||||
* @param addr The address to locate within the arena
|
||||
* @return PointerInfo with block number and offset, or invalid info if not
|
||||
* found
|
||||
*/
|
||||
struct AddressLocation {
|
||||
size_t block_number;
|
||||
size_t offset_in_block;
|
||||
bool found;
|
||||
|
||||
AddressLocation() : block_number(0), offset_in_block(0), found(false) {}
|
||||
AddressLocation(size_t block, size_t offset)
|
||||
: block_number(block), offset_in_block(offset), found(true) {}
|
||||
};
|
||||
|
||||
AddressLocation find_address_location(const void *addr) const {
|
||||
if (!current_block_ || !addr) {
|
||||
return AddressLocation();
|
||||
}
|
||||
|
||||
uintptr_t target_addr = reinterpret_cast<uintptr_t>(addr);
|
||||
|
||||
// Build list of blocks from current to first
|
||||
std::vector<Block *> blocks;
|
||||
Block *block = current_block_;
|
||||
while (block) {
|
||||
blocks.push_back(block);
|
||||
block = block->prev;
|
||||
}
|
||||
|
||||
// Check each block to see if the address falls within its used area
|
||||
for (size_t block_idx = 0; block_idx < blocks.size(); ++block_idx) {
|
||||
Block *b = blocks[block_idx];
|
||||
uintptr_t block_start = reinterpret_cast<uintptr_t>(b->data());
|
||||
|
||||
// Calculate used bytes in this specific block
|
||||
size_t block_used;
|
||||
if (block_idx == 0) {
|
||||
// Current block - use current_offset_
|
||||
block_used = current_offset_;
|
||||
} else {
|
||||
// Previous blocks are fully used
|
||||
block_used = b->size;
|
||||
}
|
||||
|
||||
uintptr_t block_used_end = block_start + block_used;
|
||||
|
||||
// Check if address falls within the used area of this block
|
||||
if (target_addr >= block_start && target_addr < block_used_end) {
|
||||
return AddressLocation(
|
||||
blocks.size() - block_idx, // block number (1-based)
|
||||
target_addr - block_start // offset within block
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return AddressLocation(); // Not found
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Debug function to visualize the arena's layout and contents.
|
||||
*
|
||||
|
||||
@@ -129,9 +129,8 @@ public:
|
||||
* @brief Construct a new CommitRequest with the given initial arena size.
|
||||
* @param arena_size Initial size for the arena allocator
|
||||
*/
|
||||
explicit CommitRequest(size_t arena_size = 4096)
|
||||
: arena_(arena_size),
|
||||
preconditions_(ArenaStlAllocator<Precondition>(&arena_)),
|
||||
explicit CommitRequest()
|
||||
: arena_(), preconditions_(ArenaStlAllocator<Precondition>(&arena_)),
|
||||
operations_(ArenaStlAllocator<Operation>(&arena_)),
|
||||
parser_context_(&arena_) {}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user