mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-12-28 18:28:32 +08:00
169 lines
4.7 KiB
Go
169 lines
4.7 KiB
Go
package cmd
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"runtime"
|
|
"runtime/pprof"
|
|
"time"
|
|
|
|
"github.com/spf13/cobra"
|
|
)
|
|
|
|
var (
|
|
cpuProfile string
|
|
memProfile string
|
|
duration time.Duration
|
|
showMemStats bool
|
|
showGoroutine bool
|
|
)
|
|
|
|
func init() {
|
|
RootCmd.AddCommand(debugCmd)
|
|
|
|
debugCmd.Flags().StringVar(&cpuProfile, "cpuprofile", "", "write cpu profile to file")
|
|
debugCmd.Flags().StringVar(&memProfile, "memprofile", "", "write memory profile to file")
|
|
debugCmd.Flags().DurationVar(&duration, "duration", 30*time.Second, "duration for cpu profiling")
|
|
debugCmd.Flags().BoolVar(&showMemStats, "memstats", false, "show memory statistics")
|
|
debugCmd.Flags().BoolVar(&showGoroutine, "goroutine", false, "show goroutine profile")
|
|
}
|
|
|
|
var debugCmd = &cobra.Command{
|
|
Use: "debug",
|
|
Short: "Performance debugging with pprof",
|
|
Long: `Debug command provides CPU and memory profiling capabilities using pprof.
|
|
|
|
Examples:
|
|
# CPU profiling for 30 seconds
|
|
1panel-agent debug --cpuprofile=cpu.prof --duration=30s
|
|
|
|
# Memory profiling
|
|
1panel-agent debug --memprofile=mem.prof
|
|
|
|
# Show memory statistics
|
|
1panel-agent debug --memstats
|
|
|
|
# Show goroutine information
|
|
1panel-agent debug --goroutine
|
|
|
|
# Combined profiling
|
|
1panel-agent debug --cpuprofile=cpu.prof --memprofile=mem.prof --memstats`,
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
if cpuProfile != "" {
|
|
if err := startCPUProfile(cpuProfile); err != nil {
|
|
return fmt.Errorf("failed to start CPU profile: %v", err)
|
|
}
|
|
defer stopCPUProfile()
|
|
time.Sleep(duration)
|
|
fmt.Printf("CPU profile saved to: %s\n", cpuProfile)
|
|
}
|
|
|
|
if memProfile != "" {
|
|
if err := writeMemProfile(memProfile); err != nil {
|
|
return fmt.Errorf("failed to write memory profile: %v", err)
|
|
}
|
|
fmt.Printf("Memory profile saved to: %s\n", memProfile)
|
|
}
|
|
|
|
if showMemStats {
|
|
printMemStats()
|
|
}
|
|
|
|
if showGoroutine {
|
|
printGoroutineInfo()
|
|
}
|
|
|
|
if cpuProfile == "" && memProfile == "" && !showMemStats && !showGoroutine {
|
|
printBasicInfo()
|
|
}
|
|
return nil
|
|
},
|
|
}
|
|
|
|
func startCPUProfile(filename string) error {
|
|
f, err := os.Create(filename)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := pprof.StartCPUProfile(f); err != nil {
|
|
f.Close()
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func stopCPUProfile() {
|
|
pprof.StopCPUProfile()
|
|
}
|
|
|
|
func writeMemProfile(filename string) error {
|
|
f, err := os.Create(filename)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer f.Close()
|
|
|
|
runtime.GC()
|
|
|
|
if err := pprof.WriteHeapProfile(f); err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func printMemStats() {
|
|
var m runtime.MemStats
|
|
runtime.ReadMemStats(&m)
|
|
|
|
fmt.Println("\n=== Memory Statistics ===")
|
|
fmt.Printf("Allocated memory: %d KB (%d MB)\n", m.Alloc/1024, m.Alloc/1024/1024)
|
|
fmt.Printf("Total allocated: %d KB (%d MB)\n", m.TotalAlloc/1024, m.TotalAlloc/1024/1024)
|
|
fmt.Printf("System memory: %d KB (%d MB)\n", m.Sys/1024, m.Sys/1024/1024)
|
|
fmt.Printf("Heap allocated: %d KB (%d MB)\n", m.HeapAlloc/1024, m.HeapAlloc/1024/1024)
|
|
fmt.Printf("Heap system: %d KB (%d MB)\n", m.HeapSys/1024, m.HeapSys/1024/1024)
|
|
fmt.Printf("Heap idle: %d KB (%d MB)\n", m.HeapIdle/1024, m.HeapIdle/1024/1024)
|
|
fmt.Printf("Heap in use: %d KB (%d MB)\n", m.HeapInuse/1024, m.HeapInuse/1024/1024)
|
|
fmt.Printf("Heap released: %d KB (%d MB)\n", m.HeapReleased/1024, m.HeapReleased/1024/1024)
|
|
fmt.Printf("Heap objects: %d\n", m.HeapObjects)
|
|
fmt.Printf("GC runs: %d\n", m.NumGC)
|
|
fmt.Printf("GC pause total: %d ns\n", m.PauseTotalNs)
|
|
fmt.Printf("Next GC: %d KB (%d MB)\n", m.NextGC/1024, m.NextGC/1024/1024)
|
|
fmt.Printf("Last GC: %s\n", time.Unix(0, int64(m.LastGC)).Format("2006-01-02 15:04:05"))
|
|
}
|
|
|
|
func printGoroutineInfo() {
|
|
fmt.Println("\n=== Goroutine Information ===")
|
|
fmt.Printf("Number of goroutines: %d\n", runtime.NumGoroutine())
|
|
fmt.Printf("Number of CPUs: %d\n", runtime.NumCPU())
|
|
fmt.Printf("GOMAXPROCS: %d\n", runtime.GOMAXPROCS(0))
|
|
|
|
buf := make([]byte, 1024*1024)
|
|
stackSize := runtime.Stack(buf, true)
|
|
fmt.Printf("\nGoroutine stack trace (first 2048 bytes):\n")
|
|
if stackSize > 2048 {
|
|
fmt.Printf("%s...\n", buf[:2048])
|
|
fmt.Printf("(truncated, total size: %d bytes)\n", stackSize)
|
|
} else {
|
|
fmt.Printf("%s\n", buf[:stackSize])
|
|
}
|
|
}
|
|
|
|
func printBasicInfo() {
|
|
fmt.Println("=== Performance Debug Info ===")
|
|
fmt.Printf("Go version: %s\n", runtime.Version())
|
|
fmt.Printf("OS/Arch: %s/%s\n", runtime.GOOS, runtime.GOARCH)
|
|
fmt.Printf("CPUs: %d\n", runtime.NumCPU())
|
|
fmt.Printf("GOMAXPROCS: %d\n", runtime.GOMAXPROCS(0))
|
|
fmt.Printf("Goroutines: %d\n", runtime.NumGoroutine())
|
|
|
|
var m runtime.MemStats
|
|
runtime.ReadMemStats(&m)
|
|
fmt.Printf("Memory allocated: %d KB\n", m.Alloc/1024)
|
|
fmt.Printf("Total allocations: %d KB\n", m.TotalAlloc/1024)
|
|
fmt.Printf("GC runs: %d\n", m.NumGC)
|
|
|
|
fmt.Println("\nUse --help to see available profiling options.")
|
|
}
|