Line data Source code
1 : // Copyright 2016 the V8 project authors. All rights reserved.
2 : // Use of this source code is governed by a BSD-style license that can be
3 : // found in the LICENSE file.
4 :
5 : #include "src/heap/code-stats.h"
6 : #include "src/objects-inl.h"
7 :
8 : namespace v8 {
9 : namespace internal {
10 :
11 : // Record code statisitcs.
12 0 : void CodeStatistics::RecordCodeAndMetadataStatistics(HeapObject* object,
13 0 : Isolate* isolate) {
14 0 : if (!object->IsAbstractCode()) {
15 0 : return;
16 : }
17 :
18 : // Record code+metadata statisitcs.
19 : AbstractCode* abstract_code = AbstractCode::cast(object);
20 0 : int size = abstract_code->SizeIncludingMetadata();
21 0 : if (abstract_code->IsCode()) {
22 0 : size += isolate->code_and_metadata_size();
23 : isolate->set_code_and_metadata_size(size);
24 : } else {
25 0 : size += isolate->bytecode_and_metadata_size();
26 : isolate->set_bytecode_and_metadata_size(size);
27 : }
28 :
29 : #ifdef DEBUG
30 : // Record code kind and code comment statistics.
31 : isolate->code_kind_statistics()[abstract_code->kind()] +=
32 : abstract_code->Size();
33 : CodeStatistics::CollectCodeCommentStatistics(object, isolate);
34 : #endif
35 : }
36 :
37 0 : void CodeStatistics::ResetCodeAndMetadataStatistics(Isolate* isolate) {
38 : isolate->set_code_and_metadata_size(0);
39 : isolate->set_bytecode_and_metadata_size(0);
40 : #ifdef DEBUG
41 : ResetCodeStatistics(isolate);
42 : #endif
43 0 : }
44 :
45 : // Collects code size statistics:
46 : // - code and metadata size
47 : // - by code kind (only in debug mode)
48 : // - by code comment (only in debug mode)
49 0 : void CodeStatistics::CollectCodeStatistics(PagedSpace* space,
50 : Isolate* isolate) {
51 0 : HeapObjectIterator obj_it(space);
52 0 : for (HeapObject* obj = obj_it.Next(); obj != NULL; obj = obj_it.Next()) {
53 0 : RecordCodeAndMetadataStatistics(obj, isolate);
54 : }
55 0 : }
56 :
57 : // Collects code size statistics in LargeObjectSpace:
58 : // - code and metadata size
59 : // - by code kind (only in debug mode)
60 : // - by code comment (only in debug mode)
61 0 : void CodeStatistics::CollectCodeStatistics(LargeObjectSpace* space,
62 : Isolate* isolate) {
63 0 : LargeObjectIterator obj_it(space);
64 0 : for (HeapObject* obj = obj_it.Next(); obj != NULL; obj = obj_it.Next()) {
65 0 : RecordCodeAndMetadataStatistics(obj, isolate);
66 : }
67 0 : }
68 :
69 : #ifdef DEBUG
70 : void CodeStatistics::ReportCodeStatistics(Isolate* isolate) {
71 : // Report code kind statistics
72 : int* code_kind_statistics = isolate->code_kind_statistics();
73 : PrintF("\n Code kind histograms: \n");
74 : for (int i = 0; i < AbstractCode::NUMBER_OF_KINDS; i++) {
75 : if (code_kind_statistics[i] > 0) {
76 : PrintF(" %-20s: %10d bytes\n",
77 : AbstractCode::Kind2String(static_cast<AbstractCode::Kind>(i)),
78 : code_kind_statistics[i]);
79 : }
80 : }
81 : PrintF("\n");
82 :
83 : // Report code and metadata statisitcs
84 : if (isolate->code_and_metadata_size() > 0) {
85 : PrintF("Code size including metadata : %10d bytes\n",
86 : isolate->code_and_metadata_size());
87 : }
88 : if (isolate->bytecode_and_metadata_size() > 0) {
89 : PrintF("Bytecode size including metadata: %10d bytes\n",
90 : isolate->bytecode_and_metadata_size());
91 : }
92 :
93 : // Report code comment statistics
94 : CommentStatistic* comments_statistics =
95 : isolate->paged_space_comments_statistics();
96 : PrintF(
97 : "Code comment statistics (\" [ comment-txt : size/ "
98 : "count (average)\"):\n");
99 : for (int i = 0; i <= CommentStatistic::kMaxComments; i++) {
100 : const CommentStatistic& cs = comments_statistics[i];
101 : if (cs.size > 0) {
102 : PrintF(" %-30s: %10d/%6d (%d)\n", cs.comment, cs.size, cs.count,
103 : cs.size / cs.count);
104 : }
105 : }
106 : PrintF("\n");
107 : }
108 :
109 : void CodeStatistics::ResetCodeStatistics(Isolate* isolate) {
110 : // Clear code kind statistics
111 : int* code_kind_statistics = isolate->code_kind_statistics();
112 : for (int i = 0; i < AbstractCode::NUMBER_OF_KINDS; i++) {
113 : code_kind_statistics[i] = 0;
114 : }
115 :
116 : // Clear code comment statistics
117 : CommentStatistic* comments_statistics =
118 : isolate->paged_space_comments_statistics();
119 : for (int i = 0; i < CommentStatistic::kMaxComments; i++) {
120 : comments_statistics[i].Clear();
121 : }
122 : comments_statistics[CommentStatistic::kMaxComments].comment = "Unknown";
123 : comments_statistics[CommentStatistic::kMaxComments].size = 0;
124 : comments_statistics[CommentStatistic::kMaxComments].count = 0;
125 : }
126 :
127 : // Adds comment to 'comment_statistics' table. Performance OK as long as
128 : // 'kMaxComments' is small
129 : void CodeStatistics::EnterComment(Isolate* isolate, const char* comment,
130 : int delta) {
131 : CommentStatistic* comments_statistics =
132 : isolate->paged_space_comments_statistics();
133 : // Do not count empty comments
134 : if (delta <= 0) return;
135 : CommentStatistic* cs = &comments_statistics[CommentStatistic::kMaxComments];
136 : // Search for a free or matching entry in 'comments_statistics': 'cs'
137 : // points to result.
138 : for (int i = 0; i < CommentStatistic::kMaxComments; i++) {
139 : if (comments_statistics[i].comment == NULL) {
140 : cs = &comments_statistics[i];
141 : cs->comment = comment;
142 : break;
143 : } else if (strcmp(comments_statistics[i].comment, comment) == 0) {
144 : cs = &comments_statistics[i];
145 : break;
146 : }
147 : }
148 : // Update entry for 'comment'
149 : cs->size += delta;
150 : cs->count += 1;
151 : }
152 :
153 : // Call for each nested comment start (start marked with '[ xxx', end marked
154 : // with ']'. RelocIterator 'it' must point to a comment reloc info.
155 : void CodeStatistics::CollectCommentStatistics(Isolate* isolate,
156 : RelocIterator* it) {
157 : DCHECK(!it->done());
158 : DCHECK(it->rinfo()->rmode() == RelocInfo::COMMENT);
159 : const char* tmp = reinterpret_cast<const char*>(it->rinfo()->data());
160 : if (tmp[0] != '[') {
161 : // Not a nested comment; skip
162 : return;
163 : }
164 :
165 : // Search for end of nested comment or a new nested comment
166 : const char* const comment_txt =
167 : reinterpret_cast<const char*>(it->rinfo()->data());
168 : const byte* prev_pc = it->rinfo()->pc();
169 : int flat_delta = 0;
170 : it->next();
171 : while (true) {
172 : // All nested comments must be terminated properly, and therefore exit
173 : // from loop.
174 : DCHECK(!it->done());
175 : if (it->rinfo()->rmode() == RelocInfo::COMMENT) {
176 : const char* const txt =
177 : reinterpret_cast<const char*>(it->rinfo()->data());
178 : flat_delta += static_cast<int>(it->rinfo()->pc() - prev_pc);
179 : if (txt[0] == ']') break; // End of nested comment
180 : // A new comment
181 : CollectCommentStatistics(isolate, it);
182 : // Skip code that was covered with previous comment
183 : prev_pc = it->rinfo()->pc();
184 : }
185 : it->next();
186 : }
187 : EnterComment(isolate, comment_txt, flat_delta);
188 : }
189 :
190 : // Collects code comment statistics
191 : void CodeStatistics::CollectCodeCommentStatistics(HeapObject* obj,
192 : Isolate* isolate) {
193 : // Bytecode objects do not contain RelocInfo. Only process code objects
194 : // for code comment statistics.
195 : if (!obj->IsCode()) {
196 : return;
197 : }
198 :
199 : Code* code = Code::cast(obj);
200 : RelocIterator it(code);
201 : int delta = 0;
202 : const byte* prev_pc = code->instruction_start();
203 : while (!it.done()) {
204 : if (it.rinfo()->rmode() == RelocInfo::COMMENT) {
205 : delta += static_cast<int>(it.rinfo()->pc() - prev_pc);
206 : CollectCommentStatistics(isolate, &it);
207 : prev_pc = it.rinfo()->pc();
208 : }
209 : it.next();
210 : }
211 :
212 : DCHECK(code->instruction_start() <= prev_pc &&
213 : prev_pc <= code->instruction_end());
214 : delta += static_cast<int>(code->instruction_end() - prev_pc);
215 : EnterComment(isolate, "NoComment", delta);
216 : }
217 : #endif
218 :
219 : } // namespace internal
220 : } // namespace v8
|