link against libz explicitly, as we use it directly
[oweals/gnunet.git] / src / testbed / gnunet-service-testbed_meminfo.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2008--2013 GNUnet e.V.
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 3, or (at your
8      option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18      Boston, MA 02110-1301, USA.
19 */
20
21 #include "platform.h"
22 #include "gnunet_util_lib.h"
23
24 /*
25  * File for parsing top-level /proc entities.
26  * Copyright Copyright (C) 1992-1998 by Michael K. Johnson, johnsonm@redhat.com
27  * Copyright 1998-2003 Albert Cahalan
28  * June 2003, Fabian Frederick, disk and slab info
29  *
30  * This library is free software; you can redistribute it and/or
31  * modify it under the terms of the GNU Lesser General Public
32  * License as published by the Free Software Foundation; either
33  * version 2.1 of the License, or (at your option) any later version.
34  *
35  * This library is distributed in the hope that it will be useful,
36  * but WITHOUT ANY WARRANTY; without even the implied warranty of
37  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
38  * Lesser General Public License for more details.
39  *
40  * You should have received a copy of the GNU Lesser General Public
41  * License along with this library; if not, write to the Free Software
42  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
43  */
44
45 #define BAD_OPEN_MESSAGE                                        \
46 "Error: /proc must be mounted\n"                                \
47 "  To mount /proc at boot you need an /etc/fstab line like:\n"  \
48 "      proc   /proc   proc    defaults\n"                       \
49 "  In the meantime, run \"mount proc /proc -t proc\"\n"
50
51 #define STAT_FILE    "/proc/stat"
52 //static int stat_fd = -1;
53 #define UPTIME_FILE  "/proc/uptime"
54 //static int uptime_fd = -1;
55 #define LOADAVG_FILE "/proc/loadavg"
56 //static int loadavg_fd = -1;
57 #define MEMINFO_FILE "/proc/meminfo"
58 static int meminfo_fd = -1;
59 #define VMINFO_FILE "/proc/vmstat"
60 //static int vminfo_fd = -1;
61
62 // As of 2.6.24 /proc/meminfo seems to need 888 on 64-bit,
63 // and would need 1258 if the obsolete fields were there.
64 static char buf[2048];
65
66 /* This macro opens filename only if necessary and seeks to 0 so
67  * that successive calls to the functions are more efficient.
68  * It also reads the current contents of the file into the global buf.
69  */
70 #define FILE_TO_BUF(filename, fd) do{                           \
71     static int local_n;                                         \
72     if (fd == -1 && (fd = open(filename, O_RDONLY)) == -1) {    \
73         fputs(BAD_OPEN_MESSAGE, stderr);                        \
74         fflush(NULL);                                           \
75         _exit(102);                                             \
76     }                                                           \
77     lseek(fd, 0L, SEEK_SET);                                    \
78     if ((local_n = read(fd, buf, sizeof buf - 1)) < 0) {        \
79         perror(filename);                                       \
80         fflush(NULL);                                           \
81         _exit(103);                                             \
82     }                                                           \
83     buf[local_n] = '\0';                                        \
84 }while(0)
85
86
87 /***********************************************************************/
88 /*
89  * Copyright 1999 by Albert Cahalan; all rights reserved.
90  * This file may be used subject to the terms and conditions of the
91  * GNU Library General Public License Version 2, or any later version
92  * at your option, as published by the Free Software Foundation.
93  * This program is distributed in the hope that it will be useful,
94  * but WITHOUT ANY WARRANTY; without even the implied warranty of
95  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
96  * GNU Library General Public License for more details.
97  */
98
99 typedef struct mem_table_struct {
100   const char *name;     /* memory type name */
101   unsigned long *slot; /* slot in return struct */
102 } mem_table_struct;
103
104 static int compare_mem_table_structs(const void *a, const void *b){
105   return strcmp(((const mem_table_struct*)a)->name,((const mem_table_struct*)b)->name);
106 }
107
108 /* example data, following junk, with comments added:
109  *
110  * MemTotal:        61768 kB    old
111  * MemFree:          1436 kB    old
112  * MemShared:           0 kB    old (now always zero; not calculated)
113  * Buffers:          1312 kB    old
114  * Cached:          20932 kB    old
115  * Active:          12464 kB    new
116  * Inact_dirty:      7772 kB    new
117  * Inact_clean:      2008 kB    new
118  * Inact_target:        0 kB    new
119  * Inact_laundry:       0 kB    new, and might be missing too
120  * HighTotal:           0 kB
121  * HighFree:            0 kB
122  * LowTotal:        61768 kB
123  * LowFree:          1436 kB
124  * SwapTotal:      122580 kB    old
125  * SwapFree:        60352 kB    old
126  * Inactive:        20420 kB    2.5.41+
127  * Dirty:               0 kB    2.5.41+
128  * Writeback:           0 kB    2.5.41+
129  * Mapped:           9792 kB    2.5.41+
130  * Slab:             4564 kB    2.5.41+
131  * Committed_AS:     8440 kB    2.5.41+
132  * PageTables:        304 kB    2.5.41+
133  * ReverseMaps:      5738       2.5.41+
134  * SwapCached:          0 kB    2.5.??+
135  * HugePages_Total:   220       2.5.??+
136  * HugePages_Free:    138       2.5.??+
137  * Hugepagesize:     4096 kB    2.5.??+
138  */
139
140 /* obsolete */
141 unsigned long kb_main_shared;
142 /* old but still kicking -- the important stuff */
143 unsigned long kb_main_buffers;
144 unsigned long kb_main_cached;
145 unsigned long kb_main_free;
146 unsigned long kb_main_total;
147 unsigned long kb_swap_free;
148 unsigned long kb_swap_total;
149 /* recently introduced */
150 unsigned long kb_high_free;
151 unsigned long kb_high_total;
152 unsigned long kb_low_free;
153 unsigned long kb_low_total;
154 /* 2.4.xx era */
155 unsigned long kb_active;
156 unsigned long kb_inact_laundry;
157 unsigned long kb_inact_dirty;
158 unsigned long kb_inact_clean;
159 unsigned long kb_inact_target;
160 unsigned long kb_swap_cached;  /* late 2.4 and 2.6+ only */
161 /* derived values */
162 unsigned long kb_swap_used;
163 unsigned long kb_main_used;
164 /* 2.5.41+ */
165 unsigned long kb_writeback;
166 unsigned long kb_slab;
167 unsigned long nr_reversemaps;
168 unsigned long kb_committed_as;
169 unsigned long kb_dirty;
170 unsigned long kb_inactive;
171 unsigned long kb_mapped;
172 unsigned long kb_pagetables;
173 // seen on a 2.6.x kernel:
174 static unsigned long kb_vmalloc_chunk;
175 static unsigned long kb_vmalloc_total;
176 static unsigned long kb_vmalloc_used;
177 // seen on 2.6.24-rc6-git12
178 static unsigned long kb_anon_pages;
179 static unsigned long kb_bounce;
180 static unsigned long kb_commit_limit;
181 static unsigned long kb_nfs_unstable;
182 static unsigned long kb_swap_reclaimable;
183 static unsigned long kb_swap_unreclaimable;
184
185 void meminfo(void){
186   char namebuf[16]; /* big enough to hold any row name */
187   mem_table_struct findme = { namebuf, NULL};
188   mem_table_struct *found;
189   char *head;
190   char *tail;
191   static const mem_table_struct mem_table[] = {
192   {"Active",       &kb_active},       // important
193   {"AnonPages",    &kb_anon_pages},
194   {"Bounce",       &kb_bounce},
195   {"Buffers",      &kb_main_buffers}, // important
196   {"Cached",       &kb_main_cached},  // important
197   {"CommitLimit",  &kb_commit_limit},
198   {"Committed_AS", &kb_committed_as},
199   {"Dirty",        &kb_dirty},        // kB version of vmstat nr_dirty
200   {"HighFree",     &kb_high_free},
201   {"HighTotal",    &kb_high_total},
202   {"Inact_clean",  &kb_inact_clean},
203   {"Inact_dirty",  &kb_inact_dirty},
204   {"Inact_laundry",&kb_inact_laundry},
205   {"Inact_target", &kb_inact_target},
206   {"Inactive",     &kb_inactive},     // important
207   {"LowFree",      &kb_low_free},
208   {"LowTotal",     &kb_low_total},
209   {"Mapped",       &kb_mapped},       // kB version of vmstat nr_mapped
210   {"MemFree",      &kb_main_free},    // important
211   {"MemShared",    &kb_main_shared},  // important, but now gone!
212   {"MemTotal",     &kb_main_total},   // important
213   {"NFS_Unstable", &kb_nfs_unstable},
214   {"PageTables",   &kb_pagetables},   // kB version of vmstat nr_page_table_pages
215   {"ReverseMaps",  &nr_reversemaps},  // same as vmstat nr_page_table_pages
216   {"SReclaimable", &kb_swap_reclaimable}, // "swap reclaimable" (dentry and inode structures)
217   {"SUnreclaim",   &kb_swap_unreclaimable},
218   {"Slab",         &kb_slab},         // kB version of vmstat nr_slab
219   {"SwapCached",   &kb_swap_cached},
220   {"SwapFree",     &kb_swap_free},    // important
221   {"SwapTotal",    &kb_swap_total},   // important
222   {"VmallocChunk", &kb_vmalloc_chunk},
223   {"VmallocTotal", &kb_vmalloc_total},
224   {"VmallocUsed",  &kb_vmalloc_used},
225   {"Writeback",    &kb_writeback},    // kB version of vmstat nr_writeback
226   };
227   const int mem_table_count = sizeof(mem_table)/sizeof(mem_table_struct);
228
229   FILE_TO_BUF(MEMINFO_FILE,meminfo_fd);
230
231   kb_inactive = ~0UL;
232
233   head = buf;
234   for(;;){
235     tail = strchr(head, ':');
236     if(!tail) break;
237     *tail = '\0';
238     if(strlen(head) >= sizeof(namebuf)){
239       head = tail+1;
240       goto nextline;
241     }
242     strcpy(namebuf,head);
243     found = bsearch(&findme, mem_table, mem_table_count,
244         sizeof(mem_table_struct), compare_mem_table_structs
245     );
246     head = tail+1;
247     if(!found) goto nextline;
248     *(found->slot) = (unsigned long)strtoull(head,&tail,10);
249 nextline:
250     tail = strchr(head, '\n');
251     if(!tail) break;
252     head = tail+1;
253   }
254   if(!kb_low_total){  /* low==main except with large-memory support */
255     kb_low_total = kb_main_total;
256     kb_low_free  = kb_main_free;
257   }
258   if(kb_inactive==~0UL){
259     kb_inactive = kb_inact_dirty + kb_inact_clean + kb_inact_laundry;
260   }
261   kb_swap_used = kb_swap_total - kb_swap_free;
262   kb_main_used = kb_main_total - kb_main_free;
263 }