HostInfoLinux.h

Go to the documentation of this file.
00001 //# HostInfo_linux.h: Linux specific memory, swap, and CPU code.
00002 //# $Id$
00003 
00004  /*
00005  **  This is a greatly MODIFIED version of a "top" machine dependent file.
00006  **  The only resemblance it bears to the original is with respect to the
00007  **  mechanics of finding various system details. The copyright details
00008  **  follow.
00009  **
00010  **  --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
00011  **
00012  **  Top users/processes display for Unix
00013  **  Version 3
00014  **
00015  **  This program may be freely redistributed,
00016  **  but this entire comment MUST remain intact.
00017  **
00018  **  Copyright (c) 1984, 1989, William LeFebvre, Rice University
00019  **  Copyright (c) 1989 - 1994, William LeFebvre, Northwestern University
00020  **  Copyright (c) 1994, 1995, William LeFebvre, Argonne National Laboratory
00021  **  Copyright (c) 1996, William LeFebvre, Group sys Consulting
00022  **  Copyright (c) 2002, Associated Universities Inc.
00023  */
00024 
00025 #ifndef CASA_HOSTINFOLINUX_H
00026 #define CASA_HOSTINFOLINUX_H
00027 
00028 # if defined(HOSTINFO_DO_IMPLEMENT)
00029 
00030 /*
00031  *          AUTHOR:       Darrell Schiebel  <drs@nrao.edu>
00032  *
00033  * ORIGINAL AUTHORS:      Richard Henderson <rth@tamu.edu>
00034  *                        Alexey Klimkin    <kad@klon.tme.mcst.ru>
00035  *
00036  *
00037  */
00038 
00039 #ifndef _GNU_SOURCE
00040 #define _GNU_SOURCE
00041 #endif
00042 #include <sched.h>
00043 #include <string.h>
00044 #include <ctype.h>
00045 #include <sys/types.h>
00046 #include <sys/stat.h>
00047 #include <sys/vfs.h>
00048 #include <unistd.h>
00049 #include <fcntl.h>
00050 #include <stdio.h>
00051 #include <stdlib.h>
00052 #include <fstream>
00053 #include <iostream>
00054 #include <string>
00055 #include <sstream>
00056 #include <vector>
00057 #include <limits>
00058 
00059 // <summary>
00060 // HostInfo for Linux machines.
00061 // </summary>
00062 
00063 // <use visibility=local>
00064 
00065 // <reviewed reviewer="UNKNOWN" date="before2004/08/25" tests="" demos="">
00066 // </reviewed>
00067 
00068 // <prerequisite>
00069 //   <li> <linkto class=HostInfo>HostInfo</linkto>
00070 // </prerequisite>
00071 
00072 // <synopsis> 
00073 // This file provides the Linux specific functions for HostInfo.
00074 // It is selectively included by HostInfo.cc.
00075 // </synopsis>
00076 //
00077 // <group name="HostInfo">
00078 
00079 #if 0
00080 #include <linux/proc_fs.h>      /* for PROC_SUPER_MAGIC */
00081 #else
00082 #define PROC_SUPER_MAGIC 0x9fa0
00083 #endif
00084 
00085 #define PROCFS "/proc"
00086 #define CPUINFO "/proc/cpuinfo"
00087 #define MEMINFO "/proc/meminfo"
00088 
00089 #define bytetok(x)      (((x) + 512) >> 10)
00090 
00091 namespace casacore { //# NAMESPACE CASACORE - BEGIN
00092 
00093 class HostMachineInfo {
00094 friend class HostInfo;
00095   
00096     HostMachineInfo( );
00097     void update_info( );
00098 
00099     int valid;
00100     int cpus;
00101 
00102     ptrdiff_t memory_total;
00103     ptrdiff_t memory_used;
00104     ptrdiff_t memory_free;
00105 
00106     ptrdiff_t swap_total;
00107     ptrdiff_t swap_used;
00108     ptrdiff_t swap_free;
00109 };
00110 
00111 // </group>
00112 
00113 
00114 static inline char *
00115 skip_ws(const char *p)
00116 {
00117     while (isspace(*p)) p++;
00118     return (char *)p;
00119 }
00120     
00121 static inline char *
00122 skip_token(const char *p)
00123 {
00124     while (isspace(*p)) p++;
00125     while (*p && !isspace(*p)) p++;
00126     return (char *)p;
00127 }
00128 
00129 // get integer value from v1 cgroup hierarchy of current processes, if
00130 // sub_value is set it returns the entry of a collection identified by value,
00131 // e.g. total_rss from memory.stat
00132 // returns std::numeric_limits<size_t>::max() on error
00133 // note unset cgroup limits usually have intptr_t.max()
00134 // does not support v2 cgroups
00135 static inline size_t
00136 get_cgroup_limit(std::string group, std::string value, std::string sub_value="")
00137 {
00138     size_t result = std::numeric_limits<size_t>::max();
00139     // assume common location, technically one needs to search for mounts
00140     const std::string cgroup = std::string("/sys/fs/cgroup/") + group + "/";
00141 
00142     // get hierarchy of current process, v1 format: id:controller:hierarchy
00143     std::string line;
00144     std::ifstream ifs("/proc/self/cgroup", std::ifstream::in);
00145     std::string hierarchy;
00146     while (getline(ifs, line)) {
00147         std::stringstream ss(line);
00148         std::string token;
00149         std::vector<std::string> fields;
00150         while (getline(ss, token, ':')) {
00151             fields.push_back(token);
00152         }
00153         if (fields.size() % 3 != 0) {
00154             return result;
00155         }
00156         for (std::vector<std::string>::size_type i=1; i < fields.size(); i+=3) {
00157             if (fields[i].find(group) != std::string::npos) {
00158                 hierarchy = fields[i + 1] + "/";
00159             }
00160         }
00161     }
00162     if (hierarchy.size() == 0) {
00163         return result;
00164     }
00165 
00166     std::ifstream flimit((cgroup + hierarchy + value).c_str(), std::ifstream::in);
00167     // if hierarchy does not exist we might be in a namespace, use the root group
00168     if (!flimit.is_open()) {
00169         flimit.open((cgroup + value).c_str(), std::ifstream::in);
00170     }
00171     if (flimit.is_open()) {
00172         if (!sub_value.empty()) {
00173             /* scan 'key value' entry like memory.stat for key == sub_value */
00174             while (getline(flimit, line)) {
00175                 std::stringstream ss(line);
00176                 std::string token;
00177                 ss >> token;
00178                 if (token == sub_value) {
00179                     ss >> result;
00180                     break;
00181                 }
00182             }
00183         }
00184         else {
00185             flimit >> result;
00186         }
00187     }
00188     return result;
00189 }
00190 
00191 HostMachineInfo::HostMachineInfo( ) : valid(1)
00192 {
00193     char buffer[4096+1];
00194     char *p;
00195 
00196     /* get number of usable CPUs */
00197     cpu_set_t cpuset;
00198     if (sched_getaffinity(0, sizeof(cpuset), &cpuset) == 0) {
00199 # ifdef CPU_COUNT /* glibc < 2.6 */
00200         cpus = CPU_COUNT(&cpuset);
00201 # else
00202         for (int i = 0; i < CPU_SETSIZE; i++) {
00203             if (CPU_ISSET(i, &cpuset)) {
00204                 cpus++;
00205             }
00206         }
00207 # endif
00208     }
00209     else {
00210 #ifndef AIPS_CRAY_PGI
00211         /* make sure the proc filesystem is mounted */
00212         {
00213             struct statfs sb;
00214             if (statfs(PROCFS, &sb) < 0 || sb.f_type != PROC_SUPER_MAGIC)
00215             {
00216                 fprintf( stderr, "proc filesystem not mounted on " PROCFS "\n" );
00217                 valid = 0;
00218                 return;
00219             }
00220         }
00221 #endif
00222 
00223         /* get number of CPUs */
00224         {
00225             cpus = 0;
00226             FILE *fptr = fopen(CPUINFO, "r");
00227             while ( (p = fgets( buffer, sizeof(buffer), fptr )) ) {
00228                 if ( ! strncmp( p, "processor", 9 ) ) ++cpus;
00229             }
00230             fclose(fptr);
00231         }
00232     }
00233 
00234     update_info();
00235 }
00236 
00237 void HostMachineInfo::update_info( )
00238 {
00239     char buffer[4096+1];
00240     int fd, len;
00241 
00242     /* get system wide memory usage */
00243     {
00244         char *p;
00245         int ret;
00246         unsigned long mem_total, mem_free, mem_cached, swp_total, swp_free;
00247 
00248         fd = open(MEMINFO, O_RDONLY);
00249         len = read(fd, buffer, sizeof(buffer)-1);
00250         close(fd);
00251         buffer[len] = '\0';
00252 
00253         p = strstr(buffer, "MemTotal:");
00254 
00255         if ((ret = sscanf (p,"MemTotal: %lu kB\nMemFree: %lu kB\n",
00256                            &mem_total, &mem_free)) != 2)
00257             cerr << "Error parsing MemTotal and MemFree in /proc/meminfo\n";
00258 
00259         p = strstr (buffer, "Cached:");
00260         if ((ret = sscanf (p,"Cached: %lu kB\n", &mem_cached)) != 1)
00261             cerr << "Error parsing Cached in /proc/meminfo\n";
00262 
00263         // can't use more memory than allowed by cgroups
00264         size_t mem_max = get_cgroup_limit("memory", "memory.limit_in_bytes") / 1024;
00265         size_t mem_used = get_cgroup_limit("memory", "memory.stat", "total_rss") / 1024;
00266         memory_total = std::min((size_t)mem_total, mem_max);
00267         // no cgroup limit
00268         if (mem_used != std::numeric_limits<size_t>::max() / 1024 &&
00269             mem_max != std::numeric_limits<size_t>::max() / 1024) {
00270             memory_free = mem_max - mem_used;
00271         }
00272         else {
00273             memory_free = (size_t)(mem_free + mem_cached);
00274         }
00275         memory_used = memory_total - memory_free;
00276 
00277         p = strstr (buffer, "SwapTotal:");
00278         if ((ret = sscanf (p, "SwapTotal: %lu kB\nSwapFree: %lu kB\n",
00279                            &swp_total, &swp_free)) != 2)
00280             cerr << "Error parsing SwapTotal and SwapFree in /proc/meminfo\n";
00281 
00282         // can't use more swap than allowed by cgroups
00283         size_t swp_max = get_cgroup_limit("memory", "memory.memsw.limit_in_bytes") / 1024;
00284         size_t swp_used = get_cgroup_limit("memory", "memory.stat", "total_swap") / 1024;
00285         // limit is mem + swap
00286         if (mem_max != std::numeric_limits<size_t>::max() / 1024) {
00287             swap_total = std::min((size_t)swp_total, swp_max - mem_max);
00288         }
00289         else {
00290             swap_total = swp_total;
00291         }
00292         if (swp_used != std::numeric_limits<size_t>::max() / 1024 &&
00293             swp_max != std::numeric_limits<size_t>::max() / 1024) {
00294             swap_free = swp_max - swp_used;
00295         }
00296         else {
00297             swap_free = swp_free;
00298         }
00299         swap_used = swap_total-swap_free;
00300 
00301 
00302     }
00303 }
00304 
00305 } //# NAMESPACE CASACORE - END
00306 
00307 # endif
00308 
00309 #endif
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Generated on 31 Aug 2016 for casa by  doxygen 1.6.1