Skip to content

Enable Full PerfSpect Functionality by Removing --noroot Flag - #44

Open
artursarlo wants to merge 2 commits into
masterfrom
asarlo/fix_hw_metrics_with_proper_perfspect_execution
Open

Enable Full PerfSpect Functionality by Removing --noroot Flag#44
artursarlo wants to merge 2 commits into
masterfrom
asarlo/fix_hw_metrics_with_proper_perfspect_execution

Conversation

@artursarlo

Copy link
Copy Markdown

Enable Full PerfSpect Functionality by Removing --noroot Flag

Motivation

PerfSpect was previously run with the --noroot flag, which disables some expected functionalities and limits hardware metrics collection capabilities. This PR removes the --noroot flag and instead configures the containerized environment with the dependencies PerfSpect requires to run with full functionality.

Problem

When running PerfSpect without the --noroot flag in a PyInstaller-packaged gProfiler container, two issues prevented successful execution:

  1. Missing runtime dependencies: Alpine Linux doesn't include sudo and bash by default, which PerfSpect requires
  2. LD_LIBRARY_PATH pollution: PyInstaller bundles glibc-built libraries (like libz.so.1) and sets LD_LIBRARY_PATH to find them. When PerfSpect runs sudo perf, sudo inherits this environment and attempts to load the glibc version of libz.so.1 instead of Alpine's musl version, causing a symbol mismatch error:
    sudo: unable to load /usr/lib/sudo/sudoers.so: Error relocating /tmp/_MEIEXxh0f/libz.so.1: __vsnprintf_chk: symbol not found
    

Solution

1. Install Required Dependencies in Container (container.Dockerfile)

RUN apk add --no-cache sudo bash
  • sudo: Required by PerfSpect to run perf commands with elevated privileges
  • bash: Required by PerfSpect's internal scripts (Alpine uses ash by default)

2. Clean PyInstaller Environment Variables (gprofiler/hw_metrics.py)

Filter out PyInstaller's temporary library paths from LD_LIBRARY_PATH before spawning PerfSpect:

env = os.environ.copy()
if 'LD_LIBRARY_PATH' in env:
    ld_paths = env['LD_LIBRARY_PATH'].split(':')
    # Filter out paths that contain _MEI (PyInstaller temp directories)
    cleaned_paths = [p for p in ld_paths if '_MEI' not in p]
    if cleaned_paths:
        env['LD_LIBRARY_PATH'] = ':'.join(cleaned_paths)
    else:
        del env['LD_LIBRARY_PATH']

subprocess.Popen(ps_cmd, env=env)

This ensures sudo loads the correct system libraries compatible with Alpine's musl libc.

3. Fix PyInstaller Hidden Imports (pyinstaller.spec)

Added missing hidden imports that PyInstaller wasn't detecting automatically:

hiddenimports=[
    'backports',
    'backports.tarfile',
    'jaraco.text',
    'jaraco.context',
    'jaraco.functools',
]

These are dependencies of pkg_resources/setuptools that were causing runtime import errors.

Changes

  • container.Dockerfile: Install sudo and bash packages
  • gprofiler/hw_metrics.py: Remove --noroot flag and add LD_LIBRARY_PATH cleaning
  • pyinstaller.spec: Add hidden imports for backports and jaraco modules

Benefits

  • ✅ PerfSpect runs with full functionality (no --noroot limitations)
  • ✅ Hardware metrics collection works properly in containerized environments
  • ✅ Maintains compatibility with PerfSpect's expected runtime environment
  • ✅ Minimal overhead (~1-2MB for sudo and bash packages)

Testing

  • ✅ Verified PerfSpect collects hardware metrics successfully without --noroot
  • ✅ Confirmed sudo works correctly with cleaned environment
  • ✅ Tested in Alpine-based container where issues were originally observed
  • ✅ Verified no PyInstaller import errors with added hidden imports

Comment thread gprofiler/hw_metrics.py
ld_paths = env['LD_LIBRARY_PATH'].split(':')
# Filter out paths that contain _MEI (PyInstaller temp directories)
cleaned_paths = [p for p in ld_paths if '_MEI' not in p]
if cleaned_paths:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

how are we sure that this change in env['LD_LIBRARY_PATH'] wont cause the regression

Comment thread gprofiler/hw_metrics.py
@@ -91,10 +91,21 @@ def start(self) -> None:
str(self._perfspect_duration),
"--output",
PERFSPECT_DATA_DIRECTORY,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

perfspect ran perfectly with --noroot. What new capabilities are enabled when running as root. Giving root access to run perfspect incurs security risk

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.

2 participants