From 0d83c3aba676e18ccf8edf0c0cc3bfb871c39de4 Mon Sep 17 00:00:00 2001 From: Ilari Liusvaara Date: Wed, 27 May 2015 17:59:00 +0300 Subject: [PATCH] Rework how memory tracking works Also adds a few new tracking categories, like movie storage --- TODO | 1 + include/core/framebuffer.hpp | 1 - include/core/misc.hpp | 2 -- include/core/moviefile.hpp | 1 + include/core/romimage.hpp | 4 ++-- include/library/framebuffer.hpp | 11 ++++++++--- include/library/memtracker.hpp | 34 ++++++++++++++++++++++++++++++++++ include/library/movie.hpp | 3 +++ include/library/portctrl-data.hpp | 9 ++++++++- src/core/advdumper.cpp | 2 +- src/core/framebuffer.cpp | 5 ----- src/core/instance.cpp | 2 +- src/core/misc.cpp | 6 ------ src/core/moviefile.cpp | 4 ++++ src/core/romimage.cpp | 19 +++++++++---------- src/emulation/Makefile | 2 +- src/library/framebuffer.cpp | 9 +++------ src/library/memtracker.cpp | 19 ++++++++++++++++++- src/library/movie.cpp | 3 ++- src/library/portctrl-data.cpp | 4 ++++ src/lua/gui-rqueue.cpp | 1 - src/lua/lua.cpp | 4 ++-- 22 files changed, 102 insertions(+), 44 deletions(-) diff --git a/TODO b/TODO index e69de29b..1bfb1ff7 100644 --- a/TODO +++ b/TODO @@ -0,0 +1 @@ +- Memory Tracking: Track dynamic state. \ No newline at end of file diff --git a/include/core/framebuffer.hpp b/include/core/framebuffer.hpp index 9bfbbc9e..9cd79fde 100644 --- a/include/core/framebuffer.hpp +++ b/include/core/framebuffer.hpp @@ -87,7 +87,6 @@ private: void do_screenshot(command::arg_filename a); struct render_info { - render_info(); framebuffer::raw fbuf; framebuffer::queue rq; uint32_t hscl; diff --git a/include/core/misc.hpp b/include/core/misc.hpp index 2853ec81..ac2d45ba 100644 --- a/include/core/misc.hpp +++ b/include/core/misc.hpp @@ -59,6 +59,4 @@ std::string mangle_name(const std::string& orig); */ std::string get_temp_file(); -memtracker& mem_tracker(); - #endif diff --git a/include/core/moviefile.hpp b/include/core/moviefile.hpp index 52cf21b1..e6beb0b3 100644 --- a/include/core/moviefile.hpp +++ b/include/core/moviefile.hpp @@ -322,6 +322,7 @@ private: void binary_io(int stream, struct core_type& romtype) throw(std::bad_alloc, std::runtime_error); void save(zip::writer& w, rrdata_set& rrd, bool as_state) throw(std::bad_alloc, std::runtime_error); void load(zip::reader& r, core_type& romtype) throw(std::bad_alloc, std::runtime_error); + memtracker::autorelease tracker; }; void emerg_save_movie(const moviefile& mv, rrdata_set& rrd); diff --git a/include/core/romimage.hpp b/include/core/romimage.hpp index d40810ba..dcc87990 100644 --- a/include/core/romimage.hpp +++ b/include/core/romimage.hpp @@ -120,8 +120,6 @@ private: rom_image& operator=(const rom_image&); //Account images. void account_images(); - //Accounted memory usage. - size_t memory_usage; //Static NULL image. static fileimage::image null_img; //Loaded ROM images. @@ -147,6 +145,8 @@ private: //Handle bundle load case. void load_bundle(const std::string& file, std::istream& spec, const std::string& tmpprefer) throw(std::bad_alloc, std::runtime_error); + //Tracker. + memtracker::autorelease tracker; }; /** diff --git a/include/library/framebuffer.hpp b/include/library/framebuffer.hpp index 4e68a512..3c94832d 100644 --- a/include/library/framebuffer.hpp +++ b/include/library/framebuffer.hpp @@ -13,6 +13,7 @@ namespace framebuffer { +extern const char* render_page_id; template struct elem {}; template<> struct elem { typedef uint32_t t; }; template<> struct elem { typedef uint64_t t; }; @@ -668,7 +669,7 @@ struct queue /** * Constructor. */ - queue(memtracker& _tracker) throw(); + queue() throw(); /** * Destructor. */ @@ -676,14 +677,18 @@ struct queue private: void add(struct object& obj) throw(std::bad_alloc); struct node { struct object* obj; struct node* next; bool killed; }; - struct page { char content[RENDER_PAGE_SIZE]; }; + struct page { + char content[RENDER_PAGE_SIZE]; + page() { memtracker::singleton()(render_page_id, RENDER_PAGE_SIZE + 36); } + ~page() { memtracker::singleton()(render_page_id, -RENDER_PAGE_SIZE - 36); } + }; struct node* queue_head; struct node* queue_tail; size_t memory_allocated; size_t pages; threads::lock display_mutex; //Synchronize display and kill. std::map memory; - memtracker& tracker; + memtracker::autorelease tracker; }; /** diff --git a/include/library/memtracker.hpp b/include/library/memtracker.hpp index 9c35f6a0..fa9de09a 100644 --- a/include/library/memtracker.hpp +++ b/include/library/memtracker.hpp @@ -7,12 +7,46 @@ class memtracker { public: + memtracker(); + ~memtracker(); void operator()(const char* category, ssize_t change); void reset(const char* category, size_t value); std::map report(); + static memtracker& singleton(); + class autorelease + { + public: + autorelease(memtracker& _track, const char* cat, size_t amount) + : tracker(_track), category(cat), committed(amount) + { + tracker(category, committed); + } + ~autorelease() + { + tracker(category, -(ssize_t)committed); + } + void operator()(ssize_t delta) + { + if(delta < 0 && committed < (size_t)-delta) { + tracker(category, -(ssize_t)committed); + committed = 0; + } else { + tracker(category, delta); + committed = committed + delta; + } + } + private: + memtracker& tracker; + const char* category; + size_t committed; + }; private: + bool invalid; threads::lock mut; std::map data; + memtracker(const memtracker&); + memtracker& operator=(const memtracker&); }; + #endif \ No newline at end of file diff --git a/include/library/movie.hpp b/include/library/movie.hpp index 21e0831a..59f2ca7c 100644 --- a/include/library/movie.hpp +++ b/include/library/movie.hpp @@ -5,6 +5,7 @@ #include #include #include "portctrl-data.hpp" +#include "memtracker.hpp" /** * Movie being played back or recorded @@ -320,6 +321,8 @@ private: uint64_t cached_subframe; //Count present subframes in frame starting from first_subframe (returns 0 if out of movie). uint32_t count_changes(uint64_t first_subframe) throw(); + //Tracker. + memtracker::autorelease tracker; }; #endif diff --git a/include/library/portctrl-data.hpp b/include/library/portctrl-data.hpp index 61b262f1..a42ae464 100644 --- a/include/library/portctrl-data.hpp +++ b/include/library/portctrl-data.hpp @@ -18,6 +18,7 @@ #include #include "json.hpp" #include "threads.hpp" +#include "memtracker.hpp" namespace binarystream { @@ -48,6 +49,7 @@ namespace binarystream namespace portctrl { +extern const char* movie_page_id; /** * Is not field terminator. * @@ -1320,7 +1322,11 @@ private: class page { public: - page() { memset(content, 0, CONTROLLER_PAGE_SIZE); } + page() { + memtracker::singleton()(movie_page_id, CONTROLLER_PAGE_SIZE + 36); + memset(content, 0, CONTROLLER_PAGE_SIZE); + } + ~page() { memtracker::singleton()(movie_page_id, -CONTROLLER_PAGE_SIZE - 36); } unsigned char content[CONTROLLER_PAGE_SIZE]; }; size_t frames_per_page; @@ -1342,6 +1348,7 @@ private: cache_page_num--; cache_page = NULL; } + memtracker::autorelease tracker; }; void frame::sync(bool x) throw() diff --git a/src/core/advdumper.cpp b/src/core/advdumper.cpp index 7a00fe16..71d79042 100644 --- a/src/core/advdumper.cpp +++ b/src/core/advdumper.cpp @@ -349,7 +349,7 @@ template bool master_dumper::render_video_hud(struct framebuffer::fb& { bool lua_kill_video = false; struct lua::render_context lrc; - framebuffer::queue rq(mem_tracker()); + framebuffer::queue rq; lrc.left_gap = lgap; lrc.right_gap = rgap; lrc.bottom_gap = bgap; diff --git a/src/core/framebuffer.cpp b/src/core/framebuffer.cpp index 4f39c4ba..45c50e5c 100644 --- a/src/core/framebuffer.cpp +++ b/src/core/framebuffer.cpp @@ -88,11 +88,6 @@ namespace framebuffer::raw emu_framebuffer::screen_corrupt; -emu_framebuffer::render_info::render_info() - : rq(mem_tracker()) -{ -} - emu_framebuffer::emu_framebuffer(subtitle_commentary& _subtitles, settingvar::group& _settings, memwatch_set& _mwatch, keyboard::keyboard& _keyboard, emulator_dispatch& _dispatch, lua_state& _lua2, loaded_rom& _rom, status_updater& _supdater, command::group& _cmd) diff --git a/src/core/instance.cpp b/src/core/instance.cpp index 4bbf9d39..6335a48a 100644 --- a/src/core/instance.cpp +++ b/src/core/instance.cpp @@ -157,7 +157,7 @@ namespace command::fnptr<> CMD_memory_use(lsnes_cmds, "show-memory", "Show memory usage", "show-memory\nShow memory usage", []() throw(std::bad_alloc, std::runtime_error) { - auto report = mem_tracker().report(); + auto report = memtracker::singleton().report(); uint32_t maxwidth_left = 0; uint32_t maxwidth_right = 0; for(auto i : report) { diff --git a/src/core/misc.cpp b/src/core/misc.cpp index 32f5be0e..4bb8c13a 100644 --- a/src/core/misc.cpp +++ b/src/core/misc.cpp @@ -241,9 +241,3 @@ std::string get_temp_file() return tname; #endif } - -memtracker& mem_tracker() -{ - static memtracker x; - return x; -} diff --git a/src/core/moviefile.cpp b/src/core/moviefile.cpp index 9ebf0bbb..ce0173bc 100644 --- a/src/core/moviefile.cpp +++ b/src/core/moviefile.cpp @@ -29,6 +29,7 @@ namespace { + const char* movie_file_id = "Movie files"; std::map memory_saves; bool check_binary_magic(int s) @@ -102,6 +103,7 @@ moviefile::brief_info::brief_info(const std::string& filename) } moviefile::moviefile() throw(std::bad_alloc) + : tracker(memtracker::singleton(), movie_file_id, sizeof(*this)) { force_corrupt = false; gametype = NULL; @@ -117,6 +119,7 @@ moviefile::moviefile() throw(std::bad_alloc) moviefile::moviefile(loaded_rom& rom, std::map& c_settings, uint64_t rtc_sec, uint64_t rtc_subsec) + : tracker(memtracker::singleton(), movie_file_id, sizeof(*this)) { force_corrupt = false; gametype = &rom.get_sysregion(); @@ -146,6 +149,7 @@ moviefile::moviefile(loaded_rom& rom, std::map& c_sett } moviefile::moviefile(const std::string& movie, core_type& romtype) throw(std::bad_alloc, std::runtime_error) + : tracker(memtracker::singleton(), movie_file_id, sizeof(*this)) { regex_results rr; if(rr = regex("\\$MEMORY:(.*)", movie)) { diff --git a/src/core/romimage.cpp b/src/core/romimage.cpp index 6391bdb4..4bf8de16 100644 --- a/src/core/romimage.cpp +++ b/src/core/romimage.cpp @@ -5,6 +5,7 @@ #include "core/nullcore.hpp" #include "core/settings.hpp" #include "core/window.hpp" +#include "library/memtracker.hpp" #include "library/zip.hpp" fileimage::image rom_image::null_img; @@ -176,16 +177,16 @@ void rom_image::setup_region(core_region& reg) } rom_image::rom_image() throw() + : tracker(memtracker::singleton(), romimage_id, sizeof(*this)) { - memory_usage = 0; rtype = &get_null_type(); region = orig_region = &get_null_region(); account_images(); } rom_image::rom_image(const std::string& file, core_type& ctype) throw(std::bad_alloc, std::runtime_error) + : tracker(memtracker::singleton(), romimage_id, sizeof(*this)) { - memory_usage = 0; rtype = &ctype; orig_region = &rtype->get_preferred_region(); unsigned romidx = 0; @@ -216,8 +217,8 @@ rom_image::rom_image(const std::string& file, core_type& ctype) throw(std::bad_a rom_image::rom_image(const std::string& file, const std::string& tmpprefer) throw(std::bad_alloc, std::runtime_error) + : tracker(memtracker::singleton(), romimage_id, sizeof(*this)) { - memory_usage = 0; std::istream& spec = zip::openrel(file, ""); std::string s; std::getline(spec, s); @@ -370,8 +371,8 @@ void rom_image::load_bundle(const std::string& file, std::istream& spec, const s rom_image::rom_image(const std::string& file, const std::string& core, const std::string& type, const std::string& _region) + : tracker(memtracker::singleton(), romimage_id, sizeof(*this)) { - memory_usage = 0; core_type* t = NULL; core_region* r = NULL; bool fullspec = (core != "" && type != ""); @@ -415,8 +416,8 @@ rom_image::rom_image(const std::string& file, const std::string& core, const std rom_image::rom_image(const std::string file[ROM_SLOT_COUNT], const std::string& core, const std::string& type, const std::string& _region) + : tracker(memtracker::singleton(), romimage_id, sizeof(*this)) { - memory_usage = 0; core_type* t = NULL; core_region* r = NULL; bool fullspec = (core != "" && type != ""); @@ -456,6 +457,7 @@ rom_image::rom_image(const std::string file[ROM_SLOT_COUNT], const std::string& throw std::runtime_error("Required ROM images missing"); rtype = t; orig_region = region = r; + account_images(); } bool rom_image::is_gamepak(const std::string& filename) throw(std::bad_alloc, std::runtime_error) @@ -477,21 +479,18 @@ bool rom_image::is_gamepak(const std::string& filename) throw(std::bad_alloc, st rom_image::~rom_image() { - //Hack: If there is no accounted size, don't unaccount it. - if(memory_usage) - mem_tracker()(romimage_id, -(ssize_t)memory_usage); } void rom_image::account_images() { //Hack: don't account any size before main. if(in_global_ctors()) return; - memory_usage = sizeof(rom_image) + msu1_base.length() + load_filename.length(); + size_t memory_usage = sizeof(rom_image) + msu1_base.length() + load_filename.length(); for(unsigned i = 0; i < ROM_SLOT_COUNT; i++) { memory_usage += (unsigned)romimg[i]; memory_usage += (unsigned)romxml[i]; } - mem_tracker()(romimage_id, (ssize_t)memory_usage); + tracker(memory_usage); } void set_hasher_callback(std::function cb) diff --git a/src/emulation/Makefile b/src/emulation/Makefile index 8b50fcf3..682a635d 100644 --- a/src/emulation/Makefile +++ b/src/emulation/Makefile @@ -8,7 +8,7 @@ __all__.files: $(CORES_FILES) lua ../genfilelist.lua $^ >$@ cat $(CORES_FLAGS) >$(ALLFLAGS) -make-ports$(DOT_EXECUTABLE_SUFFIX): make-ports.cpp ../library/json.cpp ../library/utf8.cpp ../library/string.cpp ../library/portctrl-parse.cpp ../library/portctrl-data.cpp ../library/sha256.cpp ../library/assembler.cpp ../library/hex.cpp ../library/eatarg.cpp ../library/int24.cpp ../library/binarystream.cpp ../library/integer-pool.cpp +make-ports$(DOT_EXECUTABLE_SUFFIX): make-ports.cpp ../library/json.cpp ../library/utf8.cpp ../library/string.cpp ../library/portctrl-parse.cpp ../library/portctrl-data.cpp ../library/sha256.cpp ../library/assembler.cpp ../library/hex.cpp ../library/eatarg.cpp ../library/int24.cpp ../library/binarystream.cpp ../library/integer-pool.cpp ../library/memtracker.cpp $(HOSTCC) -g -std=gnu++0x -I../../include/library -o $@ $^ $(HOSTHELPER_LDFLAGS) -Wall -DNO_ASM_GENERATION bsnes-legacy/$(ALLFILES): forcelook make-ports$(DOT_EXECUTABLE_SUFFIX) diff --git a/src/library/framebuffer.cpp b/src/library/framebuffer.cpp index 3ceea22a..e40a308a 100644 --- a/src/library/framebuffer.cpp +++ b/src/library/framebuffer.cpp @@ -14,13 +14,13 @@ namespace framebuffer { +const char* render_page_id = "Render queues"; unsigned default_shift_r; unsigned default_shift_g; unsigned default_shift_b; namespace { - const char* render_pages_id = "Render objects"; void recalculate_default_shifts() { uint32_t magic = 0x18000810; @@ -577,8 +577,6 @@ void* queue::alloc(size_t block) throw(std::bad_alloc) throw std::bad_alloc(); if(pages == 0 || memory_allocated + block > pages * RENDER_PAGE_SIZE) { memory_allocated = pages * RENDER_PAGE_SIZE; - if(!memory.count(pages)) - tracker(render_pages_id, RENDER_PAGE_SIZE); memory[pages++]; } void* mem = memory[memory_allocated / RENDER_PAGE_SIZE].content + (memory_allocated % RENDER_PAGE_SIZE); @@ -604,8 +602,8 @@ void queue::kill_request(void* obj) throw() } } -queue::queue(memtracker& _tracker) throw() - : tracker(_tracker) +queue::queue() throw() + : tracker(memtracker::singleton(), render_page_id, sizeof(*this)) { queue_head = NULL; queue_tail = NULL; @@ -616,7 +614,6 @@ queue::queue(memtracker& _tracker) throw() queue::~queue() throw() { clear(); - tracker(render_pages_id, -(ssize_t)memory.size() * RENDER_PAGE_SIZE); } object::object() throw() diff --git a/src/library/memtracker.cpp b/src/library/memtracker.cpp index 7724785b..21ee5cdc 100644 --- a/src/library/memtracker.cpp +++ b/src/library/memtracker.cpp @@ -2,6 +2,7 @@ void memtracker::operator()(const char* category, ssize_t change) { + if(invalid) return; std::string cat = category; threads::alock h(mut); if(change > 0) { @@ -19,6 +20,7 @@ void memtracker::operator()(const char* category, ssize_t change) void memtracker::reset(const char* category, size_t value) { + if(invalid) return; std::string cat = category; threads::alock h(mut); data[cat] = value; @@ -27,9 +29,24 @@ void memtracker::reset(const char* category, size_t value) std::map memtracker::report() { std::map ret; - { + if(!invalid) { threads::alock h(mut); ret = data; } return ret; } + +memtracker::memtracker() +{ + invalid = false; +} +memtracker::~memtracker() +{ + invalid = true; +} + +memtracker& memtracker::singleton() +{ + static memtracker x; + return x; +} diff --git a/src/library/movie.cpp b/src/library/movie.cpp index 16887c44..f3ce5d76 100644 --- a/src/library/movie.cpp +++ b/src/library/movie.cpp @@ -11,6 +11,7 @@ namespace { + const char* movie_id = "Movies"; bool movies_compatible(portctrl::frame_vector& old_movie, portctrl::frame_vector& new_movie, uint64_t frame, const uint32_t* polls, const std::string& old_projectid, const std::string& new_projectid) @@ -193,7 +194,7 @@ short movie::next_input(unsigned port, unsigned controller, unsigned ctrl) throw } movie::movie() throw(std::bad_alloc) - : _listener(*this) + : _listener(*this), tracker(memtracker::singleton(), movie_id, sizeof(*this)) { movie_data = NULL; seqno = 0; diff --git a/src/library/portctrl-data.cpp b/src/library/portctrl-data.cpp index 4db2f38c..726b58e0 100644 --- a/src/library/portctrl-data.cpp +++ b/src/library/portctrl-data.cpp @@ -15,6 +15,7 @@ namespace portctrl { +const char* movie_page_id = "Input tracks"; namespace { controller simple_controller = {"(system)", "system", {}}; @@ -559,6 +560,7 @@ frame_vector::~frame_vector() throw() } frame_vector::frame_vector() throw() + : tracker(memtracker::singleton(), movie_page_id, sizeof(*this)) { real_frame_count = 0; freeze_count = 0; @@ -566,6 +568,7 @@ frame_vector::frame_vector() throw() } frame_vector::frame_vector(const type_set& p) throw() + : tracker(memtracker::singleton(), movie_page_id, sizeof(*this)) { real_frame_count = 0; freeze_count = 0; @@ -594,6 +597,7 @@ void frame_vector::append(frame cframe) throw(std::bad_alloc, std::runtime_error } frame_vector::frame_vector(const frame_vector& vector) throw(std::bad_alloc) + : tracker(memtracker::singleton(), movie_page_id, sizeof(*this)) { real_frame_count = 0; freeze_count = 0; diff --git a/src/lua/gui-rqueue.cpp b/src/lua/gui-rqueue.cpp index 83344cf5..13b63037 100644 --- a/src/lua/gui-rqueue.cpp +++ b/src/lua/gui-rqueue.cpp @@ -106,7 +106,6 @@ namespace }; lua_renderqueue::lua_renderqueue(lua::state& L, uint32_t width, uint32_t height) throw() - : rqueue(mem_tracker()) { lctx.left_gap = std::numeric_limits::max(); lctx.right_gap = std::numeric_limits::max(); diff --git a/src/lua/lua.cpp b/src/lua/lua.cpp index 4e85d0bb..5535ddbc 100644 --- a/src/lua/lua.cpp +++ b/src/lua/lua.cpp @@ -191,8 +191,8 @@ lua_state::lua_state(lua::state& _L, command::group& _command, settingvar::group //We can't read the value of lua maxmem setting here (it crashes), so just set default, it will be changed //if needed. L.set_memory_limit(1 << 27); - mem_tracker()(lua_vm_id, L.get_memory_use()); - L.set_memory_change_handler([](ssize_t delta) { mem_tracker()(lua_vm_id, delta); }); + memtracker::singleton()(lua_vm_id, L.get_memory_use()); + L.set_memory_change_handler([](ssize_t delta) { memtracker::singleton()(lua_vm_id, delta); }); idle_hook_time = 0x7EFFFFFFFFFFFFFFULL; timer_hook_time = 0x7EFFFFFFFFFFFFFFULL; -- 2.11.4.GIT