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 void CodeStatistics::RecordCodeAndMetadataStatistics(HeapObject* object, 13 Isolate* isolate) { 14 if (!object->IsAbstractCode()) { 15 return; 16 } 17 18 // Record code+metadata statisitcs. 19 AbstractCode* abstract_code = AbstractCode::cast(object); 20 int size = abstract_code->SizeIncludingMetadata(); 21 if (abstract_code->IsCode()) { 22 size += isolate->code_and_metadata_size(); 23 isolate->set_code_and_metadata_size(size); 24 } else { 25 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 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 } 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 void CodeStatistics::CollectCodeStatistics(PagedSpace* space, 50 Isolate* isolate) { 51 HeapObjectIterator obj_it(space); 52 for (HeapObject* obj = obj_it.Next(); obj != NULL; obj = obj_it.Next()) { 53 RecordCodeAndMetadataStatistics(obj, isolate); 54 } 55 } 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 void CodeStatistics::CollectCodeStatistics(LargeObjectSpace* space, 62 Isolate* isolate) { 63 LargeObjectIterator obj_it(space); 64 for (HeapObject* obj = obj_it.Next(); obj != NULL; obj = obj_it.Next()) { 65 RecordCodeAndMetadataStatistics(obj, isolate); 66 } 67 } 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 221