// Copyright (c) Advanced Micro Devices, Inc., or its affiliates. // SPDX-License-Identifier: MIT #include #include // std::isspace() #include #include #include #include #include #include #include #include #include #include #include // Keep compatibility with old format for reading existing system find-db files. // To be removed when the system find-db files regenerated in the 2.0 format. #define WORKAROUND_ISSUE_1987 1 namespace miopen { bool DbRecord::SetValues(const std::string& id, const std::string& values) { constexpr auto log_level = MIOPEN_ENABLE_SQLITE ? LoggingLevel::Info2 : LoggingLevel::Info; // No need to update the file if values are the same: const auto it = map.find(id); if(it == map.end() || it->second != values) { MIOPEN_LOG(log_level, key << ", content " << (it == map.end() ? "inserted" : "overwritten") << ": " << id << ':' << values); map[id] = values; return true; } MIOPEN_LOG(log_level, key << ", content is the same, not changed:" << id << ':' << values); return false; } bool DbRecord::GetValues(const std::string& id, std::string& values) const { const auto it = map.find(id); if(it == map.end()) { MIOPEN_LOG_I(key << '=' << id << ':' << ""); return false; } values = it->second; MIOPEN_LOG_I(key << '=' << id << ':' << values); return true; } bool DbRecord::EraseValues(const std::string& id) { const auto it = map.find(id); if(it != map.end()) { MIOPEN_LOG_I(key << ", removed: " << id << ':' << it->second); map.erase(it); return true; } MIOPEN_LOG_W(key << ", not found: " << id); return false; } #if WORKAROUND_ISSUE_1987 /// Transform find-db (v.1.0) ID:VALUES to the current format. /// Implementation is intentionally straightforward. /// Do not include the 1st value from VALUES (solver name) into transformed VALUES. /// Ignore FdbKCache_Key pair (last two values). /// Append id (algorithm) to VALUES. /// Use solver name as ID. static bool TransformFindDbItem10to20(std::string& id, std::string& values) { MIOPEN_LOG_T("Legacy find-db item: " << id << ':' << values); std::size_t pos = values.find(','); if(pos == std::string::npos) return false; const auto solver = values.substr(0, pos); const auto time_workspace_pos = pos + 1; pos = values.find(',', time_workspace_pos); if(pos == std::string::npos) return false; pos = values.find(',', pos + 1); if(pos == std::string::npos) return false; const auto time_workspace = values.substr(time_workspace_pos, pos - time_workspace_pos); values = time_workspace + ',' + id; id = solver; MIOPEN_LOG_T("Transformed find-db item: " << id << ':' << values); return true; } #endif bool DbRecord::ParseContents(std::istream& contents) { std::string id_and_values; int found = 0; map.clear(); while(std::getline(contents, id_and_values, ';')) { const auto id_size = id_and_values.find(':'); // Empty VALUES is ok, empty ID is not: if(id_size == std::string::npos) { MIOPEN_LOG_E("Ill-formed file: ID not found; skipped; key: " << key); continue; } auto id = id_and_values.substr(0, id_size); auto values = id_and_values.substr(id_size + 1); const auto ltrim = [](std::string& str) { auto e = std::ranges::find_if_not(str, [](char c) { return std::isspace(c); }); str.erase(str.begin(), e); return str; }; const auto rtrim = [](std::string& str) { auto e = std::ranges::find_if_not(str | std::views::reverse, [](char c) { return std::isspace(c); }); str.erase(e.base(), str.end()); return str; }; ltrim(values); rtrim(values); #if WORKAROUND_ISSUE_1987 // Detect legacy find-db item (v.1.0 ID:VALUES) and transform it to the current format. // For now, *only* legacy find-db record use convolution algorithm as ID, so if ID is // a valid algorithm, then we can safely assume that the item is in legacy format. if(IsValidConvolutionDirAlgo(id)) { if(!TransformFindDbItem10to20(id, values)) { MIOPEN_LOG_E("Ill-formed legacy find-db item: " << values); continue; } } #endif if(map.find(id) != map.end()) { MIOPEN_LOG_E("Duplicate ID (ignored): " << id << "; key: " << key); continue; } map.emplace(id, values); ++found; } return (found > 0); } void DbRecord::WriteContents(std::ostream& stream) const { if(map.empty()) return; stream << key << '='; WriteIdsAndValues(stream); } void DbRecord::WriteIdsAndValues(std::ostream& stream) const { if(map.empty()) return; const auto pairsJoiner = [](const std::string& sum, const std::pair& pair) { const auto pair_str = pair.first + ':' + pair.second; return sum.empty() ? pair_str : sum + ';' + pair_str; }; stream << std::accumulate(map.begin(), map.end(), std::string(), pairsJoiner) << std::endl; } void DbRecord::Merge(const DbRecord& that) { if(key != that.key) return; for(const auto& that_pair : that.map) { if(map.find(that_pair.first) != map.end()) continue; map[that_pair.first] = that_pair.second; } } } // namespace miopen