summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/debugger.cc43
-rw-r--r--src/debugger.h2
-rw-r--r--src/heap.cc15
-rw-r--r--src/heap.h3
-rw-r--r--src/jdwp/jdwp_bits.h20
-rw-r--r--src/jdwp/jdwp_handler.cc2
-rw-r--r--src/jdwp/jdwp_main.cc17
-rw-r--r--src/jdwp/jdwp_priv.h3
-rw-r--r--src/utils.cc6
-rw-r--r--src/utils.h3
10 files changed, 80 insertions, 34 deletions
diff --git a/src/debugger.cc b/src/debugger.cc
index f7e80d374e..3321d68476 100644
--- a/src/debugger.cc
+++ b/src/debugger.cc
@@ -233,7 +233,7 @@ void Dbg::StopJdwp() {
void Dbg::GcDidFinish() {
if (gDdmHpifWhen != HPIF_WHEN_NEVER) {
LOG(DEBUG) << "Sending VM heap info to DDM";
- DdmSendHeapInfo(gDdmHpifWhen, false);
+ DdmSendHeapInfo(gDdmHpifWhen);
}
if (gDdmHpsgWhen != HPSG_WHEN_NEVER) {
LOG(DEBUG) << "Dumping VM heap to DDM";
@@ -867,7 +867,7 @@ void Dbg::DdmSendChunkV(int type, const struct iovec* iov, int iovcnt) {
int Dbg::DdmHandleHpifChunk(HpifWhen when) {
if (when == HPIF_WHEN_NOW) {
- DdmSendHeapInfo(when, true);
+ DdmSendHeapInfo(when);
return true;
}
@@ -901,8 +901,43 @@ bool Dbg::DdmHandleHpsgNhsgChunk(Dbg::HpsgWhen when, Dbg::HpsgWhat what, bool na
return true;
}
-void Dbg::DdmSendHeapInfo(HpifWhen reason, bool shouldLock) {
- UNIMPLEMENTED(WARNING) << "reason=" << static_cast<int>(reason) << " shouldLock=" << shouldLock;
+void Dbg::DdmSendHeapInfo(HpifWhen reason) {
+ // If there's a one-shot 'when', reset it.
+ if (reason == gDdmHpifWhen) {
+ if (gDdmHpifWhen == HPIF_WHEN_NEXT_GC) {
+ gDdmHpifWhen = HPIF_WHEN_NEVER;
+ }
+ }
+
+ /*
+ * Chunk HPIF (client --> server)
+ *
+ * Heap Info. General information about the heap,
+ * suitable for a summary display.
+ *
+ * [u4]: number of heaps
+ *
+ * For each heap:
+ * [u4]: heap ID
+ * [u8]: timestamp in ms since Unix epoch
+ * [u1]: capture reason (same as 'when' value from server)
+ * [u4]: max heap size in bytes (-Xmx)
+ * [u4]: current heap size in bytes
+ * [u4]: current number of bytes allocated
+ * [u4]: current number of objects allocated
+ */
+ uint8_t heap_count = 1;
+ std::vector<uint8_t> bytes(4 + (heap_count * (4 + 8 + 1 + 4 + 4 + 4 + 4)));
+ uint8_t* dst = &bytes[0];
+ JDWP::Write4BE(&dst, heap_count);
+ JDWP::Write4BE(&dst, 1); // Heap id (bogus; we only have one heap).
+ JDWP::Write8BE(&dst, MilliTime());
+ JDWP::Write1BE(&dst, reason);
+ JDWP::Write4BE(&dst, Heap::GetMaxMemory()); // Max allowed heap size in bytes.
+ JDWP::Write4BE(&dst, Heap::GetTotalMemory()); // Current heap size in bytes.
+ JDWP::Write4BE(&dst, Heap::GetBytesAllocated());
+ JDWP::Write4BE(&dst, Heap::GetObjectsAllocated());
+ Dbg::DdmSendChunk(CHUNK_TYPE("HPIF"), bytes.size(), &bytes[0]);
}
void Dbg::DdmSendHeapSegments(bool shouldLock, bool native) {
diff --git a/src/debugger.h b/src/debugger.h
index a818a48d53..85cc1f8fcd 100644
--- a/src/debugger.h
+++ b/src/debugger.h
@@ -257,7 +257,7 @@ public:
};
static bool DdmHandleHpsgNhsgChunk(HpsgWhen when, HpsgWhat what, bool native);
- static void DdmSendHeapInfo(HpifWhen reason, bool shouldLock);
+ static void DdmSendHeapInfo(HpifWhen reason);
static void DdmSendHeapSegments(bool shouldLock, bool native);
};
diff --git a/src/heap.cc b/src/heap.cc
index 555569a7f3..9fe77508e3 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -405,18 +405,15 @@ Object* Heap::AllocateLocked(Space* space, size_t size) {
}
int64_t Heap::GetMaxMemory() {
- UNIMPLEMENTED(WARNING);
- return 0;
+ return maximum_size_;
}
int64_t Heap::GetTotalMemory() {
- UNIMPLEMENTED(WARNING);
- return 0;
+ return alloc_space_->Size();
}
int64_t Heap::GetFreeMemory() {
- UNIMPLEMENTED(WARNING);
- return 0;
+ return alloc_space_->Size() - num_bytes_allocated_;
}
class InstanceCounter {
@@ -523,14 +520,14 @@ void Heap::CollectGarbageInternal() {
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);
+ size_t total = GetTotalMemory();
+ size_t percentFree = 100 - static_cast<size_t>(100.0f * float(num_bytes_allocated_) / total);
uint32_t duration = (t1 - t0)/1000/1000;
if (is_verbose_gc_) {
LOG(INFO) << "GC freed " << (is_small ? "<" : "") << kib_freed << "KiB, "
<< percentFree << "% free "
- << (num_bytes_allocated_/1024) << "KiB/" << (footprint/1024) << "KiB, "
+ << (num_bytes_allocated_/1024) << "KiB/" << (total/1024) << "KiB, "
<< "paused " << duration << "ms";
}
Dbg::GcDidFinish();
diff --git a/src/heap.h b/src/heap.h
index 9e21272576..2e8057100f 100644
--- a/src/heap.h
+++ b/src/heap.h
@@ -175,6 +175,9 @@ class Heap {
static void AddFinalizerReference(Object* object);
+ static size_t GetBytesAllocated() { return num_bytes_allocated_; }
+ static size_t GetObjectsAllocated() { return num_objects_allocated_; }
+
private:
// Allocates uninitialized storage.
static Object* AllocateLocked(size_t num_bytes);
diff --git a/src/jdwp/jdwp_bits.h b/src/jdwp/jdwp_bits.h
index 59ece0358c..3b951f9a8c 100644
--- a/src/jdwp/jdwp_bits.h
+++ b/src/jdwp/jdwp_bits.h
@@ -107,6 +107,26 @@ static inline void Set8BE(uint8_t* buf, uint64_t val) {
*buf = (uint8_t)(val);
}
+static inline void Write1BE(uint8_t** dst, uint8_t value) {
+ Set1(*dst, value);
+ *dst += sizeof(value);
+}
+
+static inline void Write2BE(uint8_t** dst, uint16_t value) {
+ Set2BE(*dst, value);
+ *dst += sizeof(value);
+}
+
+static inline void Write4BE(uint8_t** dst, uint32_t value) {
+ Set4BE(*dst, value);
+ *dst += sizeof(value);
+}
+
+static inline void Write8BE(uint8_t** dst, uint64_t value) {
+ Set8BE(*dst, value);
+ *dst += sizeof(value);
+}
+
/*
* Stuff a UTF-8 string into the buffer.
*/
diff --git a/src/jdwp/jdwp_handler.cc b/src/jdwp/jdwp_handler.cc
index f408c5478f..04c4734f45 100644
--- a/src/jdwp/jdwp_handler.cc
+++ b/src/jdwp/jdwp_handler.cc
@@ -1806,7 +1806,7 @@ void JdwpState::ProcessRequest(const JdwpReqHeader* pHeader, const uint8_t* buf,
* the initial setup. Only update if this is a non-DDMS packet.
*/
if (pHeader->cmdSet != kJDWPDdmCmdSet) {
- QuasiAtomicSwap64(GetNowMsec(), &lastActivityWhen);
+ QuasiAtomicSwap64(MilliTime(), &lastActivityWhen);
}
/* tell the VM that GC is okay again */
diff --git a/src/jdwp/jdwp_main.cc b/src/jdwp/jdwp_main.cc
index 1df0d66601..fa02895bba 100644
--- a/src/jdwp/jdwp_main.cc
+++ b/src/jdwp/jdwp_main.cc
@@ -412,21 +412,6 @@ Thread* JdwpState::GetDebugThread() {
*/
/*
- * Get a notion of the current time, in milliseconds.
- */
-int64_t GetNowMsec() {
-#ifdef HAVE_POSIX_CLOCKS
- struct timespec now;
- clock_gettime(CLOCK_MONOTONIC, &now);
- return now.tv_sec * 1000LL + now.tv_nsec / 1000000LL;
-#else
- struct timeval now;
- gettimeofday(&now, NULL);
- return now.tv_sec * 1000LL + now.tv_usec / 1000LL;
-#endif
-}
-
-/*
* Return the time, in milliseconds, since the last debugger activity.
*
* Returns -1 if no debugger is attached, or 0 if we're in the middle of
@@ -447,7 +432,7 @@ int64_t JdwpState::LastDebuggerActivity() {
}
/* now get the current time */
- int64_t now = GetNowMsec();
+ int64_t now = MilliTime();
CHECK_GT(now, last);
LOG(VERBOSE) << "+++ debugger interval=" << (now - last);
diff --git a/src/jdwp/jdwp_priv.h b/src/jdwp/jdwp_priv.h
index 46f79b86db..45d70f85f0 100644
--- a/src/jdwp/jdwp_priv.h
+++ b/src/jdwp/jdwp_priv.h
@@ -83,9 +83,6 @@ private:
Mutex socket_lock_;
};
-/* get current time, in msec */
-int64_t GetNowMsec();
-
} // namespace JDWP
} // namespace art
diff --git a/src/utils.cc b/src/utils.cc
index 639339abf3..4c65036ce4 100644
--- a/src/utils.cc
+++ b/src/utils.cc
@@ -49,6 +49,12 @@ std::string GetIsoDate() {
ptm->tm_hour, ptm->tm_min, ptm->tm_sec);
}
+uint64_t MilliTime() {
+ struct timespec now;
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ return static_cast<uint64_t>(now.tv_sec) * 1000LL + now.tv_nsec / 1000000LL;
+}
+
uint64_t NanoTime() {
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
diff --git a/src/utils.h b/src/utils.h
index bf8191eeaa..bb307d14da 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -209,6 +209,9 @@ bool ReadFileToString(const std::string& file_name, std::string* result);
// Returns the current date in ISO yyyy-mm-dd hh:mm:ss format.
std::string GetIsoDate();
+// Returns the current time in milliseconds (using the POSIX CLOCK_MONOTONIC).
+uint64_t MilliTime();
+
// Returns the current time in nanoseconds (using the POSIX CLOCK_MONOTONIC).
uint64_t NanoTime();