|
16 | 16 | #include "util/synthetic-events.h"
|
17 | 17 | #include "util/target.h"
|
18 | 18 | #include "util/time-utils.h"
|
| 19 | +#include "util/cgroup.h" |
19 | 20 | #include <linux/bitops.h>
|
20 | 21 | #include <linux/kernel.h>
|
21 | 22 | #include <linux/string.h>
|
@@ -414,6 +415,127 @@ int perf_event__synthesize_mmap_events(struct perf_tool *tool,
|
414 | 415 | return rc;
|
415 | 416 | }
|
416 | 417 |
|
| 418 | +#ifdef HAVE_FILE_HANDLE |
| 419 | +static int perf_event__synthesize_cgroup(struct perf_tool *tool, |
| 420 | + union perf_event *event, |
| 421 | + char *path, size_t mount_len, |
| 422 | + perf_event__handler_t process, |
| 423 | + struct machine *machine) |
| 424 | +{ |
| 425 | + size_t event_size = sizeof(event->cgroup) - sizeof(event->cgroup.path); |
| 426 | + size_t path_len = strlen(path) - mount_len + 1; |
| 427 | + struct { |
| 428 | + struct file_handle fh; |
| 429 | + uint64_t cgroup_id; |
| 430 | + } handle; |
| 431 | + int mount_id; |
| 432 | + |
| 433 | + while (path_len % sizeof(u64)) |
| 434 | + path[mount_len + path_len++] = '\0'; |
| 435 | + |
| 436 | + memset(&event->cgroup, 0, event_size); |
| 437 | + |
| 438 | + event->cgroup.header.type = PERF_RECORD_CGROUP; |
| 439 | + event->cgroup.header.size = event_size + path_len + machine->id_hdr_size; |
| 440 | + |
| 441 | + handle.fh.handle_bytes = sizeof(handle.cgroup_id); |
| 442 | + if (name_to_handle_at(AT_FDCWD, path, &handle.fh, &mount_id, 0) < 0) { |
| 443 | + pr_debug("stat failed: %s\n", path); |
| 444 | + return -1; |
| 445 | + } |
| 446 | + |
| 447 | + event->cgroup.id = handle.cgroup_id; |
| 448 | + strncpy(event->cgroup.path, path + mount_len, path_len); |
| 449 | + memset(event->cgroup.path + path_len, 0, machine->id_hdr_size); |
| 450 | + |
| 451 | + if (perf_tool__process_synth_event(tool, event, machine, process) < 0) { |
| 452 | + pr_debug("process synth event failed\n"); |
| 453 | + return -1; |
| 454 | + } |
| 455 | + |
| 456 | + return 0; |
| 457 | +} |
| 458 | + |
| 459 | +static int perf_event__walk_cgroup_tree(struct perf_tool *tool, |
| 460 | + union perf_event *event, |
| 461 | + char *path, size_t mount_len, |
| 462 | + perf_event__handler_t process, |
| 463 | + struct machine *machine) |
| 464 | +{ |
| 465 | + size_t pos = strlen(path); |
| 466 | + DIR *d; |
| 467 | + struct dirent *dent; |
| 468 | + int ret = 0; |
| 469 | + |
| 470 | + if (perf_event__synthesize_cgroup(tool, event, path, mount_len, |
| 471 | + process, machine) < 0) |
| 472 | + return -1; |
| 473 | + |
| 474 | + d = opendir(path); |
| 475 | + if (d == NULL) { |
| 476 | + pr_debug("failed to open directory: %s\n", path); |
| 477 | + return -1; |
| 478 | + } |
| 479 | + |
| 480 | + while ((dent = readdir(d)) != NULL) { |
| 481 | + if (dent->d_type != DT_DIR) |
| 482 | + continue; |
| 483 | + if (!strcmp(dent->d_name, ".") || |
| 484 | + !strcmp(dent->d_name, "..")) |
| 485 | + continue; |
| 486 | + |
| 487 | + /* any sane path should be less than PATH_MAX */ |
| 488 | + if (strlen(path) + strlen(dent->d_name) + 1 >= PATH_MAX) |
| 489 | + continue; |
| 490 | + |
| 491 | + if (path[pos - 1] != '/') |
| 492 | + strcat(path, "/"); |
| 493 | + strcat(path, dent->d_name); |
| 494 | + |
| 495 | + ret = perf_event__walk_cgroup_tree(tool, event, path, |
| 496 | + mount_len, process, machine); |
| 497 | + if (ret < 0) |
| 498 | + break; |
| 499 | + |
| 500 | + path[pos] = '\0'; |
| 501 | + } |
| 502 | + |
| 503 | + closedir(d); |
| 504 | + return ret; |
| 505 | +} |
| 506 | + |
| 507 | +int perf_event__synthesize_cgroups(struct perf_tool *tool, |
| 508 | + perf_event__handler_t process, |
| 509 | + struct machine *machine) |
| 510 | +{ |
| 511 | + union perf_event event; |
| 512 | + char cgrp_root[PATH_MAX]; |
| 513 | + size_t mount_len; /* length of mount point in the path */ |
| 514 | + |
| 515 | + if (cgroupfs_find_mountpoint(cgrp_root, PATH_MAX, "perf_event") < 0) { |
| 516 | + pr_debug("cannot find cgroup mount point\n"); |
| 517 | + return -1; |
| 518 | + } |
| 519 | + |
| 520 | + mount_len = strlen(cgrp_root); |
| 521 | + /* make sure the path starts with a slash (after mount point) */ |
| 522 | + strcat(cgrp_root, "/"); |
| 523 | + |
| 524 | + if (perf_event__walk_cgroup_tree(tool, &event, cgrp_root, mount_len, |
| 525 | + process, machine) < 0) |
| 526 | + return -1; |
| 527 | + |
| 528 | + return 0; |
| 529 | +} |
| 530 | +#else |
| 531 | +int perf_event__synthesize_cgroups(struct perf_tool *tool __maybe_unused, |
| 532 | + perf_event__handler_t process __maybe_unused, |
| 533 | + struct machine *machine __maybe_unused) |
| 534 | +{ |
| 535 | + return -1; |
| 536 | +} |
| 537 | +#endif |
| 538 | + |
417 | 539 | int perf_event__synthesize_modules(struct perf_tool *tool, perf_event__handler_t process,
|
418 | 540 | struct machine *machine)
|
419 | 541 | {
|
|
0 commit comments