1// Copyright 2014 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/diagnostics/compilation-statistics.h" 6 7#include <ostream> 8#include <vector> 9 10#include "src/base/platform/platform.h" 11 12namespace v8 { 13namespace internal { 14 15void CompilationStatistics::RecordPhaseStats(const char* phase_kind_name, 16 const char* phase_name, 17 const BasicStats& stats) { 18 base::MutexGuard guard(&record_mutex_); 19 20 std::string phase_name_str(phase_name); 21 auto it = phase_map_.find(phase_name_str); 22 if (it == phase_map_.end()) { 23 PhaseStats phase_stats(phase_map_.size(), phase_kind_name); 24 it = phase_map_.insert(std::make_pair(phase_name_str, phase_stats)).first; 25 } 26 it->second.Accumulate(stats); 27} 28 29void CompilationStatistics::RecordPhaseKindStats(const char* phase_kind_name, 30 const BasicStats& stats) { 31 base::MutexGuard guard(&record_mutex_); 32 33 std::string phase_kind_name_str(phase_kind_name); 34 auto it = phase_kind_map_.find(phase_kind_name_str); 35 if (it == phase_kind_map_.end()) { 36 PhaseKindStats phase_kind_stats(phase_kind_map_.size()); 37 it = phase_kind_map_ 38 .insert(std::make_pair(phase_kind_name_str, phase_kind_stats)) 39 .first; 40 } 41 it->second.Accumulate(stats); 42} 43 44void CompilationStatistics::RecordTotalStats(const BasicStats& stats) { 45 base::MutexGuard guard(&record_mutex_); 46 total_stats_.Accumulate(stats); 47} 48 49void CompilationStatistics::BasicStats::Accumulate(const BasicStats& stats) { 50 delta_ += stats.delta_; 51 total_allocated_bytes_ += stats.total_allocated_bytes_; 52 if (stats.absolute_max_allocated_bytes_ > absolute_max_allocated_bytes_) { 53 absolute_max_allocated_bytes_ = stats.absolute_max_allocated_bytes_; 54 max_allocated_bytes_ = stats.max_allocated_bytes_; 55 function_name_ = stats.function_name_; 56 } 57} 58 59std::string CompilationStatistics::BasicStats::AsJSON() { 60// clang-format off 61#define DICT(s) "{" << s << "}" 62#define QUOTE(s) "\"" << s << "\"" 63#define MEMBER(s) QUOTE(s) << ":" 64 65 DCHECK_EQ(function_name_.find("\""), std::string::npos); 66 67 std::stringstream stream; 68 stream << DICT( 69 MEMBER("function_name") << QUOTE(function_name_) << "," 70 MEMBER("total_allocated_bytes") << total_allocated_bytes_ << "," 71 MEMBER("max_allocated_bytes") << max_allocated_bytes_ << "," 72 MEMBER("absolute_max_allocated_bytes") << absolute_max_allocated_bytes_); 73 74 return stream.str(); 75 76#undef DICT 77#undef QUOTE 78#undef MEMBER 79 // clang-format on 80} 81 82static void WriteLine(std::ostream& os, bool machine_format, const char* name, 83 const CompilationStatistics::BasicStats& stats, 84 const CompilationStatistics::BasicStats& total_stats) { 85 const size_t kBufferSize = 128; 86 char buffer[kBufferSize]; 87 88 double ms = stats.delta_.InMillisecondsF(); 89 double percent = stats.delta_.PercentOf(total_stats.delta_); 90 double size_percent = 91 static_cast<double>(stats.total_allocated_bytes_ * 100) / 92 static_cast<double>(total_stats.total_allocated_bytes_); 93 if (machine_format) { 94 base::OS::SNPrintF(buffer, kBufferSize, 95 "\"%s_time\"=%.3f\n\"%s_space\"=%zu", name, ms, name, 96 stats.total_allocated_bytes_); 97 os << buffer; 98 } else { 99 base::OS::SNPrintF(buffer, kBufferSize, 100 "%34s %10.3f (%5.1f%%) %10zu (%5.1f%%) %10zu %10zu", 101 name, ms, percent, stats.total_allocated_bytes_, 102 size_percent, stats.max_allocated_bytes_, 103 stats.absolute_max_allocated_bytes_); 104 105 os << buffer; 106 if (!stats.function_name_.empty()) { 107 os << " " << stats.function_name_.c_str(); 108 } 109 os << std::endl; 110 } 111} 112 113static void WriteFullLine(std::ostream& os) { 114 os << "-----------------------------------------------------------" 115 "-----------------------------------------------------------\n"; 116} 117 118static void WriteHeader(std::ostream& os) { 119 WriteFullLine(os); 120 os << " Turbofan phase Time (ms) " 121 << " Space (bytes) Function\n" 122 << " " 123 << " Total Max. Abs. max.\n"; 124 WriteFullLine(os); 125} 126 127static void WritePhaseKindBreak(std::ostream& os) { 128 os << " ------------------------" 129 "-----------------------------------------------------------\n"; 130} 131 132std::ostream& operator<<(std::ostream& os, const AsPrintableStatistics& ps) { 133 // phase_kind_map_ and phase_map_ don't get mutated, so store a bunch of 134 // pointers into them. 135 const CompilationStatistics& s = ps.s; 136 137 using SortedPhaseKinds = 138 std::vector<CompilationStatistics::PhaseKindMap::const_iterator>; 139 SortedPhaseKinds sorted_phase_kinds(s.phase_kind_map_.size()); 140 for (auto it = s.phase_kind_map_.begin(); it != s.phase_kind_map_.end(); 141 ++it) { 142 sorted_phase_kinds[it->second.insert_order_] = it; 143 } 144 145 using SortedPhases = 146 std::vector<CompilationStatistics::PhaseMap::const_iterator>; 147 SortedPhases sorted_phases(s.phase_map_.size()); 148 for (auto it = s.phase_map_.begin(); it != s.phase_map_.end(); ++it) { 149 sorted_phases[it->second.insert_order_] = it; 150 } 151 152 if (!ps.machine_output) WriteHeader(os); 153 for (const auto& phase_kind_it : sorted_phase_kinds) { 154 const auto& phase_kind_name = phase_kind_it->first; 155 if (!ps.machine_output) { 156 for (const auto& phase_it : sorted_phases) { 157 const auto& phase_stats = phase_it->second; 158 if (phase_stats.phase_kind_name_ != phase_kind_name) continue; 159 const auto& phase_name = phase_it->first; 160 WriteLine(os, ps.machine_output, phase_name.c_str(), phase_stats, 161 s.total_stats_); 162 } 163 WritePhaseKindBreak(os); 164 } 165 const auto& phase_kind_stats = phase_kind_it->second; 166 WriteLine(os, ps.machine_output, phase_kind_name.c_str(), phase_kind_stats, 167 s.total_stats_); 168 os << std::endl; 169 } 170 171 if (!ps.machine_output) WriteFullLine(os); 172 WriteLine(os, ps.machine_output, "totals", s.total_stats_, s.total_stats_); 173 174 return os; 175} 176 177} // namespace internal 178} // namespace v8 179