1/* Copyright (c) 2013-2015 PLUMgrid, http://plumgrid.com 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 <linux/skbuff.h> 8#include <linux/netdevice.h> 9#include <linux/version.h> 10#include <uapi/linux/bpf.h> 11#include "bpf_helpers.h" 12 13struct bpf_map_def SEC("maps") my_map = { 14 .type = BPF_MAP_TYPE_HASH, 15 .key_size = sizeof(long), 16 .value_size = sizeof(u64), 17 .max_entries = 4096, 18}; 19 20/* kprobe is NOT a stable ABI. If kernel internals change this bpf+kprobe 21 * example will no longer be meaningful 22 */ 23SEC("kprobe/blk_mq_start_request") 24int bpf_prog1(struct pt_regs *ctx) 25{ 26 long rq = ctx->di; 27 u64 val = bpf_ktime_get_ns(); 28 29 bpf_map_update_elem(&my_map, &rq, &val, BPF_ANY); 30 return 0; 31} 32 33static unsigned int log2l(unsigned long long n) 34{ 35#define S(k) if (n >= (1ull << k)) { i += k; n >>= k; } 36 int i = -(n == 0); 37 S(32); S(16); S(8); S(4); S(2); S(1); 38 return i; 39#undef S 40} 41 42#define SLOTS 100 43 44struct bpf_map_def SEC("maps") lat_map = { 45 .type = BPF_MAP_TYPE_ARRAY, 46 .key_size = sizeof(u32), 47 .value_size = sizeof(u64), 48 .max_entries = SLOTS, 49}; 50 51SEC("kprobe/blk_update_request") 52int bpf_prog2(struct pt_regs *ctx) 53{ 54 long rq = ctx->di; 55 u64 *value, l, base; 56 u32 index; 57 58 value = bpf_map_lookup_elem(&my_map, &rq); 59 if (!value) 60 return 0; 61 62 u64 cur_time = bpf_ktime_get_ns(); 63 u64 delta = cur_time - *value; 64 65 bpf_map_delete_elem(&my_map, &rq); 66 67 /* the lines below are computing index = log10(delta)*10 68 * using integer arithmetic 69 * index = 29 ~ 1 usec 70 * index = 59 ~ 1 msec 71 * index = 89 ~ 1 sec 72 * index = 99 ~ 10sec or more 73 * log10(x)*10 = log2(x)*10/log2(10) = log2(x)*3 74 */ 75 l = log2l(delta); 76 base = 1ll << l; 77 index = (l * 64 + (delta - base) * 64 / base) * 3 / 64; 78 79 if (index >= SLOTS) 80 index = SLOTS - 1; 81 82 value = bpf_map_lookup_elem(&lat_map, &index); 83 if (value) 84 __sync_fetch_and_add((long *)value, 1); 85 86 return 0; 87} 88char _license[] SEC("license") = "GPL"; 89u32 _version SEC("version") = LINUX_VERSION_CODE; 90