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