1b1994897Sopenharmony_ci/** 2b1994897Sopenharmony_ci * Copyright (c) 2021-2022 Huawei Device Co., Ltd. 3b1994897Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 4b1994897Sopenharmony_ci * you may not use this file except in compliance with the License. 5b1994897Sopenharmony_ci * You may obtain a copy of the License at 6b1994897Sopenharmony_ci * 7b1994897Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 8b1994897Sopenharmony_ci * 9b1994897Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 10b1994897Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 11b1994897Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12b1994897Sopenharmony_ci * See the License for the specific language governing permissions and 13b1994897Sopenharmony_ci * limitations under the License. 14b1994897Sopenharmony_ci */ 15b1994897Sopenharmony_ci 16b1994897Sopenharmony_ci#include "pgo.h" 17b1994897Sopenharmony_ci#include "os/filesystem.h" 18b1994897Sopenharmony_ci#include "utils/logger.h" 19b1994897Sopenharmony_ci 20b1994897Sopenharmony_cinamespace panda::panda_file::pgo { 21b1994897Sopenharmony_ci 22b1994897Sopenharmony_ci/* static */ 23b1994897Sopenharmony_cistd::string ProfileOptimizer::GetNameInfo(const std::unique_ptr<BaseItem> &item) 24b1994897Sopenharmony_ci{ 25b1994897Sopenharmony_ci std::string identity; 26b1994897Sopenharmony_ci if (item->GetName() == CLASS_ITEM) { 27b1994897Sopenharmony_ci identity = static_cast<ClassItem *>(item.get())->GetNameItem()->GetData(); 28b1994897Sopenharmony_ci ASSERT(identity.find('L') == 0); // the first character must be 'L' 29b1994897Sopenharmony_ci // must end with ";\0",2 indicates the end mark of the count 30b1994897Sopenharmony_ci ASSERT(identity.find(";\0") == identity.length() - 2); 31b1994897Sopenharmony_ci // remove 'L' and ";\0",3 indicates the number of characters that need to be removed 32b1994897Sopenharmony_ci identity = identity.substr(1, identity.length() - 3); 33b1994897Sopenharmony_ci std::replace(identity.begin(), identity.end(), '/', '.'); 34b1994897Sopenharmony_ci } else if (item->GetName() == STRING_ITEM) { 35b1994897Sopenharmony_ci identity = static_cast<StringItem *>(item.get())->GetData(); 36b1994897Sopenharmony_ci ASSERT(identity.find('\0') == identity.length() - 1); // must end with '\0' 37b1994897Sopenharmony_ci identity.pop_back(); // remove '\0' 38b1994897Sopenharmony_ci } else { 39b1994897Sopenharmony_ci UNREACHABLE(); 40b1994897Sopenharmony_ci } 41b1994897Sopenharmony_ci return identity; 42b1994897Sopenharmony_ci} 43b1994897Sopenharmony_ci 44b1994897Sopenharmony_civoid ProfileOptimizer::MarkProfileItem(std::unique_ptr<BaseItem> &item, bool set_pgo) const 45b1994897Sopenharmony_ci{ 46b1994897Sopenharmony_ci auto inc = static_cast<uint32_t>(set_pgo); 47b1994897Sopenharmony_ci if (item->GetName() == CLASS_ITEM) { 48b1994897Sopenharmony_ci item->SetPGORank(PGO_CLASS_DEFAULT_COUNT + inc); 49b1994897Sopenharmony_ci } else if (item->GetName() == STRING_ITEM) { 50b1994897Sopenharmony_ci item->SetPGORank(PGO_STRING_DEFAULT_COUNT + inc); 51b1994897Sopenharmony_ci } else if (item->GetName() == CODE_ITEM) { 52b1994897Sopenharmony_ci item->SetPGORank(PGO_CODE_DEFAULT_COUNT + inc); 53b1994897Sopenharmony_ci } else { 54b1994897Sopenharmony_ci UNREACHABLE(); 55b1994897Sopenharmony_ci } 56b1994897Sopenharmony_ci} 57b1994897Sopenharmony_ci 58b1994897Sopenharmony_cibool ProfileOptimizer::ParseProfileData() 59b1994897Sopenharmony_ci{ 60b1994897Sopenharmony_ci std::string path = os::GetAbsolutePath(profile_file_path_); 61b1994897Sopenharmony_ci if (path == "") { 62b1994897Sopenharmony_ci LOG(ERROR, PANDAFILE) << "failed to resolve profile file path: " << profile_file_path_; 63b1994897Sopenharmony_ci return false; 64b1994897Sopenharmony_ci } 65b1994897Sopenharmony_ci 66b1994897Sopenharmony_ci std::ifstream file; 67b1994897Sopenharmony_ci file.open(path, std::ios::in); 68b1994897Sopenharmony_ci if (!file.is_open()) { 69b1994897Sopenharmony_ci LOG(ERROR, PANDAFILE) << "failed to open pgo files: " << profile_file_path_; 70b1994897Sopenharmony_ci return false; 71b1994897Sopenharmony_ci } 72b1994897Sopenharmony_ci std::string str_line; 73b1994897Sopenharmony_ci while (std::getline(file, str_line)) { 74b1994897Sopenharmony_ci if (str_line.empty()) { 75b1994897Sopenharmony_ci continue; 76b1994897Sopenharmony_ci } 77b1994897Sopenharmony_ci auto comma_pos = str_line.find(':'); 78b1994897Sopenharmony_ci if (comma_pos == std::string::npos) { 79b1994897Sopenharmony_ci continue; 80b1994897Sopenharmony_ci } 81b1994897Sopenharmony_ci auto item_type = str_line.substr(0, comma_pos); 82b1994897Sopenharmony_ci auto str = str_line.substr(comma_pos + 1); 83b1994897Sopenharmony_ci profile_data_.emplace_back(item_type, str); 84b1994897Sopenharmony_ci } 85b1994897Sopenharmony_ci 86b1994897Sopenharmony_ci return true; 87b1994897Sopenharmony_ci} 88b1994897Sopenharmony_ci 89b1994897Sopenharmony_cistatic bool cmp(const std::unique_ptr<BaseItem> &item1, const std::unique_ptr<BaseItem> &item2) 90b1994897Sopenharmony_ci{ 91b1994897Sopenharmony_ci if (item1->GetPGORank() == item2->GetPGORank()) { 92b1994897Sopenharmony_ci return item1->GetOriginalRank() < item2->GetOriginalRank(); 93b1994897Sopenharmony_ci } 94b1994897Sopenharmony_ci if ((item1->GetName() != CODE_ITEM && item2->GetName() != CODE_ITEM) || 95b1994897Sopenharmony_ci (item1->GetName() == CODE_ITEM && item2->GetName() == CODE_ITEM)) { 96b1994897Sopenharmony_ci return item1->GetPGORank() > item2->GetPGORank(); 97b1994897Sopenharmony_ci } 98b1994897Sopenharmony_ci // code items will depends on the layout of string and literal item, so put it on the end 99b1994897Sopenharmony_ci return item1->GetName() != CODE_ITEM; 100b1994897Sopenharmony_ci} 101b1994897Sopenharmony_ci 102b1994897Sopenharmony_civoid ProfileOptimizer::ProfileGuidedRelayout(std::list<std::unique_ptr<BaseItem>> &items) 103b1994897Sopenharmony_ci{ 104b1994897Sopenharmony_ci ParseProfileData(); 105b1994897Sopenharmony_ci uint32_t original_rank = 0; 106b1994897Sopenharmony_ci for (auto &item : items) { 107b1994897Sopenharmony_ci item->SetOriginalRank(original_rank++); 108b1994897Sopenharmony_ci if (!item->NeedsEmit()) { 109b1994897Sopenharmony_ci continue; 110b1994897Sopenharmony_ci } 111b1994897Sopenharmony_ci auto type_name = item->GetName(); 112b1994897Sopenharmony_ci if (type_name != CLASS_ITEM && type_name != STRING_ITEM && type_name != CODE_ITEM) { 113b1994897Sopenharmony_ci continue; 114b1994897Sopenharmony_ci } 115b1994897Sopenharmony_ci 116b1994897Sopenharmony_ci MarkProfileItem(item, false); 117b1994897Sopenharmony_ci 118b1994897Sopenharmony_ci auto finder = [&item](const std::pair<std::string, std::string> &p) { 119b1994897Sopenharmony_ci if (p.first != item->GetName()) { 120b1994897Sopenharmony_ci return false; 121b1994897Sopenharmony_ci } 122b1994897Sopenharmony_ci if (item->GetName() != CODE_ITEM) { 123b1994897Sopenharmony_ci return p.second == GetNameInfo(item); 124b1994897Sopenharmony_ci } 125b1994897Sopenharmony_ci // CodeItem can be shared between multiple methods, so we need to check all these methods 126b1994897Sopenharmony_ci auto method_names = static_cast<CodeItem *>(item.get())->GetMethodNames(); 127b1994897Sopenharmony_ci return std::find(method_names.begin(), method_names.end(), p.second) != method_names.end(); 128b1994897Sopenharmony_ci }; 129b1994897Sopenharmony_ci if (std::find_if(profile_data_.begin(), profile_data_.end(), finder) != profile_data_.end()) { 130b1994897Sopenharmony_ci MarkProfileItem(item, true); 131b1994897Sopenharmony_ci } 132b1994897Sopenharmony_ci } 133b1994897Sopenharmony_ci 134b1994897Sopenharmony_ci items.sort(cmp); 135b1994897Sopenharmony_ci} 136b1994897Sopenharmony_ci 137b1994897Sopenharmony_ci} // namespace panda::panda_file::pgo 138