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

perf: add -F +symline support #935

Draft
wants to merge 8 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion gprofiler/utils/perf.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
r"(?:(?P<freq>\d+)\s+)?(?P<event_family>[\w\-_/]+):(?:(?P<event>[\w-]+):)?(?P<suffix>[^\n]*)(?:\n(?P<stack>.*))?",
re.MULTILINE | re.DOTALL,
)
SYMLINE_REGEX = re.compile(r"(?:\+([^+]+):(\d+)){2}$")


class SupportedPerfEvent(Enum):
Expand Down Expand Up @@ -160,7 +161,8 @@ def collapse_stack(comm: str, stack: str, insert_dso_name: bool = False) -> str:
m = FRAME_REGEX.match(line)
assert m is not None, f"bad line: {line}"
sym, dso = m.group("symbol"), m.group("dso_brackets") or m.group("dso_plain")
sym = sym.split("+")[0] # strip the offset part.
if not SYMLINE_REGEX.search(sym):
sym = sym.split("+")[0] # strip the offset part.
if sym == "[unknown]" and dso != "unknown":
sym = f"({dso})"
# append kernel annotation
Expand Down
12 changes: 11 additions & 1 deletion gprofiler/utils/perf_process.py
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,17 @@ def wait_and_script(self) -> str:
perf_data = inject_data

perf_script_proc = run_process(
[perf_path(), "script", "-F", "+pid", "-i", str(perf_data)],
[
perf_path(),
"script",
"-F",
"+pid,+symline",
"-X",
"gprofiler,py-spy",
"--no-addr2line-errors",
"-i",
str(perf_data),
],
suppress_log=True,
)
return perf_script_proc.stdout.decode("utf8")
Expand Down
2 changes: 1 addition & 1 deletion scripts/perf_build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
set -euo pipefail

# downloading the zip because the git is very large (this is also very large, but still smaller)
curl -SL https://codeload.github.com/Granulate/linux/zip/5c103bf97fb268e4ea157f5e1c2a5bd6ad8c40dc -o linux.zip
curl -SL https://codeload.github.com/Granulate/linux/zip/50259d0151087e75b8bfd6c0b0edc3125ee9997f -o linux.zip
unzip -qq linux.zip
rm linux.zip
cd linux-*/
Expand Down
2 changes: 1 addition & 1 deletion tests/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,4 @@ fi
python3 -m pip install -q --upgrade setuptools pip
python3 -m pip install -r ./requirements.txt -r ./exe-requirements.txt -r ./dev-requirements.txt
# TODO: python3 -m pip install .
sudo env "PATH=$PATH" python3 -m pytest -v tests/ "$@"
sudo -E env "PATH=$PATH" python3 -m pytest -v tests/ "$@"
11 changes: 11 additions & 0 deletions tests/test_perf.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#

import logging
import time
from threading import Event
from typing import Dict, cast

Expand Down Expand Up @@ -144,6 +145,7 @@ def test_perf_comm_change(
I'm not sure it can be done, i.e is this info even kept anywhere).
"""
with system_profiler as profiler:
time.sleep(2)
# first run - we get the changed name, because the app started before perf began recording.
_assert_comm_in_profile(profiler, application_pid, False)

Expand All @@ -170,6 +172,7 @@ def test_perf_thread_comm_is_process_comm(
starts after perf, the exec comm of the process should be used (see test_perf_comm_change)
"""
with system_profiler as profiler:
time.sleep(2)
# running perf & script now with --show-task-events would show:
# pative 1925947 [010] 987095.272656: PERF_RECORD_COMM: pative:1925904/1925947
# our perf will prefer to use the exec comm, OR oldest comm available if exec
Expand Down Expand Up @@ -397,6 +400,14 @@ def test_get_average_frame_count(samples: str, count: float) -> None:
),
id="frame_with_space_parenthesis",
),
pytest.param(
" 4af76b main.cpuIntensiveWork+bar.go:21+bar.go:14 (/tmp/perf/my_go_app)",
dict(
dso_true="main.cpuIntensiveWork+bar.go:21+bar.go:14 (/tmp/perf/my_go_app)",
dso_false="main.cpuIntensiveWork+bar.go:21+bar.go:14",
),
id="frame_with_symline",
),
],
)
def test_collapse_stack_consider_dso(stack: str, insert_dso_name: bool, outcome_dict: Dict[str, str]) -> None:
Expand Down
13 changes: 12 additions & 1 deletion tests/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ def run_privileged_container(
def _no_errors(logs: str) -> None:
# example line: [2021-06-12 10:13:57,528] ERROR: gprofiler: ruby profiling failed
assert "] ERROR: " not in logs, f"found ERRORs in gProfiler logs!: {logs}"
assert "Could not acquire gProfiler's lock" not in logs, f"found lock error in gProfiler logs!: {logs}"


def run_gprofiler_in_container(docker_client: DockerClient, image: Image, command: List[str], **kwargs: Any) -> None:
Expand Down Expand Up @@ -205,7 +206,17 @@ def assert_ldd_version_container(container: Container, version: str) -> None:


def snapshot_pid_profile(profiler: ProfilerInterface, pid: int) -> ProfileData:
return profiler.snapshot()[pid]
last_snapshot = profiler.snapshot()

def has_profile() -> bool:
nonlocal last_snapshot
if pid in last_snapshot:
return True
last_snapshot = profiler.snapshot()
return pid in last_snapshot

wait_event(timeout=5, stop_event=Event(), condition=has_profile, interval=2.0)
return last_snapshot[pid]


def snapshot_pid_collapsed(profiler: ProfilerInterface, pid: int) -> StackToSampleCount:
Expand Down
Loading