Browse Source

LibJS: Add API for doing GC with a little debug log report at end

You can now pass print_report=true to Heap::collect_garbage() and it
will print out a little summary of the time spent, and counts of
live vs freed cells and blocks.
Andreas Kling 5 years ago
parent
commit
bbd3192535
2 changed files with 31 additions and 5 deletions
  1. 28 3
      Libraries/LibJS/Heap/Heap.cpp
  2. 3 2
      Libraries/LibJS/Heap/Heap.h

+ 28 - 3
Libraries/LibJS/Heap/Heap.cpp

@@ -26,6 +26,7 @@
 
 
 #include <AK/Badge.h>
 #include <AK/Badge.h>
 #include <AK/HashTable.h>
 #include <AK/HashTable.h>
+#include <LibCore/ElapsedTimer.h>
 #include <LibJS/Heap/Handle.h>
 #include <LibJS/Heap/Handle.h>
 #include <LibJS/Heap/Heap.h>
 #include <LibJS/Heap/Heap.h>
 #include <LibJS/Heap/HeapBlock.h>
 #include <LibJS/Heap/HeapBlock.h>
@@ -82,8 +83,10 @@ Cell* Heap::allocate_cell(size_t size)
     return cell;
     return cell;
 }
 }
 
 
-void Heap::collect_garbage(CollectionType collection_type)
+void Heap::collect_garbage(CollectionType collection_type, bool print_report)
 {
 {
+    Core::ElapsedTimer collection_measurement_timer;
+    collection_measurement_timer.start();
     if (collection_type == CollectionType::CollectGarbage) {
     if (collection_type == CollectionType::CollectGarbage) {
         if (m_gc_deferrals) {
         if (m_gc_deferrals) {
             m_should_gc_when_deferral_ends = true;
             m_should_gc_when_deferral_ends = true;
@@ -93,7 +96,7 @@ void Heap::collect_garbage(CollectionType collection_type)
         gather_roots(roots);
         gather_roots(roots);
         mark_live_cells(roots);
         mark_live_cells(roots);
     }
     }
-    sweep_dead_cells();
+    sweep_dead_cells(print_report, collection_measurement_timer);
 }
 }
 
 
 void Heap::gather_roots(HashTable<Cell*>& roots)
 void Heap::gather_roots(HashTable<Cell*>& roots)
@@ -230,13 +233,18 @@ void Heap::mark_live_cells(const HashTable<Cell*>& roots)
         visitor.visit(root);
         visitor.visit(root);
 }
 }
 
 
-void Heap::sweep_dead_cells()
+void Heap::sweep_dead_cells(bool print_report, const Core::ElapsedTimer& measurement_timer)
 {
 {
 #ifdef HEAP_DEBUG
 #ifdef HEAP_DEBUG
     dbg() << "sweep_dead_cells:";
     dbg() << "sweep_dead_cells:";
 #endif
 #endif
     Vector<HeapBlock*, 32> empty_blocks;
     Vector<HeapBlock*, 32> empty_blocks;
 
 
+    size_t collected_cells = 0;
+    size_t live_cells = 0;
+    size_t collected_cell_bytes = 0;
+    size_t live_cell_bytes = 0;
+
     for (auto& block : m_blocks) {
     for (auto& block : m_blocks) {
         bool block_has_live_cells = false;
         bool block_has_live_cells = false;
         block->for_each_cell([&](Cell* cell) {
         block->for_each_cell([&](Cell* cell) {
@@ -246,9 +254,13 @@ void Heap::sweep_dead_cells()
                     dbg() << "  ~ " << cell;
                     dbg() << "  ~ " << cell;
 #endif
 #endif
                     block->deallocate(cell);
                     block->deallocate(cell);
+                    ++collected_cells;
+                    collected_cell_bytes += block->cell_size();
                 } else {
                 } else {
                     cell->set_marked(false);
                     cell->set_marked(false);
                     block_has_live_cells = true;
                     block_has_live_cells = true;
+                    ++live_cells;
+                    live_cell_bytes += block->cell_size();
                 }
                 }
             }
             }
         });
         });
@@ -268,6 +280,19 @@ void Heap::sweep_dead_cells()
         dbg() << " > Live HeapBlock @ " << block << ": cell_size=" << block->cell_size();
         dbg() << " > Live HeapBlock @ " << block << ": cell_size=" << block->cell_size();
     }
     }
 #endif
 #endif
+
+    int time_spent = measurement_timer.elapsed();
+
+    if (print_report) {
+        dbg() << "Garbage collection report";
+        dbg() << "=============================================";
+        dbg() << "     Time spent: " << time_spent << " ms";
+        dbg() << "     Live cells: " << live_cells << " (" << live_cell_bytes << " bytes)";
+        dbg() << "Collected cells: " << collected_cells << " (" << collected_cell_bytes << " bytes)";
+        dbg() << "    Live blocks: " << m_blocks.size() << " (" << m_blocks.size() * HeapBlock::block_size << " bytes)";
+        dbg() << "   Freed blocks: " << empty_blocks.size() << " (" << empty_blocks.size() * HeapBlock::block_size << " bytes)";
+        dbg() << "=============================================";
+    }
 }
 }
 
 
 void Heap::did_create_handle(Badge<HandleImpl>, HandleImpl& impl)
 void Heap::did_create_handle(Badge<HandleImpl>, HandleImpl& impl)

+ 3 - 2
Libraries/LibJS/Heap/Heap.h

@@ -31,6 +31,7 @@
 #include <AK/NonnullOwnPtr.h>
 #include <AK/NonnullOwnPtr.h>
 #include <AK/Types.h>
 #include <AK/Types.h>
 #include <AK/Vector.h>
 #include <AK/Vector.h>
+#include <LibCore/Forward.h>
 #include <LibJS/Forward.h>
 #include <LibJS/Forward.h>
 #include <LibJS/Heap/Handle.h>
 #include <LibJS/Heap/Handle.h>
 #include <LibJS/Runtime/Cell.h>
 #include <LibJS/Runtime/Cell.h>
@@ -68,7 +69,7 @@ public:
         CollectEverything,
         CollectEverything,
     };
     };
 
 
-    void collect_garbage(CollectionType = CollectionType::CollectGarbage);
+    void collect_garbage(CollectionType = CollectionType::CollectGarbage, bool print_report = false);
 
 
     Interpreter& interpreter() { return m_interpreter; }
     Interpreter& interpreter() { return m_interpreter; }
 
 
@@ -90,7 +91,7 @@ private:
     void gather_roots(HashTable<Cell*>&);
     void gather_roots(HashTable<Cell*>&);
     void gather_conservative_roots(HashTable<Cell*>&);
     void gather_conservative_roots(HashTable<Cell*>&);
     void mark_live_cells(const HashTable<Cell*>& live_cells);
     void mark_live_cells(const HashTable<Cell*>& live_cells);
-    void sweep_dead_cells();
+    void sweep_dead_cells(bool print_report, const Core::ElapsedTimer&);
 
 
     Cell* cell_from_possible_pointer(FlatPtr);
     Cell* cell_from_possible_pointer(FlatPtr);