| 1 | |
| 2 | *
|
| 3 | * This program is free software; you can redistribute it and/or
|
| 4 | * modify it under the terms of version 2 of the GNU General Public
|
| 5 | * License as published by the Free Software Foundation.
|
| 6 |
|
| 7 | #include "vmlinux.h"
|
| 8 | #include <linux/version.h>
|
| 9 | #include <bpf/bpf_helpers.h>
|
| 10 | #include <bpf/bpf_tracing.h>
|
| 11 |
|
| 12 | struct start_key {
|
| 13 | dev_t dev;
|
| 14 | u32 _pad;
|
| 15 | sector_t sector;
|
| 16 | };
|
| 17 |
|
| 18 | struct {
|
| 19 | __uint(type, BPF_MAP_TYPE_HASH);
|
| 20 | __type(key, long);
|
| 21 | __type(value, u64);
|
| 22 | __uint(max_entries, 4096);
|
| 23 | } my_map SEC(".maps");
|
| 24 |
|
| 25 |
|
| 26 | SEC("tracepoint/block/block_io_start")
|
| 27 | int bpf_prog1(struct trace_event_raw_block_rq *ctx)
|
| 28 | {
|
| 29 | u64 val = bpf_ktime_get_ns();
|
| 30 | struct start_key key = {
|
| 31 | .dev = ctx->dev,
|
| 32 | .sector = ctx->sector
|
| 33 | };
|
| 34 |
|
| 35 | bpf_map_update_elem(&my_map, &key, &val, BPF_ANY);
|
| 36 | return 0;
|
| 37 | }
|
| 38 |
|
| 39 | static unsigned int log2l(unsigned long long n)
|
| 40 | {
|
| 41 | #define S(k) if (n >= (1ull << k)) { i += k; n >>= k; }
|
| 42 | int i = -(n == 0);
|
| 43 | S(32); S(16); S(8); S(4); S(2); S(1);
|
| 44 | return i;
|
| 45 | #undef S
|
| 46 | }
|
| 47 |
|
| 48 | #define SLOTS 100
|
| 49 |
|
| 50 | struct {
|
| 51 | __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
|
| 52 | __uint(key_size, sizeof(u32));
|
| 53 | __uint(value_size, sizeof(u64));
|
| 54 | __uint(max_entries, SLOTS);
|
| 55 | } lat_map SEC(".maps");
|
| 56 |
|
| 57 |
|
| 58 | SEC("tracepoint/block/block_io_done")
|
| 59 | int bpf_prog2(struct trace_event_raw_block_rq *ctx)
|
| 60 | {
|
| 61 | struct start_key key = {
|
| 62 | .dev = ctx->dev,
|
| 63 | .sector = ctx->sector
|
| 64 | };
|
| 65 |
|
| 66 | u64 *value, l, base;
|
| 67 | u32 index;
|
| 68 |
|
| 69 | value = bpf_map_lookup_elem(&my_map, &key);
|
| 70 | if (!value)
|
| 71 | return 0;
|
| 72 |
|
| 73 | u64 cur_time = bpf_ktime_get_ns();
|
| 74 | u64 delta = cur_time - *value;
|
| 75 |
|
| 76 | bpf_map_delete_elem(&my_map, &key);
|
| 77 |
|
| 78 | |
| 79 | * using integer arithmetic
|
| 80 | * index = 29 ~ 1 usec
|
| 81 | * index = 59 ~ 1 msec
|
| 82 | * index = 89 ~ 1 sec
|
| 83 | * index = 99 ~ 10sec or more
|
| 84 | * log10(x)*10 = log2(x)*10/log2(10) = log2(x)*3
|
| 85 |
|
| 86 | l = log2l(delta);
|
| 87 | base = 1ll << l;
|
| 88 | index = (l * 64 + (delta - base) * 64 / base) * 3 / 64;
|
| 89 |
|
| 90 | if (index >= SLOTS)
|
| 91 | index = SLOTS - 1;
|
| 92 |
|
| 93 | value = bpf_map_lookup_elem(&lat_map, &index);
|
| 94 | if (value)
|
| 95 | *value += 1;
|
| 96 |
|
| 97 | return 0;
|
| 98 | }
|
| 99 | char _license[] SEC("license") = "GPL";
|
| 100 | u32 _version SEC("version") = LINUX_VERSION_CODE;
|