Commit 5e113c72 authored by jochen's avatar jochen Committed by Commit bot

Use git ls-tree to collect source files instead of walking the fs

Also remove obsolete oom_dump sources.

R=machenbach@chromium.org
BUG=

Review-Url: https://codereview.chromium.org/2343423002
Cr-Commit-Position: refs/heads/master@{#39527}
parent 298ee9cd
......@@ -8,6 +8,8 @@ v8_executable("unittests") {
testonly = true
sources = [
"../../testing/gmock-support.h",
"../../testing/gtest-support.h",
"base/atomic-utils-unittest.cc",
"base/bits-unittest.cc",
"base/cpu-unittest.cc",
......
oom_dump extracts useful information from Google Chrome OOM minidumps.
To build one needs a google-breakpad checkout
(http://code.google.com/p/google-breakpad/).
First, one needs to build and install breakpad itself. For instructions
check google-breakpad, but currently it's as easy as:
./configure
make
sudo make install
(the catch: breakpad installs .so into /usr/local/lib, so you might
need some additional tweaking to make it discoverable, for example,
put a soft link into /usr/lib directory).
Next step is to build v8. Note: you should build x64 version of v8,
if you're on 64-bit platform, otherwise you would get a link error when
building oom_dump. Also, if you are testing against an older version of chrome
you should build the corresponding version of V8 to make sure that the type-id
enum have the correct values.
The last step is to build oom_dump itself. The following command should work:
cd <v8 working copy>/tools/oom_dump
scons BREAKPAD_DIR=<path to google-breakpad working copy>
(Additionally you can control v8 working copy dir, but the default should work.)
If everything goes fine, oom_dump <path to minidump> should print
some useful information about the OOM crash.
Note: currently only 32-bit Windows minidumps are supported.
# 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.
vars = Variables('custom.py')
vars.Add(PathVariable('BREAKPAD_DIR',
'Path to checkout of google-breakpad project',
'~/google-breakpad',
PathVariable.PathIsDir))
vars.Add(PathVariable('V8_DIR',
'Path to checkout of v8 project',
'../..',
PathVariable.PathIsDir))
env = Environment(variables = vars,
CPPPATH = ['${BREAKPAD_DIR}/src', '${V8_DIR}/src'],
LIBPATH = ['/usr/local/lib', '${V8_DIR}'])
env.Program('oom_dump.cc', LIBS = ['breakpad', 'v8', 'pthread'])
// 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 <stdio.h>
#include <stdlib.h>
#include <algorithm>
#include <google_breakpad/processor/minidump.h>
#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);
// Currently only 32-bit Windows minidumps are supported.
CHECK_EQ(MD_CONTEXT_X86, crash_context->GetContextCPU());
const MDRawContextX86* contextX86 = crash_context->GetContextX86();
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 == v8::internal::HeapStats::kStartMarker) {
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) == v8::internal::HeapStats::kStartMarker);
CHECK(READ_FIELD(24) == v8::internal::HeapStats::kEndMarker);
const int new_space_size = READ_FIELD(1);
const int new_space_capacity = READ_FIELD(2);
const int old_space_size = READ_FIELD(3);
const int old_space_capacity = READ_FIELD(4);
const int code_space_size = READ_FIELD(5);
const int code_space_capacity = READ_FIELD(6);
const int map_space_size = READ_FIELD(7);
const int map_space_capacity = READ_FIELD(8);
const int cell_space_size = READ_FIELD(9);
const int cell_space_capacity = READ_FIELD(10);
const int lo_space_size = READ_FIELD(11);
const int global_handle_count = READ_FIELD(12);
const int weak_global_handle_count = READ_FIELD(13);
const int pending_global_handle_count = READ_FIELD(14);
const int near_death_global_handle_count = READ_FIELD(15);
const int destroyed_global_handle_count = READ_FIELD(16);
const int memory_allocator_size = READ_FIELD(17);
const int memory_allocator_capacity = READ_FIELD(18);
const int os_error = READ_FIELD(19);
#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: %" PRIu32 " (%#" PRIx32 ")\n",
exception_thread_id, exception_thread_id);
printf("heap stats address: %#" PRIx64 "\n", heap_stats_addr);
#define PRINT_INT_STAT(stat) \
printf("\t%-25s\t% 10d\n", #stat ":", stat);
#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_space_size);
PRINT_MB_STAT(old_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);
PRINT_INT_STAT(os_error);
#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_EQ(0, objects_per_type[type]);
CHECK_EQ(0, size_per_type[type]);
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) {
if (argc != 2) {
fprintf(stderr, "usage: %s <minidump>\n", argv[0]);
return 1;
}
DumpHeapStats(argv[1]);
return 0;
}
......@@ -15,27 +15,48 @@ is referenced from a gyp/gn file, we won't necessarily detect it.
import itertools
import re
import os
import subprocess
import sys
V8_BASE = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
V8_SRC_BASE = os.path.join(V8_BASE, 'src')
V8_TEST_BASE = os.path.join(V8_BASE, 'test')
V8_INCLUDE_BASE = os.path.join(V8_BASE, 'include')
GYP_FILES = [
os.path.join(V8_BASE, 'src', 'd8.gyp'),
os.path.join(V8_BASE, 'src', 'v8.gyp'),
os.path.join(V8_BASE, 'src', 'inspector', 'inspector.gypi'),
os.path.join(V8_BASE, 'src', 'third_party', 'vtune', 'v8vtune.gyp'),
os.path.join(V8_BASE, 'samples', 'samples.gyp'),
os.path.join(V8_BASE, 'test', 'cctest', 'cctest.gyp'),
os.path.join(V8_BASE, 'test', 'fuzzer', 'fuzzer.gyp'),
os.path.join(V8_BASE, 'test', 'unittests', 'unittests.gyp'),
os.path.join(V8_BASE, 'testing', 'gmock.gyp'),
os.path.join(V8_BASE, 'testing', 'gtest.gyp'),
os.path.join(V8_BASE, 'tools', 'parser-shell.gyp'),
]
ALL_GYP_PREFIXES = [
'..',
'common',
os.path.join('src', 'third_party', 'vtune'),
'src',
'samples',
'testing',
'tools',
os.path.join('test', 'cctest'),
os.path.join('test', 'common'),
os.path.join('test', 'fuzzer'),
os.path.join('test', 'unittests'),
]
GYP_UNSUPPORTED_FEATURES = [
'gcmole',
]
GN_FILES = [
os.path.join(V8_BASE, 'BUILD.gn'),
os.path.join(V8_BASE, 'build', 'secondary', 'testing', 'gmock', 'BUILD.gn'),
os.path.join(V8_BASE, 'build', 'secondary', 'testing', 'gtest', 'BUILD.gn'),
os.path.join(V8_BASE, 'src', 'inspector', 'BUILD.gn'),
os.path.join(V8_BASE, 'test', 'cctest', 'BUILD.gn'),
os.path.join(V8_BASE, 'test', 'unittests', 'BUILD.gn'),
......@@ -46,6 +67,7 @@ GN_UNSUPPORTED_FEATURES = [
'aix',
'cygwin',
'freebsd',
'gcmole',
'openbsd',
'ppc',
'qnx',
......@@ -58,21 +80,11 @@ ALL_GN_PREFIXES = [
'..',
os.path.join('src', 'inspector'),
'src',
'testing',
os.path.join('test', 'cctest'),
os.path.join('test', 'unittests'),
]
ALL_GYP_PREFIXES = [
'..',
'common',
os.path.join('src', 'third_party', 'vtune'),
'src',
os.path.join('test', 'cctest'),
os.path.join('test', 'common'),
os.path.join('test', 'fuzzer'),
os.path.join('test', 'unittests'),
]
def pathsplit(path):
return re.split('[/\\\\]', path)
......@@ -83,13 +95,12 @@ def path_no_prefix(path, prefixes):
return path
def isources(directory, prefixes):
for root, dirs, files in os.walk(directory):
for f in files:
if not (f.endswith('.h') or f.endswith('.cc')):
continue
yield path_no_prefix(
os.path.relpath(os.path.join(root, f), V8_BASE), prefixes)
def isources(prefixes):
cmd = ['git', 'ls-tree', '-r', 'HEAD', '--full-name', '--name-only']
for f in subprocess.check_output(cmd, universal_newlines=True).split('\n'):
if not (f.endswith('.h') or f.endswith('.cc')):
continue
yield path_no_prefix(os.path.join(*pathsplit(f)), prefixes)
def iflatten(obj):
......@@ -127,10 +138,8 @@ def iflatten_gn_file(gn_file):
os.path.join(*pathsplit(match.group(1))), ALL_GN_PREFIXES)
def icheck_values(values, prefixes, *source_dirs):
for source_file in itertools.chain(
*[isources(source_dir, prefixes) for source_dir in source_dirs]
):
def icheck_values(values, prefixes):
for source_file in isources(prefixes):
if source_file not in values:
yield source_file
......@@ -139,8 +148,9 @@ def missing_gyp_files():
gyp_values = set(itertools.chain(
*[iflatten_gyp_file(gyp_file) for gyp_file in GYP_FILES]
))
return sorted(icheck_values(
gyp_values, ALL_GYP_PREFIXES, V8_SRC_BASE, V8_INCLUDE_BASE, V8_TEST_BASE))
gyp_files = sorted(icheck_values(gyp_values, ALL_GYP_PREFIXES))
return filter(
lambda x: not any(i in x for i in GYP_UNSUPPORTED_FEATURES), gyp_files)
def missing_gn_files():
......@@ -148,8 +158,7 @@ def missing_gn_files():
*[iflatten_gn_file(gn_file) for gn_file in GN_FILES]
))
gn_files = sorted(icheck_values(
gn_values, ALL_GN_PREFIXES, V8_SRC_BASE, V8_INCLUDE_BASE, V8_TEST_BASE))
gn_files = sorted(icheck_values(gn_values, ALL_GN_PREFIXES))
return filter(
lambda x: not any(i in x for i in GN_UNSUPPORTED_FEATURES), gn_files)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment