// Copyright 2014 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 <ostream> // NOLINT(readability/streams) #include <vector> #include "src/base/platform/platform.h" #include "src/compilation-statistics.h" namespace v8 { namespace internal { void CompilationStatistics::RecordPhaseStats(const char* phase_kind_name, const char* phase_name, const BasicStats& stats) { std::string phase_name_str(phase_name); auto it = phase_map_.find(phase_name_str); if (it == phase_map_.end()) { PhaseStats phase_stats(phase_map_.size(), phase_kind_name); it = phase_map_.insert(std::make_pair(phase_name_str, phase_stats)).first; } it->second.Accumulate(stats); } void CompilationStatistics::RecordPhaseKindStats(const char* phase_kind_name, const BasicStats& stats) { std::string phase_kind_name_str(phase_kind_name); auto it = phase_kind_map_.find(phase_kind_name_str); if (it == phase_kind_map_.end()) { PhaseKindStats phase_kind_stats(phase_kind_map_.size()); it = phase_kind_map_.insert(std::make_pair(phase_kind_name_str, phase_kind_stats)).first; } it->second.Accumulate(stats); } void CompilationStatistics::RecordTotalStats(size_t source_size, const BasicStats& stats) { source_size += source_size; total_stats_.Accumulate(stats); } void CompilationStatistics::BasicStats::Accumulate(const BasicStats& stats) { delta_ += stats.delta_; total_allocated_bytes_ += stats.total_allocated_bytes_; if (stats.absolute_max_allocated_bytes_ > absolute_max_allocated_bytes_) { absolute_max_allocated_bytes_ = stats.absolute_max_allocated_bytes_; max_allocated_bytes_ = stats.max_allocated_bytes_; function_name_ = stats.function_name_; } } static void WriteLine(std::ostream& os, bool machine_format, const char* name, const CompilationStatistics::BasicStats& stats, const CompilationStatistics::BasicStats& total_stats) { const size_t kBufferSize = 128; char buffer[kBufferSize]; double ms = stats.delta_.InMillisecondsF(); double percent = stats.delta_.PercentOf(total_stats.delta_); double size_percent = static_cast<double>(stats.total_allocated_bytes_ * 100) / static_cast<double>(total_stats.total_allocated_bytes_); if (machine_format) { base::OS::SNPrintF(buffer, kBufferSize, "\"%s_time\"=%.3f\n\"%s_space\"=%" PRIuS, name, ms, name, stats.total_allocated_bytes_); os << buffer; } else { base::OS::SNPrintF(buffer, kBufferSize, "%28s %10.3f (%5.1f%%) %10" PRIuS " (%5.1f%%) %10" PRIuS " %10" PRIuS, name, ms, percent, stats.total_allocated_bytes_, size_percent, stats.max_allocated_bytes_, stats.absolute_max_allocated_bytes_); os << buffer; if (stats.function_name_.size() > 0) { os << " " << stats.function_name_.c_str(); } os << std::endl; } } static void WriteFullLine(std::ostream& os) { os << "--------------------------------------------------------" "--------------------------------------------------------\n"; } static void WriteHeader(std::ostream& os) { WriteFullLine(os); os << " Turbonfan phase Time (ms) " << " Space (bytes) Function\n" << " " << " Total Max. Abs. max.\n"; WriteFullLine(os); } static void WritePhaseKindBreak(std::ostream& os) { os << " ---------------------------" "--------------------------------------------------------\n"; } std::ostream& operator<<(std::ostream& os, const AsPrintableStatistics& ps) { // phase_kind_map_ and phase_map_ don't get mutated, so store a bunch of // pointers into them. const CompilationStatistics& s = ps.s; typedef std::vector<CompilationStatistics::PhaseKindMap::const_iterator> SortedPhaseKinds; SortedPhaseKinds sorted_phase_kinds(s.phase_kind_map_.size()); for (auto it = s.phase_kind_map_.begin(); it != s.phase_kind_map_.end(); ++it) { sorted_phase_kinds[it->second.insert_order_] = it; } typedef std::vector<CompilationStatistics::PhaseMap::const_iterator> SortedPhases; SortedPhases sorted_phases(s.phase_map_.size()); for (auto it = s.phase_map_.begin(); it != s.phase_map_.end(); ++it) { sorted_phases[it->second.insert_order_] = it; } if (!ps.machine_output) WriteHeader(os); for (auto phase_kind_it : sorted_phase_kinds) { const auto& phase_kind_name = phase_kind_it->first; if (!ps.machine_output) { for (auto phase_it : sorted_phases) { const auto& phase_stats = phase_it->second; if (phase_stats.phase_kind_name_ != phase_kind_name) continue; const auto& phase_name = phase_it->first; WriteLine(os, ps.machine_output, phase_name.c_str(), phase_stats, s.total_stats_); } WritePhaseKindBreak(os); } const auto& phase_kind_stats = phase_kind_it->second; WriteLine(os, ps.machine_output, phase_kind_name.c_str(), phase_kind_stats, s.total_stats_); os << std::endl; } if (!ps.machine_output) WriteFullLine(os); WriteLine(os, ps.machine_output, "totals", s.total_stats_, s.total_stats_); return os; } } // namespace internal } // namespace v8