This commit is contained in:
Ilusha 2023-05-26 01:35:29 +03:00
commit d4c558a59a
34 changed files with 3850 additions and 0 deletions

401
tools/MemUsage/memusage.h Normal file
View file

@ -0,0 +1,401 @@
#include "GuiWindow.h"
#include "imgui.h"
#include "implot.h"
#include "nanovg.h"
#include "strings.h"
#include "filesystem.h"
#include "array.h"
#include "list.h"
#include "map.h"
#include "intersections.h"
#include "pickalloc_analizer.h"
#include "pickalloc_cfg.h"
#include <stdio.h>
class Memusage : public tp::GuiWindow {
tp::string filename;
static const char logo_len = 16;
const char logo[logo_len] = "memusage\0\0\0\0\0\0\0";
char logo_loaded[logo_len];
PickAllocConfig cfg;
enum class LoadStatus {
NONE,
DONE,
INVALID_FILE_PATH,
INVALID_FILE_FORMAT,
INTERNAL_ERROR,
} status;
typedef tp::PickAllocDataAnalizer::Event Event;
typedef tp::alni SizeKey;
struct Timeline {
tp::Array<tp::alnf> size;
tp::Array<tp::alnf> time;
tp::ualni peak = 0;
tp::ualni avereging = 0;
void recordEvents(tp::Array<Event>& events) {
tp::ualni total_mem_usage = 0;
size.extend(events.length());
time.extend(events.length());
for (auto ev : events) {
if (ev->dealloc) {
total_mem_usage -= ev->size;
} else {
total_mem_usage += ev->size;
}
time[ev.idx()] = (tp::alnf) ev->time;
size[ev.idx()] = (tp::alnf) total_mem_usage;
if (peak < total_mem_usage) {
peak = total_mem_usage;
}
}
avereging = 1;
}
void to_seconds() {
for (auto tm : time) {
tm.data() /= 1000;
}
}
};
// Contains events of fixed size
struct Group {
tp::ualni group_size = 0;
tp::Array<Event> events;
tp::ualni flag = 0;
Timeline timeline;
Group(tp::ualni grp_size) : group_size(grp_size) {}
};
tp::HashMap<Group*, SizeKey> groups;
tp::Array<Group*> groups_sorted;
public:
Memusage(const char* filename) : GuiWindow() {
this->mHeader.mAppTitle = "Mamusage Analizer";
this->mHeader.mPadding = 10;
tp::string file_path = __FILE__;
tp::make_dir_str(file_path.get_writable());
tp::make_dir_str(file_path.get_writable());
this->mRscDirectory = file_path + "/";
this->mGuiRootIsWindow = false;
LoadFonts();
this->filename = filename;
}
~Memusage() {
for (auto tl : groups) {
delete tl->val;
}
if (cfg.mAllocationSizes) delete[] cfg.mAllocationSizes;
if (cfg.mChunkLengths) delete[] cfg.mChunkLengths;
}
void run() {
// display status
for (auto i : tp::Range(2)) {
procInputs();
beginDraw();
if (mNativeWindow.mEvents.mRedraw) {
DrawCallback();
}
endDraw();
mNativeWindow.mEvents.mRedraw = true;
}
while (!mNativeWindow.mEvents.mTerminate) {
tp::Timer timer(5);
procInputs();
beginDraw();
if (mNativeWindow.mEvents.mRedraw) {
DrawCallback();
}
endDraw();
timer.wait();
if (status == LoadStatus::NONE) {
openFile();
mNativeWindow.mEvents.mRedraw = true;
}
}
}
private:
tp::ualni fileContentSize(tp::File& file) {
return file.size() - fileContentStartIdx();
}
tp::ualni fileContentStartIdx() {
return logo_len;
}
void readFile(tp::File& file) {
using namespace tp;
// read cfg
file.read(&cfg.mCapacity);
cfg.mAllocationSizes = new tp::int4[cfg.mCapacity];
cfg.mChunkLengths = new tp::int4[cfg.mCapacity];
file.read_bytes((tp::int1*)cfg.mAllocationSizes, sizeof(tp::int4) * cfg.mCapacity);
file.read_bytes((tp::int1*)cfg.mChunkLengths, sizeof(tp::int4) * cfg.mCapacity);
// read evens
tp::ualni events_length;
file.read(&events_length);
// one pass to collect data about groups in 'flag'
auto events_adress = file.adress;
for (tp::ualni i = 0; i < events_length; i++) {
Event evnt;
file.read(&evnt);
auto idx = groups.presents(evnt.size);
Group* group = NULL;
if (idx) {
group = groups.getSlotVal(idx);
} else {
group = new Group(evnt.size);
groups.put(evnt.size, group);
}
group->flag++;
}
for (auto grp : groups) {
grp->val->events.reserve(grp->val->flag);
grp->val->flag = 0;
}
file.adress = events_adress;
// read actual events
for (tp::ualni idx = 0; idx < events_length; idx++) {
Event evnt;
file.read(&evnt);
auto grp = groups.get(evnt.size);
grp->events[grp->flag] = evnt;
grp->flag++;
}
// initialize additional structure for sorting
groups_sorted.reserve(groups.size());
for (auto grp : groups) {
groups_sorted[grp.entry_idx] = grp->val;
}
// generate timelines
for (auto grp : groups_sorted) {
grp.data()->timeline.recordEvents(grp.data()->events);
grp.data()->timeline.to_seconds();
}
}
void openFile() {
using namespace tp;
File log(filename.cstr(), osfile_openflags::LOAD);
if (!log.opened) {
status = LoadStatus::INVALID_FILE_PATH;
return;
}
log.read_bytes(logo_loaded, logo_len);
if (!tp::memequal(logo_loaded, logo, logo_len)) {
status = LoadStatus::INVALID_FILE_FORMAT;
return;
}
log.Preload();
try {
readFile(log);
status = LoadStatus::DONE;
} catch (...) {
status = LoadStatus::INTERNAL_ERROR;
return;
}
}
void HeaderDrawCallback() override {
using namespace ImGui;
Button("Analize");
Button("Save To Header File");
}
void DrawCallback() {
auto pos = this->mNativeWindow.mAppearence.mSize / 2;
if (status != LoadStatus::DONE) {
nvgFillColor(mNvg, nvgRGB(250, 250, 250));
nvgFontSize(mNvg, 24);
nvgTextAlign(mNvg, NVG_ALIGN_MIDDLE | NVG_ALIGN_CENTER);
switch (status) {
case LoadStatus::NONE:
nvgText(mNvg, pos.x, pos.y, "Loading...", 0);
break;
case LoadStatus::INVALID_FILE_PATH:
nvgText(mNvg, pos.x, pos.y, "Invalid File Path", 0);
break;
case LoadStatus::INVALID_FILE_FORMAT:
nvgText(mNvg, pos.x, pos.y, "Invalid File Format", 0);
break;
case LoadStatus::INTERNAL_ERROR:
nvgText(mNvg, pos.x, pos.y, "Internal Error", 0);
}
return;
}
drawEditor();
}
enum class GroupSorting {
LARGER_SIZE,
SMALLER_SIZE,
LARGER_TOTAL_SIZE,
SMALLER_TOTAL_SIZE,
} sorting = GroupSorting::LARGER_SIZE;
void sortGroups(GroupSorting type) {
if (type == sorting) {
return;
}
switch (type) {
case Memusage::GroupSorting::LARGER_SIZE:
groups_sorted.sort([](Group* const& i1, Group* const& i2) {
return i1->group_size > i2->group_size;
});
break;
case Memusage::GroupSorting::SMALLER_SIZE:
groups_sorted.sort([](Group* const& i1, Group* const& i2) {
return i1->group_size < i2->group_size;
});
break;
case Memusage::GroupSorting::LARGER_TOTAL_SIZE:
break;
case Memusage::GroupSorting::SMALLER_TOTAL_SIZE:
break;
default:
break;
}
sorting = type;
}
Group* mGroupActive = NULL;
void groupView() {
using namespace ImGui;
int tmp;
const char* names[] = {
{"Larger Group Size"},
{"Smaller Group Size"},
//{"LARGER_TOTAL_SIZE"},
//{"SMALER_TOTAL_SIZE"},
};
tmp = (int) sorting;
Combo(" ", &tmp, names, 2);
Separator();
sortGroups((GroupSorting) tmp);
for (auto grp : groups_sorted) {
if (Selectable(tp::string((tp::alni)grp.data()->group_size).cstr())) {
mGroupActive = grp.data();
}
}
}
void drawTimeline(const Timeline& timeline) {
if (ImPlot::BeginPlot(" Plot ", {-1, -1}, ImPlotFlags_CanvasOnly | ImPlotFlags_AntiAliased)) {
ImPlot::PlotLine("Memory Usage", timeline.time.buff(), timeline.size.buff(), (tp::halni) timeline.time.length());
ImPlot::EndPlot();
}
}
void infoView() {
using namespace ImGui;
if (!mGroupActive) {
Text("No Group Selected");
return;
}
Text("Total Events : %i", mGroupActive->events.length());
Separator();
drawTimeline(mGroupActive->timeline);
}
void drawEditor() {
using namespace ImGui;
Begin("Groups View");
groupView();
End();
Begin("Info");
infoView();
End();
}
};
int main(char argc, char* argv[]) {
if (argc != 2) {
printf("invalid arguments");
return 0;
}
//ImPlot::
Memusage::InitializeTypes();
{
Memusage app(argv[1]);
ImPlot::CreateContext();
app.run();
ImPlot::DestroyContext();
printf("internal error");
}
Memusage::UnInitializeTypes();
tp::terminate();
}