1 /*
2 * Copyright (c) 2023 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 <getopt.h>
17
18 #include "ecmascript/base/string_helper.h"
19 #include "ecmascript/ecma_macros.h"
20 #include "ecmascript/log_wrapper.h"
21 #include "ecmascript/pgo_profiler/pgo_profiler_manager.h"
22 #include "ecmascript/platform/file.h"
23
24 namespace panda::ecmascript {
25 static const std::string VERSION = "0.0.0.1";
26 static const int MIN_PARAM_COUNT = 3;
27 using ApGenMode = PGOProfilerEncoder::ApGenMode;
28
29 class Option {
30 public:
31 enum class Mode : uint8_t {
32 VERSION_QUERY,
33 TO_BINARY,
34 TO_TEXT,
35 MERGE,
36 };
37
GetProfInPath() const38 std::string GetProfInPath() const
39 {
40 return profInPath_;
41 }
42
GetProfOutPath() const43 std::string GetProfOutPath() const
44 {
45 return profOutPath_;
46 }
47
GetHotnessThreshold() const48 uint32_t GetHotnessThreshold() const
49 {
50 return hotnessThreshold_;
51 }
52
GetMode() const53 Mode GetMode() const
54 {
55 return mode_;
56 }
57
ParseCommand(const int argc,const char ** argv)58 bool ParseCommand(const int argc, const char **argv)
59 {
60 if (argc <= 1) {
61 return false;
62 }
63
64 const struct option longOptions[] = {
65 {"text", required_argument, nullptr, 't'},
66 {"binary", required_argument, nullptr, 'b'},
67 {"hotness-threshold", required_argument, nullptr, 's'},
68 {"merge", no_argument, nullptr, 'm'},
69 {"help", no_argument, nullptr, 'h'},
70 {"version", no_argument, nullptr, 'v'},
71 {nullptr, 0, nullptr, 0},
72 };
73
74 const char *optstr = "tbs:hv";
75 int opt;
76 while ((opt = getopt_long_only(argc, const_cast<char **>(argv), optstr, longOptions, nullptr)) != -1) {
77 switch (opt) {
78 case 't':
79 mode_ = Mode::TO_TEXT;
80 break;
81 case 'b':
82 mode_ = Mode::TO_BINARY;
83 break;
84 case 's':
85 if (!base::StringHelper::StrToUInt32(optarg, &hotnessThreshold_)) {
86 LOG_NO_TAG(ERROR) << "hotness-threshold parse failure";
87 return false;
88 }
89 break;
90 case 'm':
91 mode_ = Mode::MERGE;
92 break;
93 case 'h':
94 return false;
95 case 'v':
96 mode_ = Mode::VERSION_QUERY;
97 return true;
98 default:
99 LOG_NO_TAG(ERROR) << "Invalid option";
100 return false;
101 }
102 }
103 if (optind != argc - MIN_PARAM_COUNT + 1) {
104 return false;
105 }
106 profInPath_ = argv[optind];
107 profOutPath_ = argv[optind + 1];
108
109 return true;
110 }
111
GetHelper() const112 std::string GetHelper() const
113 {
114 const std::string PROF_DUMP_HELP_HEAD_MSG =
115 "Usage: profdump... SOURCE... DEST... [OPTIONS]\n"
116 "\n"
117 "optional arguments:\n";
118 const std::string PROF_DUMP_HELP_OPTION_MSG =
119 "-t, --text binary to text.\n"
120 "-b, --binary text to binary.\n"
121 "-s, --hotness-threshold set minimum number of calls to filter method. default: 2\n"
122 "-m, --merge merge multi binary ap files into one.\n"
123 "-h, --help display this help and exit\n"
124 "-v, --version output version information and exit\n";
125 return PROF_DUMP_HELP_HEAD_MSG + PROF_DUMP_HELP_OPTION_MSG;
126 }
127
GetVersion() const128 const std::string GetVersion() const
129 {
130 return VERSION;
131 }
132
133 private:
134 Mode mode_ { Mode::TO_TEXT };
135 uint32_t hotnessThreshold_ { 1 };
136 std::string profInPath_;
137 std::string profOutPath_;
138 };
139
Main(const int argc,const char ** argv)140 int Main(const int argc, const char **argv)
141 {
142 Option option;
143 if (!option.ParseCommand(argc, argv)) {
144 LOG_NO_TAG(ERROR) << option.GetHelper();
145 return -1;
146 }
147 switch (option.GetMode()) {
148 case Option::Mode::VERSION_QUERY:
149 LOG_NO_TAG(ERROR) << "Ver: " << VERSION;
150 break;
151 case Option::Mode::TO_TEXT: {
152 if (PGOProfilerManager::GetInstance()->BinaryToText(option.GetProfInPath(),
153 option.GetProfOutPath(), option.GetHotnessThreshold())) {
154 LOG_NO_TAG(ERROR) << "profiler dump to text success!";
155 } else {
156 LOG_NO_TAG(ERROR) << "profiler dump to text failed!";
157 }
158 break;
159 }
160 case Option::Mode::TO_BINARY: {
161 if (PGOProfilerManager::GetInstance()->TextToBinary(option.GetProfInPath(), option.GetProfOutPath(),
162 option.GetHotnessThreshold(), ApGenMode::OVERWRITE)) {
163 LOG_NO_TAG(ERROR) << "profiler dump to binary success!";
164 } else {
165 LOG_NO_TAG(ERROR) << "profiler dump to binary failed!";
166 }
167 break;
168 }
169 case Option::Mode::MERGE: {
170 // For CLI tools, do not merge with existed output file
171 if (PGOProfilerManager::MergeApFiles(option.GetProfInPath(), option.GetProfOutPath(),
172 option.GetHotnessThreshold(), ApGenMode::OVERWRITE)) {
173 LOG_NO_TAG(ERROR) << "profiler merge success!";
174 }
175 break;
176 }
177 default:
178 break;
179 }
180 return 0;
181 }
182 } // namespace panda::ecmascript
183
main(int argc,const char ** argv)184 int main(int argc, const char **argv)
185 {
186 return panda::ecmascript::Main(argc, argv);
187 }
188