mirror of
https://github.com/dart-lang/sdk
synced 2024-09-05 00:13:50 +00:00
[ Profiler ] Avoid building empty CPU profiles when sample streaming is enabled
Building an empty CPU profile is still costly as function tables are populated whether or not there's samples in the profile. This change checks to see if any sample in the list of SampleBlocks was collected under a UserTag with streaming enabled before building the profile. TEST=CQ, manual testing Change-Id: Ib526f9999a8b2bf48a7df1488c7dcf959031cf5b Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/238183 Reviewed-by: Ryan Macnak <rmacnak@google.com> Reviewed-by: Siva Annamalai <asiva@google.com> Commit-Queue: Ben Konyi <bkonyi@google.com>
This commit is contained in:
parent
17769033cf
commit
d7935c209d
|
@ -2422,15 +2422,15 @@ void Isolate::ProcessFreeSampleBlocks(Thread* thread) {
|
|||
head = next;
|
||||
} while (head != nullptr);
|
||||
head = reversed_head;
|
||||
|
||||
if (Service::profiler_stream.enabled() && !IsSystemIsolate(this)) {
|
||||
SampleBlockListProcessor buffer(head);
|
||||
StackZone zone(thread);
|
||||
HandleScope handle_scope(thread);
|
||||
StreamableSampleFilter filter(main_port());
|
||||
Profile profile;
|
||||
profile.Build(thread, &filter, &buffer);
|
||||
if (profile.sample_count() > 0) {
|
||||
SampleBlockListProcessor buffer(head);
|
||||
if (buffer.HasStreamableSamples(thread)) {
|
||||
HandleScope handle_scope(thread);
|
||||
StreamableSampleFilter filter(main_port());
|
||||
Profile profile;
|
||||
profile.Build(thread, &filter, &buffer);
|
||||
ASSERT(profile.sample_count() > 0);
|
||||
ServiceEvent event(this, ServiceEvent::kCpuSamples);
|
||||
event.set_cpu_profile(&profile);
|
||||
Service::HandleEvent(&event);
|
||||
|
|
|
@ -713,6 +713,38 @@ ProcessedSampleBuffer* SampleBlockListProcessor::BuildProcessedSampleBuffer(
|
|||
return buffer;
|
||||
}
|
||||
|
||||
bool SampleBlockListProcessor::HasStreamableSamples(Thread* thread) {
|
||||
ReusableGrowableObjectArrayHandleScope reusable_array_handle_scope(thread);
|
||||
Zone* zone = thread->zone();
|
||||
Isolate* isolate = thread->isolate();
|
||||
ASSERT(isolate->tag_table() != GrowableObjectArray::null());
|
||||
GrowableObjectArray& tag_table = reusable_array_handle_scope.Handle();
|
||||
tag_table ^= isolate->tag_table();
|
||||
UserTag& tag = UserTag::Handle(zone);
|
||||
while (head_ != nullptr) {
|
||||
if (head_->HasStreamableSamples(tag_table, &tag)) {
|
||||
return true;
|
||||
}
|
||||
head_ = head_->next_free_;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SampleBlock::HasStreamableSamples(const GrowableObjectArray& tag_table,
|
||||
UserTag* tag) {
|
||||
for (intptr_t i = 0; i < capacity_; ++i) {
|
||||
Sample* sample = At(i);
|
||||
uword sample_tag = sample->user_tag();
|
||||
for (intptr_t j = 0; j < tag_table.Length(); ++j) {
|
||||
*tag ^= tag_table.At(j);
|
||||
if (tag->tag() == sample_tag && tag->streamable()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
ProcessedSampleBuffer* SampleBlockBuffer::BuildProcessedSampleBuffer(
|
||||
SampleFilter* filter,
|
||||
ProcessedSampleBuffer* buffer) {
|
||||
|
|
|
@ -756,6 +756,8 @@ class SampleBlock : public SampleBuffer {
|
|||
virtual Sample* ReserveSampleAndLink(Sample* previous);
|
||||
|
||||
protected:
|
||||
bool HasStreamableSamples(const GrowableObjectArray& tag_table, UserTag* tag);
|
||||
|
||||
Isolate* owner_ = nullptr;
|
||||
bool allocation_block_ = false;
|
||||
|
||||
|
@ -882,6 +884,10 @@ class SampleBlockListProcessor : public ProcessedSampleBufferBuilder {
|
|||
SampleFilter* filter,
|
||||
ProcessedSampleBuffer* buffer = nullptr);
|
||||
|
||||
// Returns true when at least one sample in the sample block list has a user
|
||||
// tag with CPU sample streaming enabled.
|
||||
bool HasStreamableSamples(Thread* thread);
|
||||
|
||||
private:
|
||||
SampleBlock* head_;
|
||||
|
||||
|
|
Loading…
Reference in a new issue