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