git-svn: trunk@4344
Török Edvin authored on 2008/11/06 23:27:27... | ... |
@@ -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 |
} |
... | ... |
@@ -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 |