• 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  #include "src/objects-inl.h"
7  
8  namespace v8 {
9  namespace internal {
10  
11  // Record code statisitcs.
RecordCodeAndMetadataStatistics(HeapObject * object,Isolate * isolate)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  
ResetCodeAndMetadataStatistics(Isolate * isolate)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)
CollectCodeStatistics(PagedSpace * space,Isolate * isolate)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)
CollectCodeStatistics(LargeObjectSpace * space,Isolate * isolate)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
ReportCodeStatistics(Isolate * isolate)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  
ResetCodeStatistics(Isolate * isolate)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
EnterComment(Isolate * isolate,const char * comment,int delta)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.
CollectCommentStatistics(Isolate * isolate,RelocIterator * it)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
CollectCodeCommentStatistics(HeapObject * obj,Isolate * isolate)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