Skip to content
Merged
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
31 changes: 4 additions & 27 deletions .github/workflows/build_and_test_epmt.yml
Original file line number Diff line number Diff line change
Expand Up @@ -138,22 +138,10 @@ jobs:
run: |
make epmt-dash

# ── papiex tarball (OUTSIDE_DOCKER): cached across runs ────────────────
# Cache key: version + OS target + "outside-docker" suffix to distinguish
# from the Docker-built variant cached by docker_build_test.
# The weekly_tarball_build workflow pre-warms this cache every Monday;
# the build below is a fallback for cache misses.
- name: Check Cache for papiex tarball (OUTSIDE_DOCKER)
id: cache-papiex
uses: actions/cache@v4
with:
path: papiex-epmt-${{ env.PAPIEX_VERSION }}-${{ env.OS_TARGET }}.tgz
key: papiex-outside-docker-${{ env.PAPIEX_VERSION }}-${{ env.OS_TARGET }}

- name: make papiex tarball
if: steps.cache-papiex.outputs.cache-hit != 'true'
run: |
make OUTSIDE_DOCKER='YUP' papiex-dist
# ── papiex compilation is handled by compile_papiex.sh at pip install time ──
# For bare-metal (non-Docker) installs, setup.py invokes compile_papiex.sh
# which downloads and compiles papiex from source. The Docker release path
# still uses the Makefile's papiex-dist target (via docker-dist).

# ── Test pip install ./src with papiex compilation via compile_papiex.sh ──
# This exercises the new setup.py hook: compile_papiex.sh downloads
Expand All @@ -177,17 +165,6 @@ jobs:
echo " (compile_papiex.sh may have skipped or failed gracefully)"
fi
epmt -v check || true
# Uninstall before the sdist-based install below
python3 -m pip uninstall -y epmt || true

- name: make epmt pip-packaging
run: |
make dist python-dist dist-test

- name: pip install epmt pip-package
run: |
ls src/dist/epmt*gz
python3 -m pip install src/dist/epmt*gz

- name: adjust path
run: |
Expand Down
21 changes: 3 additions & 18 deletions .github/workflows/weekly_cache_builds.yml
Original file line number Diff line number Diff line change
Expand Up @@ -187,24 +187,9 @@ jobs:
path: src/epmt/ui
key: epmt-dash-${{ env.EPMT_DASH_SRC_BRANCH }}

# ── papiex (OUTSIDE_DOCKER) ────────────────────────────────────
- name: Build papiex-dist (OUTSIDE_DOCKER)
run: make OUTSIDE_DOCKER='YUP' papiex-dist

- name: Verify papiex tarball exists
run: |
TARBALL="papiex-epmt-${PAPIEX_VERSION}-${OS_TARGET}.tgz"
if [ ! -f "${TARBALL}" ]; then
echo "::error::Papiex OUTSIDE_DOCKER tarball '${TARBALL}' not found."
exit 1
fi
echo "Papiex OUTSIDE_DOCKER tarball '${TARBALL}' exists."

- name: Cache papiex tarball (OUTSIDE_DOCKER)
uses: actions/cache/save@v4
with:
path: papiex-epmt-${{ env.PAPIEX_VERSION }}-${{ env.OS_TARGET }}.tgz
key: papiex-outside-docker-${{ env.PAPIEX_VERSION }}-${{ env.OS_TARGET }}
# ── papiex (OUTSIDE_DOCKER) removed ─────────────────────────
# Bare-metal papiex compilation is now handled by compile_papiex.sh
# at pip install time. Only the Docker-based papiex cache remains.

# ── Python + SQLite from source (container-path cache) ──────────
# Pre-warm the Python/SQLite build cache so build_and_test_epmt
Expand Down
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -75,4 +75,11 @@ install_papiex.log
# virtualenv
venv*

# setuptools build artifacts
src/build/
# papiex compilation byproducts (headers and helper scripts)
src/epmt/bin/
src/epmt/include/

# virtualenv
venv*
23 changes: 10 additions & 13 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -161,10 +161,14 @@ $(EPMT_RELEASE) dist:
@echo "**********************************************************"
tar -czf $(EPMT_RELEASE) epmt-install

# runs setuptools
# note that this step requires EPMT_RELEASE and PAPIEX_RELEASE, but we don't explicitly state it here, b.c.
# when we go in the docker container, the time-zone changes and therefore thet timestamp comparison triggers re-making
# targets that do not need to be remade
# runs setuptools to build the sdist.
# Used in the Docker release flow: make papiex-dist (Docker path) builds the papiex
# tarball, then python-dist extracts the pre-compiled .so files into epmt/lib/ before
# building the sdist. For bare-metal installs, papiex is compiled at pip install time
# via compile_papiex.sh instead.
# NOTE: we don't explicitly list EPMT_RELEASE and PAPIEX_RELEASE as dependencies, b.c.
# when we go in the docker container, the time-zone changes and therefore the timestamp
# comparison triggers re-making targets that do not need to be remade
python-dist:
@echo "(python-dist) whoami: $(shell whoami)"
@echo "**********************************************************"
Expand All @@ -173,6 +177,7 @@ python-dist:
cd src && echo "GOOD: cd src" || echo "I FAILED: cd src" ; \
tar zxf ../$(PAPIEX_RELEASE) && echo "GOOD: tar -zxf ../PAPIEX_RELEASE" || echo "I FAILED: tar zxf ../PAPIEX_RELEASE" ; \
mkdir -p epmt/lib && cp -a papiex-epmt-install/lib/*.so* epmt/lib/ && echo "GOOD: cp papiex libs to epmt/lib" || echo "I FAILED: cp papiex libs to epmt/lib" ; \
rm -rf papiex-epmt-install && echo "GOOD: rm papiex-epmt-install" || echo "I FAILED: rm papiex-epmt-install" ; \
pip3 install --quiet build && echo "GOOD: pip3 install build" || echo "I FAILED: pip3 install build" ; \
python3 -m build --sdist && echo "GOOD: python3 -m build --sdist" || echo "I FAILED: python3 -m build --sdist" ; \
chmod a+r dist/* && echo "GOOD: chmod a+r dist/*" || echo "I FAILED: chmod a+r dist/*"
Expand Down Expand Up @@ -282,15 +287,7 @@ $(PAPIEX_SRC)/$(PAPIEX_RELEASE): $(PAPIEX_SRC)
@echo
@echo
@echo "################### BEGIN MAKE PAPIEX TARBALL : papiex-dist ########################################"
if [ -n "${OUTSIDE_DOCKER}" ]; then \
echo "within docker. make and make check within PAPIEX_SRC/PAPIEX_RELEASE target" ; \
make -C $(PAPIEX_SRC) CONFIG_PAPIEX_PAPI=$(CONFIG_PAPIEX_PAPI) CONFIG_PAPIEX_DEBUG=$(CONFIG_PAPIEX_DEBUG) OS_TARGET=$(OS_TARGET) distclean install dist ; \
make -C $(PAPIEX_SRC) CONFIG_PAPIEX_PAPI=$(CONFIG_PAPIEX_PAPI) CONFIG_PAPIEX_DEBUG=$(CONFIG_PAPIEX_DEBUG) OS_TARGET=$(OS_TARGET) dist-test ; \
make -C $(PAPIEX_SRC) CONFIG_PAPIEX_PAPI=$(CONFIG_PAPIEX_PAPI) CONFIG_PAPIEX_DEBUG=$(CONFIG_PAPIEX_DEBUG) OS_TARGET=$(OS_TARGET) check ; \
else \
echo "outside docker. making docker-dist within PAPIEX_SRC/PAPIEX_RELEASE target" ; \
make -C $(PAPIEX_SRC) CONFIG_PAPIEX_PAPI=$(CONFIG_PAPIEX_PAPI) CONFIG_PAPIEX_DEBUG=$(CONFIG_PAPIEX_DEBUG) OS_TARGET=$(OS_TARGET) DOCKER_RUN_OPTS="$(DOCKER_RUN_OPTS)" docker-dist ; \
fi
make -C $(PAPIEX_SRC) CONFIG_PAPIEX_PAPI=$(CONFIG_PAPIEX_PAPI) CONFIG_PAPIEX_DEBUG=$(CONFIG_PAPIEX_DEBUG) OS_TARGET=$(OS_TARGET) DOCKER_RUN_OPTS="$(DOCKER_RUN_OPTS)" docker-dist

$(PAPIEX_SRC): $(PAPIEX_SRC_TARBALL)
@echo "(PAPIEX_SRC) whoami: $(shell whoami)"
Expand Down
64 changes: 47 additions & 17 deletions src/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"""
import logging
import subprocess
import sys
from pathlib import Path

from setuptools import setup
Expand All @@ -19,42 +20,71 @@
LOG_FILE = "install_papiex.log"


def _open_tty():
"""Open /dev/tty for direct user output, bypassing pip's capture."""
try:
return open("/dev/tty", "w", encoding="utf-8")
except OSError:
return None


class BuildPapiex(build):
"""Compile papiex native libraries before the standard setuptools build."""

def run(self):
script = Path(__file__).parent / "compile_papiex.sh"
if script.exists():
try:
with open(LOG_FILE, "w", encoding="utf-8") as log_fh:
subprocess.run(
[str(script)],
stdout=log_fh,
stderr=subprocess.STDOUT,
check=True,
)
self._run_compile(script)
except subprocess.CalledProcessError as exc:
logger.warning(
"papiex compilation failed (exit %d). EPMT will still "
"install but hardware counter collection will be "
"unavailable. Build log follows:\n%s",
exc.returncode, _read_log(),
"unavailable. See %s for details.",
exc.returncode, LOG_FILE,
)
except FileNotFoundError:
logger.warning(
"compile_papiex.sh not found — skipping papiex build."
)
else:
logger.info("papiex build log:\n%s", _read_log())
super().run()

@staticmethod
def _run_compile(script):
"""Run compile_papiex.sh, teeing output to /dev/tty and a log file.

def _read_log():
"""Return the contents of the papiex build log, or a fallback message."""
try:
return Path(LOG_FILE).read_text(encoding="utf-8", errors="replace")
except OSError:
return "(log file not available)"
pip suppresses build-backend stdout/stderr in non-verbose mode.
Writing directly to /dev/tty ensures the compilation progress is
always visible to interactive users. In non-interactive contexts
(CI, no TTY) the output still goes to the log file and stderr.
"""
tty_fh = _open_tty()
fallback_to_stderr = tty_fh is None

proc = subprocess.Popen(
[str(script)],
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
text=True,
)

with open(LOG_FILE, "w", encoding="utf-8") as log_fh:
for line in proc.stdout:
log_fh.write(line)
if tty_fh:
tty_fh.write(line)
tty_fh.flush()
elif fallback_to_stderr:
sys.stderr.write(line)
sys.stderr.flush()

proc.wait()

if tty_fh:
tty_fh.close()

if proc.returncode != 0:
raise subprocess.CalledProcessError(proc.returncode, str(script))


setup(cmdclass={"build": BuildPapiex})
Loading