/* * Copyright (c) 2024 Huawei Device Co., Ltd. * 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 "timers.h" #include "os/file.h" #include #include #include #include #include #include #include namespace panda { TimeStartFunc Timer::timerStart = Timer::TimerStartDoNothing; TimeEndFunc Timer::timerEnd = Timer::TimerEndDoNothing; std::unordered_map Timer::timers_; std::vector Timer::events_; std::mutex Timer::mutex_; std::string Timer::perfFile_; void Timer::InitializeTimer(std::string &perfFile) { if (!perfFile.empty()) { Timer::timerStart = Timer::TimerStartImpl; Timer::timerEnd = Timer::TimerEndImpl; perfFile_ = perfFile; } } void WriteFile(std::stringstream &ss, std::string &perfFile) { std::ofstream fs; fs.open(panda::os::file::File::GetExtendedFilePath(perfFile)); if (!fs.is_open()) { std::cerr << "Failed to open perf file: " << perfFile << ". Errro: " << std::strerror(errno) << std::endl; return; } fs << ss.str(); fs.close(); } bool DescentComparator(const std::pair p1, const std::pair p2) { return p1.second > p2.second; } void ProcessTimePointRecord( const std::string& file, const TimePointRecord& timePointRecord, double& eventTime, std::vector>& eachFileTime, std::vector& incompleteRecords) { if (timePointRecord.startTime != std::chrono::steady_clock::time_point() && timePointRecord.endTime != std::chrono::steady_clock::time_point()) { auto duration = timePointRecord.endTime - timePointRecord.startTime; if (duration.count() >= 0) { auto t = std::chrono::duration_cast(duration).count(); eventTime += t; if (!file.empty()) { eachFileTime.emplace_back(file, t); } } else { incompleteRecords.push_back(file + ": The end time is earlier than the start time"); } } else { incompleteRecords.push_back(file + ": " + (timePointRecord.startTime == std::chrono::steady_clock::time_point() ? "Lack of start time" : "Lack of end time")); } } void Timer::PrintTimers() { std::stringstream ss; ss << "------------- Compilation time consumption in milliseconds: -------------" << std::endl; ss << "Note: When compiling multiple files in parallel, " << "we will track the time consumption of each file individually. The output will aggregate these times, " << "potentially resulting in a total time consumption less than the sum of individual file times." << std::endl << std::endl; std::vector summedUpTimeString; ss << "------------- Compilation time consumption of each file: ----------------" << std::endl; for (auto &event: events_) { auto &timeRecord = timers_.at(event); auto formattedEvent = std::string(timeRecord.level, ' ') + std::string(timeRecord.level, '#') + std::string(event); double eventTime = 0.0; std::vector> eachFileTime; std::vector incompleteRecords; for (const auto &[file, timePointRecord] : timeRecord.timePoints) { ProcessTimePointRecord(file, timePointRecord, eventTime, eachFileTime, incompleteRecords); } // print each file time consumption in descending order if (!eachFileTime.empty()) { std::sort(eachFileTime.begin(), eachFileTime.end(), DescentComparator); ss << formattedEvent << ", time consumption of each file:" << std::endl; } for (auto &pair : eachFileTime) { if (!pair.first.empty()) { ss << pair.first << ": " << pair.second << " ms" <second; } else { std::cerr << "Undefined event: " << event << ". Please check!" << std::endl; } std::unique_lock lock(mutex_); auto iter = timers_.find(event); if (iter != timers_.end()) { iter->second.timePoints.emplace(fileName, tpr); } else { TimeRecord tr; tr.timePoints.emplace(fileName, tpr); tr.event = event; tr.level = level; timers_.emplace(event, tr); events_.push_back(event); } } void Timer::TimerEndImpl(const std::string_view event, std::string fileName) { auto endTime = std::chrono::steady_clock::now(); std::unique_lock lock(mutex_); auto time_record_iter = timers_.find(event); if (time_record_iter == timers_.end()) { std::cerr << "Event " << event << " not found in records, skip record end time!" << std::endl; return; } auto& timePoints = time_record_iter->second.timePoints; auto time_point_iter = timePoints.find(fileName); if (time_point_iter == timePoints.end()) { std::cerr << "Event " << event << " and file " << fileName << " start timer not found in records, skip record end time!" << std::endl; return; } time_point_iter->second.endTime = endTime; } } // namespace panda