Skip to content

add bpftrace scripts to track performance and behavior of SOF functions in the kernel - #877

Merged
marc-hb merged 2 commits into
thesofproject:mainfrom
nklayman:bpf-tracing
Jul 9, 2022
Merged

marc-hb merged 2 commits into
thesofproject:mainfrom
nklayman:bpf-tracing

Conversation

@nklayman

@nklayman nklayman commented Mar 10, 2022 •

Copy link
Copy Markdown
Contributor

Signed-off-by: Noah Klayman noah.klayman@intel.com

This PR adds some example bpftrace scripts to track performance and behavior of various SOF functions in the kernel. To run them, you'll need to install bpftrace, then run the script with bpftrace [path to script]. If you want to use the hda_irq scripts, you'll need to be running this kernel pr.

Example output from suspend_resume_time.bt:

❯ bpftrace ./kernel_tracing/bpftrace_scripts/suspend_resume_time.bt
Attaching 5 probes...
kprobe:sof_resume (runtime) started
kretprobe:sof_resume (runtime) finished, took 132135788 nsecs
kprobe:sof_suspend (system) started
kretprobe:sof_suspend (system) finished, took 738362 nsecs
kprobe:sof_resume (system) started
kretprobe:sof_resume (system) finished, took 197517950 nsecs
kprobe:sof_suspend (runtime) started
kretprobe:sof_suspend (runtime) finished, took 32807764 nsecs
kprobe:sof_resume (runtime) started
kretprobe:sof_resume (system) finished, took 187189967 nsecs
kprobe:sof_resume (system) started
kretprobe:sof_resume (system) finished, took 180462467 nsecs
kprobe:sof_suspend (runtime) started
kretprobe:sof_suspend (runtime) finished, took 32866837 nsecs
kprobe:sof_resume (runtime) started
kprobe:sof_resume (system) started
kretprobe:sof_resume (system) finished, took 188085072 nsecs
kprobe:sof_resume (runtime) started
kretprobe:sof_resume (system) finished, took 188318490 nsecs
kprobe:sof_suspend (runtime) started
kretprobe:sof_suspend (runtime) finished, took 32849861 nsecs
^C


@usecs[kretprobe:sof_resume, runtime]: 
[128K, 256K)           5 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@|

@usecs[kretprobe:sof_resume, system]: 
[128K, 256K)           5 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@|

@usecs[kretprobe:sof_suspend, runtime]: 
[16K, 32K)             2 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@                  |
[32K, 64K)             3 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@|

@usecs[kretprobe:sof_suspend, system]: 
[256, 512)             1 |@@@@@@@@@@@@@                                       |
[512, 1K)              4 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@|

Additionally, this PR includes a Python script to collect metrics and run conditions on them, see kernel_tracing/metric_evaluation. It's intended to be used on the CI machines to prevent performance regressions.

@plbossart plbossart left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

looks quite promising @nklayman, minor nit-picks to improve the commit below.

Comment thread tracing/suspend_resume_time.bt
Comment thread tracing/suspend_resume_time.bt
@plbossart

Copy link
Copy Markdown
Member

added the 'kernel maintainer' team for feedback.

@plbossart
plbossart requested a review from lgirdwood March 11, 2022 15:30

@marc-hb marc-hb left a comment •

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Can you rename the directory to something more specific, maybe sof-test/linux/tracing/ or sof-test/ktracing? We have a lot of "tracing" already and sof-test/tracing/ sounds definitely like firmware tracing.

Can you add a README with some pointers, context/purpose/intro/etc. or if too short for a README then some comments in this new .bt file? For now it's very... "raw".

@nklayman

Copy link
Copy Markdown
Contributor Author

Just added a readme and updated the directory structure to make it more clear what this is.

@plbossart

Copy link
Copy Markdown
Member

Just added a readme and updated the directory structure to make it more clear what this is.

it's better to squash all the commits together and do a git push --force to have a single commit, no?

@marc-hb

marc-hb commented Mar 11, 2022

Copy link
Copy Markdown
Collaborator

it's better to squash all the commits together and do a git push --force to have a single commit, no?

@nklayman has just used Github the way it was designed to be used, not the way we use it.

Github tolerates but does not really support rewriting history and force pushes. Github is optimized for a single commit per pull request + fixup commits just like @nklayman did. For instance try the "View changes" button above: this time it works! Same for many other Github features.

More info at zephyrproject-rtos/zephyr#39194

Note Github has an option to squash all commits right before merging. Not sure what is the final commit message then.

@marc-hb
marc-hb requested a review from greg-intel March 11, 2022 22:13
@nklayman

nklayman commented Mar 11, 2022 •

Copy link
Copy Markdown
Contributor Author

I prefer to push individually and then squash into one commit before merging, either manually or through the Github UI. Otherwise, it's a lot harder to tell what's changed and see what code review comments refer to. I can do the single commit method if you'd prefer, but as long as we squash before merging the end result is the same, and the process to get there is a bit better.

Edit: Github asks you to choose the final commit message/description when you squash and merge.

@marc-hb

marc-hb commented Mar 12, 2022 •

Copy link
Copy Markdown
Collaborator

As long as the goal is to have a single commit in the end, I totally agree the process is much better and the end result is the same. It is the way Github is designed to be used after all!

The problem is purely about consistency: as Github PRs do not support reviewing multiple commits "natively", this means learning how to use Github TWICE, in two different ways. One for reviewing a single commit (in the end), and a second workflow for reviewing multiple commits (in the end).

I don't mind at all but I've been the "local git guru" in many teams for many years so I'm not representative. I've seen many, many people struggling with ONE way to use git or Github.

I've also seen some totally blank stares from people very experienced with one way when trying to explain them the other way.

@nklayman nklayman changed the title add suspend and resume time tracking with bpftrace add bpftrace scripts to track performance and behavior of SOF functions in the kernel Mar 15, 2022

@marc-hb marc-hb left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Don't forget to run pylint now and then. It's not gospel but it's pretty good.

Comment thread kernel_tracing/metric_evaluation/test.py Outdated
Comment thread kernel_tracing/metric_evaluation/test.py Outdated
Comment thread kernel_tracing/metric_evaluation/test.py Outdated
Comment thread kernel_tracing/metric_evaluation/test.py Outdated
"@avg[kretprobe:sof_resume, runtime] < 150000",
"@avg[kretprobe:sof_resume, system] < 200000",
"@avg[kretprobe:sof_suspend, runtime] < 50000",
"@avg[kretprobe:sof_suspend, system] < 1000"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Does @avg mean "average"? Averages hide intermittent bugs, they're not very interesting.

https://bravenewgeek.com/everything-you-know-about-latency-is-wrong/

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes, it means average. However, it's purely a demo (I just made the numbers up), so it doesn't matter much. I figured it'd be better to let those more familiar with SOF figure out the real metrics/conditions to use. I assume we'll end up with some sort of script to generate test cases with device-specific conditions and tests anyways. I've renamed the spec file to sample_spec.json to make it more clear that it's just a demo.

Comment thread kernel_tracing/metric_evaluation/test.py Outdated
Comment thread kernel_tracing/metric_evaluation/test.py Outdated
Comment thread kernel_tracing/metric_evaluation/test.py Outdated
Comment thread kernel_tracing/metric_evaluation/test.py Outdated
Comment thread kernel_tracing/metric_evaluation/test.py Outdated
# Check if line is outputting a variable from the script
# bpftrace output format is `@name[key1, key2, ...] = val` (keys are optional)
if re.match("@.*: .*", line):
key, val = line.split(": ", 1)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

So an entire @name[key1, key2, ...] is a valid "key"? That's quite confusing. Could one of them not be called "key"?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

name would be the name of the map, which can be indexed by any number of keys. ie @max_time[ipc, stream] = 500 would be the map max_time indexed by two keys, in this case the value 500 is tied to keys ipc and stream. It's essentially a flattened nested map.

Comment thread kernel_tracing/metric_evaluation/test.py Outdated
Comment thread kernel_tracing/metric_evaluation/test.py Outdated
Comment thread kernel_tracing/metric_evaluation/test.py Outdated
Comment thread kernel_tracing/metric_evaluation/test.py Outdated
@nklayman
nklayman force-pushed the bpf-tracing branch 2 times, most recently from f2c6315 to 94434fd Compare April 9, 2022 05:53
@nklayman

nklayman commented Apr 9, 2022

Copy link
Copy Markdown
Contributor Author

@marc-hb all your comments should be addressed in the latest update. I switched it over to the one-condition-per-test format that you prefer, and applied the small changes. @plbossart I also squashed the commits together into two as you requested, one for the bpftrace scripts themselves and one for the metric evaluation part.

Marking this "ready for review" now as it's at a good state for others to look at. The metric evaluation script will most likely need some changes to make it work in the CI, but that's probably a better task for the CI devs rather than myself.

@nklayman
nklayman marked this pull request as ready for review April 9, 2022 05:59
@nklayman
nklayman requested a review from a team as a code owner April 9, 2022 05:59

@marc-hb marc-hb left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I think the high-level design looks great: concise, scalable and extremely promising.

On the other hand I have a number of readability concerns and when trying it I found some usability issues.

I tried to run test.py as a regular, non-root user and I got this very clear and fatal looking error but then test.py hangs forever:

collecting ... ERROR: bpftrace currently only supports running as the root user.

Similarly, I tried to run as root but without the required CONFIG_ and again I got a very clear and fatal looking error and test.py hangs forever:

collecting ... modprobe: FATAL: Module kheaders not found in directory /lib/modules/9.9.9-rc9softest

BTW would it be possible to have a sample that does nothing at all and can be run on any Linux system with very minimal CONFIG_ dependency? For the sole purpose of testing the framework, the user interface, relative directory issues, etc.

Also, some sample output in the commit message or even in the README would be great.

Comment thread kernel_tracing/metric_evaluation/conftest.py Outdated
Comment thread kernel_tracing/metric_evaluation/conftest.py Outdated
Comment thread kernel_tracing/metric_evaluation/conftest.py Outdated
Comment thread kernel_tracing/metric_evaluation/conftest.py Outdated
Comment thread kernel_tracing/metric_evaluation/sample_spec.json Outdated
Comment thread kernel_tracing/metric_evaluation/conftest.py Outdated
Comment thread kernel_tracing/readme.md Outdated
Comment thread kernel_tracing/metric_evaluation/test.py Outdated
Comment thread kernel_tracing/metric_evaluation/test.py Outdated
Comment thread kernel_tracing/metric_evaluation/test.py Outdated
Comment thread kernel_tracing/metric_evaluation/test.py Outdated

@marc-hb marc-hb left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

$ pylint kernel_tracing/metric_evaluation/test.py 
************* Module test
kernel_tracing/metric_evaluation/test.py:15:4: C0103: Variable name "conditionWithVars" doesn't conform to snake_case naming style (invalid-name)
kernel_tracing/metric_evaluation/test.py:17:8: C0103: Variable name "conditionWithVars" doesn't conform to snake_case naming style (invalid-name)

Comment thread kernel_tracing/metric_evaluation/conftest.py Outdated
@nklayman

nklayman commented Apr 14, 2022 •

Copy link
Copy Markdown
Contributor Author

@marc-hb Thanks for the review! Almost all your comments should be addressed now. The no-dependency test option is a bit tricky because the script can't really work without bpftrace. If you're okay with having that a dependency I could make a very simple case, otherwise I could try aliasing bpftrace to echo out some sample output so there's truly no dependencies. Let me know which one you prefer.

Also, I'm realising this script probably requires a readme of its own. I'll add one when I get the chance, probably this weekend.

@marc-hb

marc-hb commented Apr 14, 2022

Copy link
Copy Markdown
Collaborator

The no-dependency test option is a bit tricky because the script can't really work without bpftrace

The dependency on bpftrace user space is not a problem because it's as simple as apt install bpftrace. The annoying part is the kernel part. Reconfiguring and rebooting a kernel before submitting a fix for a minor python warning is not convenient. So I'm just wondering if it would be possible to have some kind of "bpftrace no-op" example / test case for this = anything that does not require a new kernel. If bpftrace has some hard kernel dependencies that are typically not available in stock kernels provided by distributions then too bad forget it. Maybe we could add some sort of "mock bpftrace" later.

(I've not looked at the new version yet)

@marc-hb marc-hb left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I have not tried to run it again but I find the entire code very clear and easy to read and none of this is running in production yet so bug fixes and incremental improvements can be done later: I recommend we merge this to make it easier for others to try.

@plbossart could you have another look, especially the .bt files that I'm not familiar with?

marc-hb
marc-hb previously approved these changes Apr 15, 2022

@marc-hb marc-hb left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Some review comments from a generous pytest expert friend who prefers to stay anonymous and not involved:

i don't know bpftrace but it looks a little bit like you might want to be using a parameterized fixture to run the test cases instead.
simple example usage: https://github.com/zephyrproject-rtos/west/blob/a343b7a7982355d0e5521ddcc69f700940d89e50/tests/test_manifest.py#L2885
with a parameterized fixture, you'll get finer-grained reporting and can customize pytest's notions of what each test is. as-is, it looks like you'll get a global pass/fail on a single function

I think we have parametrization already but maybe @pytest.mark.parametrize is more "pythonic", flexible and generally better way to do it. Again this can be a future improvement after merge.

@marc-hb

marc-hb commented Apr 15, 2022

Copy link
Copy Markdown
Collaborator

I think we have parametrization already but maybe @pytest.mark.parametrize is more "pythonic", flexible and generally better way to do it

I just remembered reading somewhere complaining that @pytest.mark.parametrize is static and can't be used after reading a config file. Vague and second-hand information, sorry for any noise.

@nklayman

Copy link
Copy Markdown
Contributor Author

@marc-hb latest push includes a no_dependencies.json that should work with just bpftrace installed. Also fixes edge cases where the spec file arg doesn't start with a ./ and when the bpftrace script doesn't exit in time.

@marc-hb

marc-hb commented Apr 19, 2022

Copy link
Copy Markdown
Collaborator

Nice try but:

collecting ... modprobe: FATAL: Module kheaders not found in directory /lib/modules/9.9.9-rc9softest
$ ['sleep', '1']
BPF tracing finished

Also, not running as root still hangs:

collecting ... ERROR: bpftrace currently only supports running as the root user.
  ... hangs ...
$ ps f

    987 pts/0    Ss     0:00 -bash
   1161 pts/0    R+     0:39  \_ python3 ./kernel_tracing/metric_evaluation/test.py kernel_tracing/metric_evaluation/no_dependencies.json
   1163 pts/0    Z+     0:00      \_ [bpftrace] <defunct>

BTW only bpftrace should run as root, should be started as sudo bpftrace.

Again all this can be fixed later.

@plbossart plbossart left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

the code split and what file is used for what isn't very clear to me @nklayman

Comment thread kernel_tracing/bpftrace_scripts/hda_irq_source_counts.bt
Comment thread kernel_tracing/bpftrace_scripts/suspend_resume_time.bt
Comment thread kernel_tracing/metric_evaluation/simple_bpftrace.bt
Comment thread kernel_tracing/metric_evaluation/no_dependencies.json
@nklayman
nklayman force-pushed the bpf-tracing branch 3 times, most recently from 331cb01 to 0472e88 Compare June 23, 2022 18:36

@plbossart plbossart left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

mostly ok @nklayman, just tripped on the 'val' variable that could really mean anything.

@marc-hb you good with this version?

Comment thread kernel_tracing/bpftrace_scripts/suspend_resume_time.bt
Comment thread kernel_tracing/metric_evaluation/readme.md
Comment thread kernel_tracing/metric_evaluation/simple_bpftrace.bt
nklayman added 2 commits June 30, 2022 17:01
Adds scripts to track sof_resume/suspend and ipc tx time, and count hda
irq interrupt sources and calculate timestamp deltas per-source.

Signed-off-by: Noah Klayman <noah.klayman@intel.com>
Takes a test specification from a JSON file, which contains a bpftrace
script, shell commands, and test conditions. It runs the bpftrace script
while executing shell commands, and collects all variables from
bpftrace. These are then injected into the conditions which are
evaluated with python's eval. Case execution and output formatting is
handled by pytest.

Signed-off-by: Noah Klayman <noah.klayman@intel.com>
@nklayman

Copy link
Copy Markdown
Contributor Author

BPF script changes have been moved to the first patch and var has been renamed. @marc-hb @plbossart everything look good now?

@plbossart plbossart left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM, I'll let @marc-hb comment further on the Python parts. Thanks @nklayman !

@marc-hb marc-hb left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Great start, very clear and readable. None of this is used in production yet so bugs can always be fixed later.

@marc-hb
marc-hb merged commit 45d0cd5 into thesofproject:main Jul 9, 2022
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