]> jfr.im git - irc/quakenet/newserv.git/blob - nsmstats/nsmstats.c
PROXYSCAN: add 8118 http scans.
[irc/quakenet/newserv.git] / nsmstats / nsmstats.c
1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <math.h>
4 #include <string.h>
5
6 #include "../core/nsmalloc.h"
7 #include "../core/hooks.h"
8 #include "../control/control.h"
9
10 void nsmstats(int hookhum, void *arg);
11 int nsmhistogram(void *sender, int cargc, char **cargv);
12
13 void _init(void) {
14 registerhook(HOOK_CORE_STATSREQUEST, &nsmstats);
15 registercontrolhelpcmd("nsmhistogram", NO_DEVELOPER,1,&nsmhistogram,"Usage: nsmhistogram [pool id]\nDisplays memory information for given pool.");
16 }
17
18 void _fini(void) {
19 deregisterhook(HOOK_CORE_STATSREQUEST, &nsmstats);
20 deregistercontrolcmd("nsmhistogram", &nsmhistogram);
21 }
22
23 static char *formatmbuf(unsigned long count, size_t size, size_t realsize) {
24 static char buf[1024];
25
26 snprintf(buf, sizeof(buf), "%lu items, %luKb allocated for %luKb, %luKb (%.2f%%) overhead", count, (unsigned long)size / 1024, (unsigned long)realsize / 1024, (unsigned long)(realsize - size) / 1024, (double)(realsize - size) / (double)size * 100);
27 return buf;
28 }
29
30 void nsmgenstats(struct nsmpool *pool, double *mean, double *stddev) {
31 unsigned long long int sumsq = 0;
32 struct nsminfo *np;
33
34 *mean = (double)pool->size / pool->count;
35
36 for (np=pool->first.next;np;np=np->next)
37 sumsq+=np->size * np->size;
38
39 *stddev = sqrtf((double)sumsq / pool->count - *mean * *mean);
40 }
41
42 void nsmstats(int hookhum, void *arg) {
43 int i;
44 char buf[1024], extra[1024];
45 unsigned long totalcount = 0;
46 size_t totalsize = 0, totalrealsize = 0;
47 long level = (long)arg;
48
49 for (i=0;i<MAXPOOL;i++) {
50 struct nsmpool *pool=&nsmpools[i];
51 size_t realsize;
52
53 if (!pool->count)
54 continue;
55
56 realsize=pool->size + pool->count * sizeof(struct nsminfo) + sizeof(struct nsmpool);
57
58 totalsize+=pool->size;
59 totalrealsize+=realsize;
60 totalcount+=pool->count;
61
62 if(level > 10) {
63 extra[0] = '\0';
64 if(level > 100) {
65 double mean, stddev;
66 nsmgenstats(pool, &mean, &stddev);
67
68 snprintf(extra, sizeof(extra), ", mean: %.2fKb stddev: %.2fKb", mean / 1024, stddev / 1024);
69 }
70
71 snprintf(buf, sizeof(buf), "NSMalloc: pool %2d (%10s): %s%s", i, nsmpoolnames[i]?nsmpoolnames[i]:"??", formatmbuf(pool->count, pool->size, realsize), extra);
72 triggerhook(HOOK_CORE_STATSREPLY, buf);
73 }
74 }
75
76 snprintf(buf, sizeof(buf), "NSMalloc: pool totals: %s", formatmbuf(totalcount, totalsize, totalrealsize));
77 triggerhook(HOOK_CORE_STATSREPLY, buf);
78 }
79
80 struct nsmhistogram_s {
81 size_t size;
82 unsigned long freq;
83 } nsmhistogram_s;
84
85 static int hcompare_size(const void *a, const void *b) {
86 return ((struct nsmhistogram_s *)a)->size - ((struct nsmhistogram_s *)b)->size;
87 }
88
89 static int hcompare_freq(const void *a, const void *b) {
90 return ((struct nsmhistogram_s *)a)->freq - ((struct nsmhistogram_s *)b)->freq;
91 }
92
93 /*
94 * since this is gonna process over a million allocations, we can't just do
95 * it the simple O(n^2) way, so here's the crazy fast(er) way:
96 * we create a list of all sizes and sort them, then store unique items
97 * we can then calculate frequencies in O(n log n) time by searching this
98 * sorted list using a binary chop...
99 */
100 int nsmhistogram(void *sender, int cargc, char **cargv) {
101 int i, max;
102 unsigned int poolid;
103 struct nsmpool *pool;
104 struct nsminfo *np;
105 struct nsmhistogram_s *freqs;
106 size_t cval;
107 unsigned long dst;
108
109 if(cargc < 1)
110 return CMD_USAGE;
111
112 poolid = atoi(cargv[0]);
113 if(poolid > MAXPOOL) {
114 controlreply(sender, "Bad pool id.");
115 return CMD_ERROR;
116 }
117
118 pool = &nsmpools[poolid];
119 if(pool->count == 0) {
120 controlreply(sender, "Pool is empty.");
121 return CMD_ERROR;
122 }
123
124 freqs = (struct nsmhistogram_s *)malloc(sizeof(struct nsmhistogram_s) * pool->count);
125 if(!freqs) {
126 controlreply(sender, "Error allocating first BIG array.");
127 return CMD_ERROR;
128 }
129
130 /* O(n) */
131 memset(freqs, 0, sizeof(struct nsmhistogram_s) * pool->count);
132 for(i=0,np=pool->first.next;np;np=np->next)
133 freqs[i++].size = np->size;
134
135 /* O(n log n) */
136 qsort(freqs, pool->count, sizeof(struct nsmhistogram_s), hcompare_size);
137
138 /* O(n) */
139 cval = freqs[0].size;
140 dst = 1;
141 for(i=1;i<pool->count;i++) {
142 if(cval != freqs[i].size) {
143 cval = freqs[i].size;
144 freqs[dst++].size = freqs[i].size;
145 }
146 }
147
148 /* outer loop is O(n), inner loop is O(1 + log n) => O(n + n log n) => O(n log n) */
149 for(np=pool->first.next;np;np=np->next) {
150 unsigned long low = 0, high = dst;
151 while(low < high) {
152 unsigned long mid = (low + high) / 2;
153 if (freqs[mid].size < np->size) {
154 low = mid + 1;
155 } else {
156 high = mid;
157 }
158 }
159 if((low > np->size) || (freqs[low].size != np->size)) {
160 controlreply(sender, "ERROR");
161 return CMD_ERROR;
162 } else {
163 freqs[low].freq++;
164 }
165 }
166
167 /* O(n log n) */
168 qsort(freqs, dst, sizeof(struct nsmhistogram_s), hcompare_freq);
169 max = 2000;
170
171 for(i=dst-1;i>=0&&max-->0;i--)
172 controlreply(sender, "%10lu: %10lu", (unsigned long)freqs[i].size, (unsigned long)freqs[i].freq);
173
174 free(freqs);
175 return CMD_OK;
176 }