/******************************************************************************* * * MIT License * * Copyright (c) 2019 Advanced Micro Devices, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * *******************************************************************************/ #include #include #include #include #if MIOPEN_EMBED_DB #include #endif #include #include #include #include namespace miopen { namespace debug { // NOLINTNEXTLINE (cppcoreguidelines-avoid-non-const-global-variables) MIOPEN_EXPORT bool testing_find_db_enabled = true; /// \todo Remove when #1723 is resolved. std::optional& testing_find_db_path_override() { // NOLINTNEXTLINE (cppcoreguidelines-avoid-non-const-global-variables) static std::optional data{std::nullopt}; return data; } } // namespace debug #if MIOPEN_EMBED_DB template fs::path FindDbRecord_t::GetInstalledPathEmbed(const Handle& handle, const std::string& path_suffix) { static const auto embed_path = [&] { const std::string ext = ".fdb.txt"; const auto root_path = GetSystemDbPath(); const auto base_name = handle.GetDbBasename(); const auto suffix = GetSystemFindDbSuffix() + path_suffix; const auto filename = base_name + "." + suffix + ext; const auto file_path = root_path / filename; if(miopen_data().find(make_object_file_name(filename)) != miopen_data().end()) { MIOPEN_LOG_I2("Found exact embedded find database file:" << filename); return file_path; } else { MIOPEN_LOG_I2("inexact find database search"); std::vector all_files; for(const auto& kinder : miopen_data()) { const auto& fname = kinder.first.stem(); const auto& filepath = root_path / fname; if(EndsWith(fname.string(), path_suffix + ".fdb.txt")) all_files.push_back(filepath); } const auto db_id = handle.GetTargetProperties().DbId(); const int real_cu_count = handle.GetMaxComputeUnits(); int closest_cu = std::numeric_limits::max(); fs::path best_path; for(const auto& entry : all_files) { const auto fname = entry.stem().string(); MIOPEN_LOG_I2("Checking embedded find db file: " << fname); // Check for alternate back end same ASIC if(fname.rfind(base_name, 0) == 0) { return entry; } if(db_id.empty() || !miopen::StartsWith(db_id, "gfx") || real_cu_count == 0) return fs::path{}; // Check for alternate ASIC any back end if(fname.rfind(db_id, 0) == 0) { const auto pos = fname.find('_'); int cur_count = -1; if(pos != std::string::npos) cur_count = std::stoi(fname.substr(pos + 1)); else cur_count = std::stoi(fname.substr(db_id.length()), nullptr, 16); if(abs(cur_count - real_cu_count) < (closest_cu)) { best_path = entry; closest_cu = abs(cur_count - real_cu_count); } } } return best_path; } }(); return embed_path; } #else template fs::path FindDbRecord_t::GetInstalledPathFile(const Handle& handle, const std::string& path_suffix) { static const fs::path installed_path = [&] { const std::string ext = ".fdb.txt"; const auto root_path = GetSystemDbPath(); const auto base_name = handle.GetDbBasename(); const auto suffix = GetSystemFindDbSuffix() + (path_suffix.empty() ? "" : ('.' + path_suffix)); auto file_path = root_path / (base_name + "." + suffix + ext); if(fs::exists(file_path)) { MIOPEN_LOG_I2("Found exact find database file: " << file_path); return std::move(file_path); } MIOPEN_LOG_I2("inexact find database search"); if(!fs::is_directory(root_path)) { MIOPEN_LOG_I("Database directory does not exist"); file_path = fs::path{}; return std::move(file_path); } MIOPEN_LOG_I2("Iterating over find db directory " << root_path); std::vector all_files; std::vector contents; std::copy(fs::directory_iterator(root_path), fs::directory_iterator(), std::back_inserter(contents)); for(auto const& filepath : contents) { if(fs::is_regular_file(filepath) && filepath.extension() == path_suffix + ".fdb.txt") all_files.push_back(filepath); } const auto db_id = handle.GetTargetProperties().DbId(); const int real_cu_count = handle.GetMaxComputeUnits(); int closest_cu = std::numeric_limits::max(); for(const auto& entry : all_files) { const auto fname = entry.stem().string(); MIOPEN_LOG_I("Checking find db file: " << fname); // Check for alternate back end same ASIC if(fname.starts_with(base_name)) { file_path = entry; return std::move(file_path); } if(db_id.empty() || !miopen::StartsWith(db_id, "gfx") || real_cu_count == 0) { file_path = fs::path{}; return std::move(file_path); // empty } // Check for alternate ASIC any back end if(fname.starts_with(db_id)) { const auto pos = fname.find('_'); int cur_count = -1; if(pos != std::string::npos) cur_count = std::stoi(fname.substr(pos + 1)); else cur_count = std::stoi(fname.substr(db_id.length()), nullptr, 16); if(abs(cur_count - real_cu_count) < (closest_cu)) { file_path = entry; closest_cu = abs(cur_count - real_cu_count); } } } return std::move(file_path); }(); return installed_path; } #endif template fs::path FindDbRecord_t::GetInstalledPath(const Handle& handle, const std::string& path_suffix) { #if !MIOPEN_DISABLE_SYSDB #if MIOPEN_EMBED_DB return GetInstalledPathEmbed(handle, path_suffix); #else return GetInstalledPathFile(handle, path_suffix); #endif #else std::ignore = handle; std::ignore = path_suffix; return ""; #endif } template fs::path FindDbRecord_t::GetUserPath(const Handle& handle, const std::string& path_suffix) { #if !MIOPEN_DISABLE_USERDB return GetUserDbPath() / (handle.GetDbBasename() + '.' + GetUserDbSuffix() + (path_suffix.empty() ? "" : '.' + path_suffix) + ".ufdb.txt"); #else std::ignore = handle; std::ignore = path_suffix; return ""; #endif } template bool FindDbRecord_t::Validate(const Handle& handle, const NetworkConfig& config) const { auto unbuilt = false; auto any = false; if(content.has_value()) { for(const auto& pair : content->As()) { if(in_sync) { if(!handle.GetInvoker(config, {{pair.first}})) { unbuilt = true; // This is not an logged as error because no error was detected. // Find wasn't executed yet and invokers were not prepared. LogFindDbItem(pair); break; } any = true; continue; } } } else { MIOPEN_LOG_E("Error: no content."); } return !any || unbuilt; } template void FindDbRecord_t::CopyTo(std::vector& to) const { if(content.has_value()) { const auto range = content->As(); std::transform(range.begin(), range.end(), std::back_inserter(to), [](const auto& pair) { return Solution{solver::Id{pair.first}, pair.second.time, pair.second.workspace}; }); } else { MIOPEN_LOG_E("Error: no content."); } } template void FindDbRecord_t::LogFindDbItem(const std::pair& item) const { if(content.has_value()) { MIOPEN_LOG_I2("Kernel cache entry not found for solver: " << item.first << " at network config: " << content->GetKey()); for(const auto& pair2 : content->As()) MIOPEN_LOG_I2("Find-db record content: " << pair2.first << ':' << pair2.second); } else { MIOPEN_LOG_E("Error: no content."); } } template class FindDbRecord_t; template class FindDbRecord_t; } // namespace miopen