diff options
| author | 2011-11-09 10:57:41 -0500 | |
|---|---|---|
| committer | 2011-11-09 10:57:41 -0500 | |
| commit | 0b075f18e69959f5afbe6d815a766df082ec99df (patch) | |
| tree | d984a8ca66e45d7522eadd191dc1e4d0962dabcc | |
| parent | 3aa66fd01a2b5ddbb895dd0af983cb2b700fbdc3 (diff) | |
Adjust whitespace in hprof.
Change-Id: Ia84f3a13fa240e05fbd701bac64f5a2e95c6a97c
| -rw-r--r-- | src/hprof/hprof.cc | 291 | ||||
| -rw-r--r-- | src/hprof/hprof.h | 253 | ||||
| -rw-r--r-- | src/hprof/hprof_class.cc | 78 | ||||
| -rw-r--r-- | src/hprof/hprof_heap.cc | 342 | ||||
| -rw-r--r-- | src/hprof/hprof_output.cc | 376 | ||||
| -rw-r--r-- | src/hprof/hprof_string.cc | 62 |
6 files changed, 643 insertions, 759 deletions
diff --git a/src/hprof/hprof.cc b/src/hprof/hprof.cc index e2853079c2..d00f6f968a 100644 --- a/src/hprof/hprof.cc +++ b/src/hprof/hprof.cc @@ -44,168 +44,158 @@ namespace hprof { #define kHeadSuffix "-hptemp" // TODO: use File::WriteFully -int sysWriteFully(int fd, const void* buf, size_t count, const char* logMsg) -{ - while (count != 0) { - ssize_t actual = TEMP_FAILURE_RETRY(write(fd, buf, count)); - if (actual < 0) { - int err = errno; - LOG(ERROR) << StringPrintf("%s: write failed: %s", logMsg, strerror(err)); - return err; - } else if (actual != (ssize_t) count) { - LOG(DEBUG) << StringPrintf("%s: partial write (will retry): (%d of %zd)", - logMsg, (int) actual, count); - buf = (const void*) (((const uint8_t*) buf) + actual); - } - count -= actual; +int sysWriteFully(int fd, const void* buf, size_t count, const char* logMsg) { + while (count != 0) { + ssize_t actual = TEMP_FAILURE_RETRY(write(fd, buf, count)); + if (actual < 0) { + int err = errno; + LOG(ERROR) << StringPrintf("%s: write failed: %s", logMsg, strerror(err)); + return err; + } else if (actual != (ssize_t) count) { + LOG(DEBUG) << StringPrintf("%s: partial write (will retry): (%d of %zd)", + logMsg, (int) actual, count); + buf = (const void*) (((const uint8_t*) buf) + actual); } - - return 0; + count -= actual; + } + return 0; } /* * Finish up the hprof dump. Returns true on success. */ -bool Hprof::Finish() -{ - /* flush the "tail" portion of the output */ - StartNewRecord(HPROF_TAG_HEAP_DUMP_END, HPROF_TIME); - FlushCurrentRecord(); - - // Create a new Hprof for the start of the file (as opposed to this, which is the tail). - Hprof headCtx(file_name_, fd_, true, direct_to_ddms_); - headCtx.classes_ = classes_; - headCtx.strings_ = strings_; - - LOG(INFO) << StringPrintf("hprof: dumping heap strings to \"%s\".", file_name_); - headCtx.DumpStrings(); - headCtx.DumpClasses(); - - /* Write a dummy stack trace record so the analysis - * tools don't freak out. - */ - headCtx.StartNewRecord(HPROF_TAG_STACK_TRACE, HPROF_TIME); - headCtx.current_record_.AddU4(HPROF_NULL_STACK_TRACE); - headCtx.current_record_.AddU4(HPROF_NULL_THREAD); - headCtx.current_record_.AddU4(0); // no frames - - headCtx.FlushCurrentRecord(); - - /* flush to ensure memstream pointer and size are updated */ - fflush(headCtx.mem_fp_); - fflush(mem_fp_); - - if (direct_to_ddms_) { - /* send the data off to DDMS */ - struct iovec iov[2]; - iov[0].iov_base = headCtx.file_data_ptr_; - iov[0].iov_len = headCtx.file_data_size_; - iov[1].iov_base = file_data_ptr_; - iov[1].iov_len = file_data_size_; - Dbg::DdmSendChunkV(CHUNK_TYPE("HPDS"), iov, 2); +bool Hprof::Finish() { + // flush the "tail" portion of the output + StartNewRecord(HPROF_TAG_HEAP_DUMP_END, HPROF_TIME); + FlushCurrentRecord(); + + // create a new Hprof for the start of the file (as opposed to this, which is the tail) + Hprof headCtx(file_name_, fd_, true, direct_to_ddms_); + headCtx.classes_ = classes_; + headCtx.strings_ = strings_; + + LOG(INFO) << StringPrintf("hprof: dumping heap strings to \"%s\".", file_name_); + headCtx.DumpStrings(); + headCtx.DumpClasses(); + + // write a dummy stack trace record so the analysis tools don't freak out + headCtx.StartNewRecord(HPROF_TAG_STACK_TRACE, HPROF_TIME); + headCtx.current_record_.AddU4(HPROF_NULL_STACK_TRACE); + headCtx.current_record_.AddU4(HPROF_NULL_THREAD); + headCtx.current_record_.AddU4(0); // no frames + + headCtx.FlushCurrentRecord(); + + // flush to ensure memstream pointer and size are updated + fflush(headCtx.mem_fp_); + fflush(mem_fp_); + + if (direct_to_ddms_) { + // send the data off to DDMS + struct iovec iov[2]; + iov[0].iov_base = headCtx.file_data_ptr_; + iov[0].iov_len = headCtx.file_data_size_; + iov[1].iov_base = file_data_ptr_; + iov[1].iov_len = file_data_size_; + Dbg::DdmSendChunkV(CHUNK_TYPE("HPDS"), iov, 2); + } else { + // open the output file, and copy the head and tail to it. + CHECK_EQ(headCtx.fd_, fd_); + + int outFd; + if (headCtx.fd_ >= 0) { + outFd = dup(headCtx.fd_); + if (outFd < 0) { + LOG(ERROR) << StringPrintf("dup(%d) failed: %s", headCtx.fd_, strerror(errno)); + // continue to fail-handler below + } } else { - /* - * Open the output file, and copy the head and tail to it. - */ - CHECK_EQ(headCtx.fd_, fd_); - - int outFd; - if (headCtx.fd_ >= 0) { - outFd = dup(headCtx.fd_); - if (outFd < 0) { - LOG(ERROR) << StringPrintf("dup(%d) failed: %s", headCtx.fd_, strerror(errno)); - /* continue to fail-handler below */ - } - } else { - outFd = open(file_name_, O_WRONLY|O_CREAT|O_TRUNC, 0644); - if (outFd < 0) { - LOG(ERROR) << StringPrintf("can't open %s: %s", headCtx.file_name_, strerror(errno)); - /* continue to fail-handler below */ - } - } - if (outFd < 0) { - return false; - } - - int result = sysWriteFully(outFd, headCtx.file_data_ptr_, - headCtx.file_data_size_, "hprof-head"); - result |= sysWriteFully(outFd, file_data_ptr_, file_data_size_, "hprof-tail"); - close(outFd); - if (result != 0) { - return false; - } + outFd = open(file_name_, O_WRONLY|O_CREAT|O_TRUNC, 0644); + if (outFd < 0) { + LOG(ERROR) << StringPrintf("can't open %s: %s", headCtx.file_name_, strerror(errno)); + // continue to fail-handler below + } + } + if (outFd < 0) { + return false; + } + + int result = sysWriteFully(outFd, headCtx.file_data_ptr_, + headCtx.file_data_size_, "hprof-head"); + result |= sysWriteFully(outFd, file_data_ptr_, file_data_size_, "hprof-tail"); + close(outFd); + if (result != 0) { + return false; } + } - /* throw out a log message for the benefit of "runhat" */ - LOG(INFO) << StringPrintf("hprof: heap dump completed (%dKB)", - (headCtx.file_data_size_ + file_data_size_ + 1023) / 1024); + // throw out a log message for the benefit of "runhat" + LOG(INFO) << StringPrintf("hprof: heap dump completed (%dKB)", + (headCtx.file_data_size_ + file_data_size_ + 1023) / 1024); - return true; + return true; } Hprof::~Hprof() { - /* we don't own ctx->fd_, do not close */ - - if (mem_fp_ != NULL) { - fclose(mem_fp_); - } - free(current_record_.body_); - free(file_name_); - free(file_data_ptr_); + // we don't own ctx->fd_, do not close + if (mem_fp_ != NULL) { + fclose(mem_fp_); + } + free(current_record_.body_); + free(file_name_); + free(file_data_ptr_); } /* * Visitor invoked on every root reference. */ void HprofRootVisitor(const Object* obj, void* arg) { - CHECK(arg != NULL); - Hprof* hprof = (Hprof*)arg; - hprof->VisitRoot(obj); + CHECK(arg != NULL); + Hprof* hprof = (Hprof*)arg; + hprof->VisitRoot(obj); } void Hprof::VisitRoot(const Object* obj) { - uint32_t threadId = 0; // TODO - /*RootType */ size_t type = 0; // TODO - - static const HprofHeapTag xlate[] = { - HPROF_ROOT_UNKNOWN, - HPROF_ROOT_JNI_GLOBAL, - HPROF_ROOT_JNI_LOCAL, - HPROF_ROOT_JAVA_FRAME, - HPROF_ROOT_NATIVE_STACK, - HPROF_ROOT_STICKY_CLASS, - HPROF_ROOT_THREAD_BLOCK, - HPROF_ROOT_MONITOR_USED, - HPROF_ROOT_THREAD_OBJECT, - HPROF_ROOT_INTERNED_STRING, - HPROF_ROOT_FINALIZING, - HPROF_ROOT_DEBUGGER, - HPROF_ROOT_REFERENCE_CLEANUP, - HPROF_ROOT_VM_INTERNAL, - HPROF_ROOT_JNI_MONITOR, - }; - - CHECK_LT(type, sizeof(xlate) / sizeof(HprofHeapTag)); - if (obj == NULL) { - return; - } - gc_scan_state_ = xlate[type]; - gc_thread_serial_number_ = threadId; - MarkRootObject(obj, 0); - gc_scan_state_ = 0; - gc_thread_serial_number_ = 0; + uint32_t threadId = 0; // TODO + /*RootType */ size_t type = 0; // TODO + + static const HprofHeapTag xlate[] = { + HPROF_ROOT_UNKNOWN, + HPROF_ROOT_JNI_GLOBAL, + HPROF_ROOT_JNI_LOCAL, + HPROF_ROOT_JAVA_FRAME, + HPROF_ROOT_NATIVE_STACK, + HPROF_ROOT_STICKY_CLASS, + HPROF_ROOT_THREAD_BLOCK, + HPROF_ROOT_MONITOR_USED, + HPROF_ROOT_THREAD_OBJECT, + HPROF_ROOT_INTERNED_STRING, + HPROF_ROOT_FINALIZING, + HPROF_ROOT_DEBUGGER, + HPROF_ROOT_REFERENCE_CLEANUP, + HPROF_ROOT_VM_INTERNAL, + HPROF_ROOT_JNI_MONITOR, + }; + + CHECK_LT(type, sizeof(xlate) / sizeof(HprofHeapTag)); + if (obj == NULL) { + return; + } + gc_scan_state_ = xlate[type]; + gc_thread_serial_number_ = threadId; + MarkRootObject(obj, 0); + gc_scan_state_ = 0; + gc_thread_serial_number_ = 0; } /* * Visitor invoked on every heap object. */ - -static void HprofBitmapCallback(Object *obj, void *arg) -{ - CHECK(obj != NULL); - CHECK(arg != NULL); - Hprof *hprof = (Hprof*)arg; - hprof->DumpHeapObject(obj); +static void HprofBitmapCallback(Object *obj, void *arg) { + CHECK(obj != NULL); + CHECK(arg != NULL); + Hprof *hprof = (Hprof*)arg; + hprof->DumpHeapObject(obj); } /* @@ -220,22 +210,21 @@ static void HprofBitmapCallback(Object *obj, void *arg) * * Returns 0 on success, or an error code on failure. */ -int DumpHeap(const char* fileName, int fd, bool directToDdms) -{ - CHECK(fileName != NULL); - ScopedHeapLock lock; - ScopedThreadStateChange tsc(Thread::Current(), Thread::kRunnable); - - ThreadList* thread_list = Runtime::Current()->GetThreadList(); - thread_list->SuspendAll(); - - Hprof hprof(fileName, fd, false, directToDdms); - Runtime::Current()->VisitRoots(HprofRootVisitor, &hprof); - Heap::GetLiveBits()->Walk(HprofBitmapCallback, &hprof); -//TODO: write a HEAP_SUMMARY record - int success = hprof.Finish() ? 0 : -1; - thread_list->ResumeAll(); - return success; +int DumpHeap(const char* fileName, int fd, bool directToDdms) { + CHECK(fileName != NULL); + ScopedHeapLock lock; + ScopedThreadStateChange tsc(Thread::Current(), Thread::kRunnable); + + ThreadList* thread_list = Runtime::Current()->GetThreadList(); + thread_list->SuspendAll(); + + Hprof hprof(fileName, fd, false, directToDdms); + Runtime::Current()->VisitRoots(HprofRootVisitor, &hprof); + Heap::GetLiveBits()->Walk(HprofBitmapCallback, &hprof); + // TODO: write a HEAP_SUMMARY record + int success = hprof.Finish() ? 0 : -1; + thread_list->ResumeAll(); + return success; } } // namespace hprof diff --git a/src/hprof/hprof.h b/src/hprof/hprof.h index 94852bcc6d..38520cc221 100644 --- a/src/hprof/hprof.h +++ b/src/hprof/hprof.h @@ -46,153 +46,142 @@ typedef std::tr1::unordered_map<std::string, size_t> StringMap; typedef std::tr1::unordered_map<std::string, size_t>::iterator StringMapIterator; enum HprofBasicType { - hprof_basic_object = 2, - hprof_basic_boolean = 4, - hprof_basic_char = 5, - hprof_basic_float = 6, - hprof_basic_double = 7, - hprof_basic_byte = 8, - hprof_basic_short = 9, - hprof_basic_int = 10, - hprof_basic_long = 11, + hprof_basic_object = 2, + hprof_basic_boolean = 4, + hprof_basic_char = 5, + hprof_basic_float = 6, + hprof_basic_double = 7, + hprof_basic_byte = 8, + hprof_basic_short = 9, + hprof_basic_int = 10, + hprof_basic_long = 11, }; enum HprofTag { - HPROF_TAG_STRING = 0x01, - HPROF_TAG_LOAD_CLASS = 0x02, - HPROF_TAG_UNLOAD_CLASS = 0x03, - HPROF_TAG_STACK_FRAME = 0x04, - HPROF_TAG_STACK_TRACE = 0x05, - HPROF_TAG_ALLOC_SITES = 0x06, - HPROF_TAG_HEAP_SUMMARY = 0x07, - HPROF_TAG_START_THREAD = 0x0A, - HPROF_TAG_END_THREAD = 0x0B, - HPROF_TAG_HEAP_DUMP = 0x0C, - HPROF_TAG_HEAP_DUMP_SEGMENT = 0x1C, - HPROF_TAG_HEAP_DUMP_END = 0x2C, - HPROF_TAG_CPU_SAMPLES = 0x0D, - HPROF_TAG_CONTROL_SETTINGS = 0x0E, + HPROF_TAG_STRING = 0x01, + HPROF_TAG_LOAD_CLASS = 0x02, + HPROF_TAG_UNLOAD_CLASS = 0x03, + HPROF_TAG_STACK_FRAME = 0x04, + HPROF_TAG_STACK_TRACE = 0x05, + HPROF_TAG_ALLOC_SITES = 0x06, + HPROF_TAG_HEAP_SUMMARY = 0x07, + HPROF_TAG_START_THREAD = 0x0A, + HPROF_TAG_END_THREAD = 0x0B, + HPROF_TAG_HEAP_DUMP = 0x0C, + HPROF_TAG_HEAP_DUMP_SEGMENT = 0x1C, + HPROF_TAG_HEAP_DUMP_END = 0x2C, + HPROF_TAG_CPU_SAMPLES = 0x0D, + HPROF_TAG_CONTROL_SETTINGS = 0x0E, }; -/* Values for the first byte of - * HEAP_DUMP and HEAP_DUMP_SEGMENT - * records: - */ +// Values for the first byte of HEAP_DUMP and HEAP_DUMP_SEGMENT records: enum HprofHeapTag { - /* standard */ - HPROF_ROOT_UNKNOWN = 0xFF, - HPROF_ROOT_JNI_GLOBAL = 0x01, - HPROF_ROOT_JNI_LOCAL = 0x02, - HPROF_ROOT_JAVA_FRAME = 0x03, - HPROF_ROOT_NATIVE_STACK = 0x04, - HPROF_ROOT_STICKY_CLASS = 0x05, - HPROF_ROOT_THREAD_BLOCK = 0x06, - HPROF_ROOT_MONITOR_USED = 0x07, - HPROF_ROOT_THREAD_OBJECT = 0x08, - HPROF_CLASS_DUMP = 0x20, - HPROF_INSTANCE_DUMP = 0x21, - HPROF_OBJECT_ARRAY_DUMP = 0x22, - HPROF_PRIMITIVE_ARRAY_DUMP = 0x23, - - /* Android */ - HPROF_HEAP_DUMP_INFO = 0xfe, - HPROF_ROOT_INTERNED_STRING = 0x89, - HPROF_ROOT_FINALIZING = 0x8a, /* obsolete */ - HPROF_ROOT_DEBUGGER = 0x8b, - HPROF_ROOT_REFERENCE_CLEANUP = 0x8c, /* obsolete */ - HPROF_ROOT_VM_INTERNAL = 0x8d, - HPROF_ROOT_JNI_MONITOR = 0x8e, - HPROF_UNREACHABLE = 0x90, /* obsolete */ - HPROF_PRIMITIVE_ARRAY_NODATA_DUMP = 0xc3, + /* standard */ + HPROF_ROOT_UNKNOWN = 0xFF, + HPROF_ROOT_JNI_GLOBAL = 0x01, + HPROF_ROOT_JNI_LOCAL = 0x02, + HPROF_ROOT_JAVA_FRAME = 0x03, + HPROF_ROOT_NATIVE_STACK = 0x04, + HPROF_ROOT_STICKY_CLASS = 0x05, + HPROF_ROOT_THREAD_BLOCK = 0x06, + HPROF_ROOT_MONITOR_USED = 0x07, + HPROF_ROOT_THREAD_OBJECT = 0x08, + HPROF_CLASS_DUMP = 0x20, + HPROF_INSTANCE_DUMP = 0x21, + HPROF_OBJECT_ARRAY_DUMP = 0x22, + HPROF_PRIMITIVE_ARRAY_DUMP = 0x23, + + /* Android */ + HPROF_HEAP_DUMP_INFO = 0xfe, + HPROF_ROOT_INTERNED_STRING = 0x89, + HPROF_ROOT_FINALIZING = 0x8a, /* obsolete */ + HPROF_ROOT_DEBUGGER = 0x8b, + HPROF_ROOT_REFERENCE_CLEANUP = 0x8c, /* obsolete */ + HPROF_ROOT_VM_INTERNAL = 0x8d, + HPROF_ROOT_JNI_MONITOR = 0x8e, + HPROF_UNREACHABLE = 0x90, /* obsolete */ + HPROF_PRIMITIVE_ARRAY_NODATA_DUMP = 0xc3, }; -/* Represents a top-level hprof record, whose serialized - * format is: - * - * uint8_t TAG: denoting the type of the record - * uint32_t TIME: number of microseconds since the time stamp in the header - * uint32_t LENGTH: number of bytes that follow this uint32_t field - * and belong to this record - * [uint8_t]* BODY: as many bytes as specified in the above uint32_t field - */ +// Represents a top-level hprof record, whose serialized format is: +// U1 TAG: denoting the type of the record +// U4 TIME: number of microseconds since the time stamp in the header +// U4 LENGTH: number of bytes that follow this uint32_t field and belong to this record +// U1* BODY: as many bytes as specified in the above uint32_t field class HprofRecord { - public: - int Flush(FILE *fp); - int AddU1(uint8_t value); - int AddU2(uint16_t value); - int AddU4(uint32_t value); - int AddU8(uint64_t value); - int AddId(HprofObjectId value); - int AddU1List(const uint8_t *values, size_t numValues); - int AddU2List(const uint16_t *values, size_t numValues); - int AddU4List(const uint32_t *values, size_t numValues); - int AddU8List(const uint64_t *values, size_t numValues); - int AddIdList(const HprofObjectId *values, size_t numValues); - int AddUtf8String(const char *str); - - unsigned char *body_; - uint32_t time_; - uint32_t length_; - size_t alloc_length_; - uint8_t tag_; - bool dirty_; + public: + int Flush(FILE *fp); + int AddU1(uint8_t value); + int AddU2(uint16_t value); + int AddU4(uint32_t value); + int AddU8(uint64_t value); + int AddId(HprofObjectId value); + int AddU1List(const uint8_t *values, size_t numValues); + int AddU2List(const uint16_t *values, size_t numValues); + int AddU4List(const uint32_t *values, size_t numValues); + int AddU8List(const uint64_t *values, size_t numValues); + int AddIdList(const HprofObjectId *values, size_t numValues); + int AddUtf8String(const char *str); + + unsigned char *body_; + uint32_t time_; + uint32_t length_; + size_t alloc_length_; + uint8_t tag_; + bool dirty_; }; enum HprofHeapId { - HPROF_HEAP_DEFAULT = 0, - HPROF_HEAP_ZYGOTE = 'Z', - HPROF_HEAP_APP = 'A' + HPROF_HEAP_DEFAULT = 0, + HPROF_HEAP_ZYGOTE = 'Z', + HPROF_HEAP_APP = 'A' }; class Hprof { - public: - Hprof(const char *outputFileName, int fd, bool writeHeader, bool directToDdms); - ~Hprof(); - - void VisitRoot(const Object* obj); - int DumpHeapObject(const Object *obj); - bool Finish(); - - private: - int DumpClasses(); - int DumpStrings(); - int StartNewRecord(uint8_t tag, uint32_t time); - int FlushCurrentRecord(); - int MarkRootObject(const Object *obj, jobject jniObj); - HprofClassObjectId LookupClassId(Class* clazz); - HprofStringId LookupStringId(String* string); - HprofStringId LookupStringId(const char* string); - HprofStringId LookupStringId(std::string string); - HprofStringId LookupClassNameId(Class* clazz); - - /* current_record_ *must* be first so that we - * can cast from a context to a record. - */ - HprofRecord current_record_; - - uint32_t gc_thread_serial_number_; - uint8_t gc_scan_state_; - HprofHeapId current_heap_; // which heap we're currently emitting - size_t objects_in_segment_; - - /* - * If direct_to_ddms_ is set, "file_name_" and "fd" will be ignored. - * Otherwise, "file_name_" must be valid, though if "fd" >= 0 it will - * only be used for debug messages. - */ - bool direct_to_ddms_; - char *file_name_; - char *file_data_ptr_; // for open_memstream - size_t file_data_size_; // for open_memstream - FILE *mem_fp_; - int fd_; - - mutable Mutex classes_lock_; - ClassSet classes_; - - size_t next_string_id_; - mutable Mutex strings_lock_; - StringMap strings_; + public: + Hprof(const char *outputFileName, int fd, bool writeHeader, bool directToDdms); + ~Hprof(); + + void VisitRoot(const Object* obj); + int DumpHeapObject(const Object *obj); + bool Finish(); + + private: + int DumpClasses(); + int DumpStrings(); + int StartNewRecord(uint8_t tag, uint32_t time); + int FlushCurrentRecord(); + int MarkRootObject(const Object *obj, jobject jniObj); + HprofClassObjectId LookupClassId(Class* clazz); + HprofStringId LookupStringId(String* string); + HprofStringId LookupStringId(const char* string); + HprofStringId LookupStringId(std::string string); + HprofStringId LookupClassNameId(Class* clazz); + + // current_record_ *must* be first so that we can cast from a context to a record. + HprofRecord current_record_; + + uint32_t gc_thread_serial_number_; + uint8_t gc_scan_state_; + HprofHeapId current_heap_; // which heap we're currently emitting + size_t objects_in_segment_; + + // If direct_to_ddms_ is set, "file_name_" and "fd" will be ignored. + // Otherwise, "file_name_" must be valid, though if "fd" >= 0 it will + // only be used for debug messages. + bool direct_to_ddms_; + char *file_name_; + char *file_data_ptr_; // for open_memstream + size_t file_data_size_; // for open_memstream + FILE *mem_fp_; + int fd_; + + mutable Mutex classes_lock_; + ClassSet classes_; + + size_t next_string_id_; + mutable Mutex strings_lock_; + StringMap strings_; }; int DumpHeap(const char* fileName, int fd, bool directToDdms); diff --git a/src/hprof/hprof_class.cc b/src/hprof/hprof_class.cc index ebedc2d200..4286d29467 100644 --- a/src/hprof/hprof_class.cc +++ b/src/hprof/hprof_class.cc @@ -27,61 +27,53 @@ namespace art { namespace hprof { HprofStringId Hprof::LookupClassNameId(Class* clazz) { - return LookupStringId(PrettyDescriptor(clazz->GetDescriptor())); + return LookupStringId(PrettyDescriptor(clazz->GetDescriptor())); } HprofClassObjectId Hprof::LookupClassId(Class* clazz) { - if (clazz == NULL) { - /* Someone's probably looking up the superclass - * of java.lang.Object or of a primitive class. - */ - return (HprofClassObjectId)0; - } + if (clazz == NULL) { + // clazz is the superclass of java.lang.Object or a primitive + return (HprofClassObjectId)0; + } - MutexLock mu(classes_lock_); + MutexLock mu(classes_lock_); - std::pair<ClassSetIterator, bool> result = classes_.insert(clazz); - Class* present = *result.first; + std::pair<ClassSetIterator, bool> result = classes_.insert(clazz); + Class* present = *result.first; - // Make sure that we've assigned a string ID for this class' name - LookupClassNameId(clazz); + // Make sure that we've assigned a string ID for this class' name + LookupClassNameId(clazz); - CHECK_EQ(present, clazz); - return (HprofStringId) present; + CHECK_EQ(present, clazz); + return (HprofStringId) present; } int Hprof::DumpClasses() { - MutexLock mu(classes_lock_); - - HprofRecord *rec = ¤t_record_; - - uint32_t nextSerialNumber = 1; - - for (ClassSetIterator it = classes_.begin(); it != classes_.end(); ++it) { - Class* clazz = *it; - CHECK(clazz != NULL); - - int err = StartNewRecord(HPROF_TAG_LOAD_CLASS, HPROF_TIME); - if (err != 0) { - return err; - } - - /* LOAD CLASS format: - * - * uint32_t: class serial number (always > 0) - * ID: class object ID - * uint32_t: stack trace serial number - * ID: class name string ID - * - * We use the address of the class object structure as its ID. - */ - rec->AddU4(nextSerialNumber++); - rec->AddId((HprofClassObjectId) clazz); - rec->AddU4(HPROF_NULL_STACK_TRACE); - rec->AddId(LookupClassNameId(clazz)); + MutexLock mu(classes_lock_); + HprofRecord *rec = ¤t_record_; + uint32_t nextSerialNumber = 1; + + for (ClassSetIterator it = classes_.begin(); it != classes_.end(); ++it) { + Class* clazz = *it; + CHECK(clazz != NULL); + + int err = StartNewRecord(HPROF_TAG_LOAD_CLASS, HPROF_TIME); + if (err != 0) { + return err; } - return 0; + // LOAD CLASS format: + // U4: class serial number (always > 0) + // ID: class object ID. We use the address of the class object structure as its ID. + // U4: stack trace serial number + // ID: class name string ID + rec->AddU4(nextSerialNumber++); + rec->AddId((HprofClassObjectId) clazz); + rec->AddU4(HPROF_NULL_STACK_TRACE); + rec->AddId(LookupClassNameId(clazz)); + } + + return 0; } } // namespace hprof diff --git a/src/hprof/hprof_heap.cc b/src/hprof/hprof_heap.cc index 84168e3e81..0b63e65b6a 100644 --- a/src/hprof/hprof_heap.cc +++ b/src/hprof/hprof_heap.cc @@ -25,192 +25,172 @@ namespace art { namespace hprof { -/* Set DUMP_PRIM_DATA to 1 if you want to include the contents - * of primitive arrays (byte arrays, character arrays, etc.) - * in heap dumps. This can be a large amount of data. - */ +// Set DUMP_PRIM_DATA to 1 if you want to include the contents +// of primitive arrays (byte arrays, character arrays, etc.) +// in heap dumps. This can be a large amount of data. #define DUMP_PRIM_DATA 1 #define OBJECTS_PER_SEGMENT ((size_t)128) #define BYTES_PER_SEGMENT ((size_t)4096) -/* The static field-name for the synthetic object generated to account - * for class Static overhead. - */ +// The static field-name for the synthetic object generated to account +// for class static overhead. #define STATIC_OVERHEAD_NAME "$staticOverhead" -/* The ID for the synthetic object generated to account for class - * Static overhead. - */ +// The ID for the synthetic object generated to account for class static overhead. #define CLASS_STATICS_ID(clazz) ((HprofObjectId)(((uint32_t)(clazz)) | 1)) -static HprofBasicType signatureToBasicTypeAndSize(const char *sig, size_t *sizeOut) -{ - char c = sig[0]; - HprofBasicType ret; - size_t size; - - switch (c) { - case '[': - case 'L': ret = hprof_basic_object; size = 4; break; - case 'Z': ret = hprof_basic_boolean; size = 1; break; - case 'C': ret = hprof_basic_char; size = 2; break; - case 'F': ret = hprof_basic_float; size = 4; break; - case 'D': ret = hprof_basic_double; size = 8; break; - case 'B': ret = hprof_basic_byte; size = 1; break; - case 'S': ret = hprof_basic_short; size = 2; break; - default: CHECK(false); - case 'I': ret = hprof_basic_int; size = 4; break; - case 'J': ret = hprof_basic_long; size = 8; break; - } +static HprofBasicType signatureToBasicTypeAndSize(const char *sig, size_t *sizeOut) { + char c = sig[0]; + HprofBasicType ret; + size_t size; + + switch (c) { + case '[': + case 'L': ret = hprof_basic_object; size = 4; break; + case 'Z': ret = hprof_basic_boolean; size = 1; break; + case 'C': ret = hprof_basic_char; size = 2; break; + case 'F': ret = hprof_basic_float; size = 4; break; + case 'D': ret = hprof_basic_double; size = 8; break; + case 'B': ret = hprof_basic_byte; size = 1; break; + case 'S': ret = hprof_basic_short; size = 2; break; + default: CHECK(false); + case 'I': ret = hprof_basic_int; size = 4; break; + case 'J': ret = hprof_basic_long; size = 8; break; + } - if (sizeOut != NULL) { - *sizeOut = size; - } + if (sizeOut != NULL) { + *sizeOut = size; + } - return ret; + return ret; } -static HprofBasicType primitiveToBasicTypeAndSize(Primitive::Type prim, - size_t *sizeOut) -{ - HprofBasicType ret; - size_t size; - - switch (prim) { - case Primitive::kPrimBoolean: ret = hprof_basic_boolean; size = 1; break; - case Primitive::kPrimChar: ret = hprof_basic_char; size = 2; break; - case Primitive::kPrimFloat: ret = hprof_basic_float; size = 4; break; - case Primitive::kPrimDouble: ret = hprof_basic_double; size = 8; break; - case Primitive::kPrimByte: ret = hprof_basic_byte; size = 1; break; - case Primitive::kPrimShort: ret = hprof_basic_short; size = 2; break; - default: CHECK(false); - case Primitive::kPrimInt: ret = hprof_basic_int; size = 4; break; - case Primitive::kPrimLong: ret = hprof_basic_long; size = 8; break; - } +static HprofBasicType primitiveToBasicTypeAndSize(Primitive::Type prim, size_t *sizeOut) { + HprofBasicType ret; + size_t size; + + switch (prim) { + case Primitive::kPrimBoolean: ret = hprof_basic_boolean; size = 1; break; + case Primitive::kPrimChar: ret = hprof_basic_char; size = 2; break; + case Primitive::kPrimFloat: ret = hprof_basic_float; size = 4; break; + case Primitive::kPrimDouble: ret = hprof_basic_double; size = 8; break; + case Primitive::kPrimByte: ret = hprof_basic_byte; size = 1; break; + case Primitive::kPrimShort: ret = hprof_basic_short; size = 2; break; + default: CHECK(false); + case Primitive::kPrimInt: ret = hprof_basic_int; size = 4; break; + case Primitive::kPrimLong: ret = hprof_basic_long; size = 8; break; + } - if (sizeOut != NULL) { - *sizeOut = size; - } + if (sizeOut != NULL) { + *sizeOut = size; + } - return ret; + return ret; } -/* Always called when marking objects, but only does - * something when ctx->gc_scan_state_ is non-zero, which is usually - * only true when marking the root set or unreachable - * objects. Used to add rootset references to obj. - */ -int Hprof::MarkRootObject(const Object *obj, jobject jniObj) -{ - HprofRecord *rec = ¤t_record_; - int err; // TODO: we may return this uninitialized - HprofHeapTag heapTag = (HprofHeapTag)gc_scan_state_; - - if (heapTag == 0) { - return 0; - } - - if (objects_in_segment_ >= OBJECTS_PER_SEGMENT || rec->length_ >= BYTES_PER_SEGMENT) { - // This flushes the old segment and starts a new one. - StartNewRecord(HPROF_TAG_HEAP_DUMP_SEGMENT, HPROF_TIME); - objects_in_segment_ = 0; - } - - switch (heapTag) { - // ID: object ID - case HPROF_ROOT_UNKNOWN: - case HPROF_ROOT_STICKY_CLASS: - case HPROF_ROOT_MONITOR_USED: - case HPROF_ROOT_INTERNED_STRING: - case HPROF_ROOT_FINALIZING: - case HPROF_ROOT_DEBUGGER: - case HPROF_ROOT_REFERENCE_CLEANUP: - case HPROF_ROOT_VM_INTERNAL: - rec->AddU1(heapTag); - rec->AddId((HprofObjectId)obj); - break; +// Always called when marking objects, but only does +// something when ctx->gc_scan_state_ is non-zero, which is usually +// only true when marking the root set or unreachable +// objects. Used to add rootset references to obj. +int Hprof::MarkRootObject(const Object *obj, jobject jniObj) { + HprofRecord *rec = ¤t_record_; + int err; // TODO: we may return this uninitialized + HprofHeapTag heapTag = (HprofHeapTag)gc_scan_state_; - /* ID: object ID - * ID: JNI global ref ID - */ - case HPROF_ROOT_JNI_GLOBAL: - rec->AddU1(heapTag); - rec->AddId((HprofObjectId)obj); - rec->AddId((HprofId)jniObj); - break; - - /* ID: object ID - * uint32_t: thread serial number - * uint32_t: frame number in stack trace (-1 for empty) - */ - case HPROF_ROOT_JNI_LOCAL: - case HPROF_ROOT_JNI_MONITOR: - case HPROF_ROOT_JAVA_FRAME: - rec->AddU1(heapTag); - rec->AddId((HprofObjectId)obj); - rec->AddU4(gc_thread_serial_number_); - rec->AddU4((uint32_t)-1); - break; - - /* ID: object ID - * uint32_t: thread serial number - */ - case HPROF_ROOT_NATIVE_STACK: - case HPROF_ROOT_THREAD_BLOCK: - rec->AddU1(heapTag); - rec->AddId((HprofObjectId)obj); - rec->AddU4(gc_thread_serial_number_); - break; - - /* ID: thread object ID - * uint32_t: thread serial number - * uint32_t: stack trace serial number - */ - case HPROF_ROOT_THREAD_OBJECT: - rec->AddU1(heapTag); - rec->AddId((HprofObjectId)obj); - rec->AddU4(gc_thread_serial_number_); - rec->AddU4((uint32_t)-1); //xxx - break; + if (heapTag == 0) { + return 0; + } - default: - err = 0; - break; - } + if (objects_in_segment_ >= OBJECTS_PER_SEGMENT || rec->length_ >= BYTES_PER_SEGMENT) { + // This flushes the old segment and starts a new one. + StartNewRecord(HPROF_TAG_HEAP_DUMP_SEGMENT, HPROF_TIME); + objects_in_segment_ = 0; + } - objects_in_segment_++; + switch (heapTag) { + // ID: object ID + case HPROF_ROOT_UNKNOWN: + case HPROF_ROOT_STICKY_CLASS: + case HPROF_ROOT_MONITOR_USED: + case HPROF_ROOT_INTERNED_STRING: + case HPROF_ROOT_FINALIZING: + case HPROF_ROOT_DEBUGGER: + case HPROF_ROOT_REFERENCE_CLEANUP: + case HPROF_ROOT_VM_INTERNAL: + rec->AddU1(heapTag); + rec->AddId((HprofObjectId)obj); + break; + + // ID: object ID + // ID: JNI global ref ID + case HPROF_ROOT_JNI_GLOBAL: + rec->AddU1(heapTag); + rec->AddId((HprofObjectId)obj); + rec->AddId((HprofId)jniObj); + break; + + // ID: object ID + // U4: thread serial number + // U4: frame number in stack trace (-1 for empty) + case HPROF_ROOT_JNI_LOCAL: + case HPROF_ROOT_JNI_MONITOR: + case HPROF_ROOT_JAVA_FRAME: + rec->AddU1(heapTag); + rec->AddId((HprofObjectId)obj); + rec->AddU4(gc_thread_serial_number_); + rec->AddU4((uint32_t)-1); + break; + + // ID: object ID + // U4: thread serial number + case HPROF_ROOT_NATIVE_STACK: + case HPROF_ROOT_THREAD_BLOCK: + rec->AddU1(heapTag); + rec->AddId((HprofObjectId)obj); + rec->AddU4(gc_thread_serial_number_); + break; + + // ID: thread object ID + // U4: thread serial number + // U4: stack trace serial number + case HPROF_ROOT_THREAD_OBJECT: + rec->AddU1(heapTag); + rec->AddId((HprofObjectId)obj); + rec->AddU4(gc_thread_serial_number_); + rec->AddU4((uint32_t)-1); //xxx + break; + + default: + err = 0; + break; + } - return err; + objects_in_segment_++; + return err; } -static int stackTraceSerialNumber(const void *obj) -{ - return HPROF_NULL_STACK_TRACE; +static int stackTraceSerialNumber(const void *obj) { + return HPROF_NULL_STACK_TRACE; } int Hprof::DumpHeapObject(const Object* obj) { - Class* clazz; HprofRecord *rec = ¤t_record_; - HprofHeapId desiredHeap = false ? HPROF_HEAP_ZYGOTE : HPROF_HEAP_APP; // TODO: zygote objects? if (objects_in_segment_ >= OBJECTS_PER_SEGMENT || rec->length_ >= BYTES_PER_SEGMENT) { - /* This flushes the old segment and starts a new one. - */ + // This flushes the old segment and starts a new one. StartNewRecord(HPROF_TAG_HEAP_DUMP_SEGMENT, HPROF_TIME); objects_in_segment_ = 0; - /* Starting a new HEAP_DUMP resets the heap to default. - */ + // Starting a new HEAP_DUMP resets the heap to default. current_heap_ = HPROF_HEAP_DEFAULT; } if (desiredHeap != current_heap_) { HprofStringId nameId; - /* This object is in a different heap than the current one. - * Emit a HEAP_DUMP_INFO tag to change heaps. - */ + // This object is in a different heap than the current one. + // Emit a HEAP_DUMP_INFO tag to change heaps. rec->AddU1(HPROF_HEAP_DUMP_INFO); rec->AddU4((uint32_t)desiredHeap); // uint32_t: heap id switch (desiredHeap) { @@ -221,7 +201,7 @@ int Hprof::DumpHeapObject(const Object* obj) { nameId = LookupStringId("zygote"); break; default: - /* Internal error. */ + // Internal error LOG(ERROR) << "Unexpected desiredHeap"; nameId = LookupStringId("<ILLEGAL>"); break; @@ -230,25 +210,21 @@ int Hprof::DumpHeapObject(const Object* obj) { current_heap_ = desiredHeap; } - clazz = obj->GetClass(); - + Class* clazz = obj->GetClass(); if (clazz == NULL) { - /* This object will bother HprofReader, because it has a NULL - * class, so just don't dump it. It could be - * gDvm.unlinkedJavaLangClass or it could be an object just - * allocated which hasn't been initialized yet. - */ + // This object will bother HprofReader, because it has a NULL + // class, so just don't dump it. It could be + // gDvm.unlinkedJavaLangClass or it could be an object just + // allocated which hasn't been initialized yet. } else { if (obj->IsClass()) { Class* thisClass = (Class*)obj; - /* obj is a ClassObject. - */ + // obj is a ClassObject. size_t sFieldCount = thisClass->NumStaticFields(); if (sFieldCount != 0) { int byteLength = sFieldCount*sizeof(JValue); // TODO bogus; fields are packed - /* Create a byte array to reflect the allocation of the - * StaticField array at the end of this class. - */ + // Create a byte array to reflect the allocation of the + // StaticField array at the end of this class. rec->AddU1(HPROF_PRIMITIVE_ARRAY_DUMP); rec->AddId(CLASS_STATICS_ID(obj)); rec->AddU4(stackTraceSerialNumber(obj)); @@ -269,9 +245,8 @@ int Hprof::DumpHeapObject(const Object* obj) { rec->AddId((HprofId)0); // reserved rec->AddId((HprofId)0); // reserved if (obj->IsClassClass()) { - // ClassObjects have their static fields appended, so - // aren't all the same size. But they're at least this - // size. + // ClassObjects have their static fields appended, so aren't all the same size. + // But they're at least this size. rec->AddU4(sizeof(Class)); // instance size } else if (thisClass->IsArrayClass() || thisClass->IsPrimitive()) { rec->AddU4(0); @@ -279,10 +254,9 @@ int Hprof::DumpHeapObject(const Object* obj) { rec->AddU4(thisClass->GetObjectSize()); // instance size } - rec->AddU2(0); // empty const pool + rec->AddU2(0); // empty const pool - /* Static fields - */ + // Static fields if (sFieldCount == 0) { rec->AddU2((uint16_t)0); } else { @@ -312,8 +286,7 @@ int Hprof::DumpHeapObject(const Object* obj) { } } - /* Instance fields for this class (no superclass fields) - */ + // Instance fields for this class (no superclass fields) int iFieldCount = thisClass->IsObjectClass() ? 0 : thisClass->NumInstanceFields(); rec->AddU2((uint16_t)iFieldCount); for (int i = 0; i < iFieldCount; ++i) { @@ -327,8 +300,7 @@ int Hprof::DumpHeapObject(const Object* obj) { uint32_t length = aobj->GetLength(); if (obj->IsObjectArray()) { - /* obj is an object array. - */ + // obj is an object array. rec->AddU1(HPROF_OBJECT_ARRAY_DUMP); rec->AddId((HprofObjectId)obj); @@ -336,15 +308,13 @@ int Hprof::DumpHeapObject(const Object* obj) { rec->AddU4(length); rec->AddId(LookupClassId(clazz)); - /* Dump the elements, which are always objects or NULL. - */ + // Dump the elements, which are always objects or NULL. rec->AddIdList((const HprofObjectId *)aobj->GetRawData(), length); } else { size_t size; HprofBasicType t = primitiveToBasicTypeAndSize(clazz->GetComponentType()->GetPrimitiveType(), &size); - /* obj is a primitive array. - */ + // obj is a primitive array. #if DUMP_PRIM_DATA rec->AddU1(HPROF_PRIMITIVE_ARRAY_DUMP); #else @@ -357,8 +327,7 @@ int Hprof::DumpHeapObject(const Object* obj) { rec->AddU1(t); #if DUMP_PRIM_DATA - /* Dump the raw, packed element values. - */ + // Dump the raw, packed element values. if (size == 1) { rec->AddU1List((const uint8_t *)aobj->GetRawData(), length); } else if (size == 2) { @@ -372,24 +341,19 @@ int Hprof::DumpHeapObject(const Object* obj) { } } else { - /* obj is an instance object. - */ + // obj is an instance object. rec->AddU1(HPROF_INSTANCE_DUMP); rec->AddId((HprofObjectId)obj); rec->AddU4(stackTraceSerialNumber(obj)); rec->AddId(LookupClassId(clazz)); - /* Reserve some space for the length of the instance - * data, which we won't know until we're done writing - * it. - */ + // Reserve some space for the length of the instance data, which we won't + // know until we're done writing it. size_t sizePatchOffset = rec->length_; rec->AddU4(0x77777777); - /* Write the instance data; fields for this - * class, followed by super class fields, and so on. - * Don't write the klass or monitor fields of Object.class. - */ + // Write the instance data; fields for this class, followed by super class fields, + // and so on. Don't write the klass or monitor fields of Object.class. const Class* sclass = clazz; while (!sclass->IsObjectClass()) { int ifieldCount = sclass->NumInstanceFields(); @@ -413,8 +377,7 @@ int Hprof::DumpHeapObject(const Object* obj) { sclass = sclass->GetSuperClass(); } - /* Patch the instance field length. - */ + // Patch the instance field length. size_t savedLen = rec->length_; rec->length_ = sizePatchOffset; rec->AddU4(savedLen - (sizePatchOffset + 4)); @@ -423,7 +386,6 @@ int Hprof::DumpHeapObject(const Object* obj) { } objects_in_segment_++; - return 0; } diff --git a/src/hprof/hprof_output.cc b/src/hprof/hprof_output.cc index 012bfdd525..3e26468f54 100644 --- a/src/hprof/hprof_output.cc +++ b/src/hprof/hprof_output.cc @@ -81,255 +81,211 @@ Hprof::Hprof(const char *outputFileName, int fd, bool writeHeader, bool directTo classes_lock_("hprof classes"), next_string_id_(0x400000), strings_lock_("hprof strings") { - /* - * Have to do this here, because it must happen after we - * memset the struct (want to treat file_data_ptr_/file_data_size_ - * as read-only while the file is open). - */ - FILE *fp = open_memstream(&file_data_ptr_, &file_data_size_); - if (fp == NULL) { - /* not expected */ - LOG(ERROR) << StringPrintf("hprof: open_memstream failed: %s", strerror(errno)); - CHECK(false); + // Have to do this here, because it must happen after we + // memset the struct (want to treat file_data_ptr_/file_data_size_ + // as read-only while the file is open). + FILE *fp = open_memstream(&file_data_ptr_, &file_data_size_); + if (fp == NULL) { + // not expected + LOG(ERROR) << StringPrintf("hprof: open_memstream failed: %s", strerror(errno)); + CHECK(false); + } + + direct_to_ddms_ = directToDdms; + file_name_ = strdup(outputFileName); + mem_fp_ = fp; + fd_ = fd; + + current_record_.alloc_length_ = 128; + current_record_.body_ = (unsigned char *)malloc(current_record_.alloc_length_); + // TODO check for/return an error + + if (writeHeader) { + char magic[] = HPROF_MAGIC_STRING; + unsigned char buf[4]; + + // Write the file header. + // U1: NUL-terminated magic string. + fwrite(magic, 1, sizeof(magic), fp); + + // U4: size of identifiers. We're using addresses as IDs, so make sure a pointer fits. + U4_TO_BUF_BE(buf, 0, sizeof(void *)); + fwrite(buf, 1, sizeof(uint32_t), fp); + + // The current time, in milliseconds since 0:00 GMT, 1/1/70. + struct timeval now; + uint64_t nowMs; + if (gettimeofday(&now, NULL) < 0) { + nowMs = 0; + } else { + nowMs = (uint64_t)now.tv_sec * 1000 + now.tv_usec / 1000; } - direct_to_ddms_ = directToDdms; - file_name_ = strdup(outputFileName); - mem_fp_ = fp; - fd_ = fd; - - current_record_.alloc_length_ = 128; - current_record_.body_ = (unsigned char *)malloc(current_record_.alloc_length_); -//xxx check for/return an error - - if (writeHeader) { - char magic[] = HPROF_MAGIC_STRING; - unsigned char buf[4]; - struct timeval now; - uint64_t nowMs; - - /* Write the file header. - * - * [uint8_t]*: NUL-terminated magic string. - */ - fwrite(magic, 1, sizeof(magic), fp); - - /* uint32_t: size of identifiers. We're using addresses - * as IDs, so make sure a pointer fits. - */ - U4_TO_BUF_BE(buf, 0, sizeof(void *)); - fwrite(buf, 1, sizeof(uint32_t), fp); - - /* The current time, in milliseconds since 0:00 GMT, 1/1/70. - */ - if (gettimeofday(&now, NULL) < 0) { - nowMs = 0; - } else { - nowMs = (uint64_t)now.tv_sec * 1000 + now.tv_usec / 1000; - } - - /* uint32_t: high word of the 64-bit time. - */ - U4_TO_BUF_BE(buf, 0, (uint32_t)(nowMs >> 32)); - fwrite(buf, 1, sizeof(uint32_t), fp); - - /* uint32_t: low word of the 64-bit time. - */ - U4_TO_BUF_BE(buf, 0, (uint32_t)(nowMs & 0xffffffffULL)); - fwrite(buf, 1, sizeof(uint32_t), fp); //xxx fix the time - } -} - -int HprofRecord::Flush(FILE *fp) -{ - if (dirty_) { - unsigned char headBuf[sizeof (uint8_t) + 2 * sizeof (uint32_t)]; - int nb; - - headBuf[0] = tag_; - U4_TO_BUF_BE(headBuf, 1, time_); - U4_TO_BUF_BE(headBuf, 5, length_); - - nb = fwrite(headBuf, 1, sizeof(headBuf), fp); - if (nb != sizeof(headBuf)) { - return UNIQUE_ERROR(); - } - nb = fwrite(body_, 1, length_, fp); - if (nb != (int)length_) { - return UNIQUE_ERROR(); - } - - dirty_ = false; - } -//xxx if we used less than half (or whatever) of allocLen, shrink the buffer. + // U4: high word of the 64-bit time. + U4_TO_BUF_BE(buf, 0, (uint32_t)(nowMs >> 32)); + fwrite(buf, 1, sizeof(uint32_t), fp); - return 0; + // U4: low word of the 64-bit time. + U4_TO_BUF_BE(buf, 0, (uint32_t)(nowMs & 0xffffffffULL)); + fwrite(buf, 1, sizeof(uint32_t), fp); //xxx fix the time + } } -int Hprof::FlushCurrentRecord() -{ - return current_record_.Flush(mem_fp_); -} +int HprofRecord::Flush(FILE *fp) { + if (dirty_) { + unsigned char headBuf[sizeof (uint8_t) + 2 * sizeof (uint32_t)]; -int Hprof::StartNewRecord(uint8_t tag, uint32_t time) -{ - HprofRecord *rec = ¤t_record_; + headBuf[0] = tag_; + U4_TO_BUF_BE(headBuf, 1, time_); + U4_TO_BUF_BE(headBuf, 5, length_); - int err = rec->Flush(mem_fp_); - if (err != 0) { - return err; - } else if (rec->dirty_) { - return UNIQUE_ERROR(); + int nb = fwrite(headBuf, 1, sizeof(headBuf), fp); + if (nb != sizeof(headBuf)) { + return UNIQUE_ERROR(); + } + nb = fwrite(body_, 1, length_, fp); + if (nb != (int)length_) { + return UNIQUE_ERROR(); } - rec->dirty_ = true; - rec->tag_ = tag; - rec->time_ = time; - rec->length_ = 0; - - return 0; + dirty_ = false; + } + // TODO if we used less than half (or whatever) of allocLen, shrink the buffer. + return 0; } -static inline int guaranteeRecordAppend(HprofRecord *rec, size_t nmore) -{ - size_t minSize; - - minSize = rec->length_ + nmore; - if (minSize > rec->alloc_length_) { - unsigned char *newBody; - size_t newAllocLen; - - newAllocLen = rec->alloc_length_ * 2; - if (newAllocLen < minSize) { - newAllocLen = rec->alloc_length_ + nmore + nmore/2; - } - newBody = (unsigned char *)realloc(rec->body_, newAllocLen); - if (newBody != NULL) { - rec->body_ = newBody; - rec->alloc_length_ = newAllocLen; - } else { -//TODO: set an error flag so future ops will fail - return UNIQUE_ERROR(); - } - } +int Hprof::FlushCurrentRecord() { + return current_record_.Flush(mem_fp_); +} - CHECK_LE(rec->length_ + nmore, rec->alloc_length_); - return 0; +int Hprof::StartNewRecord(uint8_t tag, uint32_t time) { + HprofRecord *rec = ¤t_record_; + + int err = rec->Flush(mem_fp_); + if (err != 0) { + return err; + } else if (rec->dirty_) { + return UNIQUE_ERROR(); + } + + rec->dirty_ = true; + rec->tag_ = tag; + rec->time_ = time; + rec->length_ = 0; + return 0; } -int HprofRecord::AddU1List(const uint8_t *values, size_t numValues) -{ - int err = guaranteeRecordAppend(this, numValues); - if (err != 0) { - return err; +static inline int guaranteeRecordAppend(HprofRecord *rec, size_t nmore) { + size_t minSize = rec->length_ + nmore; + if (minSize > rec->alloc_length_) { + size_t newAllocLen = rec->alloc_length_ * 2; + if (newAllocLen < minSize) { + newAllocLen = rec->alloc_length_ + nmore + nmore/2; } + unsigned char *newBody = (unsigned char *)realloc(rec->body_, newAllocLen); + if (newBody != NULL) { + rec->body_ = newBody; + rec->alloc_length_ = newAllocLen; + } else { + // TODO: set an error flag so future ops will fail + return UNIQUE_ERROR(); + } + } - memcpy(body_ + length_, values, numValues); - length_ += numValues; - - return 0; + CHECK_LE(rec->length_ + nmore, rec->alloc_length_); + return 0; } -int HprofRecord::AddU1(uint8_t value) -{ - int err = guaranteeRecordAppend(this, 1); - if (err != 0) { - return err; - } +int HprofRecord::AddU1List(const uint8_t *values, size_t numValues) { + int err = guaranteeRecordAppend(this, numValues); + if (err != 0) { + return err; + } - body_[length_++] = value; + memcpy(body_ + length_, values, numValues); + length_ += numValues; - return 0; + return 0; } -int HprofRecord::AddUtf8String(const char *str) -{ - /* The terminating NUL character is NOT written. - */ -//xxx don't do a strlen; add and grow as necessary, until NUL - return AddU1List((const uint8_t *)str, strlen(str)); -} +int HprofRecord::AddU1(uint8_t value) { + int err = guaranteeRecordAppend(this, 1); + if (err != 0) { + return err; + } -int HprofRecord::AddU2List(const uint16_t *values, size_t numValues) -{ - int err = guaranteeRecordAppend(this, numValues * 2); - if (err != 0) { - return err; - } - -//xxx this can be way smarter -//xxx also, don't do this bytewise if aligned and on a matching-endian arch - unsigned char *insert = body_ + length_; - for (size_t i = 0; i < numValues; i++) { - U2_TO_BUF_BE(insert, 0, *values++); - insert += sizeof(*values); - } - length_ += numValues * 2; - - return 0; + body_[length_++] = value; + return 0; } -int HprofRecord::AddU2(uint16_t value) -{ - return AddU2List(&value, 1); +int HprofRecord::AddUtf8String(const char *str) { + // The terminating NUL character is NOT written. + return AddU1List((const uint8_t *)str, strlen(str)); } -int HprofRecord::AddIdList(const HprofObjectId *values, size_t numValues) -{ - return AddU4List((const uint32_t*) values, numValues); +int HprofRecord::AddU2List(const uint16_t *values, size_t numValues) { + int err = guaranteeRecordAppend(this, numValues * 2); + if (err != 0) { + return err; + } + + unsigned char *insert = body_ + length_; + for (size_t i = 0; i < numValues; i++) { + U2_TO_BUF_BE(insert, 0, *values++); + insert += sizeof(*values); + } + length_ += numValues * 2; + return 0; } -int HprofRecord::AddU4List(const uint32_t *values, size_t numValues) -{ - int err = guaranteeRecordAppend(this, numValues * 4); - if (err != 0) { - return err; - } - -//xxx this can be way smarter -//xxx also, don't do this bytewise if aligned and on a matching-endian arch - unsigned char *insert = body_ + length_; - for (size_t i = 0; i < numValues; i++) { - U4_TO_BUF_BE(insert, 0, *values++); - insert += sizeof(*values); - } - length_ += numValues * 4; - - return 0; +int HprofRecord::AddU2(uint16_t value) { + return AddU2List(&value, 1); } -int HprofRecord::AddU4(uint32_t value) -{ - return AddU4List(&value, 1); +int HprofRecord::AddIdList(const HprofObjectId *values, size_t numValues) { + return AddU4List((const uint32_t*) values, numValues); } -int HprofRecord::AddId(HprofObjectId value) -{ - return AddU4((uint32_t) value); +int HprofRecord::AddU4List(const uint32_t *values, size_t numValues) { + int err = guaranteeRecordAppend(this, numValues * 4); + if (err != 0) { + return err; + } + + unsigned char *insert = body_ + length_; + for (size_t i = 0; i < numValues; i++) { + U4_TO_BUF_BE(insert, 0, *values++); + insert += sizeof(*values); + } + length_ += numValues * 4; + return 0; } -int HprofRecord::AddU8List(const uint64_t *values, size_t numValues) -{ - int err = guaranteeRecordAppend(this, numValues * 8); - if (err != 0) { - return err; - } +int HprofRecord::AddU4(uint32_t value) { + return AddU4List(&value, 1); +} -//xxx this can be way smarter -//xxx also, don't do this bytewise if aligned and on a matching-endian arch - unsigned char *insert = body_ + length_; - for (size_t i = 0; i < numValues; i++) { - U8_TO_BUF_BE(insert, 0, *values++); - insert += sizeof(*values); - } - length_ += numValues * 8; +int HprofRecord::AddId(HprofObjectId value) { + return AddU4((uint32_t) value); +} - return 0; +int HprofRecord::AddU8List(const uint64_t *values, size_t numValues) { + int err = guaranteeRecordAppend(this, numValues * 8); + if (err != 0) { + return err; + } + + unsigned char *insert = body_ + length_; + for (size_t i = 0; i < numValues; i++) { + U8_TO_BUF_BE(insert, 0, *values++); + insert += sizeof(*values); + } + length_ += numValues * 8; + return 0; } -int HprofRecord::AddU8(uint64_t value) -{ - return AddU8List(&value, 1); +int HprofRecord::AddU8(uint64_t value) { + return AddU8List(&value, 1); } } // namespace hprof diff --git a/src/hprof/hprof_string.cc b/src/hprof/hprof_string.cc index ab205e7b48..96acaf341c 100644 --- a/src/hprof/hprof_string.cc +++ b/src/hprof/hprof_string.cc @@ -26,54 +26,50 @@ namespace art { namespace hprof { HprofStringId Hprof::LookupStringId(String* string) { - return LookupStringId(string->ToModifiedUtf8()); + return LookupStringId(string->ToModifiedUtf8()); } HprofStringId Hprof::LookupStringId(const char* string) { - return LookupStringId(std::string(string)); + return LookupStringId(std::string(string)); } HprofStringId Hprof::LookupStringId(std::string string) { - MutexLock mu(strings_lock_); - if (strings_.find(string) == strings_.end()) { - strings_[string] = next_string_id_++; - } - return strings_[string]; + MutexLock mu(strings_lock_); + if (strings_.find(string) == strings_.end()) { + strings_[string] = next_string_id_++; + } + return strings_[string]; } int Hprof::DumpStrings() { - MutexLock mu(strings_lock_); + MutexLock mu(strings_lock_); - HprofRecord *rec = ¤t_record_; + HprofRecord *rec = ¤t_record_; - for (StringMapIterator it = strings_.begin(); it != strings_.end(); ++it) { - std::string string = (*it).first; - size_t id = (*it).second; + for (StringMapIterator it = strings_.begin(); it != strings_.end(); ++it) { + std::string string = (*it).first; + size_t id = (*it).second; - int err = StartNewRecord(HPROF_TAG_STRING, HPROF_TIME); - if (err != 0) { - return err; - } + int err = StartNewRecord(HPROF_TAG_STRING, HPROF_TIME); + if (err != 0) { + return err; + } - /* STRING format: - * - * ID: ID for this string - * [uint8_t]*: UTF8 characters for string (NOT NULL terminated) - * (the record format encodes the length) - * - * We use the address of the string data as its ID. - */ - err = rec->AddU4(id); - if (err != 0) { - return err; - } - err = rec->AddUtf8String(string.c_str()); - if (err != 0) { - return err; - } + // STRING format: + // ID: ID for this string + // U1*: UTF8 characters for string (NOT NULL terminated) + // (the record format encodes the length) + err = rec->AddU4(id); + if (err != 0) { + return err; + } + err = rec->AddUtf8String(string.c_str()); + if (err != 0) { + return err; } + } - return 0; + return 0; } } // namespace hprof |