summaryrefslogtreecommitdiff
path: root/profiling
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2025-06-26 13:49:38 +0300
committerPaul Buetow <paul@buetow.org>2025-06-26 13:49:38 +0300
commit6664996ced62c77e0c62bc1619662cbed7fccff6 (patch)
treeb995d8aa34aa68ec8f97c4be417ac96e6c6abf48 /profiling
parent72828b8c5f575cfc7c7c27c5a5d3b7fd9225b625 (diff)
feat: add profiling framework with command echoing
Created a comprehensive profiling framework for dtail commands (dcat, dgrep, dmap) to analyze CPU usage and memory allocations. The framework now prints all executed commands to stdout for full transparency. Key features: - Integrated Go profiling (CPU, memory, allocations) into all three commands - Created profile.sh bash script for analyzing pprof profiles - Added multiple Makefile targets for different profiling scenarios - Automated profiling scripts with command echoing - Support for different data sizes (quick, normal, full) - Special handling for dmap MapReduce format All profiling commands are now echoed to stdout before execution, making it easy to understand what the framework is doing and reproduce commands manually. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
Diffstat (limited to 'profiling')
-rwxr-xr-xprofiling/profile.sh210
1 files changed, 210 insertions, 0 deletions
diff --git a/profiling/profile.sh b/profiling/profile.sh
new file mode 100755
index 0000000..d0be9e2
--- /dev/null
+++ b/profiling/profile.sh
@@ -0,0 +1,210 @@
+#!/bin/bash
+
+# dprofile - Simple profile analysis script for dtail
+# A lightweight wrapper around go tool pprof
+
+set -e
+
+# Colors
+GREEN='\033[0;32m'
+YELLOW='\033[1;33m'
+RED='\033[0;31m'
+NC='\033[0m' # No Color
+
+# Default values
+TOP_N=10
+SORT_BY="flat"
+LIST_MODE=false
+PROFILE_PATH=""
+
+# Usage function
+usage() {
+ echo "dprofile - Analyze pprof profiles"
+ echo ""
+ echo "Usage:"
+ echo " dprofile <profile> # Analyze a profile"
+ echo " dprofile -list [directory] # List profiles in directory"
+ echo " dprofile -top N <profile> # Show top N functions (default: 10)"
+ echo " dprofile -cum <profile> # Sort by cumulative value"
+ echo " dprofile -web <profile> # Open web browser with flame graph"
+ echo " dprofile -text <profile> # Full text report"
+ echo " dprofile -help # Show this help"
+ echo ""
+ echo "Examples:"
+ echo " dprofile profiles/dcat_cpu_*.prof"
+ echo " dprofile -top 20 -cum profiles/dgrep_mem_*.prof"
+ echo " dprofile -list profiles/"
+ echo " dprofile -web profiles/dmap_cpu_*.prof"
+ exit 1
+}
+
+# Parse arguments
+while [[ $# -gt 0 ]]; do
+ case $1 in
+ -help|--help|-h)
+ usage
+ ;;
+ -list|--list)
+ LIST_MODE=true
+ shift
+ if [[ $# -gt 0 && ! "$1" =~ ^- ]]; then
+ PROFILE_DIR="$1"
+ shift
+ else
+ PROFILE_DIR="."
+ fi
+ ;;
+ -top|--top)
+ shift
+ TOP_N="$1"
+ shift
+ ;;
+ -cum|--cum)
+ SORT_BY="cum"
+ shift
+ ;;
+ -web|--web)
+ shift
+ if [[ $# -eq 0 ]]; then
+ echo "Error: -web requires a profile file"
+ exit 1
+ fi
+ echo -e "${GREEN}Opening web browser for $1...${NC}"
+ echo "Press Ctrl+C to stop the server"
+ exec go tool pprof -http=:8080 "$1"
+ ;;
+ -text|--text)
+ shift
+ if [[ $# -eq 0 ]]; then
+ echo "Error: -text requires a profile file"
+ exit 1
+ fi
+ exec go tool pprof -text "$1"
+ ;;
+ -*)
+ echo "Unknown option: $1"
+ usage
+ ;;
+ *)
+ PROFILE_PATH="$1"
+ shift
+ ;;
+ esac
+done
+
+# List mode
+if $LIST_MODE; then
+ echo -e "${GREEN}Profile files in $PROFILE_DIR:${NC}"
+ echo ""
+
+ # Group by tool and type
+ declare -A profiles
+
+ for file in "$PROFILE_DIR"/*.prof; do
+ if [[ -f "$file" ]]; then
+ basename=$(basename "$file")
+ # Extract tool and type (e.g., dcat_cpu -> "dcat cpu")
+ if [[ $basename =~ ^([^_]+)_([^_]+)_.*\.prof$ ]]; then
+ tool="${BASH_REMATCH[1]}"
+ type="${BASH_REMATCH[2]}"
+ key="$tool:$type"
+
+ if [[ -z "${profiles[$key]}" ]]; then
+ profiles[$key]="$file"
+ else
+ profiles[$key]="${profiles[$key]}|$file"
+ fi
+ fi
+ fi
+ done
+
+ # Display grouped profiles
+ current_tool=""
+ for key in $(echo "${!profiles[@]}" | tr ' ' '\n' | sort); do
+ IFS=':' read -r tool type <<< "$key"
+
+ if [[ "$tool" != "$current_tool" ]]; then
+ [[ -n "$current_tool" ]] && echo
+ echo -e "${YELLOW}$tool profiles:${NC}"
+ current_tool="$tool"
+ fi
+
+ echo " $type:"
+ IFS='|' read -ra files <<< "${profiles[$key]}"
+ for file in "${files[@]}"; do
+ size=$(ls -lh "$file" 2>/dev/null | awk '{print $5}')
+ timestamp=$(basename "$file" | grep -oE '[0-9]{8}_[0-9]{6}' || echo "unknown")
+ echo " $(basename "$file") ($size) - $timestamp"
+ done
+ done
+
+ [[ -z "$current_tool" ]] && echo " No profile files found in $PROFILE_DIR"
+ exit 0
+fi
+
+# Check if profile path provided
+if [[ -z "$PROFILE_PATH" ]]; then
+ usage
+fi
+
+# Check if file exists
+if [[ ! -f "$PROFILE_PATH" ]]; then
+ echo -e "${RED}Error: Profile file not found: $PROFILE_PATH${NC}"
+ exit 1
+fi
+
+# Detect profile type
+PROFILE_TYPE="unknown"
+if go tool pprof -raw "$PROFILE_PATH" 2>/dev/null | grep -q "samples/count"; then
+ PROFILE_TYPE="cpu"
+elif go tool pprof -raw "$PROFILE_PATH" 2>/dev/null | grep -q "alloc_space"; then
+ PROFILE_TYPE="memory"
+elif go tool pprof -raw "$PROFILE_PATH" 2>/dev/null | grep -q "inuse_space"; then
+ PROFILE_TYPE="memory"
+fi
+
+# Analyze profile
+echo -e "${GREEN}Profile Analysis: $PROFILE_PATH${NC}"
+echo "Type: $PROFILE_TYPE"
+echo ""
+
+# Get top functions
+echo "Top $TOP_N functions (sorted by $SORT_BY):"
+echo "================================================================"
+
+# Use different flags based on sort order
+if [[ "$SORT_BY" == "cum" ]]; then
+ echo "# Command: go tool pprof -top -cum -nodecount=$TOP_N $PROFILE_PATH"
+ go tool pprof -top -cum -nodecount="$TOP_N" "$PROFILE_PATH" 2>/dev/null | \
+ grep -E "^[[:space:]]*[0-9]+" | head -n "$TOP_N" || true
+else
+ echo "# Command: go tool pprof -top -nodecount=$TOP_N $PROFILE_PATH"
+ go tool pprof -top -nodecount="$TOP_N" "$PROFILE_PATH" 2>/dev/null | \
+ grep -E "^[[:space:]]*[0-9]+" | head -n "$TOP_N" || true
+fi
+
+echo ""
+
+# Provide helpful tips based on profile type
+if [[ "$PROFILE_TYPE" == "cpu" ]]; then
+ echo -e "${YELLOW}CPU Profile Tips:${NC}"
+ echo "- flat: time spent in the function itself"
+ echo "- cum: time spent in the function and its callees"
+ echo "- Focus on functions with high flat% for optimization"
+ echo ""
+ echo "Interactive exploration:"
+ echo " go tool pprof $PROFILE_PATH"
+ echo ""
+ echo "Generate flame graph:"
+ echo " dprofile -web $PROFILE_PATH"
+elif [[ "$PROFILE_TYPE" == "memory" ]]; then
+ echo -e "${YELLOW}Memory Profile Tips:${NC}"
+ echo "- Shows memory allocations by function"
+ echo "- Focus on unexpected allocations in hot paths"
+ echo ""
+ echo "View all allocations:"
+ echo " go tool pprof -alloc_space $PROFILE_PATH"
+ echo ""
+ echo "View in-use memory:"
+ echo " go tool pprof -inuse_space $PROFILE_PATH"
+fi \ No newline at end of file