forked from benfred/py-spy
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathjustfile
More file actions
120 lines (95 loc) · 3.58 KB
/
justfile
File metadata and controls
120 lines (95 loc) · 3.58 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
SCRIPT := "tests/scripts/busyloop.py"
# Generate flamegraph profile
default: build
#!/usr/bin/env bash
set -euo pipefail
trap 'rm -f profile-*.svg dump-*.json dump-*.txt' EXIT
SCRIPT_NAME=$(basename "{{SCRIPT}}")
# Clean up any existing test processes first
pkill -f "$SCRIPT_NAME" 2>/dev/null || true
sleep 1
# Set up py-spy command with sudo if needed
PYSPY_CMD="./target/release/py-spy"
if [[ "$OSTYPE" == "darwin"* ]]; then
PYSPY_CMD="sudo ./target/release/py-spy"
fi
# Look for our test script
TEST_PID=$(pgrep -f "$SCRIPT_NAME" 2>/dev/null | head -1 || true)
if [[ -n "$TEST_PID" ]]; then
TARGET_PID="$TEST_PID"
STARTED_PROCESS="FOUND"
echo "Found existing test process: $TARGET_PID"
else
echo "Starting new test process..."
nohup python "{{SCRIPT}}" > /tmp/test_script.out 2>&1 &
TARGET_PID=$!
sleep 3
STARTED_PROCESS="STARTED"
echo "Started test process: $TARGET_PID"
fi
# Verify process is still running
if ! kill -0 "$TARGET_PID" 2>/dev/null; then
echo "Error: Process $TARGET_PID is not running"
exit 1
fi
# Generate flamegraph
FLAMEGRAPH="profile-$(date +%s).svg"
echo "Profiling PID $TARGET_PID..."
$PYSPY_CMD record --pid "$TARGET_PID" --duration 5 --output "$FLAMEGRAPH"
# Cleanup test process if we started one
if [[ "$STARTED_PROCESS" == "STARTED" ]]; then
kill "$TARGET_PID" 2>/dev/null || true
fi
echo "Flamegraph saved: $FLAMEGRAPH"
echo "Open with: open $FLAMEGRAPH"
# Generate dump analysis
dump: build
#!/usr/bin/env bash
set -euo pipefail
trap 'rm -f profile-*.svg dump-*.json dump-*.txt' EXIT
SCRIPT_NAME=$(basename "{{SCRIPT}}")
# Clean up any existing test processes first
pkill -f "$SCRIPT_NAME" 2>/dev/null || true
sleep 1
# Set up py-spy command with sudo if needed
PYSPY_CMD="./target/release/py-spy"
if [[ "$OSTYPE" == "darwin"* ]]; then
PYSPY_CMD="sudo ./target/release/py-spy"
fi
# Look for our test script
TEST_PID=$(pgrep -f "$SCRIPT_NAME" 2>/dev/null | head -1 || true)
if [[ -n "$TEST_PID" ]]; then
TARGET_PID="$TEST_PID"
STARTED_PROCESS="FOUND"
echo "Found existing test process: $TARGET_PID"
else
echo "Starting new test process..."
nohup python "{{SCRIPT}}" > /tmp/test_script.out 2>&1 &
TARGET_PID=$!
sleep 3
STARTED_PROCESS="STARTED"
echo "Started test process: $TARGET_PID"
fi
# Verify process is still running
if ! kill -0 "$TARGET_PID" 2>/dev/null; then
echo "Error: Process $TARGET_PID is not running"
exit 1
fi
# Generate dump files
DUMP_JSON="dump-$(date +%s).json"
# Generate JSON dump
$PYSPY_CMD dump --pid "$TARGET_PID" --json > "$DUMP_JSON"
# Pretty print call stack trees with colors
if command -v jq >/dev/null 2>&1; then
jq -r '.[] | "\u001b[1;33mThread \(.thread_id) \u001b[0;36m(\(.thread_name // "unnamed"))\u001b[0m:\n" + (.frames | reverse | to_entries | map(" " + (" " * .key) + "\u001b[0;32m└─ \(.value.name)\u001b[0m \u001b[0;90m(\(.value.short_filename // .value.filename):\(.value.line))\u001b[0m") | join("\n"))' "$DUMP_JSON"
else
echo "Install jq for colored output: brew install jq"
$PYSPY_CMD dump --pid "$TARGET_PID"
fi
# Cleanup test process if we started one
if [[ "$STARTED_PROCESS" == "STARTED" ]]; then
kill "$TARGET_PID" 2>/dev/null || true
fi
# Build py-spy
build:
cargo build --release