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