Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(16)

Unified Diff: tools/oom_dump/oom_dump.cc

Issue 3170015: Initial implementation of oom_dump utility. (Closed)
Patch Set: Addressing Mads' comments Created 10 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« tools/oom_dump/README ('K') | « tools/oom_dump/SConstruct ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: tools/oom_dump/oom_dump.cc
diff --git a/tools/oom_dump/oom_dump.cc b/tools/oom_dump/oom_dump.cc
new file mode 100644
index 0000000000000000000000000000000000000000..01f6005cbcbdf71871740690f5288caab06a6a41
--- /dev/null
+++ b/tools/oom_dump/oom_dump.cc
@@ -0,0 +1,285 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <algorithm>
Mark Mentovai 2010/08/16 20:56:43 The style guide says: C system headers first, then
antonm 2010/08/17 13:13:19 Done. Also removed some now unnecessary deps.
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <google_breakpad/processor/minidump.h>
+#include <processor/logging.h>
+
+#define ENABLE_DEBUGGER_SUPPORT
+
+#include <v8.h>
+
+namespace {
+
+using google_breakpad::Minidump;
+using google_breakpad::MinidumpContext;
+using google_breakpad::MinidumpThread;
+using google_breakpad::MinidumpThreadList;
+using google_breakpad::MinidumpException;
+using google_breakpad::MinidumpMemoryRegion;
+
+const char* InstanceTypeToString(int type) {
+ static char const* names[v8::internal::LAST_TYPE] = {0};
+ if (names[v8::internal::STRING_TYPE] == NULL) {
+ using namespace v8::internal;
+#define SET(type) names[type] = #type;
+ INSTANCE_TYPE_LIST(SET)
+#undef SET
+ }
+ return names[type];
+}
+
+
+u_int32_t ReadPointedValue(MinidumpMemoryRegion* region,
+ u_int64_t base,
+ int offset) {
+ u_int32_t ptr = 0;
+ CHECK(region->GetMemoryAtAddress(base + 4 * offset, &ptr));
+ u_int32_t value = 0;
+ CHECK(region->GetMemoryAtAddress(ptr, &value));
+ return value;
+}
+
+
+void ReadArray(MinidumpMemoryRegion* region,
+ u_int64_t array_ptr,
+ int size,
+ int* output) {
+ for (int i = 0; i < size; i++) {
+ u_int32_t value;
+ CHECK(region->GetMemoryAtAddress(array_ptr + 4 * i, &value));
+ output[i] = value;
+ }
+}
+
+
+u_int32_t ReadArrayFrom(MinidumpMemoryRegion* region,
+ u_int64_t base,
+ int offset,
+ int size,
+ int* output) {
+ u_int32_t ptr = 0;
+ CHECK(region->GetMemoryAtAddress(base + 4 * offset, &ptr));
+ ReadArray(region, ptr, size, output);
+}
+
+
+double toM(int size) {
+ return size / (1024. * 1024.);
+}
+
+
+class IndirectSorter {
+ public:
+ explicit IndirectSorter(int* a) : a_(a) { }
+
+ bool operator() (int i0, int i1) {
+ return a_[i0] > a_[i1];
+ }
+
+ private:
+ int* a_;
+};
+
+void DumpHeapStats(const char *minidump_file) {
+ Minidump minidump(minidump_file);
+ CHECK(minidump.Read());
+
+ MinidumpException *exception = minidump.GetException();
+ CHECK(exception);
+
+ MinidumpContext* crash_context = exception->GetContext();
+ CHECK(crash_context);
+
+ u_int32_t exception_thread_id = 0;
+ CHECK(exception->GetThreadID(&exception_thread_id));
+
+ MinidumpThreadList* thread_list = minidump.GetThreadList();
+ CHECK(thread_list);
+
+ MinidumpThread* exception_thread =
+ thread_list->GetThreadByID(exception_thread_id);
+ CHECK(exception_thread);
+
+ const MDRawContextX86* contextX86 = crash_context->GetContextX86();
Mark Mentovai 2010/08/16 20:56:43 Have you tried this with non-x86 dumps? Does it wo
antonm 2010/08/17 13:13:19 Mark, my bad---I didn't make it explicit what is e
+ CHECK(contextX86);
+
+ const u_int32_t esp = contextX86->esp;
+
+ MinidumpMemoryRegion* memory_region = exception_thread->GetMemory();
+ CHECK(memory_region);
+
+ const u_int64_t last = memory_region->GetBase() + memory_region->GetSize();
+
+ u_int64_t heap_stats_addr = 0;
+ for (u_int64_t addr = esp; addr < last; addr += 4) {
+ u_int32_t value = 0;
+ CHECK(memory_region->GetMemoryAtAddress(addr, &value));
+ if (value >= esp && value < last) {
+ u_int32_t value2 = 0;
+ CHECK(memory_region->GetMemoryAtAddress(value, &value2));
+ if (value2 == 0xdecade00) {
Mark Mentovai 2010/08/16 20:56:43 This might be better as a symbolic constant, like
antonm 2010/08/17 13:13:19 Done.
+ heap_stats_addr = addr;
+ break;
+ }
+ }
+ }
+ CHECK(heap_stats_addr);
+
+ // Read heap stats.
+
+#define READ_FIELD(offset) \
+ ReadPointedValue(memory_region, heap_stats_addr, offset)
+
+ CHECK(READ_FIELD(0) == 0xdecade00);
+ CHECK(READ_FIELD(23) == 0xdecade01);
+
+ const int new_space_size = READ_FIELD(1);
Mark Mentovai 2010/08/16 20:56:43 Is a native "int" correct? Are these fields fixed
antonm 2010/08/17 13:13:19 They are declared as plain ints: http://www.google
+ const int new_space_capacity = READ_FIELD(2);
+ const int old_pointer_space_size = READ_FIELD(3);
+ const int old_pointer_space_capacity = READ_FIELD(4);
+ const int old_data_space_size = READ_FIELD(5);
+ const int old_data_space_capacity = READ_FIELD(6);
+ const int code_space_size = READ_FIELD(7);
+ const int code_space_capacity = READ_FIELD(8);
+ const int map_space_size = READ_FIELD(9);
+ const int map_space_capacity = READ_FIELD(10);
+ const int cell_space_size = READ_FIELD(11);
+ const int cell_space_capacity = READ_FIELD(12);
+ const int lo_space_size = READ_FIELD(13);
+ const int global_handle_count = READ_FIELD(14);
+ const int weak_global_handle_count = READ_FIELD(15);
+ const int pending_global_handle_count = READ_FIELD(16);
+ const int near_death_global_handle_count = READ_FIELD(17);
+ const int destroyed_global_handle_count = READ_FIELD(18);
+ const int memory_allocator_size = READ_FIELD(19);
+ const int memory_allocator_capacity = READ_FIELD(20);
+#undef READ_FIELD
+
+ int objects_per_type[v8::internal::LAST_TYPE + 1] = {0};
+ ReadArrayFrom(memory_region, heap_stats_addr, 21,
+ v8::internal::LAST_TYPE + 1, objects_per_type);
+
+ int size_per_type[v8::internal::LAST_TYPE + 1] = {0};
+ ReadArrayFrom(memory_region, heap_stats_addr, 22, v8::internal::LAST_TYPE + 1,
+ size_per_type);
+
+ int js_global_objects =
+ objects_per_type[v8::internal::JS_GLOBAL_OBJECT_TYPE];
+ int js_builtins_objects =
+ objects_per_type[v8::internal::JS_BUILTINS_OBJECT_TYPE];
+ int js_global_proxies =
+ objects_per_type[v8::internal::JS_GLOBAL_PROXY_TYPE];
+
+ int indices[v8::internal::LAST_TYPE + 1];
+ for (int i = 0; i <= v8::internal::LAST_TYPE; i++) {
+ indices[i] = i;
+ }
+
+ std::stable_sort(indices, indices + sizeof(indices)/sizeof(indices[0]),
+ IndirectSorter(size_per_type));
+
+ int total_size = 0;
+ for (int i = 0; i <= v8::internal::LAST_TYPE; i++) {
+ total_size += size_per_type[i];
+ }
+
+ // Print heap stats.
+
+ printf("exception thread ID: %d (%x)\n",
Mark Mentovai 2010/08/16 20:56:43 suggest 0x%x instead of just raw %x. Actually, yo
antonm 2010/08/17 13:13:19 I wasn't sure those a portable enough, but as GCC
+ exception_thread_id, exception_thread_id);
+ printf("heap stats address: %p\n", (void*)heap_stats_addr);
Mark Mentovai 2010/08/16 20:56:43 Unlike the previous one, this one's an even bigger
antonm 2010/08/17 13:13:19 Done.
+#define PRINT_INT_STAT(stat) \
+ printf("\t%-25s\t% 10d\n", #stat ":", stat);
Mark Mentovai 2010/08/16 20:56:43 These are OK if a native "int" is correct (see abo
antonm 2010/08/17 13:13:19 They should be.
+#define PRINT_MB_STAT(stat) \
+ printf("\t%-25s\t% 10.3f MB\n", #stat ":", toM(stat));
+ PRINT_MB_STAT(new_space_size);
+ PRINT_MB_STAT(new_space_capacity);
+ PRINT_MB_STAT(old_pointer_space_size);
+ PRINT_MB_STAT(old_pointer_space_capacity);
+ PRINT_MB_STAT(old_data_space_size);
+ PRINT_MB_STAT(old_data_space_capacity);
+ PRINT_MB_STAT(code_space_size);
+ PRINT_MB_STAT(code_space_capacity);
+ PRINT_MB_STAT(map_space_size);
+ PRINT_MB_STAT(map_space_capacity);
+ PRINT_MB_STAT(cell_space_size);
+ PRINT_MB_STAT(cell_space_capacity);
+ PRINT_MB_STAT(lo_space_size);
+ PRINT_INT_STAT(global_handle_count);
+ PRINT_INT_STAT(weak_global_handle_count);
+ PRINT_INT_STAT(pending_global_handle_count);
+ PRINT_INT_STAT(near_death_global_handle_count);
+ PRINT_INT_STAT(destroyed_global_handle_count);
+ PRINT_MB_STAT(memory_allocator_size);
+ PRINT_MB_STAT(memory_allocator_capacity);
+#undef PRINT_STAT
+
+ printf("\n");
+
+ printf(
+ "\tJS_GLOBAL_OBJECT_TYPE/JS_BUILTINS_OBJECT_TYPE/JS_GLOBAL_PROXY_TYPE: "
+ "%d/%d/%d\n\n",
+ js_global_objects, js_builtins_objects, js_global_proxies);
+
+ int running_size = 0;
+ for (int i = 0; i <= v8::internal::LAST_TYPE; i++) {
+ int type = indices[i];
+ const char* name = InstanceTypeToString(type);
+ if (name == NULL) {
+ // Unknown instance type. Check that there is no objects of that type.
+ CHECK(objects_per_type[type] == 0);
+ CHECK(size_per_type[type] == 0);
+ continue;
+ }
+ int size = size_per_type[type];
+ running_size += size;
+ printf("\t%-37s% 9d% 11.3f MB% 10.3f%%% 10.3f%%\n",
+ name, objects_per_type[type], toM(size),
+ 100.*size/total_size, 100.*running_size/total_size);
+ }
+ printf("\t%-37s% 9d% 11.3f MB% 10.3f%%% 10.3f%%\n",
+ "total", 0, toM(total_size), 100., 100.);
+}
+
+} // namespace
+
+int main(int argc, char **argv) {
+ BPLOG_INIT(&argc, &argv);
+
+ if (argc != 2) {
+ fprintf(stderr, "usage: %s <minidump>\n", argv[0]);
+ return 1;
+ }
+
+ DumpHeapStats(argv[1]);
+
+ return 0;
+}
« tools/oom_dump/README ('K') | « tools/oom_dump/SConstruct ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698