Browse code

mempool statistics support

git-svn: trunk@4344

Török Edvin authored on 2008/11/06 23:27:27
Showing 9 changed files
... ...
@@ -1,3 +1,10 @@
1
+Thu Nov  6 11:37:08 EET 2008 (edwin)
2
+------------------------------------
3
+ * clamd/server-th.c, clamd/session.c, clamd/thrmgr.c,
4
+ clamd/thrmgr.h, contrib/clamdtop/clamdtop.c,
5
+ libclamav/libclamav.map, libclamav/mpool.c, libclamav/mpool.h: 
6
+ mempool statistics support
7
+
1 8
 Wed Nov  5 21:49:49 EET 2008 (edwin)
2 9
 ------------------------------------
3 10
  * clamav-milter/clamav-milter.c, configure.in, libclamav/binhex.c,
... ...
@@ -160,6 +160,7 @@ static void scanner_thread(void *arg)
160 160
 
161 161
     shutdown(conn->sd, 2);
162 162
     closesocket(conn->sd);
163
+    thrmgr_setactiveengine(NULL);
163 164
     cl_free(conn->engine);
164 165
     free(conn);
165 166
     return;
... ...
@@ -240,6 +241,7 @@ static struct cl_engine *reload_db(struct cl_engine *engine, unsigned int dbopti
240 240
 	    if(!(pua_cats = strdup(engine->pua_cats)))
241 241
 		logg("^Can't make a copy of pua_cats\n");
242 242
 
243
+	thrmgr_setactiveengine(NULL);
243 244
 	cl_free(engine);
244 245
 	engine = NULL;
245 246
     }
... ...
@@ -279,6 +281,7 @@ static struct cl_engine *reload_db(struct cl_engine *engine, unsigned int dbopti
279 279
     }
280 280
     logg("Database correctly reloaded (%u signatures)\n", sigs);
281 281
 
282
+    thrmgr_setactiveengine(engine);
282 283
     return engine;
283 284
 }
284 285
 
... ...
@@ -712,8 +715,10 @@ int acceptloop_th(int *socketds, int nsockets, struct cl_engine *engine, unsigne
712 712
 	pthread_join(clamuko_pid, NULL);
713 713
     }
714 714
 #endif
715
-    if(engine)
715
+    if(engine) {
716
+	thrmgr_setactiveengine(NULL);
716 717
 	cl_free(engine);
718
+    }
717 719
 
718 720
     if(dbstat)
719 721
 	cl_statfree(dbstat);
... ...
@@ -131,6 +131,7 @@ int command(int desc, const struct cl_engine *engine, const struct cl_limits *li
131 131
 
132 132
     buff[bread] = 0;
133 133
     cli_chomp(buff);
134
+    thrmgr_setactiveengine(engine);
134 135
 
135 136
     if(!strncmp(buff, CMD1, strlen(CMD1))) { /* SCAN */
136 137
 	thrmgr_setactivetask(NULL, CMD1);
... ...
@@ -144,6 +145,10 @@ int command(int desc, const struct cl_engine *engine, const struct cl_limits *li
144 144
 
145 145
     } else if(!strncmp(buff, CMD4, strlen(CMD4))) { /* RELOAD */
146 146
 	thrmgr_setactivetask(NULL, CMD4);
147
+	/* we'll reload, hide the engine, if we are the last
148
+	 * holding a ref to the engine it'll be freed,
149
+	 * we don't want STATS command to access it */
150
+	thrmgr_setactiveengine(NULL);
147 151
 	mdprintf(desc, "RELOADING\n");
148 152
 	return COMMAND_RELOAD;
149 153
 
... ...
@@ -30,6 +30,7 @@
30 30
 
31 31
 #include "thrmgr.h"
32 32
 #include "others.h"
33
+#include "mpool.h"
33 34
 
34 35
 #if defined(C_LINUX)
35 36
 #include <malloc.h>
... ...
@@ -155,10 +156,14 @@ int thrmgr_printstats(int f)
155 155
 {
156 156
 	struct threadpool_list *l;
157 157
 	size_t cnt;
158
+	size_t pool_used = 0, pool_total = 0, pool_cnt = 0, seen_cnt = 0, error_flag = 0;
159
+	float mem_heap = 0, mem_mmap = 0, mem_used = 0, mem_free = 0, mem_releasable = 0;
160
+	const struct cl_engine **seen = NULL;
161
+
158 162
 	pthread_mutex_lock(&pools_lock);
159 163
 	for(cnt=0,l=pools;l;l=l->nxt) cnt++;
160 164
 	mdprintf(f,"POOLS: %u\n\n", cnt);
161
-	for(l= pools;l;l = l->nxt) {
165
+	for(l= pools;l && !error_flag;l = l->nxt) {
162 166
 		threadpool_t *pool = l->pool;
163 167
 		const char *state;
164 168
 		work_item_t *q;
... ...
@@ -172,6 +177,9 @@ int thrmgr_printstats(int f)
172 172
 			continue;
173 173
 		}
174 174
 		pthread_mutex_lock(&pool->pool_mutex);
175
+		/* now we can access desc->, knowing that they won't get freed
176
+		 * because the other tasks can't quit while pool_mutex is taken
177
+		 */
175 178
 		switch(pool->state) {
176 179
 			case POOL_INVALID:
177 180
 				state = "INVALID";
... ...
@@ -216,26 +224,66 @@ int thrmgr_printstats(int f)
216 216
 		mdprintf(f, "\n");
217 217
 		for(task = pool->tasks; task; task = task->nxt) {
218 218
 			long delta;
219
+			size_t used, total;
220
+
219 221
 			delta = tv_now.tv_usec - task->tv.tv_usec;
220 222
 			delta += (tv_now.tv_sec - task->tv.tv_sec)*1000000;
221 223
 			mdprintf(f,"\t%s %f %s\n",
222 224
 					task->command ? task->command : "N/A",
223 225
 					delta/1e6,
224 226
 					task->filename ? task->filename:"");
227
+			if (task->engine) {
228
+				/* we usually have at most 2 engines so a linear
229
+				 * search is good enough */
230
+				size_t i;
231
+				for (i=0;i<seen_cnt;i++) {
232
+					if (seen[i] == task->engine)
233
+						break;
234
+				}
235
+				/* we need to count the memusage from the same
236
+				 * engine only once */
237
+				if (i == seen_cnt) {
238
+					const struct cl_engine **s;
239
+					/* new engine */
240
+					++seen_cnt;
241
+					s = realloc(seen, seen_cnt * sizeof(*seen));
242
+					if (!s) {
243
+						error_flag = 1;
244
+						break;
245
+					}
246
+					seen = s;
247
+					seen[seen_cnt - 1] = task->engine;
248
+
249
+					if (mp_getstats(task->engine, &used, &total) != -1) {
250
+						pool_used += used;
251
+						pool_total += total;
252
+						pool_cnt++;
253
+					}
254
+				}
255
+			}
225 256
 		}
226 257
 		mdprintf(f,"\n");
227 258
 		pthread_mutex_unlock(&pool->pool_mutex);
228 259
 	}
260
+	free(seen);
229 261
 #if defined(C_LINUX)
230 262
 	{
231 263
 		struct mallinfo inf = mallinfo();
232
-		mdprintf(f,"MEMSTATS: heap %.3fM mmap %.3fM used %.3fM free %.3fM releasable %.3fM\n",
233
-				inf.arena/(1024*1024.0), inf.hblkhd/(1024*1024.0),
234
-				inf.uordblks/(1024*1024.0), inf.fordblks/(1024*1024.0),
235
-				inf.keepcost/(1024*1024.0));
264
+		mem_heap = inf.arena/(1024*1024.0);
265
+		mem_mmap = inf.hblkhd/(1024*1024.0);
266
+		mem_used = inf.uordblks/(1024*1024.0);
267
+		mem_free = inf.fordblks/(1024*1024.0);
268
+		mem_releasable = inf.keepcost/(1024*1024.0);
269
+		/* TODO: figure out how to print these statistics on other OSes */
236 270
 	}
237
-	/* TODO: figure out how to print these statistics on other OSes */
238 271
 #endif
272
+	if (error_flag) {
273
+		mdprintf(f, "ERROR: error encountered while formatting statistics\n");
274
+	} else {
275
+		mdprintf(f,"MEMSTATS: heap %.3fM mmap %.3fM used %.3fM free %.3fM releasable %.3fM pools %u pools_used %.3fM pools_total %.3fM\n",
276
+			mem_heap, mem_mmap, mem_used, mem_free, mem_releasable, pool_cnt,
277
+			pool_used/(1024*1024.0), pool_total/(1024*1024.0));
278
+	}
239 279
 	mdprintf(f,"END\n");
240 280
 	pthread_mutex_unlock(&pools_lock);
241 281
 	return 0;
... ...
@@ -393,6 +441,14 @@ void thrmgr_setactivetask(const char *filename, const char* command)
393 393
 	}
394 394
 }
395 395
 
396
+void thrmgr_setactiveengine(const struct cl_engine *engine)
397
+{
398
+	struct task_desc *desc = pthread_getspecific(stats_tls_key);
399
+	if(!desc)
400
+		return;
401
+	desc->engine = engine;
402
+}
403
+
396 404
 /* thread pool mutex must be held on entry */
397 405
 static void stats_init(threadpool_t *pool)
398 406
 {
... ...
@@ -50,6 +50,7 @@ struct task_desc {
50 50
 	struct timeval tv;
51 51
 	struct task_desc *prv;
52 52
 	struct task_desc *nxt;
53
+	const struct cl_engine *engine;
53 54
 };
54 55
 
55 56
 typedef struct threadpool_tag {
... ...
@@ -76,5 +77,6 @@ void thrmgr_destroy(threadpool_t *threadpool);
76 76
 int thrmgr_dispatch(threadpool_t *threadpool, void *user_data);
77 77
 int thrmgr_printstats(int outfd);
78 78
 void thrmgr_setactivetask(const char *filename, const char* command);
79
+void thrmgr_setactiveengine(const struct cl_engine *engine);
79 80
 
80 81
 #endif
... ...
@@ -142,7 +142,7 @@ static void init_windows(void)
142 142
 	version_window = subwin(stdscr, 1, maxx, 1, 0);
143 143
 	stats_head_window = subwin(stdscr, 5, maxx-48, 3, 0);
144 144
 	stats_window = subwin(stdscr, maxy-9, maxx, 7, 0);
145
-	mem_window = subwin(stdscr, 5, 48, 2, maxx-48);
145
+	mem_window = subwin(stdscr, 6, 48, 3, maxx-48);
146 146
 	status_bar_window = subwin(stdscr, 1i, maxx, maxy-1, 0);
147 147
 	touchwin(stdscr);
148 148
 	werase(stdscr);
... ...
@@ -325,33 +325,44 @@ static void output_memstats(const char* line)
325 325
 {
326 326
 	char buf[128];
327 327
 	int blink = 0;
328
-	double heapu, mmapu, totalu, totalf, releasable;
329
-	unsigned long lheapu, lmmapu, ltotalu, ltotalf, lreleasable, totalmem;
328
+	double heapu, mmapu, totalu, totalf, releasable, pools_used, pools_total;
329
+	unsigned pools_cnt;
330
+	unsigned long lheapu, lmmapu, ltotalu, ltotalf, lreleasable, totalmem, lpoolu, lpoolt;
330 331
 
331
-	if(sscanf(line, " heap %lfM mmap %lfM used %lfM free %lfM releasable %lfM",
332
-			&heapu, &mmapu, &totalu, &totalf, &releasable) != 5)
332
+	if(sscanf(line, " heap %lfM mmap %lfM used %lfM free %lfM releasable %lfM pools %u pools_used %lfM pools_total %lfM",
333
+			&heapu, &mmapu, &totalu, &totalf, &releasable, &pools_cnt, &pools_used, &pools_total) != 8)
333 334
 		return;
334 335
 	lheapu = heapu*1000;
335 336
 	lmmapu = mmapu*1000;
336 337
 	ltotalu = totalu*1000;
337 338
 	ltotalf = totalf*1000;
338 339
 	lreleasable = releasable*1000;
340
+	lpoolu = pools_used*1000;
341
+	lpoolt = pools_total*1000;
339 342
 	werase(mem_window);
340 343
 	box(mem_window, 0, 0);
344
+
341 345
 	snprintf(buf, sizeof(buf),"heap %4luM mmap %4luM releasable %3luM",
342 346
 			lheapu/1024, lmmapu/1024, lreleasable/1024);
343 347
 	mvwprintw(mem_window, 1, 1, "Memory: ");
344 348
 	print_colored(mem_window, buf);
349
+
345 350
 	mvwprintw(mem_window, 2, 1, "Malloc: ");
346 351
 	snprintf(buf, sizeof(buf),"used %4luM free %4luM total     %4luM",
347 352
 			ltotalu/1024, ltotalf/1024, (ltotalu+ltotalf)/1024);
348 353
 	print_colored(mem_window, buf);
349
-	totalmem = lheapu + lmmapu;
354
+
355
+	mvwprintw(mem_window, 3, 1, "Mempool: ");
356
+	snprintf(buf, sizeof(buf), "count  %u  used %4luM total     %4luM",
357
+			pools_cnt, lpoolu/1024, lpoolt/1024);
358
+	print_colored(mem_window, buf);
359
+
360
+	totalmem = lheapu + lmmapu + lpoolt;
350 361
 	if(totalmem > biggest_mem) {
351 362
 		biggest_mem = totalmem;
352 363
 		blink = 1;
353 364
 	}
354
-	show_bar(mem_window, 3, totalmem, lmmapu + lreleasable,
365
+	show_bar(mem_window, 4, totalmem, lmmapu + lreleasable + lpoolt - lpoolu,
355 366
 			biggest_mem, blink);
356 367
 	wrefresh(mem_window);
357 368
 }
... ...
@@ -121,6 +121,7 @@ CLAMAV_PRIVATE {
121 121
     mp_create;
122 122
     mp_destroy;
123 123
     mp_free;
124
+    mp_getstats;
124 125
   local:
125 126
     *;
126 127
 };
... ...
@@ -388,7 +388,26 @@ void mp_flush(struct MP *mp) {
388 388
   }
389 389
   used += mp->mpm.size;
390 390
   spam("Map flushed @ %p, in use: %lu\n", mp, used);
391
-  return used;
391
+}
392
+
393
+int mp_getstats(const struct cl_engine *eng, size_t *used, size_t *total)
394
+{
395
+	size_t sum_used = 0, sum_total = 0;
396
+	const struct MPMAP *mpm;
397
+	const mp_t *mp;
398
+	/* checking refcount is not necessary, but safer */
399
+	if (!eng || !eng->refcount)
400
+		return -1;
401
+	mp = eng->mempool;
402
+	if (!mp)
403
+		return -1;
404
+	for(mpm = &mp->mpm; mpm; mpm = mpm->next) {
405
+		sum_used += mpm->usize;
406
+		sum_total += mpm->size;
407
+	}
408
+	*used = sum_used;
409
+	*total = sum_total;
410
+	return 0;
392 411
 }
393 412
 
394 413
 void *mp_malloc(struct MP *mp, size_t size) {
... ...
@@ -22,7 +22,7 @@
22 22
 #define MPOOL_H
23 23
 
24 24
 #ifdef USE_MPOOL
25
-
25
+#include "cltypes.h"
26 26
 typedef struct MP mp_t;
27 27
 
28 28
 mp_t *mp_create(void);
... ...
@@ -37,8 +37,10 @@ char *cli_mp_strdup(mp_t *mp, const char *s);
37 37
 char *cli_mp_virname(mp_t *mp, char *virname, unsigned int official);
38 38
 uint16_t *cli_mp_hex2ui(mp_t *mp, const char *hex);
39 39
 void mp_flush(mp_t *mp);
40
+int mp_getstats(const struct cl_engine *engine, size_t *used, size_t *total);
40 41
 #else /* USE_MPOOL */
41 42
 
43
+typedef void mp_t;
42 44
 #define mp_malloc(a, b) cli_malloc(b)
43 45
 #define mp_free(a, b) free(b)
44 46
 #define mp_calloc(a, b, c) cli_calloc(b, c)
... ...
@@ -49,6 +51,7 @@ void mp_flush(mp_t *mp);
49 49
 #define cli_mp_virname(mp, a, b) cli_virname(a, b)
50 50
 #define cli_mp_hex2ui(mp, hex) cli_hex2ui(hex)
51 51
 #define mp_flush(val)
52
+#define mp_getstats(mp,used,total) -1
52 53
 #endif /* USE_MPOOL */
53 54
 
54 55
 #endif