]> jfr.im git - irc/quakenet/newserv.git/blob - graphing/fsample.c
Merge.
[irc/quakenet/newserv.git] / graphing / fsample.c
1 #include "fsample.h"
2
3 #include <sys/types.h>
4 #include <sys/uio.h>
5 #include <unistd.h>
6 #include <sys/mman.h>
7 #include <fcntl.h>
8 #include <stdlib.h>
9 #include <string.h>
10
11 struct fsample_p {
12 fsample_t v;
13 unsigned char iteration;
14 };
15
16 struct fsample_header {
17 char magic[4];
18 fsample_t version;
19 unsigned char iteration;
20 fsample_t lastpos;
21 };
22
23 struct fsample {
24 struct fsample_p *m;
25 int fd;
26 size_t samples, len;
27 struct fsample_header *header;
28 void *corehandler;
29 CoreHandlerDelFn corehandlerdel;
30 };
31
32 static fsample_t version = 1;
33
34 static void fscorefree(void *arg) {
35 fsample *f = (fsample *)arg;
36 munmap(f->header, f->len);
37 }
38
39 fsample *fsopen(char *filename, size_t samples, CoreHandlerAddFn chafn, CoreHandlerDelFn chdfn) {
40 int flags = 0;
41 int new = 0;
42 fsample *f = (fsample *)malloc(sizeof(fsample));
43 if(!f)
44 return NULL;
45
46 f->len = samples * sizeof(struct fsample_p) + sizeof(struct fsample_header);
47 f->fd = open(filename, O_RDWR|O_CREAT, 0600);
48
49 if(!lseek(f->fd, 0, SEEK_END))
50 new = 1;
51
52 if((f->fd == -1) || (lseek(f->fd, f->len - 1, SEEK_SET) == -1)) {
53 free(f);
54 return NULL;
55 }
56 write(f->fd, "", 1);
57
58 flags = MAP_SHARED;
59 #ifdef MAP_NOCORE
60 flags|=MAP_NOCORE;
61 #endif
62
63 f->header = mmap(NULL, f->len, PROT_READ|PROT_WRITE, flags, f->fd, 0);
64 if(f->header == MAP_FAILED) {
65 close(f->fd);
66 free(f);
67 return NULL;
68 }
69
70 if(!new && (memcmp(f->header->magic, "FSAMP", sizeof(f->header->magic)) || (version != f->header->version))) {
71 munmap(f->header, f->len);
72 close(f->fd);
73 free(f);
74 return NULL;
75 }
76
77 if(chafn && chdfn) {
78 f->corehandler = chafn(fscorefree, f);
79 f->corehandlerdel = chdfn;
80 } else {
81 f->corehandler = NULL;
82 f->corehandlerdel = NULL;
83 }
84
85 memcpy(f->header->magic, "FSAMP", sizeof(f->header->magic));
86 f->header->version = version;
87
88 f->m = (struct fsample_p *)(f->header + 1);
89 f->samples = samples;
90
91 if(f->header->iteration == 0)
92 f->header->iteration = 1;
93
94 return f;
95 }
96
97 void fsclose(fsample *f) {
98 munmap(f->header, f->len);
99 close(f->fd);
100
101 if(f->corehandlerdel && f->corehandler)
102 (f->corehandlerdel)(f->corehandler);
103
104 free(f);
105 }
106
107 static inline unsigned char previteration(fsample *f) {
108 unsigned char p = f->header->iteration - 1;
109 if(p == 0)
110 p = 255;
111 return p;
112 }
113
114
115 /* doesn't support writing to negative numbers... */
116 inline void fsset(fsample *f, fsample_t pos, fsample_t value) {
117 fsample_t actualpos = pos % f->samples;
118 struct fsample_p *p = &f->m[actualpos];
119
120 if(f->header->lastpos > actualpos) {
121 f->header->iteration++;
122 if(f->header->iteration == 0)
123 f->header->iteration = 1;
124 }
125
126 f->header->lastpos = actualpos;
127
128 p->iteration = f->header->iteration;
129 p->v = value;
130 }
131
132 static inline fsample_t mmod(int x, int y) {
133 #if -5 % 3 == -2
134 int v = x % y;
135 if(v < 0)
136 v = v + y;
137 return v;
138 #else
139 #error Unknown modulo operator function.
140 #endif
141 }
142
143 /* API functions only have access to positive indicies */
144 inline fsample_t __fsget(fsample *f, int pos, fsample_t *t) {
145 struct fsample_p *p = &f->m[mmod(pos, f->samples)];
146
147 if(p->iteration != f->header->iteration) {
148 unsigned char prev = previteration(f);
149
150 if(prev != p->iteration || (pos <= f->header->lastpos)) {
151 /*printf("bad: prev: %d p->iteration: %d, pos: %d lastpos: %d\n", prev, p->iteration, pos, f->header->lastpos);*/
152 return 0;
153 }
154 }
155
156 *t = p->v;
157 return p->iteration;
158 }
159
160 inline fsample_t fsget_r(fsample *f, fsample_t pos, fsample_t *t) {
161 struct fsample_p *p = &f->m[mmod(pos, f->samples)];
162
163 *t = p->v;
164 return p->iteration;
165 }
166
167 inline fsample_t fsget(fsample *f, fsample_t pos, fsample_t *t) {
168 return __fsget(f, pos, t);
169 }
170
171 int fsadd_m(fsample_m *f, char *filename, size_t freq, DeriveValueFn derive, void *tag) {
172 fsample_m_entry *p = &f->entry[f->pos];
173
174 p->f = fsopen(filename, f->samples / freq, f->chafn, f->chdfn);
175 if(!p->f)
176 return 0;
177
178 p->freq = freq;
179 p->derive = derive;
180 p->tag = tag;
181 f->pos++;
182 return 1;
183 }
184
185 fsample_m *fsopen_m(size_t count, char *filename, size_t samples, CoreHandlerAddFn chafn, CoreHandlerDelFn chdfn) {
186 fsample_m *n = (fsample_m *)malloc(sizeof(fsample_m) + (count + 1) * sizeof(fsample_m_entry));
187 if(!n)
188 return NULL;
189
190 n->samples = samples;
191 n->pos = 0;
192 n->chafn = chafn;
193 n->chdfn = chdfn;
194
195 if(!fsadd_m(n, filename, 1, NULL, 0)) {
196 free(n);
197 return NULL;
198 }
199
200 return n;
201 }
202
203 void fsset_m(fsample_m *f, fsample_t pos, fsample_t value) {
204 int i;
205
206 for(i=0;i<f->pos;i++) {
207 fsample_t v;
208
209 if((pos + 1) % f->entry[i].freq != 0)
210 continue;
211
212 if(f->entry[i].derive) {
213 v = (f->entry[i].derive)(f, i, pos, f->entry[i].tag);
214 } else {
215 v = value;
216 }
217
218 fsset(f->entry[i].f, pos / f->entry[i].freq, v);
219 }
220 }
221
222 void fsclose_m(fsample_m *f) {
223 int i;
224
225 for(i=0;i<f->pos;i++)
226 fsclose(f->entry[i].f);
227 free(f);
228 }
229
230 inline fsample_t __fsget_m(fsample_m *f, int entry, int pos, fsample_t *t) {
231 return __fsget(f->entry[entry].f, pos / f->entry[entry].freq, t);
232 }
233
234 inline fsample_t fsget_m(fsample_m *f, int entry, fsample_t pos, fsample_t *t) {
235 return fsget(f->entry[entry].f, pos / f->entry[entry].freq, t);
236 }
237
238 inline fsample_t fsget_mr(fsample_m *f, int entry, fsample_t pos, fsample_t *t) {
239 return fsget_r(f->entry[entry].f, pos / f->entry[entry].freq, t);
240 }
241
242 fsample_t fsamean(fsample_m *f, int entry, fsample_t pos, void *tag) {
243 fsample_t c = 0;
244 long samples = (long)tag;
245 int count = 0;
246 int rpos = pos / f->entry[0].freq;
247 int i;
248 fsample_t t;
249
250 for(i=0;i<samples;i++) {
251 if(__fsget_m(f, 0, rpos - i, &t)) {
252 c+=t;
253 count++;
254 } else {
255 /* printf("bad :(\n");*/
256 }
257 }
258
259 if(count == 0)
260 return 0;
261
262 return c / count;
263 }
264
265 fsample_t fsapmean(fsample_m *f, int entry, fsample_t pos, void *tag) {
266 fsample_t c = 0;
267 long samples = (long)tag;
268 int count = 0;
269 int rpos = pos / f->entry[entry - 1].freq;
270 int i;
271 fsample_t t;
272
273 for(i=0;i<=samples;i++) {
274 if(__fsget(f->entry[entry - 1].f, rpos - i, &t)) {
275 c+=t;
276 count++;
277 } else {
278 /*printf("bad :(\n");*/
279 }
280 }
281
282 if(count == 0)
283 return 0;
284
285 return c / count;
286 }