blob: d66ec7933bdb3a36b92bd79c97210c91946a45c8 [file] [log] [blame]
Jesse Wilsonc4824e62011-11-01 14:39:04 -04001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/*
18 * Preparation and completion of hprof data generation. The output is
19 * written into two files and then combined. This is necessary because
20 * we generate some of the data (strings and classes) while we dump the
21 * heap, and some analysis tools require that the class and string data
22 * appear first.
23 */
24
25#include "hprof.h"
Ian Rogers6d4d9fc2011-11-30 16:24:48 -080026
Elliott Hughes622a6982012-06-08 17:58:54 -070027#include <cutils/open_memstream.h>
28#include <errno.h>
29#include <fcntl.h>
30#include <stdio.h>
31#include <string.h>
32#include <sys/time.h>
33#include <sys/uio.h>
34#include <time.h>
35#include <time.h>
36#include <unistd.h>
37
38#include <set>
39
Elliott Hughes07ed66b2012-12-12 18:34:25 -080040#include "base/logging.h"
Elliott Hughese222ee02012-12-13 14:41:43 -080041#include "base/stringprintf.h"
Elliott Hughes76160052012-12-12 16:31:20 -080042#include "base/unix_file/fd_file.h"
Ian Rogers6d4d9fc2011-11-30 16:24:48 -080043#include "class_linker.h"
Ian Rogers62d6c772013-02-27 08:32:07 -080044#include "common_throws.h"
Jesse Wilsonc4824e62011-11-01 14:39:04 -040045#include "debugger.h"
Ian Rogers4f6ad8a2013-03-18 15:27:28 -070046#include "dex_file-inl.h"
Ian Rogers1d54e732013-05-02 21:10:01 -070047#include "gc/accounting/heap_bitmap.h"
48#include "gc/heap.h"
49#include "gc/space/space.h"
Elliott Hughes622a6982012-06-08 17:58:54 -070050#include "globals.h"
Ian Rogers2dd0e2c2013-01-24 12:42:14 -080051#include "mirror/class.h"
52#include "mirror/class-inl.h"
53#include "mirror/field.h"
54#include "mirror/field-inl.h"
55#include "mirror/object-inl.h"
Ian Rogers6d4d9fc2011-11-30 16:24:48 -080056#include "object_utils.h"
Elliott Hughesdcfdd2b2012-07-09 18:27:46 -070057#include "os.h"
Elliott Hughes622a6982012-06-08 17:58:54 -070058#include "safe_map.h"
Ian Rogers00f7d0e2012-07-19 15:28:27 -070059#include "scoped_thread_state_change.h"
Elliott Hughes622a6982012-06-08 17:58:54 -070060#include "thread_list.h"
Jesse Wilsonc4824e62011-11-01 14:39:04 -040061
62namespace art {
63
64namespace hprof {
65
Elliott Hughes622a6982012-06-08 17:58:54 -070066#define UNIQUE_ERROR -((((uintptr_t)__func__) << 16 | __LINE__) & (0x7fffffff))
Jesse Wilson0c54ac12011-11-09 15:14:05 -050067
Elliott Hughes622a6982012-06-08 17:58:54 -070068#define HPROF_TIME 0
69#define HPROF_NULL_STACK_TRACE 0
70#define HPROF_NULL_THREAD 0
71
72#define U2_TO_BUF_BE(buf, offset, value) \
73 do { \
74 unsigned char* buf_ = (unsigned char*)(buf); \
75 int offset_ = (int)(offset); \
76 uint16_t value_ = (uint16_t)(value); \
77 buf_[offset_ + 0] = (unsigned char)(value_ >> 8); \
78 buf_[offset_ + 1] = (unsigned char)(value_ ); \
79 } while (0)
80
81#define U4_TO_BUF_BE(buf, offset, value) \
82 do { \
83 unsigned char* buf_ = (unsigned char*)(buf); \
84 int offset_ = (int)(offset); \
85 uint32_t value_ = (uint32_t)(value); \
86 buf_[offset_ + 0] = (unsigned char)(value_ >> 24); \
87 buf_[offset_ + 1] = (unsigned char)(value_ >> 16); \
88 buf_[offset_ + 2] = (unsigned char)(value_ >> 8); \
89 buf_[offset_ + 3] = (unsigned char)(value_ ); \
90 } while (0)
91
92#define U8_TO_BUF_BE(buf, offset, value) \
93 do { \
94 unsigned char* buf_ = (unsigned char*)(buf); \
95 int offset_ = (int)(offset); \
96 uint64_t value_ = (uint64_t)(value); \
97 buf_[offset_ + 0] = (unsigned char)(value_ >> 56); \
98 buf_[offset_ + 1] = (unsigned char)(value_ >> 48); \
99 buf_[offset_ + 2] = (unsigned char)(value_ >> 40); \
100 buf_[offset_ + 3] = (unsigned char)(value_ >> 32); \
101 buf_[offset_ + 4] = (unsigned char)(value_ >> 24); \
102 buf_[offset_ + 5] = (unsigned char)(value_ >> 16); \
103 buf_[offset_ + 6] = (unsigned char)(value_ >> 8); \
104 buf_[offset_ + 7] = (unsigned char)(value_ ); \
105 } while (0)
106
107enum HprofTag {
108 HPROF_TAG_STRING = 0x01,
109 HPROF_TAG_LOAD_CLASS = 0x02,
110 HPROF_TAG_UNLOAD_CLASS = 0x03,
111 HPROF_TAG_STACK_FRAME = 0x04,
112 HPROF_TAG_STACK_TRACE = 0x05,
113 HPROF_TAG_ALLOC_SITES = 0x06,
114 HPROF_TAG_HEAP_SUMMARY = 0x07,
115 HPROF_TAG_START_THREAD = 0x0A,
116 HPROF_TAG_END_THREAD = 0x0B,
117 HPROF_TAG_HEAP_DUMP = 0x0C,
118 HPROF_TAG_HEAP_DUMP_SEGMENT = 0x1C,
119 HPROF_TAG_HEAP_DUMP_END = 0x2C,
120 HPROF_TAG_CPU_SAMPLES = 0x0D,
121 HPROF_TAG_CONTROL_SETTINGS = 0x0E,
122};
123
124// Values for the first byte of HEAP_DUMP and HEAP_DUMP_SEGMENT records:
125enum HprofHeapTag {
126 // Traditional.
127 HPROF_ROOT_UNKNOWN = 0xFF,
128 HPROF_ROOT_JNI_GLOBAL = 0x01,
129 HPROF_ROOT_JNI_LOCAL = 0x02,
130 HPROF_ROOT_JAVA_FRAME = 0x03,
131 HPROF_ROOT_NATIVE_STACK = 0x04,
132 HPROF_ROOT_STICKY_CLASS = 0x05,
133 HPROF_ROOT_THREAD_BLOCK = 0x06,
134 HPROF_ROOT_MONITOR_USED = 0x07,
135 HPROF_ROOT_THREAD_OBJECT = 0x08,
136 HPROF_CLASS_DUMP = 0x20,
137 HPROF_INSTANCE_DUMP = 0x21,
138 HPROF_OBJECT_ARRAY_DUMP = 0x22,
139 HPROF_PRIMITIVE_ARRAY_DUMP = 0x23,
140
141 // Android.
142 HPROF_HEAP_DUMP_INFO = 0xfe,
143 HPROF_ROOT_INTERNED_STRING = 0x89,
144 HPROF_ROOT_FINALIZING = 0x8a, // Obsolete.
145 HPROF_ROOT_DEBUGGER = 0x8b,
146 HPROF_ROOT_REFERENCE_CLEANUP = 0x8c, // Obsolete.
147 HPROF_ROOT_VM_INTERNAL = 0x8d,
148 HPROF_ROOT_JNI_MONITOR = 0x8e,
149 HPROF_UNREACHABLE = 0x90, // Obsolete.
Elliott Hughesdcfdd2b2012-07-09 18:27:46 -0700150 HPROF_PRIMITIVE_ARRAY_NODATA_DUMP = 0xc3, // Obsolete.
Elliott Hughes622a6982012-06-08 17:58:54 -0700151};
152
153enum HprofHeapId {
154 HPROF_HEAP_DEFAULT = 0,
155 HPROF_HEAP_ZYGOTE = 'Z',
156 HPROF_HEAP_APP = 'A'
157};
158
159enum HprofBasicType {
160 hprof_basic_object = 2,
161 hprof_basic_boolean = 4,
162 hprof_basic_char = 5,
163 hprof_basic_float = 6,
164 hprof_basic_double = 7,
165 hprof_basic_byte = 8,
166 hprof_basic_short = 9,
167 hprof_basic_int = 10,
168 hprof_basic_long = 11,
169};
170
171typedef uint32_t HprofId;
172typedef HprofId HprofStringId;
173typedef HprofId HprofObjectId;
174typedef HprofId HprofClassObjectId;
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800175typedef std::set<mirror::Class*> ClassSet;
176typedef std::set<mirror::Class*>::iterator ClassSetIterator;
Elliott Hughes622a6982012-06-08 17:58:54 -0700177typedef SafeMap<std::string, size_t> StringMap;
178typedef SafeMap<std::string, size_t>::iterator StringMapIterator;
179
180// Represents a top-level hprof record, whose serialized format is:
181// U1 TAG: denoting the type of the record
182// U4 TIME: number of microseconds since the time stamp in the header
183// U4 LENGTH: number of bytes that follow this uint32_t field and belong to this record
184// U1* BODY: as many bytes as specified in the above uint32_t field
185class HprofRecord {
186 public:
Elliott Hughesdcfdd2b2012-07-09 18:27:46 -0700187 HprofRecord() {
188 dirty_ = false;
189 alloc_length_ = 128;
190 body_ = reinterpret_cast<unsigned char*>(malloc(alloc_length_));
191 fp_ = NULL;
192 }
193
194 ~HprofRecord() {
195 free(body_);
196 }
197
198 int StartNewRecord(FILE* fp, uint8_t tag, uint32_t time) {
199 int rc = Flush();
200 if (rc != 0) {
201 return rc;
202 }
203
204 fp_ = fp;
205 tag_ = tag;
206 time_ = time;
207 length_ = 0;
208 dirty_ = true;
209 return 0;
210 }
211
212 int Flush() {
Elliott Hughes622a6982012-06-08 17:58:54 -0700213 if (dirty_) {
Elliott Hughesa21039c2012-06-21 12:09:25 -0700214 unsigned char headBuf[sizeof(uint8_t) + 2 * sizeof(uint32_t)];
Elliott Hughes622a6982012-06-08 17:58:54 -0700215
216 headBuf[0] = tag_;
217 U4_TO_BUF_BE(headBuf, 1, time_);
218 U4_TO_BUF_BE(headBuf, 5, length_);
219
Elliott Hughesdcfdd2b2012-07-09 18:27:46 -0700220 int nb = fwrite(headBuf, 1, sizeof(headBuf), fp_);
Elliott Hughes622a6982012-06-08 17:58:54 -0700221 if (nb != sizeof(headBuf)) {
222 return UNIQUE_ERROR;
223 }
Elliott Hughesdcfdd2b2012-07-09 18:27:46 -0700224 nb = fwrite(body_, 1, length_, fp_);
Elliott Hughes622a6982012-06-08 17:58:54 -0700225 if (nb != (int)length_) {
226 return UNIQUE_ERROR;
227 }
228
229 dirty_ = false;
230 }
231 // TODO if we used less than half (or whatever) of allocLen, shrink the buffer.
232 return 0;
233 }
234
235 int AddU1(uint8_t value) {
236 int err = GuaranteeRecordAppend(1);
237 if (err != 0) {
238 return err;
239 }
240
241 body_[length_++] = value;
242 return 0;
243 }
244
245 int AddU2(uint16_t value) {
246 return AddU2List(&value, 1);
247 }
248
249 int AddU4(uint32_t value) {
250 return AddU4List(&value, 1);
251 }
252
253 int AddU8(uint64_t value) {
254 return AddU8List(&value, 1);
255 }
256
257 int AddId(HprofObjectId value) {
258 return AddU4((uint32_t) value);
259 }
260
Elliott Hughesdcfdd2b2012-07-09 18:27:46 -0700261 int AddU1List(const uint8_t* values, size_t numValues) {
Elliott Hughes622a6982012-06-08 17:58:54 -0700262 int err = GuaranteeRecordAppend(numValues);
263 if (err != 0) {
264 return err;
265 }
266
267 memcpy(body_ + length_, values, numValues);
268 length_ += numValues;
269 return 0;
270 }
271
Elliott Hughesdcfdd2b2012-07-09 18:27:46 -0700272 int AddU2List(const uint16_t* values, size_t numValues) {
Elliott Hughes622a6982012-06-08 17:58:54 -0700273 int err = GuaranteeRecordAppend(numValues * 2);
274 if (err != 0) {
275 return err;
276 }
277
278 unsigned char* insert = body_ + length_;
Elliott Hughesdcfdd2b2012-07-09 18:27:46 -0700279 for (size_t i = 0; i < numValues; ++i) {
Elliott Hughes622a6982012-06-08 17:58:54 -0700280 U2_TO_BUF_BE(insert, 0, *values++);
281 insert += sizeof(*values);
282 }
283 length_ += numValues * 2;
284 return 0;
285 }
286
Elliott Hughesdcfdd2b2012-07-09 18:27:46 -0700287 int AddU4List(const uint32_t* values, size_t numValues) {
Elliott Hughes622a6982012-06-08 17:58:54 -0700288 int err = GuaranteeRecordAppend(numValues * 4);
289 if (err != 0) {
290 return err;
291 }
292
293 unsigned char* insert = body_ + length_;
Elliott Hughesdcfdd2b2012-07-09 18:27:46 -0700294 for (size_t i = 0; i < numValues; ++i) {
Elliott Hughes622a6982012-06-08 17:58:54 -0700295 U4_TO_BUF_BE(insert, 0, *values++);
296 insert += sizeof(*values);
297 }
298 length_ += numValues * 4;
299 return 0;
300 }
301
Elliott Hughesdcfdd2b2012-07-09 18:27:46 -0700302 void UpdateU4(size_t offset, uint32_t new_value) {
303 U4_TO_BUF_BE(body_, offset, new_value);
304 }
305
306 int AddU8List(const uint64_t* values, size_t numValues) {
Elliott Hughes622a6982012-06-08 17:58:54 -0700307 int err = GuaranteeRecordAppend(numValues * 8);
308 if (err != 0) {
309 return err;
310 }
311
312 unsigned char* insert = body_ + length_;
Elliott Hughesdcfdd2b2012-07-09 18:27:46 -0700313 for (size_t i = 0; i < numValues; ++i) {
Elliott Hughes622a6982012-06-08 17:58:54 -0700314 U8_TO_BUF_BE(insert, 0, *values++);
315 insert += sizeof(*values);
316 }
317 length_ += numValues * 8;
318 return 0;
319 }
320
Elliott Hughesdcfdd2b2012-07-09 18:27:46 -0700321 int AddIdList(const HprofObjectId* values, size_t numValues) {
Elliott Hughes622a6982012-06-08 17:58:54 -0700322 return AddU4List((const uint32_t*) values, numValues);
323 }
324
325 int AddUtf8String(const char* str) {
326 // The terminating NUL character is NOT written.
Elliott Hughesdcfdd2b2012-07-09 18:27:46 -0700327 return AddU1List((const uint8_t*)str, strlen(str));
Elliott Hughes622a6982012-06-08 17:58:54 -0700328 }
329
Elliott Hughesdcfdd2b2012-07-09 18:27:46 -0700330 size_t Size() const {
331 return length_;
332 }
Elliott Hughes622a6982012-06-08 17:58:54 -0700333
334 private:
335 int GuaranteeRecordAppend(size_t nmore) {
336 size_t minSize = length_ + nmore;
337 if (minSize > alloc_length_) {
338 size_t newAllocLen = alloc_length_ * 2;
339 if (newAllocLen < minSize) {
340 newAllocLen = alloc_length_ + nmore + nmore/2;
341 }
342 unsigned char* newBody = (unsigned char*)realloc(body_, newAllocLen);
343 if (newBody != NULL) {
344 body_ = newBody;
345 alloc_length_ = newAllocLen;
346 } else {
347 // TODO: set an error flag so future ops will fail
348 return UNIQUE_ERROR;
349 }
350 }
351
352 CHECK_LE(length_ + nmore, alloc_length_);
353 return 0;
354 }
Elliott Hughesdcfdd2b2012-07-09 18:27:46 -0700355
356 size_t alloc_length_;
357 unsigned char* body_;
358
359 FILE* fp_;
360 uint8_t tag_;
361 uint32_t time_;
362 size_t length_;
363 bool dirty_;
364
365 DISALLOW_COPY_AND_ASSIGN(HprofRecord);
Elliott Hughes622a6982012-06-08 17:58:54 -0700366};
367
368class Hprof {
369 public:
Elliott Hughesdcfdd2b2012-07-09 18:27:46 -0700370 Hprof(const char* output_filename, int fd, bool direct_to_ddms)
371 : filename_(output_filename),
372 fd_(fd),
373 direct_to_ddms_(direct_to_ddms),
374 start_ns_(NanoTime()),
375 current_record_(),
376 gc_thread_serial_number_(0),
377 gc_scan_state_(0),
378 current_heap_(HPROF_HEAP_DEFAULT),
379 objects_in_segment_(0),
380 header_fp_(NULL),
381 header_data_ptr_(NULL),
382 header_data_size_(0),
383 body_fp_(NULL),
384 body_data_ptr_(NULL),
385 body_data_size_(0),
386 next_string_id_(0x400000) {
387 LOG(INFO) << "hprof: heap dump \"" << filename_ << "\" starting...";
Elliott Hughes622a6982012-06-08 17:58:54 -0700388
Elliott Hughesdcfdd2b2012-07-09 18:27:46 -0700389 header_fp_ = open_memstream(&header_data_ptr_, &header_data_size_);
390 if (header_fp_ == NULL) {
391 PLOG(FATAL) << "header open_memstream failed";
392 }
Elliott Hughes622a6982012-06-08 17:58:54 -0700393
Elliott Hughesdcfdd2b2012-07-09 18:27:46 -0700394 body_fp_ = open_memstream(&body_data_ptr_, &body_data_size_);
395 if (body_fp_ == NULL) {
396 PLOG(FATAL) << "body open_memstream failed";
397 }
Jesse Wilson0c54ac12011-11-09 15:14:05 -0500398 }
399
Elliott Hughesdcfdd2b2012-07-09 18:27:46 -0700400 ~Hprof() {
401 if (header_fp_ != NULL) {
402 fclose(header_fp_);
403 }
404 if (body_fp_ != NULL) {
405 fclose(body_fp_);
406 }
407 free(header_data_ptr_);
408 free(body_data_ptr_);
409 }
Jesse Wilson0c54ac12011-11-09 15:14:05 -0500410
Ian Rogers00f7d0e2012-07-19 15:28:27 -0700411 void Dump()
Ian Rogersb726dcb2012-09-05 08:57:23 -0700412 EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_)
413 LOCKS_EXCLUDED(Locks::heap_bitmap_lock_) {
Elliott Hughesdcfdd2b2012-07-09 18:27:46 -0700414 // Walk the roots and the heap.
415 current_record_.StartNewRecord(body_fp_, HPROF_TAG_HEAP_DUMP_SEGMENT, HPROF_TIME);
Ian Rogers1d54e732013-05-02 21:10:01 -0700416 Runtime::Current()->VisitRoots(RootVisitor, this, false, false);
Ian Rogers50b35e22012-10-04 10:09:15 -0700417 Thread* self = Thread::Current();
Ian Rogers00f7d0e2012-07-19 15:28:27 -0700418 {
Ian Rogers50b35e22012-10-04 10:09:15 -0700419 WriterMutexLock mu(self, *Locks::heap_bitmap_lock_);
Mathieu Chartier357e9be2012-08-01 11:00:14 -0700420 Runtime::Current()->GetHeap()->FlushAllocStack();
421 }
422 {
Ian Rogers50b35e22012-10-04 10:09:15 -0700423 ReaderMutexLock mu(self, *Locks::heap_bitmap_lock_);
Ian Rogers00f7d0e2012-07-19 15:28:27 -0700424 Runtime::Current()->GetHeap()->GetLiveBitmap()->Walk(HeapBitmapCallback, this);
425 }
Elliott Hughesdcfdd2b2012-07-09 18:27:46 -0700426 current_record_.StartNewRecord(body_fp_, HPROF_TAG_HEAP_DUMP_END, HPROF_TIME);
427 current_record_.Flush();
428 fflush(body_fp_);
Jesse Wilson0c54ac12011-11-09 15:14:05 -0500429
Elliott Hughesdcfdd2b2012-07-09 18:27:46 -0700430 // Write the header.
431 WriteFixedHeader();
432 // Write the string and class tables, and any stack traces, to the header.
433 // (jhat requires that these appear before any of the data in the body that refers to them.)
434 WriteStringTable();
435 WriteClassTable();
436 WriteStackTraces();
437 current_record_.Flush();
438 fflush(header_fp_);
439
440 bool okay = true;
441 if (direct_to_ddms_) {
442 // Send the data off to DDMS.
443 iovec iov[2];
444 iov[0].iov_base = header_data_ptr_;
445 iov[0].iov_len = header_data_size_;
446 iov[1].iov_base = body_data_ptr_;
447 iov[1].iov_len = body_data_size_;
448 Dbg::DdmSendChunkV(CHUNK_TYPE("HPDS"), iov, 2);
449 } else {
450 // Where exactly are we writing to?
451 int out_fd;
452 if (fd_ >= 0) {
453 out_fd = dup(fd_);
454 if (out_fd < 0) {
Ian Rogers62d6c772013-02-27 08:32:07 -0800455 ThrowRuntimeException("Couldn't dump heap; dup(%d) failed: %s", fd_, strerror(errno));
Elliott Hughesdcfdd2b2012-07-09 18:27:46 -0700456 return;
457 }
458 } else {
459 out_fd = open(filename_.c_str(), O_WRONLY|O_CREAT|O_TRUNC, 0644);
460 if (out_fd < 0) {
Ian Rogers62d6c772013-02-27 08:32:07 -0800461 ThrowRuntimeException("Couldn't dump heap; open(\"%s\") failed: %s", filename_.c_str(),
462 strerror(errno));
Elliott Hughesdcfdd2b2012-07-09 18:27:46 -0700463 return;
464 }
465 }
466
Elliott Hughes76160052012-12-12 16:31:20 -0800467 UniquePtr<File> file(new File(out_fd, filename_));
Ian Rogers50b35e22012-10-04 10:09:15 -0700468 okay = file->WriteFully(header_data_ptr_, header_data_size_) &&
469 file->WriteFully(body_data_ptr_, body_data_size_);
Elliott Hughesdcfdd2b2012-07-09 18:27:46 -0700470 if (!okay) {
Ian Rogers50b35e22012-10-04 10:09:15 -0700471 std::string msg(StringPrintf("Couldn't dump heap; writing \"%s\" failed: %s",
472 filename_.c_str(), strerror(errno)));
Ian Rogers62d6c772013-02-27 08:32:07 -0800473 ThrowRuntimeException("%s", msg.c_str());
Elliott Hughesdcfdd2b2012-07-09 18:27:46 -0700474 LOG(ERROR) << msg;
475 }
Elliott Hughesdcfdd2b2012-07-09 18:27:46 -0700476 }
477
478 // Throw out a log message for the benefit of "runhat".
479 if (okay) {
480 uint64_t duration = NanoTime() - start_ns_;
Ian Rogers50b35e22012-10-04 10:09:15 -0700481 LOG(INFO) << "hprof: heap dump completed ("
482 << PrettySize(header_data_size_ + body_data_size_ + 1023)
483 << ") in " << PrettyDuration(duration);
Elliott Hughesdcfdd2b2012-07-09 18:27:46 -0700484 }
485 }
486
487 private:
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800488 static void RootVisitor(const mirror::Object* obj, void* arg)
Ian Rogersb726dcb2012-09-05 08:57:23 -0700489 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
Elliott Hughesdcfdd2b2012-07-09 18:27:46 -0700490 CHECK(arg != NULL);
491 Hprof* hprof = reinterpret_cast<Hprof*>(arg);
492 hprof->VisitRoot(obj);
493 }
494
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800495 static void HeapBitmapCallback(mirror::Object* obj, void* arg)
Ian Rogersb726dcb2012-09-05 08:57:23 -0700496 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
Elliott Hughesdcfdd2b2012-07-09 18:27:46 -0700497 CHECK(obj != NULL);
498 CHECK(arg != NULL);
499 Hprof* hprof = reinterpret_cast<Hprof*>(arg);
500 hprof->DumpHeapObject(obj);
501 }
502
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800503 void VisitRoot(const mirror::Object* obj) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
Elliott Hughesdcfdd2b2012-07-09 18:27:46 -0700504
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800505 int DumpHeapObject(mirror::Object* obj) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
Elliott Hughesdcfdd2b2012-07-09 18:27:46 -0700506
507 void Finish() {
508 }
509
Ian Rogersb726dcb2012-09-05 08:57:23 -0700510 int WriteClassTable() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
Elliott Hughesdcfdd2b2012-07-09 18:27:46 -0700511 HprofRecord* rec = &current_record_;
512 uint32_t nextSerialNumber = 1;
513
514 for (ClassSetIterator it = classes_.begin(); it != classes_.end(); ++it) {
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800515 const mirror::Class* c = *it;
Elliott Hughesdcfdd2b2012-07-09 18:27:46 -0700516 CHECK(c != NULL);
517
518 int err = current_record_.StartNewRecord(header_fp_, HPROF_TAG_LOAD_CLASS, HPROF_TIME);
519 if (err != 0) {
520 return err;
521 }
522
523 // LOAD CLASS format:
524 // U4: class serial number (always > 0)
525 // ID: class object ID. We use the address of the class object structure as its ID.
526 // U4: stack trace serial number
527 // ID: class name string ID
528 rec->AddU4(nextSerialNumber++);
529 rec->AddId((HprofClassObjectId) c);
530 rec->AddU4(HPROF_NULL_STACK_TRACE);
531 rec->AddId(LookupClassNameId(c));
532 }
533
534 return 0;
535 }
536
537 int WriteStringTable() {
538 HprofRecord* rec = &current_record_;
539
540 for (StringMapIterator it = strings_.begin(); it != strings_.end(); ++it) {
541 std::string string((*it).first);
542 size_t id = (*it).second;
543
544 int err = current_record_.StartNewRecord(header_fp_, HPROF_TAG_STRING, HPROF_TIME);
545 if (err != 0) {
546 return err;
547 }
548
549 // STRING format:
550 // ID: ID for this string
551 // U1*: UTF8 characters for string (NOT NULL terminated)
552 // (the record format encodes the length)
553 err = rec->AddU4(id);
554 if (err != 0) {
555 return err;
556 }
557 err = rec->AddUtf8String(string.c_str());
558 if (err != 0) {
559 return err;
560 }
561 }
562
563 return 0;
564 }
565
566 void StartNewHeapDumpSegment() {
567 // This flushes the old segment and starts a new one.
568 current_record_.StartNewRecord(body_fp_, HPROF_TAG_HEAP_DUMP_SEGMENT, HPROF_TIME);
569 objects_in_segment_ = 0;
570
571 // Starting a new HEAP_DUMP resets the heap to default.
572 current_heap_ = HPROF_HEAP_DEFAULT;
573 }
574
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800575 int MarkRootObject(const mirror::Object* obj, jobject jniObj);
Elliott Hughesdcfdd2b2012-07-09 18:27:46 -0700576
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800577 HprofClassObjectId LookupClassId(mirror::Class* c)
Ian Rogersb726dcb2012-09-05 08:57:23 -0700578 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
Elliott Hughesdcfdd2b2012-07-09 18:27:46 -0700579 if (c == NULL) {
580 // c is the superclass of java.lang.Object or a primitive
581 return (HprofClassObjectId)0;
582 }
583
584 std::pair<ClassSetIterator, bool> result = classes_.insert(c);
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800585 const mirror::Class* present = *result.first;
Elliott Hughesdcfdd2b2012-07-09 18:27:46 -0700586
587 // Make sure that we've assigned a string ID for this class' name
588 LookupClassNameId(c);
589
590 CHECK_EQ(present, c);
591 return (HprofStringId) present;
592 }
593
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800594 HprofStringId LookupStringId(mirror::String* string) {
Elliott Hughesdcfdd2b2012-07-09 18:27:46 -0700595 return LookupStringId(string->ToModifiedUtf8());
596 }
597
598 HprofStringId LookupStringId(const char* string) {
599 return LookupStringId(std::string(string));
600 }
601
602 HprofStringId LookupStringId(const std::string& string) {
603 StringMapIterator it = strings_.find(string);
604 if (it != strings_.end()) {
605 return it->second;
606 }
607 HprofStringId id = next_string_id_++;
608 strings_.Put(string, id);
609 return id;
610 }
611
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800612 HprofStringId LookupClassNameId(const mirror::Class* c)
Ian Rogersb726dcb2012-09-05 08:57:23 -0700613 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
Elliott Hughesdcfdd2b2012-07-09 18:27:46 -0700614 return LookupStringId(PrettyDescriptor(c));
615 }
616
617 void WriteFixedHeader() {
Elliott Hughes622a6982012-06-08 17:58:54 -0700618 char magic[] = "JAVA PROFILE 1.0.3";
Jesse Wilson0c54ac12011-11-09 15:14:05 -0500619 unsigned char buf[4];
620
621 // Write the file header.
622 // U1: NUL-terminated magic string.
Elliott Hughesdcfdd2b2012-07-09 18:27:46 -0700623 fwrite(magic, 1, sizeof(magic), header_fp_);
Jesse Wilson0c54ac12011-11-09 15:14:05 -0500624
625 // U4: size of identifiers. We're using addresses as IDs, so make sure a pointer fits.
Elliott Hughesdcfdd2b2012-07-09 18:27:46 -0700626 U4_TO_BUF_BE(buf, 0, sizeof(void*));
627 fwrite(buf, 1, sizeof(uint32_t), header_fp_);
Jesse Wilson0c54ac12011-11-09 15:14:05 -0500628
629 // The current time, in milliseconds since 0:00 GMT, 1/1/70.
Elliott Hughes7b9d9962012-04-20 18:48:18 -0700630 timeval now;
Jesse Wilson0c54ac12011-11-09 15:14:05 -0500631 uint64_t nowMs;
632 if (gettimeofday(&now, NULL) < 0) {
633 nowMs = 0;
634 } else {
635 nowMs = (uint64_t)now.tv_sec * 1000 + now.tv_usec / 1000;
636 }
637
638 // U4: high word of the 64-bit time.
639 U4_TO_BUF_BE(buf, 0, (uint32_t)(nowMs >> 32));
Elliott Hughesdcfdd2b2012-07-09 18:27:46 -0700640 fwrite(buf, 1, sizeof(uint32_t), header_fp_);
Jesse Wilson0c54ac12011-11-09 15:14:05 -0500641
642 // U4: low word of the 64-bit time.
643 U4_TO_BUF_BE(buf, 0, (uint32_t)(nowMs & 0xffffffffULL));
Elliott Hughesdcfdd2b2012-07-09 18:27:46 -0700644 fwrite(buf, 1, sizeof(uint32_t), header_fp_); //xxx fix the time
Jesse Wilson0c54ac12011-11-09 15:14:05 -0500645 }
646
Elliott Hughesdcfdd2b2012-07-09 18:27:46 -0700647 void WriteStackTraces() {
648 // Write a dummy stack trace record so the analysis tools don't freak out.
649 current_record_.StartNewRecord(header_fp_, HPROF_TAG_STACK_TRACE, HPROF_TIME);
650 current_record_.AddU4(HPROF_NULL_STACK_TRACE);
651 current_record_.AddU4(HPROF_NULL_THREAD);
652 current_record_.AddU4(0); // no frames
653 }
Jesse Wilson0c54ac12011-11-09 15:14:05 -0500654
Elliott Hughesdcfdd2b2012-07-09 18:27:46 -0700655 // If direct_to_ddms_ is set, "filename_" and "fd" will be ignored.
656 // Otherwise, "filename_" must be valid, though if "fd" >= 0 it will
657 // only be used for debug messages.
658 std::string filename_;
659 int fd_;
660 bool direct_to_ddms_;
Jesse Wilson0c54ac12011-11-09 15:14:05 -0500661
Elliott Hughesdcfdd2b2012-07-09 18:27:46 -0700662 uint64_t start_ns_;
663
664 HprofRecord current_record_;
665
666 uint32_t gc_thread_serial_number_;
667 uint8_t gc_scan_state_;
668 HprofHeapId current_heap_; // Which heap we're currently dumping.
669 size_t objects_in_segment_;
670
671 FILE* header_fp_;
672 char* header_data_ptr_;
673 size_t header_data_size_;
674
675 FILE* body_fp_;
676 char* body_data_ptr_;
677 size_t body_data_size_;
678
679 ClassSet classes_;
680 size_t next_string_id_;
681 StringMap strings_;
682
683 DISALLOW_COPY_AND_ASSIGN(Hprof);
684};
Jesse Wilson0c54ac12011-11-09 15:14:05 -0500685
686#define OBJECTS_PER_SEGMENT ((size_t)128)
687#define BYTES_PER_SEGMENT ((size_t)4096)
688
689// The static field-name for the synthetic object generated to account
690// for class static overhead.
691#define STATIC_OVERHEAD_NAME "$staticOverhead"
692// The ID for the synthetic object generated to account for class static overhead.
Elliott Hughese84278b2012-03-22 10:06:53 -0700693#define CLASS_STATICS_ID(c) ((HprofObjectId)(((uint32_t)(c)) | 1))
Jesse Wilson0c54ac12011-11-09 15:14:05 -0500694
Elliott Hughes622a6982012-06-08 17:58:54 -0700695static HprofBasicType SignatureToBasicTypeAndSize(const char* sig, size_t* sizeOut) {
Jesse Wilson0c54ac12011-11-09 15:14:05 -0500696 char c = sig[0];
697 HprofBasicType ret;
698 size_t size;
699
700 switch (c) {
701 case '[':
702 case 'L': ret = hprof_basic_object; size = 4; break;
703 case 'Z': ret = hprof_basic_boolean; size = 1; break;
704 case 'C': ret = hprof_basic_char; size = 2; break;
705 case 'F': ret = hprof_basic_float; size = 4; break;
706 case 'D': ret = hprof_basic_double; size = 8; break;
707 case 'B': ret = hprof_basic_byte; size = 1; break;
708 case 'S': ret = hprof_basic_short; size = 2; break;
709 default: CHECK(false);
710 case 'I': ret = hprof_basic_int; size = 4; break;
711 case 'J': ret = hprof_basic_long; size = 8; break;
712 }
713
714 if (sizeOut != NULL) {
715 *sizeOut = size;
716 }
717
718 return ret;
719}
720
Elliott Hughesdcfdd2b2012-07-09 18:27:46 -0700721static HprofBasicType PrimitiveToBasicTypeAndSize(Primitive::Type prim, size_t* sizeOut) {
Jesse Wilson0c54ac12011-11-09 15:14:05 -0500722 HprofBasicType ret;
723 size_t size;
724
725 switch (prim) {
726 case Primitive::kPrimBoolean: ret = hprof_basic_boolean; size = 1; break;
727 case Primitive::kPrimChar: ret = hprof_basic_char; size = 2; break;
728 case Primitive::kPrimFloat: ret = hprof_basic_float; size = 4; break;
729 case Primitive::kPrimDouble: ret = hprof_basic_double; size = 8; break;
730 case Primitive::kPrimByte: ret = hprof_basic_byte; size = 1; break;
731 case Primitive::kPrimShort: ret = hprof_basic_short; size = 2; break;
732 default: CHECK(false);
733 case Primitive::kPrimInt: ret = hprof_basic_int; size = 4; break;
734 case Primitive::kPrimLong: ret = hprof_basic_long; size = 8; break;
735 }
736
737 if (sizeOut != NULL) {
738 *sizeOut = size;
739 }
740
741 return ret;
742}
743
744// Always called when marking objects, but only does
745// something when ctx->gc_scan_state_ is non-zero, which is usually
746// only true when marking the root set or unreachable
747// objects. Used to add rootset references to obj.
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800748int Hprof::MarkRootObject(const mirror::Object* obj, jobject jniObj) {
Elliott Hughes73e66f72012-05-09 09:34:45 -0700749 HprofRecord* rec = &current_record_;
Jesse Wilson0c54ac12011-11-09 15:14:05 -0500750 HprofHeapTag heapTag = (HprofHeapTag)gc_scan_state_;
751
752 if (heapTag == 0) {
753 return 0;
754 }
755
Elliott Hughesdcfdd2b2012-07-09 18:27:46 -0700756 if (objects_in_segment_ >= OBJECTS_PER_SEGMENT || rec->Size() >= BYTES_PER_SEGMENT) {
757 StartNewHeapDumpSegment();
Jesse Wilson0c54ac12011-11-09 15:14:05 -0500758 }
759
760 switch (heapTag) {
761 // ID: object ID
762 case HPROF_ROOT_UNKNOWN:
763 case HPROF_ROOT_STICKY_CLASS:
764 case HPROF_ROOT_MONITOR_USED:
765 case HPROF_ROOT_INTERNED_STRING:
Jesse Wilson0c54ac12011-11-09 15:14:05 -0500766 case HPROF_ROOT_DEBUGGER:
Jesse Wilson0c54ac12011-11-09 15:14:05 -0500767 case HPROF_ROOT_VM_INTERNAL:
768 rec->AddU1(heapTag);
769 rec->AddId((HprofObjectId)obj);
770 break;
771
772 // ID: object ID
773 // ID: JNI global ref ID
774 case HPROF_ROOT_JNI_GLOBAL:
775 rec->AddU1(heapTag);
776 rec->AddId((HprofObjectId)obj);
777 rec->AddId((HprofId)jniObj);
778 break;
779
780 // ID: object ID
781 // U4: thread serial number
782 // U4: frame number in stack trace (-1 for empty)
783 case HPROF_ROOT_JNI_LOCAL:
784 case HPROF_ROOT_JNI_MONITOR:
785 case HPROF_ROOT_JAVA_FRAME:
786 rec->AddU1(heapTag);
787 rec->AddId((HprofObjectId)obj);
788 rec->AddU4(gc_thread_serial_number_);
789 rec->AddU4((uint32_t)-1);
790 break;
791
792 // ID: object ID
793 // U4: thread serial number
794 case HPROF_ROOT_NATIVE_STACK:
795 case HPROF_ROOT_THREAD_BLOCK:
796 rec->AddU1(heapTag);
797 rec->AddId((HprofObjectId)obj);
798 rec->AddU4(gc_thread_serial_number_);
799 break;
800
801 // ID: thread object ID
802 // U4: thread serial number
803 // U4: stack trace serial number
804 case HPROF_ROOT_THREAD_OBJECT:
805 rec->AddU1(heapTag);
806 rec->AddId((HprofObjectId)obj);
807 rec->AddU4(gc_thread_serial_number_);
808 rec->AddU4((uint32_t)-1); //xxx
809 break;
810
Elliott Hughes73e66f72012-05-09 09:34:45 -0700811 case HPROF_CLASS_DUMP:
812 case HPROF_INSTANCE_DUMP:
813 case HPROF_OBJECT_ARRAY_DUMP:
814 case HPROF_PRIMITIVE_ARRAY_DUMP:
815 case HPROF_HEAP_DUMP_INFO:
816 case HPROF_PRIMITIVE_ARRAY_NODATA_DUMP:
817 // Ignored.
818 break;
819
820 case HPROF_ROOT_FINALIZING:
821 case HPROF_ROOT_REFERENCE_CLEANUP:
822 case HPROF_UNREACHABLE:
823 LOG(FATAL) << "obsolete tag " << static_cast<int>(heapTag);
Jesse Wilson0c54ac12011-11-09 15:14:05 -0500824 break;
825 }
826
Elliott Hughesdcfdd2b2012-07-09 18:27:46 -0700827 ++objects_in_segment_;
Elliott Hughes73e66f72012-05-09 09:34:45 -0700828 return 0;
Jesse Wilson0c54ac12011-11-09 15:14:05 -0500829}
830
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800831static int StackTraceSerialNumber(const mirror::Object* /*obj*/) {
Jesse Wilson0c54ac12011-11-09 15:14:05 -0500832 return HPROF_NULL_STACK_TRACE;
833}
834
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800835int Hprof::DumpHeapObject(mirror::Object* obj) {
Elliott Hughesdcfdd2b2012-07-09 18:27:46 -0700836 HprofRecord* rec = &current_record_;
Jesse Wilson0c54ac12011-11-09 15:14:05 -0500837 HprofHeapId desiredHeap = false ? HPROF_HEAP_ZYGOTE : HPROF_HEAP_APP; // TODO: zygote objects?
838
Elliott Hughesdcfdd2b2012-07-09 18:27:46 -0700839 if (objects_in_segment_ >= OBJECTS_PER_SEGMENT || rec->Size() >= BYTES_PER_SEGMENT) {
840 StartNewHeapDumpSegment();
Jesse Wilson0c54ac12011-11-09 15:14:05 -0500841 }
842
843 if (desiredHeap != current_heap_) {
844 HprofStringId nameId;
845
846 // This object is in a different heap than the current one.
847 // Emit a HEAP_DUMP_INFO tag to change heaps.
848 rec->AddU1(HPROF_HEAP_DUMP_INFO);
849 rec->AddU4((uint32_t)desiredHeap); // uint32_t: heap id
850 switch (desiredHeap) {
851 case HPROF_HEAP_APP:
852 nameId = LookupStringId("app");
853 break;
854 case HPROF_HEAP_ZYGOTE:
855 nameId = LookupStringId("zygote");
856 break;
857 default:
858 // Internal error
859 LOG(ERROR) << "Unexpected desiredHeap";
860 nameId = LookupStringId("<ILLEGAL>");
861 break;
862 }
863 rec->AddId(nameId);
864 current_heap_ = desiredHeap;
865 }
866
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800867 mirror::Class* c = obj->GetClass();
Elliott Hughese84278b2012-03-22 10:06:53 -0700868 if (c == NULL) {
Jesse Wilson0c54ac12011-11-09 15:14:05 -0500869 // This object will bother HprofReader, because it has a NULL
870 // class, so just don't dump it. It could be
871 // gDvm.unlinkedJavaLangClass or it could be an object just
872 // allocated which hasn't been initialized yet.
873 } else {
874 if (obj->IsClass()) {
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800875 mirror::Class* thisClass = obj->AsClass();
Jesse Wilson0c54ac12011-11-09 15:14:05 -0500876 // obj is a ClassObject.
877 size_t sFieldCount = thisClass->NumStaticFields();
878 if (sFieldCount != 0) {
879 int byteLength = sFieldCount*sizeof(JValue); // TODO bogus; fields are packed
880 // Create a byte array to reflect the allocation of the
881 // StaticField array at the end of this class.
882 rec->AddU1(HPROF_PRIMITIVE_ARRAY_DUMP);
883 rec->AddId(CLASS_STATICS_ID(obj));
884 rec->AddU4(StackTraceSerialNumber(obj));
885 rec->AddU4(byteLength);
886 rec->AddU1(hprof_basic_byte);
Elliott Hughesdcfdd2b2012-07-09 18:27:46 -0700887 for (int i = 0; i < byteLength; ++i) {
Jesse Wilson0c54ac12011-11-09 15:14:05 -0500888 rec->AddU1(0);
889 }
890 }
891
892 rec->AddU1(HPROF_CLASS_DUMP);
893 rec->AddId(LookupClassId(thisClass));
894 rec->AddU4(StackTraceSerialNumber(thisClass));
895 rec->AddId(LookupClassId(thisClass->GetSuperClass()));
896 rec->AddId((HprofObjectId)thisClass->GetClassLoader());
897 rec->AddId((HprofObjectId)0); // no signer
898 rec->AddId((HprofObjectId)0); // no prot domain
899 rec->AddId((HprofId)0); // reserved
900 rec->AddId((HprofId)0); // reserved
Elliott Hughesdbb40792011-11-18 17:05:22 -0800901 if (thisClass->IsClassClass()) {
Jesse Wilson0c54ac12011-11-09 15:14:05 -0500902 // ClassObjects have their static fields appended, so aren't all the same size.
903 // But they're at least this size.
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800904 rec->AddU4(sizeof(mirror::Class)); // instance size
Jesse Wilson0c54ac12011-11-09 15:14:05 -0500905 } else if (thisClass->IsArrayClass() || thisClass->IsPrimitive()) {
906 rec->AddU4(0);
907 } else {
908 rec->AddU4(thisClass->GetObjectSize()); // instance size
909 }
910
911 rec->AddU2(0); // empty const pool
912
Ian Rogers6d4d9fc2011-11-30 16:24:48 -0800913 FieldHelper fh;
914
Jesse Wilson0c54ac12011-11-09 15:14:05 -0500915 // Static fields
916 if (sFieldCount == 0) {
917 rec->AddU2((uint16_t)0);
918 } else {
919 rec->AddU2((uint16_t)(sFieldCount+1));
920 rec->AddId(LookupStringId(STATIC_OVERHEAD_NAME));
921 rec->AddU1(hprof_basic_object);
922 rec->AddId(CLASS_STATICS_ID(obj));
923
924 for (size_t i = 0; i < sFieldCount; ++i) {
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800925 mirror::Field* f = thisClass->GetStaticField(i);
Ian Rogers6d4d9fc2011-11-30 16:24:48 -0800926 fh.ChangeField(f);
Jesse Wilson0c54ac12011-11-09 15:14:05 -0500927
928 size_t size;
Ian Rogers6d4d9fc2011-11-30 16:24:48 -0800929 HprofBasicType t = SignatureToBasicTypeAndSize(fh.GetTypeDescriptor(), &size);
930 rec->AddId(LookupStringId(fh.GetName()));
Jesse Wilson0c54ac12011-11-09 15:14:05 -0500931 rec->AddU1(t);
932 if (size == 1) {
Ian Rogersa3b59cb2013-03-19 19:50:20 -0700933 rec->AddU1(static_cast<uint8_t>(f->Get32(thisClass)));
Jesse Wilson0c54ac12011-11-09 15:14:05 -0500934 } else if (size == 2) {
Ian Rogersa3b59cb2013-03-19 19:50:20 -0700935 rec->AddU2(static_cast<uint16_t>(f->Get32(thisClass)));
Jesse Wilson0c54ac12011-11-09 15:14:05 -0500936 } else if (size == 4) {
Ian Rogersa3b59cb2013-03-19 19:50:20 -0700937 rec->AddU4(f->Get32(thisClass));
Jesse Wilson0c54ac12011-11-09 15:14:05 -0500938 } else if (size == 8) {
Ian Rogersa3b59cb2013-03-19 19:50:20 -0700939 rec->AddU8(f->Get64(thisClass));
Jesse Wilson0c54ac12011-11-09 15:14:05 -0500940 } else {
941 CHECK(false);
942 }
943 }
944 }
945
946 // Instance fields for this class (no superclass fields)
947 int iFieldCount = thisClass->IsObjectClass() ? 0 : thisClass->NumInstanceFields();
948 rec->AddU2((uint16_t)iFieldCount);
949 for (int i = 0; i < iFieldCount; ++i) {
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800950 mirror::Field* f = thisClass->GetInstanceField(i);
Ian Rogers6d4d9fc2011-11-30 16:24:48 -0800951 fh.ChangeField(f);
952 HprofBasicType t = SignatureToBasicTypeAndSize(fh.GetTypeDescriptor(), NULL);
953 rec->AddId(LookupStringId(fh.GetName()));
Jesse Wilson0c54ac12011-11-09 15:14:05 -0500954 rec->AddU1(t);
955 }
Elliott Hughese84278b2012-03-22 10:06:53 -0700956 } else if (c->IsArrayClass()) {
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800957 const mirror::Array* aobj = obj->AsArray();
Jesse Wilson0c54ac12011-11-09 15:14:05 -0500958 uint32_t length = aobj->GetLength();
959
960 if (obj->IsObjectArray()) {
961 // obj is an object array.
962 rec->AddU1(HPROF_OBJECT_ARRAY_DUMP);
963
964 rec->AddId((HprofObjectId)obj);
965 rec->AddU4(StackTraceSerialNumber(obj));
966 rec->AddU4(length);
Elliott Hughese84278b2012-03-22 10:06:53 -0700967 rec->AddId(LookupClassId(c));
Jesse Wilson0c54ac12011-11-09 15:14:05 -0500968
969 // Dump the elements, which are always objects or NULL.
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800970 rec->AddIdList((const HprofObjectId*)aobj->GetRawData(sizeof(mirror::Object*)), length);
Jesse Wilson0c54ac12011-11-09 15:14:05 -0500971 } else {
972 size_t size;
Elliott Hughese84278b2012-03-22 10:06:53 -0700973 HprofBasicType t = PrimitiveToBasicTypeAndSize(c->GetComponentType()->GetPrimitiveType(), &size);
Jesse Wilson0c54ac12011-11-09 15:14:05 -0500974
975 // obj is a primitive array.
Jesse Wilson0c54ac12011-11-09 15:14:05 -0500976 rec->AddU1(HPROF_PRIMITIVE_ARRAY_DUMP);
Jesse Wilson0c54ac12011-11-09 15:14:05 -0500977
978 rec->AddId((HprofObjectId)obj);
979 rec->AddU4(StackTraceSerialNumber(obj));
980 rec->AddU4(length);
981 rec->AddU1(t);
982
Jesse Wilson0c54ac12011-11-09 15:14:05 -0500983 // Dump the raw, packed element values.
984 if (size == 1) {
Elliott Hughesdcfdd2b2012-07-09 18:27:46 -0700985 rec->AddU1List((const uint8_t*)aobj->GetRawData(sizeof(uint8_t)), length);
Jesse Wilson0c54ac12011-11-09 15:14:05 -0500986 } else if (size == 2) {
Elliott Hughesdcfdd2b2012-07-09 18:27:46 -0700987 rec->AddU2List((const uint16_t*)(void*)aobj->GetRawData(sizeof(uint16_t)), length);
Jesse Wilson0c54ac12011-11-09 15:14:05 -0500988 } else if (size == 4) {
Elliott Hughesdcfdd2b2012-07-09 18:27:46 -0700989 rec->AddU4List((const uint32_t*)(void*)aobj->GetRawData(sizeof(uint32_t)), length);
Jesse Wilson0c54ac12011-11-09 15:14:05 -0500990 } else if (size == 8) {
Elliott Hughesdcfdd2b2012-07-09 18:27:46 -0700991 rec->AddU8List((const uint64_t*)aobj->GetRawData(sizeof(uint64_t)), length);
Jesse Wilson0c54ac12011-11-09 15:14:05 -0500992 }
Jesse Wilson0c54ac12011-11-09 15:14:05 -0500993 }
994 } else {
Jesse Wilson0c54ac12011-11-09 15:14:05 -0500995 // obj is an instance object.
996 rec->AddU1(HPROF_INSTANCE_DUMP);
997 rec->AddId((HprofObjectId)obj);
998 rec->AddU4(StackTraceSerialNumber(obj));
Elliott Hughese84278b2012-03-22 10:06:53 -0700999 rec->AddId(LookupClassId(c));
Jesse Wilson0c54ac12011-11-09 15:14:05 -05001000
1001 // Reserve some space for the length of the instance data, which we won't
1002 // know until we're done writing it.
Elliott Hughesdcfdd2b2012-07-09 18:27:46 -07001003 size_t size_patch_offset = rec->Size();
Jesse Wilson0c54ac12011-11-09 15:14:05 -05001004 rec->AddU4(0x77777777);
1005
1006 // Write the instance data; fields for this class, followed by super class fields,
1007 // and so on. Don't write the klass or monitor fields of Object.class.
Ian Rogers2dd0e2c2013-01-24 12:42:14 -08001008 const mirror::Class* sclass = c;
Ian Rogers6d4d9fc2011-11-30 16:24:48 -08001009 FieldHelper fh;
Jesse Wilson0c54ac12011-11-09 15:14:05 -05001010 while (!sclass->IsObjectClass()) {
1011 int ifieldCount = sclass->NumInstanceFields();
Elliott Hughesdcfdd2b2012-07-09 18:27:46 -07001012 for (int i = 0; i < ifieldCount; ++i) {
Ian Rogers2dd0e2c2013-01-24 12:42:14 -08001013 mirror::Field* f = sclass->GetInstanceField(i);
Ian Rogers6d4d9fc2011-11-30 16:24:48 -08001014 fh.ChangeField(f);
Jesse Wilson0c54ac12011-11-09 15:14:05 -05001015 size_t size;
Ian Rogers6d4d9fc2011-11-30 16:24:48 -08001016 SignatureToBasicTypeAndSize(fh.GetTypeDescriptor(), &size);
Jesse Wilson0c54ac12011-11-09 15:14:05 -05001017 if (size == 1) {
1018 rec->AddU1(f->Get32(obj));
1019 } else if (size == 2) {
1020 rec->AddU2(f->Get32(obj));
1021 } else if (size == 4) {
1022 rec->AddU4(f->Get32(obj));
1023 } else if (size == 8) {
1024 rec->AddU8(f->Get64(obj));
1025 } else {
1026 CHECK(false);
1027 }
1028 }
1029
1030 sclass = sclass->GetSuperClass();
1031 }
1032
1033 // Patch the instance field length.
Elliott Hughesdcfdd2b2012-07-09 18:27:46 -07001034 rec->UpdateU4(size_patch_offset, rec->Size() - (size_patch_offset + 4));
Jesse Wilson0c54ac12011-11-09 15:14:05 -05001035 }
1036 }
1037
Elliott Hughesdcfdd2b2012-07-09 18:27:46 -07001038 ++objects_in_segment_;
Jesse Wilson0c54ac12011-11-09 15:14:05 -05001039 return 0;
1040}
1041
Ian Rogers2dd0e2c2013-01-24 12:42:14 -08001042void Hprof::VisitRoot(const mirror::Object* obj) {
Jesse Wilson0b075f12011-11-09 10:57:41 -05001043 uint32_t threadId = 0; // TODO
Elliott Hughesdcfdd2b2012-07-09 18:27:46 -07001044 /*RootType*/ size_t type = 0; // TODO
Jesse Wilsonc4824e62011-11-01 14:39:04 -04001045
Jesse Wilson0b075f12011-11-09 10:57:41 -05001046 static const HprofHeapTag xlate[] = {
1047 HPROF_ROOT_UNKNOWN,
1048 HPROF_ROOT_JNI_GLOBAL,
1049 HPROF_ROOT_JNI_LOCAL,
1050 HPROF_ROOT_JAVA_FRAME,
1051 HPROF_ROOT_NATIVE_STACK,
1052 HPROF_ROOT_STICKY_CLASS,
1053 HPROF_ROOT_THREAD_BLOCK,
1054 HPROF_ROOT_MONITOR_USED,
1055 HPROF_ROOT_THREAD_OBJECT,
1056 HPROF_ROOT_INTERNED_STRING,
1057 HPROF_ROOT_FINALIZING,
1058 HPROF_ROOT_DEBUGGER,
1059 HPROF_ROOT_REFERENCE_CLEANUP,
1060 HPROF_ROOT_VM_INTERNAL,
1061 HPROF_ROOT_JNI_MONITOR,
1062 };
Jesse Wilsonc4824e62011-11-01 14:39:04 -04001063
Jesse Wilson0b075f12011-11-09 10:57:41 -05001064 CHECK_LT(type, sizeof(xlate) / sizeof(HprofHeapTag));
1065 if (obj == NULL) {
1066 return;
1067 }
1068 gc_scan_state_ = xlate[type];
1069 gc_thread_serial_number_ = threadId;
1070 MarkRootObject(obj, 0);
1071 gc_scan_state_ = 0;
1072 gc_thread_serial_number_ = 0;
Jesse Wilsonc4824e62011-11-01 14:39:04 -04001073}
1074
Elliott Hughesdcfdd2b2012-07-09 18:27:46 -07001075// If "direct_to_ddms" is true, the other arguments are ignored, and data is
1076// sent directly to DDMS.
1077// If "fd" is >= 0, the output will be written to that file descriptor.
1078// Otherwise, "filename" is used to create an output file.
1079void DumpHeap(const char* filename, int fd, bool direct_to_ddms) {
1080 CHECK(filename != NULL);
Jesse Wilsonc4824e62011-11-01 14:39:04 -04001081
Ian Rogers00f7d0e2012-07-19 15:28:27 -07001082 Runtime::Current()->GetThreadList()->SuspendAll();
Elliott Hughesdcfdd2b2012-07-09 18:27:46 -07001083 Hprof hprof(filename, fd, direct_to_ddms);
1084 hprof.Dump();
Ian Rogers00f7d0e2012-07-19 15:28:27 -07001085 Runtime::Current()->GetThreadList()->ResumeAll();
Jesse Wilsonc4824e62011-11-01 14:39:04 -04001086}
1087
1088} // namespace hprof
1089
1090} // namespace art