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