Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(459)

Unified Diff: runtime/vm/profiler_service.cc

Issue 1826753003: Use a cache for inlining information (functions + token positions) to speed up function profile (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: runtime/vm/profiler_service.cc
diff --git a/runtime/vm/profiler_service.cc b/runtime/vm/profiler_service.cc
index 1cb56ce0ae44541ea9a596aa408890165c6377d5..5c3efa6790a01c34b13df37fd3b6550c9df130ce 100644
--- a/runtime/vm/profiler_service.cc
+++ b/runtime/vm/profiler_service.cc
@@ -1065,6 +1065,160 @@ class ProfileFunctionTrieNode : public ProfileTrieNode {
};
+class ProfileCodeInlinedFunctionsCache : public ValueObject {
+ public:
+ ProfileCodeInlinedFunctionsCache()
+ : cache_cursor_(0),
+ last_hit_(0) {
+ for (intptr_t i = 0; i < kCacheSize; i++) {
+ cache_[i].Reset();
+ }
+ cache_hit_ = 0;
+ cache_miss_ = 0;
+ }
+
+ ~ProfileCodeInlinedFunctionsCache() {
+ if (FLAG_trace_profiler) {
+ intptr_t total = cache_hit_ + cache_miss_;
+ OS::Print("LOOKUPS: %" Pd " HITS: %" Pd " MISSES: %" Pd "\n",
+ total,
+ cache_hit_,
+ cache_miss_);
+ }
+ }
+
+ void Get(uword pc,
+ const Code& code,
+ ProcessedSample* sample,
+ intptr_t frame_index,
+ // Outputs:
+ GrowableArray<Function*>** inlined_functions,
+ GrowableArray<TokenPosition>** inlined_token_positions,
+ TokenPosition* token_position) {
+ const intptr_t offset = OffsetForPC(pc, code, sample, frame_index);
+ if (FindInCache(pc,
+ offset,
+ inlined_functions,
+ inlined_token_positions,
+ token_position)) {
+ // Found in cache.
+ return;
+ }
+ Add(pc, code, sample, frame_index,
+ inlined_functions, inlined_token_positions, token_position);
+ }
+
+ private:
+ bool FindInCache(uword pc,
+ intptr_t offset,
+ GrowableArray<Function*>** inlined_functions,
+ GrowableArray<TokenPosition>** inlined_token_positions,
+ TokenPosition* token_position) {
+ // Simple linear scan.
+ for (intptr_t i = 0; i < kCacheSize; i++) {
+ intptr_t index = (last_hit_ + i) % kCacheSize;
+ if ((cache_[index].pc == pc) && (cache_[index].offset == offset)) {
+ // Hit.
+ if (cache_[index].inlined_functions.length() == 0) {
+ *inlined_functions = NULL;
+ *inlined_token_positions = NULL;
+ } else {
+ *inlined_functions = &cache_[index].inlined_functions;
+ *inlined_token_positions = &cache_[index].inlined_token_positions;
+ }
+ *token_position = cache_[index].token_position;
+ cache_hit_++;
+ last_hit_ = index;
+ return true;
+ }
+ }
+ cache_miss_++;
+ return false;
+ }
+
+ // Add to cache and fill in outputs.
+ void Add(uword pc,
+ const Code& code,
+ ProcessedSample* sample,
+ intptr_t frame_index,
+ // Outputs:
+ GrowableArray<Function*>** inlined_functions,
+ GrowableArray<TokenPosition>** inlined_token_positions,
+ TokenPosition* token_position) {
+ const intptr_t offset = OffsetForPC(pc, code, sample, frame_index);
+ CacheEntry* cache_entry = &cache_[NextFreeIndex()];
+ cache_entry->pc = pc;
+ cache_entry->offset = offset;
+ code.GetInlinedFunctionsAt(offset,
+ &(cache_entry->inlined_functions),
+ &(cache_entry->inlined_token_positions));
+ cache_entry->token_position = code.GetTokenPositionAt(offset);
+ *token_position = (cache_entry->token_position);
+ if (cache_entry->inlined_functions.length() == 0) {
+ *inlined_functions = NULL;
+ *inlined_token_positions = NULL;
+ return;
+ }
+ // The inlined token position table does not include the token position
+ // of the final call. Insert it at the beginning because the table.
+ // is reversed.
+ cache_entry->inlined_token_positions.InsertAt(
+ 0,
+ cache_entry->token_position);
+
+ // Write outputs.
+ *inlined_functions = &(cache_entry->inlined_functions);
+ *inlined_token_positions = &(cache_entry->inlined_token_positions);
+ }
+
+ intptr_t NextFreeIndex() {
+ cache_cursor_ = (cache_cursor_ + 1) % kCacheSize;
+ return cache_cursor_;
+ }
+
+ intptr_t OffsetForPC(uword pc,
+ const Code& code,
+ ProcessedSample* sample,
+ intptr_t frame_index) {
+ intptr_t offset = pc - code.EntryPoint();
+ if (frame_index != 0) {
+ // The PC of frames below the top frame is a call's return address,
+ // which can belong to a different inlining interval than the call.
+ offset--;
+ } else if (sample->IsAllocationSample()) {
+ // Allocation samples skip the top frame, so the top frame's pc is
+ // also a call's return address.
+ offset--;
+ } else if (!sample->first_frame_executing()) {
+ // If the first frame wasn't executing code (i.e. we started to collect
+ // the stack trace at an exit frame), the top frame's pc is also a
+ // call's return address.
+ offset--;
+ }
+ return offset;
+ }
+
+ struct CacheEntry {
+ void Reset() {
+ pc = 0;
+ offset = 0;
+ }
+ uword pc;
+ intptr_t offset;
+ GrowableArray<Function*> inlined_functions;
+ GrowableArray<TokenPosition> inlined_token_positions;
+ TokenPosition token_position;
+ };
+
+ static const intptr_t kCacheSize = 128;
+ intptr_t cache_cursor_;
+ intptr_t last_hit_;
+ CacheEntry cache_[kCacheSize];
+ intptr_t cache_miss_;
+ intptr_t cache_hit_;
+};
+
+
class ProfileBuilder : public ValueObject {
public:
enum ProfileInfoKind {
@@ -1466,28 +1620,6 @@ class ProfileBuilder : public ValueObject {
}
}
- intptr_t OffsetForPC(uword pc,
- const Code& code,
- ProcessedSample* sample,
- intptr_t frame_index) {
- intptr_t offset = pc - code.EntryPoint();
- if (frame_index != 0) {
- // The PC of frames below the top frame is a call's return address,
- // which can belong to a different inlining interval than the call.
- offset--;
- } else if (sample->IsAllocationSample()) {
- // Allocation samples skip the top frame, so the top frame's pc is
- // also a call's return address.
- offset--;
- } else if (!sample->first_frame_executing()) {
- // If the first frame wasn't executing code (i.e. we started to collect
- // the stack trace at an exit frame), the top frame's pc is also a
- // call's return address.
- offset--;
- }
- return offset;
- }
-
ProfileFunctionTrieNode* ProcessFrame(
ProfileFunctionTrieNode* current,
intptr_t sample_index,
@@ -1501,34 +1633,28 @@ class ProfileBuilder : public ValueObject {
const intptr_t code_index = profile_code->code_table_index();
ASSERT(profile_code != NULL);
const Code& code = Code::ZoneHandle(profile_code->code());
- GrowableArray<Function*> inlined_functions;
- GrowableArray<TokenPosition> inlined_token_positions;
+ GrowableArray<Function*>* inlined_functions = NULL;
+ GrowableArray<TokenPosition>* inlined_token_positions = NULL;
TokenPosition token_position = TokenPosition::kNoSource;
if (!code.IsNull()) {
- const intptr_t offset = OffsetForPC(pc, code, sample, frame_index);
- code.GetInlinedFunctionsAt(offset,
- &inlined_functions,
- &inlined_token_positions);
- token_position = code.GetTokenPositionAt(offset);
- if (inlined_functions.length() > 0) {
- // The inlined token position table does not include the token position
- // of the final call. Insert it at the beginning because the table.
- // is reversed.
- inlined_token_positions.InsertAt(0, token_position);
- }
- ASSERT(inlined_functions.length() <= inlined_token_positions.length());
+ inlined_functions_cache_.Get(pc, code, sample, frame_index,
+ &inlined_functions,
+ &inlined_token_positions,
+ &token_position);
if (FLAG_trace_profiler_verbose) {
- for (intptr_t i = 0; i < inlined_functions.length(); i++) {
+ for (intptr_t i = 0; i < inlined_functions->length(); i++) {
const String& name =
- String::Handle(inlined_functions[i]->QualifiedScrubbedName());
+ String::Handle((*inlined_functions)[i]->QualifiedScrubbedName());
THR_Print("InlinedFunction[%" Pd "] = {%s, %s}\n",
i,
name.ToCString(),
- inlined_token_positions[i].ToCString());
+ (*inlined_token_positions)[i].ToCString());
}
}
}
- if (code.IsNull() || (inlined_functions.length() == 0)) {
+ if (code.IsNull() ||
+ (inlined_functions == NULL) ||
+ (inlined_functions->length() == 0)) {
// No inlined functions.
if (inclusive_tree_) {
current = AppendKind(code, current);
@@ -1549,12 +1675,12 @@ class ProfileBuilder : public ValueObject {
ASSERT(code.is_optimized());
if (inclusive_tree_) {
- for (intptr_t i = inlined_functions.length() - 1; i >= 0; i--) {
- Function* inlined_function = inlined_functions[i];
+ for (intptr_t i = inlined_functions->length() - 1; i >= 0; i--) {
+ Function* inlined_function = (*inlined_functions)[i];
ASSERT(inlined_function != NULL);
ASSERT(!inlined_function->IsNull());
- TokenPosition inlined_token_position = inlined_token_positions[i];
- const bool inliner = i == (inlined_functions.length() - 1);
+ TokenPosition inlined_token_position = (*inlined_token_positions)[i];
+ const bool inliner = i == (inlined_functions->length() - 1);
if (inliner) {
current = AppendKind(code, current);
}
@@ -1573,12 +1699,12 @@ class ProfileBuilder : public ValueObject {
} else {
// Append the inlined children.
current = AppendKind(kInlineFinish, current);
- for (intptr_t i = 0; i < inlined_functions.length(); i++) {
- Function* inlined_function = inlined_functions[i];
+ for (intptr_t i = 0; i < inlined_functions->length(); i++) {
+ Function* inlined_function = (*inlined_functions)[i];
ASSERT(inlined_function != NULL);
ASSERT(!inlined_function->IsNull());
- TokenPosition inlined_token_position = inlined_token_positions[i];
- const bool inliner = i == (inlined_functions.length() - 1);
+ TokenPosition inlined_token_position = (*inlined_token_positions)[i];
+ const bool inliner = i == (inlined_functions->length() - 1);
if (inliner) {
current = AppendKind(kInlineStart, current);
}
@@ -2126,7 +2252,7 @@ class ProfileBuilder : public ValueObject {
const Function& null_function_;
bool tick_functions_;
bool inclusive_tree_;
-
+ ProfileCodeInlinedFunctionsCache inlined_functions_cache_;
ProcessedSampleBuffer* samples_;
ProfileInfoKind info_kind_;
}; // ProfileBuilder.
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698