Home | History | Annotate | Download | only in heap
      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