Skip to content

Commit be683a5

Browse files
committed
libbpf-tools/biotop: Add --output for Line Protocol metrics
Add --output option to biotop to print system call metrics in Line Protocol format for time-series analysis. Include biotop_example.txt with usage, examples, and visualization guide for tools like InfluxDB and Grafana. Add images for I/O and Latency modes.
1 parent 7e4fb55 commit be683a5

File tree

5 files changed

+154
-12
lines changed

5 files changed

+154
-12
lines changed

libbpf-tools/biotop.c

Lines changed: 79 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131
#define warn(...) fprintf(stderr, __VA_ARGS__)
3232
#define OUTPUT_ROWS_LIMIT 10240
3333

34+
#define OPT_OUTPUT 1 /* --output */
35+
3436
enum SORT {
3537
ALL,
3638
IO,
@@ -50,6 +52,11 @@ struct vector {
5052
void **elems;
5153
};
5254

55+
struct data_t {
56+
struct info_t key;
57+
struct val_t value;
58+
};
59+
5360
int grow_vector(struct vector *vector) {
5461
if (vector->nr >= vector->capacity) {
5562
void **reallocated;
@@ -87,6 +94,8 @@ static int interval = 1;
8794
static int count = 99999999;
8895
static pid_t target_pid = 0;
8996
static bool verbose = false;
97+
enum output_format output = 0;
98+
static struct data_t datas[OUTPUT_ROWS_LIMIT];
9099

91100
const char *argp_program_version = "biotop 0.1";
92101
const char *argp_program_bug_address =
@@ -107,6 +116,7 @@ static const struct argp_option opts[] = {
107116
{ "rows", 'r', "ROWS", 0, "Maximum rows to print, default 20", 0 },
108117
{ "pid", 'p', "PID", 0, "Process ID to trace", 0 },
109118
{ "verbose", 'v', NULL, 0, "Verbose debug output", 0 },
119+
{ "output", OPT_OUTPUT, "FORMAT", OPTION_ARG_OPTIONAL, "Output metrics in specified format (currently only 'line' supported)", 0 },
110120
{ NULL, 'h', NULL, OPTION_HIDDEN, "Show the full help", 0 },
111121
{},
112122
};
@@ -160,6 +170,16 @@ static error_t parse_arg(int key, char *arg, struct argp_state *state)
160170
case 'h':
161171
argp_state_help(state, stderr, ARGP_HELP_STD_HELP);
162172
break;
173+
case OPT_OUTPUT:
174+
output = FORMAT_LINE_PROTOCOL;
175+
if (arg) {
176+
if (strcmp(arg, "line") == 0)
177+
output = FORMAT_LINE_PROTOCOL;
178+
else
179+
argp_error(state, "Invalid output format: %s. "
180+
"Only 'line' is supported.", arg);
181+
}
182+
break;
163183
case ARGP_KEY_ARG:
164184
errno = 0;
165185
if (pos_args == 0) {
@@ -198,11 +218,6 @@ static void sig_int(int signo)
198218
exiting = 1;
199219
}
200220

201-
struct data_t {
202-
struct info_t key;
203-
struct val_t value;
204-
};
205-
206221
static int sort_column(const void *obj1, const void *obj2)
207222
{
208223
struct data_t *d1 = (struct data_t *) obj1;
@@ -299,13 +314,58 @@ static int read_stat(struct biotop_bpf *obj, struct data_t *datas, __u32 *count)
299314
return 0;
300315
}
301316

317+
static int print_metrics(struct biotop_bpf *obj)
318+
{
319+
int i, err = 0, rows = OUTPUT_ROWS_LIMIT;
320+
time_t ts = time(NULL);
321+
struct metric m = {
322+
.name = "biotop",
323+
.tags = {{ "pid", "" }},
324+
.nr_tags = 1,
325+
.fields = {
326+
{ "I/O", 0 },
327+
{ "Kbytes", 0},
328+
{ "AVGms", 0}
329+
},
330+
.nr_fields = 3,
331+
.ts = ts
332+
};
333+
334+
err = read_stat(obj, datas, (__u32*) &rows);
335+
if (err) {
336+
fprintf(stderr, "read stat failed: %s\n", strerror(errno));
337+
return err;
338+
}
339+
340+
for (i = 0; i < rows; i++) {
341+
struct info_t *key = &datas[i].key;
342+
struct val_t *value = &datas[i].value;
343+
float avg_ms = 0;
344+
345+
/* Tag */
346+
snprintf(m.tags[0].value, sizeof(m.tags[0].value), "%u", key->pid);
347+
348+
/* To avoid floating point exception. */
349+
if (value->io)
350+
avg_ms = ((float) value->us) / 1000 / value->io;
351+
352+
/* Fields */
353+
m.fields[0].value = value->io;
354+
m.fields[1].value = value->bytes;
355+
m.fields[2].value = avg_ms;
356+
357+
print_metric(&m, output);
358+
}
359+
360+
return 0;
361+
}
362+
302363
static int print_stat(struct biotop_bpf *obj)
303364
{
304365
FILE *f;
305366
time_t t;
306367
struct tm *tm;
307368
char ts[16], buf[256];
308-
static struct data_t datas[OUTPUT_ROWS_LIMIT];
309369
int n, i, err = 0, rows = OUTPUT_ROWS_LIMIT;
310370

311371
f = fopen("/proc/loadavg", "r");
@@ -319,6 +379,7 @@ static int print_stat(struct biotop_bpf *obj)
319379
printf("%8s loadavg: %s\n", ts, buf);
320380
fclose(f);
321381
}
382+
322383
printf("%-7s %-16s %1s %-3s %-3s %-8s %5s %7s %6s\n",
323384
"PID", "COMM", "D", "MAJ", "MIN", "DISK", "I/O", "Kbytes", "AVGms");
324385

@@ -448,15 +509,21 @@ int main(int argc, char **argv)
448509
while (1) {
449510
sleep(interval);
450511

451-
if (clear_screen) {
452-
err = system("clear");
512+
if (output) {
513+
err = print_metrics(obj);
453514
if (err)
454515
goto cleanup;
455-
}
516+
} else {
517+
if (clear_screen) {
518+
err = system("clear");
519+
if (err)
520+
goto cleanup;
521+
}
456522

457-
err = print_stat(obj);
458-
if (err)
459-
goto cleanup;
523+
err = print_stat(obj);
524+
if (err)
525+
goto cleanup;
526+
}
460527

461528
count--;
462529
if (exiting || !count)

tools/biotop_example.txt

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,81 @@ This shows another "dd" command reading from xvda1. On this system, various
163163
creating and updating "status" files).
164164

165165

166+
Output Metrics in Line Protocol
167+
-------------------------------
168+
169+
The `--output` option enables `biotop` to output metrics in InfluxDB Line
170+
Protocol format, a text-based format for writing data points to time-series
171+
databases like InfluxDB. This is useful for tracking I/O operations, kilobytes
172+
transferred, and average latency per process ID (PID) for monitoring systems.
173+
174+
Usage
175+
-----
176+
Use `--output` to switch to Line Protocol output.
177+
178+
Example Output
179+
--------------
180+
Running `biotop --output` might produce:
181+
biotop,pid=279 I/O=6,Kbytes=69632,AVGms=0 1745473912
182+
biotop,pid=0 I/O=9,Kbytes=0,AVGms=94 1745473912
183+
biotop,pid=1585 I/O=14,Kbytes=94208,AVGms=1 1745473912
184+
185+
This format is easy to save to files or process with scripts and databases to
186+
monitor I/O activity over time.
187+
188+
Using the Output with InfluxDB and Grafana
189+
------------------------------------------
190+
191+
The Line Protocol output can be stored in InfluxDB and visualized in Grafana,
192+
similar to how folded stacks from `profile` are turned into flame graphs.
193+
Here's how:
194+
195+
1. Storing in InfluxDB
196+
Pipe the output into InfluxDB using the `influx` CLI. For example:
197+
198+
# biotop --output > biotop_metrics.txt
199+
influx write -b mybucket -f biotop_metrics.txt -p s
200+
201+
For real-time ingestion:
202+
# unbuffer biotop --output | influx write -b mybucket -p s
203+
204+
Note: The -p s option specifies second-precision timestamps.
205+
206+
2. Visualizing Metrics
207+
Once stored in InfluxDB, query the `biotop` measurement in Grafana to create
208+
time-series graphs. Here are some examples:
209+
210+
2.1) I/O Operations per PID
211+
Command: `biotop --output`
212+
Shows I/O operations per process ID as a time-series graph, useful for finding
213+
processes with high I/O activity.
214+
See: bcc/tools/images/biotop_io.png
215+
Query:
216+
from(bucket: "mybucket")
217+
|> range(start: v.timeRangeStart, stop: v.timeRangeStop)
218+
|> filter(fn: (r) => r._measurement == "biotop" and r._field == "I/O")
219+
220+
2.2) Latency per PID
221+
Command: `biotop --output`
222+
Shows average I/O latency per process ID in milliseconds, helping identify
223+
processes with high I/O delays.
224+
See: bcc/tools/images/biotop_latency.png
225+
Query:
226+
from(bucket: "mybucket")
227+
|> range(start: v.timeRangeStart, stop: v.timeRangeStop)
228+
|> filter(fn: (r) => r._measurement == "biotop" and r._field == "AVGms")
229+
230+
2.3) Combined I/O Metrics Dashboard
231+
Command: `biotop --output`
232+
Displays I/O operations, kilobytes transferred, and average latency per process
233+
ID in a single Grafana dashboard, providing a comprehensive view of I/O activity
234+
for real-time monitoring and trend analysis.
235+
See: bcc/tools/images/biotops.png
236+
237+
These graphs can be added to a Grafana dashboard to monitor I/O activity in
238+
real-time or analyze trends.
239+
240+
166241
USAGE message:
167242

168243
# ./biotop.py -h

tools/images/biotop_io.png

92.3 KB
Loading

tools/images/biotop_latency.png

138 KB
Loading

tools/images/biotops.png

206 KB
Loading

0 commit comments

Comments
 (0)