191 lines
No EOL
7.7 KiB
Bash
Executable file
191 lines
No EOL
7.7 KiB
Bash
Executable file
#!/bin/bash
|
|
# analyse_instruments.sh
|
|
# Usage: ./analyse_instruments.sh instruments_output_20260513_212052
|
|
|
|
set -uo pipefail
|
|
|
|
OUTPUT_DIR="${1:?Usage: $0 <output_dir>}"
|
|
|
|
if [[ ! -d "$OUTPUT_DIR" ]]; then
|
|
echo "❌ Directory not found: $OUTPUT_DIR"
|
|
exit 1
|
|
fi
|
|
|
|
echo ""
|
|
echo "═══════════════════════════════════════════════════════════════"
|
|
echo "INSTRUMENTS SESSION ANALYSIS"
|
|
echo "Directory: $OUTPUT_DIR"
|
|
echo "Analysed: $(date)"
|
|
echo "═══════════════════════════════════════════════════════════════"
|
|
echo ""
|
|
|
|
# ── Session summary ───────────────────────────────────────────────────────
|
|
|
|
SUMMARY="${OUTPUT_DIR}/00_summary.txt"
|
|
if [[ -f "$SUMMARY" ]]; then
|
|
echo "── Session Summary ──────────────────────────────────────────────"
|
|
cat "$SUMMARY"
|
|
echo ""
|
|
fi
|
|
|
|
# ── Per-template results ──────────────────────────────────────────────────
|
|
|
|
echo "── Template Results ─────────────────────────────────────────────"
|
|
printf " %-30s %-6s %-8s %s\n" "Template" "Status" "Elapsed" "Trace"
|
|
printf " %-30s %-6s %-8s %s\n" \
|
|
"──────────────────────────────" "──────" "────────" "─────"
|
|
|
|
PASS_COUNT=0
|
|
SKIP_COUNT=0
|
|
FAIL_COUNT=0
|
|
MISSING_COUNT=0
|
|
|
|
for log in "${OUTPUT_DIR}"/*.txt; do
|
|
# Skip the summary file and load tester logs
|
|
[[ "$log" == *"00_summary"* ]] && continue
|
|
[[ "$log" == *"_load_tester"* ]] && continue
|
|
[[ -f "$log" ]] || continue
|
|
|
|
name=$(basename "$log" .txt | tr '_' ' ')
|
|
|
|
# Extract status and elapsed — handle both old and new log formats
|
|
status=$(grep "^Status:" "$log" 2>/dev/null | tail -1 | sed 's/^Status:[ ]*//')
|
|
elapsed=$(grep "^Elapsed:" "$log" 2>/dev/null | tail -1 | sed 's/^Elapsed:[ ]*//')
|
|
|
|
# Fallback if fields are empty
|
|
[[ -z "$status" ]] && status="unknown"
|
|
[[ -z "$elapsed" ]] && elapsed="?"
|
|
|
|
# Check if a trace file was copied for this template
|
|
SAFE=$(echo "$name" | tr ' ' '_')
|
|
if [[ -d "${OUTPUT_DIR}/${SAFE}.trace" ]]; then
|
|
trace_status="✅ yes"
|
|
else
|
|
trace_status="❌ no"
|
|
MISSING_COUNT=$((MISSING_COUNT + 1))
|
|
fi
|
|
|
|
icon="✅"
|
|
case "$status" in
|
|
PASS) PASS_COUNT=$((PASS_COUNT + 1)) ;;
|
|
SKIP) SKIP_COUNT=$((SKIP_COUNT + 1)); icon="⚠️ " ;;
|
|
FAIL) FAIL_COUNT=$((FAIL_COUNT + 1)); icon="❌" ;;
|
|
*) icon="❓" ;;
|
|
esac
|
|
|
|
printf " %-30s %s %-4s %-8s %s\n" \
|
|
"$name" "$icon" "$status" "$elapsed" "$trace_status"
|
|
done
|
|
|
|
echo ""
|
|
echo " Pass: $PASS_COUNT Skip: $SKIP_COUNT Fail: $FAIL_COUNT Missing traces: $MISSING_COUNT"
|
|
echo ""
|
|
|
|
# ── Trace files ───────────────────────────────────────────────────────────
|
|
|
|
echo "── Trace Files in Output Directory ─────────────────────────────"
|
|
TRACE_COUNT=0
|
|
while IFS= read -r -d '' trace; do
|
|
size=$(du -sh "$trace" 2>/dev/null | awk '{print $1}')
|
|
name=$(basename "$trace")
|
|
printf " %-40s %s\n" "$name" "$size"
|
|
TRACE_COUNT=$((TRACE_COUNT + 1))
|
|
done < <(find "$OUTPUT_DIR" -name "*.trace" -print0 2>/dev/null)
|
|
|
|
if [[ $TRACE_COUNT -eq 0 ]]; then
|
|
echo " No .trace files found in $OUTPUT_DIR"
|
|
echo ""
|
|
echo " Searching common locations for recent traces…"
|
|
FOUND_ELSEWHERE=false
|
|
for search_dir in \
|
|
"${HOME}/Library/Instruments" \
|
|
"${HOME}/Documents/Instruments" \
|
|
"target/instruments"; do
|
|
if [[ -d "$search_dir" ]]; then
|
|
COUNT=$(find "$search_dir" -name "*.trace" -maxdepth 3 2>/dev/null | wc -l | tr -d ' ')
|
|
if [[ "$COUNT" -gt 0 ]]; then
|
|
echo " Found $COUNT trace(s) in: $search_dir"
|
|
find "$search_dir" -name "*.trace" -maxdepth 3 2>/dev/null \
|
|
| sort -r | head -5 | sed 's/^/ /'
|
|
FOUND_ELSEWHERE=true
|
|
fi
|
|
fi
|
|
done
|
|
if [[ "$FOUND_ELSEWHERE" == "true" ]]; then
|
|
echo ""
|
|
echo " To copy them to the output directory:"
|
|
echo " cp -r ~/Library/Instruments/*.trace ${OUTPUT_DIR}/"
|
|
fi
|
|
fi
|
|
echo ""
|
|
|
|
# ── Load tester output during each template ───────────────────────────────
|
|
|
|
LOAD_LOGS=("${OUTPUT_DIR}"/*_load_tester.txt)
|
|
# Check if glob expanded (bash 3.2 compatible way)
|
|
if [[ -f "${LOAD_LOGS[0]}" ]]; then
|
|
echo "── Load Tester Output Per Template ─────────────────────────────"
|
|
for load_log in "${LOAD_LOGS[@]}"; do
|
|
[[ -f "$load_log" ]] || continue
|
|
template_name=$(basename "$load_log" _load_tester.txt | tr '_' ' ')
|
|
echo ""
|
|
echo " During: $template_name"
|
|
echo " $(printf '─%.0s' {1..50})"
|
|
|
|
if grep -q "CONCLUSION" "$load_log" 2>/dev/null; then
|
|
# Load tester completed — show the summary table
|
|
grep -A 30 "PROGRESSIVE LOAD REPORT" "$load_log" 2>/dev/null \
|
|
| head -30 | sed 's/^/ /'
|
|
elif grep -q "connected" "$load_log" 2>/dev/null; then
|
|
# Partial run — show last meaningful output
|
|
echo " (Partial run — load tester did not complete all profiles)"
|
|
grep "connected\|registered\|PASS\|FAIL\|Duration" "$load_log" \
|
|
2>/dev/null | tail -10 | sed 's/^/ /'
|
|
else
|
|
echo " (Load tester did not reach the server during this capture)"
|
|
tail -5 "$load_log" | sed 's/^/ /'
|
|
fi
|
|
done
|
|
echo ""
|
|
fi
|
|
|
|
# ── What to open ─────────────────────────────────────────────────────────
|
|
|
|
echo "── Next Steps ───────────────────────────────────────────────────"
|
|
echo ""
|
|
|
|
if [[ $TRACE_COUNT -gt 0 ]]; then
|
|
echo " Open all traces in Instruments.app:"
|
|
echo " open ${OUTPUT_DIR}/*.trace"
|
|
echo ""
|
|
echo " Priority order:"
|
|
for priority_name in \
|
|
"Time_Profiler" \
|
|
"Locks" \
|
|
"Thread_States" \
|
|
"Allocations" \
|
|
"Leaks" \
|
|
"Network"; do
|
|
trace="${OUTPUT_DIR}/${priority_name}.trace"
|
|
if [[ -d "$trace" ]]; then
|
|
echo " open \"${trace}\""
|
|
fi
|
|
done
|
|
else
|
|
echo " ⚠️ No traces in output directory."
|
|
echo " Run the profiling script again, or copy traces manually."
|
|
echo ""
|
|
echo " Quick re-run of the most important templates:"
|
|
echo " ./run_instruments.sh --template \"Time Profiler\" --time-limit 90"
|
|
echo " ./run_instruments.sh --template \"Locks\" --time-limit 90"
|
|
echo " ./run_instruments.sh --template \"Allocations\" --time-limit 90"
|
|
fi
|
|
|
|
echo ""
|
|
echo " Re-run a single template:"
|
|
echo " ./run_instruments.sh --template \"Time Profiler\" --time-limit 120"
|
|
echo ""
|
|
echo " Re-run everything:"
|
|
echo " pkill $BINARY 2>/dev/null || true"
|
|
echo " ./run_instruments.sh"
|
|
echo "" |