# Go Runtime Profiler Implementation
## Overview
The Go profiler provides **runtime profiling** of Go programs using Go's built-in `pprof` CPU profiler. Unlike static analysis, this profiles actual execution.
## How It Works
### Runtime Profiling Process
1. **Read Original Code** - Read the user's Go source file
2. **Auto-Instrument** - Automatically inject pprof instrumentation
3. **Build Binary** - Compile the instrumented Go program
4. **Run & Profile** - Execute and collect CPU profile data
5. **Analyze** - Parse pprof output to show hot functions
### Automatic Instrumentation
The profiler automatically adds to your code:
```go
import (
"os"
"runtime/pprof"
"fmt"
"time"
)
func main() {
// CPU Profiling setup (auto-injected)
f, err := os.Create("/tmp/go_cpu_profile.prof")
if err != nil {
fmt.Fprintf(os.Stderr, "could not create CPU profile: %v\n", err)
os.Exit(1)
}
defer f.Close()
if err := pprof.StartCPUProfile(f); err != nil {
fmt.Fprintf(os.Stderr, "could not start CPU profile: %v\n", err)
os.Exit(1)
}
defer pprof.StopCPUProfile()
// Auto-terminate after duration
go func() {
time.Sleep(5 * time.Second)
fmt.Println("\nProfiler: Time limit reached, stopping...")
os.Exit(0)
}()
// YOUR ORIGINAL CODE RUNS HERE
// ...
}
```
## Usage
### Requirements
- **Go toolchain** must be installed (`go` command available)
- Your Go program must have a `main()` function
- Program should run for at least the profiling duration
### Basic Runtime Profiling
```bash
cargo run -- go myprogram.go --runtime 5
```
This will:
1. Instrument your code with pprof
2. Build and run it for 5 seconds
3. Collect CPU profile data
4. Show hot functions and sample counts
### JSON Export with Runtime Data
```bash
cargo run -- go myprogram.go --runtime 5 --json output.json
```
Exports both static analysis and runtime profiling data to JSON.
### Static Analysis Only
```bash
cargo run -- go myprogram.go
```
Shows function count, struct count, imports, and complexity (no runtime execution).
## Example Output
### Runtime Profiling Output
```
Instrumenting Go program for profiling...
Building instrumented Go program...
Running Go program with CPU profiling for 3 seconds...
Calculator result: 1023
Fibonacci(10): 55
Primes found: 25
Intensive result: 5000234.56
Data average: 0.50
Profiler: Time limit reached, stopping...
=== Profiling Results for Go ===
File Size: 2450 bytes
Lines of Code: 115
Functions: 10
Structs: 1
Imports: 3
Complexity Score: 28
Details:
- Detected 10 function definitions
- Detected 1 struct definitions
- Detected 3 import statements
=== Runtime Profile (pprof) ===
Total samples collected: 1250
Unique functions executed: 8
Top 10 Hot Functions:
1. main.computeIntensive - 450 samples (36.00%)
2. main.processData - 320 samples (25.60%)
3. main.fibonacci - 210 samples (16.80%)
4. main.findPrimes - 150 samples (12.00%)
5. main.isPrime - 80 samples (6.40%)
6. main.main - 25 samples (2.00%)
7. main.(*Calculator).Multiply - 10 samples (0.80%)
8. main.(*Calculator).Add - 5 samples (0.40%)
```
## How Instrumentation Works
### Finding the main() Function
The profiler parses your Go code to find:
- Package declaration
- Import statements
- The `main()` function
### Injecting Profiling Code
It then wraps your `main()` with:
1. Profile file creation
2. CPU profiler start
3. Auto-termination goroutine
4. Your original code
5. Profile stop (via defer)
### Preserving Your Code
- All your original code is preserved
- Only adds profiling setup at the start of `main()`
- Handles existing imports intelligently
- Maintains your code structure
## pprof Analysis
After execution, the profiler uses `go tool pprof` to analyze:
```bash
go tool pprof -top -flat /tmp/go_cpu_profile.prof
```
This shows:
- **flat time**: Time spent in each function (not including callees)
- **cum time**: Cumulative time (including callees)
- **percentage**: % of total execution time
The profiler parses this output and ranks functions by CPU usage.
## Limitations & Notes
### Current Limitations
1. **Requires main()**: Your Go file must have a `main()` function
2. **Single file**: Works best with single-file programs
3. **Go toolchain**: Must have `go` command installed
4. **Duration accuracy**: Program must run at least the specified duration
### Why Runtime Profiling Matters
Static analysis tells you:
- How many functions exist
- Code structure
- Complexity metrics
Runtime profiling tells you:
- Which functions actually run
- Where CPU time is spent
- Performance bottlenecks
- Real execution behavior
### Compared to Python's py-spy
| **Method** | Attach to running process | Instrument & run |
| **Permissions** | Requires sudo | No sudo needed |
| **Integration** | External library | Built into Go |
| **Accuracy** | Sampling (10ms) | Built-in profiler |
| **Overhead** | Low | Very low |
## Troubleshooting
### "Go is not installed"
```bash
# Install Go
brew install go # macOS
# or download from https://go.dev/dl/
```
### "Profile data was not generated"
Your program might be exiting before the duration. Make sure it:
- Runs for at least the specified time
- Doesn't crash or exit early
- Has a proper `main()` function
### Build Errors
If instrumentation fails:
- Check that your Go code compiles normally: `go build myprogram.go`
- Ensure you have a `main()` function
- Check for syntax errors in your code
### No Hot Functions Found
If pprof shows no data:
- Increase the runtime duration
- Make sure your program actually does work
- Check that CPU profiling captured data
## Example: Profiling a Web Server
```go
// server.go
package main
import (
"fmt"
"net/http"
"time"
)
func handler(w http.ResponseWriter, r *http.Request) {
// Simulate work
time.Sleep(10 * time.Millisecond)
fmt.Fprintf(w, "Hello!")
}
func main() {
http.HandleFunc("/", handler)
fmt.Println("Server starting on :8080")
http.ListenAndServe(":8080", nil)
}
```
Profile it:
```bash
# Run for 10 seconds while handling requests
cargo run -- go server.go --runtime 10
```
The profiler will show which functions consume CPU time.
## Advanced: Manual pprof Usage
If you want more control, you can manually instrument your code:
```go
import (
"os"
"runtime/pprof"
)
func main() {
f, _ := os.Create("cpu.prof")
defer f.Close()
pprof.StartCPUProfile(f)
defer pprof.StopCPUProfile()
// Your code here
}
```
Then analyze with:
```bash
go tool pprof -http=:8080 cpu.prof # Web UI
go tool pprof -text cpu.prof # Text output
go tool pprof -pdf cpu.prof > profile.pdf # PDF report
```
## Summary
The Go profiler provides **true runtime profiling** by:
- ✅ Automatically instrumenting your code with pprof
- ✅ Building and running your actual program
- ✅ Collecting real CPU profile data
- ✅ Showing which functions consume the most time
- ✅ No manual code changes required
- ✅ Works with any Go program that has `main()`
This is **runtime profiling**, not static analysis - it shows actual execution behavior! 🚀