mirror of
https://github.com/dart-lang/sdk
synced 2024-09-05 00:13:50 +00:00
Reapply "[vm, service] Gather used and capacity from various mallocs."
Avoid weak linking on iOS. TEST=ci Change-Id: Iafcb5bfdea0520d50363486e67031e1d5302d32b Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/161461 Commit-Queue: Ryan Macnak <rmacnak@google.com> Reviewed-by: Ben Konyi <bkonyi@google.com>
This commit is contained in:
parent
c3c371b971
commit
e67dd9c2c5
|
@ -174,14 +174,28 @@ class VMViewElement extends CustomElement implements Renderable {
|
|||
..children = <Element>[
|
||||
new DivElement()
|
||||
..classes = ['memberName']
|
||||
..text = 'malloc memory',
|
||||
..text = 'malloc used memory',
|
||||
new DivElement()
|
||||
..classes = ['memberValue']
|
||||
..text = _vm.heapAllocatedMemoryUsage != null
|
||||
? Utils.formatSize(_vm.heapAllocatedMemoryUsage)
|
||||
..text = _vm.mallocUsed != null
|
||||
? Utils.formatSize(_vm.mallocUsed)
|
||||
: 'unavailable'
|
||||
..title = _vm.heapAllocatedMemoryUsage != null
|
||||
? '${_vm.heapAllocatedMemoryUsage} bytes'
|
||||
..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()
|
||||
|
@ -189,12 +203,10 @@ class VMViewElement extends CustomElement implements Renderable {
|
|||
..children = <Element>[
|
||||
new DivElement()
|
||||
..classes = ['memberName']
|
||||
..text = 'malloc allocation count',
|
||||
..text = 'malloc implementation',
|
||||
new DivElement()
|
||||
..classes = ['memberValue']
|
||||
..text = _vm.heapAllocationCount != null
|
||||
? '${_vm.heapAllocationCount}'
|
||||
: 'unavailable'
|
||||
..text = _vm.mallocImplementation
|
||||
],
|
||||
new DivElement()
|
||||
..classes = ['memberItem']
|
||||
|
|
|
@ -35,10 +35,9 @@ abstract class VM implements VMRef {
|
|||
int get pid;
|
||||
|
||||
/// The current amount of native heap allocated memory within the VM.
|
||||
int get heapAllocatedMemoryUsage;
|
||||
|
||||
/// The current number of allocations on the native heap within the VM.
|
||||
int get heapAllocationCount;
|
||||
int get mallocUsed;
|
||||
int get mallocCapacity;
|
||||
String get mallocImplementation;
|
||||
|
||||
int get currentMemory;
|
||||
int get maxRSS;
|
||||
|
|
|
@ -680,8 +680,9 @@ abstract class VM extends ServiceObjectOwner implements M.VM {
|
|||
bool typeChecksEnabled = false;
|
||||
int nativeZoneMemoryUsage = 0;
|
||||
int pid = 0;
|
||||
int heapAllocatedMemoryUsage = 0;
|
||||
int heapAllocationCount = 0;
|
||||
int mallocUsed = 0;
|
||||
int mallocCapacity = 0;
|
||||
String mallocImplementation = 'unknown';
|
||||
int currentMemory = 0;
|
||||
int maxRSS = 0;
|
||||
int currentRSS = 0;
|
||||
|
@ -1041,8 +1042,9 @@ abstract class VM extends ServiceObjectOwner implements M.VM {
|
|||
nativeZoneMemoryUsage = map['_nativeZoneMemoryUsage'];
|
||||
}
|
||||
pid = map['pid'];
|
||||
heapAllocatedMemoryUsage = map['_heapAllocatedMemoryUsage'];
|
||||
heapAllocationCount = map['_heapAllocationCount'];
|
||||
mallocUsed = map['_mallocUsed'];
|
||||
mallocCapacity = map['_mallocCapacity'];
|
||||
mallocImplementation = map['_mallocImplementation'];
|
||||
embedder = map['_embedder'];
|
||||
currentMemory = map['_currentMemory'];
|
||||
maxRSS = map['_maxRSS'];
|
||||
|
|
|
@ -174,14 +174,28 @@ class VMViewElement extends CustomElement implements Renderable {
|
|||
..children = <Element>[
|
||||
new DivElement()
|
||||
..classes = ['memberName']
|
||||
..text = 'malloc memory',
|
||||
..text = 'malloc used memory',
|
||||
new DivElement()
|
||||
..classes = ['memberValue']
|
||||
..text = _vm.heapAllocatedMemoryUsage != null
|
||||
? Utils.formatSize(_vm.heapAllocatedMemoryUsage)
|
||||
..text = _vm.mallocUsed != null
|
||||
? Utils.formatSize(_vm.mallocUsed)
|
||||
: 'unavailable'
|
||||
..title = _vm.heapAllocatedMemoryUsage != null
|
||||
? '${_vm.heapAllocatedMemoryUsage} bytes'
|
||||
..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()
|
||||
|
@ -189,12 +203,10 @@ class VMViewElement extends CustomElement implements Renderable {
|
|||
..children = <Element>[
|
||||
new DivElement()
|
||||
..classes = ['memberName']
|
||||
..text = 'malloc allocation count',
|
||||
..text = 'malloc implementation',
|
||||
new DivElement()
|
||||
..classes = ['memberValue']
|
||||
..text = _vm.heapAllocationCount != null
|
||||
? '${_vm.heapAllocationCount}'
|
||||
: 'unavailable'
|
||||
..text = _vm.mallocImplementation
|
||||
],
|
||||
new DivElement()
|
||||
..classes = ['memberItem']
|
||||
|
|
|
@ -35,10 +35,9 @@ abstract class VM implements VMRef {
|
|||
int get pid;
|
||||
|
||||
/// The current amount of native heap allocated memory within the VM.
|
||||
int get heapAllocatedMemoryUsage;
|
||||
|
||||
/// The current number of allocations on the native heap within the VM.
|
||||
int get heapAllocationCount;
|
||||
int get mallocUsed;
|
||||
int get mallocCapacity;
|
||||
String get mallocImplementation;
|
||||
|
||||
int get currentMemory;
|
||||
int get maxRSS;
|
||||
|
|
|
@ -681,8 +681,9 @@ abstract class VM extends ServiceObjectOwner implements M.VM {
|
|||
bool typeChecksEnabled = false;
|
||||
int nativeZoneMemoryUsage = 0;
|
||||
int pid = 0;
|
||||
int heapAllocatedMemoryUsage = 0;
|
||||
int heapAllocationCount = 0;
|
||||
int mallocUsed = 0;
|
||||
int mallocCapacity = 0;
|
||||
String mallocImplementation = 'unknown';
|
||||
int currentMemory;
|
||||
int maxRSS;
|
||||
int currentRSS;
|
||||
|
@ -1044,8 +1045,9 @@ abstract class VM extends ServiceObjectOwner implements M.VM {
|
|||
nativeZoneMemoryUsage = map['_nativeZoneMemoryUsage'];
|
||||
}
|
||||
pid = map['pid'];
|
||||
heapAllocatedMemoryUsage = map['_heapAllocatedMemoryUsage'];
|
||||
heapAllocationCount = map['_heapAllocationCount'];
|
||||
mallocUsed = map['_mallocUsed'];
|
||||
mallocCapacity = map['_mallocCapacity'];
|
||||
mallocImplementation = map['_mallocImplementation'];
|
||||
embedder = map['_embedder'];
|
||||
currentMemory = map['_currentMemory'];
|
||||
maxRSS = map['_maxRSS'];
|
||||
|
|
|
@ -30,7 +30,9 @@ class MallocHooks : public AllStatic {
|
|||
static void set_stack_trace_collection_enabled(bool enabled);
|
||||
static void ResetStats();
|
||||
static bool Active();
|
||||
static void PrintToJSONObject(JSONObject* jsobj);
|
||||
static bool GetStats(intptr_t* used,
|
||||
intptr_t* capacity,
|
||||
const char** implementation);
|
||||
static Sample* GetSample(const void* ptr);
|
||||
|
||||
static intptr_t allocation_count();
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
|
||||
#include "gperftools/malloc_hook.h"
|
||||
|
||||
#include <malloc.h>
|
||||
|
||||
#include "platform/assert.h"
|
||||
#include "vm/hash_map.h"
|
||||
#include "vm/json_stream.h"
|
||||
|
@ -336,29 +338,14 @@ bool MallocHooks::Active() {
|
|||
return MallocHooksState::Active();
|
||||
}
|
||||
|
||||
void MallocHooks::PrintToJSONObject(JSONObject* jsobj) {
|
||||
if (!FLAG_profiler_native_memory) {
|
||||
return;
|
||||
}
|
||||
intptr_t allocated_memory = 0;
|
||||
intptr_t allocation_count = 0;
|
||||
bool add_usage = false;
|
||||
// AddProperty may call malloc which would result in an attempt
|
||||
// to acquire the lock recursively so we extract the values first
|
||||
// and then add the JSON properties.
|
||||
{
|
||||
MallocLocker ml(MallocHooksState::malloc_hook_mutex(),
|
||||
MallocHooksState::malloc_hook_mutex_owner());
|
||||
if (MallocHooksState::Active()) {
|
||||
allocated_memory = MallocHooksState::heap_allocated_memory_in_bytes();
|
||||
allocation_count = MallocHooksState::allocation_count();
|
||||
add_usage = true;
|
||||
}
|
||||
}
|
||||
if (add_usage) {
|
||||
jsobj->AddProperty("_heapAllocatedMemoryUsage", allocated_memory);
|
||||
jsobj->AddProperty("_heapAllocationCount", allocation_count);
|
||||
}
|
||||
bool MallocHooks::GetStats(intptr_t* used,
|
||||
intptr_t* capacity,
|
||||
const char** implementation) {
|
||||
struct mallinfo info = mallinfo();
|
||||
*used = info.uordblks;
|
||||
*capacity = *used + info.fordblks;
|
||||
*implementation = "tcmalloc";
|
||||
return true;
|
||||
}
|
||||
|
||||
intptr_t MallocHooks::allocation_count() {
|
||||
|
|
|
@ -8,6 +8,24 @@
|
|||
|
||||
#include "vm/malloc_hooks.h"
|
||||
|
||||
#include "vm/json_stream.h"
|
||||
|
||||
#if defined(HOST_OS_LINUX) || defined(HOST_OS_ANDROID)
|
||||
#include <malloc.h>
|
||||
#elif defined(HOST_OS_MACOS)
|
||||
#include <malloc/malloc.h>
|
||||
#endif
|
||||
|
||||
#if !defined(HOST_OS_WINDOWS) && !defined(TARGET_OS_IOS)
|
||||
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() {
|
||||
|
@ -38,8 +56,37 @@ bool MallocHooks::Active() {
|
|||
return false;
|
||||
}
|
||||
|
||||
void MallocHooks::PrintToJSONObject(JSONObject* jsobj) {
|
||||
// Do nothing.
|
||||
bool MallocHooks::GetStats(intptr_t* used,
|
||||
intptr_t* capacity,
|
||||
const char** implementation) {
|
||||
#if !defined(PRODUCT)
|
||||
#if !defined(HOST_OS_WINDOWS) && !defined(TARGET_OS_IOS)
|
||||
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
|
||||
#if defined(HOST_OS_LINUX) || defined(HOST_OS_ANDROID)
|
||||
struct mallinfo info = mallinfo();
|
||||
*used = info.uordblks;
|
||||
*capacity = *used + info.fordblks;
|
||||
*implementation = "unknown";
|
||||
return true;
|
||||
#elif defined(HOST_OS_MACOS)
|
||||
struct mstats stats = mstats();
|
||||
*used = stats.bytes_used;
|
||||
*capacity = stats.bytes_total;
|
||||
*implementation = "macos";
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
Sample* MallocHooks::GetSample(const void* ptr) {
|
||||
|
|
|
@ -4329,94 +4329,122 @@ static intptr_t GetProcessMemoryUsageHelper(JSONStream* js) {
|
|||
rss.AddProperty64("size", Service::CurrentRSS());
|
||||
JSONArray rss_children(&rss, "children");
|
||||
|
||||
JSONObject vm(&rss_children);
|
||||
intptr_t vm_size = 0;
|
||||
{
|
||||
JSONArray vm_children(&vm, "children");
|
||||
JSONObject vm(&rss_children);
|
||||
{
|
||||
JSONArray vm_children(&vm, "children");
|
||||
|
||||
{
|
||||
JSONObject profiler(&vm_children);
|
||||
profiler.AddProperty("name", "Profiler");
|
||||
profiler.AddProperty("description",
|
||||
"Samples from the Dart VM's profiler");
|
||||
intptr_t size = Profiler::Size();
|
||||
vm_size += size;
|
||||
profiler.AddProperty64("size", size);
|
||||
JSONArray(&profiler, "children");
|
||||
}
|
||||
|
||||
{
|
||||
JSONObject timeline(&vm_children);
|
||||
timeline.AddProperty("name", "Timeline");
|
||||
timeline.AddProperty(
|
||||
"description",
|
||||
"Timeline events from dart:developer and Dart_TimelineEvent");
|
||||
intptr_t size = Timeline::recorder()->Size();
|
||||
vm_size += size;
|
||||
timeline.AddProperty64("size", size);
|
||||
JSONArray(&timeline, "children");
|
||||
}
|
||||
|
||||
{
|
||||
JSONObject zone(&vm_children);
|
||||
zone.AddProperty("name", "Zone");
|
||||
zone.AddProperty("description", "Arena allocation in the Dart VM");
|
||||
intptr_t size = Zone::Size();
|
||||
vm_size += size;
|
||||
zone.AddProperty64("size", size);
|
||||
JSONArray(&zone, "children");
|
||||
}
|
||||
|
||||
{
|
||||
JSONObject semi(&vm_children);
|
||||
semi.AddProperty("name", "SemiSpace Cache");
|
||||
semi.AddProperty("description", "Cached heap regions");
|
||||
intptr_t size = SemiSpace::CachedSize();
|
||||
vm_size += size;
|
||||
semi.AddProperty64("size", size);
|
||||
JSONArray(&semi, "children");
|
||||
}
|
||||
|
||||
IsolateGroup::ForEach([&vm_children,
|
||||
&vm_size](IsolateGroup* isolate_group) {
|
||||
// Note: new_space()->CapacityInWords() includes memory that hasn't been
|
||||
// allocated from the OS yet.
|
||||
int64_t capacity =
|
||||
(isolate_group->heap()->new_space()->UsedInWords() +
|
||||
isolate_group->heap()->old_space()->CapacityInWords()) *
|
||||
kWordSize;
|
||||
int64_t used = isolate_group->heap()->TotalUsedInWords() * kWordSize;
|
||||
int64_t free = capacity - used;
|
||||
|
||||
JSONObject group(&vm_children);
|
||||
group.AddPropertyF("name", "IsolateGroup %s",
|
||||
isolate_group->source()->name);
|
||||
group.AddProperty("description", "Dart heap capacity");
|
||||
vm_size += capacity;
|
||||
group.AddProperty64("size", capacity);
|
||||
JSONArray group_children(&group, "children");
|
||||
|
||||
{
|
||||
JSONObject jsused(&group_children);
|
||||
jsused.AddProperty("name", "Used");
|
||||
jsused.AddProperty("description", "");
|
||||
jsused.AddProperty64("size", used);
|
||||
JSONArray(&jsused, "children");
|
||||
}
|
||||
|
||||
{
|
||||
JSONObject jsfree(&group_children);
|
||||
jsfree.AddProperty("name", "Free");
|
||||
jsfree.AddProperty("description", "");
|
||||
jsfree.AddProperty64("size", free);
|
||||
JSONArray(&jsfree, "children");
|
||||
}
|
||||
});
|
||||
} // vm_children
|
||||
|
||||
vm.AddProperty("name", "Dart VM");
|
||||
vm.AddProperty("description", "");
|
||||
vm.AddProperty64("size", vm_size);
|
||||
}
|
||||
|
||||
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 profiler(&vm_children);
|
||||
profiler.AddProperty("name", "Profiler");
|
||||
profiler.AddProperty("description",
|
||||
"Samples from the Dart VM's profiler");
|
||||
intptr_t size = Profiler::Size();
|
||||
vm_size += size;
|
||||
profiler.AddProperty64("size", size);
|
||||
JSONArray(&profiler, "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 timeline(&vm_children);
|
||||
timeline.AddProperty("name", "Timeline");
|
||||
timeline.AddProperty(
|
||||
"description",
|
||||
"Timeline events from dart:developer and Dart_TimelineEvent");
|
||||
intptr_t size = Timeline::recorder()->Size();
|
||||
vm_size += size;
|
||||
timeline.AddProperty64("size", size);
|
||||
JSONArray(&timeline, "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");
|
||||
}
|
||||
|
||||
{
|
||||
JSONObject zone(&vm_children);
|
||||
zone.AddProperty("name", "Zone");
|
||||
zone.AddProperty("description", "Arena allocation in the Dart VM");
|
||||
intptr_t size = Zone::Size();
|
||||
vm_size += size;
|
||||
zone.AddProperty64("size", size);
|
||||
JSONArray(&zone, "children");
|
||||
}
|
||||
|
||||
{
|
||||
JSONObject semi(&vm_children);
|
||||
semi.AddProperty("name", "SemiSpace Cache");
|
||||
semi.AddProperty("description", "Cached heap regions");
|
||||
intptr_t size = SemiSpace::CachedSize();
|
||||
vm_size += size;
|
||||
semi.AddProperty64("size", size);
|
||||
JSONArray(&semi, "children");
|
||||
}
|
||||
|
||||
IsolateGroup::ForEach(
|
||||
[&vm_children, &vm_size](IsolateGroup* isolate_group) {
|
||||
// Note: new_space()->CapacityInWords() includes memory that hasn't
|
||||
// been allocated from the OS yet.
|
||||
int64_t capacity =
|
||||
(isolate_group->heap()->new_space()->UsedInWords() +
|
||||
isolate_group->heap()->old_space()->CapacityInWords()) *
|
||||
kWordSize;
|
||||
int64_t used = isolate_group->heap()->TotalUsedInWords() * kWordSize;
|
||||
int64_t free = capacity - used;
|
||||
|
||||
JSONObject group(&vm_children);
|
||||
group.AddPropertyF("name", "IsolateGroup %s",
|
||||
isolate_group->source()->name);
|
||||
group.AddProperty("description", "Dart heap capacity");
|
||||
vm_size += capacity;
|
||||
group.AddProperty64("size", capacity);
|
||||
JSONArray group_children(&group, "children");
|
||||
|
||||
{
|
||||
JSONObject jsused(&group_children);
|
||||
jsused.AddProperty("name", "Used");
|
||||
jsused.AddProperty("description", "");
|
||||
jsused.AddProperty64("size", used);
|
||||
JSONArray(&jsused, "children");
|
||||
}
|
||||
|
||||
{
|
||||
JSONObject jsfree(&group_children);
|
||||
jsfree.AddProperty("name", "Free");
|
||||
jsfree.AddProperty("description", "");
|
||||
jsfree.AddProperty64("size", free);
|
||||
JSONArray(&jsfree, "children");
|
||||
}
|
||||
});
|
||||
} // vm_children
|
||||
|
||||
vm.AddProperty("name", "Dart VM");
|
||||
vm.AddProperty("description", "");
|
||||
vm.AddProperty64("size", vm_size);
|
||||
}
|
||||
|
||||
return vm_size;
|
||||
}
|
||||
|
@ -4848,7 +4876,15 @@ void Service::PrintJSONForVM(JSONStream* js, bool ref) {
|
|||
jsobj.AddProperty64("pid", OS::ProcessId());
|
||||
jsobj.AddPropertyTimeMillis(
|
||||
"startTime", OS::GetCurrentTimeMillis() - Dart::UptimeMillis());
|
||||
MallocHooks::PrintToJSONObject(&jsobj);
|
||||
{
|
||||
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.
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue