Basic GC logging (and class initialization timing).
Change-Id: Ibb09e556fbd42b1bb8cbd72974e8ca226aa073a5
diff --git a/src/class_linker.cc b/src/class_linker.cc
index 0299c4a..adabe97 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -1559,6 +1559,8 @@
klass->SetStatus(Class::kStatusInitializing);
}
+ uint64_t t0 = NanoTime();
+
if (!InitializeSuperClass(klass, can_run_clinit)) {
return false;
}
@@ -1569,6 +1571,8 @@
clinit->Invoke(self, NULL, NULL, NULL);
}
+ uint64_t t1 = NanoTime();
+
{
ObjectLock lock(klass);
@@ -1576,9 +1580,12 @@
WrapExceptionInInitializer();
klass->SetStatus(Class::kStatusError);
} else {
- ++Runtime::Current()->GetStats()->class_init_count;
- ++self->GetStats()->class_init_count;
- // TODO: class_init_time_ns
+ RuntimeStats* global_stats = Runtime::Current()->GetStats();
+ RuntimeStats* thread_stats = self->GetStats();
+ ++global_stats->class_init_count;
+ ++thread_stats->class_init_count;
+ global_stats->class_init_time_ns += (t1 - t0);
+ thread_stats->class_init_time_ns += (t1 - t0);
klass->SetStatus(Class::kStatusInitialized);
}
lock.NotifyAll();
diff --git a/src/heap.cc b/src/heap.cc
index 3f42c6b..019cfe2 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -454,6 +454,9 @@
ThreadList* thread_list = Runtime::Current()->GetThreadList();
thread_list->SuspendAll();
+
+ size_t initial_size = num_bytes_allocated_;
+ uint64_t t0 = NanoTime();
Object* cleared_references = NULL;
{
MarkSweep mark_sweep;
@@ -487,9 +490,24 @@
}
GrowForUtilization();
+ uint64_t t1 = NanoTime();
thread_list->ResumeAll();
EnqueueClearedReferences(&cleared_references);
+
+ // TODO: somehow make the specific GC implementation (here MarkSweep) responsible for logging.
+ size_t bytes_freed = initial_size - num_bytes_allocated_;
+ bool is_small = (bytes_freed > 0 && bytes_freed < 1024);
+ size_t kib_freed = (bytes_freed > 0 ? std::max(bytes_freed/1024, 1U) : 0);
+
+ size_t footprint = alloc_space_->Size();
+ size_t percentFree = 100 - static_cast<size_t>(100.0f * float(num_bytes_allocated_) / footprint);
+
+ uint32_t duration = (t1 - t0)/1000/1000;
+ LOG(INFO) << "GC freed " << (is_small ? "<" : "") << kib_freed << "KiB, "
+ << percentFree << "% free "
+ << (num_bytes_allocated_/1024) << "KiB/" << (footprint/1024) << "KiB, "
+ << "paused " << duration << "ms";
}
void Heap::WaitForConcurrentGcToComplete() {
diff --git a/src/utils.cc b/src/utils.cc
index 86fa312..3017807 100644
--- a/src/utils.cc
+++ b/src/utils.cc
@@ -47,6 +47,12 @@
ptm->tm_hour, ptm->tm_min, ptm->tm_sec);
}
+uint64_t NanoTime() {
+ struct timespec now;
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ return static_cast<uint64_t>(now.tv_sec) * 1000000000LL + now.tv_nsec;
+}
+
std::string PrettyDescriptor(const String* java_descriptor) {
if (java_descriptor == NULL) {
return "null";
diff --git a/src/utils.h b/src/utils.h
index 4f58c52..228925d 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -198,6 +198,9 @@
// Returns the current date in ISO yyyy-mm-dd hh:mm:ss format.
std::string GetIsoDate();
+// Returns the current time in nanoseconds (using the POSIX CLOCK_MONOTONIC).
+uint64_t NanoTime();
+
// Splits a string using the given delimiter character into a vector of
// strings. Empty strings will be omitted.
void Split(const std::string& s, char delim, std::vector<std::string>& result);