Updated with Tizen:Base source codes
[external/procps.git] / proc / slab.c
1 /* 
2  * slab.c - slab related functions for libproc
3  *
4  * Chris Rivera <cmrivera@ufl.edu>
5  * Robert Love <rml@tech9.net>
6  *
7  * This program is licensed under the GNU Library General Public License, v2
8  *
9  * Copyright (C) 2003 Chris Rivera
10  * Copyright 2004, Albert Cahalan
11  */
12
13 #include <stdlib.h>
14 #include <stdio.h>
15 #include <unistd.h>
16 #include <limits.h>
17 #include <ctype.h>
18
19 #include "slab.h"
20 #include "procps.h"
21
22 #define SLABINFO_LINE_LEN       2048
23 #define SLABINFO_VER_LEN        100
24 #define SLABINFO_FILE           "/proc/slabinfo"
25
26 static struct slab_info *free_index;
27
28 /*
29  * get_slabnode - allocate slab_info structures using a free list
30  *
31  * In the fast path, we simply return a node off the free list.  In the slow
32  * list, we malloc() a new node.  The free list is never automatically reaped,
33  * both for simplicity and because the number of slab caches is fairly
34  * constant.
35  */
36 static struct slab_info *get_slabnode(void)
37 {
38         struct slab_info *node;
39
40         if (free_index) {
41                 node = free_index;
42                 free_index = free_index->next;
43         } else {
44                 node = malloc(sizeof(struct slab_info));
45                 if (!node)
46                         perror("malloc");
47         }
48
49         return node;
50 }
51
52 /*
53  * slab_badname_detect - return true if current slab was declared with
54  *                       whitespaces for instance 
55  *                       FIXME :Other cases ?
56  */
57
58 static int slab_badname_detect(const char *restrict buffer)
59 {
60         int numberarea=0;
61         while (*buffer){
62                 if((*buffer)==' ')
63                         numberarea=1;
64                 if(isalpha(*buffer)&&numberarea)        
65                         return 1;
66                 buffer++;       
67         }
68         return 0;
69 }
70
71 /*
72  * put_slabinfo - return all allocated nodes to the free list
73  */
74 void put_slabinfo(struct slab_info *head)
75 {
76         free_index = head;
77 }
78
79 /*
80  * free_slabinfo - deallocate the memory associated with each node in the
81  * slab_info linked list
82  */
83 void free_slabinfo(struct slab_info *list)
84 {
85         while (list) {
86                 struct slab_info *temp = list->next;
87                 free(list);
88                 list = temp;
89         }
90 }
91
92 // parse_slabinfo20 - actual parse routine for slabinfo 2.x (2.6 kernels)
93 // Note: difference between 2.0 and 2.1 is in the ": globalstat" part where version 2.1 
94 // has extra column <nodeallocs>. We don't use ": globalstat" part in both versions.
95 //
96 // Formats (we don't use "statistics" extensions)
97 //
98 //  slabinfo - version: 2.1
99 //  # name            <active_objs> <num_objs> <objsize> <objperslab> <pagesperslab> \
100 //  : tunables <batchcount> <limit> <sharedfactor> \
101 //  : slabdata <active_slabs> <num_slabs> <sharedavail>
102 //
103 //  slabinfo - version: 2.1 (statistics)
104 //  # name            <active_objs> <num_objs> <objsize> <objperslab> <pagesperslab> \
105 //  : tunables <batchcount> <limit> <sharedfactor> \
106 //  : slabdata <active_slabs> <num_slabs> <sharedavail> \
107 //  : globalstat <listallocs> <maxobjs> <grown> <reaped> <error> <maxfreeable> <freelimit> <nodeallocs> \
108 //  : cpustat <allochit> <allocmiss> <freehit> <freemiss>
109 //             
110 //  slabinfo - version: 2.0
111 //  # name            <active_objs> <num_objs> <objsize> <objperslab> <pagesperslab> \
112 //  : tunables <batchcount> <limit> <sharedfactor> \
113 //  : slabdata <active_slabs> <num_slabs> <sharedavail>
114 //
115 //  slabinfo - version: 2.0 (statistics)
116 //  # name            <active_objs> <num_objs> <objsize> <objperslab> <pagesperslab> \
117 //  : tunables <batchcount> <limit> <sharedfactor> \
118 //  : slabdata <active_slabs> <num_slabs> <sharedavail> \
119 //  : globalstat <listallocs> <maxobjs> <grown> <reaped> <error> <maxfreeable> <freelimit> \
120 //  : cpustat <allochit> <allocmiss> <freehit> <freemiss>
121 static int parse_slabinfo20(struct slab_info **list, struct slab_stat *stats,
122                                 FILE *f)
123 {
124         struct slab_info *curr = NULL, *prev = NULL;
125         char buffer[SLABINFO_LINE_LEN];
126         int entries = 0;
127         int page_size = getpagesize();
128
129         stats->min_obj_size = INT_MAX;
130         stats->max_obj_size = 0;
131
132         while (fgets(buffer, SLABINFO_LINE_LEN, f)) {
133                 int assigned;
134
135                 if (buffer[0] == '#')
136                         continue;
137         
138                 curr = get_slabnode();
139                 if (!curr)
140                         break;
141
142                 if (entries++ == 0)
143                         *list = curr;
144                 else
145                         prev->next = curr;
146
147                 assigned = sscanf(buffer, "%" STRINGIFY(SLAB_INFO_NAME_LEN)
148                                 "s %d %d %d %d %d : tunables %*d %*d %*d : \
149                                 slabdata %d %d %*d", curr->name, 
150                                 &curr->nr_active_objs, &curr->nr_objs, 
151                                 &curr->obj_size, &curr->objs_per_slab,
152                                 &curr->pages_per_slab, &curr->nr_active_slabs,
153                                 &curr->nr_slabs);
154
155                 if (assigned < 8) {
156                         fprintf(stderr, "unrecognizable data in slabinfo!\n");
157                         curr = NULL;
158                         break;
159                 }
160
161                 if (curr->obj_size < stats->min_obj_size)
162                         stats->min_obj_size = curr->obj_size;
163                 if (curr->obj_size > stats->max_obj_size)
164                         stats->max_obj_size = curr->obj_size;
165
166                 curr->cache_size = (unsigned long)curr->nr_slabs * curr->pages_per_slab * page_size;
167
168                 if (curr->nr_objs) {
169                         curr->use = 100 * curr->nr_active_objs / curr->nr_objs;
170                         stats->nr_active_caches++;
171                 } else
172                         curr->use = 0;
173
174                 stats->nr_objs += curr->nr_objs;
175                 stats->nr_active_objs += curr->nr_active_objs;
176                 stats->total_size += (unsigned long)curr->nr_objs * curr->obj_size;
177                 stats->active_size += (unsigned long)curr->nr_active_objs * curr->obj_size;
178                 stats->nr_pages += curr->nr_slabs * curr->pages_per_slab;
179                 stats->nr_slabs += curr->nr_slabs;
180                 stats->nr_active_slabs += curr->nr_active_slabs;
181
182                 prev = curr;
183         }
184
185         if (!curr) {
186                 fprintf(stderr, "\rerror reading slabinfo!\n");
187                 return 1;
188         }
189
190         curr->next = NULL;
191         stats->nr_caches = entries;
192         if (stats->nr_objs)
193                 stats->avg_obj_size = stats->total_size / stats->nr_objs;
194
195         return 0;
196 }
197
198 /*
199  * parse_slabinfo11 - actual parsing routine for slabinfo 1.1 (2.4 kernels)
200  */
201 static int parse_slabinfo11(struct slab_info **list, struct slab_stat *stats,
202                                 FILE *f)
203 {
204         struct slab_info *curr = NULL, *prev = NULL;
205         char buffer[SLABINFO_LINE_LEN];
206         int entries = 0;
207         int page_size = getpagesize();
208
209         stats->min_obj_size = INT_MAX;
210         stats->max_obj_size = 0;
211
212         while (fgets(buffer, SLABINFO_LINE_LEN, f)) {
213                 int assigned;
214
215                 curr = get_slabnode();
216                 if (!curr)
217                         break;
218
219                 if (entries++ == 0)
220                         *list = curr;
221                 else
222                         prev->next = curr;
223
224                 assigned = sscanf(buffer, "%" STRINGIFY(SLAB_INFO_NAME_LEN)
225                                 "s %d %d %d %d %d %d",
226                                 curr->name, &curr->nr_active_objs,
227                                 &curr->nr_objs, &curr->obj_size,
228                                 &curr->nr_active_slabs, &curr->nr_slabs,
229                                 &curr->pages_per_slab);
230
231                 if (assigned < 6) {
232                         fprintf(stderr, "unrecognizable data in  your slabinfo version 1.1\n\r");
233                         if(slab_badname_detect(buffer))
234                                 fprintf(stderr, "Found an error in cache name at line %s\n", buffer); 
235                         curr = NULL;
236                         break;
237                 }
238
239                 if (curr->obj_size < stats->min_obj_size)
240                         stats->min_obj_size = curr->obj_size;
241                 if (curr->obj_size > stats->max_obj_size)
242                         stats->max_obj_size = curr->obj_size;
243
244                 curr->cache_size = (unsigned long)curr->nr_slabs * curr->pages_per_slab * page_size;
245
246                 if (curr->nr_objs) {
247                         curr->use = 100 * curr->nr_active_objs / curr->nr_objs;
248                         stats->nr_active_caches++;
249                 } else
250                         curr->use = 0;
251
252                 if (curr->obj_size)
253                         curr->objs_per_slab = curr->pages_per_slab *
254                                         page_size / curr->obj_size;             
255
256                 stats->nr_objs += curr->nr_objs;
257                 stats->nr_active_objs += curr->nr_active_objs;
258                 stats->total_size += (unsigned long)curr->nr_objs * curr->obj_size;
259                 stats->active_size += (unsigned long)curr->nr_active_objs * curr->obj_size;
260                 stats->nr_pages += curr->nr_slabs * curr->pages_per_slab;
261                 stats->nr_slabs += curr->nr_slabs;
262                 stats->nr_active_slabs += curr->nr_active_slabs;
263
264                 prev = curr;
265         }
266
267         if (!curr) {
268                 fprintf(stderr, "\rerror reading slabinfo!\n");
269                 return 1;
270         }
271
272         curr->next = NULL;
273         stats->nr_caches = entries;
274         if (stats->nr_objs)
275                 stats->avg_obj_size = stats->total_size / stats->nr_objs;
276
277         return 0;
278 }
279
280 /*
281  * parse_slabinfo10 - actual parsing routine for slabinfo 1.0 (2.2 kernels)
282  *
283  * Not yet implemented.  Please feel free.
284  */
285 static int parse_slabinfo10(struct slab_info **list, struct slab_stat *stats,
286                                 FILE *f)
287 {
288         (void) list, (void) stats, (void) f;
289         fprintf(stderr, "slabinfo version 1.0 not yet supported\n");
290         return 1;
291 }
292
293 /*
294  * slabinfo - parse the system's slabinfo and fill out both a linked list of
295  * slab_info structures and the slab_stat structure
296  *
297  * The function returns zero on success, in which case 'list' and 'stats' are
298  * valid.  Nonzero is returned on failure and the state of 'list' and 'stats'
299  * are undefined.
300  */
301 int get_slabinfo(struct slab_info **list, struct slab_stat *stats)
302 {
303         FILE *slabfile;
304         char buffer[SLABINFO_VER_LEN];
305         int major, minor, ret = 0;
306
307         slabfile = fopen(SLABINFO_FILE, "r");
308         if (!slabfile) {
309                 perror("fopen " SLABINFO_FILE);
310                 return 1;
311         }
312
313         if (!fgets(buffer, SLABINFO_VER_LEN, slabfile)) {
314                 fprintf(stderr, "cannot read from slabinfo\n");
315                 return 1;
316         }
317
318         if (sscanf(buffer, "slabinfo - version: %d.%d", &major, &minor) != 2) {
319                 fprintf(stderr, "not the good old slabinfo we know\n");
320                 return 1;
321         }
322
323         if (major == 2)
324                 ret = parse_slabinfo20(list, stats, slabfile);
325         else if (major == 1 && minor == 1)
326                 ret = parse_slabinfo11(list, stats, slabfile);
327         else if (major == 1 && minor == 0)
328                 ret = parse_slabinfo10(list, stats, slabfile);
329         else {
330                 fprintf(stderr, "unrecognizable slabinfo version\n");
331                 return 1;
332         }
333
334         fclose(slabfile);
335
336         return ret;
337 }