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:
Ben Konyi
2017-02-24 13:56:06 -08:00
parent 123c8a9668
commit 68a102cab2
24 changed files with 741 additions and 248 deletions
+6
View File
@@ -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
View File
@@ -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
}
+2 -2
View File
@@ -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
View File
@@ -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)
+5
View File
@@ -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();
+123 -4
View File
@@ -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)
+19 -2
View File
@@ -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)
+6
View File
@@ -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);
}
+3
View File
@@ -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);
+6
View File
@@ -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);
}
+6
View File
@@ -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);
}
+6
View File
@@ -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);
}
+6
View File
@@ -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
View File
@@ -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;
+5
View File
@@ -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
View File
@@ -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
View File
@@ -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;
}
+44 -10
View File
@@ -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);
}
+5
View File
@@ -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
View File
@@ -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);
+24
View File
@@ -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,
+9
View File
@@ -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);
}
+2 -2
View File
@@ -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);
}
}
+2 -2
View File
@@ -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.