On Mon, 8 Apr 2019 16:06:39 +0800 Qu Wenruo <quwenruo.btrfs@xxxxxxx> wrote: > Hi, > > There is the second version of btrfs tree locker analyser. > https://gist.github.com/adam900710/766767dba5381b86534c9051780ed262 > > The script is also attached to the end of mail. > > Please note that, it needs a trace event which is not yet merged. > > That patch can be find here: > https://patchwork.kernel.org/patch/10881305/ > > Unlike previous version, this version is based on trace events. > As long as we have btrfs_tree_lock() and btrfs_tree_read_lock() > events, we can using trace events to get all the needed info. > > Compared to previous in-kernel version, this one has better > resolution. For example, we have an event whose > start_ns = 100ns end_ns=200,000,000ns (200ms) interval=100ms. > > In previous in-kernel version, we will put all that 200ms latency into > the checkpoint 200ms. > > While in this version, we will put (100ms - 100ns) into checkpoint > 100ms, while another 100ms into checkpoint 200ms. > > Some test result can be found in google doc: > https://docs.google.com/spreadsheets/d/1B5ETQNMq2plIcWBgEJZ5ap6NnXcAu2A4gTogGltlq4E/edit?usp=sharing > > > The script starts below: > > #!/usr/bin/python2 > # @lint-avoid-python-3-compatibility-imports > > from __future__ import print_function > from bcc import BPF > from sys import stderr > > text_bpf = ''' > #include <uapi/linux/ptrace.h> > #define FSID_SIZE 16 > > struct data_t { > u8 fsid[FSID_SIZE]; > u64 start_ns; > u64 end_ns; > u64 owner; > }; > > BPF_PERF_OUTPUT(events); > > TRACEPOINT_PROBE(btrfs, btrfs_tree_read_lock) > { > struct data_t data; > > bpf_probe_read(data.fsid, FSID_SIZE, args->fsid); > data.start_ns = args->start_ns; > data.end_ns = args->end_ns; > data.owner = args->owner; > events.perf_submit(args, &data ,sizeof(data)); > return 0; > } > > TRACEPOINT_PROBE(btrfs, btrfs_tree_lock) > { > struct data_t data; > > bpf_probe_read(data.fsid, FSID_SIZE, args->fsid); > data.start_ns = args->start_ns; > data.end_ns = args->end_ns; > data.owner = args->owner; > events.perf_submit(args, &data ,sizeof(data)); > return 0; > } > ''' > > def is_fstree(owner): > if owner == 5 or (owner >= 256 and owner <= (2 ** 64 - 256)): > return True > return False > > # TODO: Don't use such classification while have a good idea to output > # all the needed info > def get_owner_str(owner): > if is_fstree(owner): > return 'SUBVOL' > if owner == 1: > return 'TREE_ROOT' > if owner == 2: > return 'EXTENT_ROOT' > return 'OTHER_ROOTS' > > > ''' > Sparse dict where access to hole (non-exist) key will return 0 > other than raise an exception > ''' > class sparse_dict: > data_dict = {} > def __init__(self): > self.data_dict = {} > > def __getitem__(self, key): > if key not in self.data_dict: > return 0 > return self.data_dict[key] > > def __setitem__(self, key, value): > self.data_dict[key] = value; > > def __contains__(self, key): > return (key in self.data_dict) > You can use the following for the same behaviour: from collections import defaultdict <snip> > # @results is a 2 dimension dict. > # [<aligned_timetamp>][<owner_str>] to access, no need to > # worry about non-exist key. > results = sparse_dict() results = defaultdict(int)
