@@ -50,39 +50,77 @@ func (p *DarwinMemoryProvider) AvailableMemory() (uint64, error) {
5050 return 0 , fmt .Errorf ("vm_stat: %w" , err )
5151 }
5252
53- lines := strings .Split (string (out ), "\n " )
53+ pageSize , bodyLines := parseVMStatHeader (string (out ))
54+
55+ var freePages , inactivePages uint64
56+ for _ , line := range bodyLines {
57+ line = strings .TrimSpace (line )
58+ if strings .HasPrefix (line , "Pages free:" ) {
59+ freePages = parseVMStatValue (line )
60+ } else if strings .HasPrefix (line , "Pages inactive:" ) {
61+ inactivePages = parseVMStatValue (line )
62+ }
63+ }
64+
65+ return (freePages + inactivePages ) * pageSize , nil
66+ }
67+
68+ // WiredMemory returns the amount of wired (non-pageable) memory by parsing vm_stat.
69+ func (p * DarwinMemoryProvider ) WiredMemory () (uint64 , error ) {
70+ out , err := exec .Command ("vm_stat" ).Output ()
71+ if err != nil {
72+ return 0 , fmt .Errorf ("vm_stat: %w" , err )
73+ }
74+
75+ pageSize , lines := parseVMStatHeader (string (out ))
76+ for _ , line := range lines {
77+ line = strings .TrimSpace (line )
78+ if strings .HasPrefix (line , "Pages wired down:" ) {
79+ return parseVMStatValue (line ) * pageSize , nil
80+ }
81+ }
82+ return 0 , fmt .Errorf ("vm_stat: 'Pages wired down' not found" )
83+ }
84+
85+ // ProcessRSS returns the resident set size of a process in bytes.
86+ func (p * DarwinMemoryProvider ) ProcessRSS (pid int ) (uint64 , error ) {
87+ out , err := exec .Command ("ps" , "-o" , "rss=" , "-p" ,
88+ strconv .Itoa (pid )).Output ()
89+ if err != nil {
90+ return 0 , fmt .Errorf ("ps rss for pid %d: %w" , pid , err )
91+ }
92+ // ps reports RSS in kilobytes
93+ kb , err := strconv .ParseUint (strings .TrimSpace (string (out )), 10 , 64 )
94+ if err != nil {
95+ return 0 , fmt .Errorf (
96+ "parse rss for pid %d: %w" , pid , err )
97+ }
98+ return kb * 1024 , nil
99+ }
100+
101+ // parseVMStatHeader extracts the page size and body lines from vm_stat output.
102+ func parseVMStatHeader (output string ) (uint64 , []string ) {
103+ lines := strings .Split (output , "\n " )
54104 if len (lines ) == 0 {
55- return 0 , fmt . Errorf ( "vm_stat: empty output" )
105+ return 16384 , nil
56106 }
57107
58- // First line contains page size: "Mach Virtual Memory Statistics: (page size of 16384 bytes)"
59108 var pageSize uint64
60109 firstLine := lines [0 ]
61110 if idx := strings .Index (firstLine , "page size of " ); idx >= 0 {
62111 sizeStr := firstLine [idx + len ("page size of " ):]
63112 if endIdx := strings .Index (sizeStr , " " ); endIdx >= 0 {
64113 sizeStr = sizeStr [:endIdx ]
65114 }
66- pageSize , err = strconv .ParseUint (sizeStr , 10 , 64 )
67- if err ! = nil {
68- return 0 , fmt . Errorf ( "parse page size %q: %w" , sizeStr , err )
115+ parsed , err : = strconv .ParseUint (sizeStr , 10 , 64 )
116+ if err = = nil {
117+ pageSize = parsed
69118 }
70119 }
71120 if pageSize == 0 {
72121 pageSize = 16384 // default to 16KB for Apple Silicon
73122 }
74-
75- var freePages , inactivePages uint64
76- for _ , line := range lines [1 :] {
77- line = strings .TrimSpace (line )
78- if strings .HasPrefix (line , "Pages free:" ) {
79- freePages = parseVMStatValue (line )
80- } else if strings .HasPrefix (line , "Pages inactive:" ) {
81- inactivePages = parseVMStatValue (line )
82- }
83- }
84-
85- return (freePages + inactivePages ) * pageSize , nil
123+ return pageSize , lines [1 :]
86124}
87125
88126// parseVMStatValue extracts the numeric value from a vm_stat line like "Pages free: 123456."
0 commit comments