| Index: src/heap/code-stats.cc
|
| diff --git a/src/heap/code-stats.cc b/src/heap/code-stats.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..d4ff5fbba75c4ba010350de0bdea694d9250b329
|
| --- /dev/null
|
| +++ b/src/heap/code-stats.cc
|
| @@ -0,0 +1,220 @@
|
| +// Copyright 2016 the V8 project authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "src/heap/code-stats.h"
|
| +#include "src/objects-inl.h"
|
| +
|
| +namespace v8 {
|
| +namespace internal {
|
| +
|
| +// Record code statisitcs.
|
| +void CodeStatistics::RecordCodeAndMetadataStatistics(HeapObject* object,
|
| + Isolate* isolate) {
|
| + if (!object->IsAbstractCode()) {
|
| + return;
|
| + }
|
| +
|
| + // Record code+metadata statisitcs.
|
| + AbstractCode* abstract_code = AbstractCode::cast(object);
|
| + int size = abstract_code->SizeIncludingMetadata();
|
| + if (abstract_code->IsCode()) {
|
| + size += isolate->code_and_metadata_size();
|
| + isolate->set_code_and_metadata_size(size);
|
| + } else {
|
| + size += isolate->bytecode_and_metadata_size();
|
| + isolate->set_bytecode_and_metadata_size(size);
|
| + }
|
| +
|
| +#ifdef DEBUG
|
| + // Record code kind and code comment statistics.
|
| + isolate->code_kind_statistics()[abstract_code->kind()] +=
|
| + abstract_code->Size();
|
| + CodeStatistics::CollectCodeCommentStatistics(object, isolate);
|
| +#endif
|
| +}
|
| +
|
| +void CodeStatistics::ResetCodeAndMetadataStatistics(Isolate* isolate) {
|
| + isolate->set_code_and_metadata_size(0);
|
| + isolate->set_bytecode_and_metadata_size(0);
|
| +#ifdef DEBUG
|
| + ResetCodeStatistics(isolate);
|
| +#endif
|
| +}
|
| +
|
| +// Collects code size statistics:
|
| +// - code and metadata size
|
| +// - by code kind (only in debug mode)
|
| +// - by code comment (only in debug mode)
|
| +void CodeStatistics::CollectCodeStatistics(PagedSpace* space,
|
| + Isolate* isolate) {
|
| + HeapObjectIterator obj_it(space);
|
| + for (HeapObject* obj = obj_it.Next(); obj != NULL; obj = obj_it.Next()) {
|
| + RecordCodeAndMetadataStatistics(obj, isolate);
|
| + }
|
| +}
|
| +
|
| +// Collects code size statistics in LargeObjectSpace:
|
| +// - code and metadata size
|
| +// - by code kind (only in debug mode)
|
| +// - by code comment (only in debug mode)
|
| +void CodeStatistics::CollectCodeStatistics(LargeObjectSpace* space,
|
| + Isolate* isolate) {
|
| + LargeObjectIterator obj_it(space);
|
| + for (HeapObject* obj = obj_it.Next(); obj != NULL; obj = obj_it.Next()) {
|
| + RecordCodeAndMetadataStatistics(obj, isolate);
|
| + }
|
| +}
|
| +
|
| +#ifdef DEBUG
|
| +void CodeStatistics::ReportCodeStatistics(Isolate* isolate) {
|
| + // Report code kind statistics
|
| + int* code_kind_statistics = isolate->code_kind_statistics();
|
| + PrintF("\n Code kind histograms: \n");
|
| + for (int i = 0; i < AbstractCode::NUMBER_OF_KINDS; i++) {
|
| + if (code_kind_statistics[i] > 0) {
|
| + PrintF(" %-20s: %10d bytes\n",
|
| + AbstractCode::Kind2String(static_cast<AbstractCode::Kind>(i)),
|
| + code_kind_statistics[i]);
|
| + }
|
| + }
|
| + PrintF("\n");
|
| +
|
| + // Report code and metadata statisitcs
|
| + if (isolate->code_and_metadata_size() > 0) {
|
| + PrintF("Code size including metadata : %10d bytes\n",
|
| + isolate->code_and_metadata_size());
|
| + }
|
| + if (isolate->bytecode_and_metadata_size() > 0) {
|
| + PrintF("Bytecode size including metadata: %10d bytes\n",
|
| + isolate->bytecode_and_metadata_size());
|
| + }
|
| +
|
| + // Report code comment statistics
|
| + CommentStatistic* comments_statistics =
|
| + isolate->paged_space_comments_statistics();
|
| + PrintF(
|
| + "Code comment statistics (\" [ comment-txt : size/ "
|
| + "count (average)\"):\n");
|
| + for (int i = 0; i <= CommentStatistic::kMaxComments; i++) {
|
| + const CommentStatistic& cs = comments_statistics[i];
|
| + if (cs.size > 0) {
|
| + PrintF(" %-30s: %10d/%6d (%d)\n", cs.comment, cs.size, cs.count,
|
| + cs.size / cs.count);
|
| + }
|
| + }
|
| + PrintF("\n");
|
| +}
|
| +
|
| +void CodeStatistics::ResetCodeStatistics(Isolate* isolate) {
|
| + // Clear code kind statistics
|
| + int* code_kind_statistics = isolate->code_kind_statistics();
|
| + for (int i = 0; i < AbstractCode::NUMBER_OF_KINDS; i++) {
|
| + code_kind_statistics[i] = 0;
|
| + }
|
| +
|
| + // Clear code comment statistics
|
| + CommentStatistic* comments_statistics =
|
| + isolate->paged_space_comments_statistics();
|
| + for (int i = 0; i < CommentStatistic::kMaxComments; i++) {
|
| + comments_statistics[i].Clear();
|
| + }
|
| + comments_statistics[CommentStatistic::kMaxComments].comment = "Unknown";
|
| + comments_statistics[CommentStatistic::kMaxComments].size = 0;
|
| + comments_statistics[CommentStatistic::kMaxComments].count = 0;
|
| +}
|
| +
|
| +// Adds comment to 'comment_statistics' table. Performance OK as long as
|
| +// 'kMaxComments' is small
|
| +void CodeStatistics::EnterComment(Isolate* isolate, const char* comment,
|
| + int delta) {
|
| + CommentStatistic* comments_statistics =
|
| + isolate->paged_space_comments_statistics();
|
| + // Do not count empty comments
|
| + if (delta <= 0) return;
|
| + CommentStatistic* cs = &comments_statistics[CommentStatistic::kMaxComments];
|
| + // Search for a free or matching entry in 'comments_statistics': 'cs'
|
| + // points to result.
|
| + for (int i = 0; i < CommentStatistic::kMaxComments; i++) {
|
| + if (comments_statistics[i].comment == NULL) {
|
| + cs = &comments_statistics[i];
|
| + cs->comment = comment;
|
| + break;
|
| + } else if (strcmp(comments_statistics[i].comment, comment) == 0) {
|
| + cs = &comments_statistics[i];
|
| + break;
|
| + }
|
| + }
|
| + // Update entry for 'comment'
|
| + cs->size += delta;
|
| + cs->count += 1;
|
| +}
|
| +
|
| +// Call for each nested comment start (start marked with '[ xxx', end marked
|
| +// with ']'. RelocIterator 'it' must point to a comment reloc info.
|
| +void CodeStatistics::CollectCommentStatistics(Isolate* isolate,
|
| + RelocIterator* it) {
|
| + DCHECK(!it->done());
|
| + DCHECK(it->rinfo()->rmode() == RelocInfo::COMMENT);
|
| + const char* tmp = reinterpret_cast<const char*>(it->rinfo()->data());
|
| + if (tmp[0] != '[') {
|
| + // Not a nested comment; skip
|
| + return;
|
| + }
|
| +
|
| + // Search for end of nested comment or a new nested comment
|
| + const char* const comment_txt =
|
| + reinterpret_cast<const char*>(it->rinfo()->data());
|
| + const byte* prev_pc = it->rinfo()->pc();
|
| + int flat_delta = 0;
|
| + it->next();
|
| + while (true) {
|
| + // All nested comments must be terminated properly, and therefore exit
|
| + // from loop.
|
| + DCHECK(!it->done());
|
| + if (it->rinfo()->rmode() == RelocInfo::COMMENT) {
|
| + const char* const txt =
|
| + reinterpret_cast<const char*>(it->rinfo()->data());
|
| + flat_delta += static_cast<int>(it->rinfo()->pc() - prev_pc);
|
| + if (txt[0] == ']') break; // End of nested comment
|
| + // A new comment
|
| + CollectCommentStatistics(isolate, it);
|
| + // Skip code that was covered with previous comment
|
| + prev_pc = it->rinfo()->pc();
|
| + }
|
| + it->next();
|
| + }
|
| + EnterComment(isolate, comment_txt, flat_delta);
|
| +}
|
| +
|
| +// Collects code comment statistics
|
| +void CodeStatistics::CollectCodeCommentStatistics(HeapObject* obj,
|
| + Isolate* isolate) {
|
| + // Bytecode objects do not contain RelocInfo. Only process code objects
|
| + // for code comment statistics.
|
| + if (!obj->IsCode()) {
|
| + return;
|
| + }
|
| +
|
| + Code* code = Code::cast(obj);
|
| + RelocIterator it(code);
|
| + int delta = 0;
|
| + const byte* prev_pc = code->instruction_start();
|
| + while (!it.done()) {
|
| + if (it.rinfo()->rmode() == RelocInfo::COMMENT) {
|
| + delta += static_cast<int>(it.rinfo()->pc() - prev_pc);
|
| + CollectCommentStatistics(isolate, &it);
|
| + prev_pc = it.rinfo()->pc();
|
| + }
|
| + it.next();
|
| + }
|
| +
|
| + DCHECK(code->instruction_start() <= prev_pc &&
|
| + prev_pc <= code->instruction_end());
|
| + delta += static_cast<int>(code->instruction_end() - prev_pc);
|
| + EnterComment(isolate, "NoComment", delta);
|
| +}
|
| +#endif
|
| +
|
| +} // namespace internal
|
| +} // namespace v8
|
|
|