Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tools: sof-ipc-timer.py: Timings of module init and config IPC loggings #1255

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

jsarha
Copy link
Contributor

@jsarha jsarha commented Feb 25, 2025

The sof-ipc-timer collects module initialization and configuration timings from 'journalctl -k -o short-precise' output if SOF IPC debug is enabled.

The sof-ipc-timer collects module initialization and configuration
timings from 'journalctl -k -o short-precise' output if SOF IPC debug
is enabled.

Signed-off-by: Jyri Sarha <jyri.sarha@linux.intel.com>
@jsarha jsarha requested a review from a team as a code owner February 25, 2025 19:28
Copy link
Collaborator

@marc-hb marc-hb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't look at any of the logic, just some general Python advice.

def main():
args = parse_args()

with open(args.filename, 'r', encoding='utf8') as file:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMHO a tool like this should really be "stdin-capable". Or even stdin-only which is flexible enough:

journalctl -k | tools/sof-ipc-timer.py
tools/sof-ipc-timer.py < capture.txt
for line in sys.stdin:

``

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@marc-hb currently the file is read twice (at least AFAICS), wouldn't be very convenient with stdin

mod_id = None
start = None
for line in f:
if match_obj := re.search(r" ipc tx ( |reply|done )", line):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The massive length of the indented block is a sure sign it should split into separate functions. Small functions also make interactive testing possible, that's what the "__main__" idiom below is for:

ipython3

>> import sof-ipc-timer
>> small_function("some log line")

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The massive length of the indented block is a sure sign it should split into separate functions.

@lgirdwood 's comment just reminded me of something: naming is hard (c), but when you find good function names they act like a Table of Contents that lets you quickly get the gist of what is happening without reading the whole code/book.

Functions are not just about code re-use, they're useful even when you invoke them only once; for testability and readability.

return f'{self.ppln_id}-{self.comp_id:#08x}'

def read_comp_data(f):
'''Process the dmesg to get the component ID to component name mapping,
Copy link
Collaborator

@marc-hb marc-hb Feb 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
'''Process the dmesg to get the component ID to component name mapping,
'''Process the kernel logs to get the component ID to component name mapping,

dmesg wraps around. journalctl -k does not.

journalctl can focus on certain intervals, dmesg cannot AFAIK. For instance journalctl --since $test_start_time

dmesg? Just say no :-)

Copy link
Member

@lgirdwood lgirdwood left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just needs some more readability for me.

Comment on lines +87 to +123
# msg_type shoule be either " ", "reply", or "done "
msg_type = line[match_obj.span()[0] + 8 : match_obj.span()[1]]
msg_part = line[span_end_pos:].split()
primary = int(msg_part[1].split('|')[0], 16)
extension = int(msg_part[1].split('|')[1].rstrip(":"), 16)
if msg_part[2] == "MOD_INIT_INSTANCE" or msg_part[2] == "MOD_LARGE_CONFIG_SET":
if msg_type == " ":
mod_id = primary & 0xFFFFFF
if mod_id == 0:
mod_id = None
continue
start = usecs
if mod_id == None:
continue
comp = comp_data[mod_id]
if msg_type == "reply" and args.reply_timings:
if msg_part[2] == "MOD_INIT_INSTANCE":
print("%s:\tinit reply\t%d us" % (comp.wname, usecs - start))
elif msg_part[2] == "MOD_LARGE_CONFIG_SET":
print("%s:\tconf reply\t%d us" % (comp.wname, usecs - start))
start = usecs
elif msg_type == "done ":
module_id = ""
pipeline_id = ""
if args.module_id:
module_id = "\tmodule id: " + format(mod_id, '#08x')
if args.pipeline_id:
pipeline_id = "\tpipeline id: " + str(comp.ppln_id)
if msg_part[2] == "MOD_INIT_INSTANCE":
print("%s:\tinit done\t%d us%s%s" %
(comp.wname, usecs - start, module_id, pipeline_id))
elif msg_part[2] == "MOD_LARGE_CONFIG_SET":
print("%s:\tconf done\t%d us%s%s" %
(comp.wname, usecs - start, module_id, pipeline_id))
mod_id = None
start = None
end = None
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could also do with more inline comments describing each stage

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants