Apollo 10.0
自动驾驶开放平台
main.cc
浏览该文件的文档.
1/******************************************************************************
2 * Copyright 2018 The Apollo Authors. All Rights Reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *****************************************************************************/
16
17#include <getopt.h>
18#include <csignal>
19#include <cstddef>
20#include <filesystem>
21#include <memory>
22#include <stdexcept>
23#include <string>
24#include <vector>
25
27#include "cyber/common/file.h"
29#include "cyber/init.h"
35
36#include "gflags/gflags.h"
37#include "gperftools/heap-profiler.h"
38#include "gperftools/malloc_extension.h"
39#include "gperftools/profiler.h"
40
51
52const char INFO_OPTIONS[] = "h";
53const char RECORD_OPTIONS[] = "o:ac:k:i:m:hCH";
54const char PLAY_OPTIONS[] = "f:ac:k:lr:b:e:s:d:p:h";
55const char SPLIT_OPTIONS[] = "f:o:c:k:b:e:h";
56const char RECOVER_OPTIONS[] = "f:o:h";
57
58void DisplayUsage(const std::string& binary);
59void DisplayUsage(const std::string& binary, const std::string& command);
60void DisplayUsage(const std::string& binary, const std::string& command,
61 const std::string& options);
62
63void DisplayUsage(const std::string& binary) {
64 std::cout << "usage: " << binary << " <command> [<args>]\n"
65 << "The " << binary << " commands are:\n"
66 << "\tinfo\tShow information of an exist record.\n"
67 << "\tplay\tPlay an exist record.\n"
68 << "\trecord\tRecord same topic.\n"
69 << "\tsplit\tSplit an exist record.\n"
70 << "\trecover\tRecover an exist record.\n"
71 << std::endl;
72}
73
74void DisplayUsage(const std::string& binary, const std::string& command) {
75 if (command == "info") {
76 std::cout << "usage: cyber_recorder info file" << std::endl;
77 std::cout << "usage: " << binary << " " << command << " [options]"
78 << std::endl;
79 DisplayUsage(binary, command, INFO_OPTIONS);
80 return;
81 }
82
83 std::cout << "usage: " << binary << " " << command << " [options]"
84 << std::endl;
85 if (command == "record") {
86 DisplayUsage(binary, command, RECORD_OPTIONS);
87 } else if (command == "play") {
88 DisplayUsage(binary, command, PLAY_OPTIONS);
89 } else if (command == "split") {
90 DisplayUsage(binary, command, SPLIT_OPTIONS);
91 } else if (command == "recover") {
92 DisplayUsage(binary, command, RECOVER_OPTIONS);
93 } else {
94 std::cout << "Unknown command: " << command << std::endl;
95 DisplayUsage(binary);
96 }
97}
98
99void DisplayUsage(const std::string& binary, const std::string& command,
100 const std::string& options) {
101 for (char option : options) {
102 switch (option) {
103 case 'f':
104 std::cout << "\t-f, --file <file>\t\t\tinput record file" << std::endl;
105 break;
106 case 'o':
107 std::cout << "\t-o, --output <file>\t\t\toutput record file"
108 << std::endl;
109 break;
110 case 'a':
111 std::cout << "\t-a, --all\t\t\t\t" << command << " all" << std::endl;
112 break;
113 case 'c':
114 std::cout << "\t-c, --white-channel <name>\t\tonly " << command
115 << " the specified channel" << std::endl;
116 break;
117 case 'k':
118 std::cout << "\t-k, --black-channel <name>\t\tnot " << command
119 << " the specified channel" << std::endl;
120 break;
121 case 'l':
122 std::cout << "\t-l, --loop\t\t\t\tloop " << command << std::endl;
123 break;
124 case 'r':
125 std::cout << "\t-r, --rate <1.0>\t\t\tmultiply the " << command
126 << " rate by FACTOR" << std::endl;
127 break;
128 case 'b':
129 std::cout << "\t-b, --begin 2018-07-01-00:00:00\t" << command
130 << " the record begin at" << std::endl;
131 break;
132 case 'e':
133 std::cout << "\t-e, --end 2018-07-01-00:01:00\t\t" << command
134 << " the record end at" << std::endl;
135 break;
136 case 's':
137 std::cout << "\t-s, --start <seconds>\t\t\t" << command
138 << " started at n seconds" << std::endl;
139 break;
140 case 'd':
141 std::cout << "\t-d, --delay <seconds>\t\t\t" << command
142 << " delayed n seconds" << std::endl;
143 break;
144 case 'p':
145 std::cout << "\t-p, --preload <seconds>\t\t\t" << command
146 << " after trying to preload n second(s)" << std::endl;
147 break;
148 case 'i':
149 std::cout << "\t-i, --segment-interval <seconds>\t" << command
150 << " segmented every n second(s)" << std::endl;
151 break;
152 case 'm':
153 std::cout << "\t-m, --segment-size <MB>\t\t\t" << command
154 << " segmented every n megabyte(s)" << std::endl;
155 break;
156 case 'h':
157 std::cout << "\t-h, --help\t\t\t\tshow help message" << std::endl;
158 break;
159 case 'H':
160 std::cout << "\t-H, --heap-profule\t\t\t\tprofile heap info"
161 << std::endl;
162 break;
163 case 'C':
164 std::cout << "\t-C, --cpu-profule\t\t\t\tprofile cpu info" << std::endl;
165 break;
166 case ':':
167 break;
168 default:
169 std::cout << "unknown option: -" << option;
170 break;
171 }
172 }
173}
174
175int main(int argc, char** argv) {
176 std::string binary = GetFileName(std::string(argv[0]));
177 if (argc < 2) {
178 DisplayUsage(binary);
179 return -1;
180 }
181 const std::string command(argv[1]);
182 std::string file_path;
183 if (argc >= 3) {
184 file_path = std::string(argv[2]);
185 }
186
187 int long_index = 0;
188 const std::string short_opts = "f:c:k:o:alr:b:e:s:d:p:i:m:hCH";
189 static const struct option long_opts[] = {
190 {"files", required_argument, nullptr, 'f'},
191 {"white-channel", required_argument, nullptr, 'c'},
192 {"black-channel", required_argument, nullptr, 'k'},
193 {"output", required_argument, nullptr, 'o'},
194 {"all", no_argument, nullptr, 'a'},
195 {"loop", no_argument, nullptr, 'l'},
196 {"rate", required_argument, nullptr, 'r'},
197 {"begin", required_argument, nullptr, 'b'},
198 {"end", required_argument, nullptr, 'e'},
199 {"start", required_argument, nullptr, 's'},
200 {"delay", required_argument, nullptr, 'd'},
201 {"preload", required_argument, nullptr, 'p'},
202 {"segment-interval", required_argument, nullptr, 'i'},
203 {"segment-size", required_argument, nullptr, 'm'},
204 {"help", no_argument, nullptr, 'h'},
205 {"cpu-profile", no_argument, nullptr, 'C'},
206 {"heap-profule", no_argument, nullptr, 'H'}};
207
208 std::vector<std::string> opt_file_vec;
209 std::vector<std::string> opt_output_vec;
210 std::vector<std::string> opt_white_channels;
211 std::vector<std::string> opt_black_channels;
212 static bool enable_cpu_profile = false;
213 static bool enable_heap_profile = false;
214 bool opt_all = false;
215 bool opt_loop = false;
216 float opt_rate = 1.0f;
217 uint64_t opt_begin = 0;
218 uint64_t opt_end = std::numeric_limits<uint64_t>::max();
219 double opt_start = 0;
220 uint64_t opt_delay = 0;
221 uint32_t opt_preload = 3;
222 auto opt_header = HeaderBuilder::GetHeader();
223
224 do {
225 int opt =
226 getopt_long(argc, argv, short_opts.c_str(), long_opts, &long_index);
227 if (opt == -1) {
228 break;
229 }
230 switch (opt) {
231 case 'C':
232 enable_cpu_profile = true;
233 break;
234 case 'H':
235 enable_heap_profile = true;
236 break;
237 case 'f':
238 if (!apollo::cyber::common::PathIsAbsolute(std::string(optarg))) {
239 auto opt_file_abs_path =
240 apollo::cyber::common::GetEnv("PWD") + "/" + std::string(optarg);
241 if (apollo::cyber::common::PathExists(opt_file_abs_path)) {
242 opt_file_vec.emplace_back(opt_file_abs_path);
243 } else {
244 opt_file_vec.emplace_back(std::string(optarg));
245 }
246 } else {
247 opt_file_vec.emplace_back(std::string(optarg));
248 }
249 for (int i = optind; i < argc; i++) {
250 if (*argv[i] != '-') {
251 if (!apollo::cyber::common::PathIsAbsolute(std::string(argv[i]))) {
252 auto opt_file_abs_path = apollo::cyber::common::GetEnv("PWD") +
253 "/" + std::string(argv[i]);
254 if (apollo::cyber::common::PathExists(opt_file_abs_path)) {
255 opt_file_vec.emplace_back(opt_file_abs_path);
256 } else {
257 opt_file_vec.emplace_back(std::string(argv[i]));
258 }
259 } else {
260 opt_file_vec.emplace_back(std::string(argv[i]));
261 }
262 } else {
263 break;
264 }
265 }
266 break;
267 case 'c':
268 opt_white_channels.emplace_back(std::string(optarg));
269 for (int i = optind; i < argc; i++) {
270 if (*argv[i] != '-') {
271 opt_white_channels.emplace_back(std::string(argv[i]));
272 } else {
273 break;
274 }
275 }
276 break;
277 case 'k':
278 opt_black_channels.emplace_back(std::string(optarg));
279 for (int i = optind; i < argc; i++) {
280 if (*argv[i] != '-') {
281 opt_black_channels.emplace_back(std::string(argv[i]));
282 } else {
283 break;
284 }
285 }
286 break;
287 case 'o':
288 if (!apollo::cyber::common::PathIsAbsolute(std::string(optarg))) {
289 auto opt_output_file_abs_path =
290 apollo::cyber::common::GetEnv("PWD") + "/" + std::string(optarg);
291 opt_output_vec.push_back(opt_output_file_abs_path);
292 } else {
293 opt_output_vec.push_back(std::string(optarg));
294 }
295 break;
296 case 'a':
297 opt_all = true;
298 break;
299 case 'l':
300 opt_loop = true;
301 break;
302 case 'r':
303 try {
304 opt_rate = std::stof(optarg);
305 } catch (const std::invalid_argument& ia) {
306 std::cout << "Invalid argument: -r/--rate " << std::string(optarg)
307 << std::endl;
308 return -1;
309 } catch (const std::out_of_range& e) {
310 std::cout << "Argument is out of range: -r/--rate "
311 << std::string(optarg) << std::endl;
312 return -1;
313 }
314 break;
315 case 'b':
316 opt_begin =
317 StringToUnixSeconds(std::string(optarg)) * 1000 * 1000 * 1000ULL;
318 break;
319 case 'e':
320 opt_end =
321 StringToUnixSeconds(std::string(optarg)) * 1000 * 1000 * 1000ULL;
322 break;
323 case 's':
324 try {
325 opt_start = std::stod(optarg);
326 } catch (const std::invalid_argument& ia) {
327 std::cout << "Invalid argument: -s/--start " << std::string(optarg)
328 << std::endl;
329 return -1;
330 } catch (const std::out_of_range& e) {
331 std::cout << "Argument is out of range: -s/--start "
332 << std::string(optarg) << std::endl;
333 return -1;
334 }
335 break;
336 case 'd':
337 try {
338 opt_delay = std::stoi(optarg);
339 } catch (std::invalid_argument& ia) {
340 std::cout << "Invalid argument: -d/--delay " << std::string(optarg)
341 << std::endl;
342 return -1;
343 } catch (const std::out_of_range& e) {
344 std::cout << "Argument is out of range: -d/--delay "
345 << std::string(optarg) << std::endl;
346 return -1;
347 }
348 break;
349 case 'p':
350 try {
351 opt_preload = std::stoi(optarg);
352 } catch (std::invalid_argument& ia) {
353 std::cout << "Invalid argument: -p/--preload " << std::string(optarg)
354 << std::endl;
355 return -1;
356 } catch (const std::out_of_range& e) {
357 std::cout << "Argument is out of range: -p/--preload "
358 << std::string(optarg) << std::endl;
359 return -1;
360 }
361 break;
362 case 'i':
363 try {
364 int interval_s = std::stoi(optarg);
365 if (interval_s < 0) {
366 std::cout << "Argument is less than zero: -i/--segment-interval "
367 << std::string(optarg) << std::endl;
368 return -1;
369 }
370 opt_header.set_segment_interval(interval_s * 1000000000ULL);
371 } catch (std::invalid_argument& ia) {
372 std::cout << "Invalid argument: -i/--segment-interval "
373 << std::string(optarg) << std::endl;
374 return -1;
375 } catch (const std::out_of_range& e) {
376 std::cout << "Argument is out of range: -i/--segment-interval "
377 << std::string(optarg) << std::endl;
378 return -1;
379 }
380 break;
381 case 'm':
382 try {
383 int size_mb = std::stoi(optarg);
384 if (size_mb < 0) {
385 std::cout << "Argument is less than zero: -m/--segment-size "
386 << std::string(optarg) << std::endl;
387 return -1;
388 }
389 opt_header.set_segment_raw_size(size_mb * 1024 * 1024ULL);
390 } catch (std::invalid_argument& ia) {
391 std::cout << "Invalid argument: -m/--segment-size "
392 << std::string(optarg) << std::endl;
393 return -1;
394 } catch (const std::out_of_range& e) {
395 std::cout << "Argument is out of range: -m/--segment-size "
396 << std::string(optarg) << std::endl;
397 return -1;
398 }
399 break;
400 case 'h':
401 DisplayUsage(binary, command);
402 return 0;
403 default:
404 break;
405 }
406 } while (true);
407
408 // cyber_recorder info
409 if (command == "info") {
410 if (file_path.empty()) {
411 std::cout << "usage: cyber_recorder info file" << std::endl;
412 return -1;
413 }
415 auto file_path_abs =
416 apollo::cyber::common::GetEnv("PWD") + "/" + std::string(file_path);
417 if (std::filesystem::exists(file_path_abs)) {
418 file_path = file_path_abs;
419 }
420 }
421 ::apollo::cyber::Init(argv[0]);
422 Info info;
423 bool info_result = info.Display(file_path);
424 return info_result ? 0 : -1;
425 } else if (command == "recover") {
426 if (opt_file_vec.empty()) {
427 std::cout << "MUST specify file option (-f)." << std::endl;
428 return -1;
429 }
430 if (opt_file_vec.size() > 1 || opt_output_vec.size() > 1) {
431 std::cout << "TOO many input/output file option (-f/-o)." << std::endl;
432 return -1;
433 }
434 if (opt_output_vec.empty()) {
435 std::string default_output_file = opt_file_vec[0] + ".recover";
436 opt_output_vec.push_back(default_output_file);
437 }
438 ::apollo::cyber::Init(argv[0]);
439 Recoverer recoverer(opt_file_vec[0], opt_output_vec[0]);
440 bool recover_result = recoverer.Proc();
441 return recover_result ? 0 : -1;
442 }
443
444 if (command == "play") {
445 if (opt_file_vec.empty()) {
446 std::cout << "MUST specify file option (-f)." << std::endl;
447 return -1;
448 }
449 ::apollo::cyber::Init(argv[0], "cyber_recorder");
450 PlayParam play_param;
451 play_param.is_play_all_channels = opt_all || opt_white_channels.empty();
452 play_param.is_loop_playback = opt_loop;
453 play_param.play_rate = opt_rate;
454 play_param.begin_time_ns = opt_begin;
455 play_param.end_time_ns = opt_end;
456 play_param.start_time_s = opt_start;
457 play_param.delay_time_s = opt_delay;
458 play_param.preload_time_s = opt_preload;
459 play_param.files_to_play.insert(opt_file_vec.begin(), opt_file_vec.end());
460 play_param.black_channels.insert(opt_black_channels.begin(),
461 opt_black_channels.end());
462 play_param.channels_to_play.insert(opt_white_channels.begin(),
463 opt_white_channels.end());
464 Player player(play_param);
465 const bool play_result = player.Init() && player.Start();
466 return play_result ? 0 : -1;
467 } else if (command == "record") {
468 if (opt_white_channels.empty() && !opt_all) {
469 std::cout
470 << "MUST specify channels option (-c) or all channels option (-a)."
471 << std::endl;
472 return -1;
473 }
474 if (opt_output_vec.size() > 1) {
475 std::cout << "TOO many output file option (-o)." << std::endl;
476 return -1;
477 }
478 if (opt_output_vec.empty()) {
479 std::string default_output_file =
480 apollo::cyber::common::GetEnv("PWD") + "/" +
481 UnixSecondsToString(time(nullptr), "%Y%m%d%H%M%S") + ".record";
482 opt_output_vec.push_back(default_output_file);
483 }
484 ::apollo::cyber::Init(argv[0]);
485 auto recorder = std::make_shared<Recorder>(opt_output_vec[0], opt_all,
486 opt_white_channels,
487 opt_black_channels, opt_header);
488 std::signal(SIGTERM, [](int sig) {
490 if (enable_cpu_profile) {
491 ProfilerStop();
492 }
493 if (enable_heap_profile) {
494 HeapProfilerDump("Befor shutdown");
495 HeapProfilerStop();
496 }
497 });
498
499 std::signal(SIGINT, [](int sig) {
501 if (enable_cpu_profile) {
502 ProfilerStop();
503 }
504 if (enable_heap_profile) {
505 HeapProfilerDump("Befor shutdown");
506 HeapProfilerStop();
507 }
508 });
509
510 auto base_name = std::string(argv[0]) + std::string(".prof");
511 if (enable_cpu_profile) {
512 ProfilerStart(base_name.c_str());
513 }
514 if (enable_heap_profile) {
515 HeapProfilerStart(base_name.c_str());
516 }
517 bool record_result = recorder->Start();
518 if (record_result) {
519 while (!::apollo::cyber::IsShutdown()) {
520 std::this_thread::sleep_for(std::chrono::milliseconds(100));
521 }
522 record_result = recorder->Stop();
523 }
524 return record_result ? 0 : -1;
525 } else if (command == "split") {
526 if (opt_file_vec.empty()) {
527 std::cout << "Must specify file option (-f)." << std::endl;
528 return -1;
529 }
530 if (opt_file_vec.size() > 1 || opt_output_vec.size() > 1) {
531 std::cout << "Too many input/output file option (-f/-o)." << std::endl;
532 return -1;
533 }
534 if (opt_output_vec.empty()) {
535 std::string default_output_file = opt_file_vec[0] + ".split";
536 opt_output_vec.push_back(default_output_file);
537 }
538 ::apollo::cyber::Init(argv[0]);
539 Spliter spliter(opt_file_vec[0], opt_output_vec[0], opt_white_channels,
540 opt_black_channels, opt_begin, opt_end);
541 bool split_result = spliter.Proc();
542 return split_result ? 0 : -1;
543 }
544
545 // unknown command
546 DisplayUsage(binary, command);
547 return -1;
548}
The builder of record header.
static proto::Header GetHeader()
Build a default record header.
bool Display(const std::string &file)
Definition info.cc:34
int main(int argc, char **argv)
Definition main.cc:175
const char SPLIT_OPTIONS[]
Definition main.cc:55
const char PLAY_OPTIONS[]
Definition main.cc:54
const char INFO_OPTIONS[]
Definition main.cc:52
const char RECORD_OPTIONS[]
Definition main.cc:53
const char RECOVER_OPTIONS[]
Definition main.cc:56
void DisplayUsage()
bool PathExists(const std::string &path)
Check if the path exists.
Definition file.cc:195
std::string GetFileName(const std::string &path, const bool remove_extension)
Definition file.cc:415
std::string GetEnv(const std::string &var_name, const std::string &default_value="")
Definition environment.h:29
uint64_t StringToUnixSeconds(const std::string &time_str, const std::string &format_str="%Y-%m-%d %H:%M:%S")
bool PathIsAbsolute(const std::string &path)
Definition file.cc:200
std::string UnixSecondsToString(uint64_t unix_seconds, const std::string &format_str="%Y-%m-%d-%H:%M:%S")
void OnShutdown(int sig)
Definition init.cc:89
bool IsShutdown()
Definition state.h:46
bool Init(const char *binary_name, const std::string &dag_info)
Definition init.cc:98
std::set< std::string > black_channels
Definition play_param.h:41
std::set< std::string > files_to_play
Definition play_param.h:39
std::set< std::string > channels_to_play
Definition play_param.h:40