xref: /developtools/hiperf/src/subcommand.cpp (revision 48f512ce)
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
21using namespace std;
22namespace OHOS {
23namespace Developtools {
24namespace HiPerf {
25static std::map<std::string, std::unique_ptr<SubCommand>> g_SubCommandsMap;
26std::mutex g_subCommandMutex;
27
28// parse option first
29bool 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
66bool 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
87bool 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
109void 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
128void 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
149bool SubCommand::RegisterSubCommand(std::string cmdName, std::unique_ptr<SubCommand> subCommand)
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 (g_SubCommandsMap.count(cmdName) == 0) {
162        std::lock_guard<std::mutex> lock(g_subCommandMutex);
163        g_SubCommandsMap.insert(std::make_pair(cmdName, std::move(subCommand)));
164        return true;
165    } else {
166        HLOGE("subcommand '%s' already registered!", cmdName.c_str());
167        return false;
168    }
169}
170
171void SubCommand::ClearSubCommands()
172{
173    std::lock_guard<std::mutex> lock(g_subCommandMutex);
174    g_SubCommandsMap.clear();
175}
176
177const std::map<std::string, std::unique_ptr<SubCommand>> &SubCommand::GetSubCommands()
178{
179    return g_SubCommandsMap;
180}
181
182SubCommand *SubCommand::FindSubCommand(std::string &cmdName)
183{
184    HLOGV("%s", cmdName.c_str());
185    std::lock_guard<std::mutex> lock(g_subCommandMutex);
186    auto found = g_SubCommandsMap.find(cmdName);
187    if (found != g_SubCommandsMap.end()) {
188        // remove the subcmd itself
189        return found->second.get();
190    } else {
191        return nullptr;
192    }
193}
194} // namespace HiPerf
195} // namespace Developtools
196} // namespace OHOS
197