Skip to content

Commit 097775d

Browse files
richl9biger410
authored andcommitted
lockup: detect tasks waiting for RCU grace period and possible blockers
Orabug: 37899681 Signed-off-by: Richard Li <[email protected]>
1 parent 0272a41 commit 097775d

File tree

1 file changed

+49
-6
lines changed

1 file changed

+49
-6
lines changed

drgn_tools/lockup.py

Lines changed: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
1-
# Copyright (c) 2024, Oracle and/or its affiliates.
1+
# Copyright (c) 2025, Oracle and/or its affiliates.
22
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
33
import argparse
4+
import typing
45

6+
import drgn
57
from drgn import Program
68
from drgn.helpers.common import escape_ascii_string
79
from drgn.helpers.linux.cpumask import for_each_online_cpu
810
from drgn.helpers.linux.percpu import per_cpu
911

1012
from drgn_tools.bt import bt
13+
from drgn_tools.bt import bt_has_any
1114
from drgn_tools.corelens import CorelensModule
15+
from drgn_tools.table import print_table
1216
from drgn_tools.task import task_lastrun2now
1317
from drgn_tools.util import timestamp_str
1418

@@ -17,7 +21,7 @@ def scan_lockup(
1721
prog: Program, min_run_time_seconds: int = 1, skip_swapper: bool = True
1822
) -> None:
1923
"""
20-
Scan potential lockups on cpus.
24+
Scan potential lockups on cpus and tasks waiting for RCU.
2125
2226
:param prog: drgn program
2327
:param min_run_time_seconds: int
@@ -47,13 +51,52 @@ def scan_lockup(
4751
print()
4852
nr_processes += 1
4953

50-
print(
51-
f"We found {nr_processes} processes running more than {min_run_time_seconds} seconds."
52-
)
54+
print(f"We found {nr_processes} processes running more than {min_run_time_seconds} seconds")
55+
56+
dump_tasks_waiting_rcu_gp(prog, min_run_time_seconds)
57+
58+
59+
def tasks_waiting_rcu_gp(prog: Program) -> typing.List[typing.Tuple[drgn.Object, drgn.StackFrame]]:
60+
"""
61+
Detects tasks waiting RCU grace period
62+
63+
:param prog: drgn program
64+
"""
65+
rcu_gp_fn = ["percpu_ref_switch_to_atomic_sync"]
66+
return bt_has_any(prog, rcu_gp_fn)
67+
68+
69+
def dump_tasks_waiting_rcu_gp(prog: Program, min_run_time_seconds: int) -> None:
70+
"""
71+
Prints tasks waiting on rcu grace period with details
72+
73+
:param prog: drgn program
74+
:param min_run_time_seconds: int
75+
"""
76+
tasks_waiting = tasks_waiting_rcu_gp(prog)
77+
output = [["TASK", "NAME", "PID", "PENDING_TIME"]]
78+
tasks_pids = set() # remove duplicates
79+
if tasks_waiting:
80+
for t, _ in tasks_waiting:
81+
pending_time = timestamp_str(task_lastrun2now(t))
82+
pid = t.pid.value_()
83+
if pid not in tasks_pids and task_lastrun2now(t) > min_run_time_seconds * 1e9:
84+
output.append(
85+
[
86+
hex(t.value_()),
87+
escape_ascii_string(t.comm.string_()),
88+
pid,
89+
pending_time
90+
]
91+
)
92+
tasks_pids.add(pid)
93+
print()
94+
print(f"We found below tasks waiting for rcu grace period over {min_run_time_seconds} seconds:")
95+
print_table(output)
5396

5497

5598
class LockUp(CorelensModule):
56-
"""Print tasks which have been on-cpu for too long"""
99+
"""Print tasks which have been on-cpu for too long (possible RCU blockers) and tasks waiting RCU grace period if any"""
57100

58101
name = "lockup"
59102

0 commit comments

Comments
 (0)