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