Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

perf daemon: Add 'ping' command

Add a 'ping' command to verify that the 'perf record' session is up and
operational.

It's used in the following patches via test code to make sure 'perf
record' is ready to receive signals.

Example:

# cat ~/.perfconfig
[daemon]
base=/opt/perfdata

[session-cycles]
run = -m 10M -e cycles --overwrite --switch-output -a

[session-sched]
run = -m 20M -e sched:* --overwrite --switch-output -a

Start the daemon:

# perf daemon start

Ping all sessions:

# perf daemon ping
OK cycles
OK sched

Ping specific session:

# perf daemon ping --session sched
OK sched

Committer notes:

Fixed up bug pointed by clang:

Buggy:

if (!pollfd.revents & POLLIN)

Correct code:

if (!(pollfd.revents & POLLIN))

clang warning:

builtin-daemon.c:560:6: error: logical not is only applied to the left hand side of this bitwise operator [-Werror,-Wlogical-not-parentheses]
if (!pollfd.revents & POLLIN) {
^ ~
builtin-daemon.c:560:6: note: add parentheses after the '!' to evaluate the bitwise operator first

Also use designated initialized with pollfd, i.e.:

struct pollfd pollfd = { .events = POLLIN, };

Instead of:

struct pollfd pollfd = { 0, };

To get past:

builtin-daemon.c:510:30: error: missing field 'events' initializer [-Werror,-Wmissing-field-initializers]
struct pollfd pollfd = { 0, };
^
1 error generated.

Signed-off-by: Jiri Olsa <jolsa@kernel.org>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Alexei Budankov <abudankov@huawei.com>
Cc: Ian Rogers <irogers@google.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Michael Petlan <mpetlan@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Link: https://lore.kernel.org/r/20210208200908.1019149-16-jolsa@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

Jiri Olsa and committed by
Arnaldo Carvalho de Melo
edcaa479 6a6d1804

+157
+9
tools/perf/Documentation/perf-daemon.txt
··· 15 15 'perf daemon start' [<options>] 16 16 'perf daemon stop' [<options>] 17 17 'perf daemon signal' [<options>] 18 + 'perf daemon ping' [<options>] 18 19 19 20 20 21 DESCRIPTION ··· 79 78 80 79 --session:: 81 80 Send signal to specific session. 81 + 82 + 83 + PING COMMAND 84 + ------------ 85 + The ping command sends control ping to configured sessions. 86 + 87 + --session:: 88 + Send ping to specific session. 82 89 83 90 84 91 CONFIG FILE
+148
tools/perf/builtin-daemon.c
··· 499 499 return 0; 500 500 } 501 501 502 + static int daemon_session__control(struct daemon_session *session, 503 + const char *msg, bool do_ack) 504 + { 505 + struct pollfd pollfd = { .events = POLLIN, }; 506 + char control_path[PATH_MAX]; 507 + char ack_path[PATH_MAX]; 508 + int control, ack = -1, len; 509 + char buf[20]; 510 + int ret = -1; 511 + ssize_t err; 512 + 513 + /* open the control file */ 514 + scnprintf(control_path, sizeof(control_path), "%s/%s", 515 + session->base, SESSION_CONTROL); 516 + 517 + control = open(control_path, O_WRONLY|O_NONBLOCK); 518 + if (!control) 519 + return -1; 520 + 521 + if (do_ack) { 522 + /* open the ack file */ 523 + scnprintf(ack_path, sizeof(ack_path), "%s/%s", 524 + session->base, SESSION_ACK); 525 + 526 + ack = open(ack_path, O_RDONLY, O_NONBLOCK); 527 + if (!ack) { 528 + close(control); 529 + return -1; 530 + } 531 + } 532 + 533 + /* write the command */ 534 + len = strlen(msg); 535 + 536 + err = writen(control, msg, len); 537 + if (err != len) { 538 + pr_err("failed: write to control pipe: %d (%s)\n", 539 + errno, control_path); 540 + goto out; 541 + } 542 + 543 + if (!do_ack) 544 + goto out; 545 + 546 + /* wait for an ack */ 547 + pollfd.fd = ack; 548 + 549 + if (!poll(&pollfd, 1, 2000)) { 550 + pr_err("failed: control ack timeout\n"); 551 + goto out; 552 + } 553 + 554 + if (!(pollfd.revents & POLLIN)) { 555 + pr_err("failed: did not received an ack\n"); 556 + goto out; 557 + } 558 + 559 + err = read(ack, buf, sizeof(buf)); 560 + if (err > 0) 561 + ret = strcmp(buf, "ack\n"); 562 + else 563 + perror("failed: read ack %d\n"); 564 + 565 + out: 566 + if (ack != -1) 567 + close(ack); 568 + 569 + close(control); 570 + return ret; 571 + } 572 + 502 573 static int setup_server_socket(struct daemon *daemon) 503 574 { 504 575 struct sockaddr_un addr; ··· 620 549 CMD_LIST = 0, 621 550 CMD_SIGNAL = 1, 622 551 CMD_STOP = 2, 552 + CMD_PING = 3, 623 553 CMD_MAX, 624 554 }; 625 555 ··· 642 570 int sig; 643 571 char name[SESSION_MAX]; 644 572 } signal; 573 + 574 + /* CMD_PING */ 575 + struct { 576 + int cmd; 577 + char name[SESSION_MAX]; 578 + } ping; 645 579 }; 580 + 581 + enum { 582 + PING_OK = 0, 583 + PING_FAIL = 1, 584 + PING_MAX, 585 + }; 586 + 587 + static int daemon_session__ping(struct daemon_session *session) 588 + { 589 + return daemon_session__control(session, "ping", true) ? PING_FAIL : PING_OK; 590 + } 646 591 647 592 static int cmd_session_list(struct daemon *daemon, union cmd *cmd, FILE *out) 648 593 { ··· 757 668 return 0; 758 669 } 759 670 671 + static const char *ping_str[PING_MAX] = { 672 + [PING_OK] = "OK", 673 + [PING_FAIL] = "FAIL", 674 + }; 675 + 676 + static int cmd_session_ping(struct daemon *daemon, union cmd *cmd, FILE *out) 677 + { 678 + struct daemon_session *session; 679 + bool all = false, found = false; 680 + 681 + all = !strcmp(cmd->ping.name, "all"); 682 + 683 + list_for_each_entry(session, &daemon->sessions, list) { 684 + if (all || !strcmp(cmd->ping.name, session->name)) { 685 + int state = daemon_session__ping(session); 686 + 687 + fprintf(out, "%-4s %s\n", ping_str[state], session->name); 688 + found = true; 689 + } 690 + } 691 + 692 + if (!found && !all) { 693 + fprintf(out, "%-4s %s (not found)\n", 694 + ping_str[PING_FAIL], cmd->ping.name); 695 + } 696 + return 0; 697 + } 698 + 760 699 static int handle_server_socket(struct daemon *daemon, int sock_fd) 761 700 { 762 701 int ret = -1, fd; ··· 819 702 done = 1; 820 703 ret = 0; 821 704 pr_debug("perf daemon is exciting\n"); 705 + break; 706 + case CMD_PING: 707 + ret = cmd_session_ping(daemon, &cmd, out); 822 708 break; 823 709 default: 824 710 break; ··· 1258 1138 1259 1139 signal(SIGINT, sig_handler); 1260 1140 signal(SIGTERM, sig_handler); 1141 + signal(SIGPIPE, SIG_IGN); 1261 1142 1262 1143 while (!done && !err) { 1263 1144 err = daemon__reconfig(daemon); ··· 1398 1277 return send_cmd(daemon, &cmd); 1399 1278 } 1400 1279 1280 + static int __cmd_ping(struct daemon *daemon, struct option parent_options[], 1281 + int argc, const char **argv) 1282 + { 1283 + const char *name = "all"; 1284 + struct option ping_options[] = { 1285 + OPT_STRING(0, "session", &name, "session", 1286 + "Ping to specific session"), 1287 + OPT_PARENT(parent_options), 1288 + OPT_END() 1289 + }; 1290 + union cmd cmd = { .cmd = CMD_PING, }; 1291 + 1292 + argc = parse_options(argc, argv, ping_options, daemon_usage, 0); 1293 + if (argc) 1294 + usage_with_options(daemon_usage, ping_options); 1295 + 1296 + if (setup_config(daemon)) { 1297 + pr_err("failed: config not found\n"); 1298 + return -1; 1299 + } 1300 + 1301 + scnprintf(cmd.ping.name, sizeof(cmd.ping.name), "%s", name); 1302 + return send_cmd(daemon, &cmd); 1303 + } 1304 + 1401 1305 int cmd_daemon(int argc, const char **argv) 1402 1306 { 1403 1307 struct option daemon_options[] = { ··· 1449 1303 return __cmd_signal(&__daemon, daemon_options, argc, argv); 1450 1304 else if (!strcmp(argv[0], "stop")) 1451 1305 return __cmd_stop(&__daemon, daemon_options, argc, argv); 1306 + else if (!strcmp(argv[0], "ping")) 1307 + return __cmd_ping(&__daemon, daemon_options, argc, argv); 1452 1308 1453 1309 pr_err("failed: unknown command '%s'\n", argv[0]); 1454 1310 return -1;