• 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 "subcommand.h"
17 #include <mutex>
18 #include "debug_logger.h"
19 #include "option.h"
20 
21 namespace OHOS {
22 namespace Developtools {
23 namespace HiPerf {
24 std::mutex SubCommand::subCommandMutex_;
25 std::map<std::string, std::unique_ptr<SubCommand>> SubCommand::subCommandMap_ = {};
26 std::map<std::string, std::function<SubCommand&()>> SubCommand::subCommandFuncMap_ = {};
27 
28 // parse option first
OnSubCommandOptions(std::vector<std::string> args)29 bool SubCommand::OnSubCommandOptions(std::vector<std::string> args)
30 {
31     // parse common first
32     if (!Option::GetOptionValue(args, "--dumpoptions", dumpOptions_)) {
33         return false;
34     }
35     if (!Option::GetOptionValue(args, "--help", showHelp_)
36         || !Option::GetOptionValue(args, "-h", showHelp_)) {
37         return false;
38     }
39 
40     if (showHelp_) {
41         if (!args.empty()) {
42             printf("unknown option '%s'\n", args.front().c_str());
43             return false;
44         }
45         if (OnPreSubCommand()) {
46             return false;
47         }
48     }
49 
50     if (ParseOption(args)) {
51         if (dumpOptions_) {
52             DumpOptions();
53         }
54         HLOGD(" args left over: (%zu): %s", args.size(), VectorToString(args).c_str());
55         if (!args.empty()) {
56             printf("unknown option '%s'\n", args.front().c_str());
57             return false;
58         }
59     } else {
60         HLOGD("incorrect option(s)\n");
61         return false;
62     }
63     return true;
64 }
65 
CheckRestartOption(std::string & appPackage,bool targetSystemWide,bool restart,std::vector<pid_t> & selectPids)66 bool SubCommand::CheckRestartOption(std::string &appPackage, bool targetSystemWide, bool restart,
67                                     std::vector<pid_t> &selectPids)
68 {
69     if (!restart) {
70         return true;
71     }
72     if (appPackage.empty()) {
73         printf("to detect the performance of application startup, --app option must be given\n");
74         return false;
75     }
76     if (targetSystemWide || !selectPids.empty()) {
77         printf("option --restart and -p/-a is conflict, please check usage\n");
78         return false;
79     }
80 
81     if (!appPackage.empty()) {
82         return IsRestarted(appPackage);
83     }
84     return false;
85 }
86 
HandleSubCommandExclude(const std::vector<pid_t> & excludeTids,const std::vector<std::string> & excludeThreadNames,std::vector<pid_t> & selectTids)87 bool SubCommand::HandleSubCommandExclude(const std::vector<pid_t> &excludeTids, const std::vector<std::string>
88                                          &excludeThreadNames, std::vector<pid_t> &selectTids)
89 {
90     if (!excludeTids.empty() && !excludeThreadNames.empty()) {
91         printf("option --exclude-thread and --exclude-tid is conflict, please check usage\n");
92         return false;
93     }
94     if (excludeTids.empty() && excludeThreadNames.empty()) {
95         return true;
96     }
97     if (selectTids.empty()) {
98         printf("No thread is Monitored, while attempt to exclude some threads.\n");
99         return true;
100     }
101     if (!excludeTids.empty()) {
102         ExcludeTidsFromSelectTids(excludeTids, selectTids);
103         return true;
104     }
105     ExcludeThreadsFromSelectTids(excludeThreadNames, selectTids);
106     return true;
107 }
108 
ExcludeTidsFromSelectTids(const std::vector<pid_t> & excludeTids,std::vector<pid_t> & selectTids)109 void SubCommand::ExcludeTidsFromSelectTids(const std::vector<pid_t> &excludeTids, std::vector<pid_t> &selectTids)
110 {
111     for (auto excludeTid : excludeTids) {
112         bool hasExclude = false;
113         auto pos = selectTids.begin();
114         while (pos != selectTids.end()) {
115             if (excludeTid == *pos) {
116                 pos = selectTids.erase(pos);
117                 hasExclude = true;
118                 continue;
119             }
120             ++pos;
121         }
122         if (!hasExclude) {
123             printf("No thread id %d was found to exclude.\n", excludeTid);
124         }
125     }
126 }
127 
ExcludeThreadsFromSelectTids(const std::vector<std::string> & excludeThreadNames,std::vector<pid_t> & selectTids)128 void SubCommand::ExcludeThreadsFromSelectTids(const std::vector<std::string> &excludeThreadNames,
129                                               std::vector<pid_t> &selectTids)
130 {
131     for (auto excludeName : excludeThreadNames) {
132         bool hasExclude = false;
133         auto pos = selectTids.begin();
134         while (pos != selectTids.end()) {
135             std::string threadName = virtualRuntime_.ReadThreadName(*pos, true);
136             if (excludeName == threadName) {
137                 pos = selectTids.erase(pos);
138                 hasExclude = true;
139                 continue;
140             }
141             ++pos;
142         }
143         if (!hasExclude) {
144             printf("No thread named %s was found to exclude.\n", excludeName.c_str());
145         }
146     }
147 }
148 
RegisterSubCommand(const std::string & cmdName,std::function<SubCommand & ()> func)149 bool SubCommand::RegisterSubCommand(const std::string& cmdName, std::function<SubCommand&()> func)
150 {
151     HLOGV("%s", cmdName.c_str());
152     if (cmdName.empty()) {
153         HLOGE("unable to register empty subcommand!");
154         return false;
155     }
156     if (cmdName.front() == '-') {
157         HLOGE("unable use '-' at the begin of subcommand '%s'", cmdName.c_str());
158         return false;
159     }
160 
161     if (subCommandFuncMap_.find(cmdName) == subCommandFuncMap_.end()) {
162         std::lock_guard<std::mutex> lock(subCommandMutex_);
163         subCommandFuncMap_.insert(std::make_pair(cmdName, func));
164         return true;
165     } else {
166         HLOGE("subcommand '%s' already registered!", cmdName.c_str());
167         return false;
168     }
169 }
170 
RegisterSubCommand(const std::string & cmdName,std::unique_ptr<SubCommand> subCommand)171 bool SubCommand::RegisterSubCommand(const std::string& cmdName, std::unique_ptr<SubCommand> subCommand)
172 {
173     SubCommand* subCommandPtr = subCommand.get();
174     auto func = [subCommandPtr]() -> SubCommand& {
175         return *subCommandPtr;
176     };
177     if (RegisterSubCommand(cmdName, func)) {
178         std::lock_guard<std::mutex> lock(subCommandMutex_);
179         subCommandMap_[cmdName] = std::move(subCommand);
180         return true;
181     }
182     return false;
183 }
184 
ClearSubCommands()185 void SubCommand::ClearSubCommands()
186 {
187     std::lock_guard<std::mutex> lock(subCommandMutex_);
188     subCommandFuncMap_.clear();
189     subCommandMap_.clear();
190 }
191 
GetSubCommands()192 const std::map<std::string, std::function<SubCommand&()>>& SubCommand::GetSubCommands()
193 {
194     return subCommandFuncMap_;
195 }
196 
FindSubCommand(std::string & cmdName)197 SubCommand *SubCommand::FindSubCommand(std::string &cmdName)
198 {
199     HLOGV("%s", cmdName.c_str());
200     std::lock_guard<std::mutex> lock(subCommandMutex_);
201     auto found = subCommandFuncMap_.find(cmdName);
202     if (found != subCommandFuncMap_.end()) {
203         return &(found->second());
204     } else {
205         return nullptr;
206     }
207 }
208 } // namespace HiPerf
209 } // namespace Developtools
210 } // namespace OHOS
211