Skip to content

Commit eb72b98

Browse files
committed
chore: add script for profiling
Signed-off-by: vprashar2929 <vibhu.sharma2929@gmail.com>
1 parent 2b56585 commit eb72b98

File tree

2 files changed

+202
-0
lines changed

2 files changed

+202
-0
lines changed

.github/workflows/profiling.yaml

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
name: Profiling Report
2+
# This configuration runs two separate workflows for PRs
3+
# 1. On 'pull_request': Builds and run pprof profiling scripts
4+
# 2. On 'pull_request_target': Deploys the artifacts from (1) with write permissions
5+
on:
6+
pull_request:
7+
pull_request_target:
8+
9+
permissions:
10+
contents: write # Needed for gh-pages push
11+
pull-requests: write # Needed for PR comment
12+
13+
jobs:
14+
# Job 1: Run on the PR from the fork with a read-only token
15+
build_and_profile:
16+
# This job only runs for the 'pull_request' event, not 'pull_request_target'
17+
if: github.event_name == 'pull_request'
18+
runs-on: ubuntu-latest
19+
steps:
20+
- name: Checkout source
21+
uses: actions/checkout@v4
22+
# This explicitly checks out the head of the pull request
23+
with:
24+
ref: ${{ github.event.pull_request.head.sha }}
25+
26+
- name: Build Kepler
27+
run: |
28+
make build
29+
30+
- name: Enable fake cpu meter
31+
shell: bash
32+
run: |
33+
sed -i '/fake-cpu-meter:/{n;s/enabled: false/enabled: true/}' hack/config.yaml
34+
35+
- name: Run Kepler in the background
36+
run: |
37+
nohup ./bin/kepler --config.file=hack/config.yaml > kepler.log 2>&1 &
38+
39+
- name: Run profiling script
40+
run: |
41+
./hack/reports/profiling.sh
42+
43+
- name: Upload profiling artifacts
44+
uses: actions/upload-artifact@v4
45+
with:
46+
name: profiling-results-${{ github.event.pull_request.number }}
47+
path: ./tmp
48+
retention-days: 1 # Keep artifact for 1 day
49+
50+
- name: Run must gather
51+
shell: bash
52+
run: |
53+
echo "::group::Get logs for kepler"
54+
cat kepler.log || true
55+
echo "::endgroup::"
56+
57+
echo "::group::Fetch metrics from localhost:28282"
58+
curl -s http://localhost:28282/metrics || true
59+
echo "::endgroup::"
60+
61+
# Job 2: Run in the context of the base repo with a write token
62+
deploy_and_comment:
63+
# This job only runs for the 'pull_request_target' event
64+
if: github.event_name == 'pull_request_target'
65+
runs-on: ubuntu-latest
66+
# It requires the build_and_profile job from the corresponding 'pull_request' workflow to succeed
67+
needs: build_and_profile
68+
steps:
69+
- name: Checkout source
70+
uses: actions/checkout@v4
71+
# Checks out the base branch of the PR, NOT the fork's code
72+
73+
- name: Download rofiling artifacts
74+
uses: actions/download-artifact@v4
75+
with:
76+
name: profiling-results-${{ github.event.pull_request.number }}
77+
path: ./tmp
78+
79+
- name: Deploy to GitHub Pages
80+
id: deployment
81+
uses: peaceiris/actions-gh-pages@v4
82+
with:
83+
github_token: ${{ secrets.GITHUB_TOKEN }}
84+
publish_dir: ./tmp
85+
destination_dir: pr-${{ github.event.pull_request.number }}
86+
keep_files: false
87+
user_name: github-actions[bot]
88+
user_email: github-actions[bot]@users.noreply.github.com
89+
90+
- name: Generate comment message
91+
id: generate_message
92+
run: |
93+
{
94+
echo "message<<EOF"
95+
echo "Profiling reports are ready to be viewed."
96+
echo ""
97+
echo "CPU Profiling Reports:"
98+
echo " * Graph (CPU): https://${{ github.repository_owner }}.github.io/${{ github.event.repository.name }}/pr-${{ github.event.pull_request.number }}/cpu-profile/graph-cpu.html"
99+
echo " * Flamegraph (CPU): https://${{ github.repository_owner }}.github.io/${{ github.event.repository.name }}/pr-${{ github.event.pull_request.number }}/cpu-profile/flamegraph-cpu.html"
100+
echo ""
101+
echo "Memory Profiling Reports:"
102+
echo " * Graph (Allocated Objects): https://${{ github.repository_owner }}.github.io/${{ github.event.repository.name }}/pr-${{ github.event.pull_request.number }}/mem-profile/graph-alloc_objects.html"
103+
echo " * Flamegraph (Allocated Space): https://${{ github.repository_owner }}.github.io/${{ github.event.repository.name }}/pr-${{ github.event.pull_request.number }}/mem-profile/flamegraph-alloc_space.html"
104+
echo ""
105+
echo "EOF"
106+
} >> $GITHUB_OUTPUT
107+
108+
- name: Create PR Comment with report links
109+
uses: thollander/actions-comment-pull-request@v3
110+
with:
111+
message: ${{ steps.generate_message.outputs.message }}

hack/reports/profiling.sh

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
#!/usr/bin/env bash
2+
3+
set -eu -o pipefail
4+
trap cleanup INT EXIT
5+
6+
# config
7+
declare DURATION=${DURATION:-30}
8+
declare KEPLER_PORT=${KEPLER_PORT:-28282}
9+
10+
# constants
11+
PROJECT_ROOT="$(git rev-parse --show-toplevel)"
12+
declare -r PROJECT_ROOT
13+
declare -r TMP_DIR="$PROJECT_ROOT/tmp"
14+
declare -r CPU_PROFILE_DIR="$TMP_DIR/cpu-profile"
15+
declare -r MEM_PROFILE_DIR="$TMP_DIR/mem-profile"
16+
declare -r KEPLER_BIN_DIR="$PROJECT_ROOT/bin"
17+
declare -r CPU_HTTP_PORT=29000
18+
declare -r MEM_HTTP_PORT=29001
19+
20+
source "$PROJECT_ROOT/hack/utils.bash"
21+
22+
cleanup() {
23+
info "Cleaning up ..."
24+
# Terminate all background jobs (e.g. pprof servers)
25+
{ jobs -p | xargs -I {} -- pkill -TERM -P {}; } || true
26+
wait
27+
sleep 1
28+
29+
return 0
30+
}
31+
32+
capture_cpu_profile() {
33+
run go tool pprof -proto -seconds "$DURATION" \
34+
-output "$CPU_PROFILE_DIR"/profile.pb.gz "$KEPLER_BIN_DIR/kepler" \
35+
"http://localhost:$KEPLER_PORT/debug/pprof/profile" || return 1
36+
37+
# Start pprof web server in background
38+
run go tool pprof --http "localhost:$CPU_HTTP_PORT" --no_browser \
39+
"$KEPLER_BIN_DIR/kepler" "$CPU_PROFILE_DIR/profile.pb.gz" </dev/null &
40+
sleep 1
41+
# Fetch visualizations
42+
for sample in {cpu,samples}; do
43+
curl --fail "http://localhost:$CPU_HTTP_PORT/ui/?si=$sample" -o "$CPU_PROFILE_DIR/graph-$sample.html" || return 1
44+
curl --fail "http://localhost:$CPU_HTTP_PORT/ui/flamegraph?si=$sample" -o "$CPU_PROFILE_DIR/flamegraph-$sample.html" || return 1
45+
for page in top peek source disasm; do
46+
curl --fail "http://localhost:$CPU_HTTP_PORT/ui/$page?si=$sample" -o "$CPU_PROFILE_DIR/$page-$sample.html" || return 1
47+
done
48+
done
49+
50+
return 0
51+
}
52+
53+
capture_mem_profile() {
54+
run go tool pprof -proto -seconds "$DURATION" \
55+
-output "$MEM_PROFILE_DIR"/profile.pb.gz "$KEPLER_BIN_DIR/kepler" \
56+
"http://localhost:$KEPLER_PORT/debug/pprof/heap" || return 1
57+
58+
# Start pprof web server in background
59+
run go tool pprof --http "localhost:$MEM_HTTP_PORT" --no_browser \
60+
"$KEPLER_BIN_DIR/kepler" "$MEM_PROFILE_DIR/profile.pb.gz" </dev/null &
61+
sleep 1
62+
# Fetch visualizations
63+
for sample in {alloc,inuse}_{objects,space}; do
64+
curl --fail "http://localhost:$MEM_HTTP_PORT/ui/?si=$sample" -o "$MEM_PROFILE_DIR/graph-$sample.html" || return 1
65+
curl --fail "http://localhost:$MEM_HTTP_PORT/ui/flamegraph?si=$sample" -o "$MEM_PROFILE_DIR/flamegraph-$sample.html" || return 1
66+
for page in top peek source disasm; do
67+
curl --fail "http://localhost:$MEM_HTTP_PORT/ui/$page?si=$sample" -o "$MEM_PROFILE_DIR/$page-$sample.html" || return 1
68+
done
69+
done
70+
71+
return 0
72+
}
73+
74+
main() {
75+
cd "$PROJECT_ROOT"
76+
mkdir -p "${CPU_PROFILE_DIR}"
77+
mkdir -p "${MEM_PROFILE_DIR}"
78+
79+
header "Running CPU Profiling"
80+
capture_cpu_profile || {
81+
fail "CPU Profiling failed"
82+
return 1
83+
}
84+
header "Running Memory Profiling"
85+
capture_mem_profile || {
86+
fail "Memory Profiling failed"
87+
return 1
88+
}
89+
}
90+
91+
main "$@"

0 commit comments

Comments
 (0)