2 * slab.c - slab related functions for libproc
4 * Chris Rivera <cmrivera@ufl.edu>
5 * Robert Love <rml@tech9.net>
7 * This program is licensed under the GNU Library General Public License, v2
9 * Copyright (C) 2003 Chris Rivera
10 * Copyright 2004, Albert Cahalan
22 #define SLABINFO_LINE_LEN 2048
23 #define SLABINFO_VER_LEN 100
24 #define SLABINFO_FILE "/proc/slabinfo"
26 static struct slab_info *free_index;
29 * get_slabnode - allocate slab_info structures using a free list
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
36 static struct slab_info *get_slabnode(void)
38 struct slab_info *node;
42 free_index = free_index->next;
44 node = malloc(sizeof(struct slab_info));
53 * slab_badname_detect - return true if current slab was declared with
54 * whitespaces for instance
55 * FIXME :Other cases ?
58 static int slab_badname_detect(const char *restrict buffer)
64 if(isalpha(*buffer)&&numberarea)
72 * put_slabinfo - return all allocated nodes to the free list
74 void put_slabinfo(struct slab_info *head)
80 * free_slabinfo - deallocate the memory associated with each node in the
81 * slab_info linked list
83 void free_slabinfo(struct slab_info *list)
86 struct slab_info *temp = list->next;
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.
96 // Formats (we don't use "statistics" extensions)
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>
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>
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>
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,
124 struct slab_info *curr = NULL, *prev = NULL;
125 char buffer[SLABINFO_LINE_LEN];
127 int page_size = getpagesize();
129 stats->min_obj_size = INT_MAX;
130 stats->max_obj_size = 0;
132 while (fgets(buffer, SLABINFO_LINE_LEN, f)) {
135 if (buffer[0] == '#')
138 curr = get_slabnode();
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,
156 fprintf(stderr, "unrecognizable data in slabinfo!\n");
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;
166 curr->cache_size = (unsigned long)curr->nr_slabs * curr->pages_per_slab * page_size;
169 curr->use = 100 * curr->nr_active_objs / curr->nr_objs;
170 stats->nr_active_caches++;
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;
186 fprintf(stderr, "\rerror reading slabinfo!\n");
191 stats->nr_caches = entries;
193 stats->avg_obj_size = stats->total_size / stats->nr_objs;
199 * parse_slabinfo11 - actual parsing routine for slabinfo 1.1 (2.4 kernels)
201 static int parse_slabinfo11(struct slab_info **list, struct slab_stat *stats,
204 struct slab_info *curr = NULL, *prev = NULL;
205 char buffer[SLABINFO_LINE_LEN];
207 int page_size = getpagesize();
209 stats->min_obj_size = INT_MAX;
210 stats->max_obj_size = 0;
212 while (fgets(buffer, SLABINFO_LINE_LEN, f)) {
215 curr = get_slabnode();
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);
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);
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;
244 curr->cache_size = (unsigned long)curr->nr_slabs * curr->pages_per_slab * page_size;
247 curr->use = 100 * curr->nr_active_objs / curr->nr_objs;
248 stats->nr_active_caches++;
253 curr->objs_per_slab = curr->pages_per_slab *
254 page_size / curr->obj_size;
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;
268 fprintf(stderr, "\rerror reading slabinfo!\n");
273 stats->nr_caches = entries;
275 stats->avg_obj_size = stats->total_size / stats->nr_objs;
281 * parse_slabinfo10 - actual parsing routine for slabinfo 1.0 (2.2 kernels)
283 * Not yet implemented. Please feel free.
285 static int parse_slabinfo10(struct slab_info **list, struct slab_stat *stats,
288 (void) list, (void) stats, (void) f;
289 fprintf(stderr, "slabinfo version 1.0 not yet supported\n");
294 * slabinfo - parse the system's slabinfo and fill out both a linked list of
295 * slab_info structures and the slab_stat structure
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'
301 int get_slabinfo(struct slab_info **list, struct slab_stat *stats)
304 char buffer[SLABINFO_VER_LEN];
305 int major, minor, ret = 0;
307 slabfile = fopen(SLABINFO_FILE, "r");
309 perror("fopen " SLABINFO_FILE);
313 if (!fgets(buffer, SLABINFO_VER_LEN, slabfile)) {
314 fprintf(stderr, "cannot read from slabinfo\n");
318 if (sscanf(buffer, "slabinfo - version: %d.%d", &major, &minor) != 2) {
319 fprintf(stderr, "not the good old slabinfo we know\n");
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);
330 fprintf(stderr, "unrecognizable slabinfo version\n");