Skip to content

Commit

Permalink
task: add "ps" corelens module
Browse files Browse the repository at this point in the history
Co-authored-by: Partha Sarathi Satapathy <[email protected]>
Signed-off-by: Siddhi Katage <[email protected]>
  • Loading branch information
SiddhiK29 and pssatapathy-oracle committed Dec 19, 2023
1 parent 398a1e9 commit 65ddb41
Show file tree
Hide file tree
Showing 2 changed files with 176 additions and 3 deletions.
172 changes: 170 additions & 2 deletions drgn_tools/task.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,16 @@
and configurations.
"""
import argparse
from typing import Dict
from typing import Iterable
from typing import Optional

import drgn
from drgn import Object
from drgn import Program
from drgn.helpers.common.format import escape_ascii_string
from drgn.helpers.linux.cpumask import for_each_online_cpu
from drgn.helpers.linux.list import list_for_each_entry
from drgn.helpers.linux.percpu import per_cpu
from drgn.helpers.linux.pid import for_each_task
from drgn.helpers.linux.sched import cpu_curr
Expand All @@ -25,6 +28,12 @@
from drgn_tools.table import print_table
from drgn_tools.util import has_member

rss_task_dict_global: Dict[int, int] = {}
rss_mm_dict_global = {}
rss_task_dict: Dict[int, Optional[int]] = {}

ByteToKB = 1024


def nanosecs_to_secs(nanosecs: int) -> float:
"""
Expand Down Expand Up @@ -185,6 +194,139 @@ def get_command(task: Object) -> str:
return escape_ascii_string(task.comm.string_())


def get_ppid(task: Object) -> int:
"""
:returns: Parent PID of the task
"""
return task.parent.pid.value_()


def build_rss_global(prog: Program) -> None:
"""
:Build the global rsss table
O(N) logic, used n total ps rss list
"""
MM_FILEPAGES = prog.constant("MM_FILEPAGES")
MM_ANONPAGES = prog.constant("MM_ANONPAGES")
MM_SHMEMPAGES = prog.constant("MM_SHMEMPAGES")

for task in for_each_task(prog):
rss_task = task_filerss = task_anonrss = task_shmrss = 0

task_filerss = task.rss_stat.count[MM_FILEPAGES].value_()
task_anonrss = task.rss_stat.count[MM_ANONPAGES].value_()
task_shmrss = task.rss_stat.count[MM_SHMEMPAGES].value_()

rss_task += task_filerss + task_anonrss + task_shmrss

gid = task.tgid.value_()
try:
gid_rss = rss_task_dict_global[gid]
except KeyError:
gid_rss = 0
else:
rss_task += gid_rss

rss_task_dict_global[gid] = rss_task

try:
filerss = task.mm.rss_stat.count[MM_FILEPAGES].counter.value_()
anonrss = task.mm.rss_stat.count[MM_ANONPAGES].counter.value_()
shmrss = task.mm.rss_stat.count[MM_SHMEMPAGES].counter.value_()

rss_mm = filerss + anonrss + shmrss
except drgn.FaultError:
rss_mm = 0

rss_mm_dict_global[task.pid.value_()] = rss_mm


def get_rss(prog: Program, task: Object) -> int:
"""
:returns RSS value for a task
should be used for single task
"""
MM_FILEPAGES = prog.constant("MM_FILEPAGES")
MM_ANONPAGES = prog.constant("MM_ANONPAGES")
MM_SHMEMPAGES = prog.constant("MM_SHMEMPAGES")

try:
filerss = task.mm.rss_stat.count[MM_FILEPAGES].counter.value_()
anonrss = task.mm.rss_stat.count[MM_ANONPAGES].counter.value_()
shmrss = task.mm.rss_stat.count[MM_SHMEMPAGES].counter.value_()

rss_mm = filerss + anonrss + shmrss

except drgn.FaultError:
rss_mm = 0

gid = task.tgid.value_()

rss_task = rss_task_dict.get(gid)

if gid in rss_task_dict:
rss_task = rss_task_dict[gid]
else:
rss_task = 0
ltask = task.group_leader

task_filerss = ltask.rss_stat.count[MM_FILEPAGES].value_()
task_anonrss = ltask.rss_stat.count[MM_ANONPAGES].value_()
task_shmrss = ltask.rss_stat.count[MM_SHMEMPAGES].value_()

rss_task += task_filerss + task_anonrss + task_shmrss

for gtask in list_for_each_entry(
"struct task_struct",
task.group_leader.thread_group.address_of_(),
"thread_group",
):
task_filerss = gtask.rss_stat.count[MM_FILEPAGES].value_()
task_anonrss = gtask.rss_stat.count[MM_ANONPAGES].value_()
task_shmrss = gtask.rss_stat.count[MM_SHMEMPAGES].value_()

rss_task += task_filerss + task_anonrss + task_shmrss

rss_task_dict[gid] = rss_task

rss = rss_mm + rss_task
page_size = prog["PAGE_SIZE"].value_()
rss_kb = (rss * page_size) // ByteToKB

return rss_kb


def get_pct_mem(prog: Program, task: Object) -> str:
"""
: returns %MEM value
"""
gid = task.tgid.value_()
rss_task = rss_task_dict_global[gid]
rss_mm = rss_mm_dict_global[task.pid.value_()]
tot_rss = rss_mm + rss_task

page_shift = prog["PAGE_SHIFT"].value_()
page_offset_base = prog["page_offset_base"].value_()
high_mem = prog["high_memory"].value_()
total_pages = (high_mem - page_offset_base) >> page_shift
mem = (tot_rss * 100) / total_pages
pct_mem = "%.1f" % mem

return pct_mem


def get_vmem(prog: Program, task: Object) -> float:
"""
returns VSZ value
"""
try:
page_size = prog["PAGE_SIZE"].value_()
vmem = (task.mm.total_vm.value_() * page_size) // ByteToKB
except drgn.FaultError:
vmem = 0
return vmem


def show_tasks_last_runtime(tasks: Iterable[Object]) -> None:
"""
Display task information in their last arrival order.
Expand All @@ -203,6 +345,30 @@ def show_tasks_last_runtime(tasks: Iterable[Object]) -> None:
print_table(rows)


def show_taskinfo(prog: Program, tasks: Iterable[Object]) -> None:
"""
Display task information.
"""
rows = [["PID", "PPID", "CPU", "TASK", "ST", "%MEM", "VSZ", "RSS", "COMM"]]
tasks = list(tasks)
tasks.sort(key=get_pid)
for t in tasks:
rows.append(
[
str(get_pid(t)),
str(get_ppid(t)),
str(task_cpu(t)),
hex(t.value_()),
task_state_to_char(t),
get_pct_mem(prog, t),
str(get_vmem(prog, t)),
str(get_rss(prog, t)),
get_command(t),
]
)
print_table(rows)


class Taskinfo(CorelensModule):
"""
Corelens Module for ps
Expand All @@ -221,7 +387,9 @@ def add_args(self, parser: argparse.ArgumentParser) -> None:
)

def run(self, prog: Program, args: argparse.Namespace) -> None:
build_rss_global(prog)
tasks = for_each_task(prog)
if args.last_run:
show_tasks_last_runtime(for_each_task(prog))
show_tasks_last_runtime(tasks)
else:
raise NotImplementedError("currently, only ps -m is implemented")
show_taskinfo(prog, tasks)
7 changes: 6 additions & 1 deletion tests/test_task.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
# Copyright (c) 2023, Oracle and/or its affiliates.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
from drgn.helpers.linux.pid import find_task
from drgn.helpers.linux.pid import for_each_task

from drgn_tools import task


def test_task_last_runtime(prog):
task.show_tasks_last_runtime(for_each_task(prog))
tasks = for_each_task(prog)

task.show_tasks_last_runtime(tasks)
task.show_taskinfo(prog, tasks)
task.get_rss(prog, find_task(prog, 1))

0 comments on commit 65ddb41

Please sign in to comment.