1#!/usr/bin/env python3 2# Copyright (c) PLUMgrid, Inc. 3# Licensed under the Apache License, Version 2.0 (the "License") 4 5from bcc import BPF 6from ctypes import c_int, c_ulonglong 7import random 8import time 9from unittest import main, TestCase 10 11class TestHistogram(TestCase): 12 def test_simple(self): 13 b = BPF(text=b""" 14#include <uapi/linux/ptrace.h> 15struct bpf_map; 16BPF_HISTOGRAM(hist1); 17BPF_HASH(stub); 18int kprobe__htab_map_delete_elem(struct pt_regs *ctx, struct bpf_map *map, u64 *k) { 19 hist1.increment(bpf_log2l(*k)); 20 hist1.atomic_increment(bpf_log2l(*k)); 21 return 0; 22} 23""") 24 for i in range(0, 32): 25 for j in range(0, random.randint(1, 10)): 26 try: del b[b"stub"][c_ulonglong(1 << i)] 27 except: pass 28 b[b"hist1"].print_log2_hist() 29 30 for i in range(32, 64): 31 for j in range(0, random.randint(1, 10)): 32 try: del b[b"stub"][c_ulonglong(1 << i)] 33 except: pass 34 b[b"hist1"].print_log2_hist() 35 b.cleanup() 36 37 def test_struct(self): 38 b = BPF(text=b""" 39#include <uapi/linux/ptrace.h> 40struct bpf_map; 41typedef struct { void *map; u64 slot; } Key; 42BPF_HISTOGRAM(hist1, Key, 1024); 43BPF_HASH(stub1); 44BPF_HASH(stub2); 45int kprobe__htab_map_delete_elem(struct pt_regs *ctx, struct bpf_map *map, u64 *k) { 46 hist1.increment((Key){map, bpf_log2l(*k)}); 47 hist1.atomic_increment((Key){map, bpf_log2l(*k)}); 48 return 0; 49} 50""") 51 for i in range(0, 64): 52 for j in range(0, random.randint(1, 10)): 53 try: del b[b"stub1"][c_ulonglong(1 << i)] 54 except: pass 55 try: del b[b"stub2"][c_ulonglong(1 << i)] 56 except: pass 57 b[b"hist1"].print_log2_hist() 58 b.cleanup() 59 60 def test_chars(self): 61 b = BPF(text=b""" 62#include <uapi/linux/ptrace.h> 63#include <linux/sched.h> 64#include <linux/version.h> 65typedef struct { char name[TASK_COMM_LEN]; u64 slot; } Key; 66BPF_HISTOGRAM(hist1, Key, 1024); 67int kprobe__finish_task_switch(struct pt_regs *ctx, struct task_struct *prev) { 68#if LINUX_VERSION_CODE < KERNEL_VERSION(5,5,0) 69 Key k = {.slot = bpf_log2l(prev->real_start_time)}; 70#else 71 Key k = {.slot = bpf_log2l(prev->start_boottime)}; 72#endif 73 if (!bpf_get_current_comm(&k.name, sizeof(k.name))) { 74 hist1.increment(k); 75 hist1.atomic_increment(k); 76 } 77 return 0; 78} 79""") 80 for i in range(0, 100): time.sleep(0.01) 81 b[b"hist1"].print_log2_hist() 82 b.cleanup() 83 84 def test_multiple_key(self): 85 b = BPF(text=b""" 86#include <uapi/linux/ptrace.h> 87#include <uapi/linux/fs.h> 88struct hist_s_key { 89 u64 key_1; 90 u64 key_2; 91}; 92struct hist_key { 93 struct hist_s_key s_key; 94 u64 slot; 95}; 96BPF_HISTOGRAM(mk_hist, struct hist_key, 1024); 97int kprobe__vfs_read(struct pt_regs *ctx, struct file *file, 98 char __user *buf, size_t count) { 99 struct hist_key key = {.slot = bpf_log2l(count)}; 100 key.s_key.key_1 = (unsigned long)buf & 0x70; 101 key.s_key.key_2 = (unsigned long)buf & 0x7; 102 mk_hist.increment(key); 103 return 0; 104} 105""") 106 def bucket_sort(buckets): 107 buckets.sort() 108 return buckets 109 110 for i in range(0, 100): time.sleep(0.01) 111 b[b"mk_hist"].print_log2_hist("size", "k_1 & k_2", 112 section_print_fn=lambda bucket: "%3d %d" % (bucket[0], bucket[1]), 113 bucket_fn=lambda bucket: (bucket.key_1, bucket.key_2), 114 strip_leading_zero=True, 115 bucket_sort_fn=bucket_sort) 116 b.cleanup() 117 118if __name__ == "__main__": 119 main() 120