1// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5#include "vm/compiler/backend/code_statistics.h"
6
7namespace dart {
8
9CombinedCodeStatistics::CombinedCodeStatistics() {
10 unaccounted_bytes_ = 0;
11 alignment_bytes_ = 0;
12 object_header_bytes_ = 0;
13 return_const_count_ = 0;
14 return_const_with_load_field_count_ = 0;
15 intptr_t i = 0;
16
17#define DO(type, attrs) \
18 entries_[i].name = #type; \
19 entries_[i].bytes = 0; \
20 entries_[i++].count = 0;
21
22 FOR_EACH_INSTRUCTION(DO)
23
24#undef DO
25
26#define DO(type, attrs) \
27 entries_[i].name = "SlowPath:" #type; \
28 entries_[i].bytes = 0; \
29 entries_[i++].count = 0;
30
31 FOR_EACH_INSTRUCTION(DO)
32
33#undef DO
34
35#define INIT_SPECIAL_ENTRY(tag, str) \
36 entries_[tag].name = str; \
37 entries_[tag].bytes = 0; \
38 entries_[tag].count = 0;
39
40 INIT_SPECIAL_ENTRY(kTagAssertAssignableParameterCheck,
41 "AssertAssignable:ParameterCheck");
42 INIT_SPECIAL_ENTRY(kTagAssertAssignableInsertedByFrontend,
43 "AssertAssignable:InsertedByFrontend");
44 INIT_SPECIAL_ENTRY(kTagAssertAssignableFromSource,
45 "AssertAssignable:FromSource");
46
47 INIT_SPECIAL_ENTRY(kTagCheckedEntry, "<checked-entry-prologue>");
48 INIT_SPECIAL_ENTRY(kTagIntrinsics, "<intrinsics>");
49#undef INIT_SPECIAL_ENTRY
50}
51
52void CombinedCodeStatistics::DumpStatistics() {
53 ASSERT(unaccounted_bytes_ >= 0);
54
55 Entry* sorted[kNumEntries];
56 for (intptr_t i = 0; i < kNumEntries; i++) {
57 sorted[i] = &entries_[i];
58 }
59 qsort(sorted, kNumEntries, sizeof(Entry*), &CompareEntries);
60
61 intptr_t instruction_bytes = 0;
62 for (intptr_t i = 0; i < kNumEntries; i++) {
63 instruction_bytes += entries_[i].bytes;
64 }
65 intptr_t total = object_header_bytes_ + instruction_bytes +
66 unaccounted_bytes_ + alignment_bytes_;
67 float ftotal = static_cast<float>(total) / 100.0;
68
69 OS::PrintErr("--------------------\n");
70
71 for (intptr_t i = 0; i < kNumEntries; i++) {
72 Entry* entry = sorted[i];
73 const char* name = entry->name;
74 intptr_t bytes = entry->bytes;
75 intptr_t count = entry->count;
76 float percent = bytes / ftotal;
77 float avg = static_cast<float>(bytes) / count;
78 if (bytes > 0) {
79 OS::PrintErr(
80 "%5.2f %% "
81 "% 8" Pd
82 " bytes "
83 "% 8" Pd
84 " count "
85 "%8.2f avg bytes/entry "
86 "- %s\n",
87 percent, bytes, count, avg, name);
88 }
89 }
90
91 OS::PrintErr("--------------------\n");
92
93 OS::PrintErr("%5.2f %% % 8" Pd " bytes unaccounted\n",
94 unaccounted_bytes_ / ftotal, unaccounted_bytes_);
95 OS::PrintErr("%5.2f %% % 8" Pd " bytes alignment\n",
96 alignment_bytes_ / ftotal, alignment_bytes_);
97 OS::PrintErr("%5.2f %% % 8" Pd " bytes instruction object header\n",
98 object_header_bytes_ / ftotal, object_header_bytes_);
99 OS::PrintErr("%5.2f %% % 8" Pd " bytes instructions\n",
100 instruction_bytes / ftotal, instruction_bytes);
101 OS::PrintErr("--------------------\n");
102 OS::PrintErr("%5.2f %% % 8" Pd " bytes in total\n", total / ftotal, total);
103 OS::PrintErr("--------------------\n");
104 OS::PrintErr("% 8" Pd " return-constant functions\n", return_const_count_);
105 OS::PrintErr("% 8" Pd " return-constant-with-load-field functions\n",
106 return_const_with_load_field_count_);
107 OS::PrintErr("--------------------\n");
108}
109
110int CombinedCodeStatistics::CompareEntries(const void* a, const void* b) {
111 const intptr_t a_size = (*static_cast<const Entry* const*>(a))->bytes;
112 const intptr_t b_size = (*static_cast<const Entry* const*>(b))->bytes;
113 if (a_size < b_size) {
114 return -1;
115 } else if (a_size > b_size) {
116 return 1;
117 } else {
118 return 0;
119 }
120}
121
122CodeStatistics::CodeStatistics(compiler::Assembler* assembler)
123 : assembler_(assembler) {
124 memset(entries_, 0, CombinedCodeStatistics::kNumEntries * sizeof(Entry));
125 instruction_bytes_ = 0;
126 unaccounted_bytes_ = 0;
127 alignment_bytes_ = 0;
128
129 stack_index_ = -1;
130 for (intptr_t i = 0; i < kStackSize; i++)
131 stack_[i] = -1;
132}
133
134void CodeStatistics::Begin(Instruction* instruction) {
135 SpecialBegin(static_cast<intptr_t>(instruction->statistics_tag()));
136}
137
138void CodeStatistics::End(Instruction* instruction) {
139 SpecialEnd(static_cast<intptr_t>(instruction->statistics_tag()));
140}
141
142void CodeStatistics::SpecialBegin(intptr_t tag) {
143 stack_index_++;
144 RELEASE_ASSERT(stack_index_ < kStackSize);
145 RELEASE_ASSERT(stack_[stack_index_] == -1);
146 RELEASE_ASSERT(tag < CombinedCodeStatistics::kNumEntries);
147 stack_[stack_index_] = assembler_->CodeSize();
148 RELEASE_ASSERT(stack_[stack_index_] >= 0);
149}
150
151void CodeStatistics::SpecialEnd(intptr_t tag) {
152 RELEASE_ASSERT(stack_index_ > 0 || stack_[stack_index_] >= 0);
153 RELEASE_ASSERT(tag < CombinedCodeStatistics::kNumEntries);
154
155 intptr_t diff = assembler_->CodeSize() - stack_[stack_index_];
156 RELEASE_ASSERT(diff >= 0);
157 RELEASE_ASSERT(entries_[tag].bytes >= 0);
158 RELEASE_ASSERT(entries_[tag].count >= 0);
159 entries_[tag].bytes += diff;
160 entries_[tag].count++;
161 instruction_bytes_ += diff;
162 stack_[stack_index_] = -1;
163 stack_index_--;
164}
165
166void CodeStatistics::Finalize() {
167 intptr_t function_size = assembler_->CodeSize();
168 unaccounted_bytes_ = function_size - instruction_bytes_;
169 ASSERT(unaccounted_bytes_ >= 0);
170
171 const intptr_t unaligned_bytes = Instructions::HeaderSize() + function_size;
172 alignment_bytes_ =
173 Utils::RoundUp(unaligned_bytes, kObjectAlignment) - unaligned_bytes;
174 assembler_ = NULL;
175}
176
177void CodeStatistics::AppendTo(CombinedCodeStatistics* stat) {
178 intptr_t sum = 0;
179 bool returns_constant = true;
180 bool returns_const_with_load_field_ = true;
181
182 for (intptr_t i = 0; i < CombinedCodeStatistics::kNumEntries; i++) {
183 intptr_t bytes = entries_[i].bytes;
184 stat->entries_[i].count += entries_[i].count;
185 if (bytes > 0) {
186 sum += bytes;
187 stat->entries_[i].bytes += bytes;
188 if (i != CombinedCodeStatistics::kTagParallelMove &&
189 i != CombinedCodeStatistics::kTagReturn &&
190 i != CombinedCodeStatistics::kTagCheckStackOverflow &&
191 i != CombinedCodeStatistics::kTagCheckStackOverflowSlowPath) {
192 returns_constant = false;
193 if (i != CombinedCodeStatistics::kTagLoadField &&
194 i != CombinedCodeStatistics::kTagTargetEntry &&
195 i != CombinedCodeStatistics::kTagJoinEntry) {
196 returns_const_with_load_field_ = false;
197 }
198 }
199 }
200 }
201 stat->unaccounted_bytes_ += unaccounted_bytes_;
202 ASSERT(stat->unaccounted_bytes_ >= 0);
203 stat->alignment_bytes_ += alignment_bytes_;
204 stat->object_header_bytes_ += Instructions::HeaderSize();
205
206 if (returns_constant) stat->return_const_count_++;
207 if (returns_const_with_load_field_) {
208 stat->return_const_with_load_field_count_++;
209 }
210}
211
212} // namespace dart
213