Files
paddlepaddle--paddle/paddle/common/performance_statistician.cc
T
2026-07-13 12:40:42 +08:00

173 lines
6.0 KiB
C++

// Copyright (c) 2024 CINN Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "paddle/common/performance_statistician.h"
#include <fstream>
#include <numeric>
#include <stack>
#include "paddle/common/enforce.h"
#include "paddle/common/errors.h"
namespace common {
std::vector<TimeDuration> PerformanceReporter::ExtractDuration(
const std::vector<TimePointInfo>& records, bool contain_recursive) {
std::vector<TimeDuration> durations;
std::stack<TimePointInfo> stk;
for (const auto& info : records) {
if (info.is_start) {
stk.push(info);
} else {
PADDLE_ENFORCE_EQ(
(!stk.empty() && stk.top().is_start),
true,
common::errors::InvalidArgument(
"There is a problem with the call stack of records"));
auto start = stk.top();
stk.pop();
if (contain_recursive || stk.empty()) {
durations.emplace_back(info.time_point - start.time_point);
}
}
}
return durations;
}
TimeDuration PerformanceReporter::Sum(
const std::vector<TimeDuration>& records) {
return std::accumulate(records.begin(), records.end(), TimeDuration::zero());
}
TimeDuration PerformanceReporter::Mean(
const std::vector<TimeDuration>& records) {
if (records.empty()) return TimeDuration::zero();
return Sum(records) / records.size();
}
TimeDuration PerformanceReporter::Max(
const std::vector<TimeDuration>& records) {
return *std::max_element(records.begin(), records.end());
}
TimeDuration PerformanceReporter::Min(
const std::vector<TimeDuration>& records) {
return *std::min_element(records.begin(), records.end());
}
std::vector<TimeDuration> PerformanceReporter::TopK(
const std::vector<TimeDuration>& records, int top_count) {
std::vector<TimeDuration> top_k(top_count);
std::partial_sort_copy(records.begin(),
records.end(),
top_k.begin(),
top_k.end(),
std::greater<TimeDuration>());
return top_k;
}
TimeDuration PerformanceReporter::TrimMean(
const std::vector<TimeDuration>& durations) {
int top_count = durations.size();
if (top_count == 0) return TimeDuration::zero();
auto top_k = TopK(durations, top_count);
int remove_num = top_count / 5;
auto avg_time = std::accumulate(top_k.begin() + remove_num,
top_k.end() - remove_num,
TimeDuration::zero());
return avg_time / (top_count - 2 * remove_num);
}
std::string PerformanceReporter::Report(
const std::vector<TimePointInfo>& records) {
if (records.empty()) return "[No Record]";
std::stringstream ss;
std::string unit = "us";
auto durations = ExtractDuration(records);
int top_count = durations.size();
auto total_time = std::chrono::duration_cast<TimeDuration>(Sum(durations));
auto mean_time = std::chrono::duration_cast<TimeDuration>(Mean(durations));
auto trim_mean_time =
std::chrono::duration_cast<TimeDuration>(TrimMean(durations));
auto max_time = std::chrono::duration_cast<TimeDuration>(Max(durations));
auto min_time = std::chrono::duration_cast<TimeDuration>(Min(durations));
auto top_k = TopK(durations, top_count);
ss << "Call Count = " << durations.size()
<< "\t Total Time = " << total_time.count() << unit
<< "\t Mean Time = " << mean_time.count() << unit
<< "\t Trim Mean Time = " << trim_mean_time.count() << unit
<< "\t Max Time = " << max_time.count() << unit
<< "\t Min Time = " << min_time.count() << unit << "\n";
ss << "Records " << top_count << ": [";
for (size_t i = 0; i < durations.size(); ++i) {
ss << i + 1 << ": "
<< std::chrono::duration_cast<TimeDuration>(durations[i]).count() << unit
<< " ";
}
ss << "]\n";
ss << "Top " << top_count << ": [";
for (size_t i = 0; i < top_k.size(); ++i) {
ss << i + 1 << ": "
<< std::chrono::duration_cast<TimeDuration>(top_k[i]).count() << unit
<< " ";
}
ss << "]\n";
return ss.str();
}
std::string PerformanceReporter::Report(const PerformanceStatistician& stat) {
std::stringstream ss;
ss << "\n";
ss << "=============================================================Start "
"Report=============================================================\n";
std::vector<std::string> labels = stat.Labels();
for (const std::string& label : labels) {
// std::cerr << "label: " << label << std::endl;
ss << "Label = [" << label << "]\n";
ss << Report(stat.Record(label));
// std::cerr << "rep: " << ss.str() << std::endl;
ss << "--------------------------------------------------------------------"
"----------------------------------------------------------------\n";
}
ss << "==============================================================End "
"Report=============================================================="
"\n";
return ss.str();
}
void PerformanceReporter::WriteToFile(const std::string& file,
const std::string& report) {
std::ofstream ofs;
ofs.open(file, std::ofstream::out | std::ofstream::ate);
if (ofs.is_open()) {
ofs << report << std::flush;
}
}
void PerformanceStatisticsStart(const std::string& label) {
common::PerformanceStatistician& ps =
common::PerformanceStatistician::Instance();
ps.Start(label);
}
void PerformanceStatisticsEnd(const std::string& label) {
common::PerformanceStatistician& ps =
common::PerformanceStatistician::Instance();
ps.End(label);
}
} // namespace common