Fixed tests not having MallocHooks initialized for tests in release mode.
Revert "Revert "Fixed issue in MallocHooks where a MallocHookScope was accidentally removed during a merge, causing a deadlock in the hooks. Also turned off stack trace collection in a test that was timing out as a result of the stack trace collection.""
This reverts commit 1a5b555aa9.
BUG=
R=zra@google.com
Review-Url: https://codereview.chromium.org/2711353003 .
This commit is contained in:
@@ -11,6 +11,7 @@
|
||||
#include "vm/globals.h"
|
||||
#include "vm/heap.h"
|
||||
#include "vm/isolate.h"
|
||||
#include "vm/malloc_hooks.h"
|
||||
#include "vm/object.h"
|
||||
#include "vm/zone.h"
|
||||
|
||||
@@ -35,6 +36,9 @@ 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(); \
|
||||
@@ -42,6 +46,8 @@ extern const uint8_t* core_isolate_snapshot_instructions;
|
||||
StackZone __zone__(__thread__); \
|
||||
HandleScope __hs__(__thread__); \
|
||||
Dart_BenchmarkHelper##name(benchmark, __thread__); \
|
||||
MallocHooks::set_stack_trace_collection_enabled( \
|
||||
__stack_trace_collection_enabled__); \
|
||||
} \
|
||||
static void Dart_BenchmarkHelper##name(Benchmark* benchmark, Thread* thread)
|
||||
|
||||
|
||||
+14
-1
@@ -152,7 +152,6 @@ char* Dart::InitOnce(const uint8_t* vm_isolate_snapshot,
|
||||
start_time_micros_ = OS::GetCurrentMonotonicMicros();
|
||||
VirtualMemory::InitOnce();
|
||||
OSThread::InitOnce();
|
||||
MallocHooks::InitOnce();
|
||||
if (FLAG_support_timeline) {
|
||||
Timeline::InitOnce();
|
||||
}
|
||||
@@ -233,6 +232,13 @@ char* Dart::InitOnce(const uint8_t* vm_isolate_snapshot,
|
||||
return strdup("Precompiled runtime requires a precompiled snapshot");
|
||||
#else
|
||||
StubCode::InitOnce();
|
||||
// MallocHooks can't be initialized until StubCode has been since stack
|
||||
// trace generation relies on stub methods that are generated in
|
||||
// StubCode::InitOnce().
|
||||
// TODO(bkonyi) Split initialization for stack trace collection from the
|
||||
// initialization for the actual malloc hooks to increase accuracy of
|
||||
// memory consumption statistics.
|
||||
MallocHooks::InitOnce();
|
||||
#endif
|
||||
} else {
|
||||
return strdup("Invalid vm isolate snapshot seen");
|
||||
@@ -271,6 +277,13 @@ char* Dart::InitOnce(const uint8_t* vm_isolate_snapshot,
|
||||
#else
|
||||
vm_snapshot_kind_ = Snapshot::kNone;
|
||||
StubCode::InitOnce();
|
||||
// MallocHooks can't be initialized until StubCode has been since stack
|
||||
// trace generation relies on stub methods that are generated in
|
||||
// StubCode::InitOnce().
|
||||
// TODO(bkonyi) Split initialization for stack trace collection from the
|
||||
// initialization for the actual malloc hooks to increase accuracy of
|
||||
// memory consumption statistics.
|
||||
MallocHooks::InitOnce();
|
||||
Symbols::InitOnce(vm_isolate_);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ class BaseDirectChainedHashMap : public B {
|
||||
|
||||
BaseDirectChainedHashMap(const BaseDirectChainedHashMap& other);
|
||||
|
||||
~BaseDirectChainedHashMap() {
|
||||
virtual ~BaseDirectChainedHashMap() {
|
||||
allocator_->template Free<HashMapListElement>(array_, array_size_);
|
||||
allocator_->template Free<HashMapListElement>(lists_, lists_size_);
|
||||
}
|
||||
@@ -42,7 +42,7 @@ class BaseDirectChainedHashMap : public B {
|
||||
|
||||
bool IsEmpty() const { return count_ == 0; }
|
||||
|
||||
void Clear() {
|
||||
virtual void Clear() {
|
||||
if (!IsEmpty()) {
|
||||
count_ = 0;
|
||||
InitArray(array_, array_size_);
|
||||
|
||||
+224
-101
@@ -4,7 +4,8 @@
|
||||
|
||||
#include "platform/globals.h"
|
||||
|
||||
#if defined(DART_USE_TCMALLOC) && !defined(PRODUCT)
|
||||
#if defined(DART_USE_TCMALLOC) && !defined(PRODUCT) && \
|
||||
!defined(TARGET_ARCH_DBC) && !defined(TARGET_OS_FUCHSIA)
|
||||
|
||||
#include "vm/malloc_hooks.h"
|
||||
|
||||
@@ -14,92 +15,33 @@
|
||||
#include "vm/hash_map.h"
|
||||
#include "vm/json_stream.h"
|
||||
#include "vm/os_thread.h"
|
||||
#include "vm/profiler.h"
|
||||
|
||||
namespace dart {
|
||||
|
||||
// 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_;
|
||||
};
|
||||
|
||||
|
||||
// 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:
|
||||
typedef const void* Key;
|
||||
typedef intptr_t Value;
|
||||
|
||||
struct Pair {
|
||||
Key key;
|
||||
Value value;
|
||||
Pair() : key(NULL), value(-1) {}
|
||||
Pair(const Key key, const Value& value) : key(key), value(value) {}
|
||||
Pair(const Pair& other) : key(other.key), value(other.value) {}
|
||||
};
|
||||
|
||||
static Key KeyOf(Pair kv) { return kv.key; }
|
||||
static Value ValueOf(Pair kv) { return kv.value; }
|
||||
static intptr_t Hashcode(Key key) { return 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;
|
||||
|
||||
inline void Insert(const Key& key, const Value& value) {
|
||||
Pair pair(key, value);
|
||||
MallocDirectChainedHashMap<AddressKeyValueTrait>::Insert(pair);
|
||||
}
|
||||
|
||||
inline 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;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
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() { return active_; }
|
||||
static void Init() {
|
||||
address_map_ = new AddressMap();
|
||||
active_ = true;
|
||||
original_pid_ = OS::ProcessId();
|
||||
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() {
|
||||
@@ -139,36 +81,146 @@ class MallocHooksState : public AllStatic {
|
||||
|
||||
static AddressMap* address_map() { return address_map_; }
|
||||
|
||||
static void ResetStats() {
|
||||
ASSERT(malloc_hook_mutex()->IsOwnedByCurrentThread());
|
||||
allocation_count_ = 0;
|
||||
heap_allocated_memory_in_bytes_ = 0;
|
||||
address_map_->Clear();
|
||||
}
|
||||
|
||||
static void TearDown() {
|
||||
ASSERT(malloc_hook_mutex()->IsOwnedByCurrentThread());
|
||||
active_ = false;
|
||||
original_pid_ = kInvalidPid;
|
||||
ResetStats();
|
||||
delete address_map_;
|
||||
}
|
||||
static void ResetStats();
|
||||
static void TearDown();
|
||||
|
||||
private:
|
||||
static bool active_;
|
||||
static intptr_t original_pid_;
|
||||
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:
|
||||
explicit AllocationInfo(intptr_t allocation_size)
|
||||
: sample_(NULL), 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);
|
||||
}
|
||||
}
|
||||
|
||||
Sample* sample() const { return sample_; }
|
||||
intptr_t allocation_size() const { return allocation_size_; }
|
||||
|
||||
private:
|
||||
Sample* sample_;
|
||||
intptr_t allocation_size_;
|
||||
|
||||
// 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, particularily
|
||||
// StackTraceMallocHookLengthTest. If this value is updated, please make sure
|
||||
// that the MallocHooks test cases pass on all platforms.
|
||||
static const intptr_t kSkipCount = 5;
|
||||
};
|
||||
|
||||
|
||||
// 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) {}
|
||||
};
|
||||
|
||||
static Key KeyOf(Pair kv) { return kv.key; }
|
||||
static Value ValueOf(Pair kv) { return kv.value; }
|
||||
static intptr_t Hashcode(Key key) { return 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_ =
|
||||
@@ -180,6 +232,36 @@ 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::InitOnce() {
|
||||
if (!FLAG_enable_malloc_hooks) {
|
||||
return;
|
||||
@@ -218,6 +300,25 @@ void MallocHooks::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_enable_malloc_hooks) {
|
||||
return;
|
||||
@@ -234,7 +335,9 @@ bool MallocHooks::Active() {
|
||||
if (!FLAG_enable_malloc_hooks) {
|
||||
return false;
|
||||
}
|
||||
ASSERT(MallocHooksState::malloc_hook_mutex()->IsOwnedByCurrentThread());
|
||||
MallocLocker ml(MallocHooksState::malloc_hook_mutex(),
|
||||
MallocHooksState::malloc_hook_mutex_owner());
|
||||
|
||||
return MallocHooksState::Active();
|
||||
}
|
||||
|
||||
@@ -252,7 +355,7 @@ void MallocHooks::PrintToJSONObject(JSONObject* jsobj) {
|
||||
{
|
||||
MallocLocker ml(MallocHooksState::malloc_hook_mutex(),
|
||||
MallocHooksState::malloc_hook_mutex_owner());
|
||||
if (Active()) {
|
||||
if (MallocHooksState::Active()) {
|
||||
allocated_memory = MallocHooksState::heap_allocated_memory_in_bytes();
|
||||
allocation_count = MallocHooksState::allocation_count();
|
||||
add_usage = true;
|
||||
@@ -285,6 +388,23 @@ intptr_t MallocHooks::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()) {
|
||||
@@ -296,7 +416,7 @@ void MallocHooksState::RecordAllocHook(const void* ptr, size_t size) {
|
||||
// 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, size);
|
||||
MallocHooksState::address_map()->Insert(ptr, new AllocationInfo(size));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -311,14 +431,17 @@ void MallocHooksState::RecordFreeHook(const void* ptr) {
|
||||
MallocHooksState::malloc_hook_mutex_owner());
|
||||
// Now that we hold the lock, check to make sure everything is still active.
|
||||
if ((ptr != NULL) && MallocHooksState::Active()) {
|
||||
intptr_t size = 0;
|
||||
if (MallocHooksState::address_map()->Lookup(ptr, &size)) {
|
||||
MallocHooksState::DecrementHeapAllocatedMemoryInBytes(size);
|
||||
AllocationInfo* allocation_info = NULL;
|
||||
if (MallocHooksState::address_map()->Lookup(ptr, &allocation_info)) {
|
||||
MallocHooksState::DecrementHeapAllocatedMemoryInBytes(
|
||||
allocation_info->allocation_size());
|
||||
MallocHooksState::address_map()->Remove(ptr);
|
||||
delete allocation_info;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // defined(DART_USE_TCMALLOC) && !defined(PRODUCT)
|
||||
#endif // defined(DART_USE_TCMALLOC) && !defined(PRODUCT) &&
|
||||
// !defined(TARGET_ARCH_DBC) && !defined(TARGET_OS_FUCHSIA)
|
||||
|
||||
@@ -11,14 +11,19 @@
|
||||
namespace dart {
|
||||
|
||||
class JSONObject;
|
||||
class Sample;
|
||||
|
||||
class MallocHooks : public AllStatic {
|
||||
public:
|
||||
static void InitOnce();
|
||||
static void TearDown();
|
||||
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 void PrintToJSONObject(JSONObject* jsobj);
|
||||
static Sample* GetSample(const void* ptr);
|
||||
|
||||
static intptr_t allocation_count();
|
||||
static intptr_t heap_allocated_memory_in_bytes();
|
||||
|
||||
@@ -4,13 +4,15 @@
|
||||
|
||||
#include "platform/globals.h"
|
||||
|
||||
#if defined(DART_USE_TCMALLOC) && !defined(PRODUCT)
|
||||
#if defined(DART_USE_TCMALLOC) && !defined(PRODUCT) && \
|
||||
!defined(TARGET_ARCH_DBC) && !defined(TARGET_OS_FUCHSIA)
|
||||
|
||||
#include "platform/assert.h"
|
||||
#include "vm/class_finalizer.h"
|
||||
#include "vm/globals.h"
|
||||
#include "vm/malloc_hooks.h"
|
||||
#include "vm/symbols.h"
|
||||
#include "vm/os.h"
|
||||
#include "vm/profiler.h"
|
||||
#include "vm/profiler_service.h"
|
||||
#include "vm/unit_test.h"
|
||||
|
||||
namespace dart {
|
||||
@@ -64,7 +66,7 @@ UNIT_TEST_CASE(FreeUnseenMemoryMallocHookTest) {
|
||||
EXPECT_EQ(0L, MallocHooks::heap_allocated_memory_in_bytes());
|
||||
|
||||
const intptr_t buffer_size = 10;
|
||||
volatile char* buffer = new char[buffer_size];
|
||||
char* buffer = new char[buffer_size];
|
||||
MallocHookTestBufferInitializer(buffer, buffer_size);
|
||||
|
||||
EXPECT_EQ(1L, MallocHooks::allocation_count());
|
||||
@@ -85,6 +87,123 @@ UNIT_TEST_CASE(FreeUnseenMemoryMallocHookTest) {
|
||||
FLAG_enable_malloc_hooks = enable_malloc_hooks_saved;
|
||||
}
|
||||
|
||||
|
||||
VM_UNIT_TEST_CASE(StackTraceMallocHookSimpleTest) {
|
||||
bool enable_malloc_hooks_saved = FLAG_enable_malloc_hooks;
|
||||
FLAG_enable_malloc_hooks = true;
|
||||
|
||||
MallocHooks::InitOnce();
|
||||
MallocHooks::ResetStats();
|
||||
|
||||
bool enable_stack_traces_saved =
|
||||
MallocHooks::stack_trace_collection_enabled();
|
||||
MallocHooks::set_stack_trace_collection_enabled(true);
|
||||
|
||||
char* var = static_cast<char*>(malloc(16 * sizeof(char)));
|
||||
Sample* sample = MallocHooks::GetSample(var);
|
||||
EXPECT(sample != NULL);
|
||||
|
||||
free(var);
|
||||
sample = MallocHooks::GetSample(var);
|
||||
EXPECT(sample == NULL);
|
||||
MallocHooks::TearDown();
|
||||
MallocHooks::set_stack_trace_collection_enabled(enable_stack_traces_saved);
|
||||
FLAG_enable_malloc_hooks = enable_malloc_hooks_saved;
|
||||
}
|
||||
|
||||
|
||||
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) {
|
||||
bool enable_malloc_hooks_saved = FLAG_enable_malloc_hooks;
|
||||
FLAG_enable_malloc_hooks = true;
|
||||
|
||||
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;
|
||||
|
||||
MallocHooks::InitOnce();
|
||||
MallocHooks::ResetStats();
|
||||
|
||||
bool enable_stack_traces_saved =
|
||||
MallocHooks::stack_trace_collection_enabled();
|
||||
MallocHooks::set_stack_trace_collection_enabled(true);
|
||||
|
||||
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.");
|
||||
}
|
||||
|
||||
free(var);
|
||||
MallocHooks::TearDown();
|
||||
MallocHooks::set_stack_trace_collection_enabled(enable_stack_traces_saved);
|
||||
FLAG_enable_malloc_hooks = enable_malloc_hooks_saved;
|
||||
}
|
||||
|
||||
|
||||
ISOLATE_UNIT_TEST_CASE(StackTraceMallocHookSimpleJSONTest) {
|
||||
bool enable_malloc_hooks_saved = FLAG_enable_malloc_hooks;
|
||||
FLAG_enable_malloc_hooks = true;
|
||||
|
||||
MallocHooks::InitOnce();
|
||||
MallocHooks::ResetStats();
|
||||
|
||||
bool enable_stack_traces_saved =
|
||||
MallocHooks::stack_trace_collection_enabled();
|
||||
MallocHooks::set_stack_trace_collection_enabled(true);
|
||||
|
||||
ClearProfileVisitor cpv(Isolate::Current());
|
||||
Profiler::sample_buffer()->VisitSamples(&cpv);
|
||||
|
||||
char* var = static_cast<char*>(malloc(16 * sizeof(char)));
|
||||
JSONStream js;
|
||||
ProfilerService::PrintNativeAllocationJSON(&js, Profile::kNoTags, -1, -1);
|
||||
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.
|
||||
EXPECT_SUBSTRING("\"dart::Dart_TestStackTraceMallocHookSimpleJSONTest()\"",
|
||||
json);
|
||||
EXPECT_SUBSTRING("\"dart::TestCase::Run()\"", json);
|
||||
EXPECT_SUBSTRING("\"dart::TestCaseBase::RunTest()\"", json);
|
||||
EXPECT_SUBSTRING("\"main\"", json);
|
||||
|
||||
free(var);
|
||||
MallocHooks::TearDown();
|
||||
MallocHooks::set_stack_trace_collection_enabled(enable_stack_traces_saved);
|
||||
FLAG_enable_malloc_hooks = enable_malloc_hooks_saved;
|
||||
}
|
||||
|
||||
}; // namespace dart
|
||||
|
||||
#endif // defined(DART_USE_TCMALLOC) && !defined(PRODUCT)
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
|
||||
#include "platform/globals.h"
|
||||
|
||||
#if !defined(DART_USE_TCMALLOC) || defined(PRODUCT)
|
||||
#if !defined(DART_USE_TCMALLOC) || defined(PRODUCT) || \
|
||||
defined(TARGET_ARCH_DBC) || defined(TARGET_OS_FUCHSIA)
|
||||
|
||||
#include "vm/malloc_hooks.h"
|
||||
|
||||
@@ -20,6 +21,21 @@ void MallocHooks::TearDown() {
|
||||
}
|
||||
|
||||
|
||||
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.
|
||||
}
|
||||
@@ -46,4 +62,5 @@ intptr_t MallocHooks::heap_allocated_memory_in_bytes() {
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // defined(DART_USE_TCMALLOC) || defined(PRODUCT)
|
||||
#endif // !defined(DART_USE_TCMALLOC) || defined(PRODUCT) ||
|
||||
// defined(TARGET_ARCH_DBC) || defined(TARGET_OS_FUCHSIA)
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "vm/dart_entry.h"
|
||||
#include "vm/debugger.h"
|
||||
#include "vm/isolate.h"
|
||||
#include "vm/malloc_hooks.h"
|
||||
#include "vm/object.h"
|
||||
#include "vm/object_store.h"
|
||||
#include "vm/simulator.h"
|
||||
@@ -2709,6 +2710,9 @@ 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(CodeImmutability) {
|
||||
bool stack_trace_collection_enabled =
|
||||
MallocHooks::stack_trace_collection_enabled();
|
||||
MallocHooks::set_stack_trace_collection_enabled(false);
|
||||
extern void GenerateIncrement(Assembler * assembler);
|
||||
Assembler _assembler_;
|
||||
GenerateIncrement(&_assembler_);
|
||||
@@ -2726,6 +2730,8 @@ ISOLATE_UNIT_TEST_CASE(CodeImmutability) {
|
||||
// TODO(regis, fschneider): Should this be FATAL() instead?
|
||||
OS::DebugBreak();
|
||||
}
|
||||
MallocHooks::set_stack_trace_collection_enabled(
|
||||
stack_trace_collection_enabled);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -95,6 +95,9 @@ class OS {
|
||||
// Debug break.
|
||||
static void DebugBreak();
|
||||
|
||||
// Returns the current program counter.
|
||||
static uintptr_t GetProgramCounter();
|
||||
|
||||
// Not all platform support strndup.
|
||||
static char* StrNDup(const char* s, intptr_t n);
|
||||
static intptr_t StrNLen(const char* s, intptr_t n);
|
||||
|
||||
@@ -276,6 +276,12 @@ void OS::DebugBreak() {
|
||||
}
|
||||
|
||||
|
||||
uintptr_t DART_NOINLINE OS::GetProgramCounter() {
|
||||
return reinterpret_cast<uintptr_t>(
|
||||
__builtin_extract_return_addr(__builtin_return_address(0)));
|
||||
}
|
||||
|
||||
|
||||
char* OS::StrNDup(const char* s, intptr_t n) {
|
||||
return strndup(s, n);
|
||||
}
|
||||
|
||||
@@ -177,6 +177,12 @@ void OS::DebugBreak() {
|
||||
}
|
||||
|
||||
|
||||
uintptr_t DART_NOINLINE OS::GetProgramCounter() {
|
||||
return reinterpret_cast<uintptr_t>(
|
||||
__builtin_extract_return_addr(__builtin_return_address(0)));
|
||||
}
|
||||
|
||||
|
||||
char* OS::StrNDup(const char* s, intptr_t n) {
|
||||
return strndup(s, n);
|
||||
}
|
||||
|
||||
@@ -287,6 +287,12 @@ void OS::DebugBreak() {
|
||||
}
|
||||
|
||||
|
||||
uintptr_t DART_NOINLINE OS::GetProgramCounter() {
|
||||
return reinterpret_cast<uintptr_t>(
|
||||
__builtin_extract_return_addr(__builtin_return_address(0)));
|
||||
}
|
||||
|
||||
|
||||
char* OS::StrNDup(const char* s, intptr_t n) {
|
||||
return strndup(s, n);
|
||||
}
|
||||
|
||||
@@ -266,6 +266,12 @@ void OS::DebugBreak() {
|
||||
}
|
||||
|
||||
|
||||
uintptr_t DART_NOINLINE OS::GetProgramCounter() {
|
||||
return reinterpret_cast<uintptr_t>(
|
||||
__builtin_extract_return_addr(__builtin_return_address(0)));
|
||||
}
|
||||
|
||||
|
||||
char* OS::StrNDup(const char* s, intptr_t n) {
|
||||
// strndup has only been added to Mac OS X in 10.7. We are supplying
|
||||
// our own copy here if needed.
|
||||
|
||||
+10
-2
@@ -116,7 +116,7 @@ class OSThread : public BaseThread {
|
||||
bool ThreadInterruptsEnabled();
|
||||
|
||||
// The currently executing thread, or NULL if not yet initialized.
|
||||
static OSThread* Current() {
|
||||
static OSThread* TryCurrent() {
|
||||
BaseThread* thread = GetCurrentTLS();
|
||||
OSThread* os_thread = NULL;
|
||||
if (thread != NULL) {
|
||||
@@ -126,7 +126,15 @@ class OSThread : public BaseThread {
|
||||
Thread* vm_thread = reinterpret_cast<Thread*>(thread);
|
||||
os_thread = GetOSThreadFromThread(vm_thread);
|
||||
}
|
||||
} else {
|
||||
}
|
||||
return os_thread;
|
||||
}
|
||||
|
||||
// The currently executing thread. If there is no currently executing thread,
|
||||
// a new OSThread is created and returned.
|
||||
static OSThread* Current() {
|
||||
OSThread* os_thread = TryCurrent();
|
||||
if (os_thread == NULL) {
|
||||
os_thread = CreateAndSetUnknownThread();
|
||||
}
|
||||
return os_thread;
|
||||
|
||||
@@ -265,6 +265,11 @@ void OS::DebugBreak() {
|
||||
}
|
||||
|
||||
|
||||
DART_NOINLINE uintptr_t OS::GetProgramCounter() {
|
||||
return reinterpret_cast<uintptr_t>(_ReturnAddress());
|
||||
}
|
||||
|
||||
|
||||
char* OS::StrNDup(const char* s, intptr_t n) {
|
||||
intptr_t len = strlen(s);
|
||||
if ((n < 0) || (len < 0)) {
|
||||
|
||||
+128
-51
@@ -168,7 +168,7 @@ Sample* SampleBuffer::ReserveSampleAndLink(Sample* previous) {
|
||||
ASSERT(previous != NULL);
|
||||
intptr_t next_index = ReserveSampleSlot();
|
||||
Sample* next = At(next_index);
|
||||
next->Init(previous->isolate(), previous->timestamp(), previous->tid());
|
||||
next->Init(previous->port(), previous->timestamp(), previous->tid());
|
||||
next->set_head_sample(false);
|
||||
// Mark that previous continues at next.
|
||||
previous->SetContinuationIndex(next_index);
|
||||
@@ -321,7 +321,7 @@ bool SampleFilter::TaskFilterSample(Sample* sample) {
|
||||
|
||||
|
||||
ClearProfileVisitor::ClearProfileVisitor(Isolate* isolate)
|
||||
: SampleVisitor(isolate) {}
|
||||
: SampleVisitor(isolate->main_port()) {}
|
||||
|
||||
|
||||
void ClearProfileVisitor::VisitSample(Sample* sample) {
|
||||
@@ -357,15 +357,17 @@ static void DumpStackFrame(intptr_t frame_index, uword pc) {
|
||||
|
||||
class ProfilerStackWalker : public ValueObject {
|
||||
public:
|
||||
ProfilerStackWalker(Isolate* isolate,
|
||||
ProfilerStackWalker(Dart_Port port_id,
|
||||
Sample* head_sample,
|
||||
SampleBuffer* sample_buffer)
|
||||
: isolate_(isolate),
|
||||
SampleBuffer* sample_buffer,
|
||||
intptr_t skip_count = 0)
|
||||
: port_id_(port_id),
|
||||
sample_(head_sample),
|
||||
sample_buffer_(sample_buffer),
|
||||
skip_count_(skip_count),
|
||||
frames_skipped_(0),
|
||||
frame_index_(0),
|
||||
total_frames_(0) {
|
||||
ASSERT(isolate_ != NULL);
|
||||
if (sample_ == NULL) {
|
||||
ASSERT(sample_buffer_ == NULL);
|
||||
} else {
|
||||
@@ -375,6 +377,11 @@ class ProfilerStackWalker : public ValueObject {
|
||||
}
|
||||
|
||||
bool Append(uword pc) {
|
||||
if (frames_skipped_ < skip_count_) {
|
||||
frames_skipped_++;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (sample_ == NULL) {
|
||||
DumpStackFrame(frame_index_, pc);
|
||||
frame_index_++;
|
||||
@@ -404,9 +411,11 @@ class ProfilerStackWalker : public ValueObject {
|
||||
}
|
||||
|
||||
protected:
|
||||
Isolate* isolate_;
|
||||
Dart_Port port_id_;
|
||||
Sample* sample_;
|
||||
SampleBuffer* sample_buffer_;
|
||||
intptr_t skip_count_;
|
||||
intptr_t frames_skipped_;
|
||||
intptr_t frame_index_;
|
||||
intptr_t total_frames_;
|
||||
};
|
||||
@@ -424,8 +433,14 @@ class ProfilerDartStackWalker : public ProfilerStackWalker {
|
||||
uword fp,
|
||||
uword sp,
|
||||
bool exited_dart_code,
|
||||
bool allocation_sample)
|
||||
: ProfilerStackWalker(thread->isolate(), sample, sample_buffer),
|
||||
bool allocation_sample,
|
||||
intptr_t skip_count = 0)
|
||||
: ProfilerStackWalker((thread->isolate() != NULL)
|
||||
? thread->isolate()->main_port()
|
||||
: ILLEGAL_PORT,
|
||||
sample,
|
||||
sample_buffer,
|
||||
skip_count),
|
||||
pc_(reinterpret_cast<uword*>(pc)),
|
||||
fp_(reinterpret_cast<uword*>(fp)),
|
||||
sp_(reinterpret_cast<uword*>(sp)),
|
||||
@@ -597,15 +612,16 @@ class ProfilerDartStackWalker : public ProfilerStackWalker {
|
||||
//
|
||||
class ProfilerNativeStackWalker : public ProfilerStackWalker {
|
||||
public:
|
||||
ProfilerNativeStackWalker(Isolate* isolate,
|
||||
ProfilerNativeStackWalker(Dart_Port port_id,
|
||||
Sample* sample,
|
||||
SampleBuffer* sample_buffer,
|
||||
uword stack_lower,
|
||||
uword stack_upper,
|
||||
uword pc,
|
||||
uword fp,
|
||||
uword sp)
|
||||
: ProfilerStackWalker(isolate, sample, sample_buffer),
|
||||
uword sp,
|
||||
intptr_t skip_count = 0)
|
||||
: ProfilerStackWalker(port_id, sample, sample_buffer, skip_count),
|
||||
stack_upper_(stack_upper),
|
||||
original_pc_(pc),
|
||||
original_fp_(fp),
|
||||
@@ -614,6 +630,7 @@ class ProfilerNativeStackWalker : public ProfilerStackWalker {
|
||||
|
||||
void walk() {
|
||||
const uword kMaxStep = VirtualMemory::PageSize();
|
||||
|
||||
Append(original_pc_);
|
||||
|
||||
uword* pc = reinterpret_cast<uword*>(original_pc_);
|
||||
@@ -796,6 +813,29 @@ static void CollectSample(Isolate* isolate,
|
||||
}
|
||||
|
||||
|
||||
static bool ValidateThreadStackBounds(uintptr_t fp,
|
||||
uintptr_t sp,
|
||||
uword stack_lower,
|
||||
uword stack_upper) {
|
||||
if (stack_lower >= stack_upper) {
|
||||
// Stack boundary is invalid.
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((sp < stack_lower) || (sp >= stack_upper)) {
|
||||
// Stack pointer is outside thread's stack boundary.
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((fp < stack_lower) || (fp >= stack_upper)) {
|
||||
// Frame pointer is outside threads's stack boundary.
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Get |isolate|'s stack boundary and verify that |sp| and |fp| are within
|
||||
// it. If |get_os_thread_bounds| is true then if |isolate| stackbounds are
|
||||
// not available we fallback to using underlying OS thread bounds. This only
|
||||
@@ -807,8 +847,12 @@ static bool GetAndValidateThreadStackBounds(Thread* thread,
|
||||
uword* stack_lower,
|
||||
uword* stack_upper,
|
||||
bool get_os_thread_bounds = false) {
|
||||
ASSERT(thread != NULL);
|
||||
OSThread* os_thread = thread->os_thread();
|
||||
OSThread* os_thread = NULL;
|
||||
if (thread != NULL) {
|
||||
os_thread = thread->os_thread();
|
||||
} else {
|
||||
os_thread = OSThread::Current();
|
||||
}
|
||||
ASSERT(os_thread != NULL);
|
||||
ASSERT(stack_lower != NULL);
|
||||
ASSERT(stack_upper != NULL);
|
||||
@@ -844,22 +888,7 @@ static bool GetAndValidateThreadStackBounds(Thread* thread,
|
||||
*stack_lower = sp;
|
||||
}
|
||||
|
||||
if (*stack_lower >= *stack_upper) {
|
||||
// Stack boundary is invalid.
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((sp < *stack_lower) || (sp >= *stack_upper)) {
|
||||
// Stack pointer is outside thread's stack boundary.
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((fp < *stack_lower) || (fp >= *stack_upper)) {
|
||||
// Frame pointer is outside threads's stack boundary.
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return ValidateThreadStackBounds(fp, sp, *stack_lower, *stack_upper);
|
||||
}
|
||||
|
||||
|
||||
@@ -887,7 +916,7 @@ static Sample* SetupSample(Thread* thread,
|
||||
Isolate* isolate = thread->isolate();
|
||||
ASSERT(sample_buffer != NULL);
|
||||
Sample* sample = sample_buffer->ReserveSample();
|
||||
sample->Init(isolate, OS::GetCurrentMonotonicMicros(), tid);
|
||||
sample->Init(isolate->main_port(), OS::GetCurrentMonotonicMicros(), tid);
|
||||
uword vm_tag = thread->vm_tag();
|
||||
#if defined(USING_SIMULATOR) && !defined(TARGET_ARCH_DBC)
|
||||
// When running in the simulator, the runtime entry function address
|
||||
@@ -905,6 +934,23 @@ static Sample* SetupSample(Thread* thread,
|
||||
}
|
||||
|
||||
|
||||
static Sample* SetupSampleNative(SampleBuffer* sample_buffer, ThreadId tid) {
|
||||
Sample* sample = sample_buffer->ReserveSample();
|
||||
sample->Init(ILLEGAL_PORT, OS::GetCurrentMonotonicMicros(), tid);
|
||||
sample->set_is_native_allocation_sample(true);
|
||||
|
||||
Thread* thread = Thread::Current();
|
||||
|
||||
// TODO(bkonyi) Any samples created while a current thread doesn't exist are
|
||||
// ignored by the NativeAllocationSampleFilter since the default task is
|
||||
// kUnknownTask. Is this what we want to do?
|
||||
if (thread != NULL) {
|
||||
sample->set_thread_task(thread->task_kind());
|
||||
}
|
||||
return sample;
|
||||
}
|
||||
|
||||
|
||||
static bool CheckIsolate(Isolate* isolate) {
|
||||
if ((isolate == NULL) || (Dart::vm_isolate() == NULL)) {
|
||||
// No isolate.
|
||||
@@ -914,18 +960,6 @@ static bool CheckIsolate(Isolate* isolate) {
|
||||
}
|
||||
|
||||
|
||||
#if defined(TARGET_OS_WINDOWS)
|
||||
__declspec(noinline) static uintptr_t GetProgramCounter() {
|
||||
return reinterpret_cast<uintptr_t>(_ReturnAddress());
|
||||
}
|
||||
#else
|
||||
static uintptr_t __attribute__((noinline)) GetProgramCounter() {
|
||||
return reinterpret_cast<uintptr_t>(
|
||||
__builtin_extract_return_addr(__builtin_return_address(0)));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void Profiler::DumpStackTrace(void* context) {
|
||||
#if defined(TARGET_OS_LINUX) || defined(TARGET_OS_MACOS)
|
||||
ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
|
||||
@@ -944,7 +978,7 @@ void Profiler::DumpStackTrace(void* context) {
|
||||
void Profiler::DumpStackTrace() {
|
||||
uintptr_t sp = Thread::GetCurrentStackPointer();
|
||||
uintptr_t fp = 0;
|
||||
uintptr_t pc = GetProgramCounter();
|
||||
uintptr_t pc = OS::GetProgramCounter();
|
||||
|
||||
COPY_FP_REGISTER(fp);
|
||||
|
||||
@@ -992,7 +1026,8 @@ void Profiler::DumpStackTrace(uword sp, uword fp, uword pc) {
|
||||
}
|
||||
|
||||
ProfilerNativeStackWalker native_stack_walker(
|
||||
isolate, NULL, NULL, stack_lower, stack_upper, pc, fp, sp);
|
||||
(isolate != NULL) ? isolate->main_port() : ILLEGAL_PORT, NULL, NULL,
|
||||
stack_lower, stack_upper, pc, fp, sp);
|
||||
native_stack_walker.walk();
|
||||
OS::PrintErr("-- End of DumpStackTrace\n");
|
||||
}
|
||||
@@ -1017,7 +1052,7 @@ void Profiler::SampleAllocation(Thread* thread, intptr_t cid) {
|
||||
|
||||
uintptr_t sp = Thread::GetCurrentStackPointer();
|
||||
uintptr_t fp = 0;
|
||||
uintptr_t pc = GetProgramCounter();
|
||||
uintptr_t pc = OS::GetProgramCounter();
|
||||
|
||||
COPY_FP_REGISTER(fp);
|
||||
|
||||
@@ -1039,7 +1074,8 @@ void Profiler::SampleAllocation(Thread* thread, intptr_t cid) {
|
||||
|
||||
if (FLAG_profile_vm) {
|
||||
ProfilerNativeStackWalker native_stack_walker(
|
||||
isolate, sample, sample_buffer, stack_lower, stack_upper, pc, fp, sp);
|
||||
(isolate != NULL) ? isolate->main_port() : ILLEGAL_PORT, sample,
|
||||
sample_buffer, stack_lower, stack_upper, pc, fp, sp);
|
||||
native_stack_walker.walk();
|
||||
} else if (exited_dart_code) {
|
||||
ProfilerDartStackWalker dart_exit_stack_walker(
|
||||
@@ -1048,7 +1084,7 @@ void Profiler::SampleAllocation(Thread* thread, intptr_t cid) {
|
||||
dart_exit_stack_walker.walk();
|
||||
} else {
|
||||
// Fall back.
|
||||
uintptr_t pc = GetProgramCounter();
|
||||
uintptr_t pc = OS::GetProgramCounter();
|
||||
Sample* sample = SetupSample(thread, sample_buffer, os_thread->trace_id());
|
||||
sample->SetAllocationCid(cid);
|
||||
sample->SetAt(0, pc);
|
||||
@@ -1056,6 +1092,44 @@ void Profiler::SampleAllocation(Thread* thread, intptr_t cid) {
|
||||
}
|
||||
|
||||
|
||||
Sample* Profiler::SampleNativeAllocation(intptr_t skip_count) {
|
||||
SampleBuffer* sample_buffer = Profiler::sample_buffer();
|
||||
if (sample_buffer == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uintptr_t sp = Thread::GetCurrentStackPointer();
|
||||
uintptr_t fp = 0;
|
||||
uintptr_t pc = OS::GetProgramCounter();
|
||||
|
||||
COPY_FP_REGISTER(fp);
|
||||
|
||||
uword stack_lower = 0;
|
||||
uword stack_upper = 0;
|
||||
if (!InitialRegisterCheck(pc, fp, sp)) {
|
||||
AtomicOperations::IncrementInt64By(
|
||||
&counters_.failure_native_allocation_sample, 1);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(OSThread::GetCurrentStackBounds(&stack_lower, &stack_upper) &&
|
||||
ValidateThreadStackBounds(fp, sp, stack_lower, stack_upper))) {
|
||||
// Could not get stack boundary.
|
||||
AtomicOperations::IncrementInt64By(
|
||||
&counters_.failure_native_allocation_sample, 1);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
OSThread* os_thread = OSThread::Current();
|
||||
Sample* sample = SetupSampleNative(sample_buffer, os_thread->trace_id());
|
||||
ProfilerNativeStackWalker native_stack_walker(
|
||||
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, uintptr_t pc) {
|
||||
ASSERT(thread != NULL);
|
||||
OSThread* os_thread = thread->os_thread();
|
||||
@@ -1181,7 +1255,8 @@ void Profiler::SampleThread(Thread* thread,
|
||||
}
|
||||
|
||||
ProfilerNativeStackWalker native_stack_walker(
|
||||
isolate, sample, sample_buffer, stack_lower, stack_upper, pc, fp, sp);
|
||||
(isolate != NULL) ? isolate->main_port() : ILLEGAL_PORT, sample,
|
||||
sample_buffer, stack_lower, stack_upper, pc, fp, sp);
|
||||
const bool exited_dart_code = thread->HasExitedDartCode();
|
||||
ProfilerDartStackWalker dart_stack_walker(thread, sample, sample_buffer,
|
||||
stack_lower, stack_upper, pc, fp,
|
||||
@@ -1341,7 +1416,9 @@ ProcessedSampleBuffer* SampleBuffer::BuildProcessedSampleBuffer(
|
||||
// An inner sample in a chain of samples.
|
||||
continue;
|
||||
}
|
||||
if (sample->isolate() != filter->isolate()) {
|
||||
// If we're requesting all the native allocation samples, we don't care
|
||||
// whether or not we're in the same isolate as the sample.
|
||||
if (sample->port() != filter->port()) {
|
||||
// Another isolate.
|
||||
continue;
|
||||
}
|
||||
@@ -1420,7 +1497,7 @@ Sample* SampleBuffer::Next(Sample* sample) {
|
||||
// Sanity check.
|
||||
ASSERT(sample != next_sample);
|
||||
// Detect invalid chaining.
|
||||
if (sample->isolate() != next_sample->isolate()) {
|
||||
if (sample->port() != next_sample->port()) {
|
||||
return NULL;
|
||||
}
|
||||
if (sample->timestamp() != next_sample->timestamp()) {
|
||||
|
||||
+29
-15
@@ -41,6 +41,8 @@ struct ProfilerCounters {
|
||||
int64_t stack_walker_dart_exit;
|
||||
int64_t stack_walker_dart;
|
||||
int64_t stack_walker_none;
|
||||
// Count of failed checks:
|
||||
int64_t failure_native_allocation_sample;
|
||||
};
|
||||
|
||||
|
||||
@@ -58,6 +60,7 @@ class Profiler : public AllStatic {
|
||||
static void DumpStackTrace();
|
||||
|
||||
static void SampleAllocation(Thread* thread, intptr_t cid);
|
||||
static Sample* SampleNativeAllocation(intptr_t skip_count);
|
||||
|
||||
// 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
|
||||
@@ -91,7 +94,7 @@ class Profiler : public AllStatic {
|
||||
|
||||
class SampleVisitor : public ValueObject {
|
||||
public:
|
||||
explicit SampleVisitor(Isolate* isolate) : isolate_(isolate), visited_(0) {}
|
||||
explicit SampleVisitor(Dart_Port port) : port_(port), visited_(0) {}
|
||||
virtual ~SampleVisitor() {}
|
||||
|
||||
virtual void VisitSample(Sample* sample) = 0;
|
||||
@@ -100,10 +103,10 @@ class SampleVisitor : public ValueObject {
|
||||
|
||||
void IncrementVisited() { visited_++; }
|
||||
|
||||
Isolate* isolate() const { return isolate_; }
|
||||
Dart_Port port() const { return port_; }
|
||||
|
||||
private:
|
||||
Isolate* isolate_;
|
||||
Dart_Port port_;
|
||||
intptr_t visited_;
|
||||
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(SampleVisitor);
|
||||
@@ -112,11 +115,11 @@ class SampleVisitor : public ValueObject {
|
||||
|
||||
class SampleFilter : public ValueObject {
|
||||
public:
|
||||
SampleFilter(Isolate* isolate,
|
||||
SampleFilter(Dart_Port port,
|
||||
intptr_t thread_task_mask,
|
||||
int64_t time_origin_micros,
|
||||
int64_t time_extent_micros)
|
||||
: isolate_(isolate),
|
||||
: port_(port),
|
||||
thread_task_mask_(thread_task_mask),
|
||||
time_origin_micros_(time_origin_micros),
|
||||
time_extent_micros_(time_extent_micros) {
|
||||
@@ -130,7 +133,7 @@ class SampleFilter : public ValueObject {
|
||||
// Return |true| if |sample| passes the filter.
|
||||
virtual bool FilterSample(Sample* sample) { return true; }
|
||||
|
||||
Isolate* isolate() const { return isolate_; }
|
||||
Dart_Port port() const { return port_; }
|
||||
|
||||
// Returns |true| if |sample| passes the time filter.
|
||||
bool TimeFilterSample(Sample* sample);
|
||||
@@ -139,7 +142,7 @@ class SampleFilter : public ValueObject {
|
||||
bool TaskFilterSample(Sample* sample);
|
||||
|
||||
private:
|
||||
Isolate* isolate_;
|
||||
Dart_Port port_;
|
||||
intptr_t thread_task_mask_;
|
||||
int64_t time_origin_micros_;
|
||||
int64_t time_extent_micros_;
|
||||
@@ -157,21 +160,20 @@ class ClearProfileVisitor : public SampleVisitor {
|
||||
// Each Sample holds a stack trace from an isolate.
|
||||
class Sample {
|
||||
public:
|
||||
void Init(Isolate* isolate, int64_t timestamp, ThreadId tid) {
|
||||
void Init(Dart_Port port, int64_t timestamp, ThreadId tid) {
|
||||
Clear();
|
||||
timestamp_ = timestamp;
|
||||
tid_ = tid;
|
||||
isolate_ = isolate;
|
||||
port_ = port;
|
||||
}
|
||||
|
||||
// Isolate sample was taken from.
|
||||
Isolate* isolate() const { return isolate_; }
|
||||
Dart_Port port() const { return port_; }
|
||||
|
||||
// Thread sample was taken on.
|
||||
ThreadId tid() const { return tid_; }
|
||||
|
||||
void Clear() {
|
||||
isolate_ = NULL;
|
||||
port_ = ILLEGAL_PORT;
|
||||
pc_marker_ = 0;
|
||||
for (intptr_t i = 0; i < kStackBufferSizeInWords; i++) {
|
||||
stack_buffer_[i] = 0;
|
||||
@@ -268,6 +270,15 @@ class Sample {
|
||||
state_ = ClassAllocationSampleBit::update(allocation_sample, state_);
|
||||
}
|
||||
|
||||
bool is_native_allocation_sample() const {
|
||||
return NativeAllocationSampleBit::decode(state_);
|
||||
}
|
||||
|
||||
void set_is_native_allocation_sample(bool native_allocation_sample) {
|
||||
state_ =
|
||||
NativeAllocationSampleBit::update(native_allocation_sample, state_);
|
||||
}
|
||||
|
||||
Thread::TaskKind thread_task() const { return ThreadTaskBit::decode(state_); }
|
||||
|
||||
void set_thread_task(Thread::TaskKind task) {
|
||||
@@ -331,7 +342,8 @@ class Sample {
|
||||
kClassAllocationSampleBit = 6,
|
||||
kContinuationSampleBit = 7,
|
||||
kThreadTaskBit = 8, // 5 bits.
|
||||
kNextFreeBit = 13,
|
||||
kNativeAllocationSampleBit = 13,
|
||||
kNextFreeBit = 14,
|
||||
};
|
||||
class HeadSampleBit : public BitField<uword, bool, kHeadSampleBit, 1> {};
|
||||
class LeafFrameIsDart : public BitField<uword, bool, kLeafFrameIsDartBit, 1> {
|
||||
@@ -348,10 +360,12 @@ class Sample {
|
||||
: public BitField<uword, bool, kContinuationSampleBit, 1> {};
|
||||
class ThreadTaskBit
|
||||
: public BitField<uword, Thread::TaskKind, kThreadTaskBit, 5> {};
|
||||
class NativeAllocationSampleBit
|
||||
: public BitField<uword, bool, kNativeAllocationSampleBit, 1> {};
|
||||
|
||||
int64_t timestamp_;
|
||||
ThreadId tid_;
|
||||
Isolate* isolate_;
|
||||
Dart_Port port_;
|
||||
uword pc_marker_;
|
||||
uword stack_buffer_[kStackBufferSizeInWords];
|
||||
uword vm_tag_;
|
||||
@@ -474,7 +488,7 @@ class SampleBuffer {
|
||||
// Bad sample.
|
||||
continue;
|
||||
}
|
||||
if (sample->isolate() != visitor->isolate()) {
|
||||
if (sample->port() != visitor->port()) {
|
||||
// Another isolate.
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -2670,16 +2670,19 @@ void ProfilerService::PrintJSONImpl(Thread* thread,
|
||||
|
||||
class NoAllocationSampleFilter : public SampleFilter {
|
||||
public:
|
||||
NoAllocationSampleFilter(Isolate* isolate,
|
||||
NoAllocationSampleFilter(Dart_Port port,
|
||||
intptr_t thread_task_mask,
|
||||
int64_t time_origin_micros,
|
||||
int64_t time_extent_micros)
|
||||
: SampleFilter(isolate,
|
||||
: SampleFilter(port,
|
||||
thread_task_mask,
|
||||
time_origin_micros,
|
||||
time_extent_micros) {}
|
||||
|
||||
bool FilterSample(Sample* sample) { return !sample->is_allocation_sample(); }
|
||||
bool FilterSample(Sample* sample) {
|
||||
return !sample->is_allocation_sample() &&
|
||||
!sample->is_native_allocation_sample();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -2690,7 +2693,7 @@ void ProfilerService::PrintJSON(JSONStream* stream,
|
||||
int64_t time_extent_micros) {
|
||||
Thread* thread = Thread::Current();
|
||||
Isolate* isolate = thread->isolate();
|
||||
NoAllocationSampleFilter filter(isolate, Thread::kMutatorTask,
|
||||
NoAllocationSampleFilter filter(isolate->main_port(), Thread::kMutatorTask,
|
||||
time_origin_micros, time_extent_micros);
|
||||
const bool as_timeline = false;
|
||||
PrintJSONImpl(thread, stream, tag_order, extra_tags, &filter, as_timeline);
|
||||
@@ -2699,12 +2702,12 @@ void ProfilerService::PrintJSON(JSONStream* stream,
|
||||
|
||||
class ClassAllocationSampleFilter : public SampleFilter {
|
||||
public:
|
||||
ClassAllocationSampleFilter(Isolate* isolate,
|
||||
ClassAllocationSampleFilter(Dart_Port port,
|
||||
const Class& cls,
|
||||
intptr_t thread_task_mask,
|
||||
int64_t time_origin_micros,
|
||||
int64_t time_extent_micros)
|
||||
: SampleFilter(isolate,
|
||||
: SampleFilter(port,
|
||||
thread_task_mask,
|
||||
time_origin_micros,
|
||||
time_extent_micros),
|
||||
@@ -2722,6 +2725,21 @@ class ClassAllocationSampleFilter : public SampleFilter {
|
||||
};
|
||||
|
||||
|
||||
class NativeAllocationSampleFilter : public SampleFilter {
|
||||
public:
|
||||
NativeAllocationSampleFilter(intptr_t thread_task_mask,
|
||||
int64_t time_origin_micros,
|
||||
int64_t time_extent_micros)
|
||||
: SampleFilter(ILLEGAL_PORT,
|
||||
thread_task_mask,
|
||||
time_origin_micros,
|
||||
time_extent_micros) {}
|
||||
bool FilterSample(Sample* sample) {
|
||||
return sample->is_native_allocation_sample();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
void ProfilerService::PrintAllocationJSON(JSONStream* stream,
|
||||
Profile::TagOrder tag_order,
|
||||
const Class& cls,
|
||||
@@ -2729,8 +2747,24 @@ void ProfilerService::PrintAllocationJSON(JSONStream* stream,
|
||||
int64_t time_extent_micros) {
|
||||
Thread* thread = Thread::Current();
|
||||
Isolate* isolate = thread->isolate();
|
||||
ClassAllocationSampleFilter filter(isolate, cls, Thread::kMutatorTask,
|
||||
time_origin_micros, time_extent_micros);
|
||||
ClassAllocationSampleFilter filter(isolate->main_port(), cls,
|
||||
Thread::kMutatorTask, time_origin_micros,
|
||||
time_extent_micros);
|
||||
const bool as_timeline = false;
|
||||
PrintJSONImpl(thread, stream, tag_order, kNoExtraTags, &filter, as_timeline);
|
||||
}
|
||||
|
||||
|
||||
void ProfilerService::PrintNativeAllocationJSON(JSONStream* stream,
|
||||
Profile::TagOrder tag_order,
|
||||
int64_t time_origin_micros,
|
||||
int64_t time_extent_micros) {
|
||||
Thread* thread = Thread::Current();
|
||||
const intptr_t thread_task_mask = Thread::kMutatorTask |
|
||||
Thread::kCompilerTask |
|
||||
Thread::kSweeperTask | Thread::kMarkerTask;
|
||||
NativeAllocationSampleFilter filter(thread_task_mask, time_origin_micros,
|
||||
time_extent_micros);
|
||||
const bool as_timeline = false;
|
||||
PrintJSONImpl(thread, stream, tag_order, kNoExtraTags, &filter, as_timeline);
|
||||
}
|
||||
@@ -2745,8 +2779,8 @@ void ProfilerService::PrintTimelineJSON(JSONStream* stream,
|
||||
const intptr_t thread_task_mask = Thread::kMutatorTask |
|
||||
Thread::kCompilerTask |
|
||||
Thread::kSweeperTask | Thread::kMarkerTask;
|
||||
NoAllocationSampleFilter filter(isolate, thread_task_mask, time_origin_micros,
|
||||
time_extent_micros);
|
||||
NoAllocationSampleFilter filter(isolate->main_port(), thread_task_mask,
|
||||
time_origin_micros, time_extent_micros);
|
||||
const bool as_timeline = true;
|
||||
PrintJSONImpl(thread, stream, tag_order, kNoExtraTags, &filter, as_timeline);
|
||||
}
|
||||
|
||||
@@ -419,6 +419,11 @@ class ProfilerService : public AllStatic {
|
||||
int64_t time_origin_micros,
|
||||
int64_t time_extent_micros);
|
||||
|
||||
static void PrintNativeAllocationJSON(JSONStream* stream,
|
||||
Profile::TagOrder tag_order,
|
||||
int64_t time_origin_micros,
|
||||
int64_t time_extent_micros);
|
||||
|
||||
static void PrintTimelineJSON(JSONStream* stream,
|
||||
Profile::TagOrder tag_order,
|
||||
int64_t time_origin_micros,
|
||||
|
||||
+57
-56
@@ -68,12 +68,12 @@ class MaxProfileDepthScope : public ValueObject {
|
||||
|
||||
class ProfileSampleBufferTestHelper {
|
||||
public:
|
||||
static intptr_t IterateCount(const Isolate* isolate,
|
||||
static intptr_t IterateCount(const Dart_Port port,
|
||||
const SampleBuffer& sample_buffer) {
|
||||
intptr_t c = 0;
|
||||
for (intptr_t i = 0; i < sample_buffer.capacity(); i++) {
|
||||
Sample* sample = sample_buffer.At(i);
|
||||
if (sample->isolate() != isolate) {
|
||||
if (sample->port() != port) {
|
||||
continue;
|
||||
}
|
||||
c++;
|
||||
@@ -82,12 +82,12 @@ class ProfileSampleBufferTestHelper {
|
||||
}
|
||||
|
||||
|
||||
static intptr_t IterateSumPC(const Isolate* isolate,
|
||||
static intptr_t IterateSumPC(const Dart_Port port,
|
||||
const SampleBuffer& sample_buffer) {
|
||||
intptr_t c = 0;
|
||||
for (intptr_t i = 0; i < sample_buffer.capacity(); i++) {
|
||||
Sample* sample = sample_buffer.At(i);
|
||||
if (sample->isolate() != isolate) {
|
||||
if (sample->port() != port) {
|
||||
continue;
|
||||
}
|
||||
c += sample->At(0);
|
||||
@@ -99,7 +99,7 @@ class ProfileSampleBufferTestHelper {
|
||||
|
||||
TEST_CASE(Profiler_SampleBufferWrapTest) {
|
||||
SampleBuffer* sample_buffer = new SampleBuffer(3);
|
||||
Isolate* i = reinterpret_cast<Isolate*>(0x1);
|
||||
Dart_Port i = 123;
|
||||
EXPECT_EQ(0, ProfileSampleBufferTestHelper::IterateSumPC(i, *sample_buffer));
|
||||
Sample* s;
|
||||
s = sample_buffer->ReserveSample();
|
||||
@@ -124,7 +124,7 @@ TEST_CASE(Profiler_SampleBufferWrapTest) {
|
||||
|
||||
TEST_CASE(Profiler_SampleBufferIterateTest) {
|
||||
SampleBuffer* sample_buffer = new SampleBuffer(3);
|
||||
Isolate* i = reinterpret_cast<Isolate*>(0x1);
|
||||
Dart_Port i = 123;
|
||||
EXPECT_EQ(0, ProfileSampleBufferTestHelper::IterateCount(i, *sample_buffer));
|
||||
Sample* s;
|
||||
s = sample_buffer->ReserveSample();
|
||||
@@ -147,7 +147,7 @@ TEST_CASE(Profiler_AllocationSampleTest) {
|
||||
Isolate* isolate = Isolate::Current();
|
||||
SampleBuffer* sample_buffer = new SampleBuffer(3);
|
||||
Sample* sample = sample_buffer->ReserveSample();
|
||||
sample->Init(isolate, 0, 0);
|
||||
sample->Init(isolate->main_port(), 0, 0);
|
||||
sample->set_metadata(99);
|
||||
sample->set_is_allocation_sample(true);
|
||||
EXPECT_EQ(99, sample->allocation_cid());
|
||||
@@ -173,11 +173,11 @@ static RawFunction* GetFunction(const Library& lib, const char* name) {
|
||||
|
||||
class AllocationFilter : public SampleFilter {
|
||||
public:
|
||||
AllocationFilter(Isolate* isolate,
|
||||
AllocationFilter(Dart_Port port,
|
||||
intptr_t cid,
|
||||
int64_t time_origin_micros = -1,
|
||||
int64_t time_extent_micros = -1)
|
||||
: SampleFilter(isolate,
|
||||
: SampleFilter(port,
|
||||
Thread::kMutatorTask,
|
||||
time_origin_micros,
|
||||
time_extent_micros),
|
||||
@@ -239,7 +239,8 @@ TEST_CASE(Profiler_TrivialRecordAllocation) {
|
||||
HANDLESCOPE(thread);
|
||||
Profile profile(isolate);
|
||||
// Filter for the class in the time range.
|
||||
AllocationFilter filter(isolate, class_a.id(), before_allocations_micros,
|
||||
AllocationFilter filter(isolate->main_port(), class_a.id(),
|
||||
before_allocations_micros,
|
||||
allocation_extent_micros);
|
||||
profile.Build(thread, &filter, Profile::kNoTags);
|
||||
// We should have 1 allocation sample.
|
||||
@@ -306,8 +307,8 @@ TEST_CASE(Profiler_TrivialRecordAllocation) {
|
||||
StackZone zone(thread);
|
||||
HANDLESCOPE(thread);
|
||||
Profile profile(isolate);
|
||||
AllocationFilter filter(isolate, class_a.id(), Dart_TimelineGetMicros(),
|
||||
16000);
|
||||
AllocationFilter filter(isolate->main_port(), class_a.id(),
|
||||
Dart_TimelineGetMicros(), 16000);
|
||||
profile.Build(thread, &filter, Profile::kNoTags);
|
||||
// We should have no allocation samples because none occured within
|
||||
// the specified time range.
|
||||
@@ -350,7 +351,7 @@ TEST_CASE(Profiler_ToggleRecordAllocation) {
|
||||
StackZone zone(thread);
|
||||
HANDLESCOPE(thread);
|
||||
Profile profile(isolate);
|
||||
AllocationFilter filter(isolate, class_a.id());
|
||||
AllocationFilter filter(isolate->main_port(), class_a.id());
|
||||
profile.Build(thread, &filter, Profile::kNoTags);
|
||||
// We should have no allocation samples.
|
||||
EXPECT_EQ(0, profile.sample_count());
|
||||
@@ -368,7 +369,7 @@ TEST_CASE(Profiler_ToggleRecordAllocation) {
|
||||
StackZone zone(thread);
|
||||
HANDLESCOPE(thread);
|
||||
Profile profile(isolate);
|
||||
AllocationFilter filter(isolate, class_a.id());
|
||||
AllocationFilter filter(isolate->main_port(), class_a.id());
|
||||
profile.Build(thread, &filter, Profile::kNoTags);
|
||||
// We should have one allocation sample.
|
||||
EXPECT_EQ(1, profile.sample_count());
|
||||
@@ -439,7 +440,7 @@ TEST_CASE(Profiler_ToggleRecordAllocation) {
|
||||
StackZone zone(thread);
|
||||
HANDLESCOPE(thread);
|
||||
Profile profile(isolate);
|
||||
AllocationFilter filter(isolate, class_a.id());
|
||||
AllocationFilter filter(isolate->main_port(), class_a.id());
|
||||
profile.Build(thread, &filter, Profile::kNoTags);
|
||||
// We should still only have one allocation sample.
|
||||
EXPECT_EQ(1, profile.sample_count());
|
||||
@@ -480,7 +481,7 @@ TEST_CASE(Profiler_CodeTicks) {
|
||||
StackZone zone(thread);
|
||||
HANDLESCOPE(thread);
|
||||
Profile profile(isolate);
|
||||
AllocationFilter filter(isolate, class_a.id());
|
||||
AllocationFilter filter(isolate->main_port(), class_a.id());
|
||||
profile.Build(thread, &filter, Profile::kNoTags);
|
||||
// We should have no allocation samples.
|
||||
EXPECT_EQ(0, profile.sample_count());
|
||||
@@ -503,7 +504,7 @@ TEST_CASE(Profiler_CodeTicks) {
|
||||
StackZone zone(thread);
|
||||
HANDLESCOPE(thread);
|
||||
Profile profile(isolate);
|
||||
AllocationFilter filter(isolate, class_a.id());
|
||||
AllocationFilter filter(isolate->main_port(), class_a.id());
|
||||
profile.Build(thread, &filter, Profile::kNoTags);
|
||||
// We should have three allocation samples.
|
||||
EXPECT_EQ(3, profile.sample_count());
|
||||
@@ -583,7 +584,7 @@ TEST_CASE(Profiler_FunctionTicks) {
|
||||
StackZone zone(thread);
|
||||
HANDLESCOPE(thread);
|
||||
Profile profile(isolate);
|
||||
AllocationFilter filter(isolate, class_a.id());
|
||||
AllocationFilter filter(isolate->main_port(), class_a.id());
|
||||
profile.Build(thread, &filter, Profile::kNoTags);
|
||||
// We should have no allocation samples.
|
||||
EXPECT_EQ(0, profile.sample_count());
|
||||
@@ -606,7 +607,7 @@ TEST_CASE(Profiler_FunctionTicks) {
|
||||
StackZone zone(thread);
|
||||
HANDLESCOPE(thread);
|
||||
Profile profile(isolate);
|
||||
AllocationFilter filter(isolate, class_a.id());
|
||||
AllocationFilter filter(isolate->main_port(), class_a.id());
|
||||
profile.Build(thread, &filter, Profile::kNoTags);
|
||||
// We should have three allocation samples.
|
||||
EXPECT_EQ(3, profile.sample_count());
|
||||
@@ -677,7 +678,7 @@ TEST_CASE(Profiler_IntrinsicAllocation) {
|
||||
StackZone zone(thread);
|
||||
HANDLESCOPE(thread);
|
||||
Profile profile(isolate);
|
||||
AllocationFilter filter(isolate, double_class.id());
|
||||
AllocationFilter filter(isolate->main_port(), double_class.id());
|
||||
profile.Build(thread, &filter, Profile::kNoTags);
|
||||
// We should have no allocation samples.
|
||||
EXPECT_EQ(0, profile.sample_count());
|
||||
@@ -691,7 +692,7 @@ TEST_CASE(Profiler_IntrinsicAllocation) {
|
||||
StackZone zone(thread);
|
||||
HANDLESCOPE(thread);
|
||||
Profile profile(isolate);
|
||||
AllocationFilter filter(isolate, double_class.id());
|
||||
AllocationFilter filter(isolate->main_port(), double_class.id());
|
||||
profile.Build(thread, &filter, Profile::kNoTags);
|
||||
// We should have one allocation sample.
|
||||
EXPECT_EQ(1, profile.sample_count());
|
||||
@@ -717,7 +718,7 @@ TEST_CASE(Profiler_IntrinsicAllocation) {
|
||||
StackZone zone(thread);
|
||||
HANDLESCOPE(thread);
|
||||
Profile profile(isolate);
|
||||
AllocationFilter filter(isolate, double_class.id());
|
||||
AllocationFilter filter(isolate->main_port(), double_class.id());
|
||||
profile.Build(thread, &filter, Profile::kNoTags);
|
||||
// We should still only have one allocation sample.
|
||||
EXPECT_EQ(1, profile.sample_count());
|
||||
@@ -747,7 +748,7 @@ TEST_CASE(Profiler_ArrayAllocation) {
|
||||
StackZone zone(thread);
|
||||
HANDLESCOPE(thread);
|
||||
Profile profile(isolate);
|
||||
AllocationFilter filter(isolate, array_class.id());
|
||||
AllocationFilter filter(isolate->main_port(), array_class.id());
|
||||
profile.Build(thread, &filter, Profile::kNoTags);
|
||||
// We should have no allocation samples.
|
||||
EXPECT_EQ(0, profile.sample_count());
|
||||
@@ -761,7 +762,7 @@ TEST_CASE(Profiler_ArrayAllocation) {
|
||||
StackZone zone(thread);
|
||||
HANDLESCOPE(thread);
|
||||
Profile profile(isolate);
|
||||
AllocationFilter filter(isolate, array_class.id());
|
||||
AllocationFilter filter(isolate->main_port(), array_class.id());
|
||||
profile.Build(thread, &filter, Profile::kNoTags);
|
||||
// We should have one allocation sample.
|
||||
EXPECT_EQ(1, profile.sample_count());
|
||||
@@ -789,7 +790,7 @@ TEST_CASE(Profiler_ArrayAllocation) {
|
||||
StackZone zone(thread);
|
||||
HANDLESCOPE(thread);
|
||||
Profile profile(isolate);
|
||||
AllocationFilter filter(isolate, array_class.id());
|
||||
AllocationFilter filter(isolate->main_port(), array_class.id());
|
||||
profile.Build(thread, &filter, Profile::kNoTags);
|
||||
// We should still only have one allocation sample.
|
||||
EXPECT_EQ(1, profile.sample_count());
|
||||
@@ -813,7 +814,7 @@ TEST_CASE(Profiler_ArrayAllocation) {
|
||||
StackZone zone(thread);
|
||||
HANDLESCOPE(thread);
|
||||
Profile profile(isolate);
|
||||
AllocationFilter filter(isolate, array_class.id());
|
||||
AllocationFilter filter(isolate->main_port(), array_class.id());
|
||||
profile.Build(thread, &filter, Profile::kNoTags);
|
||||
// We should still only have one allocation sample.
|
||||
EXPECT_EQ(1, profile.sample_count());
|
||||
@@ -861,7 +862,7 @@ TEST_CASE(Profiler_ContextAllocation) {
|
||||
StackZone zone(thread);
|
||||
HANDLESCOPE(thread);
|
||||
Profile profile(isolate);
|
||||
AllocationFilter filter(isolate, context_class.id());
|
||||
AllocationFilter filter(isolate->main_port(), context_class.id());
|
||||
profile.Build(thread, &filter, Profile::kNoTags);
|
||||
// We should have no allocation samples.
|
||||
EXPECT_EQ(0, profile.sample_count());
|
||||
@@ -875,7 +876,7 @@ TEST_CASE(Profiler_ContextAllocation) {
|
||||
StackZone zone(thread);
|
||||
HANDLESCOPE(thread);
|
||||
Profile profile(isolate);
|
||||
AllocationFilter filter(isolate, context_class.id());
|
||||
AllocationFilter filter(isolate->main_port(), context_class.id());
|
||||
profile.Build(thread, &filter, Profile::kNoTags);
|
||||
// We should have one allocation sample.
|
||||
EXPECT_EQ(1, profile.sample_count());
|
||||
@@ -899,7 +900,7 @@ TEST_CASE(Profiler_ContextAllocation) {
|
||||
StackZone zone(thread);
|
||||
HANDLESCOPE(thread);
|
||||
Profile profile(isolate);
|
||||
AllocationFilter filter(isolate, context_class.id());
|
||||
AllocationFilter filter(isolate->main_port(), context_class.id());
|
||||
profile.Build(thread, &filter, Profile::kNoTags);
|
||||
// We should still only have one allocation sample.
|
||||
EXPECT_EQ(1, profile.sample_count());
|
||||
@@ -942,7 +943,7 @@ TEST_CASE(Profiler_ClosureAllocation) {
|
||||
StackZone zone(thread);
|
||||
HANDLESCOPE(thread);
|
||||
Profile profile(isolate);
|
||||
AllocationFilter filter(isolate, closure_class.id());
|
||||
AllocationFilter filter(isolate->main_port(), closure_class.id());
|
||||
filter.set_enable_vm_ticks(true);
|
||||
profile.Build(thread, &filter, Profile::kNoTags);
|
||||
// We should have one allocation sample.
|
||||
@@ -970,7 +971,7 @@ TEST_CASE(Profiler_ClosureAllocation) {
|
||||
StackZone zone(thread);
|
||||
HANDLESCOPE(thread);
|
||||
Profile profile(isolate);
|
||||
AllocationFilter filter(isolate, closure_class.id());
|
||||
AllocationFilter filter(isolate->main_port(), closure_class.id());
|
||||
filter.set_enable_vm_ticks(true);
|
||||
profile.Build(thread, &filter, Profile::kNoTags);
|
||||
// We should still only have one allocation sample.
|
||||
@@ -1004,7 +1005,7 @@ TEST_CASE(Profiler_TypedArrayAllocation) {
|
||||
StackZone zone(thread);
|
||||
HANDLESCOPE(thread);
|
||||
Profile profile(isolate);
|
||||
AllocationFilter filter(isolate, float32_list_class.id());
|
||||
AllocationFilter filter(isolate->main_port(), float32_list_class.id());
|
||||
profile.Build(thread, &filter, Profile::kNoTags);
|
||||
// We should have no allocation samples.
|
||||
EXPECT_EQ(0, profile.sample_count());
|
||||
@@ -1018,7 +1019,7 @@ TEST_CASE(Profiler_TypedArrayAllocation) {
|
||||
StackZone zone(thread);
|
||||
HANDLESCOPE(thread);
|
||||
Profile profile(isolate);
|
||||
AllocationFilter filter(isolate, float32_list_class.id());
|
||||
AllocationFilter filter(isolate->main_port(), float32_list_class.id());
|
||||
profile.Build(thread, &filter, Profile::kNoTags);
|
||||
// We should have one allocation sample.
|
||||
EXPECT_EQ(1, profile.sample_count());
|
||||
@@ -1042,7 +1043,7 @@ TEST_CASE(Profiler_TypedArrayAllocation) {
|
||||
StackZone zone(thread);
|
||||
HANDLESCOPE(thread);
|
||||
Profile profile(isolate);
|
||||
AllocationFilter filter(isolate, float32_list_class.id());
|
||||
AllocationFilter filter(isolate->main_port(), float32_list_class.id());
|
||||
profile.Build(thread, &filter, Profile::kNoTags);
|
||||
// We should still only have one allocation sample.
|
||||
EXPECT_EQ(1, profile.sample_count());
|
||||
@@ -1056,7 +1057,7 @@ TEST_CASE(Profiler_TypedArrayAllocation) {
|
||||
StackZone zone(thread);
|
||||
HANDLESCOPE(thread);
|
||||
Profile profile(isolate);
|
||||
AllocationFilter filter(isolate, float32_list_class.id());
|
||||
AllocationFilter filter(isolate->main_port(), float32_list_class.id());
|
||||
profile.Build(thread, &filter, Profile::kNoTags);
|
||||
// We should now have two allocation samples.
|
||||
EXPECT_EQ(2, profile.sample_count());
|
||||
@@ -1088,7 +1089,7 @@ TEST_CASE(Profiler_StringAllocation) {
|
||||
StackZone zone(thread);
|
||||
HANDLESCOPE(thread);
|
||||
Profile profile(isolate);
|
||||
AllocationFilter filter(isolate, one_byte_string_class.id());
|
||||
AllocationFilter filter(isolate->main_port(), one_byte_string_class.id());
|
||||
profile.Build(thread, &filter, Profile::kNoTags);
|
||||
// We should have no allocation samples.
|
||||
EXPECT_EQ(0, profile.sample_count());
|
||||
@@ -1102,7 +1103,7 @@ TEST_CASE(Profiler_StringAllocation) {
|
||||
StackZone zone(thread);
|
||||
HANDLESCOPE(thread);
|
||||
Profile profile(isolate);
|
||||
AllocationFilter filter(isolate, one_byte_string_class.id());
|
||||
AllocationFilter filter(isolate->main_port(), one_byte_string_class.id());
|
||||
profile.Build(thread, &filter, Profile::kNoTags);
|
||||
// We should still only have one allocation sample.
|
||||
EXPECT_EQ(1, profile.sample_count());
|
||||
@@ -1128,7 +1129,7 @@ TEST_CASE(Profiler_StringAllocation) {
|
||||
StackZone zone(thread);
|
||||
HANDLESCOPE(thread);
|
||||
Profile profile(isolate);
|
||||
AllocationFilter filter(isolate, one_byte_string_class.id());
|
||||
AllocationFilter filter(isolate->main_port(), one_byte_string_class.id());
|
||||
profile.Build(thread, &filter, Profile::kNoTags);
|
||||
// We should still only have one allocation sample.
|
||||
EXPECT_EQ(1, profile.sample_count());
|
||||
@@ -1142,7 +1143,7 @@ TEST_CASE(Profiler_StringAllocation) {
|
||||
StackZone zone(thread);
|
||||
HANDLESCOPE(thread);
|
||||
Profile profile(isolate);
|
||||
AllocationFilter filter(isolate, one_byte_string_class.id());
|
||||
AllocationFilter filter(isolate->main_port(), one_byte_string_class.id());
|
||||
profile.Build(thread, &filter, Profile::kNoTags);
|
||||
// We should now have two allocation samples.
|
||||
EXPECT_EQ(2, profile.sample_count());
|
||||
@@ -1175,7 +1176,7 @@ TEST_CASE(Profiler_StringInterpolation) {
|
||||
StackZone zone(thread);
|
||||
HANDLESCOPE(thread);
|
||||
Profile profile(isolate);
|
||||
AllocationFilter filter(isolate, one_byte_string_class.id());
|
||||
AllocationFilter filter(isolate->main_port(), one_byte_string_class.id());
|
||||
profile.Build(thread, &filter, Profile::kNoTags);
|
||||
// We should have no allocation samples.
|
||||
EXPECT_EQ(0, profile.sample_count());
|
||||
@@ -1189,7 +1190,7 @@ TEST_CASE(Profiler_StringInterpolation) {
|
||||
StackZone zone(thread);
|
||||
HANDLESCOPE(thread);
|
||||
Profile profile(isolate);
|
||||
AllocationFilter filter(isolate, one_byte_string_class.id());
|
||||
AllocationFilter filter(isolate->main_port(), one_byte_string_class.id());
|
||||
profile.Build(thread, &filter, Profile::kNoTags);
|
||||
// We should still only have one allocation sample.
|
||||
EXPECT_EQ(1, profile.sample_count());
|
||||
@@ -1217,7 +1218,7 @@ TEST_CASE(Profiler_StringInterpolation) {
|
||||
StackZone zone(thread);
|
||||
HANDLESCOPE(thread);
|
||||
Profile profile(isolate);
|
||||
AllocationFilter filter(isolate, one_byte_string_class.id());
|
||||
AllocationFilter filter(isolate->main_port(), one_byte_string_class.id());
|
||||
profile.Build(thread, &filter, Profile::kNoTags);
|
||||
// We should still only have one allocation sample.
|
||||
EXPECT_EQ(1, profile.sample_count());
|
||||
@@ -1231,7 +1232,7 @@ TEST_CASE(Profiler_StringInterpolation) {
|
||||
StackZone zone(thread);
|
||||
HANDLESCOPE(thread);
|
||||
Profile profile(isolate);
|
||||
AllocationFilter filter(isolate, one_byte_string_class.id());
|
||||
AllocationFilter filter(isolate->main_port(), one_byte_string_class.id());
|
||||
profile.Build(thread, &filter, Profile::kNoTags);
|
||||
// We should now have two allocation samples.
|
||||
EXPECT_EQ(2, profile.sample_count());
|
||||
@@ -1291,7 +1292,7 @@ TEST_CASE(Profiler_FunctionInline) {
|
||||
StackZone zone(thread);
|
||||
HANDLESCOPE(thread);
|
||||
Profile profile(isolate);
|
||||
AllocationFilter filter(isolate, class_a.id());
|
||||
AllocationFilter filter(isolate->main_port(), class_a.id());
|
||||
profile.Build(thread, &filter, Profile::kNoTags);
|
||||
// We should have no allocation samples.
|
||||
EXPECT_EQ(0, profile.sample_count());
|
||||
@@ -1310,7 +1311,7 @@ TEST_CASE(Profiler_FunctionInline) {
|
||||
StackZone zone(thread);
|
||||
HANDLESCOPE(thread);
|
||||
Profile profile(isolate);
|
||||
AllocationFilter filter(isolate, class_a.id());
|
||||
AllocationFilter filter(isolate->main_port(), class_a.id());
|
||||
profile.Build(thread, &filter, Profile::kNoTags);
|
||||
// We should have 50,000 allocation samples.
|
||||
EXPECT_EQ(50000, profile.sample_count());
|
||||
@@ -1428,7 +1429,7 @@ TEST_CASE(Profiler_FunctionInline) {
|
||||
StackZone zone(thread);
|
||||
HANDLESCOPE(thread);
|
||||
Profile profile(isolate);
|
||||
AllocationFilter filter(isolate, class_a.id());
|
||||
AllocationFilter filter(isolate->main_port(), class_a.id());
|
||||
profile.Build(thread, &filter, Profile::kNoTags,
|
||||
ProfilerService::kCodeTransitionTagsBit);
|
||||
// We should have 50,000 allocation samples.
|
||||
@@ -1601,7 +1602,7 @@ TEST_CASE(Profiler_InliningIntervalBoundry) {
|
||||
StackZone zone(thread);
|
||||
HANDLESCOPE(thread);
|
||||
Profile profile(isolate);
|
||||
AllocationFilter filter(isolate, class_a.id());
|
||||
AllocationFilter filter(isolate->main_port(), class_a.id());
|
||||
profile.Build(thread, &filter, Profile::kNoTags);
|
||||
// We should have no allocation samples.
|
||||
EXPECT_EQ(0, profile.sample_count());
|
||||
@@ -1619,7 +1620,7 @@ TEST_CASE(Profiler_InliningIntervalBoundry) {
|
||||
StackZone zone(thread);
|
||||
HANDLESCOPE(thread);
|
||||
Profile profile(isolate);
|
||||
AllocationFilter filter(isolate, class_a.id());
|
||||
AllocationFilter filter(isolate->main_port(), class_a.id());
|
||||
profile.Build(thread, &filter, Profile::kNoTags);
|
||||
EXPECT_EQ(1, profile.sample_count());
|
||||
ProfileTrieWalker walker(&profile);
|
||||
@@ -1718,7 +1719,7 @@ TEST_CASE(Profiler_ChainedSamples) {
|
||||
StackZone zone(thread);
|
||||
HANDLESCOPE(thread);
|
||||
Profile profile(isolate);
|
||||
AllocationFilter filter(isolate, class_a.id());
|
||||
AllocationFilter filter(isolate->main_port(), class_a.id());
|
||||
profile.Build(thread, &filter, Profile::kNoTags);
|
||||
// We should have 1 allocation sample.
|
||||
EXPECT_EQ(1, profile.sample_count());
|
||||
@@ -1820,7 +1821,7 @@ TEST_CASE(Profiler_BasicSourcePosition) {
|
||||
StackZone zone(thread);
|
||||
HANDLESCOPE(thread);
|
||||
Profile profile(isolate);
|
||||
AllocationFilter filter(isolate, class_a.id());
|
||||
AllocationFilter filter(isolate->main_port(), class_a.id());
|
||||
profile.Build(thread, &filter, Profile::kNoTags);
|
||||
// We should have one allocation samples.
|
||||
EXPECT_EQ(1, profile.sample_count());
|
||||
@@ -1914,7 +1915,7 @@ TEST_CASE(Profiler_BasicSourcePositionOptimized) {
|
||||
StackZone zone(thread);
|
||||
HANDLESCOPE(thread);
|
||||
Profile profile(isolate);
|
||||
AllocationFilter filter(isolate, class_a.id());
|
||||
AllocationFilter filter(isolate->main_port(), class_a.id());
|
||||
profile.Build(thread, &filter, Profile::kNoTags);
|
||||
// We should have one allocation samples.
|
||||
EXPECT_EQ(1, profile.sample_count());
|
||||
@@ -2001,7 +2002,7 @@ TEST_CASE(Profiler_SourcePosition) {
|
||||
StackZone zone(thread);
|
||||
HANDLESCOPE(thread);
|
||||
Profile profile(isolate);
|
||||
AllocationFilter filter(isolate, class_a.id());
|
||||
AllocationFilter filter(isolate->main_port(), class_a.id());
|
||||
profile.Build(thread, &filter, Profile::kNoTags);
|
||||
// We should have one allocation samples.
|
||||
EXPECT_EQ(1, profile.sample_count());
|
||||
@@ -2126,7 +2127,7 @@ TEST_CASE(Profiler_SourcePositionOptimized) {
|
||||
StackZone zone(thread);
|
||||
HANDLESCOPE(thread);
|
||||
Profile profile(isolate);
|
||||
AllocationFilter filter(isolate, class_a.id());
|
||||
AllocationFilter filter(isolate->main_port(), class_a.id());
|
||||
profile.Build(thread, &filter, Profile::kNoTags);
|
||||
// We should have one allocation samples.
|
||||
EXPECT_EQ(1, profile.sample_count());
|
||||
@@ -2234,7 +2235,7 @@ TEST_CASE(Profiler_BinaryOperatorSourcePosition) {
|
||||
StackZone zone(thread);
|
||||
HANDLESCOPE(thread);
|
||||
Profile profile(isolate);
|
||||
AllocationFilter filter(isolate, class_a.id());
|
||||
AllocationFilter filter(isolate->main_port(), class_a.id());
|
||||
profile.Build(thread, &filter, Profile::kNoTags);
|
||||
// We should have one allocation samples.
|
||||
EXPECT_EQ(1, profile.sample_count());
|
||||
@@ -2368,7 +2369,7 @@ TEST_CASE(Profiler_BinaryOperatorSourcePositionOptimized) {
|
||||
StackZone zone(thread);
|
||||
HANDLESCOPE(thread);
|
||||
Profile profile(isolate);
|
||||
AllocationFilter filter(isolate, class_a.id());
|
||||
AllocationFilter filter(isolate->main_port(), class_a.id());
|
||||
profile.Build(thread, &filter, Profile::kNoTags);
|
||||
// We should have one allocation samples.
|
||||
EXPECT_EQ(1, profile.sample_count());
|
||||
@@ -2427,7 +2428,7 @@ static void InsertFakeSample(SampleBuffer* sample_buffer, uword* pc_offsets) {
|
||||
Isolate* isolate = Isolate::Current();
|
||||
Sample* sample = sample_buffer->ReserveSample();
|
||||
ASSERT(sample != NULL);
|
||||
sample->Init(isolate, OS::GetCurrentMonotonicMicros(),
|
||||
sample->Init(isolate->main_port(), OS::GetCurrentMonotonicMicros(),
|
||||
OSThread::Current()->trace_id());
|
||||
sample->set_thread_task(Thread::kMutatorTask);
|
||||
|
||||
|
||||
@@ -3235,6 +3235,28 @@ static bool GetAllocationSamples(Thread* thread, JSONStream* js) {
|
||||
}
|
||||
|
||||
|
||||
static const MethodParameter* get_native_allocation_samples_params[] = {
|
||||
NO_ISOLATE_PARAMETER,
|
||||
new EnumParameter("tags", true, tags_enum_names),
|
||||
new Int64Parameter("timeOriginMicros", false),
|
||||
new Int64Parameter("timeExtentMicros", false),
|
||||
NULL,
|
||||
};
|
||||
|
||||
|
||||
static bool GetNativeAllocationSamples(Thread* thread, JSONStream* js) {
|
||||
Profile::TagOrder tag_order =
|
||||
EnumMapper(js->LookupParam("tags"), tags_enum_names, tags_enum_values);
|
||||
int64_t time_origin_micros =
|
||||
Int64Parameter::Parse(js->LookupParam("timeOriginMicros"));
|
||||
int64_t time_extent_micros =
|
||||
Int64Parameter::Parse(js->LookupParam("timeExtentMicros"));
|
||||
ProfilerService::PrintNativeAllocationJSON(js, tag_order, time_origin_micros,
|
||||
time_extent_micros);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static const MethodParameter* clear_cpu_profile_params[] = {
|
||||
RUNNABLE_ISOLATE_PARAMETER, NULL,
|
||||
};
|
||||
@@ -4057,6 +4079,8 @@ static const ServiceMethodDescriptor service_methods_[] = {
|
||||
get_allocation_profile_params },
|
||||
{ "_getAllocationSamples", GetAllocationSamples,
|
||||
get_allocation_samples_params },
|
||||
{ "_getNativeAllocationSamples", GetNativeAllocationSamples,
|
||||
get_native_allocation_samples_params },
|
||||
{ "getClassList", GetClassList,
|
||||
get_class_list_params },
|
||||
{ "_getCpuProfile", GetCpuProfile,
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "vm/dart_api_message.h"
|
||||
#include "vm/dart_api_state.h"
|
||||
#include "vm/flags.h"
|
||||
#include "vm/malloc_hooks.h"
|
||||
#include "vm/snapshot.h"
|
||||
#include "vm/symbols.h"
|
||||
#include "vm/unicode.h"
|
||||
@@ -1122,6 +1123,11 @@ static void IterateScripts(const Library& lib) {
|
||||
}
|
||||
|
||||
ISOLATE_UNIT_TEST_CASE(GenerateSource) {
|
||||
// Disable stack trace collection for this test as it results in a timeout.
|
||||
bool stack_trace_collection_enabled =
|
||||
MallocHooks::stack_trace_collection_enabled();
|
||||
MallocHooks::set_stack_trace_collection_enabled(false);
|
||||
|
||||
Zone* zone = thread->zone();
|
||||
Isolate* isolate = thread->isolate();
|
||||
const GrowableObjectArray& libs =
|
||||
@@ -1135,6 +1141,9 @@ ISOLATE_UNIT_TEST_CASE(GenerateSource) {
|
||||
OS::Print("Generating source for library: %s\n", uri.ToCString());
|
||||
IterateScripts(lib);
|
||||
}
|
||||
|
||||
MallocHooks::set_stack_trace_collection_enabled(
|
||||
stack_trace_collection_enabled);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -56,8 +56,8 @@ void SourceReport::Init(Thread* thread,
|
||||
ClearScriptTable();
|
||||
if (IsReportRequested(kProfile)) {
|
||||
// Build the profile.
|
||||
SampleFilter samplesForIsolate(thread_->isolate(), Thread::kMutatorTask, -1,
|
||||
-1);
|
||||
SampleFilter samplesForIsolate(thread_->isolate()->main_port(),
|
||||
Thread::kMutatorTask, -1, -1);
|
||||
profile_.Build(thread, &samplesForIsolate, Profile::kNoTags);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
// Dart test program for testing isolate communication with
|
||||
// typed objects.
|
||||
// VMOptions=--disassemble --no-background-compilation
|
||||
// VMOptions=--disassemble --print-variable-descriptors --no-background-compilation
|
||||
// VMOptions=--disassemble --no-background-compilation --enable-malloc-hooks=false
|
||||
// VMOptions=--disassemble --print-variable-descriptors --no-background-compilation --enable-malloc-hooks=false
|
||||
|
||||
// Tests proper object recognition in disassembler.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user