mirror of
https://github.com/dart-lang/sdk
synced 2024-09-05 16:41:07 +00:00
[vm] Remove tcmalloc and malloc profiler.
The standalone VM originally began statically linking tcmalloc to work around bugs in the system malloc for Fiber. Later it used tcmalloc's hooks to implement a profiler, but this is rarely used since it is only available in debug mode, misses early allocations, and often misses late allocations from an exhausted sample buffer. Removing it altogether avoids build complexity around which combinations of compiler/architecture/sysroot support tcmalloc, and reduces binary size. TEST=ci Change-Id: I4b259e18b82b2d12a2a60962aabf83bd8d997d19 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/286120 Reviewed-by: Ben Konyi <bkonyi@google.com> Commit-Queue: Ryan Macnak <rmacnak@google.com>
This commit is contained in:
parent
08d9d8586a
commit
c67fac9cb4
5
DEPS
5
DEPS
|
@ -95,7 +95,6 @@ vars = {
|
|||
"boringssl_rev": "87f316d7748268eb56f2dc147bd593254ae93198",
|
||||
"browser-compat-data_tag": "ac8cae697014da1ff7124fba33b0b4245cc6cd1b", # v1.0.22
|
||||
"devtools_rev": "bf15e7348d53dc83531d503be94e0c035b604984",
|
||||
"gperftools_revision": "bf8b714bf5075d0a6f2f28504b43095e2b1e11c5",
|
||||
"icu_rev": "81d656878ec611cb0b42d52c82e9dae93920d9ba",
|
||||
"jinja2_rev": "2222b31554f03e62600cd7e383376a7c187967a1",
|
||||
"libprotobuf_rev": "24487dd1045c7f3d64a21f38a3f0c06cc4cf2edb",
|
||||
|
@ -334,10 +333,6 @@ deps = {
|
|||
Var('chromium_git') + '/external/github.com/mdn/browser-compat-data' +
|
||||
"@" + Var("browser-compat-data_tag"),
|
||||
|
||||
Var("dart_root") + "/third_party/tcmalloc/gperftools":
|
||||
Var('chromium_git') + '/external/github.com/gperftools/gperftools.git' +
|
||||
"@" + Var("gperftools_revision"),
|
||||
|
||||
Var("dart_root") + "/third_party/pkg/args":
|
||||
Var("dart_git") + "args.git" + "@" + Var("args_rev"),
|
||||
Var("dart_root") + "/third_party/pkg/async":
|
||||
|
|
|
@ -155,13 +155,6 @@ config("dart_config") {
|
|||
}
|
||||
|
||||
include_dirs = [ "include" ]
|
||||
if (dart_use_tcmalloc) {
|
||||
defines += [ "DART_USE_TCMALLOC" ]
|
||||
include_dirs += [ "../third_party/tcmalloc/gperftools/src" ]
|
||||
}
|
||||
if (dart_use_mallinfo2) {
|
||||
defines += [ "DART_USE_MALLINFO2" ]
|
||||
}
|
||||
|
||||
if (dart_use_compressed_pointers) {
|
||||
defines += [ "DART_COMPRESSED_POINTERS" ]
|
||||
|
|
|
@ -196,10 +196,6 @@ template("build_gen_snapshot") {
|
|||
"//third_party",
|
||||
]
|
||||
|
||||
if (dart_use_tcmalloc) {
|
||||
deps += [ "//third_party/tcmalloc" ]
|
||||
}
|
||||
|
||||
if (is_mac) {
|
||||
frameworks = [
|
||||
"CoreFoundation.framework",
|
||||
|
@ -752,10 +748,6 @@ template("dart_executable") {
|
|||
defines += [ "EXCLUDE_CFE_AND_KERNEL_PLATFORM" ]
|
||||
}
|
||||
|
||||
if (dart_use_tcmalloc) {
|
||||
deps += [ "//third_party/tcmalloc" ]
|
||||
}
|
||||
|
||||
include_dirs = [
|
||||
"..",
|
||||
"//third_party",
|
||||
|
@ -967,11 +959,6 @@ executable("run_vm_tests") {
|
|||
]
|
||||
defines = [ "TESTING" ]
|
||||
|
||||
if (dart_use_tcmalloc) {
|
||||
deps += [ "//third_party/tcmalloc" ]
|
||||
defines += [ "DART_USE_TCMALLOC" ]
|
||||
}
|
||||
|
||||
if (is_fuchsia) {
|
||||
if (using_fuchsia_gn_sdk) {
|
||||
include_dirs += [ "$fuchsia_sdk_path/pkg/trace-engine/include" ]
|
||||
|
|
|
@ -160,45 +160,6 @@ class VMViewElement extends CustomElement implements Renderable {
|
|||
new DivElement()
|
||||
..classes = ['memberItem']
|
||||
..children = <Element>[
|
||||
new DivElement()
|
||||
..classes = ['memberName']
|
||||
..text = 'malloc used memory',
|
||||
new DivElement()
|
||||
..classes = ['memberValue']
|
||||
..text = Utils.formatSize(_vm.mallocUsed)
|
||||
..title = '${_vm.mallocUsed} bytes'
|
||||
],
|
||||
new DivElement()
|
||||
..classes = ['memberItem']
|
||||
..children = <Element>[
|
||||
new DivElement()
|
||||
..classes = ['memberName']
|
||||
..text = 'malloc capacity memory',
|
||||
new DivElement()
|
||||
..classes = ['memberValue']
|
||||
..text = Utils.formatSize(_vm.mallocCapacity)
|
||||
..title = '${_vm.mallocCapacity} bytes'
|
||||
],
|
||||
new DivElement()
|
||||
..classes = ['memberItem']
|
||||
..children = <Element>[
|
||||
new DivElement()
|
||||
..classes = ['memberName']
|
||||
..text = 'malloc implementation',
|
||||
new DivElement()
|
||||
..classes = ['memberValue']
|
||||
..text = _vm.mallocImplementation
|
||||
],
|
||||
new DivElement()
|
||||
..classes = ['memberItem']
|
||||
..children = <Element>[
|
||||
new DivElement()
|
||||
..classes = ['memberName']
|
||||
..children = <Element>[
|
||||
new SpanElement()..text = 'view ',
|
||||
new AnchorElement(href: Uris.nativeMemory())
|
||||
..text = 'malloc profile'
|
||||
],
|
||||
new DivElement()
|
||||
..classes = ['memberName']
|
||||
..children = <Element>[
|
||||
|
|
|
@ -36,11 +36,6 @@ abstract class VM implements VMRef {
|
|||
/// The process id for the VM.
|
||||
int get pid;
|
||||
|
||||
/// The current amount of native heap allocated memory within the VM.
|
||||
int get mallocUsed;
|
||||
int get mallocCapacity;
|
||||
String get mallocImplementation;
|
||||
|
||||
int get currentMemory;
|
||||
int get maxRSS;
|
||||
int get currentRSS;
|
||||
|
|
|
@ -674,9 +674,6 @@ abstract class VM extends ServiceObjectOwner implements M.VM {
|
|||
int architectureBits = 0;
|
||||
int nativeZoneMemoryUsage = 0;
|
||||
int pid = 0;
|
||||
int mallocUsed = 0;
|
||||
int mallocCapacity = 0;
|
||||
String mallocImplementation = 'unknown';
|
||||
int currentMemory = 0;
|
||||
int maxRSS = 0;
|
||||
int currentRSS = 0;
|
||||
|
@ -1035,9 +1032,6 @@ abstract class VM extends ServiceObjectOwner implements M.VM {
|
|||
nativeZoneMemoryUsage = map['_nativeZoneMemoryUsage'];
|
||||
}
|
||||
pid = map['pid'];
|
||||
mallocUsed = map['_mallocUsed'] ?? -1;
|
||||
mallocCapacity = map['_mallocCapacity'] ?? -1;
|
||||
mallocImplementation = map['_mallocImplementation'] ?? 'unknown';
|
||||
embedder = map['_embedder'];
|
||||
currentMemory = map['_currentMemory'];
|
||||
maxRSS = map['_maxRSS'];
|
||||
|
|
|
@ -1,86 +0,0 @@
|
|||
// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
// VMOptions=--profiler_native_memory
|
||||
|
||||
import 'package:observatory/sample_profile.dart';
|
||||
import 'package:observatory/models.dart' as M;
|
||||
import 'package:observatory/service_io.dart';
|
||||
import 'package:test/test.dart';
|
||||
import 'test_helper.dart';
|
||||
|
||||
void verifyHelper(var root, bool exclusive) {
|
||||
if (root.children.length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(root is FunctionCallTreeNode)) {
|
||||
print('${root.profileCode.code.name}');
|
||||
} else {
|
||||
print('${root.profileFunction.function.name}');
|
||||
}
|
||||
|
||||
int inclusiveAllocations = 0;
|
||||
int exclusiveAllocations = 0;
|
||||
|
||||
for (int i = 0; i < root.children.length; i++) {
|
||||
inclusiveAllocations += root.children[i].inclusiveNativeAllocations as int;
|
||||
exclusiveAllocations += root.children[i].exclusiveNativeAllocations as int;
|
||||
}
|
||||
|
||||
int rootMemory;
|
||||
if (exclusive) {
|
||||
rootMemory = root.inclusiveNativeAllocations + exclusiveAllocations;
|
||||
} else {
|
||||
rootMemory =
|
||||
root.inclusiveNativeAllocations - root.exclusiveNativeAllocations;
|
||||
}
|
||||
|
||||
expect(inclusiveAllocations == rootMemory, isTrue);
|
||||
for (int i = 0; i < root.children.length; i++) {
|
||||
verifyHelper(root.children[i], exclusive);
|
||||
}
|
||||
}
|
||||
|
||||
void verify(var tree, bool exclusive) {
|
||||
var node = tree.root;
|
||||
expect(node, isNotNull);
|
||||
expect(node.children.length >= 0, isTrue);
|
||||
|
||||
for (int i = 0; i < node.children.length; i++) {
|
||||
verifyHelper(node.children[i], exclusive);
|
||||
}
|
||||
}
|
||||
|
||||
var tests = <VMTest>[
|
||||
// Verify inclusive tries.
|
||||
(VM vm) async {
|
||||
var response =
|
||||
await vm.invokeRpc('_getNativeAllocationSamples', {'_code': true})
|
||||
as ServiceMap;
|
||||
SampleProfile cpuProfile = new SampleProfile();
|
||||
await cpuProfile.load(vm, response);
|
||||
var codeTree = cpuProfile.loadCodeTree(M.ProfileTreeDirection.inclusive);
|
||||
var functionTree =
|
||||
cpuProfile.loadFunctionTree(M.ProfileTreeDirection.inclusive);
|
||||
verify(codeTree, false);
|
||||
verify(functionTree, false);
|
||||
},
|
||||
// Verify exclusive tries.
|
||||
(VM vm) async {
|
||||
var response =
|
||||
await vm.invokeRpc('_getNativeAllocationSamples', {'_code': true})
|
||||
as ServiceMap;
|
||||
SampleProfile cpuProfile = new SampleProfile();
|
||||
await cpuProfile.load(vm, response);
|
||||
var codeTreeExclusive =
|
||||
cpuProfile.loadCodeTree(M.ProfileTreeDirection.exclusive);
|
||||
var functionTreeExclusive =
|
||||
cpuProfile.loadFunctionTree(M.ProfileTreeDirection.exclusive);
|
||||
verify(codeTreeExclusive, true);
|
||||
verify(functionTreeExclusive, true);
|
||||
}
|
||||
];
|
||||
|
||||
main(args) async => runVMTests(args, tests);
|
|
@ -61,9 +61,6 @@ async_scope_test: Pass, Slow
|
|||
[ $compiler == dartk || $compiler == dartkp ]
|
||||
rewind_test: Pass, Slow
|
||||
|
||||
[ $system != linux || $arch != ia32 && $arch != x64 ]
|
||||
get_native_allocation_samples_test: Skip # Unsupported.
|
||||
|
||||
# Skip all service tests because random reloads interfere.
|
||||
[ $hot_reload || $hot_reload_rollback ]
|
||||
*: SkipByDesign # The service tests should run without being reloaded.
|
||||
|
|
|
@ -170,52 +170,6 @@ class VMViewElement extends CustomElement implements Renderable {
|
|||
new DivElement()
|
||||
..classes = ['memberItem']
|
||||
..children = <Element>[
|
||||
new DivElement()
|
||||
..classes = ['memberName']
|
||||
..text = 'malloc used memory',
|
||||
new DivElement()
|
||||
..classes = ['memberValue']
|
||||
..text = _vm.mallocUsed != null
|
||||
? Utils.formatSize(_vm.mallocUsed)
|
||||
: 'unavailable'
|
||||
..title =
|
||||
_vm.mallocUsed != null ? '${_vm.mallocUsed} bytes' : null
|
||||
],
|
||||
new DivElement()
|
||||
..classes = ['memberItem']
|
||||
..children = <Element>[
|
||||
new DivElement()
|
||||
..classes = ['memberName']
|
||||
..text = 'malloc capacity memory',
|
||||
new DivElement()
|
||||
..classes = ['memberValue']
|
||||
..text = _vm.mallocCapacity != null
|
||||
? Utils.formatSize(_vm.mallocCapacity)
|
||||
: 'unavailable'
|
||||
..title = _vm.mallocCapacity != null
|
||||
? '${_vm.mallocCapacity} bytes'
|
||||
: null
|
||||
],
|
||||
new DivElement()
|
||||
..classes = ['memberItem']
|
||||
..children = <Element>[
|
||||
new DivElement()
|
||||
..classes = ['memberName']
|
||||
..text = 'malloc implementation',
|
||||
new DivElement()
|
||||
..classes = ['memberValue']
|
||||
..text = _vm.mallocImplementation
|
||||
],
|
||||
new DivElement()
|
||||
..classes = ['memberItem']
|
||||
..children = <Element>[
|
||||
new DivElement()
|
||||
..classes = ['memberName']
|
||||
..children = <Element>[
|
||||
new SpanElement()..text = 'view ',
|
||||
new AnchorElement(href: Uris.nativeMemory())
|
||||
..text = 'malloc profile'
|
||||
],
|
||||
new DivElement()
|
||||
..classes = ['memberName']
|
||||
..children = <Element>[
|
||||
|
|
|
@ -34,11 +34,6 @@ abstract class VM implements VMRef {
|
|||
/// The process id for the VM.
|
||||
int get pid;
|
||||
|
||||
/// The current amount of native heap allocated memory within the VM.
|
||||
int get mallocUsed;
|
||||
int get mallocCapacity;
|
||||
String get mallocImplementation;
|
||||
|
||||
int get currentMemory;
|
||||
int get maxRSS;
|
||||
int get currentRSS;
|
||||
|
|
|
@ -680,9 +680,6 @@ abstract class VM extends ServiceObjectOwner implements M.VM {
|
|||
int architectureBits;
|
||||
int nativeZoneMemoryUsage = 0;
|
||||
int pid = 0;
|
||||
int mallocUsed = 0;
|
||||
int mallocCapacity = 0;
|
||||
String mallocImplementation = 'unknown';
|
||||
int currentMemory;
|
||||
int maxRSS;
|
||||
int currentRSS;
|
||||
|
@ -1044,9 +1041,6 @@ abstract class VM extends ServiceObjectOwner implements M.VM {
|
|||
nativeZoneMemoryUsage = map['_nativeZoneMemoryUsage'];
|
||||
}
|
||||
pid = map['pid'];
|
||||
mallocUsed = map['_mallocUsed'];
|
||||
mallocCapacity = map['_mallocCapacity'];
|
||||
mallocImplementation = map['_mallocImplementation'];
|
||||
embedder = map['_embedder'];
|
||||
currentMemory = map['_currentMemory'];
|
||||
maxRSS = map['_maxRSS'];
|
||||
|
|
|
@ -1,84 +0,0 @@
|
|||
// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
// VMOptions=--profiler_native_memory
|
||||
|
||||
import 'package:observatory_2/sample_profile.dart';
|
||||
import 'package:observatory_2/models.dart' as M;
|
||||
import 'package:observatory_2/service_io.dart';
|
||||
import 'package:test/test.dart';
|
||||
import 'test_helper.dart';
|
||||
|
||||
void verifyHelper(var root, bool exclusive) {
|
||||
if (root.children.length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(root is FunctionCallTreeNode)) {
|
||||
print('${root.profileCode.code.name}');
|
||||
} else {
|
||||
print('${root.profileFunction.function.name}');
|
||||
}
|
||||
|
||||
int inclusiveAllocations = 0;
|
||||
int exclusiveAllocations = 0;
|
||||
|
||||
for (int i = 0; i < root.children.length; i++) {
|
||||
inclusiveAllocations += root.children[i].inclusiveNativeAllocations;
|
||||
exclusiveAllocations += root.children[i].exclusiveNativeAllocations;
|
||||
}
|
||||
|
||||
int rootMemory;
|
||||
if (exclusive) {
|
||||
rootMemory = root.inclusiveNativeAllocations + exclusiveAllocations;
|
||||
} else {
|
||||
rootMemory =
|
||||
root.inclusiveNativeAllocations - root.exclusiveNativeAllocations;
|
||||
}
|
||||
|
||||
expect(inclusiveAllocations == rootMemory, isTrue);
|
||||
for (int i = 0; i < root.children.length; i++) {
|
||||
verifyHelper(root.children[i], exclusive);
|
||||
}
|
||||
}
|
||||
|
||||
void verify(var tree, bool exclusive) {
|
||||
var node = tree.root;
|
||||
expect(node, isNotNull);
|
||||
expect(node.children.length >= 0, isTrue);
|
||||
|
||||
for (int i = 0; i < node.children.length; i++) {
|
||||
verifyHelper(node.children[i], exclusive);
|
||||
}
|
||||
}
|
||||
|
||||
var tests = <VMTest>[
|
||||
// Verify inclusive tries.
|
||||
(VM vm) async {
|
||||
var response =
|
||||
await vm.invokeRpc('_getNativeAllocationSamples', {'_code': true});
|
||||
SampleProfile cpuProfile = new SampleProfile();
|
||||
await cpuProfile.load(vm, response);
|
||||
var codeTree = cpuProfile.loadCodeTree(M.ProfileTreeDirection.inclusive);
|
||||
var functionTree =
|
||||
cpuProfile.loadFunctionTree(M.ProfileTreeDirection.inclusive);
|
||||
verify(codeTree, false);
|
||||
verify(functionTree, false);
|
||||
},
|
||||
// Verify exclusive tries.
|
||||
(VM vm) async {
|
||||
var response =
|
||||
await vm.invokeRpc('_getNativeAllocationSamples', {'_code': true});
|
||||
SampleProfile cpuProfile = new SampleProfile();
|
||||
await cpuProfile.load(vm, response);
|
||||
var codeTreeExclusive =
|
||||
cpuProfile.loadCodeTree(M.ProfileTreeDirection.exclusive);
|
||||
var functionTreeExclusive =
|
||||
cpuProfile.loadFunctionTree(M.ProfileTreeDirection.exclusive);
|
||||
verify(codeTreeExclusive, true);
|
||||
verify(functionTreeExclusive, true);
|
||||
}
|
||||
];
|
||||
|
||||
main(args) async => runVMTests(args, tests);
|
|
@ -67,9 +67,6 @@ async_scope_test: Pass, Slow
|
|||
[ $compiler == dartk || $compiler == dartkp ]
|
||||
rewind_test: Pass, Slow
|
||||
|
||||
[ $system != linux || $arch != ia32 && $arch != x64 ]
|
||||
get_native_allocation_samples_test: Skip # Unsupported.
|
||||
|
||||
# Skip all service tests because random reloads interfere.
|
||||
[ $hot_reload || $hot_reload_rollback ]
|
||||
*: SkipByDesign # The service tests should run without being reloaded.
|
||||
|
|
|
@ -42,14 +42,6 @@ declare_args() {
|
|||
# verified at the operating system level.
|
||||
dart_use_fallback_root_certificates = false
|
||||
|
||||
# Whether to link the standalone VM against tcmalloc. The standalone build of
|
||||
# the VM enables this only for Linux builds.
|
||||
dart_use_tcmalloc = false
|
||||
|
||||
# Whether to use mallinfo2 instead of mallinfo which is deprecated starting
|
||||
# with libc 2.33
|
||||
dart_use_mallinfo2 = false
|
||||
|
||||
# Whether to link Crashpad library for crash handling. Only supported on
|
||||
# Windows for now.
|
||||
dart_use_crashpad = false
|
||||
|
|
|
@ -248,12 +248,6 @@ dart_2/optimized_stacktrace_line_and_column_test: SkipByDesign # Looks for filen
|
|||
dart_2/optimized_stacktrace_line_test: SkipByDesign # Looks for filenames in stacktrace output
|
||||
dart_2/regress_37382_test: SkipByDesign # Matches the type arguments names
|
||||
|
||||
# Enabling of dartk for sim{arm,arm64} revealed these test failures, which
|
||||
# are to be triaged. Isolate tests are skipped on purpose due to the usage of
|
||||
# batch mode.
|
||||
[ $compiler == dartk && $mode == debug && ($arch == simarm || $arch == simarm64 || $arch == simarm64c || $arch == simriscv32 || $arch == simriscv64) ]
|
||||
cc/StackTraceMallocHookLengthTest: Fail # Please triage.
|
||||
|
||||
[ $compiler == dartk && $mode == product && $runtime == vm ]
|
||||
cc/CorelibIsolateStartup: Timeout, Pass
|
||||
|
||||
|
|
|
@ -15,7 +15,6 @@ List<String> compilerFlagsForFile(String filepath) {
|
|||
'-Iruntime',
|
||||
'-Ithird_party',
|
||||
'-Iruntime/include',
|
||||
'-Ithird_party/tcmalloc/gperftools/src',
|
||||
'-Ithird_party/boringssl/src/include',
|
||||
'-Ithird_party/zlib',
|
||||
'-DTARGET_ARCH_X64',
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
#include "vm/dart.h"
|
||||
#include "vm/globals.h"
|
||||
#include "vm/isolate.h"
|
||||
#include "vm/malloc_hooks.h"
|
||||
#include "vm/object.h"
|
||||
#include "vm/unit_test.h"
|
||||
#include "vm/zone.h"
|
||||
|
@ -36,16 +35,11 @@ extern const uint8_t* core_isolate_snapshot_instructions;
|
|||
static void Dart_BenchmarkHelper##name(Benchmark* benchmark, \
|
||||
Thread* thread); \
|
||||
void Dart_Benchmark##name(Benchmark* benchmark) { \
|
||||
bool __stack_trace_collection_enabled__ = \
|
||||
MallocHooks::stack_trace_collection_enabled(); \
|
||||
MallocHooks::set_stack_trace_collection_enabled(false); \
|
||||
FLAG_old_gen_growth_space_ratio = 100; \
|
||||
BenchmarkIsolateScope __isolate__(benchmark); \
|
||||
Thread* __thread__ = Thread::Current(); \
|
||||
ASSERT(__thread__->isolate() == benchmark->isolate()); \
|
||||
Dart_BenchmarkHelper##name(benchmark, __thread__); \
|
||||
MallocHooks::set_stack_trace_collection_enabled( \
|
||||
__stack_trace_collection_enabled__); \
|
||||
} \
|
||||
static void Dart_BenchmarkHelper##name(Benchmark* benchmark, Thread* thread)
|
||||
|
||||
|
|
|
@ -27,7 +27,6 @@
|
|||
#include "vm/isolate.h"
|
||||
#include "vm/isolate_reload.h"
|
||||
#include "vm/kernel_isolate.h"
|
||||
#include "vm/malloc_hooks.h"
|
||||
#include "vm/message_handler.h"
|
||||
#include "vm/metrics.h"
|
||||
#include "vm/native_entry.h"
|
||||
|
@ -409,13 +408,6 @@ char* Dart::DartInit(const Dart_InitializeParams* params) {
|
|||
#else
|
||||
StubCode::Init();
|
||||
Object::FinishInit(vm_isolate_->group());
|
||||
// MallocHooks can't be initialized until StubCode has been since stack
|
||||
// trace generation relies on stub methods that are generated in
|
||||
// StubCode::Init().
|
||||
// TODO(bkonyi) Split initialization for stack trace collection from the
|
||||
// initialization for the actual malloc hooks to increase accuracy of
|
||||
// memory consumption statistics.
|
||||
MallocHooks::Init();
|
||||
#endif
|
||||
} else {
|
||||
return Utils::StrDup("Invalid vm isolate snapshot seen");
|
||||
|
@ -456,13 +448,6 @@ char* Dart::DartInit(const Dart_InitializeParams* params) {
|
|||
vm_snapshot_kind_ = Snapshot::kNone;
|
||||
StubCode::Init();
|
||||
Object::FinishInit(vm_isolate_->group());
|
||||
// MallocHooks can't be initialized until StubCode has been since stack
|
||||
// trace generation relies on stub methods that are generated in
|
||||
// StubCode::Init().
|
||||
// TODO(bkonyi) Split initialization for stack trace collection from the
|
||||
// initialization for the actual malloc hooks to increase accuracy of
|
||||
// memory consumption statistics.
|
||||
MallocHooks::Init();
|
||||
Symbols::Init(vm_isolate_->group());
|
||||
#endif
|
||||
}
|
||||
|
@ -806,7 +791,6 @@ char* Dart::Cleanup() {
|
|||
if (FLAG_trace_shutdown) {
|
||||
OS::PrintErr("[+%" Pd64 "ms] SHUTDOWN: Done\n", UptimeMillis());
|
||||
}
|
||||
MallocHooks::Cleanup();
|
||||
Flags::Cleanup();
|
||||
#if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
|
||||
IsolateGroupReloadContext::SetFileModifiedCallback(NULL);
|
||||
|
|
|
@ -1,44 +0,0 @@
|
|||
// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
#ifndef RUNTIME_VM_MALLOC_HOOKS_H_
|
||||
#define RUNTIME_VM_MALLOC_HOOKS_H_
|
||||
|
||||
#include "vm/allocation.h"
|
||||
#include "vm/globals.h"
|
||||
|
||||
namespace dart {
|
||||
|
||||
class JSONObject;
|
||||
class Sample;
|
||||
|
||||
// The number of frames that are generated by the malloc hooks and collection
|
||||
// of the stack trace. These frames are ignored when collecting the stack
|
||||
// trace for a memory allocation. If this number is incorrect, some tests in
|
||||
// malloc_hook_tests.cc might fail, particularly
|
||||
// StackTraceMallocHookLengthTest. If this value is updated, please make sure
|
||||
// that the MallocHooks test cases pass on all platforms.
|
||||
extern const intptr_t kSkipCount;
|
||||
|
||||
class MallocHooks : public AllStatic {
|
||||
public:
|
||||
static void Init();
|
||||
static void Cleanup();
|
||||
static bool ProfilingEnabled();
|
||||
static bool stack_trace_collection_enabled();
|
||||
static void set_stack_trace_collection_enabled(bool enabled);
|
||||
static void ResetStats();
|
||||
static bool Active();
|
||||
static bool GetStats(intptr_t* used,
|
||||
intptr_t* capacity,
|
||||
const char** implementation);
|
||||
static Sample* GetSample(const void* ptr);
|
||||
|
||||
static intptr_t allocation_count();
|
||||
static intptr_t heap_allocated_memory_in_bytes();
|
||||
};
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // RUNTIME_VM_MALLOC_HOOKS_H_
|
|
@ -1,17 +0,0 @@
|
|||
// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
#include "vm/malloc_hooks.h"
|
||||
|
||||
#include "vm/globals.h"
|
||||
|
||||
#if defined(HOST_ARCH_ARM)
|
||||
|
||||
namespace dart {
|
||||
|
||||
const intptr_t kSkipCount = 5;
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // defined(HOST_ARCH_ARM)
|
|
@ -1,17 +0,0 @@
|
|||
// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
#include "vm/malloc_hooks.h"
|
||||
|
||||
#include "vm/globals.h"
|
||||
|
||||
#if defined(HOST_ARCH_ARM64)
|
||||
|
||||
namespace dart {
|
||||
|
||||
const intptr_t kSkipCount = 5;
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // defined(HOST_ARCH_ARM64)
|
|
@ -1,21 +0,0 @@
|
|||
// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
#include "vm/malloc_hooks.h"
|
||||
|
||||
#include "vm/globals.h"
|
||||
|
||||
#if defined(HOST_ARCH_IA32)
|
||||
|
||||
namespace dart {
|
||||
|
||||
#if defined(DEBUG)
|
||||
const intptr_t kSkipCount = 7;
|
||||
#elif !(defined(PRODUCT) || defined(DEBUG))
|
||||
const intptr_t kSkipCount = 6;
|
||||
#endif
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // defined(HOST_ARCH_IA32)
|
|
@ -1,17 +0,0 @@
|
|||
// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
#include "vm/malloc_hooks.h"
|
||||
|
||||
#include "vm/globals.h"
|
||||
|
||||
#if defined(HOST_ARCH_RISCV32) || defined(HOST_ARCH_RISCV64)
|
||||
|
||||
namespace dart {
|
||||
|
||||
const intptr_t kSkipCount = 5;
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // defined(HOST_ARCH_RISCV32) || defined(HOST_ARCH_RISCV64)
|
|
@ -1,428 +0,0 @@
|
|||
// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
#include "platform/globals.h"
|
||||
|
||||
#if defined(DART_USE_TCMALLOC) && defined(DEBUG)
|
||||
|
||||
#include "vm/malloc_hooks.h"
|
||||
|
||||
#include "gperftools/malloc_hook.h"
|
||||
|
||||
#include <malloc.h>
|
||||
|
||||
#include "platform/assert.h"
|
||||
#include "vm/hash_map.h"
|
||||
#include "vm/json_stream.h"
|
||||
#include "vm/os_thread.h"
|
||||
#include "vm/profiler.h"
|
||||
|
||||
namespace dart {
|
||||
|
||||
class AddressMap;
|
||||
|
||||
// MallocHooksState contains all of the state related to the configuration of
|
||||
// the malloc hooks, allocation information, and locks.
|
||||
class MallocHooksState : public AllStatic {
|
||||
public:
|
||||
static void RecordAllocHook(const void* ptr, size_t size);
|
||||
static void RecordFreeHook(const void* ptr);
|
||||
|
||||
static bool Active() {
|
||||
ASSERT(malloc_hook_mutex()->IsOwnedByCurrentThread());
|
||||
return active_;
|
||||
}
|
||||
static void Init();
|
||||
|
||||
static bool ProfilingEnabled() { return (OSThread::TryCurrent() != NULL); }
|
||||
|
||||
static bool stack_trace_collection_enabled() {
|
||||
return stack_trace_collection_enabled_;
|
||||
}
|
||||
|
||||
static void set_stack_trace_collection_enabled(bool enabled) {
|
||||
stack_trace_collection_enabled_ = enabled;
|
||||
}
|
||||
|
||||
static bool IsOriginalProcess() {
|
||||
ASSERT(original_pid_ != kInvalidPid);
|
||||
return original_pid_ == OS::ProcessId();
|
||||
}
|
||||
|
||||
static Mutex* malloc_hook_mutex() { return malloc_hook_mutex_; }
|
||||
static ThreadId* malloc_hook_mutex_owner() {
|
||||
return &malloc_hook_mutex_owner_;
|
||||
}
|
||||
static bool IsLockHeldByCurrentThread() {
|
||||
return (malloc_hook_mutex_owner_ == OSThread::GetCurrentThreadId());
|
||||
}
|
||||
|
||||
static intptr_t allocation_count() { return allocation_count_; }
|
||||
|
||||
static intptr_t heap_allocated_memory_in_bytes() {
|
||||
return heap_allocated_memory_in_bytes_;
|
||||
}
|
||||
|
||||
static void IncrementHeapAllocatedMemoryInBytes(intptr_t size) {
|
||||
ASSERT(malloc_hook_mutex()->IsOwnedByCurrentThread());
|
||||
ASSERT(size >= 0);
|
||||
heap_allocated_memory_in_bytes_ += size;
|
||||
++allocation_count_;
|
||||
}
|
||||
|
||||
static void DecrementHeapAllocatedMemoryInBytes(intptr_t size) {
|
||||
ASSERT(malloc_hook_mutex()->IsOwnedByCurrentThread());
|
||||
ASSERT(size >= 0);
|
||||
ASSERT(heap_allocated_memory_in_bytes_ >= size);
|
||||
heap_allocated_memory_in_bytes_ -= size;
|
||||
--allocation_count_;
|
||||
ASSERT(allocation_count_ >= 0);
|
||||
}
|
||||
|
||||
static AddressMap* address_map() { return address_map_; }
|
||||
|
||||
static void ResetStats();
|
||||
static void TearDown();
|
||||
|
||||
private:
|
||||
static Mutex* malloc_hook_mutex_;
|
||||
static ThreadId malloc_hook_mutex_owner_;
|
||||
|
||||
// Variables protected by malloc_hook_mutex_.
|
||||
static bool active_;
|
||||
static bool stack_trace_collection_enabled_;
|
||||
static intptr_t allocation_count_;
|
||||
static intptr_t heap_allocated_memory_in_bytes_;
|
||||
static AddressMap* address_map_;
|
||||
// End protected variables.
|
||||
|
||||
static intptr_t original_pid_;
|
||||
static const intptr_t kInvalidPid = -1;
|
||||
};
|
||||
|
||||
// A locker-type class similar to MutexLocker which tracks which thread
|
||||
// currently holds the lock. We use this instead of MutexLocker and
|
||||
// mutex->IsOwnedByCurrentThread() since IsOwnedByCurrentThread() is only
|
||||
// enabled for debug mode.
|
||||
class MallocLocker : public ValueObject {
|
||||
public:
|
||||
explicit MallocLocker(Mutex* mutex, ThreadId* owner)
|
||||
: mutex_(mutex), owner_(owner) {
|
||||
ASSERT(owner != NULL);
|
||||
mutex_->Lock();
|
||||
ASSERT(*owner_ == OSThread::kInvalidThreadId);
|
||||
*owner_ = OSThread::GetCurrentThreadId();
|
||||
}
|
||||
|
||||
virtual ~MallocLocker() {
|
||||
ASSERT(*owner_ == OSThread::GetCurrentThreadId());
|
||||
*owner_ = OSThread::kInvalidThreadId;
|
||||
mutex_->Unlock();
|
||||
}
|
||||
|
||||
private:
|
||||
Mutex* mutex_;
|
||||
ThreadId* owner_;
|
||||
};
|
||||
|
||||
// AllocationInfo contains all information related to a given allocation
|
||||
// including:
|
||||
// -Allocation size in bytes
|
||||
// -Stack trace corresponding to the location of allocation, if applicable
|
||||
class AllocationInfo {
|
||||
public:
|
||||
AllocationInfo(uword address, intptr_t allocation_size)
|
||||
: sample_(NULL), address_(address), allocation_size_(allocation_size) {
|
||||
// Stack trace collection is disabled when we are in the process of creating
|
||||
// the first OSThread in order to prevent deadlocks.
|
||||
if (MallocHooksState::ProfilingEnabled() &&
|
||||
MallocHooksState::stack_trace_collection_enabled()) {
|
||||
sample_ = Profiler::SampleNativeAllocation(kSkipCount, address,
|
||||
allocation_size);
|
||||
ASSERT((sample_ == NULL) ||
|
||||
(sample_->native_allocation_address() == address_));
|
||||
}
|
||||
}
|
||||
|
||||
~AllocationInfo() {
|
||||
if (sample_ != NULL) {
|
||||
Profiler::allocation_sample_buffer()->FreeAllocationSample(sample_);
|
||||
}
|
||||
}
|
||||
|
||||
Sample* sample() const { return sample_; }
|
||||
intptr_t allocation_size() const { return allocation_size_; }
|
||||
|
||||
private:
|
||||
// Note: sample_ is not owned by AllocationInfo, but by the SampleBuffer
|
||||
// created by the profiler. As such, this is only here to track if the sample
|
||||
// is still associated with a native allocation, and its fields are never
|
||||
// accessed from this class.
|
||||
Sample* sample_;
|
||||
uword address_;
|
||||
intptr_t allocation_size_;
|
||||
};
|
||||
|
||||
// Custom key/value trait specifically for address/size pairs. Unlike
|
||||
// RawPointerKeyValueTrait, the default value is -1 as 0 can be a valid entry.
|
||||
class AddressKeyValueTrait : public AllStatic {
|
||||
public:
|
||||
typedef const void* Key;
|
||||
typedef AllocationInfo* Value;
|
||||
|
||||
struct Pair {
|
||||
Key key;
|
||||
Value value;
|
||||
Pair() : key(NULL), value(NULL) {}
|
||||
Pair(const Key key, const Value& value) : key(key), value(value) {}
|
||||
Pair(const Pair& other) : key(other.key), value(other.value) {}
|
||||
Pair& operator=(const Pair&) = default;
|
||||
};
|
||||
|
||||
static Key KeyOf(Pair kv) { return kv.key; }
|
||||
static Value ValueOf(Pair kv) { return kv.value; }
|
||||
static uword Hash(Key key) {
|
||||
return Utils::WordHash(reinterpret_cast<intptr_t>(key));
|
||||
}
|
||||
static bool IsKeyEqual(Pair kv, Key key) { return kv.key == key; }
|
||||
};
|
||||
|
||||
// Map class that will be used to store mappings between ptr -> allocation size.
|
||||
class AddressMap : public MallocDirectChainedHashMap<AddressKeyValueTrait> {
|
||||
public:
|
||||
typedef AddressKeyValueTrait::Key Key;
|
||||
typedef AddressKeyValueTrait::Value Value;
|
||||
typedef AddressKeyValueTrait::Pair Pair;
|
||||
|
||||
virtual ~AddressMap() { Clear(); }
|
||||
|
||||
void Insert(const Key& key, const Value& value) {
|
||||
Pair pair(key, value);
|
||||
MallocDirectChainedHashMap<AddressKeyValueTrait>::Insert(pair);
|
||||
}
|
||||
|
||||
bool Lookup(const Key& key, Value* value) {
|
||||
ASSERT(value != NULL);
|
||||
Pair* pair = MallocDirectChainedHashMap<AddressKeyValueTrait>::Lookup(key);
|
||||
if (pair == NULL) {
|
||||
return false;
|
||||
} else {
|
||||
*value = pair->value;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void Clear() {
|
||||
Iterator iter = GetIterator();
|
||||
Pair* result = iter.Next();
|
||||
while (result != NULL) {
|
||||
delete result->value;
|
||||
result->value = NULL;
|
||||
result = iter.Next();
|
||||
}
|
||||
MallocDirectChainedHashMap<AddressKeyValueTrait>::Clear();
|
||||
}
|
||||
};
|
||||
|
||||
// MallocHooks state / locks.
|
||||
bool MallocHooksState::active_ = false;
|
||||
bool MallocHooksState::stack_trace_collection_enabled_ = false;
|
||||
intptr_t MallocHooksState::original_pid_ = MallocHooksState::kInvalidPid;
|
||||
Mutex* MallocHooksState::malloc_hook_mutex_ = new Mutex();
|
||||
ThreadId MallocHooksState::malloc_hook_mutex_owner_ =
|
||||
OSThread::kInvalidThreadId;
|
||||
|
||||
// Memory allocation state information.
|
||||
intptr_t MallocHooksState::allocation_count_ = 0;
|
||||
intptr_t MallocHooksState::heap_allocated_memory_in_bytes_ = 0;
|
||||
AddressMap* MallocHooksState::address_map_ = NULL;
|
||||
|
||||
void MallocHooksState::Init() {
|
||||
address_map_ = new AddressMap();
|
||||
active_ = true;
|
||||
#if defined(DEBUG)
|
||||
stack_trace_collection_enabled_ = true;
|
||||
#else
|
||||
stack_trace_collection_enabled_ = false;
|
||||
#endif // defined(DEBUG)
|
||||
original_pid_ = OS::ProcessId();
|
||||
}
|
||||
|
||||
void MallocHooksState::ResetStats() {
|
||||
ASSERT(malloc_hook_mutex()->IsOwnedByCurrentThread());
|
||||
allocation_count_ = 0;
|
||||
heap_allocated_memory_in_bytes_ = 0;
|
||||
address_map_->Clear();
|
||||
}
|
||||
|
||||
void MallocHooksState::TearDown() {
|
||||
ASSERT(malloc_hook_mutex()->IsOwnedByCurrentThread());
|
||||
active_ = false;
|
||||
original_pid_ = kInvalidPid;
|
||||
ResetStats();
|
||||
delete address_map_;
|
||||
address_map_ = NULL;
|
||||
}
|
||||
|
||||
void MallocHooks::Init() {
|
||||
if (!FLAG_profiler_native_memory || MallocHooks::Active()) {
|
||||
return;
|
||||
}
|
||||
MallocLocker ml(MallocHooksState::malloc_hook_mutex(),
|
||||
MallocHooksState::malloc_hook_mutex_owner());
|
||||
ASSERT(!MallocHooksState::Active());
|
||||
|
||||
MallocHooksState::Init();
|
||||
|
||||
// Register malloc hooks.
|
||||
bool success = false;
|
||||
success = MallocHook::AddNewHook(&MallocHooksState::RecordAllocHook);
|
||||
ASSERT(success);
|
||||
success = MallocHook::AddDeleteHook(&MallocHooksState::RecordFreeHook);
|
||||
ASSERT(success);
|
||||
}
|
||||
|
||||
void MallocHooks::Cleanup() {
|
||||
if (!FLAG_profiler_native_memory || !MallocHooks::Active()) {
|
||||
return;
|
||||
}
|
||||
MallocLocker ml(MallocHooksState::malloc_hook_mutex(),
|
||||
MallocHooksState::malloc_hook_mutex_owner());
|
||||
ASSERT(MallocHooksState::Active());
|
||||
|
||||
// Remove malloc hooks.
|
||||
bool success = false;
|
||||
success = MallocHook::RemoveNewHook(&MallocHooksState::RecordAllocHook);
|
||||
ASSERT(success);
|
||||
success = MallocHook::RemoveDeleteHook(&MallocHooksState::RecordFreeHook);
|
||||
ASSERT(success);
|
||||
|
||||
MallocHooksState::TearDown();
|
||||
}
|
||||
|
||||
bool MallocHooks::ProfilingEnabled() {
|
||||
return MallocHooksState::ProfilingEnabled();
|
||||
}
|
||||
|
||||
bool MallocHooks::stack_trace_collection_enabled() {
|
||||
MallocLocker ml(MallocHooksState::malloc_hook_mutex(),
|
||||
MallocHooksState::malloc_hook_mutex_owner());
|
||||
return MallocHooksState::stack_trace_collection_enabled();
|
||||
}
|
||||
|
||||
void MallocHooks::set_stack_trace_collection_enabled(bool enabled) {
|
||||
MallocLocker ml(MallocHooksState::malloc_hook_mutex(),
|
||||
MallocHooksState::malloc_hook_mutex_owner());
|
||||
MallocHooksState::set_stack_trace_collection_enabled(enabled);
|
||||
}
|
||||
|
||||
void MallocHooks::ResetStats() {
|
||||
if (!FLAG_profiler_native_memory) {
|
||||
return;
|
||||
}
|
||||
MallocLocker ml(MallocHooksState::malloc_hook_mutex(),
|
||||
MallocHooksState::malloc_hook_mutex_owner());
|
||||
if (MallocHooksState::Active()) {
|
||||
MallocHooksState::ResetStats();
|
||||
}
|
||||
}
|
||||
|
||||
bool MallocHooks::Active() {
|
||||
if (!FLAG_profiler_native_memory) {
|
||||
return false;
|
||||
}
|
||||
MallocLocker ml(MallocHooksState::malloc_hook_mutex(),
|
||||
MallocHooksState::malloc_hook_mutex_owner());
|
||||
|
||||
return MallocHooksState::Active();
|
||||
}
|
||||
|
||||
bool MallocHooks::GetStats(intptr_t* used,
|
||||
intptr_t* capacity,
|
||||
const char** implementation) {
|
||||
#if defined(DART_USE_MALLINFO2)
|
||||
struct mallinfo2 info = mallinfo2();
|
||||
#else
|
||||
struct mallinfo info = mallinfo();
|
||||
#endif // defined(DART_USE_MALLINFO2)
|
||||
*used = info.uordblks;
|
||||
*capacity = *used + info.fordblks;
|
||||
*implementation = "tcmalloc";
|
||||
return true;
|
||||
}
|
||||
|
||||
intptr_t MallocHooks::allocation_count() {
|
||||
if (!FLAG_profiler_native_memory) {
|
||||
return 0;
|
||||
}
|
||||
MallocLocker ml(MallocHooksState::malloc_hook_mutex(),
|
||||
MallocHooksState::malloc_hook_mutex_owner());
|
||||
return MallocHooksState::allocation_count();
|
||||
}
|
||||
|
||||
intptr_t MallocHooks::heap_allocated_memory_in_bytes() {
|
||||
if (!FLAG_profiler_native_memory) {
|
||||
return 0;
|
||||
}
|
||||
MallocLocker ml(MallocHooksState::malloc_hook_mutex(),
|
||||
MallocHooksState::malloc_hook_mutex_owner());
|
||||
return MallocHooksState::heap_allocated_memory_in_bytes();
|
||||
}
|
||||
|
||||
Sample* MallocHooks::GetSample(const void* ptr) {
|
||||
MallocLocker ml(MallocHooksState::malloc_hook_mutex(),
|
||||
MallocHooksState::malloc_hook_mutex_owner());
|
||||
|
||||
ASSERT(MallocHooksState::Active());
|
||||
|
||||
if (ptr != NULL) {
|
||||
AllocationInfo* allocation_info = NULL;
|
||||
if (MallocHooksState::address_map()->Lookup(ptr, &allocation_info)) {
|
||||
ASSERT(allocation_info != NULL);
|
||||
return allocation_info->sample();
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void MallocHooksState::RecordAllocHook(const void* ptr, size_t size) {
|
||||
if (MallocHooksState::IsLockHeldByCurrentThread() ||
|
||||
!MallocHooksState::IsOriginalProcess()) {
|
||||
return;
|
||||
}
|
||||
|
||||
MallocLocker ml(MallocHooksState::malloc_hook_mutex(),
|
||||
MallocHooksState::malloc_hook_mutex_owner());
|
||||
// Now that we hold the lock, check to make sure everything is still active.
|
||||
if ((ptr != NULL) && MallocHooksState::Active()) {
|
||||
MallocHooksState::IncrementHeapAllocatedMemoryInBytes(size);
|
||||
MallocHooksState::address_map()->Insert(
|
||||
ptr, new AllocationInfo(reinterpret_cast<uword>(ptr), size));
|
||||
}
|
||||
}
|
||||
|
||||
void MallocHooksState::RecordFreeHook(const void* ptr) {
|
||||
if (MallocHooksState::IsLockHeldByCurrentThread() ||
|
||||
!MallocHooksState::IsOriginalProcess()) {
|
||||
return;
|
||||
}
|
||||
|
||||
MallocLocker ml(MallocHooksState::malloc_hook_mutex(),
|
||||
MallocHooksState::malloc_hook_mutex_owner());
|
||||
// Now that we hold the lock, check to make sure everything is still active.
|
||||
if ((ptr != NULL) && MallocHooksState::Active()) {
|
||||
AllocationInfo* allocation_info = NULL;
|
||||
if (MallocHooksState::address_map()->Lookup(ptr, &allocation_info)) {
|
||||
MallocHooksState::DecrementHeapAllocatedMemoryInBytes(
|
||||
allocation_info->allocation_size());
|
||||
const bool result = MallocHooksState::address_map()->Remove(ptr);
|
||||
ASSERT(result);
|
||||
delete allocation_info;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // defined(DART_USE_TCMALLOC) && !defined(DEBUG)
|
|
@ -1,209 +0,0 @@
|
|||
// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
#include "platform/globals.h"
|
||||
|
||||
#if defined(DART_USE_TCMALLOC) && defined(DEBUG)
|
||||
|
||||
#include "platform/assert.h"
|
||||
#include "vm/globals.h"
|
||||
#include "vm/malloc_hooks.h"
|
||||
#include "vm/os.h"
|
||||
#include "vm/profiler.h"
|
||||
#include "vm/profiler_service.h"
|
||||
#include "vm/unit_test.h"
|
||||
|
||||
namespace dart {
|
||||
|
||||
static void MallocHookTestBufferInitializer(volatile char* buffer,
|
||||
uintptr_t size) {
|
||||
// Run through the buffer and do something. If we don't do this and the memory
|
||||
// in buffer isn't touched, the tcmalloc hooks won't be called.
|
||||
for (uintptr_t i = 0; i < size; ++i) {
|
||||
buffer[i] = i;
|
||||
}
|
||||
}
|
||||
|
||||
class EnableMallocHooksScope : public ValueObject {
|
||||
public:
|
||||
EnableMallocHooksScope() {
|
||||
OSThread::Current(); // Ensure not allocated during test.
|
||||
saved_enable_malloc_hooks_ = FLAG_profiler_native_memory;
|
||||
FLAG_profiler_native_memory = true;
|
||||
MallocHooks::Init();
|
||||
MallocHooks::ResetStats();
|
||||
}
|
||||
|
||||
~EnableMallocHooksScope() {
|
||||
MallocHooks::Cleanup();
|
||||
FLAG_profiler_native_memory = saved_enable_malloc_hooks_;
|
||||
}
|
||||
|
||||
private:
|
||||
bool saved_enable_malloc_hooks_;
|
||||
};
|
||||
|
||||
class EnableMallocHooksAndStacksScope : public EnableMallocHooksScope {
|
||||
public:
|
||||
EnableMallocHooksAndStacksScope() {
|
||||
OSThread::Current(); // Ensure not allocated during test.
|
||||
saved_enable_stack_traces_ = MallocHooks::stack_trace_collection_enabled();
|
||||
MallocHooks::set_stack_trace_collection_enabled(true);
|
||||
if (!FLAG_profiler) {
|
||||
FLAG_profiler = true;
|
||||
Profiler::Init();
|
||||
}
|
||||
MallocHooks::ResetStats();
|
||||
}
|
||||
|
||||
~EnableMallocHooksAndStacksScope() {
|
||||
MallocHooks::set_stack_trace_collection_enabled(saved_enable_stack_traces_);
|
||||
}
|
||||
|
||||
private:
|
||||
bool saved_enable_stack_traces_;
|
||||
};
|
||||
|
||||
UNIT_TEST_CASE(BasicMallocHookTest) {
|
||||
EnableMallocHooksScope scope;
|
||||
|
||||
EXPECT_EQ(0L, MallocHooks::allocation_count());
|
||||
EXPECT_EQ(0L, MallocHooks::heap_allocated_memory_in_bytes());
|
||||
const intptr_t buffer_size = 10;
|
||||
char* buffer = new char[buffer_size];
|
||||
MallocHookTestBufferInitializer(buffer, buffer_size);
|
||||
|
||||
EXPECT_EQ(1L, MallocHooks::allocation_count());
|
||||
EXPECT_EQ(static_cast<intptr_t>(sizeof(char) * buffer_size),
|
||||
MallocHooks::heap_allocated_memory_in_bytes());
|
||||
|
||||
delete[] buffer;
|
||||
EXPECT_EQ(0L, MallocHooks::allocation_count());
|
||||
EXPECT_EQ(0L, MallocHooks::heap_allocated_memory_in_bytes());
|
||||
}
|
||||
|
||||
UNIT_TEST_CASE(FreeUnseenMemoryMallocHookTest) {
|
||||
EnableMallocHooksScope scope;
|
||||
|
||||
const intptr_t pre_hook_buffer_size = 3;
|
||||
char* pre_hook_buffer = new char[pre_hook_buffer_size];
|
||||
MallocHookTestBufferInitializer(pre_hook_buffer, pre_hook_buffer_size);
|
||||
|
||||
MallocHooks::ResetStats();
|
||||
EXPECT_EQ(0L, MallocHooks::allocation_count());
|
||||
EXPECT_EQ(0L, MallocHooks::heap_allocated_memory_in_bytes());
|
||||
|
||||
const intptr_t buffer_size = 10;
|
||||
char* buffer = new char[buffer_size];
|
||||
MallocHookTestBufferInitializer(buffer, buffer_size);
|
||||
|
||||
EXPECT_EQ(1L, MallocHooks::allocation_count());
|
||||
EXPECT_EQ(static_cast<intptr_t>(sizeof(char) * buffer_size),
|
||||
MallocHooks::heap_allocated_memory_in_bytes());
|
||||
|
||||
delete[] pre_hook_buffer;
|
||||
EXPECT_EQ(1L, MallocHooks::allocation_count());
|
||||
EXPECT_EQ(static_cast<intptr_t>(sizeof(char) * buffer_size),
|
||||
MallocHooks::heap_allocated_memory_in_bytes());
|
||||
|
||||
delete[] buffer;
|
||||
EXPECT_EQ(0L, MallocHooks::allocation_count());
|
||||
EXPECT_EQ(0L, MallocHooks::heap_allocated_memory_in_bytes());
|
||||
}
|
||||
|
||||
DART_NOINLINE
|
||||
static void* IgnoreUseAfterFree(void* x) {
|
||||
return x;
|
||||
}
|
||||
|
||||
VM_UNIT_TEST_CASE(StackTraceMallocHookSimpleTest) {
|
||||
EnableMallocHooksAndStacksScope scope;
|
||||
|
||||
char* var = static_cast<char*>(malloc(16 * sizeof(char)));
|
||||
Sample* sample = MallocHooks::GetSample(var);
|
||||
EXPECT(sample != NULL);
|
||||
|
||||
void* lookup_var = IgnoreUseAfterFree(var);
|
||||
free(var);
|
||||
sample = MallocHooks::GetSample(lookup_var);
|
||||
EXPECT(sample == NULL);
|
||||
}
|
||||
|
||||
static char* DART_NOINLINE StackTraceLengthHelper(uintptr_t* end_address) {
|
||||
char* var = static_cast<char*>(malloc(16 * sizeof(char)));
|
||||
*end_address = OS::GetProgramCounter();
|
||||
return var;
|
||||
}
|
||||
|
||||
VM_UNIT_TEST_CASE(StackTraceMallocHookLengthTest) {
|
||||
EnableMallocHooksAndStacksScope scope;
|
||||
|
||||
uintptr_t test_start_address =
|
||||
reinterpret_cast<uintptr_t>(Dart_TestStackTraceMallocHookLengthTest);
|
||||
uintptr_t helper_start_address =
|
||||
reinterpret_cast<uintptr_t>(StackTraceLengthHelper);
|
||||
uintptr_t helper_end_address = 0;
|
||||
|
||||
char* var = StackTraceLengthHelper(&helper_end_address);
|
||||
Sample* sample = MallocHooks::GetSample(var);
|
||||
EXPECT(sample != NULL);
|
||||
uintptr_t test_end_address = OS::GetProgramCounter();
|
||||
|
||||
// Ensure that all stack frames are where we expect them to be in the sample.
|
||||
// If they aren't, the kSkipCount constant in malloc_hooks.cc is likely
|
||||
// incorrect.
|
||||
uword address = sample->At(0);
|
||||
bool first_result =
|
||||
(helper_start_address <= address) && (helper_end_address >= address);
|
||||
EXPECT(first_result);
|
||||
address = sample->At(1);
|
||||
bool second_result =
|
||||
(test_start_address <= address) && (test_end_address >= address);
|
||||
EXPECT(second_result);
|
||||
|
||||
if (!(first_result && second_result)) {
|
||||
OS::PrintErr(
|
||||
"If this test is failing, it's likely that the value set for"
|
||||
" the number of frames to skip in malloc_hooks.cc is "
|
||||
"incorrect for this configuration/platform. This value can be"
|
||||
" found in malloc_hooks.cc in the AllocationInfo class, and "
|
||||
"is stored in the kSkipCount constant.\n");
|
||||
OS::PrintErr("First result: %d Second Result: %d\n", first_result,
|
||||
second_result);
|
||||
OS::PrintErr("Dumping sample stack trace:\n");
|
||||
sample->DumpStackTrace();
|
||||
}
|
||||
|
||||
free(var);
|
||||
}
|
||||
|
||||
ISOLATE_UNIT_TEST_CASE(StackTraceMallocHookSimpleJSONTest) {
|
||||
EnableMallocHooksAndStacksScope scope;
|
||||
|
||||
ClearProfileVisitor cpv(Isolate::Current());
|
||||
Profiler::sample_block_buffer()->VisitSamples(&cpv);
|
||||
|
||||
char* var = static_cast<char*>(malloc(16 * sizeof(char)));
|
||||
JSONStream js;
|
||||
ProfilerService::PrintNativeAllocationJSON(&js, -1, -1, false);
|
||||
const char* json = js.ToCString();
|
||||
|
||||
// Check that all the stack frames from the current down to main are actually
|
||||
// present in the profile. This is just a simple sanity check to make sure
|
||||
// that the ProfileTrie has a representation of the stack trace collected when
|
||||
// var is allocated. More intense testing is already done in profiler_test.cc.
|
||||
// This is brittle: inlining and ICF in the C compiler and linker will affect
|
||||
// the frames we see.
|
||||
EXPECT_SUBSTRING("\"dart::Dart_TestStackTraceMallocHookSimpleJSONTest()\"",
|
||||
json);
|
||||
EXPECT_SUBSTRING("\"dart::TestCase::Run()\"", json);
|
||||
EXPECT_SUBSTRING("\"dart::TestCaseBase::RunTest()\"", json);
|
||||
EXPECT_SUBSTRING("\"main\"", json);
|
||||
|
||||
free(var);
|
||||
}
|
||||
|
||||
}; // namespace dart
|
||||
|
||||
#endif // defined(DART_USE_TCMALLOC) && !defined(DEBUG)
|
|
@ -1,92 +0,0 @@
|
|||
// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
#include "platform/globals.h"
|
||||
|
||||
#if !defined(DEBUG) || !defined(DART_USE_TCMALLOC)
|
||||
|
||||
#include "vm/malloc_hooks.h"
|
||||
|
||||
#include "vm/json_stream.h"
|
||||
|
||||
#if defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_ANDROID)
|
||||
#include <malloc.h>
|
||||
#elif defined(DART_HOST_OS_MACOS)
|
||||
#include <malloc/malloc.h>
|
||||
#endif
|
||||
|
||||
#if !defined(DART_HOST_OS_WINDOWS) && !defined(DART_HOST_OS_MACOS)
|
||||
extern "C" {
|
||||
__attribute__((weak)) uintptr_t __sanitizer_get_current_allocated_bytes();
|
||||
__attribute__((weak)) uintptr_t __sanitizer_get_heap_size();
|
||||
__attribute__((weak)) int __sanitizer_install_malloc_and_free_hooks(
|
||||
void (*malloc_hook)(const void*, uintptr_t),
|
||||
void (*free_hook)(const void*));
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace dart {
|
||||
|
||||
void MallocHooks::Init() {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
void MallocHooks::Cleanup() {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
bool MallocHooks::ProfilingEnabled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MallocHooks::stack_trace_collection_enabled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
void MallocHooks::set_stack_trace_collection_enabled(bool enabled) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
void MallocHooks::ResetStats() {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
bool MallocHooks::Active() {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MallocHooks::GetStats(intptr_t* used,
|
||||
intptr_t* capacity,
|
||||
const char** implementation) {
|
||||
#if !defined(PRODUCT)
|
||||
#if !defined(DART_HOST_OS_WINDOWS) && !defined(DART_HOST_OS_MACOS)
|
||||
if (__sanitizer_get_current_allocated_bytes != nullptr &&
|
||||
__sanitizer_get_heap_size != nullptr) {
|
||||
*used = __sanitizer_get_current_allocated_bytes();
|
||||
*capacity = __sanitizer_get_heap_size();
|
||||
*implementation = "scudo";
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
Sample* MallocHooks::GetSample(const void* ptr) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
intptr_t MallocHooks::allocation_count() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
intptr_t MallocHooks::heap_allocated_memory_in_bytes() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // !defined(DART_USE_TCMALLOC) && ...
|
|
@ -1,21 +0,0 @@
|
|||
// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
#include "vm/malloc_hooks.h"
|
||||
|
||||
#include "vm/globals.h"
|
||||
|
||||
#if defined(HOST_ARCH_X64)
|
||||
|
||||
namespace dart {
|
||||
|
||||
#if defined(DEBUG)
|
||||
const intptr_t kSkipCount = 6;
|
||||
#elif !(defined(PRODUCT) || defined(DEBUG))
|
||||
const intptr_t kSkipCount = 5;
|
||||
#endif
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // defined(HOST_ARCH_X64)
|
|
@ -24,7 +24,6 @@
|
|||
#include "vm/debugger_api_impl_test.h"
|
||||
#include "vm/flags.h"
|
||||
#include "vm/isolate.h"
|
||||
#include "vm/malloc_hooks.h"
|
||||
#include "vm/message_handler.h"
|
||||
#include "vm/object.h"
|
||||
#include "vm/object_store.h"
|
||||
|
@ -2783,9 +2782,6 @@ ISOLATE_UNIT_TEST_CASE(Code) {
|
|||
// Test for immutability of generated instructions. The test crashes with a
|
||||
// segmentation fault when writing into it.
|
||||
ISOLATE_UNIT_TEST_CASE_WITH_EXPECTATION(CodeImmutability, "Crash") {
|
||||
bool stack_trace_collection_enabled =
|
||||
MallocHooks::stack_trace_collection_enabled();
|
||||
MallocHooks::set_stack_trace_collection_enabled(false);
|
||||
extern void GenerateIncrement(compiler::Assembler * assembler);
|
||||
compiler::ObjectPoolBuilder object_pool_builder;
|
||||
compiler::Assembler _assembler_(&object_pool_builder);
|
||||
|
@ -2806,8 +2802,6 @@ ISOLATE_UNIT_TEST_CASE_WITH_EXPECTATION(CodeImmutability, "Crash") {
|
|||
// is switched off.
|
||||
FATAL("Test requires --write-protect-code; skip by forcing expected crash");
|
||||
}
|
||||
MallocHooks::set_stack_trace_collection_enabled(
|
||||
stack_trace_collection_enabled);
|
||||
}
|
||||
|
||||
class CodeTestHelper {
|
||||
|
@ -2823,9 +2817,6 @@ class CodeTestHelper {
|
|||
// Test for executability of generated instructions. The test crashes with a
|
||||
// segmentation fault when executing the writeable view.
|
||||
ISOLATE_UNIT_TEST_CASE_WITH_EXPECTATION(CodeExecutability, "Crash") {
|
||||
bool stack_trace_collection_enabled =
|
||||
MallocHooks::stack_trace_collection_enabled();
|
||||
MallocHooks::set_stack_trace_collection_enabled(false);
|
||||
extern void GenerateIncrement(compiler::Assembler * assembler);
|
||||
compiler::ObjectPoolBuilder object_pool_builder;
|
||||
compiler::Assembler _assembler_(&object_pool_builder);
|
||||
|
@ -2859,8 +2850,6 @@ ISOLATE_UNIT_TEST_CASE_WITH_EXPECTATION(CodeExecutability, "Crash") {
|
|||
// is switched off.
|
||||
FATAL("Test requires --dual-map-code; skip by forcing expected crash");
|
||||
}
|
||||
MallocHooks::set_stack_trace_collection_enabled(
|
||||
stack_trace_collection_enabled);
|
||||
}
|
||||
|
||||
// Test for Embedded String object in the instructions.
|
||||
|
|
|
@ -528,7 +528,6 @@ void Profiler::DumpStackTrace(uword sp, uword fp, uword pc, bool for_crash) {
|
|||
|
||||
RelaxedAtomic<bool> Profiler::initialized_ = false;
|
||||
SampleBlockBuffer* Profiler::sample_block_buffer_ = nullptr;
|
||||
AllocationSampleBuffer* Profiler::allocation_sample_buffer_ = nullptr;
|
||||
|
||||
bool SampleBlockProcessor::initialized_ = false;
|
||||
bool SampleBlockProcessor::shutdown_ = false;
|
||||
|
@ -550,7 +549,6 @@ void Profiler::Init() {
|
|||
if (sample_block_buffer_ == nullptr) {
|
||||
intptr_t num_blocks = CalculateSampleBufferCapacity();
|
||||
sample_block_buffer_ = new SampleBlockBuffer(num_blocks);
|
||||
Profiler::InitAllocationSampleBuffer();
|
||||
}
|
||||
ThreadInterrupter::Init();
|
||||
ThreadInterrupter::Startup();
|
||||
|
@ -559,13 +557,6 @@ void Profiler::Init() {
|
|||
initialized_ = true;
|
||||
}
|
||||
|
||||
void Profiler::InitAllocationSampleBuffer() {
|
||||
ASSERT(Profiler::allocation_sample_buffer_ == NULL);
|
||||
if (FLAG_profiler_native_memory) {
|
||||
Profiler::allocation_sample_buffer_ = new AllocationSampleBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
class SampleBlockCleanupVisitor : public IsolateVisitor {
|
||||
public:
|
||||
SampleBlockCleanupVisitor() = default;
|
||||
|
@ -827,81 +818,6 @@ Sample* SampleBlockBuffer::ReserveSampleImpl(Isolate* isolate,
|
|||
return next->ReserveSample();
|
||||
}
|
||||
|
||||
AllocationSampleBuffer::AllocationSampleBuffer(intptr_t capacity) {
|
||||
const intptr_t size =
|
||||
Utils::RoundUp(capacity * sizeof(Sample), VirtualMemory::PageSize());
|
||||
const bool executable = false;
|
||||
const bool compressed = false;
|
||||
memory_ =
|
||||
VirtualMemory::Allocate(size, executable, compressed, "dart-profiler");
|
||||
if (memory_ == NULL) {
|
||||
OUT_OF_MEMORY();
|
||||
}
|
||||
Init(reinterpret_cast<Sample*>(memory_->address()), capacity);
|
||||
free_sample_list_ = nullptr;
|
||||
cursor_ = 0;
|
||||
}
|
||||
|
||||
AllocationSampleBuffer::~AllocationSampleBuffer() {
|
||||
delete memory_;
|
||||
memory_ = nullptr;
|
||||
}
|
||||
|
||||
void AllocationSampleBuffer::FreeAllocationSample(Sample* sample) {
|
||||
MutexLocker ml(&mutex_);
|
||||
while (sample != nullptr) {
|
||||
Sample* next = sample->continuation_sample();
|
||||
sample->Clear();
|
||||
sample->set_next_free(free_sample_list_);
|
||||
free_sample_list_ = sample;
|
||||
sample = next;
|
||||
}
|
||||
}
|
||||
|
||||
intptr_t AllocationSampleBuffer::ReserveSampleSlotLocked() {
|
||||
if (free_sample_list_ != NULL) {
|
||||
Sample* free_sample = free_sample_list_;
|
||||
free_sample_list_ = free_sample->next_free();
|
||||
free_sample->set_next_free(NULL);
|
||||
uint8_t* samples_array_ptr = reinterpret_cast<uint8_t*>(samples_);
|
||||
uint8_t* free_sample_ptr = reinterpret_cast<uint8_t*>(free_sample);
|
||||
return static_cast<intptr_t>((free_sample_ptr - samples_array_ptr) /
|
||||
sizeof(Sample));
|
||||
} else if (cursor_ < static_cast<intptr_t>(capacity_ - 1)) {
|
||||
return cursor_ += 1;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
Sample* AllocationSampleBuffer::ReserveSampleAndLink(Sample* previous) {
|
||||
MutexLocker ml(&mutex_);
|
||||
ASSERT(previous != NULL);
|
||||
intptr_t next_index = ReserveSampleSlotLocked();
|
||||
if (next_index < 0) {
|
||||
// Could not find a free sample.
|
||||
return NULL;
|
||||
}
|
||||
Sample* next = At(next_index);
|
||||
next->Init(previous->port(), previous->timestamp(), previous->tid());
|
||||
next->set_native_allocation_address(previous->native_allocation_address());
|
||||
next->set_native_allocation_size_bytes(
|
||||
previous->native_allocation_size_bytes());
|
||||
next->set_head_sample(false);
|
||||
// Mark that previous continues at next.
|
||||
previous->SetContinuation(next);
|
||||
return next;
|
||||
}
|
||||
|
||||
Sample* AllocationSampleBuffer::ReserveSample() {
|
||||
MutexLocker ml(&mutex_);
|
||||
intptr_t index = ReserveSampleSlotLocked();
|
||||
if (index < 0) {
|
||||
return NULL;
|
||||
}
|
||||
return At(index);
|
||||
}
|
||||
|
||||
// Attempts to find the true return address when a Dart frame is being setup
|
||||
// or torn down.
|
||||
// NOTE: Architecture specific implementations below.
|
||||
|
@ -1301,27 +1217,6 @@ static Sample* SetupSample(Thread* thread,
|
|||
return sample;
|
||||
}
|
||||
|
||||
static Sample* SetupSampleNative(AllocationSampleBuffer* sample_buffer,
|
||||
ThreadId tid) {
|
||||
Sample* sample = sample_buffer->ReserveSample();
|
||||
if (sample == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
sample->Init(ILLEGAL_PORT, OS::GetCurrentMonotonicMicros(), tid);
|
||||
Thread* thread = Thread::Current();
|
||||
|
||||
// Note: setting thread task in order to be consistent with other samples. The
|
||||
// task kind is not used by NativeAllocationSampleFilter for filtering
|
||||
// purposes as some samples may be collected when no thread exists.
|
||||
if (thread != NULL) {
|
||||
sample->set_thread_task(thread->task_kind());
|
||||
sample->set_vm_tag(thread->vm_tag());
|
||||
} else {
|
||||
sample->set_vm_tag(VMTag::kEmbedderTagId);
|
||||
}
|
||||
return sample;
|
||||
}
|
||||
|
||||
static bool CheckIsolate(Isolate* isolate) {
|
||||
if ((isolate == NULL) || (Dart::vm_isolate() == NULL)) {
|
||||
// No isolate.
|
||||
|
@ -1392,53 +1287,6 @@ void Profiler::SampleAllocation(Thread* thread,
|
|||
}
|
||||
}
|
||||
|
||||
Sample* Profiler::SampleNativeAllocation(intptr_t skip_count,
|
||||
uword address,
|
||||
uintptr_t allocation_size) {
|
||||
AllocationSampleBuffer* sample_buffer = Profiler::allocation_sample_buffer();
|
||||
if (sample_buffer == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uintptr_t sp = OSThread::GetCurrentStackPointer();
|
||||
uintptr_t fp = 0;
|
||||
uintptr_t pc = OS::GetProgramCounter();
|
||||
|
||||
COPY_FP_REGISTER(fp);
|
||||
|
||||
uword stack_lower = 0;
|
||||
uword stack_upper = 0;
|
||||
if (!(OSThread::GetCurrentStackBounds(&stack_lower, &stack_upper) &&
|
||||
ValidateThreadStackBounds(fp, sp, stack_lower, stack_upper))) {
|
||||
// Could not get stack boundary.
|
||||
counters_.failure_native_allocation_sample.fetch_add(1);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
OSThread* os_thread = OSThread::Current();
|
||||
Sample* sample = SetupSampleNative(sample_buffer, os_thread->trace_id());
|
||||
if (sample == NULL) {
|
||||
OS::PrintErr(
|
||||
"Native memory profile sample buffer is full because there are more "
|
||||
"than %" Pd
|
||||
" outstanding allocations. Not recording allocation "
|
||||
"0x%" Px " with size: %" Pu " bytes.\n",
|
||||
sample_buffer->capacity(), address, allocation_size);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sample->set_native_allocation_address(address);
|
||||
sample->set_native_allocation_size_bytes(allocation_size);
|
||||
|
||||
ProfilerNativeStackWalker native_stack_walker(
|
||||
&counters_, ILLEGAL_PORT, sample, sample_buffer, stack_lower, stack_upper,
|
||||
pc, fp, sp, skip_count);
|
||||
|
||||
native_stack_walker.walk();
|
||||
|
||||
return sample;
|
||||
}
|
||||
|
||||
void Profiler::SampleThreadSingleFrame(Thread* thread,
|
||||
Sample* sample,
|
||||
uintptr_t pc) {
|
||||
|
@ -1752,8 +1600,6 @@ ProcessedSample* SampleBuffer::BuildProcessedSample(
|
|||
ProcessedSample* processed_sample = new (zone) ProcessedSample();
|
||||
|
||||
// Copy state bits from sample.
|
||||
processed_sample->set_native_allocation_size_bytes(
|
||||
sample->native_allocation_size_bytes());
|
||||
processed_sample->set_timestamp(sample->timestamp());
|
||||
processed_sample->set_tid(sample->tid());
|
||||
processed_sample->set_vm_tag(sample->vm_tag());
|
||||
|
@ -1814,9 +1660,7 @@ ProcessedSample::ProcessedSample()
|
|||
user_tag_(0),
|
||||
allocation_cid_(-1),
|
||||
allocation_identity_hash_(0),
|
||||
truncated_(false),
|
||||
timeline_code_trie_(nullptr),
|
||||
timeline_function_trie_(nullptr) {}
|
||||
truncated_(false) {}
|
||||
|
||||
void ProcessedSample::FixupCaller(const CodeLookupTable& clt,
|
||||
uword pc_marker,
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
#include "vm/code_observers.h"
|
||||
#include "vm/globals.h"
|
||||
#include "vm/growable_array.h"
|
||||
#include "vm/malloc_hooks.h"
|
||||
#include "vm/native_symbol.h"
|
||||
#include "vm/object.h"
|
||||
#include "vm/tags.h"
|
||||
|
@ -28,9 +27,7 @@ class ProcessedSample;
|
|||
class ProcessedSampleBuffer;
|
||||
|
||||
class Sample;
|
||||
class AllocationSampleBuffer;
|
||||
class SampleBlock;
|
||||
class ProfileTrieNode;
|
||||
|
||||
#define PROFILER_COUNTERS(V) \
|
||||
V(bail_out_unknown_task) \
|
||||
|
@ -45,7 +42,6 @@ class ProfileTrieNode;
|
|||
V(incomplete_sample_fp_bounds) \
|
||||
V(incomplete_sample_fp_step) \
|
||||
V(incomplete_sample_bad_pc) \
|
||||
V(failure_native_allocation_sample) \
|
||||
V(sample_allocation_failure)
|
||||
|
||||
struct ProfilerCounters {
|
||||
|
@ -57,7 +53,6 @@ struct ProfilerCounters {
|
|||
class Profiler : public AllStatic {
|
||||
public:
|
||||
static void Init();
|
||||
static void InitAllocationSampleBuffer();
|
||||
static void Cleanup();
|
||||
|
||||
static void SetSampleDepth(intptr_t depth);
|
||||
|
@ -75,9 +70,6 @@ class Profiler : public AllStatic {
|
|||
static void set_sample_block_buffer(SampleBlockBuffer* buffer) {
|
||||
sample_block_buffer_ = buffer;
|
||||
}
|
||||
static AllocationSampleBuffer* allocation_sample_buffer() {
|
||||
return allocation_sample_buffer_;
|
||||
}
|
||||
|
||||
static void DumpStackTrace(void* context);
|
||||
static void DumpStackTrace(bool for_crash = true);
|
||||
|
@ -85,9 +77,6 @@ class Profiler : public AllStatic {
|
|||
static void SampleAllocation(Thread* thread,
|
||||
intptr_t cid,
|
||||
uint32_t identity_hash);
|
||||
static Sample* SampleNativeAllocation(intptr_t skip_count,
|
||||
uword address,
|
||||
uintptr_t allocation_size);
|
||||
|
||||
// SampleThread is called from inside the signal handler and hence it is very
|
||||
// critical that the implementation of SampleThread does not do any of the
|
||||
|
@ -125,7 +114,6 @@ class Profiler : public AllStatic {
|
|||
static RelaxedAtomic<bool> initialized_;
|
||||
|
||||
static SampleBlockBuffer* sample_block_buffer_;
|
||||
static AllocationSampleBuffer* allocation_sample_buffer_;
|
||||
|
||||
static ProfilerCounters counters_;
|
||||
|
||||
|
@ -236,11 +224,6 @@ class Sample {
|
|||
state_ = 0;
|
||||
next_ = nullptr;
|
||||
allocation_identity_hash_ = 0;
|
||||
#if defined(DART_USE_TCMALLOC) && defined(DEBUG)
|
||||
native_allocation_address_ = 0;
|
||||
native_allocation_size_bytes_ = 0;
|
||||
next_free_ = NULL;
|
||||
#endif
|
||||
set_head_sample(true);
|
||||
}
|
||||
|
||||
|
@ -336,32 +319,6 @@ class Sample {
|
|||
allocation_identity_hash_ = hash;
|
||||
}
|
||||
|
||||
#if defined(DART_USE_TCMALLOC) && defined(DEBUG)
|
||||
uword native_allocation_address() const { return native_allocation_address_; }
|
||||
void set_native_allocation_address(uword address) {
|
||||
native_allocation_address_ = address;
|
||||
}
|
||||
|
||||
uintptr_t native_allocation_size_bytes() const {
|
||||
return native_allocation_size_bytes_;
|
||||
}
|
||||
void set_native_allocation_size_bytes(uintptr_t size) {
|
||||
native_allocation_size_bytes_ = size;
|
||||
}
|
||||
|
||||
Sample* next_free() const { return next_free_; }
|
||||
void set_next_free(Sample* next_free) { next_free_ = next_free; }
|
||||
#else
|
||||
uword native_allocation_address() const { return 0; }
|
||||
void set_native_allocation_address(uword address) { UNREACHABLE(); }
|
||||
|
||||
uintptr_t native_allocation_size_bytes() const { return 0; }
|
||||
void set_native_allocation_size_bytes(uintptr_t size) { UNREACHABLE(); }
|
||||
|
||||
Sample* next_free() const { return nullptr; }
|
||||
void set_next_free(Sample* next_free) { UNREACHABLE(); }
|
||||
#endif // defined(DART_USE_TCMALLOC) && defined(DEBUG)
|
||||
|
||||
Thread::TaskKind thread_task() const { return ThreadTaskBit::decode(state_); }
|
||||
|
||||
void set_thread_task(Thread::TaskKind task) {
|
||||
|
@ -450,36 +407,9 @@ class Sample {
|
|||
Sample* next_;
|
||||
uint32_t allocation_identity_hash_;
|
||||
|
||||
#if defined(DART_USE_TCMALLOC) && defined(DEBUG)
|
||||
uword native_allocation_address_;
|
||||
uintptr_t native_allocation_size_bytes_;
|
||||
Sample* next_free_;
|
||||
#endif
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Sample);
|
||||
};
|
||||
|
||||
class NativeAllocationSampleFilter : public SampleFilter {
|
||||
public:
|
||||
NativeAllocationSampleFilter(int64_t time_origin_micros,
|
||||
int64_t time_extent_micros)
|
||||
: SampleFilter(ILLEGAL_PORT,
|
||||
SampleFilter::kNoTaskFilter,
|
||||
time_origin_micros,
|
||||
time_extent_micros) {}
|
||||
|
||||
bool FilterSample(Sample* sample) {
|
||||
// If the sample is an allocation sample, we need to check that the
|
||||
// memory at the address hasn't been freed, and if the address associated
|
||||
// with the allocation has been freed and then reissued.
|
||||
void* alloc_address =
|
||||
reinterpret_cast<void*>(sample->native_allocation_address());
|
||||
ASSERT(alloc_address != NULL);
|
||||
Sample* recorded_sample = MallocHooks::GetSample(alloc_address);
|
||||
return (sample == recorded_sample);
|
||||
}
|
||||
};
|
||||
|
||||
class AbstractCode {
|
||||
public:
|
||||
explicit AbstractCode(ObjectPtr code) : code_(Object::Handle(code)) {
|
||||
|
@ -887,35 +817,11 @@ class StreamingSampleBufferBuilder : public ProcessedSampleBufferBuilder {
|
|||
DISALLOW_COPY_AND_ASSIGN(StreamingSampleBufferBuilder);
|
||||
};
|
||||
|
||||
class AllocationSampleBuffer : public SampleBuffer {
|
||||
public:
|
||||
explicit AllocationSampleBuffer(intptr_t capacity = 60000);
|
||||
virtual ~AllocationSampleBuffer();
|
||||
|
||||
virtual Sample* ReserveSample();
|
||||
virtual Sample* ReserveSampleAndLink(Sample* previous);
|
||||
void FreeAllocationSample(Sample* sample);
|
||||
|
||||
intptr_t Size() { return memory_->size(); }
|
||||
|
||||
private:
|
||||
intptr_t ReserveSampleSlotLocked();
|
||||
|
||||
Mutex mutex_;
|
||||
Sample* free_sample_list_;
|
||||
VirtualMemory* memory_;
|
||||
RelaxedAtomic<int> cursor_ = 0;
|
||||
DISALLOW_COPY_AND_ASSIGN(AllocationSampleBuffer);
|
||||
};
|
||||
|
||||
intptr_t Profiler::Size() {
|
||||
intptr_t size = 0;
|
||||
if (sample_block_buffer_ != nullptr) {
|
||||
size += sample_block_buffer_->Size();
|
||||
}
|
||||
if (allocation_sample_buffer_ != nullptr) {
|
||||
size += allocation_sample_buffer_->Size();
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
|
@ -972,17 +878,6 @@ class ProcessedSample : public ZoneAllocated {
|
|||
|
||||
bool IsAllocationSample() const { return allocation_cid_ > 0; }
|
||||
|
||||
bool is_native_allocation_sample() const {
|
||||
return native_allocation_size_bytes_ != 0;
|
||||
}
|
||||
|
||||
uintptr_t native_allocation_size_bytes() const {
|
||||
return native_allocation_size_bytes_;
|
||||
}
|
||||
void set_native_allocation_size_bytes(uintptr_t allocation_size) {
|
||||
native_allocation_size_bytes_ = allocation_size;
|
||||
}
|
||||
|
||||
// Was the stack trace truncated?
|
||||
bool truncated() const { return truncated_; }
|
||||
void set_truncated(bool truncated) { truncated_ = truncated; }
|
||||
|
@ -993,20 +888,6 @@ class ProcessedSample : public ZoneAllocated {
|
|||
first_frame_executing_ = first_frame_executing;
|
||||
}
|
||||
|
||||
ProfileTrieNode* timeline_code_trie() const { return timeline_code_trie_; }
|
||||
void set_timeline_code_trie(ProfileTrieNode* trie) {
|
||||
ASSERT(timeline_code_trie_ == NULL);
|
||||
timeline_code_trie_ = trie;
|
||||
}
|
||||
|
||||
ProfileTrieNode* timeline_function_trie() const {
|
||||
return timeline_function_trie_;
|
||||
}
|
||||
void set_timeline_function_trie(ProfileTrieNode* trie) {
|
||||
ASSERT(timeline_function_trie_ == NULL);
|
||||
timeline_function_trie_ = trie;
|
||||
}
|
||||
|
||||
private:
|
||||
void FixupCaller(const CodeLookupTable& clt,
|
||||
uword pc_marker,
|
||||
|
@ -1026,10 +907,6 @@ class ProcessedSample : public ZoneAllocated {
|
|||
uint32_t allocation_identity_hash_;
|
||||
bool truncated_;
|
||||
bool first_frame_executing_;
|
||||
uword native_allocation_address_;
|
||||
uintptr_t native_allocation_size_bytes_;
|
||||
ProfileTrieNode* timeline_code_trie_;
|
||||
ProfileTrieNode* timeline_function_trie_;
|
||||
|
||||
friend class SampleBuffer;
|
||||
DISALLOW_COPY_AND_ASSIGN(ProcessedSample);
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
#include "vm/hash_map.h"
|
||||
#include "vm/heap/safepoint.h"
|
||||
#include "vm/log.h"
|
||||
#include "vm/malloc_hooks.h"
|
||||
#include "vm/native_symbol.h"
|
||||
#include "vm/object.h"
|
||||
#include "vm/os.h"
|
||||
|
@ -1698,10 +1697,6 @@ void Profile::PrintSamplesJSON(JSONObject* obj, bool code_samples) {
|
|||
if (sample->truncated()) {
|
||||
sample_obj.AddProperty("truncated", true);
|
||||
}
|
||||
if (sample->is_native_allocation_sample()) {
|
||||
sample_obj.AddProperty64("_nativeAllocationSizeBytes",
|
||||
sample->native_allocation_size_bytes());
|
||||
}
|
||||
{
|
||||
JSONArray stack(&sample_obj, "stack");
|
||||
// Walk the sampled PCs.
|
||||
|
@ -1882,16 +1877,6 @@ void ProfilerService::PrintAllocationJSON(JSONStream* stream,
|
|||
PrintJSONImpl(thread, stream, &filter, Profiler::sample_block_buffer(), true);
|
||||
}
|
||||
|
||||
void ProfilerService::PrintNativeAllocationJSON(JSONStream* stream,
|
||||
int64_t time_origin_micros,
|
||||
int64_t time_extent_micros,
|
||||
bool include_code_samples) {
|
||||
Thread* thread = Thread::Current();
|
||||
NativeAllocationSampleFilter filter(time_origin_micros, time_extent_micros);
|
||||
PrintJSONImpl(thread, stream, &filter, Profiler::allocation_sample_buffer(),
|
||||
include_code_samples);
|
||||
}
|
||||
|
||||
void ProfilerService::ClearSamples() {
|
||||
SampleBlockBuffer* sample_block_buffer = Profiler::sample_block_buffer();
|
||||
if (sample_block_buffer == nullptr) {
|
||||
|
|
|
@ -438,11 +438,6 @@ class ProfilerService : public AllStatic {
|
|||
int64_t time_origin_micros,
|
||||
int64_t time_extent_micros);
|
||||
|
||||
static void PrintNativeAllocationJSON(JSONStream* stream,
|
||||
int64_t time_origin_micros,
|
||||
int64_t time_extent_micros,
|
||||
bool include_code_samples);
|
||||
|
||||
static void ClearSamples();
|
||||
|
||||
private:
|
||||
|
|
|
@ -538,109 +538,6 @@ ISOLATE_UNIT_TEST_CASE(Profiler_NullSampleBuffer) {
|
|||
EXPECT_EQ(0, profile.sample_count());
|
||||
}
|
||||
|
||||
#if defined(DART_USE_TCMALLOC) && defined(DART_HOST_OS_LINUX) && \
|
||||
defined(DEBUG) && defined(HOST_ARCH_X64)
|
||||
|
||||
DART_NOINLINE static void NativeAllocationSampleHelper(char** result) {
|
||||
ASSERT(result != NULL);
|
||||
*result = static_cast<char*>(malloc(sizeof(char) * 1024));
|
||||
}
|
||||
|
||||
ISOLATE_UNIT_TEST_CASE(Profiler_NativeAllocation) {
|
||||
bool enable_malloc_hooks_saved = FLAG_profiler_native_memory;
|
||||
FLAG_profiler_native_memory = true;
|
||||
|
||||
EnableProfiler();
|
||||
|
||||
MallocHooks::Init();
|
||||
MallocHooks::ResetStats();
|
||||
bool stack_trace_collection_enabled =
|
||||
MallocHooks::stack_trace_collection_enabled();
|
||||
MallocHooks::set_stack_trace_collection_enabled(true);
|
||||
|
||||
char* result = NULL;
|
||||
const int64_t before_allocations_micros = Dart_TimelineGetMicros();
|
||||
NativeAllocationSampleHelper(&result);
|
||||
|
||||
// Disable stack allocation stack trace collection to avoid muddying up
|
||||
// results.
|
||||
MallocHooks::set_stack_trace_collection_enabled(false);
|
||||
const int64_t after_allocations_micros = Dart_TimelineGetMicros();
|
||||
const int64_t allocation_extent_micros =
|
||||
after_allocations_micros - before_allocations_micros;
|
||||
|
||||
// Walk the trie and do a sanity check of the allocation values associated
|
||||
// with each node.
|
||||
{
|
||||
Thread* thread = Thread::Current();
|
||||
StackZone zone(thread);
|
||||
Profile profile;
|
||||
|
||||
// Filter for the class in the time range.
|
||||
NativeAllocationSampleFilter filter(before_allocations_micros,
|
||||
allocation_extent_micros);
|
||||
profile.Build(thread, &filter, Profiler::allocation_sample_buffer());
|
||||
// We should have 1 allocation sample.
|
||||
EXPECT_EQ(1, profile.sample_count());
|
||||
ProfileStackWalker walker(&profile);
|
||||
|
||||
// Move down from the root.
|
||||
EXPECT_SUBSTRING("[Native]", walker.CurrentName());
|
||||
EXPECT_EQ(1024ul, profile.SampleAt(0)->native_allocation_size_bytes());
|
||||
EXPECT(walker.Down());
|
||||
EXPECT_STREQ("dart::Dart_TestProfiler_NativeAllocation()",
|
||||
walker.CurrentName());
|
||||
EXPECT(walker.Down());
|
||||
EXPECT_STREQ("dart::TestCase::Run()", walker.CurrentName());
|
||||
EXPECT(walker.Down());
|
||||
EXPECT_STREQ("dart::TestCaseBase::RunTest()", walker.CurrentName());
|
||||
EXPECT(walker.Down());
|
||||
EXPECT_STREQ("dart::TestCaseBase::RunAll()", walker.CurrentName());
|
||||
EXPECT(walker.Down());
|
||||
EXPECT_SUBSTRING("[Native]", walker.CurrentName());
|
||||
EXPECT(walker.Down());
|
||||
EXPECT_STREQ("main", walker.CurrentName());
|
||||
EXPECT(!walker.Down());
|
||||
}
|
||||
|
||||
MallocHooks::set_stack_trace_collection_enabled(true);
|
||||
free(result);
|
||||
MallocHooks::set_stack_trace_collection_enabled(false);
|
||||
|
||||
// Check to see that the native allocation sample associated with the memory
|
||||
// freed above is marked as free and is no longer reported.
|
||||
{
|
||||
Thread* thread = Thread::Current();
|
||||
StackZone zone(thread);
|
||||
Profile profile;
|
||||
|
||||
// Filter for the class in the time range.
|
||||
NativeAllocationSampleFilter filter(before_allocations_micros,
|
||||
allocation_extent_micros);
|
||||
profile.Build(thread, &filter, Profiler::sample_block_buffer());
|
||||
// We should have 0 allocation samples since we freed the memory.
|
||||
EXPECT_EQ(0, profile.sample_count());
|
||||
}
|
||||
|
||||
// Query with a time filter where no allocations occurred.
|
||||
{
|
||||
Thread* thread = Thread::Current();
|
||||
StackZone zone(thread);
|
||||
Profile profile;
|
||||
NativeAllocationSampleFilter filter(Dart_TimelineGetMicros(), 16000);
|
||||
profile.Build(thread, &filter, Profiler::sample_block_buffer());
|
||||
// We should have no allocation samples because none occurred within
|
||||
// the specified time range.
|
||||
EXPECT_EQ(0, profile.sample_count());
|
||||
}
|
||||
|
||||
MallocHooks::set_stack_trace_collection_enabled(
|
||||
stack_trace_collection_enabled);
|
||||
FLAG_profiler_native_memory = enable_malloc_hooks_saved;
|
||||
}
|
||||
#endif // defined(DART_USE_TCMALLOC) && defined(DART_HOST_OS_LINUX) && \
|
||||
// defined(DEBUG) && defined(HOST_ARCH_X64)
|
||||
|
||||
ISOLATE_UNIT_TEST_CASE(Profiler_ToggleRecordAllocation) {
|
||||
EnableProfiler();
|
||||
|
||||
|
|
|
@ -27,7 +27,6 @@
|
|||
#include "vm/isolate.h"
|
||||
#include "vm/kernel_isolate.h"
|
||||
#include "vm/lockers.h"
|
||||
#include "vm/malloc_hooks.h"
|
||||
#include "vm/message.h"
|
||||
#include "vm/message_handler.h"
|
||||
#include "vm/message_snapshot.h"
|
||||
|
@ -535,18 +534,6 @@ static bool CheckProfilerDisabled(Thread* thread, JSONStream* js) {
|
|||
return false;
|
||||
}
|
||||
|
||||
static bool CheckNativeAllocationProfilerDisabled(Thread* thread,
|
||||
JSONStream* js) {
|
||||
if (CheckProfilerDisabled(thread, js)) {
|
||||
return true;
|
||||
}
|
||||
if (!FLAG_profiler_native_memory) {
|
||||
js->PrintError(kFeatureDisabled, "Native memory profiling is disabled.");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool GetIntegerId(const char* s, intptr_t* id, int base = 10) {
|
||||
if ((s == NULL) || (*s == '\0')) {
|
||||
// Empty string.
|
||||
|
@ -4476,30 +4463,6 @@ static void GetAllocationTraces(Thread* thread, JSONStream* js) {
|
|||
}
|
||||
}
|
||||
|
||||
static const MethodParameter* const get_native_allocation_samples_params[] = {
|
||||
NO_ISOLATE_PARAMETER,
|
||||
new Int64Parameter("timeOriginMicros", false),
|
||||
new Int64Parameter("timeExtentMicros", false),
|
||||
NULL,
|
||||
};
|
||||
|
||||
static void GetNativeAllocationSamples(Thread* thread, JSONStream* js) {
|
||||
int64_t time_origin_micros =
|
||||
Int64Parameter::Parse(js->LookupParam("timeOriginMicros"));
|
||||
int64_t time_extent_micros =
|
||||
Int64Parameter::Parse(js->LookupParam("timeExtentMicros"));
|
||||
bool include_code_samples =
|
||||
BoolParameter::Parse(js->LookupParam("_code"), false);
|
||||
#if defined(DEBUG)
|
||||
IsolateGroup::Current()->heap()->CollectAllGarbage(GCReason::kDebugging);
|
||||
#endif
|
||||
if (CheckNativeAllocationProfilerDisabled(thread, js)) {
|
||||
return;
|
||||
}
|
||||
ProfilerService::PrintNativeAllocationJSON(
|
||||
js, time_origin_micros, time_extent_micros, include_code_samples);
|
||||
}
|
||||
|
||||
static const MethodParameter* const clear_cpu_samples_params[] = {
|
||||
RUNNABLE_ISOLATE_PARAMETER,
|
||||
NULL,
|
||||
|
@ -4776,35 +4739,6 @@ static intptr_t GetProcessMemoryUsageHelper(JSONStream* js) {
|
|||
vm.AddProperty64("size", vm_size);
|
||||
}
|
||||
|
||||
// On Android, malloc is better labeled by /proc/self/smaps.
|
||||
#if !defined(DART_HOST_OS_ANDROID)
|
||||
intptr_t used, capacity;
|
||||
const char* implementation;
|
||||
if (MallocHooks::GetStats(&used, &capacity, &implementation)) {
|
||||
JSONObject malloc(&rss_children);
|
||||
malloc.AddPropertyF("name", "Malloc (%s)", implementation);
|
||||
malloc.AddProperty("description", "");
|
||||
malloc.AddProperty64("size", capacity);
|
||||
JSONArray malloc_children(&malloc, "children");
|
||||
|
||||
{
|
||||
JSONObject malloc_used(&malloc_children);
|
||||
malloc_used.AddProperty("name", "Used");
|
||||
malloc_used.AddProperty("description", "");
|
||||
malloc_used.AddProperty64("size", used);
|
||||
JSONArray(&malloc_used, "children");
|
||||
}
|
||||
|
||||
{
|
||||
JSONObject malloc_free(&malloc_children);
|
||||
malloc_free.AddProperty("name", "Free");
|
||||
malloc_free.AddProperty("description", "");
|
||||
malloc_free.AddProperty64("size", capacity - used);
|
||||
JSONArray(&malloc_free, "children");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_ANDROID)
|
||||
AddVMMappings(&rss_children);
|
||||
#endif
|
||||
|
@ -5292,15 +5226,6 @@ void Service::PrintJSONForVM(JSONStream* js, bool ref) {
|
|||
jsobj.AddProperty64("pid", OS::ProcessId());
|
||||
jsobj.AddPropertyTimeMillis(
|
||||
"startTime", OS::GetCurrentTimeMillis() - Dart::UptimeMillis());
|
||||
{
|
||||
intptr_t used, capacity;
|
||||
const char* implementation;
|
||||
if (MallocHooks::GetStats(&used, &capacity, &implementation)) {
|
||||
jsobj.AddProperty("_mallocUsed", used);
|
||||
jsobj.AddProperty("_mallocCapacity", capacity);
|
||||
jsobj.AddProperty("_mallocImplementation", implementation);
|
||||
}
|
||||
}
|
||||
PrintJSONForEmbedderInformation(&jsobj);
|
||||
// Construct the isolate and isolate_groups list.
|
||||
{
|
||||
|
@ -5872,8 +5797,6 @@ static const ServiceMethodDescriptor service_methods_[] = {
|
|||
get_allocation_profile_params },
|
||||
{ "getAllocationTraces", GetAllocationTraces,
|
||||
get_allocation_traces_params },
|
||||
{ "_getNativeAllocationSamples", GetNativeAllocationSamples,
|
||||
get_native_allocation_samples_params },
|
||||
{ "getClassList", GetClassList,
|
||||
get_class_list_params },
|
||||
{ "getCpuSamples", GetCpuSamples,
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
#include "vm/dart_api_state.h"
|
||||
#include "vm/debugger_api_impl_test.h"
|
||||
#include "vm/flags.h"
|
||||
#include "vm/malloc_hooks.h"
|
||||
#include "vm/message_snapshot.h"
|
||||
#include "vm/snapshot.h"
|
||||
#include "vm/symbols.h"
|
||||
|
|
|
@ -161,14 +161,6 @@ vm_sources = [
|
|||
"log.h",
|
||||
"longjump.cc",
|
||||
"longjump.h",
|
||||
"malloc_hooks.h",
|
||||
"malloc_hooks_arm.cc",
|
||||
"malloc_hooks_arm64.cc",
|
||||
"malloc_hooks_ia32.cc",
|
||||
"malloc_hooks_riscv.cc",
|
||||
"malloc_hooks_tcmalloc.cc",
|
||||
"malloc_hooks_unsupported.cc",
|
||||
"malloc_hooks_x64.cc",
|
||||
"megamorphic_cache_table.cc",
|
||||
"megamorphic_cache_table.h",
|
||||
"memory_region.cc",
|
||||
|
@ -426,7 +418,6 @@ vm_sources_tests = [
|
|||
"kernel_test.cc",
|
||||
"log_test.cc",
|
||||
"longjump_test.cc",
|
||||
"malloc_hooks_test.cc",
|
||||
"memory_region_test.cc",
|
||||
"message_handler_test.cc",
|
||||
"message_test.cc",
|
||||
|
|
3
third_party/tcmalloc/.gitignore
vendored
3
third_party/tcmalloc/.gitignore
vendored
|
@ -1,3 +0,0 @@
|
|||
*.mk
|
||||
*.Makefile
|
||||
/gperftools
|
137
third_party/tcmalloc/BUILD.gn
vendored
137
third_party/tcmalloc/BUILD.gn
vendored
|
@ -1,137 +0,0 @@
|
|||
# Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
|
||||
# for details. All rights reserved. Use of this source code is governed by a
|
||||
# BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
import("tcmalloc_sources.gni")
|
||||
|
||||
config("internal_config") {
|
||||
visibility = [ ":*" ] # Only targets in this file can depend on this.
|
||||
cflags = [
|
||||
"-Wall",
|
||||
"-Wextra",
|
||||
"-Wno-format",
|
||||
"-Wno-missing-field-initializers",
|
||||
"-Wno-sign-compare",
|
||||
"-Wno-type-limits",
|
||||
"-Wno-unused-result",
|
||||
"-Wno-unused-parameter",
|
||||
"-Wno-unused-function",
|
||||
"-Wno-unused-but-set-variable",
|
||||
"-Wno-vla",
|
||||
"-g3",
|
||||
"-ggdb3",
|
||||
"-fstack-protector",
|
||||
"-Wa,--noexecstack",
|
||||
"-fno-omit-frame-pointer",
|
||||
"-fno-builtin-malloc",
|
||||
"-fno-builtin-free",
|
||||
"-fno-builtin-realloc",
|
||||
"-fno-builtin-calloc",
|
||||
"-fno-builtin-cfree",
|
||||
"-fno-builtin-memalign",
|
||||
"-fno-builtin-posix_memalign",
|
||||
"-fno-builtin-valloc",
|
||||
"-fno-builtin-pvalloc",
|
||||
"-fsized-deallocation",
|
||||
"-faligned-new",
|
||||
]
|
||||
if (is_clang) {
|
||||
cflags += [
|
||||
"-Wno-unused-const-variable",
|
||||
"-Wno-implicit-int-float-conversion",
|
||||
]
|
||||
}
|
||||
if (current_cpu == "arm" && !is_clang) {
|
||||
cflags += [ "-Wno-psabi" ]
|
||||
}
|
||||
}
|
||||
|
||||
config("link_config") {
|
||||
visibility = [ ":*" ] # Only targets in this file can depend on this.
|
||||
ldflags = [
|
||||
# Don't let linker rip this symbol out, otherwise the heap&cpu
|
||||
# profilers will not initialize properly on startup.
|
||||
"-Wl,-uIsHeapProfilerRunning,-uProfilerStart",
|
||||
]
|
||||
}
|
||||
|
||||
source_set("dynamic_annotations") {
|
||||
configs -= [
|
||||
"//build/config/compiler:chromium_code",
|
||||
"//build/config/compiler:clang_stackrealign",
|
||||
]
|
||||
configs += [ ":internal_config" ]
|
||||
|
||||
include_dirs = [
|
||||
"include",
|
||||
"gperftools/src/base",
|
||||
"gperftools/src",
|
||||
]
|
||||
|
||||
sources = [
|
||||
"gperftools/src/base/dynamic_annotations.c",
|
||||
"gperftools/src/base/dynamic_annotations.h",
|
||||
]
|
||||
}
|
||||
|
||||
source_set("tcmalloc") {
|
||||
configs -= [
|
||||
"//build/config/compiler:chromium_code",
|
||||
"//build/config/compiler:clang_stackrealign",
|
||||
"//build/config/compiler:compiler_arm_thumb",
|
||||
]
|
||||
configs += [ ":internal_config" ]
|
||||
|
||||
public_configs = [ ":link_config" ]
|
||||
|
||||
deps = [ ":dynamic_annotations" ]
|
||||
|
||||
include_dirs = [
|
||||
"include",
|
||||
"gperftools/src/base",
|
||||
"gperftools/src",
|
||||
]
|
||||
|
||||
# Disable the heap checker in tcmalloc.
|
||||
defines = [
|
||||
"ENABLE_EMERGENCY_MALLOC",
|
||||
"NO_HEAP_CHECK",
|
||||
|
||||
# Disable debug even in a Dart Debug build. It is too slow.
|
||||
"NDEBUG",
|
||||
]
|
||||
|
||||
if (is_product) {
|
||||
# Disable stack sampling for heap profiling in Product builds.
|
||||
defines += [ "NO_TCMALLOC_SAMPLES" ]
|
||||
|
||||
# To override the C library functions, we can't hide symbols.
|
||||
configs -= [ "//build/config/gcc:symbol_visibility_hidden" ]
|
||||
}
|
||||
|
||||
cflags = [
|
||||
"-Wnon-virtual-dtor",
|
||||
"-Woverloaded-virtual",
|
||||
"-fno-rtti",
|
||||
"-fpermissive",
|
||||
]
|
||||
|
||||
if (!is_clang) {
|
||||
cflags += [ "-Wno-format" ]
|
||||
}
|
||||
|
||||
sources = tcmalloc_sources - [
|
||||
# No debug allocator.
|
||||
"gperftools/src/debugallocation.cc",
|
||||
|
||||
# Not needed when using emergency malloc.
|
||||
"gperftools/src/fake_stacktrace_scope.cc",
|
||||
|
||||
# Not using the cpuprofiler
|
||||
"gperftools/src/profile-handler.cc",
|
||||
"gperftools/src/profile-handler.h",
|
||||
"gperftools/src/profiledata.cc",
|
||||
"gperftools/src/profiledata.h",
|
||||
"gperftools/src/profiler.cc",
|
||||
]
|
||||
}
|
28
third_party/tcmalloc/COPYING
vendored
28
third_party/tcmalloc/COPYING
vendored
|
@ -1,28 +0,0 @@
|
|||
Copyright (c) 2005, Google Inc.
|
||||
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.
|
1
third_party/tcmalloc/OWNERS
vendored
1
third_party/tcmalloc/OWNERS
vendored
|
@ -1 +0,0 @@
|
|||
file:/tools/OWNERS_VM
|
25
third_party/tcmalloc/README.dart
vendored
25
third_party/tcmalloc/README.dart
vendored
|
@ -1,25 +0,0 @@
|
|||
Dart uses tcmalloc in the standalone VM on Linux.
|
||||
|
||||
To roll tcmalloc forward:
|
||||
. Clone the gperftools git repo at the revision you want in a directory off
|
||||
to the side.
|
||||
|
||||
. Run a configure command similar to the one in the configure_command file in
|
||||
this directory. It is up to you to determine if different flags are required
|
||||
for the newer gperftools.
|
||||
|
||||
. From that repo, copy src/config.h and src/gperftools/tcmalloc.h, and any other
|
||||
generated header files to the include/ directory in this directory.
|
||||
|
||||
. Also copy the COPYING file and any other relevant licensing information.
|
||||
|
||||
. Make sure that include/config.h defines HAVE_UCONTEXT_H on Linux,
|
||||
|
||||
. Update tcmalloc_sources.gypi, and tcmalloc.gyp if necessary. This may require
|
||||
inspecting gperftools/Makefile.am to see any additional source files and
|
||||
preprocessor defines (-D flags).
|
||||
|
||||
. Update the DEPS file with the new git hash.
|
||||
|
||||
. Build and run tests for Debug, Release, and Product builds for ia32, x64,
|
||||
and arm for Linux and any other OSs that are supported.
|
2
third_party/tcmalloc/configure_command
vendored
2
third_party/tcmalloc/configure_command
vendored
|
@ -1,2 +0,0 @@
|
|||
./autogen.sh
|
||||
./configure --enable-emergency-malloc --enable-frame-pointers --disable-cpu-profiler --disable-heap-checker --disable-debugalloc --enable-sized-delete --disable-libunwind
|
282
third_party/tcmalloc/include/config.h
vendored
282
third_party/tcmalloc/include/config.h
vendored
|
@ -1,282 +0,0 @@
|
|||
/* src/config.h. Generated from config.h.in by configure. */
|
||||
/* src/config.h.in. Generated from configure.ac by autoheader. */
|
||||
|
||||
|
||||
#ifndef GPERFTOOLS_CONFIG_H_
|
||||
#define GPERFTOOLS_CONFIG_H_
|
||||
|
||||
|
||||
/* enable aggressive decommit by default */
|
||||
/* #undef ENABLE_AGGRESSIVE_DECOMMIT_BY_DEFAULT */
|
||||
|
||||
/* Build new/delete operators for overaligned types */
|
||||
#define ENABLE_ALIGNED_NEW_DELETE 1
|
||||
|
||||
/* Build runtime detection for sized delete */
|
||||
/* #undef ENABLE_DYNAMIC_SIZED_DELETE */
|
||||
|
||||
/* report large allocation */
|
||||
/* #undef ENABLE_LARGE_ALLOC_REPORT */
|
||||
|
||||
/* Build sized deletion operators */
|
||||
#define ENABLE_SIZED_DELETE 1
|
||||
|
||||
/* Define to 1 if you have the <asm/ptrace.h> header file. */
|
||||
/* #undef HAVE_ASM_PTRACE_H */
|
||||
|
||||
/* Define to 1 if you have the <conflict-signal.h> header file. */
|
||||
/* #undef HAVE_CONFLICT_SIGNAL_H */
|
||||
|
||||
/* define if the compiler supports basic C++11 syntax */
|
||||
#define HAVE_CXX11 1
|
||||
|
||||
/* Define to 1 if you have the <cygwin/signal.h> header file. */
|
||||
/* #undef HAVE_CYGWIN_SIGNAL_H */
|
||||
|
||||
/* Define to 1 if you have the declaration of `backtrace', and to 0 if you
|
||||
don't. */
|
||||
/* #undef HAVE_DECL_BACKTRACE */
|
||||
|
||||
/* Define to 1 if you have the declaration of `cfree', and to 0 if you don't.
|
||||
*/
|
||||
#define HAVE_DECL_CFREE 0
|
||||
|
||||
/* Define to 1 if you have the declaration of `memalign', and to 0 if you
|
||||
don't. */
|
||||
#define HAVE_DECL_MEMALIGN 1
|
||||
|
||||
/* Define to 1 if you have the declaration of `nanosleep', and to 0 if you
|
||||
don't. */
|
||||
/* #undef HAVE_DECL_NANOSLEEP */
|
||||
|
||||
/* Define to 1 if you have the declaration of `posix_memalign', and to 0 if
|
||||
you don't. */
|
||||
#define HAVE_DECL_POSIX_MEMALIGN 1
|
||||
|
||||
/* Define to 1 if you have the declaration of `pvalloc', and to 0 if you
|
||||
don't. */
|
||||
#define HAVE_DECL_PVALLOC 1
|
||||
|
||||
/* Define to 1 if you have the declaration of `sleep', and to 0 if you don't.
|
||||
*/
|
||||
/* #undef HAVE_DECL_SLEEP */
|
||||
|
||||
/* Define to 1 if you have the declaration of `valloc', and to 0 if you don't.
|
||||
*/
|
||||
#define HAVE_DECL_VALLOC 1
|
||||
|
||||
/* Define to 1 if you have the <dlfcn.h> header file. */
|
||||
#define HAVE_DLFCN_H 1
|
||||
|
||||
/* Define to 1 if the system has the type `Elf32_Versym'. */
|
||||
#define HAVE_ELF32_VERSYM 1
|
||||
|
||||
/* Define to 1 if you have the <execinfo.h> header file. */
|
||||
#define HAVE_EXECINFO_H 1
|
||||
|
||||
/* Define to 1 if you have the <fcntl.h> header file. */
|
||||
#define HAVE_FCNTL_H 1
|
||||
|
||||
/* Define to 1 if you have the <features.h> header file. */
|
||||
#define HAVE_FEATURES_H 1
|
||||
|
||||
/* Define to 1 if you have the `fork' function. */
|
||||
#define HAVE_FORK 1
|
||||
|
||||
/* Define to 1 if you have the `geteuid' function. */
|
||||
#define HAVE_GETEUID 1
|
||||
|
||||
/* Define to 1 if you have the <glob.h> header file. */
|
||||
#define HAVE_GLOB_H 1
|
||||
|
||||
/* Define to 1 if you have the <grp.h> header file. */
|
||||
#define HAVE_GRP_H 1
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#define HAVE_INTTYPES_H 1
|
||||
|
||||
/* Define to 1 if you have the <libunwind.h> header file. */
|
||||
/* #undef HAVE_LIBUNWIND_H */
|
||||
|
||||
/* Define to 1 if you have the <linux/ptrace.h> header file. */
|
||||
#define HAVE_LINUX_PTRACE_H 1
|
||||
|
||||
/* Define if this is Linux that has SIGEV_THREAD_ID */
|
||||
#define HAVE_LINUX_SIGEV_THREAD_ID 1
|
||||
|
||||
/* Define to 1 if you have the <malloc.h> header file. */
|
||||
#define HAVE_MALLOC_H 1
|
||||
|
||||
/* Define to 1 if you have a working `mmap' system call. */
|
||||
#define HAVE_MMAP 1
|
||||
|
||||
/* Define to 1 if you have the <poll.h> header file. */
|
||||
#define HAVE_POLL_H 1
|
||||
|
||||
/* define if libc has program_invocation_name */
|
||||
#define HAVE_PROGRAM_INVOCATION_NAME 1
|
||||
|
||||
/* Define if you have POSIX threads libraries and header files. */
|
||||
#define HAVE_PTHREAD 1
|
||||
|
||||
/* defined to 1 if pthread symbols are exposed even without include pthread.h
|
||||
*/
|
||||
/* #undef HAVE_PTHREAD_DESPITE_ASKING_FOR */
|
||||
|
||||
/* Define to 1 if you have the <pwd.h> header file. */
|
||||
#define HAVE_PWD_H 1
|
||||
|
||||
/* Define to 1 if you have the `sbrk' function. */
|
||||
#define HAVE_SBRK 1
|
||||
|
||||
/* Define to 1 if you have the <sched.h> header file. */
|
||||
#define HAVE_SCHED_H 1
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#define HAVE_STDINT_H 1
|
||||
|
||||
/* Define to 1 if you have the <stdio.h> header file. */
|
||||
#define HAVE_STDIO_H 1
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#define HAVE_STDLIB_H 1
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
#define HAVE_STRINGS_H 1
|
||||
|
||||
/* Define to 1 if you have the <string.h> header file. */
|
||||
#define HAVE_STRING_H 1
|
||||
|
||||
/* Define to 1 if the system has the type `struct mallinfo'. */
|
||||
#define HAVE_STRUCT_MALLINFO 1
|
||||
|
||||
/* Define to 1 if you have the <sys/cdefs.h> header file. */
|
||||
#define HAVE_SYS_CDEFS_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/prctl.h> header file. */
|
||||
#define HAVE_SYS_PRCTL_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/resource.h> header file. */
|
||||
#define HAVE_SYS_RESOURCE_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/socket.h> header file. */
|
||||
#define HAVE_SYS_SOCKET_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#define HAVE_SYS_STAT_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/syscall.h> header file. */
|
||||
#define HAVE_SYS_SYSCALL_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#define HAVE_SYS_TYPES_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/ucontext.h> header file. */
|
||||
#define HAVE_SYS_UCONTEXT_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/wait.h> header file. */
|
||||
#define HAVE_SYS_WAIT_H 1
|
||||
|
||||
/* Define to 1 if compiler supports __thread */
|
||||
#define HAVE_TLS 1
|
||||
|
||||
/* Define to 1 if you have the <ucontext.h> header file. */
|
||||
#define HAVE_UCONTEXT_H 1
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#define HAVE_UNISTD_H 1
|
||||
|
||||
/* Whether <unwind.h> contains _Unwind_Backtrace */
|
||||
#define HAVE_UNWIND_BACKTRACE 1
|
||||
|
||||
/* Define to 1 if you have the <unwind.h> header file. */
|
||||
#define HAVE_UNWIND_H 1
|
||||
|
||||
/* define if your compiler has __attribute__ */
|
||||
#define HAVE___ATTRIBUTE__ 1
|
||||
|
||||
/* define if your compiler supports alignment of functions */
|
||||
#define HAVE___ATTRIBUTE__ALIGNED_FN 1
|
||||
|
||||
/* Define to 1 if compiler supports __environ */
|
||||
#define HAVE___ENVIRON 1
|
||||
|
||||
/* Define to 1 if you have the `__sbrk' function. */
|
||||
#define HAVE___SBRK 1
|
||||
|
||||
/* prefix where we look for installed files */
|
||||
#define INSTALL_PREFIX "/usr/local"
|
||||
|
||||
/* Define to 1 if int32_t is equivalent to intptr_t */
|
||||
/* #undef INT32_EQUALS_INTPTR */
|
||||
|
||||
/* Define to the sub-directory where libtool stores uninstalled libraries. */
|
||||
#define LT_OBJDIR ".libs/"
|
||||
|
||||
/* Name of package */
|
||||
#define PACKAGE "gperftools"
|
||||
|
||||
/* Define to the address where bug reports for this package should be sent. */
|
||||
#define PACKAGE_BUGREPORT "gperftools@googlegroups.com"
|
||||
|
||||
/* Define to the full name of this package. */
|
||||
#define PACKAGE_NAME "gperftools"
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#define PACKAGE_STRING "gperftools 2.10"
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#define PACKAGE_TARNAME "gperftools"
|
||||
|
||||
/* Define to the home page for this package. */
|
||||
#define PACKAGE_URL ""
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#define PACKAGE_VERSION "2.10"
|
||||
|
||||
/* How to access the PC from a struct ucontext */
|
||||
/* #undef PC_FROM_UCONTEXT */
|
||||
|
||||
/* Always the empty-string on non-windows systems. On windows, should be
|
||||
"__declspec(dllexport)". This way, when we compile the dll, we export our
|
||||
functions/classes. It's safe to define this here because config.h is only
|
||||
used internally, to compile the DLL, and every DLL source file #includes
|
||||
"config.h" before anything else. */
|
||||
#define PERFTOOLS_DLL_DECL /**/
|
||||
|
||||
/* Mark the systems where we know it's bad if pthreads runs too
|
||||
early before main (before threads are initialized, presumably). */
|
||||
#ifdef __FreeBSD__
|
||||
#define PTHREADS_CRASHES_IF_RUN_TOO_EARLY 1
|
||||
#endif
|
||||
|
||||
/* Define to necessary symbol if this constant uses a non-standard name on
|
||||
your system. */
|
||||
/* #undef PTHREAD_CREATE_JOINABLE */
|
||||
|
||||
/* Define to 1 if all of the C90 standard headers exist (not just the ones
|
||||
required in a freestanding environment). This macro is provided for
|
||||
backward compatibility; new code need not use it. */
|
||||
#define STDC_HEADERS 1
|
||||
|
||||
/* Define 8 bytes of allocation alignment for tcmalloc */
|
||||
/* #undef TCMALLOC_ALIGN_8BYTES */
|
||||
|
||||
/* Define internal page size for tcmalloc as number of left bitshift */
|
||||
/* #undef TCMALLOC_PAGE_SIZE_SHIFT */
|
||||
|
||||
/* Version number of package */
|
||||
#define VERSION "2.10"
|
||||
|
||||
/* C99 says: define this to get the PRI... macros from stdint.h */
|
||||
#ifndef __STDC_FORMAT_MACROS
|
||||
# define __STDC_FORMAT_MACROS 1
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __MINGW32__
|
||||
#include "windows/mingw.h"
|
||||
#endif
|
||||
|
||||
#endif /* #ifndef GPERFTOOLS_CONFIG_H_ */
|
||||
|
163
third_party/tcmalloc/include/gperftools/tcmalloc.h
vendored
163
third_party/tcmalloc/include/gperftools/tcmalloc.h
vendored
|
@ -1,163 +0,0 @@
|
|||
// -*- Mode: C; c-basic-offset: 2; indent-tabs-mode: nil -*-
|
||||
/* Copyright (c) 2003, Google Inc.
|
||||
* 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.
|
||||
*
|
||||
* ---
|
||||
* Author: Sanjay Ghemawat <opensource@google.com>
|
||||
* .h file by Craig Silverstein <opensource@google.com>
|
||||
*/
|
||||
|
||||
#ifndef TCMALLOC_TCMALLOC_H_
|
||||
#define TCMALLOC_TCMALLOC_H_
|
||||
|
||||
#include <stddef.h> /* for size_t */
|
||||
#ifdef __cplusplus
|
||||
#include <new> /* for std::nothrow_t, std::align_val_t */
|
||||
#endif
|
||||
|
||||
/* Define the version number so folks can check against it */
|
||||
#define TC_VERSION_MAJOR 2
|
||||
#define TC_VERSION_MINOR 8
|
||||
#define TC_VERSION_PATCH ""
|
||||
#define TC_VERSION_STRING "gperftools 2.8"
|
||||
|
||||
/* For struct mallinfo, if it's defined. */
|
||||
#if 1
|
||||
# include <malloc.h>
|
||||
#endif
|
||||
|
||||
#ifndef PERFTOOLS_NOTHROW
|
||||
|
||||
#if __cplusplus >= 201103L
|
||||
#define PERFTOOLS_NOTHROW noexcept
|
||||
#elif defined(__cplusplus)
|
||||
#define PERFTOOLS_NOTHROW throw()
|
||||
#else
|
||||
# ifdef __GNUC__
|
||||
# define PERFTOOLS_NOTHROW __attribute__((__nothrow__))
|
||||
# else
|
||||
# define PERFTOOLS_NOTHROW
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef PERFTOOLS_DLL_DECL
|
||||
# ifdef _WIN32
|
||||
# define PERFTOOLS_DLL_DECL __declspec(dllimport)
|
||||
# else
|
||||
# define PERFTOOLS_DLL_DECL
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/*
|
||||
* Returns a human-readable version string. If major, minor,
|
||||
* and/or patch are not NULL, they are set to the major version,
|
||||
* minor version, and patch-code (a string, usually "").
|
||||
*/
|
||||
PERFTOOLS_DLL_DECL const char* tc_version(int* major, int* minor,
|
||||
const char** patch) PERFTOOLS_NOTHROW;
|
||||
|
||||
PERFTOOLS_DLL_DECL void* tc_malloc(size_t size) PERFTOOLS_NOTHROW;
|
||||
PERFTOOLS_DLL_DECL void* tc_malloc_skip_new_handler(size_t size) PERFTOOLS_NOTHROW;
|
||||
PERFTOOLS_DLL_DECL void tc_free(void* ptr) PERFTOOLS_NOTHROW;
|
||||
PERFTOOLS_DLL_DECL void tc_free_sized(void *ptr, size_t size) PERFTOOLS_NOTHROW;
|
||||
PERFTOOLS_DLL_DECL void* tc_realloc(void* ptr, size_t size) PERFTOOLS_NOTHROW;
|
||||
PERFTOOLS_DLL_DECL void* tc_calloc(size_t nmemb, size_t size) PERFTOOLS_NOTHROW;
|
||||
PERFTOOLS_DLL_DECL void tc_cfree(void* ptr) PERFTOOLS_NOTHROW;
|
||||
|
||||
PERFTOOLS_DLL_DECL void* tc_memalign(size_t __alignment,
|
||||
size_t __size) PERFTOOLS_NOTHROW;
|
||||
PERFTOOLS_DLL_DECL int tc_posix_memalign(void** ptr,
|
||||
size_t align, size_t size) PERFTOOLS_NOTHROW;
|
||||
PERFTOOLS_DLL_DECL void* tc_valloc(size_t __size) PERFTOOLS_NOTHROW;
|
||||
PERFTOOLS_DLL_DECL void* tc_pvalloc(size_t __size) PERFTOOLS_NOTHROW;
|
||||
|
||||
PERFTOOLS_DLL_DECL void tc_malloc_stats(void) PERFTOOLS_NOTHROW;
|
||||
PERFTOOLS_DLL_DECL int tc_mallopt(int cmd, int value) PERFTOOLS_NOTHROW;
|
||||
#if 1
|
||||
PERFTOOLS_DLL_DECL struct mallinfo tc_mallinfo(void) PERFTOOLS_NOTHROW;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This is an alias for MallocExtension::instance()->GetAllocatedSize().
|
||||
* It is equivalent to
|
||||
* OS X: malloc_size()
|
||||
* glibc: malloc_usable_size()
|
||||
* Windows: _msize()
|
||||
*/
|
||||
PERFTOOLS_DLL_DECL size_t tc_malloc_size(void* ptr) PERFTOOLS_NOTHROW;
|
||||
|
||||
#ifdef __cplusplus
|
||||
PERFTOOLS_DLL_DECL int tc_set_new_mode(int flag) PERFTOOLS_NOTHROW;
|
||||
PERFTOOLS_DLL_DECL void* tc_new(size_t size);
|
||||
PERFTOOLS_DLL_DECL void* tc_new_nothrow(size_t size,
|
||||
const std::nothrow_t&) PERFTOOLS_NOTHROW;
|
||||
PERFTOOLS_DLL_DECL void tc_delete(void* p) PERFTOOLS_NOTHROW;
|
||||
PERFTOOLS_DLL_DECL void tc_delete_sized(void* p, size_t size) PERFTOOLS_NOTHROW;
|
||||
PERFTOOLS_DLL_DECL void tc_delete_nothrow(void* p,
|
||||
const std::nothrow_t&) PERFTOOLS_NOTHROW;
|
||||
PERFTOOLS_DLL_DECL void* tc_newarray(size_t size);
|
||||
PERFTOOLS_DLL_DECL void* tc_newarray_nothrow(size_t size,
|
||||
const std::nothrow_t&) PERFTOOLS_NOTHROW;
|
||||
PERFTOOLS_DLL_DECL void tc_deletearray(void* p) PERFTOOLS_NOTHROW;
|
||||
PERFTOOLS_DLL_DECL void tc_deletearray_sized(void* p, size_t size) PERFTOOLS_NOTHROW;
|
||||
PERFTOOLS_DLL_DECL void tc_deletearray_nothrow(void* p,
|
||||
const std::nothrow_t&) PERFTOOLS_NOTHROW;
|
||||
|
||||
#if 1 && __cplusplus >= 201703L
|
||||
PERFTOOLS_DLL_DECL void* tc_new_aligned(size_t size, std::align_val_t al);
|
||||
PERFTOOLS_DLL_DECL void* tc_new_aligned_nothrow(size_t size, std::align_val_t al,
|
||||
const std::nothrow_t&) PERFTOOLS_NOTHROW;
|
||||
PERFTOOLS_DLL_DECL void tc_delete_aligned(void* p, std::align_val_t al) PERFTOOLS_NOTHROW;
|
||||
PERFTOOLS_DLL_DECL void tc_delete_sized_aligned(void* p, size_t size, std::align_val_t al) PERFTOOLS_NOTHROW;
|
||||
PERFTOOLS_DLL_DECL void tc_delete_aligned_nothrow(void* p, std::align_val_t al,
|
||||
const std::nothrow_t&) PERFTOOLS_NOTHROW;
|
||||
PERFTOOLS_DLL_DECL void* tc_newarray_aligned(size_t size, std::align_val_t al);
|
||||
PERFTOOLS_DLL_DECL void* tc_newarray_aligned_nothrow(size_t size, std::align_val_t al,
|
||||
const std::nothrow_t&) PERFTOOLS_NOTHROW;
|
||||
PERFTOOLS_DLL_DECL void tc_deletearray_aligned(void* p, std::align_val_t al) PERFTOOLS_NOTHROW;
|
||||
PERFTOOLS_DLL_DECL void tc_deletearray_sized_aligned(void* p, size_t size, std::align_val_t al) PERFTOOLS_NOTHROW;
|
||||
PERFTOOLS_DLL_DECL void tc_deletearray_aligned_nothrow(void* p, std::align_val_t al,
|
||||
const std::nothrow_t&) PERFTOOLS_NOTHROW;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
/* We're only un-defining for public */
|
||||
#if !defined(GPERFTOOLS_CONFIG_H_)
|
||||
|
||||
#undef PERFTOOLS_NOTHROW
|
||||
|
||||
#endif /* GPERFTOOLS_CONFIG_H_ */
|
||||
|
||||
#endif /* #ifndef TCMALLOC_TCMALLOC_H_ */
|
155
third_party/tcmalloc/tcmalloc_sources.gni
vendored
155
third_party/tcmalloc/tcmalloc_sources.gni
vendored
|
@ -1,155 +0,0 @@
|
|||
# Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
|
||||
# for details. All rights reserved. Use of this source code is governed by a
|
||||
# BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
tcmalloc_sources = [
|
||||
# gperftools/src/
|
||||
"gperftools/src/addressmap-inl.h",
|
||||
"gperftools/src/central_freelist.cc",
|
||||
"gperftools/src/central_freelist.h",
|
||||
"gperftools/src/common.cc",
|
||||
"gperftools/src/common.h",
|
||||
"gperftools/src/config_for_unittests.h",
|
||||
"gperftools/src/debugallocation.cc",
|
||||
"gperftools/src/emergency_malloc.cc",
|
||||
"gperftools/src/emergency_malloc_for_stacktrace.cc",
|
||||
"gperftools/src/emergency_malloc.h",
|
||||
"gperftools/src/fake_stacktrace_scope.cc",
|
||||
"gperftools/src/getenv_safe.h",
|
||||
"gperftools/src/getpc.h",
|
||||
"gperftools/src/heap-checker-bcad.cc",
|
||||
"gperftools/src/heap-checker.cc",
|
||||
"gperftools/src/heap-profiler.cc",
|
||||
"gperftools/src/heap-profile-stats.h",
|
||||
"gperftools/src/heap-profile-table.cc",
|
||||
"gperftools/src/heap-profile-table.h",
|
||||
"gperftools/src/internal_logging.cc",
|
||||
"gperftools/src/internal_logging.h",
|
||||
"gperftools/src/libc_override_gcc_and_weak.h",
|
||||
"gperftools/src/libc_override_glibc.h",
|
||||
"gperftools/src/libc_override.h",
|
||||
"gperftools/src/libc_override_osx.h",
|
||||
"gperftools/src/libc_override_redefine.h",
|
||||
"gperftools/src/linked_list.h",
|
||||
"gperftools/src/malloc_extension.cc",
|
||||
"gperftools/src/malloc_hook.cc",
|
||||
"gperftools/src/malloc_hook-inl.h",
|
||||
"gperftools/src/malloc_hook_mmap_freebsd.h",
|
||||
"gperftools/src/malloc_hook_mmap_linux.h",
|
||||
"gperftools/src/maybe_emergency_malloc.h",
|
||||
"gperftools/src/maybe_threads.cc",
|
||||
"gperftools/src/maybe_threads.h",
|
||||
"gperftools/src/memfs_malloc.cc",
|
||||
"gperftools/src/memory_region_map.cc",
|
||||
"gperftools/src/memory_region_map.h",
|
||||
"gperftools/src/packed-cache-inl.h",
|
||||
"gperftools/src/page_heap_allocator.h",
|
||||
"gperftools/src/page_heap.cc",
|
||||
"gperftools/src/page_heap.h",
|
||||
"gperftools/src/pagemap.h",
|
||||
"gperftools/src/profiledata.cc",
|
||||
"gperftools/src/profiledata.h",
|
||||
"gperftools/src/profile-handler.cc",
|
||||
"gperftools/src/profile-handler.h",
|
||||
"gperftools/src/profiler.cc",
|
||||
"gperftools/src/raw_printer.cc",
|
||||
"gperftools/src/raw_printer.h",
|
||||
"gperftools/src/sampler.cc",
|
||||
"gperftools/src/sampler.h",
|
||||
"gperftools/src/span.cc",
|
||||
"gperftools/src/span.h",
|
||||
"gperftools/src/stacktrace_arm-inl.h",
|
||||
"gperftools/src/stacktrace.cc",
|
||||
"gperftools/src/stacktrace_generic-inl.h",
|
||||
"gperftools/src/stacktrace_impl_setup-inl.h",
|
||||
"gperftools/src/stacktrace_instrument-inl.h",
|
||||
"gperftools/src/stacktrace_libgcc-inl.h",
|
||||
"gperftools/src/stacktrace_libunwind-inl.h",
|
||||
"gperftools/src/stacktrace_powerpc-darwin-inl.h",
|
||||
"gperftools/src/stacktrace_powerpc-inl.h",
|
||||
"gperftools/src/stacktrace_powerpc-linux-inl.h",
|
||||
"gperftools/src/stack_trace_table.cc",
|
||||
"gperftools/src/stack_trace_table.h",
|
||||
"gperftools/src/stacktrace_win32-inl.h",
|
||||
"gperftools/src/stacktrace_x86-inl.h",
|
||||
"gperftools/src/static_vars.cc",
|
||||
"gperftools/src/static_vars.h",
|
||||
"gperftools/src/symbolize.cc",
|
||||
"gperftools/src/symbolize.h",
|
||||
"gperftools/src/system-alloc.cc",
|
||||
"gperftools/src/system-alloc.h",
|
||||
"gperftools/src/tcmalloc.cc",
|
||||
"gperftools/src/tcmalloc_guard.h",
|
||||
"gperftools/src/tcmalloc.h",
|
||||
"gperftools/src/thread_cache.cc",
|
||||
"gperftools/src/thread_cache.h",
|
||||
|
||||
# gperftools/src/base/
|
||||
"gperftools/src/base/arm_instruction_set_select.h",
|
||||
"gperftools/src/base/atomicops.h",
|
||||
"gperftools/src/base/atomicops-internals-arm-generic.h",
|
||||
"gperftools/src/base/atomicops-internals-arm-v6plus.h",
|
||||
"gperftools/src/base/atomicops-internals-gcc.h",
|
||||
"gperftools/src/base/atomicops-internals-linuxppc.h",
|
||||
"gperftools/src/base/atomicops-internals-macosx.h",
|
||||
"gperftools/src/base/atomicops-internals-mips.h",
|
||||
"gperftools/src/base/atomicops-internals-windows.h",
|
||||
"gperftools/src/base/atomicops-internals-x86.cc",
|
||||
"gperftools/src/base/atomicops-internals-x86.h",
|
||||
"gperftools/src/base/basictypes.h",
|
||||
"gperftools/src/base/commandlineflags.h",
|
||||
# This C files is compiled into a separate target.
|
||||
# "gperftools/src/base/dynamic_annotations.c",
|
||||
# "gperftools/src/base/dynamic_annotations.h",
|
||||
"gperftools/src/base/elfcore.h",
|
||||
"gperftools/src/base/elf_mem_image.cc",
|
||||
"gperftools/src/base/elf_mem_image.h",
|
||||
"gperftools/src/base/googleinit.h",
|
||||
"gperftools/src/base/linux_syscall_support.h",
|
||||
"gperftools/src/base/linuxthreads.cc",
|
||||
"gperftools/src/base/linuxthreads.h",
|
||||
"gperftools/src/base/logging.cc",
|
||||
"gperftools/src/base/logging.h",
|
||||
"gperftools/src/base/low_level_alloc.cc",
|
||||
"gperftools/src/base/low_level_alloc.h",
|
||||
"gperftools/src/base/simple_mutex.h",
|
||||
"gperftools/src/base/spinlock.cc",
|
||||
"gperftools/src/base/spinlock.h",
|
||||
"gperftools/src/base/spinlock_internal.cc",
|
||||
"gperftools/src/base/spinlock_internal.h",
|
||||
"gperftools/src/base/spinlock_linux-inl.h",
|
||||
"gperftools/src/base/spinlock_posix-inl.h",
|
||||
"gperftools/src/base/spinlock_win32-inl.h",
|
||||
"gperftools/src/base/stl_allocator.h",
|
||||
"gperftools/src/base/sysinfo.cc",
|
||||
"gperftools/src/base/sysinfo.h",
|
||||
"gperftools/src/base/thread_annotations.h",
|
||||
"gperftools/src/base/thread_lister.c",
|
||||
"gperftools/src/base/thread_lister.h",
|
||||
"gperftools/src/base/vdso_support.cc",
|
||||
"gperftools/src/base/vdso_support.h",
|
||||
|
||||
# gperftools/src/google/
|
||||
"gperftools/src/google/heap-checker.h",
|
||||
"gperftools/src/google/heap-profiler.h",
|
||||
"gperftools/src/google/malloc_extension_c.h",
|
||||
"gperftools/src/google/malloc_extension.h",
|
||||
"gperftools/src/google/malloc_hook_c.h",
|
||||
"gperftools/src/google/malloc_hook.h",
|
||||
"gperftools/src/google/profiler.h",
|
||||
"gperftools/src/google/stacktrace.h",
|
||||
"gperftools/src/google/tcmalloc.h",
|
||||
|
||||
# gperftools/src/gperftools/
|
||||
"gperftools/src/gperftools/heap-checker.h",
|
||||
"gperftools/src/gperftools/heap-profiler.h",
|
||||
"gperftools/src/gperftools/malloc_extension_c.h",
|
||||
"gperftools/src/gperftools/malloc_extension.h",
|
||||
"gperftools/src/gperftools/malloc_hook_c.h",
|
||||
"gperftools/src/gperftools/malloc_hook.h",
|
||||
"gperftools/src/gperftools/profiler.h",
|
||||
"gperftools/src/gperftools/stacktrace.h",
|
||||
|
||||
# gperftools/src/third_party/
|
||||
"gperftools/src/third_party/valgrind.h",
|
||||
]
|
10
tools/gn.py
10
tools/gn.py
|
@ -243,16 +243,6 @@ def ToGnArgs(args, mode, arch, target_os, sanitizer, verify_sdk_hash):
|
|||
|
||||
gn_args['bssl_use_clang_integrated_as'] = True
|
||||
|
||||
# Use tcmalloc only when targeting Linux and when not using ASAN.
|
||||
# TODO(51111): Re-enable for riscv64.
|
||||
gn_args['dart_use_tcmalloc'] = ((gn_args['target_os'] == 'linux') and
|
||||
(gn_args['target_cpu'] != 'riscv32') and
|
||||
(gn_args['target_cpu'] != 'riscv64') and
|
||||
sanitizer == 'none')
|
||||
|
||||
# Use mallinfo2 if specified on the command line
|
||||
gn_args['dart_use_mallinfo2'] = args.use_mallinfo2
|
||||
|
||||
if gn_args['target_os'] == 'linux':
|
||||
if gn_args['target_cpu'] == 'arm':
|
||||
# Default to -mfloat-abi=hard and -mfpu=neon for arm on Linux as we're
|
||||
|
|
Loading…
Reference in a new issue