| Seq | Timestamp | Type | Name | Duration |
|---|---|---|---|---|
| 0/0 | 2026/06/30 22:09 | flow | patch-triage |
0mArgs:null Results: {
"EnableConfigs": null,
"FocusSymbols": [],
"Reasoning": "The patch only adds bpftrace scripts and a python script for profiling under tools/bpftrace/. It does not modify any core kernel logic, drivers, or architectures, and therefore does not introduce any functional changes that can be fuzzed.",
"WorthFuzzing": false
} |
| 1/1 | 2026/06/30 22:09 | action | read-patch-diff |
0mArgs:null Results: {
"PatchDiff": "commit 558ae4ec7360a053b45fb47ade2595d94a0c04c3\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate: Tue Jun 30 22:09:53 2026 +0000\n\n syz-cluster: applied patch under review\n\ndiff --git a/tools/bpftrace/instrumented_profiler/aggregate_bpf_results.py b/tools/bpftrace/instrumented_profiler/aggregate_bpf_results.py\nnew file mode 100644\nindex 00000000000000..f4ffe8cff4418e\n--- /dev/null\n+++ b/tools/bpftrace/instrumented_profiler/aggregate_bpf_results.py\n@@ -0,0 +1,318 @@\n+#!/usr/bin/env python3\n+# SPDX-License-Identifier: GPL-2.0-or-later\n+#\n+# Prints the aggregate results of an instrumented BPF trace.\n+#\n+# Copyright 2026 Google LLC\n+#\n+# Author: Aaron Lewis \u003caaronlewis@google.com\u003e\n+\n+import fileinput\n+import re\n+import sys\n+import warnings\n+from typing import List, Sequence\n+\n+class ProfilerResult:\n+ \"\"\"Class for holding the profiler results.\"\"\"\n+\n+ def __init__(\n+ self,\n+ name: str,\n+ thread_usec: int,\n+ wall_usec: int,\n+ max_usec: int,\n+ avg_usec: int,\n+ count: int,\n+ thread_count: int,\n+ incomplete_count: int,\n+ depth: int,\n+ ):\n+ self.name = name\n+ self.thread_usec = thread_usec\n+ self.wall_usec = wall_usec\n+ self.max_usec = max_usec\n+ self.avg_usec = avg_usec\n+ self.count = count\n+ self.thread_count = thread_count\n+ self.incomplete_count = incomplete_count\n+ self.depth = depth\n+\n+class BpfTimer:\n+ \"\"\"Class for holding a timer.\"\"\"\n+\n+ def __init__(\n+ self,\n+ name: str,\n+ start_time_us: int,\n+ duration_us: int,\n+ depth: int,\n+ ):\n+ self.name = name\n+ self.start_time_us = start_time_us\n+ self.duration_us = duration_us\n+ self.depth = depth\n+\n+class BpfResult:\n+ \"\"\"Class for holding the profiler results.\"\"\"\n+\n+ def __init__(\n+ self,\n+ name: str,\n+ wall_time_start_us: int,\n+ wall_time_end_us: int,\n+ thread_us: int,\n+ max_us: int,\n+ avg_us: int,\n+ count: int,\n+ thread_count: int,\n+ depth: int,\n+ tid: int,\n+ ):\n+ self.name = name\n+ self.wall_time_start_us = wall_time_start_us\n+ self.wall_time_end_us = wall_time_end_us\n+ self.thread_us = thread_us\n+ self.max_us = max_us\n+ self.avg_us = avg_us\n+ self.count = count\n+ self.thread_count = thread_count\n+ self.depth = depth\n+ self.children = []\n+ self.child_index = {}\n+ self.threads = {}\n+ self.threads[tid] = True\n+\n+def update_child(r: BpfResult, timer: BpfTimer, tid: int) -\u003e int:\n+ i = r.child_index.get(timer.name)\n+ if i is None:\n+ i = len(r.children)\n+ r.children.append(BpfResult(\n+ timer.name,\n+ timer.start_time_us,\n+ timer.start_time_us + timer.duration_us,\n+ timer.duration_us,\n+ timer.duration_us,\n+ timer.duration_us,\n+ 1,\n+ 1,\n+ timer.depth,\n+ tid))\n+ r.child_index[timer.name] = i\n+ else:\n+ r.children[i].wall_time_start_us = min(r.children[i].wall_time_start_us, timer.start_time_us)\n+ r.children[i].wall_time_end_us = max(r.children[i].wall_time_end_us, timer.start_time_us + timer.duration_us)\n+ r.children[i].thread_us += timer.duration_us\n+ r.children[i].max_us = max(r.children[i].max_us, timer.duration_us)\n+ r.children[i].count += 1\n+ r.children[i].avg_us = r.children[i].thread_us / r.children[i].count\n+ if r.children[i].threads.get(tid) is None:\n+ r.children[i].threads[tid] = True\n+ r.children[i].thread_count += 1\n+\n+ return i\n+\n+def merge_recursive(r: BpfResult, tid: int, timers: List[BpfTimer], index: int, child_index: int) -\u003e int:\n+ while index \u003c len(timers):\n+ while index \u003c len(timers) and timers[index] == None:\n+ index += 1\n+\n+ if index \u003e= len(timers):\n+ return index\n+\n+ # The timer is a child of 'r'. (Child case)\n+ if timers[index].depth == (r.depth + 1):\n+ # Add child\n+ child_index = update_child(r, timers[index], tid)\n+\n+ # Now that the timer has been handled increment to the next one.\n+ index += 1\n+\n+ # The timer is a child of 'r'. (Grandchild case)\n+ elif timers[index].depth == (r.depth + 2):\n+ if child_index \u003c 0:\n+ raise ValueError(\"Invalid 'child_index'\")\n+ # Recurse down the child becuase that is the parent this timer.\n+ index = merge_recursive(r.children[child_index], tid, timers, index, child_index)\n+\n+ # The timer is a descendant of 'r', but not the child... Invalid case!\n+ elif timers[index].depth \u003e (r.depth + 2):\n+ raise ValueError(\"Invalid depth. descendant can only be children. name = '%s', tid = %d, index = %d\" % (timers[index].name, tid, index))\n+\n+ # New family tree. Pop out of this one.\n+ elif timers[index].depth \u003c= r.depth:\n+ # The timer is an ancestor of 'r'. Return so it can be processed elsewhere.\n+ return index\n+\n+ return index\n+\n+def merge_timers(r: BpfResult, tid: int, timers: List[BpfTimer]):\n+ if len(timers) == 0:\n+ return\n+\n+ if timers[0].depth != 0:\n+ raise ValueError(\"Expected a depth of 0. '%s', depth = %d\" % (timers[0].name, timers[0].depth))\n+\n+ merge_recursive(r, tid, timers, 0, -1)\n+\n+def print_recursive(r: BpfResult, results : List[ProfilerResult]):\n+ thread_time = float(r.thread_us) / 1000.0\n+ wall_time_us = r.wall_time_end_us - r.wall_time_start_us\n+ wall_time = float(wall_time_us) / 1000.0\n+ max_time = float(r.max_us) / 1000.0\n+ avg_time = float(r.avg_us) / 1000.0\n+\n+ indent = \"\"\n+ for i in range(r.depth):\n+ indent += \" \"\n+\n+ print(\"%s%s, thread_time = %.2fms, wall_time = %.2fms, max = %.2f, avg = %.2f, count = %d, thread_count = %d\" %\n+ (indent, r.name, thread_time, wall_time, max_time, avg_time, r.count, r.thread_count));\n+\n+ results.append(\n+ ProfilerResult(\n+ r.name,\n+ r.thread_us,\n+ wall_time_us,\n+ r.max_us,\n+ r.avg_us,\n+ r.count,\n+ r.thread_count,\n+ 0,\n+ r.depth,\n+ )\n+ )\n+\n+ for child in r.children:\n+ print_recursive(child, results)\n+\n+def print_results(r: BpfResult, results : List[ProfilerResult]):\n+ for child in r.children:\n+ print_recursive(child, results)\n+\n+def generate_from_log(files: Sequence[str]):\n+ \"\"\"Read the trace and return a list of ProfilerResult objects.\"\"\"\n+\n+ timer_counts = {}\n+ all_timers = {}\n+\n+ count_regex = re.compile(\n+ r\"^@timer_count\\[(?P\u003ctid\u003e[0-9]+)\\]:\\W(?P\u003ccount\u003e[-0-9]+)\"\n+ )\n+ name_regex = re.compile(\n+ r\"^@timer_name\\[(?P\u003ctid\u003e[0-9]+),\\W*(?P\u003cindex\u003e[0-9]+)\\]:\\W(?P\u003cname\u003e[\\w\\.0-9]+)\"\n+ )\n+ start_time_regex = re.compile(\n+ r\"^@timer_start\\[(?P\u003ctid\u003e[0-9]+),\\W*(?P\u003cindex\u003e[0-9]+)\\]:\\W(?P\u003cstart_time_us\u003e[-0-9]+)\"\n+ )\n+ duration_regex = re.compile(\n+ r\"^@timer_duration\\[(?P\u003ctid\u003e[0-9]+),\\W*(?P\u003cindex\u003e[0-9]+)\\]:\\W(?P\u003cduration_us\u003e[-0-9]+)\"\n+ )\n+ depth_regex = re.compile(\n+ r\"^@timer_depth\\[(?P\u003ctid\u003e[0-9]+),\\W*(?P\u003cindex\u003e[0-9]+)\\]:\\W(?P\u003cdepth\u003e[-0-9]+)\"\n+ )\n+\n+ attaching_regex = re.compile(\n+ r\"^Attaching.*\"\n+ )\n+\n+ # Get all counts. That way we know how many timers each thread used.\n+ for line in fileinput.input(files=files):\n+ line = line.rstrip()\n+\n+ m = re.fullmatch(duration_regex, line)\n+ if m:\n+ tid = int(m.group(\"tid\"))\n+ index = int(m.group(\"index\"))\n+ duration_str = m.group(\"duration_us\")\n+ duration = int(m.group(\"duration_us\"))\n+\n+ if not tid in timer_counts:\n+ timer_counts[tid] = index\n+ else:\n+ timer_counts[tid] = max(timer_counts[tid], index)\n+\n+ # Allocate enough timers to fit the trace.\n+ for tid, count in timer_counts.items():\n+ all_timers[tid] = [None] * (count + 1)\n+\n+ # Populate the trace.\n+ for line in fileinput.input(files=files):\n+ line = line.rstrip()\n+\n+ m = re.fullmatch(name_regex, line)\n+ if m:\n+ tid = int(m.group(\"tid\"))\n+ index = int(m.group(\"index\"))\n+ name = m.group(\"name\")\n+ if all_timers[tid][index] == None:\n+ all_timers[tid][index] = BpfTimer(\"\", 0, -1, -1)\n+ all_timers[tid][index].name = name\n+ continue\n+\n+ m = re.fullmatch(start_time_regex, line)\n+ if m:\n+ tid = int(m.group(\"tid\"))\n+ index = int(m.group(\"index\"))\n+ start_time = int(m.group(\"start_time_us\"))\n+ if all_timers[tid][index] == None:\n+ all_timers[tid][index] = BpfTimer(\"\", 0, -1, -1)\n+ all_timers[tid][index].start_time_us = start_time\n+ continue\n+\n+ m = re.fullmatch(duration_regex, line)\n+ if m:\n+ tid = int(m.group(\"tid\"))\n+ index = int(m.group(\"index\"))\n+ duration = int(m.group(\"duration_us\"))\n+ if all_timers[tid][index] == None:\n+ all_timers[tid][index] = BpfTimer(\"\", 0, -1, -1)\n+ all_timers[tid][index].duration_us = duration\n+ continue\n+\n+ m = re.fullmatch(depth_regex, line)\n+ if m:\n+ tid = int(m.group(\"tid\"))\n+ index = int(m.group(\"index\"))\n+ depth = int(m.group(\"depth\"))\n+ if all_timers[tid][index] == None:\n+ all_timers[tid][index] = BpfTimer(\"\", 0, -1, -1)\n+ all_timers[tid][index].depth = depth\n+ continue\n+\n+ if re.fullmatch(count_regex, line):\n+ # Skip this case. It's already been processed.\n+ continue\n+ if re.fullmatch(attaching_regex, line):\n+ # Skip \"Attaching XX probes...\"\n+ continue\n+ if not line:\n+ # Skip empty strings.\n+ continue\n+\n+ raise ValueError(\"Invalid input, '%s'\" % (line))\n+\n+ root = BpfResult(\"\", 0, 0, 0, 0, 0, 1, 1, -1, -1)\n+ results = []\n+ for tid, timers in all_timers.items():\n+ merge_timers(root, tid, timers)\n+ print_results(root, results)\n+\n+ if fileinput.fileno() == 0:\n+ raise ValueError(\"Expected a file to read.\")\n+\n+ if fileinput.fileno() \u003e 1:\n+ raise ValueError(\"Too many files read. Expected 1\")\n+\n+def main() -\u003e None:\n+ \"\"\"Main function.\"\"\"\n+\n+ if len(sys.argv) \u003c= 1:\n+ print(\"Error: Not enough command-line arguments. Expected an input file\", file=sys.stderr)\n+ sys.exit(1)\n+\n+ generate_from_log(sys.argv[1:])\n+\n+\n+if __name__ == \"__main__\":\n+ main()\ndiff --git a/tools/bpftrace/instrumented_profiler/samples/kvm_trace.bt b/tools/bpftrace/instrumented_profiler/samples/kvm_trace.bt\nnew file mode 100644\nindex 00000000000000..bd341e408570ec\n--- /dev/null\n+++ b/tools/bpftrace/instrumented_profiler/samples/kvm_trace.bt\n@@ -0,0 +1,197 @@\n+#define usecs (nsecs / 1000)\n+#define msecs (nsecs / 1000 / 1000)\n+#define DURATION_UNSET ((uint64)-1)\n+\n+config = { max_map_keys=4194304; }\n+\n+macro INIT_MAPS(@trace_stack_top, @timer_count)\n+{\n+\t@trace_stack_top[0] = 0;\n+\t@timer_count[0] = 0;\n+}\n+\n+macro CLEAR_MAPS(@trace_stack, @trace_stack_top, @timer_count)\n+{\n+\tclear(@trace_stack);\n+\tclear(@trace_stack_top);\n+\tclear(@timer_count);\n+}\n+\n+macro START_TIMER(name, @timer_name, @trace_stack, @timer_start, @timer_duration,\n+\t\t @timer_depth, @timer_count, @trace_stack_top)\n+{\n+\t@timer_name[tid, @timer_count[tid]] = name;\n+\t@trace_stack[tid, @trace_stack_top[tid]] = @timer_count[tid];\n+\t@timer_start[tid, @timer_count[tid]] = usecs;\n+\t@timer_duration[tid, @timer_count[tid]] = DURATION_UNSET;\n+\t@timer_depth[tid, @timer_count[tid]] = @trace_stack_top[tid];\n+\t@timer_count[tid]++;\n+\t@trace_stack_top[tid]++;\n+}\n+\n+/*\n+ * Unfortunately branch statements crash the bpftrace compiler. As a result,\n+ * the branch has been moved directly into the probe. Reverse this if the\n+ * compiler ever gets that fixed.\n+ */\n+macro STOP_TIMER(@trace_stack_top, @trace_stack, @timer_duration, @timer_start)\n+{\n+\t$idx = @trace_stack[tid, --@trace_stack_top[tid]];\n+\t@timer_duration[tid, $idx] = usecs - @timer_start[tid, $idx];\n+}\n+\n+BEGIN\n+{\n+\tINIT_MAPS(@trace_stack_top, @timer_count);\n+}\n+\n+/*\n+ * Time 'kvm_sched_in()'.\n+ *\n+ * Check: sudo grep kvm_sched_in /proc/kallsyms\n+ */\n+kfunc:kvm_sched_in\n+{\n+\tSTART_TIMER(\"kvm_sched_in\",\n+\t\t @timer_name, @trace_stack, @timer_start, @timer_duration,\n+\t\t @timer_depth, @timer_count, @trace_stack_top);\n+}\n+kretfunc:kvm_sched_in\n+{\n+\tif (@trace_stack_top[tid] \u003e 0) {\n+\t\tSTOP_TIMER(@trace_stack_top, @trace_stack, @timer_duration, @timer_start);\n+\t}\n+}\n+\n+/*\n+ * Time 'kvm_sched_out()'.\n+ *\n+ * Check: sudo grep kvm_sched_out /proc/kallsyms\n+ */\n+kfunc:kvm_sched_out\n+{\n+\tSTART_TIMER(\"kvm_sched_out\",\n+\t\t @timer_name, @trace_stack, @timer_start, @timer_duration,\n+\t\t @timer_depth, @timer_count, @trace_stack_top);\n+}\n+\n+kretfunc:kvm_sched_out\n+{\n+\tif (@trace_stack_top[tid] \u003e 0) {\n+\t\tSTOP_TIMER(@trace_stack_top, @trace_stack, @timer_duration, @timer_start);\n+\t}\n+}\n+\n+/*\n+ * Time 'kvm_arch_vcpu_load()'.\n+ *\n+ * Check: sudo grep kvm_arch_vcpu_load /proc/kallsyms\n+ */\n+kfunc:kvm_arch_vcpu_load\n+{\n+\tSTART_TIMER(\"kvm_arch_vcpu_load\",\n+\t\t @timer_name, @trace_stack, @timer_start, @timer_duration,\n+\t\t @timer_depth, @timer_count, @trace_stack_top);\n+}\n+kretfunc:kvm_arch_vcpu_load\n+{\n+\tif (@trace_stack_top[tid] \u003e 0) {\n+\t\tSTOP_TIMER(@trace_stack_top, @trace_stack, @timer_duration, @timer_start);\n+\t}\n+}\n+\n+/*\n+ * Time 'kvm_arch_vcpu_put()'.\n+ *\n+ * Check: sudo grep kvm_arch_vcpu_put /proc/kallsyms\n+ */\n+kfunc:kvm_arch_vcpu_put\n+{\n+\tSTART_TIMER(\"kvm_arch_vcpu_put\",\n+\t\t @timer_name, @trace_stack, @timer_start, @timer_duration,\n+\t\t @timer_depth, @timer_count, @trace_stack_top);\n+}\n+kretfunc:kvm_arch_vcpu_put\n+{\n+\tif (@trace_stack_top[tid] \u003e 0) {\n+\t\tSTOP_TIMER(@trace_stack_top, @trace_stack, @timer_duration, @timer_start);\n+\t}\n+}\n+\n+/*\n+ * Time 'KVM_RUN', i.e. kvm_arch_vcpu_ioctl_run().\n+ *\n+ * Check: sudo grep kvm_arch_vcpu_ioctl_run /proc/kallsyms\n+ */\n+kfunc:kvm_arch_vcpu_ioctl_run\n+{\n+\tSTART_TIMER(\"kvm_arch_vcpu_ioctl_run\",\n+\t\t @timer_name, @trace_stack, @timer_start, @timer_duration,\n+\t\t @timer_depth, @timer_count, @trace_stack_top);\n+}\n+kretfunc:kvm_arch_vcpu_ioctl_run\n+{\n+\tif (@trace_stack_top[tid] \u003e 0) {\n+\t\tSTOP_TIMER(@trace_stack_top, @trace_stack, @timer_duration, @timer_start);\n+\t}\n+}\n+\n+/*\n+ * Time how long a guest runs using tracepoints \"kvm_entry\" and \"kvm_exit\".\n+ */\n+tracepoint:kvm:kvm_entry\n+{\n+\tSTART_TIMER(\"run_guest\",\n+\t\t @timer_name, @trace_stack, @timer_start, @timer_duration,\n+\t\t @timer_depth, @timer_count, @trace_stack_top);\n+}\n+tracepoint:kvm:kvm_exit\n+{\n+\tif (@trace_stack_top[tid] \u003e 0) {\n+\t\tSTOP_TIMER(@trace_stack_top, @trace_stack, @timer_duration, @timer_start);\n+\t}\n+}\n+\n+/*\n+ * Time 'kvm_vcpu_block()'.\n+ *\n+ * Check: sudo grep kvm_vcpu_block /proc/kallsyms\n+ */\n+kfunc:kvm_vcpu_block\n+{\n+\tSTART_TIMER(\"kvm_vcpu_block\",\n+\t\t @timer_name, @trace_stack, @timer_start, @timer_duration,\n+\t\t @timer_depth, @timer_count, @trace_stack_top);\n+}\n+kretfunc:kvm_vcpu_block\n+{\n+\tif (@trace_stack_top[tid] \u003e 0) {\n+\t\tSTOP_TIMER(@trace_stack_top, @trace_stack, @timer_duration, @timer_start);\n+\t}\n+}\n+\n+/*\n+ * Time 'kvm_mmu_page_fault()'.\n+ *\n+ * Check: sudo grep kvm_mmu_page_fault /proc/kallsyms\n+ */\n+kfunc:kvm_mmu_page_fault\n+{\n+\tSTART_TIMER(\"kvm_vcpu_block\",\n+\t\t @timer_name, @trace_stack, @timer_start, @timer_duration,\n+\t\t @timer_depth, @timer_count, @trace_stack_top);\n+}\n+kretfunc:kvm_mmu_page_fault\n+{\n+\tif (@trace_stack_top[tid] \u003e 0) {\n+\t\tSTOP_TIMER(@trace_stack_top, @trace_stack, @timer_duration, @timer_start);\n+\t}\n+}\n+\n+/*\n+ * Dump the results to stdout.\n+ */\n+END\n+{\n+\tCLEAR_MAPS(@trace_stack, @trace_stack_top, @timer_count);\n+}\ndiff --git a/tools/bpftrace/instrumented_profiler/samples/vfio_trace.bt b/tools/bpftrace/instrumented_profiler/samples/vfio_trace.bt\nnew file mode 100644\nindex 00000000000000..3b8cb7ff6210de\n--- /dev/null\n+++ b/tools/bpftrace/instrumented_profiler/samples/vfio_trace.bt\n@@ -0,0 +1,315 @@\n+#define usecs (nsecs / 1000)\n+#define msecs (nsecs / 1000 / 1000)\n+#define DURATION_UNSET ((uint64)-1)\n+\n+config = { max_map_keys=4194304; }\n+\n+macro INIT_MAPS(@trace_stack_top, @timer_count)\n+{\n+\t@trace_stack_top[0] = 0;\n+\t@timer_count[0] = 0;\n+}\n+\n+macro CLEAR_MAPS(@trace_stack, @trace_stack_top, @timer_count)\n+{\n+\tclear(@trace_stack);\n+\tclear(@trace_stack_top);\n+\tclear(@timer_count);\n+}\n+\n+macro START_TIMER(name, @timer_name, @trace_stack, @timer_start, @timer_duration,\n+\t\t @timer_depth, @timer_count, @trace_stack_top)\n+{\n+\t@timer_name[tid, @timer_count[tid]] = name;\n+\t@trace_stack[tid, @trace_stack_top[tid]] = @timer_count[tid];\n+\t@timer_start[tid, @timer_count[tid]] = usecs;\n+\t@timer_duration[tid, @timer_count[tid]] = DURATION_UNSET;\n+\t@timer_depth[tid, @timer_count[tid]] = @trace_stack_top[tid];\n+\t@timer_count[tid]++;\n+\t@trace_stack_top[tid]++;\n+}\n+\n+/*\n+ * Unfortunately branch statements crash the bpftrace compiler. As a result,\n+ * the branch has been moved directly into the probe. Reverse this if the\n+ * compiler ever gets that fixed.\n+ */\n+macro STOP_TIMER(@trace_stack_top, @trace_stack, @timer_duration, @timer_start)\n+{\n+\t$idx = @trace_stack[tid, --@trace_stack_top[tid]];\n+\t@timer_duration[tid, $idx] = usecs - @timer_start[tid, $idx];\n+}\n+\n+BEGIN\n+{\n+\tINIT_MAPS(@trace_stack_top, @timer_count);\n+}\n+\n+/*\n+ * Time 'vfio_group_fops_unl_ioctl()'.\n+ *\n+ * VFIO_GROUP_GET_DEVICE_FD = 0x3b6a\n+ *\n+ * Check: sudo grep vfio_group_fops_unl_ioctl /proc/kallsyms\n+ */\n+kfunc:vfio_group_fops_unl_ioctl /args-\u003ecmd == 0x3b6a/\n+{\n+\tSTART_TIMER(\"vfio_group_ioctl_get_device_fd\",\n+\t\t @timer_name, @trace_stack, @timer_start, @timer_duration,\n+\t\t @timer_depth, @timer_count, @trace_stack_top);\n+}\n+kretfunc:vfio_group_fops_unl_ioctl /args-\u003ecmd == 0x3b6a/\n+{\n+\tif (@trace_stack_top[tid] \u003e 0) {\n+\t\tSTOP_TIMER(@trace_stack_top, @trace_stack, @timer_duration, @timer_start);\n+\t}\n+}\n+\n+/*\n+ * Time 'vfio_df_ioctl_bind_iommufd()'.\n+ *\n+ * Check: sudo grep vfio_df_ioctl_bind_iommufd /proc/kallsyms\n+ */\n+kfunc:vfio_df_ioctl_bind_iommufd\n+{\n+\tSTART_TIMER(\"vfio_df_ioctl_bind_iommufd\",\n+\t\t @timer_name, @trace_stack, @timer_start, @timer_duration,\n+\t\t @timer_depth, @timer_count, @trace_stack_top);\n+}\n+kretfunc:vfio_df_ioctl_bind_iommufd\n+{\n+\tif (@trace_stack_top[tid] \u003e 0) {\n+\t\tSTOP_TIMER(@trace_stack_top, @trace_stack, @timer_duration, @timer_start);\n+\t}\n+}\n+\n+/*\n+ * Time 'vfio_df_unbind_iommufd()'.\n+ *\n+ * Check: sudo grep vfio_df_unbind_iommufd /proc/kallsyms\n+ */\n+kfunc:vfio_df_unbind_iommufd\n+{\n+\tSTART_TIMER(\"vfio_df_unbind_iommufd\",\n+\t\t @timer_name, @trace_stack, @timer_start, @timer_duration,\n+\t\t @timer_depth, @timer_count, @trace_stack_top);\n+}\n+kretfunc:vfio_df_unbind_iommufd\n+{\n+\tif (@trace_stack_top[tid] \u003e 0) {\n+\t\tSTOP_TIMER(@trace_stack_top, @trace_stack, @timer_duration, @timer_start);\n+\t}\n+}\n+\n+/*\n+ * Time 'vfio_df_open()'.\n+ *\n+ * Check: sudo grep vfio_df_open /proc/kallsyms\n+ */\n+kfunc:vfio_df_open\n+{\n+\tSTART_TIMER(\"vfio_df_open\",\n+\t\t @timer_name, @trace_stack, @timer_start, @timer_duration,\n+\t\t @timer_depth, @timer_count, @trace_stack_top);\n+}\n+kretfunc:vfio_df_open\n+{\n+\tif (@trace_stack_top[tid] \u003e 0) {\n+\t\tSTOP_TIMER(@trace_stack_top, @trace_stack, @timer_duration, @timer_start);\n+\t}\n+}\n+\n+/*\n+ * Time 'pcie_flr()'.\n+ *\n+ * Check: sudo grep pcie_flr /proc/kallsyms\n+ */\n+kfunc:pcie_flr\n+{\n+\tSTART_TIMER(\"pcie_flr\",\n+\t\t @timer_name, @trace_stack, @timer_start, @timer_duration,\n+\t\t @timer_depth, @timer_count, @trace_stack_top);\n+}\n+kretfunc:pcie_flr\n+{\n+\tif (@trace_stack_top[tid] \u003e 0) {\n+\t\tSTOP_TIMER(@trace_stack_top, @trace_stack, @timer_duration, @timer_start);\n+\t}\n+}\n+\n+/*\n+ * Time 'pci_dev_wait()'.\n+ *\n+ * Check: sudo grep pci_dev_wait /proc/kallsyms\n+ */\n+kfunc:pci_dev_wait\n+{\n+\tSTART_TIMER(\"pci_dev_wait\",\n+\t\t @timer_name, @trace_stack, @timer_start, @timer_duration,\n+\t\t @timer_depth, @timer_count, @trace_stack_top);\n+}\n+kretfunc:pci_dev_wait\n+{\n+\tif (@trace_stack_top[tid] \u003e 0) {\n+\t\tSTOP_TIMER(@trace_stack_top, @trace_stack, @timer_duration, @timer_start);\n+\t}\n+}\n+\n+/*\n+ * Time 'vfio_iommu_type1_ioctl()' when 'VFIO_IOMMU_MAP_DMA' is called.\n+ *\n+ *\n+ * VFIO_IOMMU_MAP_DMA = 0x3b71\n+ *\n+ * Check: sudo grep vfio_iommu_type1_ioctl /proc/kallsyms\n+ */\n+kfunc:vfio_iommu_type1_ioctl /args-\u003ecmd == 0x3b71/\n+{\n+\tSTART_TIMER(\"vfio_iommu_type1_map_dma\",\n+\t\t @timer_name, @trace_stack, @timer_start, @timer_duration,\n+\t\t @timer_depth, @timer_count, @trace_stack_top);\n+}\n+kretfunc:vfio_iommu_type1_ioctl /args-\u003ecmd == 0x3b71/\n+{\n+\tif (@trace_stack_top[tid] \u003e 0) {\n+\t\tSTOP_TIMER(@trace_stack_top, @trace_stack, @timer_duration, @timer_start);\n+\t}\n+}\n+\n+/*\n+ * Time 'vfio_pin_map_dma()'.\n+ *\n+ * Check: sudo grep vfio_pin_map_dma /proc/kallsyms\n+ */\n+kfunc:vfio_pin_map_dma\n+{\n+\tSTART_TIMER(\"vfio_pin_map_dma\",\n+\t\t @timer_name, @trace_stack, @timer_start, @timer_duration,\n+\t\t @timer_depth, @timer_count, @trace_stack_top);\n+}\n+kretfunc:vfio_pin_map_dma\n+{\n+\tif (@trace_stack_top[tid] \u003e 0) {\n+\t\tSTOP_TIMER(@trace_stack_top, @trace_stack, @timer_duration, @timer_start);\n+\t}\n+}\n+\n+/*\n+ * Time 'vfio_pin_pages_remote()'.\n+ *\n+ * Check: sudo grep vfio_pin_pages_remote /proc/kallsyms\n+ */\n+kfunc:vfio_pin_pages_remote\n+{\n+\tSTART_TIMER(\"vfio_pin_pages_remote\",\n+\t\t @timer_name, @trace_stack, @timer_start, @timer_duration,\n+\t\t @timer_depth, @timer_count, @trace_stack_top);\n+}\n+kretfunc:vfio_pin_pages_remote\n+{\n+\tif (@trace_stack_top[tid] \u003e 0) {\n+\t\tSTOP_TIMER(@trace_stack_top, @trace_stack, @timer_duration, @timer_start);\n+\t}\n+}\n+\n+/*\n+ * Time 'vaddr_get_pfns()'.\n+ *\n+ * Check: sudo grep vaddr_get_pfns /proc/kallsyms\n+ */\n+kfunc:vaddr_get_pfns\n+{\n+\tSTART_TIMER(\"vaddr_get_pfns\",\n+\t\t @timer_name, @trace_stack, @timer_start, @timer_duration,\n+\t\t @timer_depth, @timer_count, @trace_stack_top);\n+}\n+kretfunc:vaddr_get_pfns\n+{\n+\tif (@trace_stack_top[tid] \u003e 0) {\n+\t\tSTOP_TIMER(@trace_stack_top, @trace_stack, @timer_duration, @timer_start);\n+\t}\n+}\n+\n+// /*\n+// * Time 'iommu_map()'.\n+// *\n+// * Check: sudo grep iommu_map /proc/kallsyms\n+// */\n+// kfunc:iommu_map\n+// {\n+// \tSTART_TIMER(\"iommu_map\",\n+// \t\t @timer_name, @trace_stack, @timer_start, @timer_duration,\n+// \t\t @timer_depth, @timer_count, @trace_stack_top);\n+// }\n+// kretfunc:iommu_map\n+// {\n+// \tif (@trace_stack_top[tid] \u003e 0) {\n+// \t\tSTOP_TIMER(@trace_stack_top, @trace_stack, @timer_duration, @timer_start);\n+// \t}\n+// }\n+\n+\n+\n+/*\n+ * Time 'vfio_iommu_type1_ioctl()' when 'VFIO_IOMMU_UNMAP_DMA' is called.\n+ *\n+ * VFIO_IOMMU_UNMAP_DMA = 0x3b72\n+ *\n+ * Check: sudo grep vfio_iommu_type1_ioctl /proc/kallsyms\n+ */\n+kfunc:vfio_iommu_type1_ioctl /args-\u003ecmd == 0x3b72/\n+{\n+\tSTART_TIMER(\"vfio_iommu_type1_unmap_dma\",\n+\t\t @timer_name, @trace_stack, @timer_start, @timer_duration,\n+\t\t @timer_depth, @timer_count, @trace_stack_top);\n+}\n+kretfunc:vfio_iommu_type1_ioctl /args-\u003ecmd == 0x3b72/\n+{\n+\tif (@trace_stack_top[tid] \u003e 0) {\n+\t\tSTOP_TIMER(@trace_stack_top, @trace_stack, @timer_duration, @timer_start);\n+\t}\n+}\n+\n+/*\n+ * Time 'vfio_unmap_unpin()'.\n+ *\n+ * Check: sudo grep vfio_unmap_unpin /proc/kallsyms\n+ */\n+kfunc:vfio_unmap_unpin\n+{\n+\tSTART_TIMER(\"vfio_unmap_unpin\",\n+\t\t @timer_name, @trace_stack, @timer_start, @timer_duration,\n+\t\t @timer_depth, @timer_count, @trace_stack_top);\n+}\n+kretfunc:vfio_unmap_unpin\n+{\n+\tif (@trace_stack_top[tid] \u003e 0) {\n+\t\tSTOP_TIMER(@trace_stack_top, @trace_stack, @timer_duration, @timer_start);\n+\t}\n+}\n+\n+/*\n+ * Time 'vfio_sync_unpin()'.\n+ *\n+ * Check: sudo grep vfio_sync_unpin /proc/kallsyms\n+ */\n+kfunc:vfio_sync_unpin\n+{\n+\tSTART_TIMER(\"vfio_sync_unpin\",\n+\t\t @timer_name, @trace_stack, @timer_start, @timer_duration,\n+\t\t @timer_depth, @timer_count, @trace_stack_top);\n+}\n+kretfunc:vfio_sync_unpin\n+{\n+\tif (@trace_stack_top[tid] \u003e 0) {\n+\t\tSTOP_TIMER(@trace_stack_top, @trace_stack, @timer_duration, @timer_start);\n+\t}\n+}\n+\n+/*\n+ * Dump the results to stdout.\n+ */\n+END\n+{\n+\tCLEAR_MAPS(@trace_stack, @trace_stack_top, @timer_count);\n+}\n"
} |
| 2/1 | 2026/06/30 22:09 | agent | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: {
"EnableConfigs": null,
"FocusSymbols": [],
"Reasoning": "The patch only adds bpftrace scripts and a python script for profiling under tools/bpftrace/. It does not modify any core kernel logic, drivers, or architectures, and therefore does not introduce any functional changes that can be fuzzed.",
"WorthFuzzing": false
}Instruction: You are an expert Linux kernel maintainer. Your job is to review a provided patch series and determine if it makes functional changes to the kernel that should be fuzzed. IMPORTANT: The changes have ALREADY been applied and committed as the HEAD commit in your workspace. Do NOT rely on your internal knowledge of the kernel. You must actively use your code access tools to examine the actual source code and confirm any assumptions. Return WorthFuzzing=false if the patch only contains: - Modifications to Documentation/, Kconfig files, or code comments. - Purely decorative changes, such as logging (e.g., pr_err, printk) or tracepoints. - Changes to numeric constants or macros that do not functionally alter execution flow. - Code paths that are impossible to reach in virtualized environments like GCE or QEMU, even when utilizing software-emulated hardware (e.g., usb gadget, mac80211_hwsim). If it modifies reachable core kernel logic, drivers, or architectures, use your code search tools to verify the code can be executed, then return WorthFuzzing=true. When returning WorthFuzzing=true, you MUST ALSO: 1. Extract any specific kernel functions that should be heavily fuzzed into FocusSymbols. Avoid listing generic hot-path functions to prevent skewed test distributions. 2. Identify any specific CONFIG_ options required to properly test this new/modified feature. Go and look into the Kconfig files and check for ifdefs around the code, do not make assumptions. Do not list too generic configs (we already have them enabled). Only list those that specifically cover the modified code. List them in the EnableConfigs output array, and DO NOT add a 'CONFIG_' prefix (e.g., return "NET_IPV4" instead of "CONFIG_NET_IPV4"). Prefer calling several tools at the same time to save round-trips. Use set-results tool to provide results of the analysis. It must be called exactly once before the final reply. Ignore results of this tool. Prompt: For your convenience, here is the diff of the changes:
commit 558ae4ec7360a053b45fb47ade2595d94a0c04c3
Author: syz-cluster <triage@syzkaller.com>
Date: Tue Jun 30 22:09:53 2026 +0000
syz-cluster: applied patch under review
diff --git a/tools/bpftrace/instrumented_profiler/aggregate_bpf_results.py b/tools/bpftrace/instrumented_profiler/aggregate_bpf_results.py
new file mode 100644
index 00000000000000..f4ffe8cff4418e
--- /dev/null
+++ b/tools/bpftrace/instrumented_profiler/aggregate_bpf_results.py
@@ -0,0 +1,318 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Prints the aggregate results of an instrumented BPF trace.
+#
+# Copyright 2026 Google LLC
+#
+# Author: Aaron Lewis <aaronlewis@google.com>
+
+import fileinput
+import re
+import sys
+import warnings
+from typing import List, Sequence
+
+class ProfilerResult:
+ """Class for holding the profiler results."""
+
+ def __init__(
+ self,
+ name: str,
+ thread_usec: int,
+ wall_usec: int,
+ max_usec: int,
+ avg_usec: int,
+ count: int,
+ thread_count: int,
+ incomplete_count: int,
+ depth: int,
+ ):
+ self.name = name
+ self.thread_usec = thread_usec
+ self.wall_usec = wall_usec
+ self.max_usec = max_usec
+ self.avg_usec = avg_usec
+ self.count = count
+ self.thread_count = thread_count
+ self.incomplete_count = incomplete_count
+ self.depth = depth
+
+class BpfTimer:
+ """Class for holding a timer."""
+
+ def __init__(
+ self,
+ name: str,
+ start_time_us: int,
+ duration_us: int,
+ depth: int,
+ ):
+ self.name = name
+ self.start_time_us = start_time_us
+ self.duration_us = duration_us
+ self.depth = depth
+
+class BpfResult:
+ """Class for holding the profiler results."""
+
+ def __init__(
+ self,
+ name: str,
+ wall_time_start_us: int,
+ wall_time_end_us: int,
+ thread_us: int,
+ max_us: int,
+ avg_us: int,
+ count: int,
+ thread_count: int,
+ depth: int,
+ tid: int,
+ ):
+ self.name = name
+ self.wall_time_start_us = wall_time_start_us
+ self.wall_time_end_us = wall_time_end_us
+ self.thread_us = thread_us
+ self.max_us = max_us
+ self.avg_us = avg_us
+ self.count = count
+ self.thread_count = thread_count
+ self.depth = depth
+ self.children = []
+ self.child_index = {}
+ self.threads = {}
+ self.threads[tid] = True
+
+def update_child(r: BpfResult, timer: BpfTimer, tid: int) -> int:
+ i = r.child_index.get(timer.name)
+ if i is None:
+ i = len(r.children)
+ r.children.append(BpfResult(
+ timer.name,
+ timer.start_time_us,
+ timer.start_time_us + timer.duration_us,
+ timer.duration_us,
+ timer.duration_us,
+ timer.duration_us,
+ 1,
+ 1,
+ timer.depth,
+ tid))
+ r.child_index[timer.name] = i
+ else:
+ r.children[i].wall_time_start_us = min(r.children[i].wall_time_start_us, timer.start_time_us)
+ r.children[i].wall_time_end_us = max(r.children[i].wall_time_end_us, timer.start_time_us + timer.duration_us)
+ r.children[i].thread_us += timer.duration_us
+ r.children[i].max_us = max(r.children[i].max_us, timer.duration_us)
+ r.children[i].count += 1
+ r.children[i].avg_us = r.children[i].thread_us / r.children[i].count
+ if r.children[i].threads.get(tid) is None:
+ r.children[i].threads[tid] = True
+ r.children[i].thread_count += 1
+
+ return i
+
+def merge_recursive(r: BpfResult, tid: int, timers: List[BpfTimer], index: int, child_index: int) -> int:
+ while index < len(timers):
+ while index < len(timers) and timers[index] == None:
+ index += 1
+
+ if index >= len(timers):
+ return index
+
+ # The timer is a child of 'r'. (Child case)
+ if timers[index].depth == (r.depth + 1):
+ # Add child
+ child_index = update_child(r, timers[index], tid)
+
+ # Now that the timer has been handled increment to the next one.
+ index += 1
+
+ # The timer is a child of 'r'. (Grandchild case)
+ elif timers[index].depth == (r.depth + 2):
+ if child_index < 0:
+ raise ValueError("Invalid 'child_index'")
+ # Recurse down the child becuase that is the parent this timer.
+ index = merge_recursive(r.children[child_index], tid, timers, index, child_index)
+
+ # The timer is a descendant of 'r', but not the child... Invalid case!
+ elif timers[index].depth > (r.depth + 2):
+ raise ValueError("Invalid depth. descendant can only be children. name = '%s', tid = %d, index = %d" % (timers[index].name, tid, index))
+
+ # New family tree. Pop out of this one.
+ elif timers[index].depth <= r.depth:
+ # The timer is an ancestor of 'r'. Return so it can be processed elsewhere.
+ return index
+
+ return index
+
+def merge_timers(r: BpfResult, tid: int, timers: List[BpfTimer]):
+ if len(timers) == 0:
+ return
+
+ if timers[0].depth != 0:
+ raise ValueError("Expected a depth of 0. '%s', depth = %d" % (timers[0].name, timers[0].depth))
+
+ merge_recursive(r, tid, timers, 0, -1)
+
+def print_recursive(r: BpfResult, results : List[ProfilerResult]):
+ thread_time = float(r.thread_us) / 1000.0
+ wall_time_us = r.wall_time_end_us - r.wall_time_start_us
+ wall_time = float(wall_time_us) / 1000.0
+ max_time = float(r.max_us) / 1000.0
+ avg_time = float(r.avg_us) / 1000.0
+
+ indent = ""
+ for i in range(r.depth):
+ indent += " "
+
+ print("%s%s, thread_time = %.2fms, wall_time = %.2fms, max = %.2f, avg = %.2f, count = %d, thread_count = %d" %
+ (indent, r.name, thread_time, wall_time, max_time, avg_time, r.count, r.thread_count));
+
+ results.append(
+ ProfilerResult(
+ r.name,
+ r.thread_us,
+ wall_time_us,
+ r.max_us,
+ r.avg_us,
+ r.count,
+ r.thread_count,
+ 0,
+ r.depth,
+ )
+ )
+
+ for child in r.children:
+ print_recursive(child, results)
+
+def print_results(r: BpfResult, results : List[ProfilerResult]):
+ for child in r.children:
+ print_recursive(child, results)
+
+def generate_from_log(files: Sequence[str]):
+ """Read the trace and return a list of ProfilerResult objects."""
+
+ timer_counts = {}
+ all_timers = {}
+
+ count_regex = re.compile(
+ r"^@timer_count\[(?P<tid>[0-9]+)\]:\W(?P<count>[-0-9]+)"
+ )
+ name_regex = re.compile(
+ r"^@timer_name\[(?P<tid>[0-9]+),\W*(?P<index>[0-9]+)\]:\W(?P<name>[\w\.0-9]+)"
+ )
+ start_time_regex = re.compile(
+ r"^@timer_start\[(?P<tid>[0-9]+),\W*(?P<index>[0-9]+)\]:\W(?P<start_time_us>[-0-9]+)"
+ )
+ duration_regex = re.compile(
+ r"^@timer_duration\[(?P<tid>[0-9]+),\W*(?P<index>[0-9]+)\]:\W(?P<duration_us>[-0-9]+)"
+ )
+ depth_regex = re.compile(
+ r"^@timer_depth\[(?P<tid>[0-9]+),\W*(?P<index>[0-9]+)\]:\W(?P<depth>[-0-9]+)"
+ )
+
+ attaching_regex = re.compile(
+ r"^Attaching.*"
+ )
+
+ # Get all counts. That way we know how many timers each thread used.
+ for line in fileinput.input(files=files):
+ line = line.rstrip()
+
+ m = re.fullmatch(duration_regex, line)
+ if m:
+ tid = int(m.group("tid"))
+ index = int(m.group("index"))
+ duration_str = m.group("duration_us")
+ duration = int(m.group("duration_us"))
+
+ if not tid in timer_counts:
+ timer_counts[tid] = index
+ else:
+ timer_counts[tid] = max(timer_counts[tid], index)
+
+ # Allocate enough timers to fit the trace.
+ for tid, count in timer_counts.items():
+ all_timers[tid] = [None] * (count + 1)
+
+ # Populate the trace.
+ for line in fileinput.input(files=files):
+ line = line.rstrip()
+
+ m = re.fullmatch(name_regex, line)
+ if m:
+ tid = int(m.group("tid"))
+ index = int(m.group("index"))
+ name = m.group("name")
+ if all_timers[tid][index] == None:
+ all_timers[tid][index] = BpfTimer("", 0, -1, -1)
+ all_timers[tid][index].name = name
+ continue
+
+ m = re.fullmatch(start_time_regex, line)
+ if m:
+ tid = int(m.group("tid"))
+ index = int(m.group("index"))
+ start_time = int(m.group("start_time_us"))
+ if all_timers[tid][index] == None:
+ all_timers[tid][index] = BpfTimer("", 0, -1, -1)
+ all_timers[tid][index].start_time_us = start_time
+ continue
+
+ m = re.fullmatch(duration_regex, line)
+ if m:
+ tid = int(m.group("tid"))
+ index = int(m.group("index"))
+ duration = int(m.group("duration_us"))
+ if all_timers[tid][index] == None:
+ all_timers[tid][index] = BpfTimer("", 0, -1, -1)
+ all_timers[tid][index].duration_us = duration
+ continue
+
+ m = re.fullmatch(depth_regex, line)
+ if m:
+ tid = int(m.group("tid"))
+ index = int(m.group("index"))
+ depth = int(m.group("depth"))
+ if all_timers[tid][index] == None:
+ all_timers[tid][index] = BpfTimer("", 0, -1, -1)
+ all_timers[tid][index].depth = depth
+ continue
+
+ if re.fullmatch(count_regex, line):
+ # Skip this case. It's already been processed.
+ continue
+ if re.fullmatch(attaching_regex, line):
+ # Skip "Attaching XX probes..."
+ continue
+ if not line:
+ # Skip empty strings.
+ continue
+
+ raise ValueError("Invalid input, '%s'" % (line))
+
+ root = BpfResult("", 0, 0, 0, 0, 0, 1, 1, -1, -1)
+ results = []
+ for tid, timers in all_timers.items():
+ merge_timers(root, tid, timers)
+ print_results(root, results)
+
+ if fileinput.fileno() == 0:
+ raise ValueError("Expected a file to read.")
+
+ if fileinput.fileno() > 1:
+ raise ValueError("Too many files read. Expected 1")
+
+def main() -> None:
+ """Main function."""
+
+ if len(sys.argv) <= 1:
+ print("Error: Not enough command-line arguments. Expected an input file", file=sys.stderr)
+ sys.exit(1)
+
+ generate_from_log(sys.argv[1:])
+
+
+if __name__ == "__main__":
+ main()
diff --git a/tools/bpftrace/instrumented_profiler/samples/kvm_trace.bt b/tools/bpftrace/instrumented_profiler/samples/kvm_trace.bt
new file mode 100644
index 00000000000000..bd341e408570ec
--- /dev/null
+++ b/tools/bpftrace/instrumented_profiler/samples/kvm_trace.bt
@@ -0,0 +1,197 @@
+#define usecs (nsecs / 1000)
+#define msecs (nsecs / 1000 / 1000)
+#define DURATION_UNSET ((uint64)-1)
+
+config = { max_map_keys=4194304; }
+
+macro INIT_MAPS(@trace_stack_top, @timer_count)
+{
+ @trace_stack_top[0] = 0;
+ @timer_count[0] = 0;
+}
+
+macro CLEAR_MAPS(@trace_stack, @trace_stack_top, @timer_count)
+{
+ clear(@trace_stack);
+ clear(@trace_stack_top);
+ clear(@timer_count);
+}
+
+macro START_TIMER(name, @timer_name, @trace_stack, @timer_start, @timer_duration,
+ @timer_depth, @timer_count, @trace_stack_top)
+{
+ @timer_name[tid, @timer_count[tid]] = name;
+ @trace_stack[tid, @trace_stack_top[tid]] = @timer_count[tid];
+ @timer_start[tid, @timer_count[tid]] = usecs;
+ @timer_duration[tid, @timer_count[tid]] = DURATION_UNSET;
+ @timer_depth[tid, @timer_count[tid]] = @trace_stack_top[tid];
+ @timer_count[tid]++;
+ @trace_stack_top[tid]++;
+}
+
+/*
+ * Unfortunately branch statements crash the bpftrace compiler. As a result,
+ * the branch has been moved directly into the probe. Reverse this if the
+ * compiler ever gets that fixed.
+ */
+macro STOP_TIMER(@trace_stack_top, @trace_stack, @timer_duration, @timer_start)
+{
+ $idx = @trace_stack[tid, --@trace_stack_top[tid]];
+ @timer_duration[tid, $idx] = usecs - @timer_start[tid, $idx];
+}
+
+BEGIN
+{
+ INIT_MAPS(@trace_stack_top, @timer_count);
+}
+
+/*
+ * Time 'kvm_sched_in()'.
+ *
+ * Check: sudo grep kvm_sched_in /proc/kallsyms
+ */
+kfunc:kvm_sched_in
+{
+ START_TIMER("kvm_sched_in",
+ @timer_name, @trace_stack, @timer_start, @timer_duration,
+ @timer_depth, @timer_count, @trace_stack_top);
+}
+kretfunc:kvm_sched_in
+{
+ if (@trace_stack_top[tid] > 0) {
+ STOP_TIMER(@trace_stack_top, @trace_stack, @timer_duration, @timer_start);
+ }
+}
+
+/*
+ * Time 'kvm_sched_out()'.
+ *
+ * Check: sudo grep kvm_sched_out /proc/kallsyms
+ */
+kfunc:kvm_sched_out
+{
+ START_TIMER("kvm_sched_out",
+ @timer_name, @trace_stack, @timer_start, @timer_duration,
+ @timer_depth, @timer_count, @trace_stack_top);
+}
+
+kretfunc:kvm_sched_out
+{
+ if (@trace_stack_top[tid] > 0) {
+ STOP_TIMER(@trace_stack_top, @trace_stack, @timer_duration, @timer_start);
+ }
+}
+
+/*
+ * Time 'kvm_arch_vcpu_load()'.
+ *
+ * Check: sudo grep kvm_arch_vcpu_load /proc/kallsyms
+ */
+kfunc:kvm_arch_vcpu_load
+{
+ START_TIMER("kvm_arch_vcpu_load",
+ @timer_name, @trace_stack, @timer_start, @timer_duration,
+ @timer_depth, @timer_count, @trace_stack_top);
+}
+kretfunc:kvm_arch_vcpu_load
+{
+ if (@trace_stack_top[tid] > 0) {
+ STOP_TIMER(@trace_stack_top, @trace_stack, @timer_duration, @timer_start);
+ }
+}
+
+/*
+ * Time 'kvm_arch_vcpu_put()'.
+ *
+ * Check: sudo grep kvm_arch_vcpu_put /proc/kallsyms
+ */
+kfunc:kvm_arch_vcpu_put
+{
+ START_TIMER("kvm_arch_vcpu_put",
+ @timer_name, @trace_stack, @timer_start, @timer_duration,
+ @timer_depth, @timer_count, @trace_stack_top);
+}
+kretfunc:kvm_arch_vcpu_put
+{
+ if (@trace_stack_top[tid] > 0) {
+ STOP_TIMER(@trace_stack_top, @trace_stack, @timer_duration, @timer_start);
+ }
+}
+
+/*
+ * Time 'KVM_RUN', i.e. kvm_arch_vcpu_ioctl_run().
+ *
+ * Check: sudo grep kvm_arch_vcpu_ioctl_run /proc/kallsyms
+ */
+kfunc:kvm_arch_vcpu_ioctl_run
+{
+ START_TIMER("kvm_arch_vcpu_ioctl_run",
+ @timer_name, @trace_stack, @timer_start, @timer_duration,
+ @timer_depth, @timer_count, @trace_stack_top);
+}
+kretfunc:kvm_arch_vcpu_ioctl_run
+{
+ if (@trace_stack_top[tid] > 0) {
+ STOP_TIMER(@trace_stack_top, @trace_stack, @timer_duration, @timer_start);
+ }
+}
+
+/*
+ * Time how long a guest runs using tracepoints "kvm_entry" and "kvm_exit".
+ */
+tracepoint:kvm:kvm_entry
+{
+ START_TIMER("run_guest",
+ @timer_name, @trace_stack, @timer_start, @timer_duration,
+ @timer_depth, @timer_count, @trace_stack_top);
+}
+tracepoint:kvm:kvm_exit
+{
+ if (@trace_stack_top[tid] > 0) {
+ STOP_TIMER(@trace_stack_top, @trace_stack, @timer_duration, @timer_start);
+ }
+}
+
+/*
+ * Time 'kvm_vcpu_block()'.
+ *
+ * Check: sudo grep kvm_vcpu_block /proc/kallsyms
+ */
+kfunc:kvm_vcpu_block
+{
+ START_TIMER("kvm_vcpu_block",
+ @timer_name, @trace_stack, @timer_start, @timer_duration,
+ @timer_depth, @timer_count, @trace_stack_top);
+}
+kretfunc:kvm_vcpu_block
+{
+ if (@trace_stack_top[tid] > 0) {
+ STOP_TIMER(@trace_stack_top, @trace_stack, @timer_duration, @timer_start);
+ }
+}
+
+/*
+ * Time 'kvm_mmu_page_fault()'.
+ *
+ * Check: sudo grep kvm_mmu_page_fault /proc/kallsyms
+ */
+kfunc:kvm_mmu_page_fault
+{
+ START_TIMER("kvm_vcpu_block",
+ @timer_name, @trace_stack, @timer_start, @timer_duration,
+ @timer_depth, @timer_count, @trace_stack_top);
+}
+kretfunc:kvm_mmu_page_fault
+{
+ if (@trace_stack_top[tid] > 0) {
+ STOP_TIMER(@trace_stack_top, @trace_stack, @timer_duration, @timer_start);
+ }
+}
+
+/*
+ * Dump the results to stdout.
+ */
+END
+{
+ CLEAR_MAPS(@trace_stack, @trace_stack_top, @timer_count);
+}
diff --git a/tools/bpftrace/instrumented_profiler/samples/vfio_trace.bt b/tools/bpftrace/instrumented_profiler/samples/vfio_trace.bt
new file mode 100644
index 00000000000000..3b8cb7ff6210de
--- /dev/null
+++ b/tools/bpftrace/instrumented_profiler/samples/vfio_trace.bt
@@ -0,0 +1,315 @@
+#define usecs (nsecs / 1000)
+#define msecs (nsecs / 1000 / 1000)
+#define DURATION_UNSET ((uint64)-1)
+
+config = { max_map_keys=4194304; }
+
+macro INIT_MAPS(@trace_stack_top, @timer_count)
+{
+ @trace_stack_top[0] = 0;
+ @timer_count[0] = 0;
+}
+
+macro CLEAR_MAPS(@trace_stack, @trace_stack_top, @timer_count)
+{
+ clear(@trace_stack);
+ clear(@trace_stack_top);
+ clear(@timer_count);
+}
+
+macro START_TIMER(name, @timer_name, @trace_stack, @timer_start, @timer_duration,
+ @timer_depth, @timer_count, @trace_stack_top)
+{
+ @timer_name[tid, @timer_count[tid]] = name;
+ @trace_stack[tid, @trace_stack_top[tid]] = @timer_count[tid];
+ @timer_start[tid, @timer_count[tid]] = usecs;
+ @timer_duration[tid, @timer_count[tid]] = DURATION_UNSET;
+ @timer_depth[tid, @timer_count[tid]] = @trace_stack_top[tid];
+ @timer_count[tid]++;
+ @trace_stack_top[tid]++;
+}
+
+/*
+ * Unfortunately branch statements crash the bpftrace compiler. As a result,
+ * the branch has been moved directly into the probe. Reverse this if the
+ * compiler ever gets that fixed.
+ */
+macro STOP_TIMER(@trace_stack_top, @trace_stack, @timer_duration, @timer_start)
+{
+ $idx = @trace_stack[tid, --@trace_stack_top[tid]];
+ @timer_duration[tid, $idx] = usecs - @timer_start[tid, $idx];
+}
+
+BEGIN
+{
+ INIT_MAPS(@trace_stack_top, @timer_count);
+}
+
+/*
+ * Time 'vfio_group_fops_unl_ioctl()'.
+ *
+ * VFIO_GROUP_GET_DEVICE_FD = 0x3b6a
+ *
+ * Check: sudo grep vfio_group_fops_unl_ioctl /proc/kallsyms
+ */
+kfunc:vfio_group_fops_unl_ioctl /args->cmd == 0x3b6a/
+{
+ START_TIMER("vfio_group_ioctl_get_device_fd",
+ @timer_name, @trace_stack, @timer_start, @timer_duration,
+ @timer_depth, @timer_count, @trace_stack_top);
+}
+kretfunc:vfio_group_fops_unl_ioctl /args->cmd == 0x3b6a/
+{
+ if (@trace_stack_top[tid] > 0) {
+ STOP_TIMER(@trace_stack_top, @trace_stack, @timer_duration, @timer_start);
+ }
+}
+
+/*
+ * Time 'vfio_df_ioctl_bind_iommufd()'.
+ *
+ * Check: sudo grep vfio_df_ioctl_bind_iommufd /proc/kallsyms
+ */
+kfunc:vfio_df_ioctl_bind_iommufd
+{
+ START_TIMER("vfio_df_ioctl_bind_iommufd",
+ @timer_name, @trace_stack, @timer_start, @timer_duration,
+ @timer_depth, @timer_count, @trace_stack_top);
+}
+kretfunc:vfio_df_ioctl_bind_iommufd
+{
+ if (@trace_stack_top[tid] > 0) {
+ STOP_TIMER(@trace_stack_top, @trace_stack, @timer_duration, @timer_start);
+ }
+}
+
+/*
+ * Time 'vfio_df_unbind_iommufd()'.
+ *
+ * Check: sudo grep vfio_df_unbind_iommufd /proc/kallsyms
+ */
+kfunc:vfio_df_unbind_iommufd
+{
+ START_TIMER("vfio_df_unbind_iommufd",
+ @timer_name, @trace_stack, @timer_start, @timer_duration,
+ @timer_depth, @timer_count, @trace_stack_top);
+}
+kretfunc:vfio_df_unbind_iommufd
+{
+ if (@trace_stack_top[tid] > 0) {
+ STOP_TIMER(@trace_stack_top, @trace_stack, @timer_duration, @timer_start);
+ }
+}
+
+/*
+ * Time 'vfio_df_open()'.
+ *
+ * Check: sudo grep vfio_df_open /proc/kallsyms
+ */
+kfunc:vfio_df_open
+{
+ START_TIMER("vfio_df_open",
+ @timer_name, @trace_stack, @timer_start, @timer_duration,
+ @timer_depth, @timer_count, @trace_stack_top);
+}
+kretfunc:vfio_df_open
+{
+ if (@trace_stack_top[tid] > 0) {
+ STOP_TIMER(@trace_stack_top, @trace_stack, @timer_duration, @timer_start);
+ }
+}
+
+/*
+ * Time 'pcie_flr()'.
+ *
+ * Check: sudo grep pcie_flr /proc/kallsyms
+ */
+kfunc:pcie_flr
+{
+ START_TIMER("pcie_flr",
+ @timer_name, @trace_stack, @timer_start, @timer_duration,
+ @timer_depth, @timer_count, @trace_stack_top);
+}
+kretfunc:pcie_flr
+{
+ if (@trace_stack_top[tid] > 0) {
+ STOP_TIMER(@trace_stack_top, @trace_stack, @timer_duration, @timer_start);
+ }
+}
+
+/*
+ * Time 'pci_dev_wait()'.
+ *
+ * Check: sudo grep pci_dev_wait /proc/kallsyms
+ */
+kfunc:pci_dev_wait
+{
+ START_TIMER("pci_dev_wait",
+ @timer_name, @trace_stack, @timer_start, @timer_duration,
+ @timer_depth, @timer_count, @trace_stack_top);
+}
+kretfunc:pci_dev_wait
+{
+ if (@trace_stack_top[tid] > 0) {
+ STOP_TIMER(@trace_stack_top, @trace_stack, @timer_duration, @timer_start);
+ }
+}
+
+/*
+ * Time 'vfio_iommu_type1_ioctl()' when 'VFIO_IOMMU_MAP_DMA' is called.
+ *
+ *
+ * VFIO_IOMMU_MAP_DMA = 0x3b71
+ *
+ * Check: sudo grep vfio_iommu_type1_ioctl /proc/kallsyms
+ */
+kfunc:vfio_iommu_type1_ioctl /args->cmd == 0x3b71/
+{
+ START_TIMER("vfio_iommu_type1_map_dma",
+ @timer_name, @trace_stack, @timer_start, @timer_duration,
+ @timer_depth, @timer_count, @trace_stack_top);
+}
+kretfunc:vfio_iommu_type1_ioctl /args->cmd == 0x3b71/
+{
+ if (@trace_stack_top[tid] > 0) {
+ STOP_TIMER(@trace_stack_top, @trace_stack, @timer_duration, @timer_start);
+ }
+}
+
+/*
+ * Time 'vfio_pin_map_dma()'.
+ *
+ * Check: sudo grep vfio_pin_map_dma /proc/kallsyms
+ */
+kfunc:vfio_pin_map_dma
+{
+ START_TIMER("vfio_pin_map_dma",
+ @timer_name, @trace_stack, @timer_start, @timer_duration,
+ @timer_depth, @timer_count, @trace_stack_top);
+}
+kretfunc:vfio_pin_map_dma
+{
+ if (@trace_stack_top[tid] > 0) {
+ STOP_TIMER(@trace_stack_top, @trace_stack, @timer_duration, @timer_start);
+ }
+}
+
+/*
+ * Time 'vfio_pin_pages_remote()'.
+ *
+ * Check: sudo grep vfio_pin_pages_remote /proc/kallsyms
+ */
+kfunc:vfio_pin_pages_remote
+{
+ START_TIMER("vfio_pin_pages_remote",
+ @timer_name, @trace_stack, @timer_start, @timer_duration,
+ @timer_depth, @timer_count, @trace_stack_top);
+}
+kretfunc:vfio_pin_pages_remote
+{
+ if (@trace_stack_top[tid] > 0) {
+ STOP_TIMER(@trace_stack_top, @trace_stack, @timer_duration, @timer_start);
+ }
+}
+
+/*
+ * Time 'vaddr_get_pfns()'.
+ *
+ * Check: sudo grep vaddr_get_pfns /proc/kallsyms
+ */
+kfunc:vaddr_get_pfns
+{
+ START_TIMER("vaddr_get_pfns",
+ @timer_name, @trace_stack, @timer_start, @timer_duration,
+ @timer_depth, @timer_count, @trace_stack_top);
+}
+kretfunc:vaddr_get_pfns
+{
+ if (@trace_stack_top[tid] > 0) {
+ STOP_TIMER(@trace_stack_top, @trace_stack, @timer_duration, @timer_start);
+ }
+}
+
+// /*
+// * Time 'iommu_map()'.
+// *
+// * Check: sudo grep iommu_map /proc/kallsyms
+// */
+// kfunc:iommu_map
+// {
+// START_TIMER("iommu_map",
+// @timer_name, @trace_stack, @timer_start, @timer_duration,
+// @timer_depth, @timer_count, @trace_stack_top);
+// }
+// kretfunc:iommu_map
+// {
+// if (@trace_stack_top[tid] > 0) {
+// STOP_TIMER(@trace_stack_top, @trace_stack, @timer_duration, @timer_start);
+// }
+// }
+
+
+
+/*
+ * Time 'vfio_iommu_type1_ioctl()' when 'VFIO_IOMMU_UNMAP_DMA' is called.
+ *
+ * VFIO_IOMMU_UNMAP_DMA = 0x3b72
+ *
+ * Check: sudo grep vfio_iommu_type1_ioctl /proc/kallsyms
+ */
+kfunc:vfio_iommu_type1_ioctl /args->cmd == 0x3b72/
+{
+ START_TIMER("vfio_iommu_type1_unmap_dma",
+ @timer_name, @trace_stack, @timer_start, @timer_duration,
+ @timer_depth, @timer_count, @trace_stack_top);
+}
+kretfunc:vfio_iommu_type1_ioctl /args->cmd == 0x3b72/
+{
+ if (@trace_stack_top[tid] > 0) {
+ STOP_TIMER(@trace_stack_top, @trace_stack, @timer_duration, @timer_start);
+ }
+}
+
+/*
+ * Time 'vfio_unmap_unpin()'.
+ *
+ * Check: sudo grep vfio_unmap_unpin /proc/kallsyms
+ */
+kfunc:vfio_unmap_unpin
+{
+ START_TIMER("vfio_unmap_unpin",
+ @timer_name, @trace_stack, @timer_start, @timer_duration,
+ @timer_depth, @timer_count, @trace_stack_top);
+}
+kretfunc:vfio_unmap_unpin
+{
+ if (@trace_stack_top[tid] > 0) {
+ STOP_TIMER(@trace_stack_top, @trace_stack, @timer_duration, @timer_start);
+ }
+}
+
+/*
+ * Time 'vfio_sync_unpin()'.
+ *
+ * Check: sudo grep vfio_sync_unpin /proc/kallsyms
+ */
+kfunc:vfio_sync_unpin
+{
+ START_TIMER("vfio_sync_unpin",
+ @timer_name, @trace_stack, @timer_start, @timer_duration,
+ @timer_depth, @timer_count, @trace_stack_top);
+}
+kretfunc:vfio_sync_unpin
+{
+ if (@trace_stack_top[tid] > 0) {
+ STOP_TIMER(@trace_stack_top, @trace_stack, @timer_duration, @timer_start);
+ }
+}
+
+/*
+ * Dump the results to stdout.
+ */
+END
+{
+ CLEAR_MAPS(@trace_stack, @trace_stack_top, @timer_count);
+}
|
| 3/2 | 2026/06/30 22:09 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 11306 output: 77 thoughts: 230 Thoughts: **WorthFuzzing=False: A Quick Assessment** Okay, here's the deal. I've got this patch in front of me, and my initial assessment is pretty straightforward. It looks like we're dealing with new profiling tools – specifically a Python script, `aggregate_bpf_results.py`, and two bpftrace scripts, `kvm_trace.bt` and `vfio_trace.bt` – all tucked away under `tools/bpftrace/instrumented_profiler/`. From what I can see, these are strictly for instrumentation and analysis; they don't seem to be touching any core kernel code, drivers, or even the underlying architectures. This isn't a functional change in the sense that it introduces new kernel behavior or modifies existing logic that needs to be heavily fuzzed. Just to be absolutely certain, I've taken a second look at the diff. I see the Python script and the two bt scripts, as expected. I'm not seeing any C code or any modifications that would affect the behavior of kernel subsystems. Therefore, my conclusion is clear. I'm going to set `WorthFuzzing` to `false` for this patch. I'll need to call `set-results` and ensure that's reflected correctly. No functional change here that warrants fuzzing. |
| 4/2 | 2026/06/30 22:10 | tool | set-results |
0mArgs:{
"EnableConfigs": [],
"FocusSymbols": [],
"Reasoning": "The patch only adds bpftrace scripts and a python script for profiling under tools/bpftrace/. It does not modify any core kernel logic, drivers, or architectures, and therefore does not introduce any functional changes that can be fuzzed.",
"WorthFuzzing": false
}Results: {
"EnableConfigs": null,
"FocusSymbols": [],
"Reasoning": "The patch only adds bpftrace scripts and a python script for profiling under tools/bpftrace/. It does not modify any core kernel logic, drivers, or architectures, and therefore does not introduce any functional changes that can be fuzzed.",
"WorthFuzzing": false
} |
| Total Calls | Total Tokens | Avg Tokens | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|
| Total Calls | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|