| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141 |
- //go:build darwin || linux || windows
- package libbox
- import (
- "os"
- "path/filepath"
- "runtime"
- "strings"
- "time"
- "github.com/sagernet/sing-box/experimental/libbox/internal/oomprofile"
- "github.com/sagernet/sing-box/service/oomkiller"
- "github.com/sagernet/sing/common/byteformats"
- "github.com/sagernet/sing/common/memory"
- )
- func init() {
- sOOMReporter = &oomReporter{}
- }
- var oomReportProfiles = []string{
- "allocs",
- "block",
- "goroutine",
- "heap",
- "mutex",
- "threadcreate",
- }
- type oomReportMetadata struct {
- reportMetadata
- RecordedAt string `json:"recordedAt"`
- MemoryUsage string `json:"memoryUsage"`
- AvailableMemory string `json:"availableMemory,omitempty"`
- // Heap
- HeapAlloc string `json:"heapAlloc,omitempty"`
- HeapObjects uint64 `json:"heapObjects,omitempty,string"`
- HeapInuse string `json:"heapInuse,omitempty"`
- HeapIdle string `json:"heapIdle,omitempty"`
- HeapReleased string `json:"heapReleased,omitempty"`
- HeapSys string `json:"heapSys,omitempty"`
- // Stack
- StackInuse string `json:"stackInuse,omitempty"`
- StackSys string `json:"stackSys,omitempty"`
- // Runtime metadata
- MSpanInuse string `json:"mSpanInuse,omitempty"`
- MSpanSys string `json:"mSpanSys,omitempty"`
- MCacheSys string `json:"mCacheSys,omitempty"`
- BuckHashSys string `json:"buckHashSys,omitempty"`
- GCSys string `json:"gcSys,omitempty"`
- OtherSys string `json:"otherSys,omitempty"`
- Sys string `json:"sys,omitempty"`
- // GC & runtime
- TotalAlloc string `json:"totalAlloc,omitempty"`
- NumGC uint32 `json:"numGC,omitempty,string"`
- NumGoroutine int `json:"numGoroutine,omitempty,string"`
- NextGC string `json:"nextGC,omitempty"`
- LastGC string `json:"lastGC,omitempty"`
- }
- type oomReporter struct{}
- var _ oomkiller.OOMReporter = (*oomReporter)(nil)
- func (r *oomReporter) WriteReport(memoryUsage uint64) error {
- now := time.Now().UTC()
- reportsDir := filepath.Join(sWorkingPath, "oom_reports")
- err := os.MkdirAll(reportsDir, 0o777)
- if err != nil {
- return err
- }
- chownReport(reportsDir)
- destPath, err := nextAvailableReportPath(reportsDir, now)
- if err != nil {
- return err
- }
- err = os.MkdirAll(destPath, 0o777)
- if err != nil {
- return err
- }
- chownReport(destPath)
- for _, name := range oomReportProfiles {
- writeOOMProfile(destPath, name)
- }
- writeReportFile(destPath, "cmdline", []byte(strings.Join(os.Args, "\000")))
- var memStats runtime.MemStats
- runtime.ReadMemStats(&memStats)
- metadata := oomReportMetadata{
- reportMetadata: baseReportMetadata(),
- RecordedAt: now.Format(time.RFC3339),
- MemoryUsage: byteformats.FormatMemoryBytes(memoryUsage),
- // Heap
- HeapAlloc: byteformats.FormatMemoryBytes(memStats.HeapAlloc),
- HeapObjects: memStats.HeapObjects,
- HeapInuse: byteformats.FormatMemoryBytes(memStats.HeapInuse),
- HeapIdle: byteformats.FormatMemoryBytes(memStats.HeapIdle),
- HeapReleased: byteformats.FormatMemoryBytes(memStats.HeapReleased),
- HeapSys: byteformats.FormatMemoryBytes(memStats.HeapSys),
- // Stack
- StackInuse: byteformats.FormatMemoryBytes(memStats.StackInuse),
- StackSys: byteformats.FormatMemoryBytes(memStats.StackSys),
- // Runtime metadata
- MSpanInuse: byteformats.FormatMemoryBytes(memStats.MSpanInuse),
- MSpanSys: byteformats.FormatMemoryBytes(memStats.MSpanSys),
- MCacheSys: byteformats.FormatMemoryBytes(memStats.MCacheSys),
- BuckHashSys: byteformats.FormatMemoryBytes(memStats.BuckHashSys),
- GCSys: byteformats.FormatMemoryBytes(memStats.GCSys),
- OtherSys: byteformats.FormatMemoryBytes(memStats.OtherSys),
- Sys: byteformats.FormatMemoryBytes(memStats.Sys),
- // GC & runtime
- TotalAlloc: byteformats.FormatMemoryBytes(memStats.TotalAlloc),
- NumGC: memStats.NumGC,
- NumGoroutine: runtime.NumGoroutine(),
- NextGC: byteformats.FormatMemoryBytes(memStats.NextGC),
- }
- if memStats.LastGC > 0 {
- metadata.LastGC = time.Unix(0, int64(memStats.LastGC)).UTC().Format(time.RFC3339)
- }
- availableMemory := memory.Available()
- if availableMemory > 0 {
- metadata.AvailableMemory = byteformats.FormatMemoryBytes(availableMemory)
- }
- writeReportMetadata(destPath, metadata)
- copyConfigSnapshot(destPath)
- return nil
- }
- func writeOOMProfile(destPath string, name string) {
- filePath, err := oomprofile.WriteFile(destPath, name)
- if err != nil {
- return
- }
- chownReport(filePath)
- }
|