|
12 | 12 | formatter_class=argparse.RawDescriptionHelpFormatter)
|
13 | 13 | parser.add_argument("-p", "--pid", type=int, help="The id of the process to trace.")
|
14 | 14 | parser.add_argument("-i", "--interval", type=int, help="The interval in seconds on which to report the latency distribution.")
|
15 |
| -parser.add_argument("-c", "--count", type=int, default=16, help="The count of samples over which to calculate the moving average.") |
| 15 | +parser.add_argument("-c", "--count", type=int, default=16, help="The maximum number of samples over which to calculate the moving average.") |
16 | 16 | parser.add_argument("-f", "--filterstr", type=str, default="", help="The prefix filter for the operation input. If specified, only operations for which the input string starts with the filterstr are traced.")
|
17 |
| -parser.add_argument("-v", "--verbose", dest="verbose", action="store_true", help="If true, will output verbose logging information.") |
| 17 | +parser.add_argument("-v", "--verbose", dest="verbose", action="store_true", help="If true, will output generated bpf program and verbose logging information.") |
| 18 | +parser.add_argument("-s", "--sdt", dest="sdt", action="store_true", help="If true, will use the probes, created by systemtap's dtrace.") |
| 19 | + |
18 | 20 | parser.set_defaults(verbose=False)
|
19 | 21 | args = parser.parse_args()
|
20 | 22 | this_pid = int(args.pid)
|
21 | 23 | this_interval = int(args.interval)
|
22 |
| -this_count = int(args.count) |
| 24 | +this_maxsamplesize = int(args.count) |
23 | 25 | this_filter = str(args.filterstr)
|
24 | 26 |
|
25 | 27 | if this_interval < 1:
|
26 | 28 | print("Invalid value for interval, using 1.")
|
27 | 29 | this_interval = 1
|
28 | 30 |
|
29 |
| -if this_count < 1: |
30 |
| - print("Invalid value for count, using 1.") |
31 |
| - this_count = 1 |
| 31 | +if this_maxsamplesize < 1: |
| 32 | + print("Invalid value for this_maxsamplesize, using 1.") |
| 33 | + this_maxsamplesize = 1 |
32 | 34 |
|
33 | 35 | debugLevel=0
|
34 | 36 | if args.verbose:
|
|
39 | 41 | bpf_text = open(bpf_text_shared, 'r').read()
|
40 | 42 | bpf_text += """
|
41 | 43 |
|
42 |
| -const u32 MAX_SAMPLES = SAMPLE_COUNT; |
| 44 | +const u32 max_sample_size = MAX_SAMPLE_SIZE; |
43 | 45 |
|
44 | 46 | struct hash_key_t
|
45 | 47 | {
|
46 |
| - char input[64]; |
| 48 | + char input[64]; // The operation id is used as key |
47 | 49 | };
|
48 | 50 |
|
49 | 51 | struct hash_leaf_t
|
50 | 52 | {
|
51 |
| - u32 count; |
52 |
| - u64 total; |
53 |
| - u64 average; |
| 53 | + u32 sample_size; // Number of operation samples taken |
| 54 | + u64 total; // Cumulative duration of the operations |
| 55 | + u64 average; // Moving average duration of the operations |
54 | 56 | };
|
55 | 57 |
|
56 | 58 | /**
|
|
83 | 85 | return 0;
|
84 | 86 | }
|
85 | 87 |
|
86 |
| - if (hash_leaf->count < MAX_SAMPLES) { |
87 |
| - hash_leaf->count++; |
| 88 | + if (hash_leaf->sample_size < max_sample_size) { |
| 89 | + ++hash_leaf->sample_size; |
88 | 90 | } else {
|
89 | 91 | hash_leaf->total -= hash_leaf->average;
|
90 | 92 | }
|
91 | 93 |
|
92 | 94 | hash_leaf->total += duration;
|
93 |
| - hash_leaf->average = hash_leaf->total / hash_leaf->count; |
| 95 | + hash_leaf->average = hash_leaf->total / hash_leaf->sample_size; |
94 | 96 |
|
95 | 97 | return 0;
|
96 | 98 | }
|
97 | 99 | """
|
98 | 100 |
|
99 |
| -bpf_text = bpf_text.replace("SAMPLE_COUNT", str(this_count)) |
| 101 | +bpf_text = bpf_text.replace("MAX_SAMPLE_SIZE", str(this_maxsamplesize)) |
100 | 102 | bpf_text = bpf_text.replace("FILTER_STRING", this_filter)
|
101 | 103 | if this_filter:
|
102 |
| - bpf_text = bpf_text.replace("FILTER", "if (!filter(start_data.input)) { return 0; }") |
| 104 | + bpf_text = bpf_text.replace("FILTER_STATEMENT", "if (!filter(start_data.input)) { return 0; }") |
103 | 105 | else:
|
104 |
| - bpf_text = bpf_text.replace("FILTER", "") |
| 106 | + bpf_text = bpf_text.replace("FILTER_STATEMENT", "") |
105 | 107 |
|
106 | 108 | # Create USDT context
|
107 |
| -print("Attaching probes to pid %d" % this_pid) |
| 109 | +print("lat_avg.py - Attaching probes to pid: %d; filter: %s" % (this_pid, this_filter)) |
108 | 110 | usdt_ctx = USDT(pid=this_pid)
|
109 |
| -usdt_ctx.enable_probe(probe="operation_start", fn_name="trace_operation_start") |
110 |
| -usdt_ctx.enable_probe(probe="operation_end", fn_name="trace_operation_end") |
| 111 | + |
| 112 | +if args.sdt: |
| 113 | + usdt_ctx.enable_probe(probe="usdt_sample_lib1_sdt:operation_start_sdt", fn_name="trace_operation_start") |
| 114 | + usdt_ctx.enable_probe(probe="usdt_sample_lib1_sdt:operation_end_sdt", fn_name="trace_operation_end") |
| 115 | +else: |
| 116 | + usdt_ctx.enable_probe(probe="usdt_sample_lib1:operation_start", fn_name="trace_operation_start") |
| 117 | + usdt_ctx.enable_probe(probe="usdt_sample_lib1:operation_end", fn_name="trace_operation_end") |
111 | 118 |
|
112 | 119 | # Create BPF context, load BPF program
|
113 | 120 | bpf_ctx = BPF(text=bpf_text, usdt_contexts=[usdt_ctx], debug=debugLevel)
|
114 | 121 |
|
115 | 122 | print("Tracing... Hit Ctrl-C to end.")
|
116 | 123 |
|
117 | 124 | lat_hash = bpf_ctx.get_table("lat_hash")
|
| 125 | +print("%-12s %-64s %8s %16s" % ("time", "input", "sample_size", "latency (us)")) |
118 | 126 | while (1):
|
119 | 127 | try:
|
120 | 128 | sleep(this_interval)
|
121 | 129 | except KeyboardInterrupt:
|
122 | 130 | exit()
|
123 | 131 |
|
124 |
| - print("[%s]" % strftime("%H:%M:%S")) |
125 |
| - print("%-64s %8s %16s" % ("input", "count", "latency (us)")) |
126 | 132 | for k, v in lat_hash.items():
|
127 |
| - print("%-64s %8d %16d" % (k.input, v.count, v.average / 1000)) |
| 133 | + print("%-12s %-64s %8d %16d" % (strftime("%H:%M:%S"), k.input, v.sample_size, v.average / 1000)) |
0 commit comments