casacore
Loading...
Searching...
No Matches
HostInfoLinux.h
Go to the documentation of this file.
1//# HostInfo_linux.h: Linux specific memory, swap, and CPU code.
2
3 /*
4 ** This is a greatly MODIFIED version of a "top" machine dependent file.
5 ** The only resemblance it bears to the original is with respect to the
6 ** mechanics of finding various system details. The copyright details
7 ** follow.
8 **
9 ** --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
10 **
11 ** Top users/processes display for Unix
12 ** Version 3
13 **
14 ** This program may be freely redistributed,
15 ** but this entire comment MUST remain intact.
16 **
17 ** Copyright (c) 1984, 1989, William LeFebvre, Rice University
18 ** Copyright (c) 1989 - 1994, William LeFebvre, Northwestern University
19 ** Copyright (c) 1994, 1995, William LeFebvre, Argonne National Laboratory
20 ** Copyright (c) 1996, William LeFebvre, Group sys Consulting
21 ** Copyright (c) 2002, Associated Universities Inc.
22 */
23
24#ifndef CASA_HOSTINFOLINUX_H
25#define CASA_HOSTINFOLINUX_H
26
27# if defined(HOSTINFO_DO_IMPLEMENT)
28
29/*
30 * AUTHOR: Darrell Schiebel <drs@nrao.edu>
31 *
32 * ORIGINAL AUTHORS: Richard Henderson <rth@tamu.edu>
33 * Alexey Klimkin <kad@klon.tme.mcst.ru>
34 *
35 *
36 */
37
38#ifndef _GNU_SOURCE
39#define _GNU_SOURCE
40#endif
41#include <sched.h>
42#include <string.h>
43#include <ctype.h>
44#include <sys/types.h>
45#include <sys/stat.h>
46#include <sys/vfs.h>
47#include <unistd.h>
48#include <fcntl.h>
49#include <stdio.h>
50#include <stdlib.h>
51#include <fstream>
52#include <iostream>
53#include <string>
54#include <sstream>
55#include <vector>
56#include <limits>
57#include <sys/time.h>
58#include <sys/resource.h>
59
60
61// <summary>
62// HostInfo for Linux machines.
63// </summary>
64
65// <use visibility=local>
66
67// <reviewed reviewer="UNKNOWN" date="before2004/08/25" tests="" demos="">
68// </reviewed>
69
70// <prerequisite>
71// <li> <linkto class=HostInfo>HostInfo</linkto>
72// </prerequisite>
73
74// <synopsis>
75// This file provides the Linux specific functions for HostInfo.
76// It is selectively included by HostInfo.cc.
77// </synopsis>
78//
79// <group name="HostInfo">
80
81#if 0
82#include <linux/proc_fs.h> /* for PROC_SUPER_MAGIC */
83#else
84#define PROC_SUPER_MAGIC 0x9fa0
85#endif
86
87#define PROCFS "/proc"
88#define CPUINFO "/proc/cpuinfo"
89#define MEMINFO "/proc/meminfo"
90
91#define bytetok(x) (((x) + 512) >> 10)
92
93namespace casacore { //# NAMESPACE CASACORE - BEGIN
94
95class HostMachineInfo {
96friend class HostInfo;
97
98 HostMachineInfo( );
99 void update_info( );
100
101 int valid;
102 int cpus;
103
104 ptrdiff_t memory_total;
105 ptrdiff_t memory_used;
106 ptrdiff_t memory_free;
107
108 ptrdiff_t swap_total;
109 ptrdiff_t swap_used;
110 ptrdiff_t swap_free;
111};
112
113// </group>
114
115
116static inline char *
117skip_ws(const char *p)
118{
119 while (isspace(*p)) p++;
120 return (char *)p;
121}
122
123static inline char *
124skip_token(const char *p)
125{
126 while (isspace(*p)) p++;
127 while (*p && !isspace(*p)) p++;
128 return (char *)p;
129}
130
131// get integer value from v1 cgroup hierarchy of current processes, if
132// sub_value is set it returns the entry of a collection identified by value,
133// e.g. total_rss from memory.stat
134// returns std::numeric_limits<uInt64>::max() on error
135// note unset cgroup limits usually have intptr_t.max()
136// does not support v2 cgroups
137static inline uInt64
138get_cgroup_limit(std::string group, std::string value, std::string sub_value="")
139{
140 uInt64 result = std::numeric_limits<uInt64>::max();
141 // assume common location, technically one needs to search for mounts
142 const std::string cgroup = std::string("/sys/fs/cgroup/") + group + "/";
143
144 // get hierarchy of current process, v1 format: id:controller:hierarchy
145 std::string line;
146 std::ifstream ifs("/proc/self/cgroup", std::ifstream::in);
147 std::string hierarchy;
148 while (getline(ifs, line)) {
149 std::stringstream ss(line);
150 std::string token;
151 std::vector<std::string> fields;
152 while (getline(ss, token, ':')) {
153 fields.push_back(token);
154 }
155 if (fields.size() % 3 != 0) {
156 return result;
157 }
158 for (std::vector<std::string>::size_type i=1; i < fields.size(); i+=3) {
159 if (fields[i].find(group) != std::string::npos) {
160 hierarchy = fields[i + 1] + "/";
161 }
162 }
163 }
164 if (hierarchy.size() == 0) {
165 return result;
166 }
167
168 std::ifstream flimit((cgroup + hierarchy + value).c_str(), std::ifstream::in);
169 // if hierarchy does not exist we might be in a namespace, use the root group
170 if (!flimit.is_open()) {
171 flimit.open((cgroup + value).c_str(), std::ifstream::in);
172 }
173 if (flimit.is_open()) {
174 if (!sub_value.empty()) {
175 /* scan 'key value' entry like memory.stat for key == sub_value */
176 while (getline(flimit, line)) {
177 std::stringstream ss(line);
178 std::string token;
179 ss >> token;
180 if (token == sub_value) {
181 ss >> result;
182 break;
183 }
184 }
185 }
186 else {
187 flimit >> result;
188 }
189 }
190 return result;
191}
192
193HostMachineInfo::HostMachineInfo( ) : valid(1)
194{
195 char buffer[4096+1];
196 char *p;
197
198 /* get number of usable CPUs */
199 cpu_set_t cpuset;
200 if (sched_getaffinity(0, sizeof(cpuset), &cpuset) == 0) {
201# ifdef CPU_COUNT /* glibc < 2.6 */
202 cpus = CPU_COUNT(&cpuset);
203# else
204 for (int i = 0; i < CPU_SETSIZE; i++) {
205 if (CPU_ISSET(i, &cpuset)) {
206 cpus++;
207 }
208 }
209# endif
210 }
211 else {
212#ifndef AIPS_CRAY_PGI
213 /* make sure the proc filesystem is mounted */
214 {
215 struct statfs sb;
216 if (statfs(PROCFS, &sb) < 0 || sb.f_type != PROC_SUPER_MAGIC)
217 {
218 fprintf( stderr, "proc filesystem not mounted on " PROCFS "\n" );
219 valid = 0;
220 return;
221 }
222 }
223#endif
224
225 /* get number of CPUs */
226 {
227 cpus = 0;
228 FILE *fptr = fopen(CPUINFO, "r");
229 while ( (p = fgets( buffer, sizeof(buffer), fptr )) ) {
230 if ( ! strncmp( p, "processor", 9 ) ) ++cpus;
231 }
232 fclose(fptr);
233 }
234 }
235
236 update_info();
237}
238
239void HostMachineInfo::update_info( )
240{
241 char buffer[4096+1];
242 int fd, len;
243
244 /* get system wide memory usage */
245 {
246 char *p;
247 unsigned long sys_mem_total, sys_mem_free, sys_mem_cached,
248 sys_mem_avail, sys_swap_total, sys_swap_free;
249
250 fd = open(MEMINFO, O_RDONLY);
251 len = ::read(fd, buffer, sizeof(buffer)-1);
252 close(fd);
253 buffer[len] = '\0';
254
255 p = strstr(buffer, "MemTotal:");
256
257 if (sscanf (p,"MemTotal: %lu kB\nMemFree: %lu kB\n",
258 &sys_mem_total, &sys_mem_free) != 2)
259 cerr << "Error parsing MemTotal and MemFree in /proc/meminfo\n";
260
261 p = strstr (buffer, "Cached:");
262 if (sscanf (p,"Cached: %lu kB\n", &sys_mem_cached) != 1)
263 cerr << "Error parsing Cached in /proc/meminfo\n";
264
265 /* available since 3.14, real available memory accounting for
266 * unreclaimable page cache and slab cache */
267 p = strstr (buffer, "MemAvailable:");
268 if (!p || sscanf (p,"MemAvailable: %lu kB\n", &sys_mem_avail) != 1) {
269 /* too old kernel, estimate via cache and free */
270 sys_mem_avail = sys_mem_cached + sys_mem_free;
271 }
272
273 /* check resource limits, note that these are not enforced by linux */
274 struct rlimit rlim;
275 if (getrlimit(RLIMIT_RSS, &rlim) == 0 && rlim.rlim_cur > 0) {
276 sys_mem_total = std::min(rlim.rlim_cur / 1024, (rlim_t)sys_mem_total);
277 /* without cgroups we cannot determine available memory within the limit */
278 sys_mem_avail = std::min(sys_mem_total, sys_mem_avail);
279 }
280
281 /* can't use more memory than allowed by cgroups, enforced */
282 uInt64 proc_mem_max = get_cgroup_limit("memory", "memory.limit_in_bytes") / 1024;
283 /* usage_in_bytes also includes cache so use memory.stat */
284 uInt64 proc_mem_used = get_cgroup_limit("memory", "memory.stat", "total_rss") / 1024;
285
286 /* set HostInfo memoryTotal() */
287 memory_total = std::min((uInt64)sys_mem_total, proc_mem_max);
288
289 /* if we have a valid cgroup limit we can determine memoryFree() exactly */
290 if (proc_mem_max <= sys_mem_total && proc_mem_used <= proc_mem_max) {
291 memory_free = proc_mem_max - proc_mem_used;
292 }
293 else {
294 /* no cgroups so we have to assume all memory of host is available */
295 memory_free = std::min((uInt64)sys_mem_avail, (uInt64)memory_total);
296 }
297 memory_used = memory_total - memory_free;
298
299 p = strstr (buffer, "SwapTotal:");
300 if (sscanf (p, "SwapTotal: %lu kB\nSwapFree: %lu kB\n",
301 &sys_swap_total, &sys_swap_free) != 2)
302 cerr << "Error parsing SwapTotal and SwapFree in /proc/meminfo\n";
303
304 /* can't use more swap than allowed by cgroups */
305 uInt64 proc_swap_max = get_cgroup_limit("memory", "memory.memsw.limit_in_bytes") / 1024;
306 uInt64 proc_swap_used = get_cgroup_limit("memory", "memory.stat", "total_swap") / 1024;
307 /* limit is mem + swap */
308 if (proc_mem_max <= sys_mem_total && proc_mem_max <= proc_swap_max) {
309 proc_swap_max = proc_swap_max - proc_mem_max;
310 }
311
312 /* set swapTotal() */
313 swap_total = std::min((uInt64)sys_swap_total, proc_swap_max);
314
315 if (proc_swap_max <= (uInt64)swap_total && proc_swap_used <= proc_swap_max) {
316 swap_free = proc_swap_max - proc_swap_used;
317 }
318 else {
319 swap_free = sys_swap_free;
320 }
321 swap_used = swap_total - swap_free;
322 }
323}
324
325} //# NAMESPACE CASACORE - END
326
327# endif
328
329#endif
this file contains all the compiler specific defines
Definition mainpage.dox:28
void close() override
Flush and close the file.
LatticeExprNode value(const LatticeExprNode &expr)
This function returns the value of the expression without a mask.
unsigned long long uInt64
Definition aipsxtype.h:37