| // 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) { | |
| base::LockGuard<base::Mutex> guard(&record_mutex_); | |
| 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) { | |
| base::LockGuard<base::Mutex> guard(&record_mutex_); | |
| 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) { | |
| base::LockGuard<base::Mutex> guard(&record_mutex_); | |
| 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 << " Turbofan 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 (const auto& phase_kind_it : sorted_phase_kinds) { | |
| const auto& phase_kind_name = phase_kind_it->first; | |
| if (!ps.machine_output) { | |
| for (const 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 |