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