Include a new heap summary line in the SIGQUIT output.
Looks like this:
Heap: 87% free, 4MB/32MB; 6327 objects
While I'm here, fix another long-standing TODO to make PrettySize have the
usual google3 behavior. (I took the specific thresholds from Chromium.)
Also distinguish between the more general "Dump" member functions and the
specific SIGQUIT-related ones by consistently calling the latter DumpForSigQuit.
Change-Id: I76e783adc18dd089bac9b348f53dc9860a0fe4b9
diff --git a/src/heap.cc b/src/heap.cc
index eb62807..b4bc7ce 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -641,16 +641,10 @@
if (VLOG_IS_ON(gc) || gc_was_particularly_slow) {
// TODO: somehow make the specific GC implementation (here MarkSweep) responsible for logging.
size_t bytes_freed = initial_size - num_bytes_allocated_;
- if (bytes_freed > KB) { // ignore freed bytes in output if > 1KB
- bytes_freed = RoundDown(bytes_freed, KB);
- }
- size_t bytes_allocated = RoundUp(num_bytes_allocated_, KB);
// lose low nanoseconds in duration. TODO: make this part of PrettyDuration
duration_ns = (duration_ns / 1000) * 1000;
- size_t total = GetTotalMemory();
- size_t percentFree = 100 - static_cast<size_t>(100.0f * static_cast<float>(num_bytes_allocated_) / total);
- LOG(INFO) << "GC freed " << PrettySize(bytes_freed) << ", " << percentFree << "% free, "
- << PrettySize(bytes_allocated) << "/" << PrettySize(total) << ", "
+ LOG(INFO) << "GC freed " << PrettySize(bytes_freed) << ", " << GetPercentFree() << "% free, "
+ << PrettySize(num_bytes_allocated_) << "/" << PrettySize(GetTotalMemory()) << ", "
<< "paused " << PrettyDuration(duration_ns);
}
Dbg::GcDidFinish();
@@ -663,6 +657,17 @@
lock_->AssertHeld();
}
+void Heap::DumpForSigQuit(std::ostream& os) {
+ os << "Heap: " << GetPercentFree() << "% free, "
+ << PrettySize(num_bytes_allocated_) << "/" << PrettySize(GetTotalMemory())
+ << "; " << num_objects_allocated_ << " objects";
+}
+
+size_t Heap::GetPercentFree() {
+ size_t total = GetTotalMemory();
+ return 100 - static_cast<size_t>(100.0f * static_cast<float>(num_bytes_allocated_) / total);
+}
+
void Heap::SetIdealFootprint(size_t max_allowed_footprint) {
size_t alloc_space_capacity = alloc_space_->Capacity();
if (max_allowed_footprint > alloc_space_capacity) {
diff --git a/src/heap.h b/src/heap.h
index 7717871..3f0ffc0 100644
--- a/src/heap.h
+++ b/src/heap.h
@@ -17,6 +17,7 @@
#ifndef ART_SRC_HEAP_H_
#define ART_SRC_HEAP_H_
+#include <iosfwd>
#include <string>
#include <vector>
@@ -219,6 +220,8 @@
return alloc_space_;
}
+ void DumpForSigQuit(std::ostream& os);
+
private:
// Allocates uninitialized storage.
Object* AllocateLocked(size_t num_bytes);
@@ -239,6 +242,8 @@
// collection.
void GrowForUtilization();
+ size_t GetPercentFree();
+
void AddSpace(Space* space);
void VerifyObjectLocked(const Object *obj);
diff --git a/src/runtime.cc b/src/runtime.cc
index 77c887e..947eec5 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -745,13 +745,13 @@
#undef REGISTER
}
-void Runtime::Dump(std::ostream& os) {
- // TODO: dump other runtime statistics?
+void Runtime::DumpForSigQuit(std::ostream& os) {
GetClassLinker()->DumpForSigQuit(os);
GetInternTable()->DumpForSigQuit(os);
+ GetHeap()->DumpForSigQuit(os);
os << "\n";
- thread_list_->Dump(os);
+ thread_list_->DumpForSigQuit(os);
}
void Runtime::DumpLockHolders(std::ostream& os) {
diff --git a/src/runtime.h b/src/runtime.h
index 0dea763..2bf1148 100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -130,7 +130,7 @@
// Detaches the current native thread from the runtime.
void DetachCurrentThread();
- void Dump(std::ostream& os);
+ void DumpForSigQuit(std::ostream& os);
void DumpLockHolders(std::ostream& os);
~Runtime();
diff --git a/src/signal_catcher.cc b/src/signal_catcher.cc
index be21372..dd31fa7 100644
--- a/src/signal_catcher.cc
+++ b/src/signal_catcher.cc
@@ -114,7 +114,7 @@
os << "Cmd line: " << cmdline << "\n";
}
- runtime->Dump(os);
+ runtime->DumpForSigQuit(os);
if (false) {
std::string maps;
diff --git a/src/thread_list.cc b/src/thread_list.cc
index 43a8561..80ab2cf 100644
--- a/src/thread_list.cc
+++ b/src/thread_list.cc
@@ -54,7 +54,7 @@
return thread_list_lock_.GetOwner();
}
-void ThreadList::Dump(std::ostream& os) {
+void ThreadList::DumpForSigQuit(std::ostream& os) {
ScopedThreadListLock thread_list_lock;
DumpLocked(os);
}
diff --git a/src/thread_list.h b/src/thread_list.h
index 0691808..f0b4f6b 100644
--- a/src/thread_list.h
+++ b/src/thread_list.h
@@ -31,7 +31,7 @@
explicit ThreadList();
~ThreadList();
- void Dump(std::ostream& os);
+ void DumpForSigQuit(std::ostream& os);
void DumpLocked(std::ostream& os); // For thread suspend timeout dumps.
pid_t GetLockOwner(); // For SignalCatcher.
diff --git a/src/utils.cc b/src/utils.cc
index 70d15bf..ea50073 100644
--- a/src/utils.cc
+++ b/src/utils.cc
@@ -345,16 +345,26 @@
return result;
}
-std::string PrettySize(size_t size_in_bytes) {
- if ((size_in_bytes / GB) * GB == size_in_bytes) {
- return StringPrintf("%zdGB", size_in_bytes / GB);
- } else if ((size_in_bytes / MB) * MB == size_in_bytes) {
- return StringPrintf("%zdMB", size_in_bytes / MB);
- } else if ((size_in_bytes / KB) * KB == size_in_bytes) {
- return StringPrintf("%zdKB", size_in_bytes / KB);
- } else {
- return StringPrintf("%zdB", size_in_bytes);
+std::string PrettySize(size_t byte_count) {
+ // The byte thresholds at which we display amounts. A byte count is displayed
+ // in unit U when kUnitThresholds[U] <= bytes < kUnitThresholds[U+1].
+ static const size_t kUnitThresholds[] = {
+ 0, // B up to...
+ 3*1024, // KB up to...
+ 2*1024*1024, // MB up to...
+ 1024*1024*1024 // GB from here.
+ };
+ static const size_t kBytesPerUnit[] = { 1, KB, MB, GB };
+ static const char* const kUnitStrings[] = { "B", "KB", "MB", "GB" };
+
+ int i = arraysize(kUnitThresholds);
+ while (--i > 0) {
+ if (byte_count >= kUnitThresholds[i]) {
+ break;
+ }
}
+
+ return StringPrintf("%zd%s", byte_count / kBytesPerUnit[i], kUnitStrings[i]);
}
std::string PrettyDuration(uint64_t nano_duration) {
diff --git a/src/utils.h b/src/utils.h
index f11a769..f94c05e 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -191,7 +191,7 @@
// Returns a human-readable form of the name of the given class with its class loader.
std::string PrettyClassAndClassLoader(const Class* c);
-// Returns a human-readable size string. e.g. "1MB"
+// Returns a human-readable size string such as "1MB".
std::string PrettySize(size_t size_in_bytes);
// Returns a human-readable time string which prints every nanosecond while trying to limit the
diff --git a/src/utils_test.cc b/src/utils_test.cc
index e0b2139..311bd16 100644
--- a/src/utils_test.cc
+++ b/src/utils_test.cc
@@ -135,15 +135,17 @@
if (sizeof(size_t) > sizeof(uint32_t)) {
EXPECT_EQ("100GB", PrettySize(100 * GB));
}
- EXPECT_EQ("1MB", PrettySize(1 * MB));
+ EXPECT_EQ("1024KB", PrettySize(1 * MB));
EXPECT_EQ("10MB", PrettySize(10 * MB));
EXPECT_EQ("100MB", PrettySize(100 * MB));
- EXPECT_EQ("1KB", PrettySize(1 * KB));
+ EXPECT_EQ("1024B", PrettySize(1 * KB));
EXPECT_EQ("10KB", PrettySize(10 * KB));
EXPECT_EQ("100KB", PrettySize(100 * KB));
+ EXPECT_EQ("0B", PrettySize(0));
EXPECT_EQ("1B", PrettySize(1));
EXPECT_EQ("10B", PrettySize(10));
EXPECT_EQ("100B", PrettySize(100));
+ EXPECT_EQ("512B", PrettySize(512));
}
TEST_F(UtilsTest, PrettyDuration) {