Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
a3d7e54
Add Darwin PMDA testing infrastructure with fast local build system
tallpsmith Dec 11, 2025
3b6ad19
Update unit test runner to work without system PCP installation
tallpsmith Dec 11, 2025
b55eacf
Add Darwin PMDA testing infrastructure with fast local build system
tallpsmith Dec 11, 2025
8988801
Update unit test runner to work without system PCP installation
tallpsmith Dec 11, 2025
6c73c5a
Correct kernel uptime metric check.
tallpsmith Dec 27, 2025
e482fdb
Introduce Cirrus CLI(Tart VM) task file to build PCP in a macOS vm lo…
tallpsmith Dec 27, 2025
d677435
Correct macOS installation packaging script to work better inside a T…
tallpsmith Dec 27, 2025
0464605
Remove execution of unit/integration tests (this is for a different b…
tallpsmith Dec 27, 2025
2358e95
Added documentation
tallpsmith Dec 27, 2025
6f58de3
Revert "Remove execution of unit/integration tests (this is for a dif…
tallpsmith Dec 28, 2025
7341c13
Merge branch 'macos-darwin-pmda-qa' of github.com:tallpsmith/pcp into…
tallpsmith Dec 28, 2025
88970ad
Improved macOS local dev/unit testing setup to speed up development c…
tallpsmith Dec 30, 2025
1fe6264
Correct dev makefile to reference templated files inside the cloned b…
tallpsmith Dec 30, 2025
5dc34e9
Also correct the unit test running script to reference the build dire…
tallpsmith Dec 30, 2025
b49d238
darwin: upgrade to vm_statistics64 API
tallpsmith Dec 31, 2025
9db0865
darwin: add memory compression metrics
tallpsmith Dec 31, 2025
71f12b9
darwin: add VFS statistics
tallpsmith Jan 1, 2026
84f829d
Correct unit test check for DSO depending on whether it is built loca…
tallpsmith Jan 1, 2026
53f0a25
Add mac-specific pmrep configurations to emulate more like pmstat doe…
tallpsmith Jan 1, 2026
ca2914d
CI: add comprehensive pmcd debugging to macOS workflow
tallpsmith Jan 1, 2026
ec57b91
CI: enhance pmcd startup debugging in macOS workflow
tallpsmith Jan 1, 2026
d5b3119
CI: fix pmcd startup - run directly without --verify flag
tallpsmith Jan 1, 2026
ba0f896
CI: wait for pmcd to start naturally instead of manual launch
tallpsmith Jan 1, 2026
ed00aa9
tests: remove timeout wrapper, use native -s samples option
tallpsmith Jan 1, 2026
bf9ad67
CI: add Python module debugging for pmrep failures
tallpsmith Jan 1, 2026
61d5102
CI: set PYTHONPATH to fix pmrep module import errors
tallpsmith Jan 1, 2026
4f37c11
tests: remove timeout from test-pmstat.sh
tallpsmith Jan 1, 2026
f3b053f
darwin: fix pmstat test patterns for multi-line output
tallpsmith Jan 1, 2026
468812c
Issue #2303 add swap metrics to Darwin PMDA to allow them to be expos…
tallpsmith Dec 3, 2025
1ccd7ed
pmrep: enable swap.used metric in macstat configurations
tallpsmith Jan 1, 2026
daf0f8c
darwin: add UDP protocol statistics
tallpsmith Jan 1, 2026
14654a6
darwin: add ICMP protocol statistics
tallpsmith Jan 2, 2026
e02f30a
gitignore: add Claude Code working files
tallpsmith Jan 2, 2026
e3be853
docs: add Darwin PMDA enhancement plan document
tallpsmith Jan 2, 2026
50ab438
darwin: add socket statistics
tallpsmith Jan 2, 2026
ed6a9cb
docs: update plan for completed Step 2.3 (socket counts)
tallpsmith Jan 2, 2026
d431bae
darwin: fix VFS error handling to use fail-fast pattern
tallpsmith Jan 2, 2026
0924082
docs: add code review workflow and error handling patterns to plan
tallpsmith Jan 2, 2026
96a4191
darwin: add TCP connection state metrics
tallpsmith Jan 2, 2026
5ff8261
docs: update plan for completed Step 2.4 (TCP connection states)
tallpsmith Jan 2, 2026
afa1e4e
docs: add PR link to plan document
tallpsmith Jan 2, 2026
1d967ef
ci: enable TCP statistics in Cirrus CI for testing
tallpsmith Jan 3, 2026
2bf73ec
darwin: add TCP protocol statistics
tallpsmith Jan 3, 2026
540e530
darwin: fix tcp.c indentation to use tabs
tallpsmith Jan 3, 2026
4eb9ac8
docs: update plan with code style rules and Step 2.5a completion
tallpsmith Jan 3, 2026
f5c406e
darwin: add TCP stats access control detection and documentation
tallpsmith Jan 3, 2026
776116b
darwin: refactor fetch functions to their respective modules
tallpsmith Jan 3, 2026
509069e
Update plan with completed state and add additional ideas.
tallpsmith Jan 3, 2026
9afb1b9
darwin: add comprehensive pmrep monitoring views (Step 2.6)
tallpsmith Jan 3, 2026
f667ebb
Update plan: Step 2.6 (pmrep views) completed
tallpsmith Jan 3, 2026
472451e
Extend pmrep integration tests to cover all new monitoring views
tallpsmith Jan 3, 2026
f169f34
Make pmrep integration tests blocking - fail fast on validation errors
tallpsmith Jan 3, 2026
00408a1
darwin: fix DISK_INDOM undeclared identifier after refactoring
tallpsmith Jan 3, 2026
d89607d
darwin: remove static from indomtab to fix linker errors
tallpsmith Jan 3, 2026
1ff2b97
pmrep: escape percent sign in macstat.conf cache_hit_ratio unit
tallpsmith Jan 3, 2026
43306ef
pmrep: escape percent sign in cache_hit_ratio.label
tallpsmith Jan 3, 2026
3a2e05e
pmrep: fix macstat.conf bugs and improve layout
tallpsmith Jan 4, 2026
785686c
docs: update plan with Step 2.6 QA feedback and fixes
tallpsmith Jan 4, 2026
e0b925a
darwin_proc: add process I/O statistics (Step 3.1)
tallpsmith Jan 5, 2026
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
81 changes: 81 additions & 0 deletions .cirrus.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
task:
name: macOS PCP Build
macos_instance:
image: ghcr.io/cirruslabs/macos-tahoe-base:latest
# Cache Homebrew prefix + download cache
homebrew_cache:
folder: /opt/homebrew
# Also cache downloaded bottles to avoid re-downloading on cache miss/rebuild
# (you can list multiple folders)
# folders:
# - /opt/homebrew
# - ~/Library/Caches/Homebrew
fingerprint_script: |
brew --version
echo $HOMEBREW_NO_AUTO_UPDATE # if you use it
brew list --versions | sort # list installed formulae & versions
populate_script: |
# This runs only on cache miss — safe to install everything here
echo "Populating Homebrew cache..."
# Homebrew is already in base images, but we can ensure update if needed
brew update --quiet || true
brew install coreutils gnu-tar pkg-config python3 python-setuptools autoconf || true # idempotent
# Optional: clean up non-deterministic files before cache upload
before_cache_script: |
brew cleanup --prune=all || true
rm -rf ~/Library/Caches/Homebrew/downloads # optional, if too noisy
#brew_setup_script:
# Now this will be very fast if cache hit
#- echo "Setting up dependencies (cached!)"
# - brew install coreutils gnu-tar pkg-config python3 python-setuptools autoconf || true # idempotent
enable_tcp_stats_script: |
echo "Enabling TCP statistics for testing..."
sudo sysctl -w net.inet.tcp.disable_access_to_stats=0
echo "Verifying setting:"
sysctl net.inet.tcp.disable_access_to_stats
pcp_build_script: |
[ "$PCP_SKIP_BUILD" == "true" ] && echo "SKIPPING BUILD" || ./Makepkgs --verbose
pcp_install_script: |
DMG_PATH=$(find pcp-**/build/mac -name "pcp-*.dmg" | head -1) # Find the generated DMG
echo "Found DMG: $DMG_PATH"
MOUNT_OUTPUT=$(hdiutil attach "$DMG_PATH" | tail -1) # Mount the DMG
VOLUME_PATH=$(echo "$MOUNT_OUTPUT" | awk '{print $3}')
echo "Mounted at: $VOLUME_PATH"
PKG_PATH=$(find "$VOLUME_PATH" -name "*.pkg" | head -1) # Find and install the PKG
echo "Found PKG: $PKG_PATH"
ls -alh $PKG_PATH
pkgutil --check-signature $PKG_PATH || true # this returns 1 when things are ok
sudo installer -pkg "$PKG_PATH" -target / -verbose # Install (sudo is passwordless in GitHub Actions)
check_pmcd_is_running_postinstall_script: |
echo "Waiting for pcp service to start (it can take a while after install)..."
TIMEOUT=180 # 3 minutes
ELAPSED=0
INTERVAL=5

while [ $ELAPSED -lt $TIMEOUT ]; do
if pcp 2>/dev/null; then
echo "pcp service is responding"
break
fi
sleep $INTERVAL
ELAPSED=$((ELAPSED + INTERVAL))
done

if [ $ELAPSED -ge $TIMEOUT ]; then
echo "ERROR: pcp service failed to start within $TIMEOUT seconds"
exit 1
fi
run_unit_tests_script: |
cd scripts/darwin/test/unit
./run-unit-tests.sh
run_integration_tests_script: |
cd scripts/darwin/test/integration
./run-integration-tests.sh
pause_script: |
if [ "$PCP_PAUSE_AFTER_INSTALL" == "true" ]; then
echo "VM IP: $(ipconfig getifaddr en0)"
sleep 3600 # Keeps VM alive for an hour
else
echo "No pause required, finishing"
fi

230 changes: 230 additions & 0 deletions .github/workflows/macOS.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,32 @@ jobs:
id: install-brew-deps
run: |
brew install autoconf unixodbc
- name: Configure PCP
id: configure
run: |
echo "Configuring PCP..."
./configure --prefix=/usr --libexecdir=/usr/lib --sysconfdir=/etc --localstatedir=/var
- name: Build on macOS
id: Build
run: |
source pybuilddeps/bin/activate
xcodebuild -version
./Makepkgs -verbose
# Darwin PMDA Unit Tests (pre-installation)
- name: Run Darwin PMDA Unit Tests
id: unit-tests
if: success()
run: |
echo "Running Darwin PMDA unit tests..."
cd scripts/darwin/test/unit
./run-unit-tests.sh
- name: Debug on unit test failure
if: failure() && steps.unit-tests.conclusion == 'failure'
run: |
echo "Unit tests failed. Checking build artifacts..."
find . -name "pmda_darwin.dylib" -o -name "pmdadarwin"
echo "Checking for pmcd build..."
find . -name "dbpmda"
- name: Debug on failure
if: failure() && steps.Build.conclusion == 'failure'
run: |
Expand Down Expand Up @@ -94,6 +114,216 @@ jobs:
echo "Checking for expected directories..."
test -d /etc/pcp && echo "✓ /etc/pcp exists"
test -d /var/lib/pcp && echo "✓ /var/lib/pcp exists"
# Darwin PMDA Integration Tests (post-installation)
- name: Wait for pmcd to start
if: success() && steps.install-test.conclusion == 'success'
id: wait-for-pmcd
run: |
echo "=== Installation Verification ==="
echo "PCP installation check:"
which pmcd && echo "pmcd binary: $(which pmcd)" || echo "pmcd not in PATH"
which pminfo && echo "pminfo binary: $(which pminfo)" || echo "pminfo not in PATH"
which pcp && echo "pcp binary: $(which pcp)" || echo "pcp not in PATH"

echo ""
echo "Critical directories:"
test -d /etc/pcp && echo "✓ /etc/pcp exists" || echo "✗ /etc/pcp MISSING"
test -d /var/lib/pcp && echo "✓ /var/lib/pcp exists" || echo "✗ /var/lib/pcp MISSING"
test -d /var/log/pcp && echo "✓ /var/log/pcp exists" || echo "✗ /var/log/pcp MISSING"
test -d /var/log/pcp/pmcd && echo "✓ /var/log/pcp/pmcd exists" || echo "✗ /var/log/pcp/pmcd MISSING"

echo ""
echo "pmcd.conf contents:"
cat /etc/pcp/pmcd/pmcd.conf 2>/dev/null || echo "pmcd.conf not found"

echo ""
echo "Checking launchd plist:"
test -f /Library/LaunchDaemons/org.pcp.pmcd.plist && echo "✓ org.pcp.pmcd.plist exists" || echo "✗ org.pcp.pmcd.plist MISSING"

echo ""
echo "=== Waiting for pmcd service to start (post-install) ==="
echo "The installer should have started pmcd via launchd..."

TIMEOUT=60 # Wait up to 60 seconds
ELAPSED=0
INTERVAL=3

while [ $ELAPSED -lt $TIMEOUT ]; do
echo "Checking if pmcd is responding (${ELAPSED}s elapsed)..."

# Check if pcp command works (like in .cirrus.yml)
if pcp 2>/dev/null; then
echo "✓ pmcd service is responding!"
break
fi

# Also check if pminfo can connect
if pminfo -h localhost -f hinv.ncpu 2>/dev/null; then
echo "✓ pmcd is accepting connections!"
break
fi

sleep $INTERVAL
ELAPSED=$((ELAPSED + INTERVAL))
done

if [ $ELAPSED -ge $TIMEOUT ]; then
echo "✗ ERROR: pmcd service failed to start within $TIMEOUT seconds"

echo ""
echo "=== Diagnostic Information ==="
echo "pmcd process status:"
pgrep pmcd && echo "pmcd is running (PID: $(pgrep pmcd))" || echo "pmcd NOT running"

echo ""
echo "pmcd full process details:"
ps aux | grep pmcd | grep -v grep || echo "No pmcd process found"

echo ""
echo "pmcd command line:"
sudo ps -p $(pgrep pmcd) -o pid,ppid,user,command 2>/dev/null || echo "Cannot get process details"

echo ""
echo "pmcd network connections:"
sudo lsof -i -P | grep pmcd || echo "No network connections"

echo ""
echo "pmcd log (last 30 lines):"
sudo tail -30 /var/log/pcp/pmcd/pmcd.log 2>/dev/null || echo "No pmcd.log"

echo ""
echo "launchd plist stdout/stderr:"
sudo cat /var/log/pcp/pmcd/plist.stdout 2>/dev/null || echo "No plist.stdout"
sudo cat /var/log/pcp/pmcd/plist.stderr 2>/dev/null || echo "No plist.stderr"

exit 1
fi

echo ""
echo "=== pmcd Service Verification ==="
echo "pmcd process status:"
pgrep pmcd && echo "✓ pmcd is running (PID: $(pgrep pmcd))" || echo "✗ pmcd failed to start"

echo ""
echo "pmcd command line:"
sudo ps -p $(pgrep pmcd) -o pid,ppid,user,command || echo "Cannot get process details"

echo ""
echo "pmcd listening ports:"
sudo lsof -i -P | grep pmcd || echo "No network connections found for pmcd"

echo ""
echo "Test localhost connectivity to pmcd port (44321):"
nc -z localhost 44321 && echo "✓ Can connect to localhost:44321" || echo "✗ Cannot connect to localhost:44321"

echo ""
echo "Test 127.0.0.1 connectivity to pmcd port (44321):"
nc -z 127.0.0.1 44321 && echo "✓ Can connect to 127.0.0.1:44321" || echo "✗ Cannot connect to 127.0.0.1:44321"
- name: Run Darwin PMDA Integration Tests
id: integration-tests
if: success() && steps.wait-for-pmcd.conclusion == 'success'
run: |
echo "=== Python and pmrep debugging ==="
echo "pmrep location:"
which pmrep
head -1 $(which pmrep)

echo ""
echo "Python versions available:"
which python3 && python3 --version || echo "python3 not found"
which python && python --version || echo "python not found"

echo ""
echo "Python sys.path for pmrep's Python:"
$(head -1 $(which pmrep) | sed 's/#!//') -c "import sys; print('\n'.join(sys.path))"

echo ""
echo "Looking for pcp module:"
find /usr/local -name "pcp.py" -o -name "pcp" -type d 2>/dev/null | grep -i python || echo "No pcp module found in /usr/local"

echo ""
echo "Check if pcp module is installed:"
$(head -1 $(which pmrep) | sed 's/#!//') -c "import pcp; print('pcp module location:', pcp.__file__)" 2>&1 || echo "pcp module not importable"

echo ""
echo "Setting PYTHONPATH to include PCP module location..."
export PYTHONPATH="/usr/local/lib/python3.13/site-packages:${PYTHONPATH:-}"
echo "PYTHONPATH=${PYTHONPATH}"

echo ""
echo "Verify pcp module is now importable:"
$(head -1 $(which pmrep) | sed 's/#!//') -c "import pcp; print('✓ pcp module found at:', pcp.__file__)"

echo ""
echo "Running Darwin PMDA integration tests..."
cd scripts/darwin/test/integration
./run-integration-tests.sh
- name: Test pmstat with Darwin metrics
if: success() && steps.integration-tests.conclusion == 'success'
run: |
echo "Testing pmstat output..."
cd scripts/darwin/test/integration
./test-pmstat.sh
- name: Debug on integration test failure
if: failure() && (steps.integration-tests.conclusion == 'failure' || steps.wait-for-pmcd.conclusion == 'failure')
run: |
echo "Integration tests failed. Collecting diagnostics..."

echo "=== PCP Configuration ==="
pmconfig 2>&1 || echo "pmconfig failed"

echo ""
echo "=== pmcd.conf contents ==="
cat /etc/pcp/pmcd/pmcd.conf 2>/dev/null || echo "pmcd.conf not found"

echo ""
echo "=== pmcd status ==="
pgrep pmcd && echo "pmcd is running (PID: $(pgrep pmcd))" || echo "pmcd not running"

echo ""
echo "=== pmcd network connections ==="
sudo lsof -i -P | grep pmcd || echo "No network connections for pmcd"

echo ""
echo "=== All listening ports ==="
sudo lsof -i -P | grep LISTEN || echo "No listening ports found"

echo ""
echo "=== Connectivity tests ==="
nc -z localhost 44321 && echo "✓ localhost:44321 is reachable" || echo "✗ localhost:44321 is NOT reachable"
nc -z 127.0.0.1 44321 && echo "✓ 127.0.0.1:44321 is reachable" || echo "✗ 127.0.0.1:44321 is NOT reachable"

echo ""
echo "=== pmcd log (last 50 lines) ==="
sudo tail -50 /var/log/pcp/pmcd/pmcd.log 2>/dev/null || echo "No pmcd log found"

echo ""
echo "=== darwin PMDA log (last 50 lines) ==="
sudo tail -50 /var/log/pcp/pmcd/darwin.log 2>/dev/null || echo "No darwin PMDA log found"

echo ""
echo "=== darwin PMDA status ==="
pminfo -f pmcd.agent.status 2>/dev/null | grep darwin || echo "Darwin PMDA not loaded"

echo ""
echo "=== Available PMDAs ==="
ls -la /usr/local/lib/pcp/pmdas/ 2>/dev/null || ls -la /Library/PCP/pmdas/ 2>/dev/null || echo "PMDA directory not found"

echo ""
echo "=== Test simple metric with explicit localhost ==="
pminfo -h localhost -f hinv.ncpu 2>&1 || echo "pminfo with localhost failed"

echo ""
echo "=== Test simple metric with explicit 127.0.0.1 ==="
pminfo -h 127.0.0.1 -f hinv.ncpu 2>&1 || echo "pminfo with 127.0.0.1 failed"

echo ""
echo "=== Test simple metric with default host ==="
pminfo -f hinv.ncpu 2>&1 || echo "pminfo with default host failed"

echo ""
echo "=== PCP environment variables ==="
env | grep PCP || echo "No PCP env vars set"
- name: Cleanup - Unmount DMG
if: always()
run: |
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,6 @@ provisioning/osxsierra.legally.ok
*.gdb_history
*vgcore.*
tmpfiles.init.setup

# Claude Code working files
.claude/
7 changes: 7 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,3 +167,10 @@ keep the differences minimal in order to ease future updates of vendored code.

**All bugs and CVEs of a vendored library in turn become responsibilities of the
PCP maintainers as well** (and fixes must be pushed upstream).

## Platform-Specific Development

### macOS with Tart VMs

macOS developers can build in isolated VMs for clean, reproducible builds that match the CI environment. See [MACOS_DEVELOPMENT.md](MACOS_DEVELOPMENT.md) for details.

Loading
Loading