• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) Huawei Technologies Co., Ltd. 2021. All rights reserved.
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 <arpa/inet.h>
17 #include <cinttypes>
18 #include <condition_variable>
19 #include <csignal>
20 #include <cstdio>
21 #include <cstring>
22 #include <fstream>
23 #include <getopt.h>
24 #include <grpcpp/grpcpp.h>
25 #include <ifaddrs.h>
26 #include <netinet/in.h>
27 #include <ostream>
28 #include <sys/types.h>
29 #include <thread>
30 #include <unistd.h>
31 #include <vector>
32 #include <future>
33 
34 #include "common.h"
35 #include "command_line.h"
36 #include "google/protobuf/text_format.h"
37 #include "parameters.h"
38 #include "parse_plugin_config.h"
39 #include "profiler_service.grpc.pb.h"
40 #include "trace_plugin_config.pb.h"
41 
42 using google::protobuf::TextFormat;
43 
44 namespace {
45 constexpr int ADDR_BUFFER_SIZE = 128;
46 constexpr int MS_PER_S = 1000;
47 constexpr int KEEP_SESSION_TIMEOUT_MS = 5 * 1000;
48 constexpr int KEEP_SESSION_SLEEP_SECOND = 3;
49 constexpr int DEFAULT_SESSION_TIME_S = 10;
50 const std::string DEFAULT_OUTPUT_FILE = "/data/local/tmp/hiprofiler_data.htrace";
51 const std::string HIPROFILERD_NAME("hiprofilerd");
52 const std::string HIPROFILER_PLUGINS_NAME("hiprofiler_plugins");
53 const std::string NATIVE_DAEMON_NAME("native_daemon");
54 
55 uint32_t g_sampleDuration = 0;
56 int g_hiprofilerdPid = -1;
57 int g_hiprofilerPluginsPid = -1;
58 int g_nativeDaemonPid = -1;
59 std::condition_variable g_sessionCv;
60 std::condition_variable g_keepSessionCv;
61 bool g_exitProcessFlag = false;
62 
63 std::mutex g_keepSessionMutex;
64 std::mutex g_sessionMutex;
65 
GetLoopbackAddress()66 std::string GetLoopbackAddress()
67 {
68     char addressBuffer[ADDR_BUFFER_SIZE] = "";
69     struct ifaddrs* ifAddrStruct = nullptr;
70     void* tmpAddrPtr = nullptr;
71 
72     getifaddrs(&ifAddrStruct);
73     while (ifAddrStruct != nullptr) {
74         if (ifAddrStruct->ifa_addr == nullptr) {
75             ifAddrStruct = ifAddrStruct->ifa_next;
76             continue;
77         }
78         if (ifAddrStruct->ifa_addr->sa_family == AF_INET) {
79             // is a valid IP4 Address
80             tmpAddrPtr = &((reinterpret_cast<struct sockaddr_in*>(ifAddrStruct->ifa_addr))->sin_addr);
81             inet_ntop(AF_INET, tmpAddrPtr, addressBuffer, INET_ADDRSTRLEN);
82             if (strcmp(addressBuffer, "127.0.0.1") == 0) {
83                 break;
84             }
85         } else if (ifAddrStruct->ifa_addr->sa_family == AF_INET6) { // check it is IP6
86             // is a valid IP6 Address
87             tmpAddrPtr = &((reinterpret_cast<struct sockaddr_in*>(ifAddrStruct->ifa_addr))->sin_addr);
88             inet_ntop(AF_INET6, tmpAddrPtr, addressBuffer, INET6_ADDRSTRLEN);
89         }
90         ifAddrStruct = ifAddrStruct->ifa_next;
91     }
92 
93     freeifaddrs(ifAddrStruct);
94     return addressBuffer;
95 }
96 
GetServicePort()97 uint16_t GetServicePort()
98 {
99     return COMMON::GetServicePort();
100 }
101 
MakeCreateRequest(const std::string & config,const std::string & keepSecond,const std::string & outputFile)102 std::unique_ptr<CreateSessionRequest> MakeCreateRequest(const std::string& config,
103                                                         const std::string& keepSecond,
104                                                         const std::string& outputFile)
105 {
106     auto request = std::make_unique<CreateSessionRequest>();
107     if (!request) {
108         return nullptr;
109     }
110 
111     std::string content = config;
112     if (content.empty()) {
113         printf("config file empty!");
114         return nullptr;
115     }
116 
117     if (!ParsePluginConfig::GetInstance().GetParser().ParseFromString(content, request.get())) {
118         printf("config [%s] parse FAILED!\n", content.c_str());
119         return nullptr;
120     }
121 
122     auto sessionConfig = request->mutable_session_config();
123     if (!sessionConfig) {
124         return nullptr;
125     }
126 
127     request->set_request_id(1);
128     if (!keepSecond.empty()) {
129         int ks = std::stoi(keepSecond);
130         if (ks > 0) {
131             sessionConfig->set_sample_duration(ks * MS_PER_S);
132         }
133     } else if (sessionConfig->sample_duration() <= 0) {
134         sessionConfig->set_sample_duration(DEFAULT_SESSION_TIME_S * MS_PER_S);
135     }
136     if (!outputFile.empty()) {
137         sessionConfig->set_result_file(outputFile);
138     } else if (sessionConfig->result_file() == "") {
139         sessionConfig->set_result_file(DEFAULT_OUTPUT_FILE);
140     }
141     printf("keepSecond: %us, outputFileName: %s\n", sessionConfig->sample_duration() / MS_PER_S,
142         sessionConfig->result_file().c_str());
143 
144     g_sampleDuration = sessionConfig->sample_duration();
145     for (int i = 0; i < request->plugin_configs().size(); i++) {
146         auto pluginConfig = request->mutable_plugin_configs(i);
147         if (!ParsePluginConfig::GetInstance().SetSerializePluginsConfig(pluginConfig->name(), *pluginConfig)) {
148             printf("set %s plugin config failed\n", pluginConfig->name().c_str());
149             return nullptr;
150         }
151     }
152 
153     content.clear();
154     if (!TextFormat::PrintToString(*request.get(), &content)) {
155         printf("config message format FAILED!\n");
156         return nullptr;
157     }
158 
159     return request;
160 }
161 
GetProfilerServiceStub()162 std::unique_ptr<IProfilerService::Stub> GetProfilerServiceStub()
163 {
164     std::string serviceUri = GetLoopbackAddress() + ":" + std::to_string(GetServicePort());
165     auto grpcChannel = grpc::CreateChannel(serviceUri, grpc::InsecureChannelCredentials());
166     if (grpcChannel == nullptr) {
167         printf("Create gRPC channel failed!\n");
168         return nullptr;
169     }
170     return IProfilerService::NewStub(grpcChannel);
171 }
172 
GetCapabilities(std::string & content,bool isCheck)173 bool GetCapabilities(std::string& content, bool isCheck)
174 {
175     auto profilerStub = GetProfilerServiceStub();
176     if (profilerStub == nullptr) {
177         printf("Get profiler service stub failed!\n");
178         return false;
179     }
180 
181     GetCapabilitiesRequest capRequest;
182     GetCapabilitiesResponse capResponse;
183     capRequest.set_request_id(0);
184     grpc::ClientContext capContext;
185     grpc::Status status = profilerStub->GetCapabilities(&capContext, capRequest, &capResponse);
186     if (!status.ok()) {
187         printf("Service not started\n");
188         return false;
189     }
190 
191     if (!TextFormat::PrintToString(capResponse, &content)) {
192         printf("capabilities message format FAILED!\n");
193         return false;
194     }
195 
196     if (!isCheck) {
197         printf("support plugin list:\n%s\n", content.c_str());
198     }
199     return true;
200 }
201 
CreateSession(std::unique_ptr<IProfilerService::Stub> & profilerStub,const std::string & config,const std::string & keepSecond,const std::string & outputFile)202 uint32_t CreateSession(std::unique_ptr<IProfilerService::Stub>& profilerStub, const std::string& config,
203     const std::string& keepSecond, const std::string& outputFile)
204 {
205     auto request = MakeCreateRequest(config, keepSecond, outputFile);
206     if (!request) {
207         printf("MakeCreateRequest failed!\n");
208         return 0;
209     }
210 
211     CreateSessionResponse createResponse;
212     grpc::ClientContext createSessionContext;
213     grpc::Status status = profilerStub->CreateSession(&createSessionContext, *request, &createResponse);
214     if (!status.ok()) {
215         printf("CreateSession FAIL\n");
216         return 0;
217     }
218 
219     return createResponse.session_id();
220 }
221 
CheckStartSession(std::unique_ptr<IProfilerService::Stub> & profilerStub,uint32_t & sessionId)222 bool CheckStartSession(std::unique_ptr<IProfilerService::Stub>& profilerStub, uint32_t& sessionId)
223 {
224     StartSessionRequest startRequest;
225     StartSessionResponse startResponse;
226     startRequest.set_request_id(0);
227     startRequest.set_session_id(sessionId);
228     grpc::ClientContext startContext;
229     grpc::Status status = profilerStub->StartSession(&startContext, startRequest, &startResponse);
230     if (!status.ok()) {
231         printf("StartSession FAIL\n");
232         return false;
233     }
234 
235     return true;
236 }
237 
CheckStopSession(std::unique_ptr<IProfilerService::Stub> & profilerStub,uint32_t & sessionId)238 bool CheckStopSession(std::unique_ptr<IProfilerService::Stub>& profilerStub, uint32_t& sessionId)
239 {
240     StopSessionRequest stopRequest;
241     StopSessionResponse stopResponse;
242     grpc::ClientContext stopContext;
243     stopRequest.set_session_id(sessionId);
244     grpc::Status status = profilerStub->StopSession(&stopContext, stopRequest, &stopResponse);
245     if (!status.ok()) {
246         return false;
247     }
248 
249     printf("StopSession done!\n");
250     return true;
251 }
252 
CheckDestroySession(std::unique_ptr<IProfilerService::Stub> & profilerStub,uint32_t & sessionId)253 bool CheckDestroySession(std::unique_ptr<IProfilerService::Stub>& profilerStub, uint32_t& sessionId)
254 {
255     DestroySessionRequest destroyRequest;
256     DestroySessionResponse destroyResponse;
257     grpc::ClientContext destroyContext;
258     destroyRequest.set_session_id(sessionId);
259     grpc::Status status = profilerStub->DestroySession(&destroyContext, destroyRequest, &destroyResponse);
260     if (!status.ok()) {
261         return false;
262     }
263 
264     printf("DestroySession done!\n");
265     return true;
266 }
267 
StartThread(std::unique_ptr<IProfilerService::Stub> & profilerStub,uint32_t & id,std::atomic<bool> & sendHeart)268 void StartThread(std::unique_ptr<IProfilerService::Stub>& profilerStub, uint32_t& id, std::atomic<bool>& sendHeart)
269 {
270     while (sendHeart.load()) {
271         KeepSessionRequest keepRequest;
272         keepRequest.set_request_id(0);
273         keepRequest.set_session_id(id);
274         keepRequest.set_keep_alive_time(KEEP_SESSION_TIMEOUT_MS);
275         grpc::ClientContext keepContext;
276         KeepSessionResponse keepResponse;
277         profilerStub->KeepSession(&keepContext, keepRequest, &keepResponse);
278 
279         std::unique_lock<std::mutex> lck(g_keepSessionMutex);
280         g_keepSessionCv.wait_for(lck, std::chrono::seconds(KEEP_SESSION_SLEEP_SECOND));
281     }
282 }
283 
StopThread(std::thread & keepSessionThread,std::atomic<bool> & sendHeart)284 void StopThread(std::thread& keepSessionThread, std::atomic<bool>& sendHeart)
285 {
286     sendHeart = false;
287     g_keepSessionCv.notify_one();
288     if (keepSessionThread.joinable()) {
289         keepSessionThread.join();
290     }
291 }
292 
DoCapture(const std::string & config,const std::string & keepSecond,const std::string & outputFile)293 bool DoCapture(const std::string& config, const std::string& keepSecond, const std::string& outputFile)
294 {
295     auto profilerStub = GetProfilerServiceStub();
296     if (profilerStub == nullptr) {
297         printf("Get profiler service stub failed!\n");
298         return false;
299     }
300     if (g_exitProcessFlag) {
301         return false;
302     }
303 
304     uint32_t sessionId = CreateSession(profilerStub, config, keepSecond, outputFile);
305     if (sessionId == 0) {
306         printf("Create session returns Id 0\n");
307         return false;
308     }
309     if (g_exitProcessFlag) {
310         // session has been created, need to destroy the session.
311         return CheckDestroySession(profilerStub, sessionId);
312     }
313 
314     // start keepSessionThread, in order to ensure the sessionId is valid.
315     std::atomic<bool> sendHeart = true;
316     std::thread keepSessionThread(StartThread, std::ref(profilerStub), std::ref(sessionId), std::ref(sendHeart));
317     if (g_exitProcessFlag) {
318         // session has been created and keepSessionThread has been started.
319         // need to stop keepSessionThread and destroy the session.
320         StopThread(keepSessionThread, sendHeart);
321         return CheckDestroySession(profilerStub, sessionId);
322     }
323 
324     if (!CheckStartSession(profilerStub, sessionId)) {
325         return false;
326     }
327 
328     if (!g_exitProcessFlag) {
329         // waiting for the collection time to end or signal wakeup.
330         printf("tracing %u ms....\n", g_sampleDuration);
331         std::cout.flush();
332         std::unique_lock<std::mutex> lck(g_sessionMutex);
333         g_sessionCv.wait_for(lck, std::chrono::milliseconds(g_sampleDuration));
334     }
335 
336     bool ret = false;
337     if (CheckStopSession(profilerStub, sessionId) && CheckDestroySession(profilerStub, sessionId)) {
338         ret = true;
339     }
340 
341     StopThread(keepSessionThread, sendHeart);
342     return ret;
343 }
344 
345 struct DataContext {
346     bool isGetGrpcAddr = false;
347     std::string traceKeepSecond;
348     std::string configFile;
349     std::string outputFile;
350     bool isHelp = false;
351     bool isShowPluginList = false;
352     bool isStartProcess = false;
353     bool isKillProcess = false;
354 };
355 
ParseCmdline(CommandLine & cmdLine,DataContext & data)356 void ParseCmdline(CommandLine& cmdLine, DataContext& data)
357 {
358     cmdLine.AddParamSwitch("--getport", "-q", data.isGetGrpcAddr, "get grpc address");
359     cmdLine.AddParamText("--time", "-t", data.traceKeepSecond, "trace time");
360     cmdLine.AddParamText("--out", "-o", data.outputFile, "output file name");
361     cmdLine.AddParamSwitch("--help", "-h", data.isHelp, "make some help");
362     cmdLine.AddParamSwitch("--list", "-l", data.isShowPluginList, "plugin list");
363     cmdLine.AddParamSwitch("--start", "-s", data.isStartProcess, "start dependent process");
364     cmdLine.AddParamSwitch("--kill", "-k", data.isKillProcess, "kill dependent process");
365     cmdLine.AddParamText("--config", "-c", data.configFile, "start trace by config file");
366 }
367 
CheckGrpcMsgSend()368 int CheckGrpcMsgSend()
369 {
370     auto profilerStub = GetProfilerServiceStub();
371     if (profilerStub == nullptr) {
372         printf("Get profiler service stub failed!\n");
373         return -1;
374     }
375 
376     GetCapabilitiesRequest request;
377     GetCapabilitiesResponse response;
378     request.set_request_id(0);
379 
380     grpc::ClientContext context;
381     grpc::Status status = profilerStub->GetCapabilities(&context, request, &response);
382     if (!status.ok()) {
383         printf("Service not started\n");
384         return -1;
385     }
386 
387     printf("OK\n");
388     printf("ip:%s\n", GetLoopbackAddress().c_str());
389     printf("port:%u\n", GetServicePort());
390     return 0;
391 }
392 
StartDependentProcess()393 bool StartDependentProcess()
394 {
395     constexpr int waitProcMills = 300;
396     OHOS::system::SetParameter("hiviewdfx.hiprofiler.memprofiler.start", "0");
397     std::this_thread::sleep_for(std::chrono::milliseconds(waitProcMills));
398     if (getuid() == 0) {
399         if (!COMMON::IsProcessExist(HIPROFILERD_NAME, g_hiprofilerdPid)) {
400             // need start hiprofilerd
401             std::vector<char*> argvVec;
402             argvVec.push_back(const_cast<char*>(HIPROFILERD_NAME.c_str()));
403             g_hiprofilerdPid = COMMON::StartProcess(HIPROFILERD_NAME, argvVec);
404             // Wait for the hiprofilerd to start
405             std::this_thread::sleep_for(std::chrono::milliseconds(waitProcMills));
406         }
407 
408         if (!COMMON::IsProcessExist(HIPROFILER_PLUGINS_NAME, g_hiprofilerPluginsPid)) {
409             // need start hiprofiler_plugins
410             std::vector<char*> argvVec;
411             argvVec.push_back(const_cast<char*>(HIPROFILER_PLUGINS_NAME.c_str()));
412             g_hiprofilerPluginsPid = COMMON::StartProcess(HIPROFILER_PLUGINS_NAME, argvVec);
413             // Wait for the hiprofiler_plugins add preset plugin
414             std::this_thread::sleep_for(std::chrono::milliseconds(waitProcMills));
415         }
416 
417         if (!COMMON::IsProcessExist(NATIVE_DAEMON_NAME, g_nativeDaemonPid)) {
418             // need start native_daemon
419             std::vector<char*> argvVec;
420             argvVec.push_back(const_cast<char*>(NATIVE_DAEMON_NAME.c_str()));
421             g_nativeDaemonPid = COMMON::StartProcess(NATIVE_DAEMON_NAME, argvVec);
422             // Wait for the native_daemon to start
423             std::this_thread::sleep_for(std::chrono::milliseconds(waitProcMills));
424         }
425     } else {
426         OHOS::system::SetParameter("hiviewdfx.hiprofiler.profilerd.start", "0");
427         OHOS::system::SetParameter("hiviewdfx.hiprofiler.plugins.start", "0");
428         OHOS::system::SetParameter("hiviewdfx.hiprofiler.native_memoryd.start", "0");
429 
430         OHOS::system::SetParameter("hiviewdfx.hiprofiler.profilerd.start", "1");
431         std::this_thread::sleep_for(std::chrono::milliseconds(waitProcMills));
432         OHOS::system::SetParameter("hiviewdfx.hiprofiler.plugins.start", "1");
433         std::this_thread::sleep_for(std::chrono::milliseconds(waitProcMills));
434         OHOS::system::SetParameter("hiviewdfx.hiprofiler.native_memoryd.start", "1");
435         std::this_thread::sleep_for(std::chrono::milliseconds(waitProcMills));
436     }
437 
438     std::string content = "";
439     GetCapabilities(content, true);
440     if (content == "") {
441         printf("Please confirm whether the plugin exists\n");
442         return false;
443     }
444 
445     return true;
446 }
447 
CheckProcessExit(const std::string & processName,int & pid)448 bool CheckProcessExit(const std::string& processName, int& pid)
449 {
450     int nCount = 5; // 5: try 5 times
451     constexpr int waitExitMills = 1000;
452     while (nCount > 0) {
453         if (COMMON::IsProcessExist(processName, pid)) {
454             nCount--;
455             std::this_thread::sleep_for(std::chrono::milliseconds(waitExitMills));
456         } else {
457             break;
458         }
459     }
460     return nCount > 0;
461 }
462 
KillDependentProcess()463 void KillDependentProcess()
464 {
465     constexpr int waitProcMills = 300;
466     OHOS::system::SetParameter("hiviewdfx.hiprofiler.memprofiler.start", "0");
467     std::this_thread::sleep_for(std::chrono::milliseconds(waitProcMills));
468     if (getuid() == 0) {
469         // if pid is equal to -1, need to get pid first.
470         if (g_nativeDaemonPid == -1) {
471             COMMON::IsProcessExist(NATIVE_DAEMON_NAME, g_nativeDaemonPid);
472         }
473         if (g_hiprofilerPluginsPid == -1) {
474             COMMON::IsProcessExist(HIPROFILER_PLUGINS_NAME, g_hiprofilerPluginsPid);
475         }
476         if (g_hiprofilerdPid == -1) {
477             COMMON::IsProcessExist(HIPROFILERD_NAME, g_hiprofilerdPid);
478         }
479         COMMON::KillProcess(g_nativeDaemonPid);
480         if (CheckProcessExit(NATIVE_DAEMON_NAME, g_nativeDaemonPid)) {
481             printf("process native_daemon exits successfully\n");
482         } else {
483             printf("process native_daemon exits failed\n");
484         }
485         COMMON::KillProcess(g_hiprofilerPluginsPid);
486         if (CheckProcessExit(HIPROFILER_PLUGINS_NAME, g_hiprofilerPluginsPid)) {
487             printf("process hiprofiler_plugins exits successfully\n");
488         } else {
489             printf("process hiprofiler_plugins exits failed\n");
490         }
491         COMMON::KillProcess(g_hiprofilerdPid);
492         if (CheckProcessExit(HIPROFILERD_NAME, g_hiprofilerdPid)) {
493             printf("process hiprofilerd exits successfully\n");
494         } else {
495             printf("process hiprofilerd exits failed\n");
496         }
497     } else {
498         OHOS::system::SetParameter("hiviewdfx.hiprofiler.profilerd.start", "0");
499         OHOS::system::SetParameter("hiviewdfx.hiprofiler.plugins.start", "0");
500         OHOS::system::SetParameter("hiviewdfx.hiprofiler.native_memoryd.start", "0");
501     }
502 }
503 
ParseConfig(const std::string & configFile,std::string & config)504 bool ParseConfig(const std::string& configFile, std::string& config)
505 {
506     std::string configFileWithPath = configFile;
507     if (configFile.find('/') == std::string::npos) {
508         std::string path("/data/local/tmp/");
509         configFileWithPath = path + configFile; // add default path
510     }
511 
512     printf("Read config from %s\n", configFileWithPath.c_str());
513     std::vector<std::string> validPaths = { "/data/local/tmp/" };
514     if (!COMMON::ReadFile(configFileWithPath, validPaths, config)) {
515         printf("Read %s fail, please place it under \'/data/local/tmp/\'.\n", configFile.c_str());
516         return false;
517     }
518     config = ParsePluginConfig::GetInstance().GetPluginsConfig(config);
519     if (config.empty()) {
520         printf("Error config file: %s\n", configFileWithPath.c_str()); // no config in command or config file
521         return false;
522     }
523     return true;
524 }
525 
SignalHandler(int signal)526 void SignalHandler(int signal)
527 {
528     if (signal == SIGINT) {
529         g_exitProcessFlag = true;
530         std::async(&std::condition_variable::notify_one, &g_sessionCv);
531     }
532 }
533 } // namespace
534 
main(int argc,char * argv[])535 int main(int argc, char* argv[])
536 {
537     if (!COMMON::GetDeveloperMode()) {
538         return -1;
539     }
540     signal(SIGINT, SignalHandler);
541 
542     std::string config = "";
543     while (true) {
544         struct option long_options[] = {
545             {"getport", no_argument, nullptr, 'q'},
546             {"time", required_argument, nullptr, 't'},
547             {"out", required_argument, nullptr, 'o'},
548             {"help", no_argument, nullptr, 'h'},
549             {"list", no_argument, nullptr, 'l'},
550             {"start", no_argument,  nullptr, 's'},
551             {"kill", no_argument,  nullptr, 'k'},
552             {"config", required_argument, nullptr, 'c'},
553             {nullptr, 0, nullptr, 0}
554         };
555         int option = getopt_long(argc, argv, "c:t:o:qhlsk", long_options, nullptr);
556         if (option == -1) {
557             break;  // CONFIG.
558         }
559 
560         if (option == 'c' && strcmp(optarg, "-") == 0) {
561             std::string content;
562             std::istreambuf_iterator<char> begin(std::cin);
563             std::istreambuf_iterator<char> end = {};
564             content.assign(begin, end);
565             config = ParsePluginConfig::GetInstance().GetPluginsConfig(content);
566             if (config.empty()) {
567                 printf("Please check the configuration!\n");
568                 return -1;
569             }
570         }
571     }
572 
573     DataContext data;
574     CommandLine& cmdLine = CommandLine::GetInstance();
575     ParseCmdline(cmdLine, data);
576 
577     std::vector<std::string> argvVector;
578     for (int i = 0; i < argc; i++) {
579         if (((i + 1) < argc) && (strcmp(argv[i], "-c") == 0 || strcmp(argv[i], "--config") == 0) &&
580             (strcmp(argv[i + 1], "-") == 0)) {
581             i++;
582         } else {
583             argvVector.push_back(argv[i]);
584         }
585     }
586     if (argc < 1 || cmdLine.AnalyzeParam(argvVector) < 0 || data.isHelp) {
587         cmdLine.PrintHelp();
588         exit(0);
589     }
590 
591     // need to delete old file.
592     remove(data.outputFile.c_str());
593 
594     if (config.empty() && !data.configFile.empty()) {
595         if (!ParseConfig(data.configFile, config)) {
596             return -1;
597         }
598     }
599 
600     if (data.isStartProcess) {
601         if (!StartDependentProcess()) {
602             if (data.isKillProcess) {
603                 KillDependentProcess();
604             }
605             return 0;
606         }
607     }
608 
609     if (data.isGetGrpcAddr) { // handle get port
610         int ret = CheckGrpcMsgSend();
611         if (data.isKillProcess) {
612             KillDependentProcess();
613         }
614         return ret;
615     }
616 
617     if (data.isShowPluginList) { // handle show plugin list
618         std::string content = "";
619         GetCapabilities(content, false);
620         if (data.isKillProcess) {
621             KillDependentProcess();
622         }
623         return 0;
624     }
625 
626     if (config.empty()) { // normal case
627         if (data.isKillProcess) {
628             KillDependentProcess();
629             return 1;
630         }
631         if (!data.isStartProcess) {
632             printf("config file argument must sepcified!\n");
633         }
634         return 1;
635     }
636     // do capture work
637     if (DoCapture(config, data.traceKeepSecond, data.outputFile)) {
638         printf("DONE\n");
639     }
640 
641     if (data.isKillProcess) {
642         KillDependentProcess();
643     }
644     return 0;
645 }
646