| // Copyright 2022 The SwiftShader 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 "SpirvProfiler.hpp" |
| |
| #include "System/Debug.hpp" |
| |
| #include "spirv-tools/libspirv.h" |
| |
| #include <string.h> |
| #include <atomic> |
| #include <fstream> |
| |
| namespace { |
| std::string GetSpvOpName(const spv::Op &op) |
| { |
| return std::string("Op") + spvOpcodeString(static_cast<uint32_t>(op)); |
| } |
| |
| std::string ConcatPath(const std::string &base, const std::string &file) |
| { |
| if(base.size() == 0) |
| { |
| return file; |
| } |
| char lastChar = *base.rend(); |
| if(lastChar == '\\' || lastChar == '/') |
| { |
| return base + file; |
| } |
| return base + "/" + file; |
| } |
| } // namespace |
| |
| namespace sw { |
| |
| SpirvProfiler::SpirvProfiler(const Configuration &config) |
| : cfg(config) |
| { |
| reportFilePath = ConcatPath(cfg.spvProfilingReportDir, "spirv_profile.txt"); |
| |
| reportThreadStop = false; |
| reportThread = std::thread{ [this] { |
| while(!reportThreadStop.load(std::memory_order_acquire)) |
| { |
| std::this_thread::sleep_for(std::chrono::milliseconds(cfg.spvProfilingReportPeriodMs)); |
| ReportSnapshot(); |
| } |
| } }; |
| } |
| |
| SpirvProfiler::~SpirvProfiler() |
| { |
| reportThreadStop.store(true, std::memory_order_release); |
| reportThread.join(); |
| } |
| |
| void SpirvProfiler::ReportSnapshot() |
| { |
| std::ofstream f{ reportFilePath }; |
| |
| if(!f) |
| { |
| warn("Error writing SPIR-V profile to file %s: %s\n", reportFilePath.c_str(), strerror(errno)); |
| return; |
| } |
| |
| auto profiles = GetRegisteredProfilesSnapshot(); |
| for(const auto &[shaderId, profileData] : profiles) |
| { |
| f << "[Shader " << shaderId << "]" << std::endl; |
| |
| f << "[SPIR-V operand execution count]" << std::endl; |
| for(const auto &[spvOp, execCount] : profileData->spvOpExecutionCount) |
| { |
| f << GetSpvOpName(spvOp) << ": " << execCount << std::endl; |
| } |
| |
| f << std::endl; |
| } |
| |
| f.close(); |
| } |
| |
| void SpirvProfiler::RegisterShaderForProfiling(std::string shaderId, std::unique_ptr<SpirvProfileData> profData) |
| { |
| marl::lock lock{ profileMux }; |
| shaderProfiles[shaderId] = std::move(profData); |
| } |
| |
| std::unordered_map<std::string, SpirvProfileData *> SpirvProfiler::GetRegisteredProfilesSnapshot() |
| { |
| marl::lock lock{ profileMux }; |
| std::unordered_map<std::string, SpirvProfileData *> snapshot; |
| for(const auto &[shaderId, profileData] : shaderProfiles) |
| { |
| snapshot.emplace(shaderId, profileData.get()); |
| } |
| return snapshot; |
| } |
| } // namespace sw |