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