File: TaskIterator.cc

package info (click to toggle)
bpfcc 0.18.0%2Bds-2
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 12,368 kB
  • sloc: ansic: 132,727; python: 36,226; cpp: 26,973; sh: 710; yacc: 525; makefile: 141; lex: 94
file content (141 lines) | stat: -rw-r--r-- 3,016 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
/*
 * Copyright (c) Facebook, Inc.
 * Licensed under the Apache License, Version 2.0 (the "License")
 *
 * Usage:
 *   ./TaskIterator
 *
 * BPF task iterator is available since linux 5.8.
 * This example shows how to dump all threads in the system with
 * bpf iterator. An example output likes below:
 *   tid     comm
 *   1       systemd
 *   2       kthreadd
 *   3       rcu_gp
 *   4       rcu_par_gp
 *   6       kworker/0:0H
 *   ...
 *   2613386 sleep
 *   2613474 GetCountersCPU6
 *   2613587 GetCountersCPU7
 *   2613621 CPUThreadPool69
 *   2613906 GetCountersCPU5
 *   2614140 GetCountersCPU2
 *   2614193 CfgrExtension56
 *   2614449 ruby-timer-thr
 *   2614529 chef-client
 *   2615122 systemd-hostnam
 *   ...
 *   2608477 sudo
 *   2608478 TaskIterator
 */

#include <unistd.h>
#include <fstream>
#include <iostream>
#include <string>

#include "bcc_version.h"
#include "BPF.h"

const std::string BPF_PROGRAM = R"(
#include <linux/bpf.h>
#include <linux/seq_file.h>
#include <linux/sched.h>

/* the structure is defined in .c file, so explicitly define
 * the structure here.
 */
struct bpf_iter__task {
  union {
    struct bpf_iter_meta *meta;
  };
  union {
    struct task_struct *task;
  };
};

struct info_t {
  int tid;
  char comm[TASK_COMM_LEN];
};

BPF_ITER(task) {
  struct seq_file *seq = ctx->meta->seq;
  struct task_struct *task = ctx->task;
  struct info_t info = {};

  if (task == (void *)0)
    return 0;

  info.tid = task->pid;
  __builtin_memcpy(&info.comm, task->comm, sizeof(info.comm));
  bpf_seq_write(seq, &info, sizeof(info));

  return 0;
}
)";

// linux/sched.h
#define TASK_COMM_LEN	16

struct info_t {
  int tid;
  char comm[TASK_COMM_LEN];
};

int main() {
  ebpf::BPF bpf;
  auto res = bpf.init(BPF_PROGRAM);
  if (res.code() != 0) {
    std::cerr << res.msg() << std::endl;
    return 1;
  }

  int prog_fd;
  res = bpf.load_func("bpf_iter__task", BPF_PROG_TYPE_TRACING, prog_fd);
  if (res.code() != 0) {
    std::cerr << res.msg() << std::endl;
    return 1;
  }

  int link_fd = bcc_iter_attach(prog_fd, NULL, 0);
  if (link_fd < 0) {
    std::cerr << "bcc_iter_attach failed: " << link_fd << std::endl;
    return 1;
  }

  int iter_fd = bcc_iter_create(link_fd);
  if (iter_fd < 0) {
    std::cerr << "bcc_iter_create failed: " << iter_fd << std::endl;
    close(link_fd);
    return 1;
  }

  // Header.
  printf("tid\tcomm\n");

  struct info_t info[20];
  int len, leftover = 0, info_size = 20 * sizeof(struct info_t);
  while ((len = read(iter_fd, (char *)info + leftover, info_size - leftover))) {
    if (len < 0) {
      if (len == -EAGAIN)
	continue;
      std::cerr << "read failed: " << len << std::endl;
      break;
    }

    int num_info = len / sizeof(struct info_t);
    for (int i = 0; i < num_info; i++) {
      printf("%d\t%s\n", info[i].tid, info[i].comm);
    }

    leftover = len % sizeof(struct info_t);
    if (num_info > 0)
      memcpy(info, (void *)&info[num_info], leftover);
  }

  close(iter_fd);
  close(link_fd);
  return 0;
}