1 /*
2  * Author:   David Robert Nadeau
3  * Site:     http://NadeauSoftware.com/
4  * License:  Creative Commons Attribution 3.0 Unported License
5  *           http://creativecommons.org/licenses/by/3.0/deed.en_US
6  * Modified: Holger Vogt, 2019
7  */
8 
9 #include "ngspice/ngspice.h"
10 #include "resource.h"
11 
12 #if defined(_WIN32)
13 #undef BOOLEAN
14 #include <windows.h>
15 #include <psapi.h>
16 
17 #elif defined(__unix__) || defined(__unix) || defined(unix) || (defined(__APPLE__) && defined(__MACH__))
18 #include <unistd.h>
19 #include <sys/resource.h>
20 
21 #if defined(__APPLE__) && defined(__MACH__)
22 #include <mach/mach.h>
23 
24 #elif (defined(_AIX) || defined(__TOS__AIX__)) || (defined(__sun__) || defined(__sun) || defined(sun) && (defined(__SVR4) || defined(__svr4__)))
25 #include <fcntl.h>
26 #include <procfs.h>
27 
28 #elif defined(__linux__) || defined(__linux) || defined(linux) || defined(__gnu_linux__)
29 #include <stdio.h>
30 
31 #endif
32 
33 #else
34 #error "Cannot define getPeakRSS( ) or getCurrentRSS( ) for an unknown OS."
35 #endif
36 
37 
38 /**
39  * Returns the peak (maximum so far) resident set size (physical
40  * memory use) measured in bytes, or zero if the value cannot be
41  * determined on this OS.
42  */
getPeakRSS(void)43 unsigned long long getPeakRSS(void)
44 {
45 #if defined(HAVE__PROC_MEMINFO)
46     /* Linux ---------------------------------------------------- */
47     unsigned long long rss = 0L;
48     FILE* fp = NULL;
49     if ( (fp = fopen( "/proc/self/statm", "r" )) == NULL )
50             return (unsigned long long) 0L; /* Can't open? */
51     if ( fscanf( fp, "%llu", &rss ) != 1 )
52     {
53         fclose( fp );
54         return 0L;      /* Can't read? */
55     }
56     fclose( fp );
57         return rss * (unsigned long long) sysconf(_SC_PAGESIZE);
58 
59 #elif defined(HAVE_GETRUSAGE)
60     /* BSD, Linux, and OSX --------------------------------------
61      * not (yet) available with CYGWIN */
62     struct rusage rusage;
63     getrusage(RUSAGE_SELF, &rusage);
64 #if defined(__APPLE__) && defined(__MACH__)
65     return (unsigned long long) rusage.ru_maxrss;
66 #else
67     return (unsigned long long) (rusage.ru_maxrss * 1024L);
68 #endif
69 
70 #elif defined(_WIN32)
71     /* Windows -------------------------------------------------- */
72     PROCESS_MEMORY_COUNTERS info;
73     GetProcessMemoryInfo( GetCurrentProcess( ), &info, sizeof(info) );
74         return (unsigned long long) info.PeakWorkingSetSize;
75 
76 #elif (defined(_AIX) || defined(__TOS__AIX__)) || (defined(__sun__) || defined(__sun) || defined(sun) && (defined(__SVR4) || defined(__svr4__)))
77     /* AIX and Solaris ------------------------------------------ */
78     struct psinfo psinfo;
79     int fd = -1;
80     if ( (fd = open( "/proc/self/psinfo", O_RDONLY )) == -1 )
81         return 0L;      /* Can't open? */
82     if ( read( fd, &psinfo, sizeof(psinfo) ) != sizeof(psinfo) )
83     {
84         close( fd );
85         return 0L;      /* Can't read? */
86     }
87     close( fd );
88         return (unsigned long long) (psinfo.pr_rssize * 1024L);
89 
90 #else
91     /* Unknown OS ----------------------------------------------- */
92     return 0L;          /* Unsupported. */
93 #endif
94 }
95 
96 
97 
98 
99 
100 /**
101  * Returns the current resident set size (physical memory use) measured
102  * in bytes, or zero if the value cannot be determined on this OS.
103  */
getCurrentRSS(void)104 unsigned long long getCurrentRSS(void)
105 {
106 #if defined(_WIN32)
107     /* Windows -------------------------------------------------- */
108     PROCESS_MEMORY_COUNTERS info;
109     GetProcessMemoryInfo( GetCurrentProcess( ), &info, sizeof(info) );
110         return (unsigned long long) info.WorkingSetSize;
111 
112 #elif defined(__APPLE__) && defined(__MACH__)
113     /* OSX ------------------------------------------------------ */
114     struct mach_task_basic_info info;
115     mach_msg_type_number_t infoCount = MACH_TASK_BASIC_INFO_COUNT;
116     if ( task_info( mach_task_self( ), MACH_TASK_BASIC_INFO,
117         (task_info_t)&info, &infoCount ) != KERN_SUCCESS )
118         return 0L;      /* Can't access? */
119         return (unsigned long long) info.resident_size;
120 
121 //#elif defined(__linux__) || defined(__linux) || defined(linux) || defined(__gnu_linux__)
122 #elif defined(HAVE__PROC_MEMINFO)
123     /* Linux ---------------------------------------------------- */
124     unsigned long long rss = 0L;
125     FILE* fp = NULL;
126     if ( (fp = fopen( "/proc/self/statm", "r" )) == NULL )
127             return (unsigned long long) 0L; /* Can't open? */
128     if ( fscanf( fp, "%*s%llu", &rss ) != 1 )
129     {
130         fclose( fp );
131         return 0L;      /* Can't read? */
132     }
133     fclose( fp );
134         return rss * (unsigned long long) sysconf(_SC_PAGESIZE);
135 
136 #else
137     /* AIX, BSD, Solaris, and Unknown OS ------------------------ */
138     return (unsigned long long) 0L; /* Unsupported. */
139 #endif
140 }
141