X-Git-Url: https://git.llucax.com/software/dgc/cdgc.git/blobdiff_plain/7e73b6245c0d7f6af8da2228a2fdbc9404ad69ec..9457e6cc1d1c824901af4fa8baca99f9b753b9cd:/rt/gc/cdgc/stats.d diff --git a/rt/gc/cdgc/stats.d b/rt/gc/cdgc/stats.d index 562d955..b854812 100644 --- a/rt/gc/cdgc/stats.d +++ b/rt/gc/cdgc/stats.d @@ -123,12 +123,16 @@ struct MallocInfo double timestamp = -1.0; /// Time spent in the malloc() call (in seconds). double time = -1.0; + /// Address of the pointer returned by malloc. + void* ptr = null; /// Memory requested by the malloc() call (in bytes). size_t size = 0; /// Memory attributes as BlkAttr flags. uint attr = 0; /// True if this malloc() triggered a collection. bool collected = false; + /// Address of the pointer map bitmask. + size_t* ptrmap = null; } @@ -153,7 +157,7 @@ struct Stats private: /// The GC instance we are collecting stats from. - .gc.GC gc = null; + .gc.GC* gc = null; /// True if statistics should be collected. bool active = false; @@ -184,13 +188,13 @@ private: /// Fill a MemoryInfo struct with the current state of the GC heap. void fill_memory_info(MemoryInfo* mem_info) { - mem_info.overhead += .gc.GC.classinfo.init.length + .gc.Gcx.sizeof - + .gc.pools.size_of + .gc.roots.size_of + .gc.ranges.size_of; + mem_info.overhead += .gc.GC.sizeof + gc.pools.elements_sizeof + + gc.roots.elements_sizeof + gc.ranges.elements_sizeof; // pools - for (size_t i = 0; i < .gc.pools.length; i++) + for (size_t i = 0; i < gc.pools.length; i++) { - auto pool = .gc.pools[i]; + auto pool = gc.pools[i]; mem_info.overhead += pool.npages * ubyte.sizeof; // the 5 bitmaps (mark, scan, free, final, noscan) mem_info.overhead += 5 * (GCBits.sizeof @@ -202,12 +206,12 @@ private: if (bin < .gc.B_PAGE) { size_t size = .gc.binsize[bin]; - size_t bitstride = size / 16; - size_t bitbase = pn * (.gc.PAGESIZE / 16); - size_t bittop = bitbase + (.gc.PAGESIZE / 16); - for (auto biti = bitbase; biti < bittop; biti += bitstride) + size_t attrstride = size / 16; + size_t attrbase = pn * (.gc.PAGESIZE / 16); + size_t attrtop = attrbase + (.gc.PAGESIZE / 16); + for (auto attri = attrbase; attri < attrtop; attri += attrstride) { - if (pool.freebits.test(biti)) + if (pool.freebits.test(attri)) mem_info.free += size; else mem_info.used += size; // TODO: wasted @@ -224,8 +228,8 @@ private: cstdio.FILE* start_file(char* filename, char* header) { cstdio.FILE* file = cstdio.fopen(filename, "w"); - assert (file !is null); - cstdio.fputs(header, file); + if (file !is null) + cstdio.fputs(header, file); return file; } @@ -233,16 +237,27 @@ private: { if (this.mallocs_file is null) return; + auto ptrmap = this.malloc_info.ptrmap; + auto ptrmask_offset = (ptrmap[0] - 1) / (size_t.sizeof * 8) + 1; cstdio.fprintf(this.mallocs_file, - "%f,%f,%zu,%zu,%zu,%zu,%zu\n", - //0 1 2 3 4 5 6 + "%f,%f,%p,%zu,%zu,%zu,%zu,%zu,%p,%zu,%0*zX,%0*zX\n", + //0 1 2 3 4 5 6 7 8 9 10 11 this.malloc_info.timestamp, // 0 this.malloc_info.time, // 1 - this.malloc_info.size, // 2 - this.malloc_info.collected ? 1u : 0u, // 3 - this.malloc_info.attr & .gc.BlkAttr.FINALIZE, // 4 - this.malloc_info.attr & .gc.BlkAttr.NO_SCAN, // 5 - this.malloc_info.attr & .gc.BlkAttr.NO_MOVE); // 6 + this.malloc_info.ptr, // 2 + this.malloc_info.size, // 3 + this.malloc_info.collected ? 1u : 0u, // 4 + this.malloc_info.attr & .gc.BlkAttr.FINALIZE, // 5 + this.malloc_info.attr & .gc.BlkAttr.NO_SCAN, // 6 + this.malloc_info.attr & .gc.BlkAttr.NO_MOVE, // 7 + ptrmap, // 8 + ptrmap[0] * size_t.sizeof, // 9 + size_t.sizeof, // fill length + ptrmap[1], // 10 + size_t.sizeof, // fill length + ptrmap[1 + ptrmask_offset]); // 11 + // TODO: make it an option + cstdio.fflush(this.mallocs_file); } void print_collection() @@ -264,6 +279,8 @@ private: this.collection_info.after.free, // 9 this.collection_info.after.wasted, // 10 this.collection_info.after.overhead); // 11 + // TODO: make it an option + cstdio.fflush(this.collections_file); } @@ -276,25 +293,29 @@ public: * the program start time (in seconds since the epoch) needs to be taken to * properly add timestamps to allocations and collections. */ - static Stats opCall(.gc.GC gc) + static Stats opCall(.gc.GC* gc) { Stats this_; this_.gc = gc; if (options.malloc_stats_file[0] != '\0') { - this_.active = true; this_.mallocs_file = this_.start_file( options.malloc_stats_file.ptr, - "Timestamp,Time,Size,Collection triggered," - "Finalize,No scan,No move\n"); + "Timestamp,Time,Pointer,Size,Collection triggered," + "Finalize,No scan,No move,Pointer map,Type size," + "Pointer map scan bitmask (first word, hexa)," + "Pointer map pointer bitmask (first word, hexa)\n"); + if (this_.mallocs_file !is null) + this_.active = true; } // collection if (options.collect_stats_file[0] != '\0') { - this_.active = true; this_.collections_file = this_.start_file( options.collect_stats_file.ptr, "Timestamp,Malloc time,Collection time,Stop-the-world time," "Used before,Free before,Wasted before,Overhead before," "Used after,Free after,Wasted after,Overhead after\n"); + if (this_.collections_file !is null) + this_.active = true; } this_.program_start = this_.now(); return this_; @@ -309,7 +330,8 @@ public: } /// Inform the start of an allocation. - void malloc_started(size_t size, uint attr) + // TODO: store/use type information + void malloc_started(size_t size, uint attr, size_t* ptrmap_bitmask) { if (!this.active) return; @@ -321,6 +343,7 @@ public: this.malloc_info.time = now; this.malloc_info.size = size; this.malloc_info.attr = attr; + this.malloc_info.ptrmap = ptrmap_bitmask; // this.malloc_info.collected is filled in malloc_finished() // collection this.collection_info = this.collection_info.init; @@ -329,7 +352,7 @@ public: } /// Inform the end of an allocation. - void malloc_finished() + void malloc_finished(void* ptr) { if (!this.active) return; @@ -339,6 +362,7 @@ public: this.malloc_info.time = now - this.malloc_info.time; if (collected) this.malloc_info.collected = true; + this.malloc_info.ptr = ptr; this.print_malloc(); if (!collected) return;