@@ -1850,20 +1850,33 @@ void displayMemoryUsageDetails() {
18501850
18511851 // Query the actual Resident Set Size (RSS) for the PID
18521852 pid_t pid = getCurrentPID();
1853- ulong currentRSS = getRSS(pid);
1854- addLogEntry(" current Resident Set Size (RSS) = " ~ to! string (currentRSS) ~ " KB" );
1853+ ulong currentRSS;
1854+ version (FreeBSD ) {
1855+ currentRSS = getRSSFreeBSD(pid);
1856+ } else version (linux ) {
1857+ currentRSS = getRSSLinux(pid);
1858+ } else {
1859+ currentRSS = getRSS(pid);
1860+ }
18551861
1856- // Calculate difference
1857- if (previousRSS != 0 ) {
1858- addLogEntry(" previous Resident Set Size (RSS) = " ~ to! string (previousRSS) ~ " KB" );
1859- // Delta between current and previous RSS
1860- long rssDifference = cast (long ) currentRSS - cast (long ) previousRSS;
1861- string sign = rssDifference > 0 ? " +" : (rssDifference < 0 ? " " : " " );
1862- addLogEntry(" difference in Resident Set Size (RSS) = " ~ sign ~ to! string (rssDifference) ~ " KB" );
1862+ if (currentRSS != 0 ) {
1863+ addLogEntry(" current Resident Set Size (RSS) = " ~ to! string (currentRSS) ~ " KB" );
1864+
1865+ // Calculate difference
1866+ if (previousRSS != 0 ) {
1867+ addLogEntry(" previous Resident Set Size (RSS) = " ~ to! string (previousRSS) ~ " KB" );
1868+ // Delta between current and previous RSS
1869+ long rssDifference = cast (long ) currentRSS - cast (long ) previousRSS;
1870+ string sign = rssDifference > 0 ? " +" : (rssDifference < 0 ? " " : " " );
1871+ addLogEntry(" difference in Resident Set Size (RSS) = " ~ sign ~ to! string (rssDifference) ~ " KB" );
1872+ }
1873+
1874+ // Update the previous RSS value only after a valid RSS sample
1875+ previousRSS = currentRSS;
1876+ } else {
1877+ addLogEntry(" current Resident Set Size (RSS) = unavailable" );
18631878 }
18641879
1865- // Update the previous RSS value
1866- previousRSS = currentRSS;
18671880 addLogEntry(" -----------------------------------------------------" );
18681881 addLogEntry();
18691882}
@@ -2008,48 +2021,156 @@ void forceExit() {
20082021
20092022// Get the current PID of the application
20102023pid_t getCurrentPID () {
2011- // The '/proc/self' is a symlink to the current process's proc directory
2012- string path = " /proc/self/stat" ;
2013-
2014- // Read the content of the stat file
2015- string content;
2016- try {
2017- content = readText(path);
2018- } catch (Exception e) {
2019- writeln(" Failed to read stat file: " , e.msg);
2020- return 0 ;
2021- }
2022-
2023- // The first value in the stat file is the PID
2024- auto parts = split(content);
2025- return to! pid_t (parts[0 ]); // Convert the first part to pid_t
2024+ return getpid ();
20262025}
20272026
20282027// Access the Resident Set Size (RSS) based on the PID of the running application
20292028ulong getRSS (pid_t pid) {
2030- // Construct the path to the statm file for the given PID
2031- string path = format(" /proc/%s/statm" , to! string (pid));
2029+ version (FreeBSD ) {
2030+ return getRSSFreeBSD (pid);
2031+ } else version (linux ) {
2032+ return getRSSLinux (pid);
2033+ } else {
2034+ return 0 ;
2035+ }
2036+ }
20322037
2033- // Read the content of the file
2034- string content;
2035- try {
2036- content = readText(path) ;
2037- } catch ( Exception e) {
2038- writeln( " Failed to read statm file: " , e.msg);
2039- return 0 ;
2040- }
2038+ // Access the Resident Set Size (RSS) using the Linux /proc filesystem
2039+ ulong getRSSLinux ( pid_t pid) {
2040+ if (pid <= 0 ) {
2041+ return 0 ;
2042+ }
2043+
2044+ // Construct the path to the statm file for the given PID
2045+ string path = format( " /proc/%s/statm " , to ! string (pid));
20412046
2042- // Split the content and get the RSS (second value)
2043- auto stats = split(content);
2044- if (stats.length < 2 ) {
2045- writeln(" Unexpected format in statm file." );
2046- return 0 ;
2047- }
2047+ // Read the content of the file
2048+ string content;
2049+ try {
2050+ content = readText(path);
2051+ } catch (Exception e) {
2052+ addLogEntry(" Failed to read statm file: " ~ e.msg);
2053+ return 0 ;
2054+ }
20482055
2049- // RSS is in pages, convert it to kilobytes
2050- ulong rssPages = to! ulong (stats[1 ]);
2051- ulong rssKilobytes = rssPages * sysconf(_SC_PAGESIZE) / 1024 ;
2052- return rssKilobytes;
2056+ // Split the content and get the RSS (second value)
2057+ auto stats = split(content);
2058+ if (stats.length < 2 ) {
2059+ addLogEntry(" Unexpected format in statm file: " ~ path);
2060+ return 0 ;
2061+ }
2062+
2063+ // RSS is in pages, convert it to kilobytes
2064+ ulong rssPages;
2065+ try {
2066+ rssPages = to! ulong (stats[1 ]);
2067+ } catch (Exception e) {
2068+ addLogEntry(" Failed to parse RSS page count from statm file: " ~ path ~ " : " ~ e.msg);
2069+ return 0 ;
2070+ }
2071+
2072+ auto pageSize = sysconf(_SC_PAGESIZE);
2073+ if (pageSize <= 0 ) {
2074+ addLogEntry(" Failed to determine system page size while calculating Linux RSS" );
2075+ return 0 ;
2076+ }
2077+
2078+ ulong rssKilobytes = (rssPages * cast (ulong ) pageSize) / 1024 ;
2079+ return rssKilobytes;
2080+ }
2081+
2082+ // Access the Resident Set Size (RSS) using FreeBSD-native process telemetry
2083+ ulong getRSSFreeBSD (pid_t pid) {
2084+ if (pid <= 0 ) {
2085+ return 0 ;
2086+ }
2087+
2088+ version (FreeBSD ) {
2089+ import core.sys.freebsd.sys.sysctl : CTL_KERN , KERN_PROC , KERN_PROC_PID , sysctl;
2090+ import core.sys.freebsd.sys.types : segsz_t , vm_size_t;
2091+ import core.sys.posix.signal : sigset_t;
2092+ import core.sys.posix.sys.types : gid_t , uid_t ;
2093+
2094+ // DRuntime does not expose sys/user.h as a portable kinfo_proc binding, so
2095+ // define only the stable kinfo_proc prefix required to reach ki_rssize.
2096+ // The full sysctl result is still queried into a correctly-sized byte buffer.
2097+ extern (C ) struct FreeBSDKinfoProcRSSPrefix {
2098+ int ki_structsize;
2099+ int ki_layout;
2100+ void * ki_args;
2101+ void * ki_paddr;
2102+ void * ki_addr;
2103+ void * ki_tracep;
2104+ void * ki_textvp;
2105+ void * ki_fd;
2106+ void * ki_vmspace;
2107+ const (void )* ki_wchan;
2108+ pid_t ki_pid;
2109+ pid_t ki_ppid;
2110+ pid_t ki_pgid;
2111+ pid_t ki_tpgid;
2112+ pid_t ki_sid;
2113+ pid_t ki_tsid;
2114+ short ki_jobc;
2115+ short ki_spare_short1;
2116+ uint ki_tdev_freebsd11;
2117+ sigset_t ki_siglist;
2118+ sigset_t ki_sigmask;
2119+ sigset_t ki_sigignore;
2120+ sigset_t ki_sigcatch;
2121+ uid_t ki_uid;
2122+ uid_t ki_ruid;
2123+ uid_t ki_svuid;
2124+ gid_t ki_rgid;
2125+ gid_t ki_svgid;
2126+ short ki_ngroups;
2127+ short ki_spare_short2;
2128+ gid_t [16 ] ki_groups;
2129+ vm_size_t ki_size;
2130+ segsz_t ki_rssize;
2131+ }
2132+
2133+ int [4 ] mib = [
2134+ CTL_KERN ,
2135+ KERN_PROC ,
2136+ KERN_PROC_PID ,
2137+ cast (int ) pid
2138+ ];
2139+
2140+ size_t processInfoLength;
2141+ if (sysctl(mib.ptr, cast (uint ) mib.length, null , &processInfoLength, null , 0 ) != 0 ) {
2142+ addLogEntry(" Failed to determine FreeBSD process RSS buffer size via sysctl for PID: " ~ to! string (pid));
2143+ return 0 ;
2144+ }
2145+
2146+ if (processInfoLength < FreeBSDKinfoProcRSSPrefix.sizeof) {
2147+ addLogEntry(" Failed to query FreeBSD process RSS via sysctl: returned process information is too small for PID: " ~ to! string (pid));
2148+ return 0 ;
2149+ }
2150+
2151+ auto processInfo = new ubyte [](processInfoLength);
2152+ if (sysctl(mib.ptr, cast (uint ) mib.length, processInfo.ptr, &processInfoLength, null , 0 ) != 0 ) {
2153+ addLogEntry(" Failed to query FreeBSD process RSS via sysctl for PID: " ~ to! string (pid));
2154+ return 0 ;
2155+ }
2156+
2157+ if (processInfoLength < FreeBSDKinfoProcRSSPrefix.sizeof) {
2158+ addLogEntry(" Failed to query FreeBSD process RSS via sysctl: incomplete process information returned for PID: " ~ to! string (pid));
2159+ return 0 ;
2160+ }
2161+
2162+ auto processInfoPrefix = cast (FreeBSDKinfoProcRSSPrefix* ) processInfo.ptr;
2163+ auto pageSize = sysconf(_SC_PAGESIZE);
2164+ if (pageSize <= 0 ) {
2165+ addLogEntry(" Failed to determine system page size while calculating FreeBSD RSS" );
2166+ return 0 ;
2167+ }
2168+
2169+ // FreeBSD reports ki_rssize in pages.
2170+ return (cast (ulong ) processInfoPrefix.ki_rssize * cast (ulong ) pageSize) / 1024 ;
2171+ } else {
2172+ return 0 ;
2173+ }
20532174}
20542175
20552176// Getting around the @nogc problem
0 commit comments