@@ -33,14 +33,178 @@ jobs:
33
33
mkdir -p /tmp/artifacts/
34
34
ARTIFACT_PATH=/tmp/artifacts make test-benchmark
35
35
36
- - name : Compare with baseline
36
+ - name : Convert Benchmark Output to Prometheus Metrics
37
37
run : |
38
- go install golang.org/x/perf/cmd/benchstat@latest
39
- benchstat benchmarks/baseline.txt /tmp/artifacts/new.txt | tee /tmp/artifacts/output
38
+ mkdir -p /tmp/artifacts/prometheus/
39
+ cat << 'EOF' > benchmark_to_prometheus.py
40
+ import sys
41
+ import re
40
42
41
- - name : Upload benchmark results
43
+ def parse_benchmark_output(benchmark_output):
44
+ metrics = []
45
+ for line in benchmark_output.split("\n"):
46
+ match = re.match(r"Benchmark([\w\d]+)-\d+\s+\d+\s+([\d]+)\s+ns/op\s+([\d]+)\s+B/op\s+([\d]+)\s+allocs/op", line)
47
+ if match:
48
+ benchmark_name = match.group(1).lower()
49
+ time_ns = match.group(2)
50
+ memory_bytes = match.group(3)
51
+ allocs = match.group(4)
52
+
53
+ metrics.append(f"benchmark_{benchmark_name}_ns {time_ns}")
54
+ metrics.append(f"benchmark_{benchmark_name}_allocs {allocs}")
55
+ metrics.append(f"benchmark_{benchmark_name}_mem_bytes {memory_bytes}")
56
+
57
+ return "\n".join(metrics)
58
+
59
+ if __name__ == "__main__":
60
+ benchmark_output = sys.stdin.read()
61
+ metrics = parse_benchmark_output(benchmark_output)
62
+ print(metrics)
63
+ EOF
64
+
65
+ cat /tmp/artifacts/new.txt | python3 benchmark_to_prometheus.py > /tmp/artifacts/prometheus/metrics.txt
66
+
67
+ # - name: Compare with baseline
68
+ # run: |
69
+ # go install golang.org/x/perf/cmd/benchstat@latest
70
+ # benchstat benchmarks/baseline.txt /tmp/artifacts/new.txt | tee /tmp/artifacts/output
71
+
72
+ - name : Upload Benchmark Metrics
73
+ uses : actions/upload-artifact@v4
74
+ with :
75
+ name : benchmark-metrics
76
+ path : /tmp/artifacts/prometheus/
77
+
78
+ start-prometheus :
79
+ needs : benchmark
80
+ runs-on : ubuntu-latest
81
+ steps :
82
+ - name : Checkout code
83
+ uses : actions/checkout@v4
84
+ with :
85
+ fetch-depth : 0
86
+
87
+ - name : Download Benchmark Metrics
88
+ uses : actions/download-artifact@v4
89
+ with :
90
+ name : benchmark-metrics
91
+ path : ./
92
+
93
+ - name : List Downloaded Metrics files
94
+ run : ls -lh
95
+
96
+ - name : Set Up Prometheus Config
97
+ run : |
98
+ cat << 'EOF' > prometheus.yml
99
+ global:
100
+ scrape_interval: 5s
101
+ scrape_configs:
102
+ - job_name: 'benchmark_metrics'
103
+ static_configs:
104
+ - targets: ['localhost:9000']
105
+ EOF
106
+ mkdir -p ${{ github.workspace }}/prometheus-data
107
+ sudo chown -R 65534:65534 ${{ github.workspace }}/prometheus-data
108
+ sudo chmod -R 777 ${{ github.workspace }}/prometheus-data
109
+
110
+ - name : Run Prometheus
111
+ run : |
112
+ docker run -d --name prometheus -p 9090:9090 \
113
+ -v ${{ github.workspace }}/prometheus.yml:/etc/prometheus/prometheus.yml \
114
+ -v ${{ github.workspace }}/prometheus-data:/prometheus \
115
+ prom/prometheus --config.file=/etc/prometheus/prometheus.yml \
116
+ --storage.tsdb.path=/prometheus --storage.tsdb.retention.time=1h --web.enable-admin-api
117
+
118
+ - name : Wait for Prometheus to start
119
+ run : sleep 10
120
+
121
+ - name : Check Prometheus is running
122
+ run : curl -s http://localhost:9090/-/ready || (docker logs prometheus && exit 1)
123
+
124
+ - name : Start HTTP Server to Expose Metrics
125
+ run : |
126
+ cat << 'EOF' > server.py
127
+ from http.server import SimpleHTTPRequestHandler, HTTPServer
128
+
129
+ class MetricsHandler(SimpleHTTPRequestHandler):
130
+ def do_GET(self):
131
+ if self.path == "/metrics":
132
+ self.send_response(200)
133
+ self.send_header("Content-type", "text/plain")
134
+ self.end_headers()
135
+ with open("metrics.txt", "r") as f:
136
+ self.wfile.write(f.read().encode())
137
+ else:
138
+ self.send_response(404)
139
+ self.end_headers()
140
+
141
+ if __name__ == "__main__":
142
+ server = HTTPServer(('0.0.0.0', 9000), MetricsHandler)
143
+ print("Serving on port 9000...")
144
+ server.serve_forever()
145
+ EOF
146
+
147
+ nohup python3 server.py &
148
+
149
+ - name : Wait for Prometheus to Collect Data
150
+ run : sleep 30
151
+
152
+ - name : Check Benchmark Metrics Against Threshold
153
+ run : |
154
+ MAX_TIME_NS=1200000000 # 1.2s
155
+ MAX_ALLOCS=4000
156
+ MAX_MEM_BYTES=450000
157
+
158
+ # Query Prometheus Metrics
159
+ time_ns=$(curl -s "http://localhost:9090/api/v1/query?query=benchmark_create_cluster_catalog_ns" | jq -r '.data.result[0].value[1]')
160
+ allocs=$(curl -s "http://localhost:9090/api/v1/query?query=benchmark_create_cluster_catalog_allocs" | jq -r '.data.result[0].value[1]')
161
+ mem_bytes=$(curl -s "http://localhost:9090/api/v1/query?query=benchmark_create_cluster_catalog_mem_bytes" | jq -r '.data.result[0].value[1]')
162
+
163
+ echo "⏳ Benchmark Execution Time: $time_ns ns"
164
+ echo "🛠️ Memory Allocations: $allocs"
165
+ echo "💾 Memory Usage: $mem_bytes bytes"
166
+
167
+ # threshold checking
168
+ if (( $(echo "$time_ns > $MAX_TIME_NS" | bc -l) )); then
169
+ echo "❌ ERROR: Execution time exceeds threshold!"
170
+ exit 1
171
+ fi
172
+
173
+ if (( $(echo "$allocs > $MAX_ALLOCS" | bc -l) )); then
174
+ echo "❌ ERROR: Too many memory allocations!"
175
+ exit 1
176
+ fi
177
+
178
+ if (( $(echo "$mem_bytes > $MAX_MEM_BYTES" | bc -l) )); then
179
+ echo "❌ ERROR: Memory usage exceeds threshold!"
180
+ exit 1
181
+ fi
182
+
183
+ echo "✅ All benchmarks passed within threshold!"
184
+
185
+ - name : Trigger Prometheus Snapshot
186
+ run : |
187
+ curl -X POST http://localhost:9090/api/v1/admin/tsdb/snapshot || (docker logs prometheus && exit 1)
188
+
189
+ - name : Find and Upload Prometheus Snapshot
190
+ run : |
191
+ SNAPSHOT_PATH=$(ls -td ${{ github.workspace }}/prometheus-data/snapshots/* 2>/dev/null | head -1 || echo "")
192
+ if [[ -z "$SNAPSHOT_PATH" ]]; then
193
+ echo "❌ No Prometheus snapshot found!"
194
+ docker logs prometheus
195
+ exit 1
196
+ fi
197
+
198
+ echo "✅ Prometheus snapshot stored in: $SNAPSHOT_PATH"
199
+ tar -czf $GITHUB_WORKSPACE/prometheus_snapshot.tar.gz -C "$SNAPSHOT_PATH" .
200
+
201
+
202
+ - name : Stop Prometheus
203
+ run : docker stop prometheus
204
+
205
+ - name : Upload Prometheus Snapshot
42
206
uses : actions/upload-artifact@v4
43
207
with :
44
- name : benchmark-artifacts
45
- path : /tmp/artifacts/
208
+ name : prometheus-snapshot
209
+ path : prometheus_snapshot.tar.gz
46
210
0 commit comments