Skip to content

Commit

Permalink
capture maximum heap usage per memory tag
Browse files Browse the repository at this point in the history
  • Loading branch information
matth-x committed Aug 9, 2024
1 parent 04c3820 commit 4f36623
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 28 deletions.
11 changes: 9 additions & 2 deletions src/MicroOcpp/Core/ConfigurationContainerFlash.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ class ConfigurationContainerFlash : public ConfigurationContainer, public AllocO
return save();
}

auto doc = FilesystemUtils::loadJson(filesystem, getFilename());
auto doc = FilesystemUtils::loadJson(filesystem, getFilename(), getMemoryTag());
if (!doc) {
MO_DBG_ERR("failed to load %s", getFilename());
return false;
Expand Down Expand Up @@ -130,7 +130,14 @@ class ConfigurationContainerFlash : public ConfigurationContainer, public AllocO
config = nullptr;
}
if (!config) {
key_pooled = static_cast<char*>(MO_MALLOC(key, strlen(key) + 1));
#if MO_ENABLE_HEAP_PROFILER
char memoryTag [64];
snprintf(memoryTag, sizeof(memoryTag), "%s%s", "v16.Configuration.", key);
#else
const char *memoryTag = nullptr;
(void)memoryTag;
#endif
key_pooled = static_cast<char*>(MO_MALLOC(memoryTag, strlen(key) + 1));
if (!key_pooled) {
MO_DBG_ERR("OOM: %s", key);
return false;
Expand Down
4 changes: 2 additions & 2 deletions src/MicroOcpp/Core/FilesystemUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

using namespace MicroOcpp;

std::unique_ptr<MemJsonDoc> FilesystemUtils::loadJson(std::shared_ptr<FilesystemAdapter> filesystem, const char *fn) {
std::unique_ptr<MemJsonDoc> FilesystemUtils::loadJson(std::shared_ptr<FilesystemAdapter> filesystem, const char *fn, const char *memoryTag) {
if (!filesystem || !fn || *fn == '\0') {
MO_DBG_ERR("Format error");
return nullptr;
Expand Down Expand Up @@ -56,7 +56,7 @@ std::unique_ptr<MemJsonDoc> FilesystemUtils::loadJson(std::shared_ptr<Filesystem

while (err == DeserializationError::NoMemory && capacity <= MO_MAX_JSON_CAPACITY) {

doc = makeMemJsonDoc(capacity, fn);
doc = makeMemJsonDoc(capacity, memoryTag);
err = deserializeJson(*doc, fileReader);

capacity *= 2;
Expand Down
2 changes: 1 addition & 1 deletion src/MicroOcpp/Core/FilesystemUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ class ArduinoJsonFileAdapter {

namespace FilesystemUtils {

std::unique_ptr<MemJsonDoc> loadJson(std::shared_ptr<FilesystemAdapter> filesystem, const char *fn);
std::unique_ptr<MemJsonDoc> loadJson(std::shared_ptr<FilesystemAdapter> filesystem, const char *fn, const char *memoryTag = nullptr);
bool storeJson(std::shared_ptr<FilesystemAdapter> filesystem, const char *fn, const MemJsonDoc& doc);

bool remove_if(std::shared_ptr<FilesystemAdapter> filesystem, std::function<bool(const char*)> pred);
Expand Down
93 changes: 78 additions & 15 deletions src/MicroOcpp/Core/Memory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,47 +18,104 @@ struct MemBlockInfo {
updateTag(ptr, tag);
}

void updateTag(void* ptr, const char *tag) {
if (!tag) {
return;
}
if (tagger_ptr == nullptr || ptr < tagger_ptr) {
MO_DBG_DEBUG("update tag from %s to %s, ptr from %p to %p", this->tag.c_str(), tag, tagger_ptr, ptr);
tagger_ptr = ptr;
this->tag = tag;
void updateTag(void* ptr, const char *tag);
};

std::map<void*,MemBlockInfo> memBlocks; //key: memory address of malloc'd block

struct MemTagInfo {
size_t current_size = 0;
size_t max_size = 0;

MemTagInfo(size_t size) {
operator+=(size);
}

void operator+=(size_t size) {
current_size += size;
max_size = std::max(max_size, current_size);
}

void operator-=(size_t size) {
if (size > current_size) {
MO_DBG_ERR("captured size does not fit");
//return; let it happen for now
}
current_size -= size;
}
};

std::map<void*,MemBlockInfo> memBlocks; //key: memory address of malloc'd block
std::map<std::string,MemTagInfo> memTags;

size_t memTotal, memTotalMax;

void MemBlockInfo::updateTag(void* ptr, const char *tag) {
if (!tag) {
return;
}
if (tagger_ptr == nullptr || ptr < tagger_ptr) {
MO_DBG_VERBOSE("update tag from %s to %s, ptr from %p to %p", this->tag.c_str(), tag, tagger_ptr, ptr);

auto tagInfo = memTags.find(this->tag);
if (tagInfo != memTags.end()) {
tagInfo->second -= size;
}

tagInfo = memTags.find(tag);
if (tagInfo != memTags.end()) {
tagInfo->second += size;
} else {
memTags.emplace(tag, size);
}

tagger_ptr = ptr;
this->tag = tag;
}
}

#endif //MO_ENABLE_HEAP_PROFILER

void mo_mem_deinit() {
#if MO_ENABLE_HEAP_PROFILER
memBlocks.clear();
memTags.clear();
#endif
}

void *mo_mem_malloc(const char *tag, size_t size) {
MO_DBG_DEBUG("malloc %zu B (%s)", size, tag ? tag : "unspecified");
MO_DBG_VERBOSE("malloc %zu B (%s)", size, tag ? tag : "unspecified");

auto ptr = malloc(size);

#if MO_ENABLE_HEAP_PROFILER
if (ptr) {
memBlocks.emplace(ptr, MemBlockInfo(ptr, tag, size));

memTotal += size;
memTotalMax = std::max(memTotalMax, memTotal);
}
#endif
return ptr;
}

void mo_mem_free(void* ptr) {
MO_DBG_DEBUG("free");
MO_DBG_VERBOSE("free");

#if MO_ENABLE_HEAP_PROFILER
if (ptr) {
memBlocks.erase(ptr);

auto blockInfo = memBlocks.find(ptr);
if (blockInfo != memBlocks.end()) {
auto tagInfo = memTags.find(blockInfo->second.tag);
if (tagInfo != memTags.end()) {
tagInfo->second -= blockInfo->second.size;
}
memTotal -= blockInfo->second.size;
}

if (blockInfo != memBlocks.end()) {
memBlocks.erase(blockInfo);
}
}
#endif
free(ptr);
Expand All @@ -67,7 +124,7 @@ void mo_mem_free(void* ptr) {
#if MO_ENABLE_HEAP_PROFILER

void mo_mem_set_tag(void *ptr, const char *tag) {
MO_DBG_DEBUG("set tag (%s)", tag ? tag : "unspecified");
MO_DBG_VERBOSE("set tag (%s)", tag ? tag : "unspecified");

if (!tag) {
return;
Expand All @@ -88,7 +145,7 @@ void mo_mem_set_tag(void *ptr, const char *tag) {
}

if (!hasTagged) {
MO_DBG_DEBUG("memory area doesn't apply");
MO_DBG_VERBOSE("memory area doesn't apply");
}
}

Expand Down Expand Up @@ -127,7 +184,13 @@ void mo_mem_print_stats() {
printf("%s - %zu B\n", tag.first.c_str(), tag.second);
}

printf("Blocks: %zu\nTotal usage: %zu B\nTags: %zu\nTotal tagged: %zu B\nUntagged: %zu\nTotal untagged: %zu B\n", memBlocks.size(), size, tags.size(), size_control, untagged, untagged_size);
size_t size_control2 = 0;
for (const auto& tag : memTags) {
size_control2 += tag.second.current_size;
printf("%s - %zu B (max. %zu B)\n", tag.first.c_str(), tag.second.current_size, tag.second.max_size);
}

printf("Blocks: %zu\nTotal usage: %zu B\nTags: %zu\nTotal tagged: %zu B\nTags2: %zu\nTotal tagged2: %zu B\nUntagged: %zu\nTotal untagged: %zu B\nCurrent usage: %zu B\nMaximum usage: %zu B\n", memBlocks.size(), size, tags.size(), size_control, memTags.size(), size_control2, untagged, untagged_size, memTotal, memTotalMax);
}

#endif //MO_ENABLE_HEAP_PROFILER
Expand Down
16 changes: 8 additions & 8 deletions src/MicroOcpp/Core/Memory.h
Original file line number Diff line number Diff line change
Expand Up @@ -140,11 +140,11 @@ class AllocOverrider {
}
public:
void *operator new(size_t size) {
MO_DBG_DEBUG("AllocOverrider new %zu B", size);
MO_DBG_VERBOSE("AllocOverrider new %zu B", size);
return MO_MALLOC(nullptr, size);
}
void operator delete(void * ptr) {
MO_DBG_DEBUG("AllocOverrider delete");
MO_DBG_VERBOSE("AllocOverrider delete");
MO_FREE(ptr);
}

Expand Down Expand Up @@ -206,7 +206,7 @@ struct Allocator {
}

T *allocate(size_t count) {
MO_DBG_DEBUG("Allocator allocate %zu B (%s)", sizeof(T) * count, tag ? tag : "unspecified");
MO_DBG_VERBOSE("Allocator allocate %zu B (%s)", sizeof(T) * count, tag ? tag : "unspecified");
return static_cast<T*>(
MO_MALLOC(
#if MO_ENABLE_HEAP_PROFILER
Expand All @@ -217,7 +217,7 @@ struct Allocator {
sizeof(T) * count));
}
void deallocate(T *ptr, size_t count) {
MO_DBG_DEBUG("Allocator deallocate %zu B (%s)", sizeof(T) * count, tag ? tag : "unspecified");
MO_DBG_VERBOSE("Allocator deallocate %zu B (%s)", sizeof(T) * count, tag ? tag : "unspecified");
MO_FREE(ptr);
}

Expand Down Expand Up @@ -342,7 +342,7 @@ class ArduinoJsonAllocator {
}

void *allocate(size_t size) {
MO_DBG_DEBUG("ArduinoJsonAllocator allocate %zu B (%s)", size, tag ? tag : "unspecified");
MO_DBG_VERBOSE("ArduinoJsonAllocator allocate %zu B (%s)", size, tag ? tag : "unspecified");
return MO_MALLOC(
#if MO_ENABLE_HEAP_PROFILER
tag,
Expand All @@ -352,7 +352,7 @@ class ArduinoJsonAllocator {
size);
}
void deallocate(void *ptr) {
MO_DBG_DEBUG("ArduinoJsonAllocator deallocate");
MO_DBG_VERBOSE("ArduinoJsonAllocator deallocate");
MO_FREE(ptr);
}
};
Expand All @@ -361,7 +361,7 @@ using MemJsonDoc = BasicJsonDocument<ArduinoJsonAllocator>;

template<class T, typename ...Args>
T *mo_mem_new(const char *tag, Args&& ...args) {
MO_DBG_DEBUG("mo_mem_new %zu B (%s)", sizeof(T), tag ? tag : "unspecified");
MO_DBG_VERBOSE("mo_mem_new %zu B (%s)", sizeof(T), tag ? tag : "unspecified");
if (auto ptr = MO_MALLOC(tag, sizeof(T))) {
return new(ptr) T(std::forward<Args>(args)...);
}
Expand All @@ -370,7 +370,7 @@ T *mo_mem_new(const char *tag, Args&& ...args) {

template<class T>
void mo_mem_delete(T *ptr) {
MO_DBG_DEBUG("mo_mem_delete");
MO_DBG_VERBOSE("mo_mem_delete");
if (ptr) {
ptr->~T();
MO_FREE(ptr);
Expand Down

0 comments on commit 4f36623

Please sign in to comment.