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

Unified Diff: runtime/vm/code_statistics.cc

Issue 2584613002: PATCH (not to be comitted): Support for printing instruction statistics
Patch Set: Fixed polymorphic call inside try, added more tags for remaining unknown code Created 4 years 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 | « runtime/vm/code_statistics.h ('k') | runtime/vm/flow_graph_compiler.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: runtime/vm/code_statistics.cc
diff --git a/runtime/vm/code_statistics.cc b/runtime/vm/code_statistics.cc
new file mode 100644
index 0000000000000000000000000000000000000000..906a4d049c11cf00055af9600dc360deb2af9da1
--- /dev/null
+++ b/runtime/vm/code_statistics.cc
@@ -0,0 +1,258 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#include "vm/code_statistics.h"
+
+namespace dart {
+
+CombinedCodeStatistics::CombinedCodeStatistics() {
+ unaccounted_bytes_ = 0;
+ alignment_bytes_ = 0;
+ object_header_bytes_ = 0;
+ wasteful_function_count_ = 0;
+ return_const_count_ = 0;
+ return_const_with_load_field_count_ = 0;
+ intptr_t i = 0;
+
+#define DO(type) \
+ entries_[i].name = #type; \
+ entries_[i].bytes = 0; \
+ entries_[i++].count = 0;
+
+ FOR_EACH_INSTRUCTION(DO)
+
+#undef DO
+
+#define INIT_SPECIAL_ENTRY(tag, str) \
+ entries_[tag].name = str; \
+ entries_[tag].bytes = 0; \
+ entries_[tag].count = 0;
+
+ INIT_SPECIAL_ENTRY(kPolymorphicInstanceCallAsStaticCall,
+ "PolymorphicInstanceCall -> StaticCall")
+
+ INIT_SPECIAL_ENTRY(kTagCheckedSmiSlowPath, "<slow-path:checked-smi>")
+ INIT_SPECIAL_ENTRY(kTagCheckedSmiCmpSlowPath, "<slow-path:checked-smi-compare>")
+ INIT_SPECIAL_ENTRY(kTagBoxAllocationSlowPath, "<slow-path:box-allocation>")
+ INIT_SPECIAL_ENTRY(kTagAllocateContextSlowPath,
+ "<slow-path:allocate-context>")
+ INIT_SPECIAL_ENTRY(kTagCheckStackOverflowSlowPath,
+ "<slow-path:stack-overflow>")
+ INIT_SPECIAL_ENTRY(kTagMegamorphicSlowPath, "<slow-path:megamorphic>")
+
+ INIT_SPECIAL_ENTRY(kTagCheckArgumentCount, "<check argument count>");
+ INIT_SPECIAL_ENTRY(kTagCopyParameters, "<copy parameters>");
+ INIT_SPECIAL_ENTRY(kTagStubCode, "<stub-code>");
+ INIT_SPECIAL_ENTRY(kTagCheckedEntry, "<checked-entry-prologue>");
+ INIT_SPECIAL_ENTRY(kTagFrameEntry, "<frame-entry>");
+ INIT_SPECIAL_ENTRY(kTagLoadClosureContext, "<load-closure-context>");
+ INIT_SPECIAL_ENTRY(kTagIntrinsics, "<intrinsics>");
+ INIT_SPECIAL_ENTRY(kDebugAfterBody, "<debug-after-body>");
+
+ INIT_SPECIAL_ENTRY(kTagTrySyncSpilling, "<try-sync-spilling-code>");
+
+#undef INIT_SPECIAL_ENTRY
+}
+
+void CombinedCodeStatistics::DumpStatistics() {
+ ASSERT(unaccounted_bytes_ >= 0);
+
+ SlowSort();
+
+ intptr_t instruction_bytes = 0;
+ for (intptr_t i = 0; i < kNumEntries; i++) {
+ instruction_bytes += entries_[i].bytes;
+ }
+ intptr_t total = object_header_bytes_ +
+ instruction_bytes +
+ unaccounted_bytes_ +
+ alignment_bytes_;
+ float ftotal = static_cast<float>(total) / 100.0;
+
+ fprintf(stderr, "--------------------\n");
+
+ for (intptr_t i = 0; i < kNumEntries; i++) {
+ const char* name = entries_[i].name;
+ intptr_t bytes = entries_[i].bytes;
+ intptr_t count = entries_[i].count;
+ float percent = bytes / ftotal;
+ float avg = static_cast<float>(bytes) / count;
+ if (bytes > 0) {
+ fprintf(
+ stderr,
+ "%5.2f %% "
+ "% 8" Pd " bytes "
+ "% 8" Pd " count "
+ "%8.2f avg bytes/entry "
+ "- %s\n",
+ percent,
+ bytes,
+ count,
+ avg,
+ name);
+ }
+ }
+
+ fprintf(stderr, "--------------------\n");
+
+ fprintf(stderr, "%5.2f %% % 8" Pd " bytes unaccounted\n",
+ unaccounted_bytes_/ftotal, unaccounted_bytes_);
+ fprintf(stderr, "%5.2f %% % 8" Pd " bytes alignment\n",
+ alignment_bytes_ / ftotal, alignment_bytes_);
+ fprintf(stderr, "%5.2f %% % 8" Pd " bytes instruction object header\n",
+ object_header_bytes_ / ftotal, object_header_bytes_);
+ fprintf(stderr, "%5.2f %% % 8" Pd " bytes instructions\n",
+ instruction_bytes / ftotal, instruction_bytes);
+ fprintf(stderr, "--------------------\n");
+ fprintf(stderr, "%5.2f %% % 8" Pd " bytes in total\n",
+ total/ftotal, total);
+ fprintf(stderr, "--------------------\n");
+ fprintf(stderr, "% 8" Pd " return-constant functions\n", return_const_count_);
+ fprintf(stderr, "% 8" Pd " return-constant-with-load-field functions\n",
+ return_const_with_load_field_count_);
+ fprintf(stderr, "% 8" Pd " wasteful functions (body < 2 * frame overhead)\n",
+ wasteful_function_count_);
+ fprintf(stderr, "--------------------\n");
+}
+
+
+void CombinedCodeStatistics::SlowSort() {
+ for (intptr_t upper = kNumEntries - 1; upper >= 0; upper--) {
+ intptr_t largest_index = 0;
+ intptr_t largest_value = entries_[largest_index].bytes;
+ for (intptr_t i = 1; i <= upper; i++) {
+ intptr_t bytes = entries_[i].bytes;
+ if (largest_value < bytes) {
+ largest_index = i;
+ largest_value = bytes;
+ }
+ }
+ if (largest_index != upper) Swap(largest_index, upper);
+ }
+}
+
+void CombinedCodeStatistics::Swap(intptr_t a, intptr_t b) {
+ const char* a_name = entries_[a].name;
+ intptr_t a_bytes = entries_[a].bytes;
+ intptr_t a_count = entries_[a].count;
+
+ entries_[a].name = entries_[b].name;
+ entries_[a].bytes = entries_[b].bytes;
+ entries_[a].count = entries_[b].count;
+
+ entries_[b].name = a_name;
+ entries_[b].bytes = a_bytes;
+ entries_[b].count = a_count;
+}
+
+CodeStatistics::CodeStatistics(Assembler* assembler)
+ : assembler_(assembler) {
+ memset(entries_, 0, CombinedCodeStatistics::kNumEntries * sizeof(Entry));
+ instruction_bytes_ = 0;
+ unaccounted_bytes_ = 0;
+ alignment_bytes_ = 0;
+
+ stack_index_ = -1;
+ for (intptr_t i = 0; i < kStackSize; i++) stack_[i] = -1;
+}
+
+void CodeStatistics::Begin(Instruction* instruction) {
+ SpecialBegin(static_cast<intptr_t>(instruction->tag()));
+}
+
+void CodeStatistics::End(Instruction* instruction) {
+ SpecialEnd(static_cast<intptr_t>(instruction->tag()));
+}
+
+void CodeStatistics::SpecialBegin(intptr_t tag) {
+ stack_index_++;
+ ASSERT(stack_index_ < kStackSize);
+ ASSERT(stack_[stack_index_] == -1);
+ ASSERT(tag < CombinedCodeStatistics::kNumEntries);
+ stack_[stack_index_] = assembler_->CodeSize();
+ ASSERT(stack_[stack_index_] >= 0);
+}
+
+void CodeStatistics::SpecialEnd(intptr_t tag) {
+ ASSERT(stack_index_ > 0 || stack_[stack_index_] >= 0);
+ ASSERT(tag < CombinedCodeStatistics::kNumEntries);
+
+ intptr_t diff = assembler_->CodeSize() - stack_[stack_index_];
+ ASSERT(diff >= 0);
+ ASSERT(entries_[tag].bytes >= 0);
+ ASSERT(entries_[tag].count >= 0);
+ entries_[tag].bytes += diff;
+ entries_[tag].count++;
+ instruction_bytes_ += diff;
+ stack_[stack_index_] = -1;
+ stack_index_--;
+
+ // By adding to the current stack index we will increase the 'assembler_->CodeSize()' offset
+ // when the parent instruction started, thereby reducing it's accounted size
+ // by `diff`.
+ if (tag == CombinedCodeStatistics::kTagTrySyncSpilling) {
+ // We make try-sync-spilling code be subtracted from the calls.
+ ASSERT(stack_index_ >= 0);
+ stack_[stack_index_] += diff;
+ } else if (tag == CombinedCodeStatistics::kPolymorphicInstanceCallAsStaticCall) {
+ // We make polymorphic-as-static-calls be subtraced from the polymorphic
+ // calls.
+ ASSERT(stack_index_ >= 0);
+ stack_[stack_index_] += diff;
+ }
+}
+
+void CodeStatistics::Finalize() {
+ intptr_t function_size = assembler_->CodeSize();
+ unaccounted_bytes_ = function_size - instruction_bytes_;
+ ASSERT(unaccounted_bytes_ >= 0);
+ alignment_bytes_ =
+ Utils::RoundUp(function_size, OS::PreferredCodeAlignment()) -
+ function_size;
+ assembler_ = NULL;
+}
+
+void CodeStatistics::AppendTo(CombinedCodeStatistics* stat) {
+ intptr_t sum = 0;
+ bool returns_constant = true;
+ bool returns_const_with_load_field_ = true;
+
+ for (intptr_t i = 0; i < CombinedCodeStatistics::kNumEntries; i++) {
+ intptr_t bytes = entries_[i].bytes;
+ stat->entries_[i].count += entries_[i].count;
+ if (bytes > 0) {
+ sum += bytes;
+ stat->entries_[i].bytes += bytes;
+ if (i != CombinedCodeStatistics::kTagFrameEntry &&
+ i != CombinedCodeStatistics::kTagParallelMove &&
+ i != CombinedCodeStatistics::kTagReturn &&
+ i != CombinedCodeStatistics::kTagCheckStackOverflow &&
+ i != CombinedCodeStatistics::kTagCheckStackOverflowSlowPath) {
+ returns_constant = false;
+ if (i != CombinedCodeStatistics::kTagLoadField &&
+ i != CombinedCodeStatistics::kTagTargetEntry &&
+ i != CombinedCodeStatistics::kTagJoinEntry) {
+ returns_const_with_load_field_ = false;
+ }
+ }
+ }
+ }
+ stat->unaccounted_bytes_ += unaccounted_bytes_;
+ ASSERT(stat->unaccounted_bytes_ >= 0);
+ stat->alignment_bytes_ += alignment_bytes_;
+ stat->object_header_bytes_ += Instructions::HeaderSize();
+
+ intptr_t frame_overhead =
+ entries_[CombinedCodeStatistics::kTagFrameEntry].bytes +
+ entries_[CombinedCodeStatistics::kTagReturn].bytes;
+
+ bool is_wasteful = sum < (2 * frame_overhead);
+ if (is_wasteful) stat->wasteful_function_count_++;
+ if (returns_constant) stat->return_const_count_++;
+ if (returns_const_with_load_field_) {
+ stat->return_const_with_load_field_count_++;
+ }
+}
+
+} // namespace dart
« no previous file with comments | « runtime/vm/code_statistics.h ('k') | runtime/vm/flow_graph_compiler.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698