1 /*
2 * Copyright (c) 2021 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 "command_line.h"
17 #include "google/protobuf/text_format.h"
18 #include "profiler_service.grpc.pb.h"
19
20 #include <grpcpp/grpcpp.h>
21
22 #include <cinttypes>
23 #include <cstdio>
24 #include <cstring>
25 #include <fstream>
26 #include <ostream>
27 #include <vector>
28
29 #include <arpa/inet.h>
30 #include <ifaddrs.h>
31 #include <netinet/in.h>
32 #include <sys/types.h>
33 #include <unistd.h>
34
35 namespace {
36 constexpr int ADDR_BUFFER_SIZE = 128;
37 constexpr int MS_PER_S = 1000;
38 constexpr uint16_t SERVICE_PORT = 50051;
39 constexpr uint32_t US_PER_MS = 1000;
40
41 uint32_t g_sampleDuration = 0;
42
GetLoopbackAddress()43 std::string GetLoopbackAddress()
44 {
45 char addressBuffer[ADDR_BUFFER_SIZE] = "";
46 struct ifaddrs* ifAddrStruct = nullptr;
47 void* tmpAddrPtr = nullptr;
48
49 getifaddrs(&ifAddrStruct);
50 while (ifAddrStruct != nullptr) {
51 if (ifAddrStruct->ifa_addr->sa_family == AF_INET) {
52 // is a valid IP4 Address
53 tmpAddrPtr = &((reinterpret_cast<struct sockaddr_in*>(ifAddrStruct->ifa_addr))->sin_addr);
54 inet_ntop(AF_INET, tmpAddrPtr, addressBuffer, INET_ADDRSTRLEN);
55 if (strcmp(addressBuffer, "127.0.0.1") == 0) {
56 break;
57 }
58 } else if (ifAddrStruct->ifa_addr->sa_family == AF_INET6) { // check it is IP6
59 // is a valid IP6 Address
60 tmpAddrPtr = &((reinterpret_cast<struct sockaddr_in*>(ifAddrStruct->ifa_addr))->sin_addr);
61 inet_ntop(AF_INET6, tmpAddrPtr, addressBuffer, INET6_ADDRSTRLEN);
62 }
63 ifAddrStruct = ifAddrStruct->ifa_next;
64 }
65
66 freeifaddrs(ifAddrStruct);
67 return addressBuffer;
68 }
69
GetServicePort()70 uint16_t GetServicePort()
71 {
72 return SERVICE_PORT;
73 }
74
ReadFileToString(const std::string & fileName)75 std::string ReadFileToString(const std::string& fileName)
76 {
77 std::ifstream inputString(fileName, std::ios::in);
78 if (!inputString) {
79 printf("can't open %s\n", fileName.c_str());
80 return "";
81 }
82 std::string content(std::istreambuf_iterator<char>(inputString), {});
83 return content;
84 }
85
ReadConfigContent(const std::string & configFile)86 std::string ReadConfigContent(const std::string& configFile)
87 {
88 std::string content;
89 if (configFile == "-") { // Read configuration information from standard input
90 std::string line;
91 while (std::getline(std::cin, line)) {
92 content += line + "\n";
93 }
94 } else {
95 content = ReadFileToString(configFile);
96 }
97 return content;
98 }
99
MakeCreateRequest(const std::string & configFile,const std::string & keepSecond,const std::string & outputFile)100 std::unique_ptr<CreateSessionRequest> MakeCreateRequest(const std::string& configFile,
101 const std::string& keepSecond,
102 const std::string& outputFile)
103 {
104 auto request = std::make_unique<CreateSessionRequest>();
105 if (!request) {
106 return nullptr;
107 }
108
109 std::string content = ReadConfigContent(configFile);
110 if (content.empty()) {
111 printf("config file empty!");
112 return nullptr;
113 }
114 printf("================================\n");
115 printf("CONFIG: read %zu bytes from %s:\n%s", content.size(), configFile.c_str(), content.c_str());
116 if (!google::protobuf::TextFormat::ParseFromString(content, request.get())) {
117 printf("config file [%s] parse FAILED!\n", configFile.c_str());
118 return nullptr;
119 }
120
121 auto sessionConfig = request->mutable_session_config();
122 if (!sessionConfig) {
123 return nullptr;
124 }
125
126 request->set_request_id(1);
127 printf("--------------------------------\n");
128 printf("keepSecond: %s,\noutputFileName: %s\n", keepSecond.c_str(), outputFile.c_str());
129 if (!keepSecond.empty()) {
130 int ks = std::stoi(keepSecond);
131 if (ks > 0) {
132 sessionConfig->set_sample_duration(ks * MS_PER_S);
133 }
134 }
135 if (!outputFile.empty()) {
136 sessionConfig->set_result_file(outputFile);
137 }
138
139 g_sampleDuration = sessionConfig->sample_duration();
140 content.clear();
141 if (!google::protobuf::TextFormat::PrintToString(*request.get(), &content)) {
142 printf("config message format FAILED!\n");
143 return nullptr;
144 }
145 printf("--------------------------------\n");
146 printf("CONFIG: final config content:\n%s", content.c_str());
147 printf("================================\n");
148 return request;
149 }
150
GetProfilerServiceStub()151 std::unique_ptr<IProfilerService::Stub> GetProfilerServiceStub()
152 {
153 std::string serviceUri = GetLoopbackAddress() + ":" + std::to_string(GetServicePort());
154 auto grpcChannel = grpc::CreateChannel(serviceUri, grpc::InsecureChannelCredentials());
155 if (grpcChannel == nullptr) {
156 printf("FAIL\nCreate gRPC channel failed!\n");
157 return nullptr;
158 }
159 return IProfilerService::NewStub(grpcChannel);
160 }
161
CreateSession(const std::string & configFile,const std::string & keepSecond,const std::string & outputFile)162 uint32_t CreateSession(const std::string& configFile, const std::string& keepSecond, const std::string& outputFile)
163 {
164 auto profilerStub = GetProfilerServiceStub();
165 if (profilerStub == nullptr) {
166 printf("FAIL\nGet profiler service stub failed!\n");
167 return 0;
168 }
169
170 auto request = MakeCreateRequest(configFile, keepSecond, outputFile);
171 if (!request) {
172 printf("FAIL\nMakeCreateRequest failed!\n");
173 return 0;
174 }
175
176 CreateSessionResponse createResponse;
177 grpc::ClientContext createSessionContext;
178 grpc::Status status = profilerStub->CreateSession(&createSessionContext, *request, &createResponse);
179 if (!status.ok()) {
180 printf("FAIL\nCreateSession FAIL\n");
181 return 0;
182 }
183
184 return createResponse.session_id();
185 }
186
DoCapture(const std::string & configFile,const std::string & keepSecond,const std::string & outputFile)187 bool DoCapture(const std::string& configFile, const std::string& keepSecond, const std::string& outputFile)
188 {
189 uint32_t sessionId = CreateSession(configFile, keepSecond, outputFile);
190 auto profilerStub = GetProfilerServiceStub();
191 if (profilerStub == nullptr) {
192 printf("FAIL\nGet profiler service stub failed!\n");
193 return false;
194 }
195
196 StartSessionRequest startRequest;
197 StartSessionResponse startResponse;
198 startRequest.set_request_id(0);
199 startRequest.set_session_id(sessionId);
200 grpc::ClientContext startContext;
201 grpc::Status status = profilerStub->StartSession(&startContext, startRequest, &startResponse);
202 if (!status.ok()) {
203 printf("FAIL\nStartSession FAIL\n");
204 return false;
205 }
206
207 printf("tracing %u ms....\n", g_sampleDuration);
208 usleep(g_sampleDuration * US_PER_MS);
209
210 StopSessionRequest stopRequest;
211 StopSessionResponse stopResponse;
212 grpc::ClientContext stopContext;
213 stopRequest.set_session_id(sessionId);
214 status = profilerStub->StopSession(&stopContext, stopRequest, &stopResponse);
215 if (!status.ok()) {
216 printf("FAIL\nStopSession FAIL\n");
217 return false;
218 }
219 printf("StopSession done!\n");
220
221 DestroySessionRequest destroyRequest;
222 DestroySessionResponse destroyResponse;
223 grpc::ClientContext destroyContext;
224 destroyRequest.set_session_id(sessionId);
225 status = profilerStub->DestroySession(&destroyContext, destroyRequest, &destroyResponse);
226 if (!status.ok()) {
227 printf("FAIL\nDestroySession FAIL\n");
228 return false;
229 }
230 printf("DestroySession done!\n");
231 return true;
232 }
233 } // namespace
234
main(int argc,char * argv[])235 int main(int argc, char* argv[])
236 {
237 CommandLine* pCmdLine = &CommandLine::GetInstance();
238
239 bool isGetGrpcAddr = false;
240 pCmdLine->AddParamSwitch("--getport", "-q", isGetGrpcAddr, "get grpc address");
241
242 std::string configFile;
243 pCmdLine->AddParamText("--config", "-c", configFile, "start trace by config file");
244
245 std::string traceKeepSecond;
246 pCmdLine->AddParamText("--time", "-t", traceKeepSecond, "trace time");
247
248 std::string outputFile;
249 pCmdLine->AddParamText("--out", "-o", outputFile, "output file name");
250
251 bool isHelp = false;
252 pCmdLine->AddParamSwitch("--help", "-h", isHelp, "make some help");
253
254 std::vector<std::string> argvVector;
255 for (int i = 0; i < argc; i++) {
256 argvVector.push_back(argv[i]);
257 }
258 if (argc < 1 || pCmdLine->AnalyzeParam(argvVector) < 0 || isHelp) {
259 pCmdLine->PrintHelp();
260 exit(0);
261 }
262 if (isGetGrpcAddr) { // handle get port
263 auto profilerStub = GetProfilerServiceStub();
264 if (profilerStub == nullptr) {
265 printf("FAIL\nGet profiler service stub failed!\n");
266 return -1;
267 }
268
269 GetCapabilitiesRequest request;
270 GetCapabilitiesResponse response;
271 request.set_request_id(0);
272
273 grpc::ClientContext context;
274 grpc::Status status = profilerStub->GetCapabilities(&context, request, &response);
275 if (!status.ok()) {
276 printf("FAIL\nService not started\n");
277 return -1;
278 }
279
280 printf("OK\n");
281 printf("ip:%s\n", GetLoopbackAddress().c_str());
282 printf("port:%u\n", GetServicePort());
283 return 0;
284 }
285
286 if (configFile.empty()) { // normal case
287 printf("FAIL\nconfig file argument must sepcified!");
288 return 1;
289 }
290 // do capture work
291 if (DoCapture(configFile, traceKeepSecond, outputFile)) {
292 printf("DONE\n");
293 }
294
295 return 0;
296 }
297