mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-09-13 18:15:31 +08:00
feat: add core debug cmd for cpu/mem analysis (#9186)
This commit is contained in:
parent
a6a2d9991c
commit
d61a77bec7
1 changed files with 169 additions and 0 deletions
169
core/cmd/server/cmd/debug.go
Normal file
169
core/cmd/server/cmd/debug.go
Normal file
|
@ -0,0 +1,169 @@
|
|||
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-core debug --cpuprofile=cpu.prof --duration=30s
|
||||
|
||||
# Memory profiling
|
||||
1panel-core debug --memprofile=mem.prof
|
||||
|
||||
# Show memory statistics
|
||||
1panel-core debug --memstats
|
||||
|
||||
# Show goroutine information
|
||||
1panel-core debug --goroutine
|
||||
|
||||
# Combined profiling
|
||||
1panel-core 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.")
|
||||
}
|
Loading…
Add table
Reference in a new issue