1 /* Authors: Lutong Wang and Bangqi Xu */
2 /*
3  * Copyright (c) 2019, The Regents of the University of California
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *     * Redistributions of source code must retain the above copyright
9  *       notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above copyright
11  *       notice, this list of conditions and the following disclaimer in the
12  *       documentation and/or other materials provided with the distribution.
13  *     * Neither the name of the University nor the
14  *       names of its contributors may be used to endorse or promote products
15  *       derived from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS BE LIABLE FOR ANY DIRECT,
21  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 /*
30  * Author:  David Robert Nadeau
31  * Site:    http://NadeauSoftware.com/
32  * License: Creative Commons Attribution 3.0 Unported License
33  *          http://creativecommons.org/licenses/by/3.0/deed.en_US
34  */
35 
36 #if defined(_WIN32)
37 #include <psapi.h>
38 #include <windows.h>
39 
40 #elif defined(__unix__) || defined(__unix) || defined(unix) \
41     || (defined(__APPLE__) && defined(__MACH__))
42 #include <sys/resource.h>
43 #include <unistd.h>
44 
45 #if defined(__APPLE__) && defined(__MACH__)
46 #include <mach/mach.h>
47 
48 #elif (defined(_AIX) || defined(__TOS__AIX__)) \
49     || (defined(__sun__) || defined(__sun)     \
50         || defined(sun) && (defined(__SVR4) || defined(__svr4__)))
51 #include <fcntl.h>
52 #include <procfs.h>
53 
54 #elif defined(__linux__) || defined(__linux) || defined(linux) \
55     || defined(__gnu_linux__)
56 #include <stdio.h>
57 
58 #endif
59 
60 #else
61 #error "Cannot define getPeakRSS( ) or getCurrentRSS( ) for an unknown OS."
62 #endif
63 
64 /**
65  * Returns the peak (maximum so far) resident set size (physical
66  * memory use) measured in bytes, or zero if the value cannot be
67  * determined on this OS.
68  */
getPeakRSS()69 size_t getPeakRSS()
70 {
71 #if defined(_WIN32)
72   /* Windows -------------------------------------------------- */
73   PROCESS_MEMORY_COUNTERS info;
74   GetProcessMemoryInfo(GetCurrentProcess(), &info, sizeof(info));
75   return (size_t) info.PeakWorkingSetSize;
76 
77 #elif (defined(_AIX) || defined(__TOS__AIX__)) \
78     || (defined(__sun__) || defined(__sun)     \
79         || defined(sun) && (defined(__SVR4) || defined(__svr4__)))
80   /* AIX and Solaris ------------------------------------------ */
81   struct psinfo psinfo;
82   int fd = -1;
83   if ((fd = open("/proc/self/psinfo", O_RDONLY)) == -1)
84     return (size_t) 0L; /* Can't open? */
85   if (read(fd, &psinfo, sizeof(psinfo)) != sizeof(psinfo)) {
86     close(fd);
87     return (size_t) 0L; /* Can't read? */
88   }
89   close(fd);
90   return (size_t)(psinfo.pr_rssize * 1024L);
91 
92 #elif defined(__unix__) || defined(__unix) || defined(unix) \
93     || (defined(__APPLE__) && defined(__MACH__))
94   /* BSD, Linux, and OSX -------------------------------------- */
95   struct rusage rusage;
96   getrusage(RUSAGE_SELF, &rusage);
97 #if defined(__APPLE__) && defined(__MACH__)
98   return (size_t) rusage.ru_maxrss;
99 #else
100   return (size_t)(rusage.ru_maxrss * 1024L);
101 #endif
102 
103 #else
104   /* Unknown OS ----------------------------------------------- */
105   return (size_t) 0L; /* Unsupported. */
106 #endif
107 }
108 
109 /**
110  * Returns the current resident set size (physical memory use) measured
111  * in bytes, or zero if the value cannot be determined on this OS.
112  */
getCurrentRSS()113 size_t getCurrentRSS()
114 {
115 #if defined(_WIN32)
116   /* Windows -------------------------------------------------- */
117   PROCESS_MEMORY_COUNTERS info;
118   GetProcessMemoryInfo(GetCurrentProcess(), &info, sizeof(info));
119   return (size_t) info.WorkingSetSize;
120 
121 #elif defined(__APPLE__) && defined(__MACH__)
122   /* OSX ------------------------------------------------------ */
123   struct mach_task_basic_info info;
124   mach_msg_type_number_t infoCount = MACH_TASK_BASIC_INFO_COUNT;
125   if (task_info(mach_task_self(),
126                 MACH_TASK_BASIC_INFO,
127                 (task_info_t) &info,
128                 &infoCount)
129       != KERN_SUCCESS)
130     return (size_t) 0L; /* Can't access? */
131   return (size_t) info.resident_size;
132 
133 #elif defined(__linux__) || defined(__linux) || defined(linux) \
134     || defined(__gnu_linux__)
135   /* Linux ---------------------------------------------------- */
136   long rss = 0L;
137   FILE* fp = NULL;
138   if ((fp = fopen("/proc/self/statm", "r")) == NULL)
139     return (size_t) 0L; /* Can't open? */
140   if (fscanf(fp, "%*s%ld", &rss) != 1) {
141     fclose(fp);
142     return (size_t) 0L; /* Can't read? */
143   }
144   fclose(fp);
145   return (size_t) rss * (size_t) sysconf(_SC_PAGESIZE);
146 
147 #else
148   /* AIX, BSD, Solaris, and Unknown OS ------------------------ */
149   return (size_t) 0L; /* Unsupported. */
150 #endif
151 }
152