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