fast-stats 1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/ext/stats/stats.c ADDED
@@ -0,0 +1,597 @@
1
+ /* stats.c */
2
+
3
+ #include <stdio.h>
4
+ #include <stdlib.h>
5
+ #include <string.h>
6
+ #include <assert.h>
7
+ #include <time.h>
8
+ #include <sys/time.h>
9
+ #include <unistd.h>
10
+
11
+ #ifdef DARWIN
12
+ #include <mach/mach_time.h>
13
+ #endif
14
+
15
+ #include "stats/error.h"
16
+ #include "stats/stats.h"
17
+ #include "stats/hash.h"
18
+ #include "stats/debug.h"
19
+
20
+
21
+ static void stats_init_data(struct stats *stats);
22
+ static int stats_hash_probe(struct stats_data *data, const char *key, int len);
23
+
24
+
25
+ #ifdef DARWIN
26
+ static mach_timebase_info_data_t timebase_info = {0,0};
27
+ #endif
28
+
29
+ #ifdef LINUX
30
+ long long current_time()
31
+ {
32
+ struct timespec ts;
33
+
34
+ clock_gettime(CLOCK_MONOTONIC,&ts);
35
+
36
+ return (long long)ts.tv_sec * 1000000000ll + (long long)ts.tv_nsec;
37
+ }
38
+
39
+ long long time_delta_to_nanos(long long start, long long end)
40
+ {
41
+ return start - end;
42
+ }
43
+ #endif
44
+
45
+ #ifdef DARWIN
46
+ long long current_time()
47
+ {
48
+ return mach_absolute_time();
49
+ }
50
+
51
+ long long time_delta_to_nanos(long long start, long long end)
52
+ {
53
+ long long elapsed, elapsed_nano;
54
+
55
+ elapsed = end - start;
56
+
57
+ if (timebase_info.denom == 0)
58
+ {
59
+ mach_timebase_info(&timebase_info);
60
+ }
61
+
62
+ // Do the maths. We hope that the multiplication doesn't
63
+ // overflow; the price you pay for working in fixed point.
64
+
65
+ elapsed_nano = elapsed * timebase_info.numer / timebase_info.denom;
66
+
67
+ return elapsed_nano;
68
+ }
69
+ #endif
70
+
71
+ /*
72
+ * stats_create
73
+ *
74
+ * Create and initialize a stats object. The resources needed for the stats
75
+ * (files, shared memory, semaphore, etc) are not opened yet. The stats_open
76
+ * call must be invoked.
77
+ *
78
+ * If stats_create returns a stats object, you must call stats_free on it
79
+ * to releaseall memory used by the stats object.
80
+ *
81
+ * Returns:
82
+ * S_OK - success
83
+ * ERROR_INVALID_PARAMETERS - the name was too long
84
+ * ERROR_MEMORY - out of memory / memory allocation error
85
+ */
86
+ int stats_create(const char *name, struct stats **stats_out)
87
+ {
88
+ struct stats * stats = NULL;
89
+ int err;
90
+ char lock_name[SEMAPHORE_MAX_NAME_LEN+1];
91
+ char mem_name[SHARED_MEMORY_MAX_NAME_LEN];
92
+
93
+ /* printf("Sizeof stats counter is %ld\n",sizeof(struct stats_counter)); */
94
+ assert(sizeof(struct stats_header) == 16);
95
+ assert(sizeof(struct stats_counter) == 56);
96
+
97
+ if (stats_out == NULL)
98
+ return ERROR_INVALID_PARAMETERS;
99
+
100
+ /* check that the length of the name plus the extension we are adding is not too long */
101
+ if (strlen(name) + 4 > SEMAPHORE_MAX_NAME_LEN)
102
+ return ERROR_INVALID_PARAMETERS;
103
+ if (strlen(name) + 4 > SHARED_MEMORY_MAX_NAME_LEN)
104
+ return ERROR_INVALID_PARAMETERS;
105
+
106
+ strcpy(lock_name,name);
107
+ strcat(lock_name,".sem");
108
+ strcpy(mem_name,name);
109
+ strcat(mem_name,".mem");
110
+
111
+ stats = (struct stats *) malloc(sizeof(struct stats));
112
+ if (stats == NULL)
113
+ {
114
+ err = ERROR_MEMORY;
115
+ goto fail;
116
+ }
117
+
118
+ stats->magic = STATS_MAGIC;
119
+ stats->data = NULL;
120
+
121
+ err = lock_init(&stats->lock, lock_name);
122
+ if (err != S_OK)
123
+ goto fail;
124
+
125
+ err = shared_memory_init(&stats->shmem, mem_name, OMODE_OPEN_OR_CREATE | DESTROY_ON_CLOSE_IF_LAST, sizeof(struct stats_data));
126
+ if (err != S_OK)
127
+ goto fail;
128
+
129
+ err = S_OK;
130
+ goto ok;
131
+
132
+ fail:
133
+ if (stats)
134
+ {
135
+ free(stats);
136
+ stats = NULL;
137
+ }
138
+
139
+ ok:
140
+ *stats_out = stats;
141
+ return err;
142
+ }
143
+
144
+
145
+ /*
146
+ * stats_open
147
+ *
148
+ * Opens the resources needed for a stats object. After this call returns
149
+ * successfully, the stats object is ready for use.
150
+ *
151
+ * The resources allocated by stats_open must be freed by a corresponding
152
+ * call to stats_close().
153
+ *
154
+ * Returns:
155
+ * S_OK - success
156
+ * ERROR_INVALID_PARAMETERS - the stats object passed was not valid
157
+ */
158
+ int stats_open(struct stats *stats)
159
+ {
160
+ int err;
161
+
162
+ if (!stats || stats->magic != STATS_MAGIC || stats->data != NULL)
163
+ return ERROR_INVALID_PARAMETERS;
164
+
165
+ assert(!lock_is_open(&stats->lock));
166
+ assert(!shared_memory_is_open(&stats->shmem));
167
+ assert(stats->data == NULL);
168
+
169
+ /* open the lock */
170
+ err = lock_open(&stats->lock);
171
+ if (err == S_OK)
172
+ {
173
+ /* acquire the lock to make the process of getting and initializing the shared memory atomic */
174
+ lock_acquire(&stats->lock);
175
+
176
+ /* open the shared memory */
177
+ err = shared_memory_open(&stats->shmem);
178
+ if (err == S_OK)
179
+ {
180
+ assert(shared_memory_size(&stats->shmem) == sizeof(struct stats_data));
181
+ assert(shared_memory_ptr(&stats->shmem) != NULL);
182
+
183
+ /* get the pointer to the shared memory and initialize it if this process created it */
184
+ stats->data = (struct stats_data *) shared_memory_ptr(&stats->shmem);
185
+
186
+ if (shared_memory_was_created(&stats->shmem))
187
+ {
188
+ stats_init_data(stats);
189
+ }
190
+
191
+ assert(stats->data->hdr.stats_magic == STATS_MAGIC);
192
+ }
193
+
194
+ lock_release(&stats->lock);
195
+ }
196
+
197
+ assert((err == S_OK && stats->data != NULL) || (err != S_OK && stats->data == NULL));
198
+
199
+ return err;
200
+ }
201
+
202
+ static void stats_init_data(struct stats *stats)
203
+ {
204
+ DPRINTF("Intializing stats data\n");
205
+
206
+ memset(stats->data,0,sizeof(struct stats_data));
207
+ stats->data->hdr.stats_magic = STATS_MAGIC;
208
+ }
209
+
210
+ int stats_close(struct stats *stats)
211
+ {
212
+ int shared_mem_destroyed;
213
+ shared_memory_close(&stats->shmem,&shared_mem_destroyed);
214
+ lock_close(&stats->lock,shared_mem_destroyed);
215
+ return S_OK;
216
+ }
217
+
218
+ int stats_free(struct stats *stats)
219
+ {
220
+ free(stats);
221
+ return S_OK;
222
+ }
223
+
224
+ int stats_allocate_counter(struct stats *stats, const char *name, struct stats_counter **ctr_out)
225
+ {
226
+ int loc, key_len;
227
+ int err = S_OK;
228
+ struct stats_counter *ctr = NULL;
229
+
230
+ if (!stats || stats->magic != STATS_MAGIC || stats->data == NULL)
231
+ return ERROR_INVALID_PARAMETERS;
232
+
233
+ if (ctr_out == NULL)
234
+ return ERROR_INVALID_PARAMETERS;
235
+
236
+ key_len = strlen(name);
237
+ if (key_len > MAX_COUNTER_KEY_LENGTH)
238
+ return ERROR_STATS_KEY_TOO_LONG;
239
+
240
+ lock_acquire(&stats->lock);
241
+
242
+ loc = stats_hash_probe(stats->data, name, key_len);
243
+ if (loc == -1)
244
+ {
245
+ err = ERROR_STATS_CANNOT_ALLOCATE_COUNTER;
246
+ }
247
+ else
248
+ {
249
+ ctr = stats->data->ctr + loc;
250
+ if (ctr->ctr_allocation_status != ALLOCATION_STATUS_ALLOCATED)
251
+ {
252
+ ctr->ctr_allocation_status = ALLOCATION_STATUS_ALLOCATED;
253
+ ctr->ctr_allocation_seq = stats->data->hdr.stats_sequence_number++;
254
+ ctr->ctr_key_len = key_len;
255
+ memcpy(ctr->ctr_key, name, key_len);
256
+ }
257
+ }
258
+
259
+ lock_release(&stats->lock);
260
+
261
+ *ctr_out = ctr;
262
+
263
+ assert((*ctr_out != NULL && err == S_OK) || (*ctr_out == NULL && err != S_OK));
264
+
265
+ return err;
266
+ }
267
+
268
+ static int ctr_compare(const void * a, const void * b)
269
+ {
270
+ const struct stats_counter *actr = *(struct stats_counter **)a;
271
+ const struct stats_counter *bctr = *(struct stats_counter **)b;
272
+ return actr->ctr_allocation_seq - bctr->ctr_allocation_seq;
273
+ }
274
+
275
+ int stats_get_counters(struct stats *stats, struct stats_counter **counters, int counter_size, int *counter_out, int *sequence_number_out)
276
+ {
277
+ int err = S_OK;
278
+ int i, n;
279
+ struct stats_data *data;
280
+ int seq_no;
281
+
282
+ if (!stats || stats->magic != STATS_MAGIC || stats->data == NULL)
283
+ return ERROR_INVALID_PARAMETERS;
284
+
285
+ if (!counters || counter_size <= 0)
286
+ return ERROR_INVALID_PARAMETERS;
287
+
288
+ data = stats->data;
289
+ memset(counters, 0, sizeof(struct stats_counter *) * counter_size);
290
+ n = 0;
291
+ i = 0;
292
+
293
+ lock_acquire(&stats->lock);
294
+
295
+ while (i < COUNTER_TABLE_SIZE && n < counter_size)
296
+ {
297
+ if (data->ctr[i].ctr_allocation_status == ALLOCATION_STATUS_ALLOCATED)
298
+ {
299
+ counters[n] = data->ctr + i;
300
+ n++;
301
+ }
302
+ i++;
303
+ }
304
+
305
+ seq_no = data->hdr.stats_sequence_number;
306
+
307
+ lock_release(&stats->lock);
308
+
309
+ qsort(counters,n,sizeof(struct stats_counter *),ctr_compare);
310
+
311
+ if (counter_out)
312
+ *counter_out = n;
313
+
314
+ if (sequence_number_out)
315
+ *sequence_number_out = seq_no;
316
+
317
+ return err;
318
+ }
319
+
320
+
321
+ static int stats_hash_probe(struct stats_data *data, const char *key, int len)
322
+ {
323
+ uint32_t h, k, n;
324
+ int i, probes = 1;
325
+
326
+ h = fast_hash(key,len);
327
+ k = h % COUNTER_TABLE_SIZE;
328
+
329
+ if (data->ctr[k].ctr_allocation_status == ALLOCATION_STATUS_FREE)
330
+ {
331
+ return k;
332
+ }
333
+ else if (data->ctr[k].ctr_allocation_status == ALLOCATION_STATUS_ALLOCATED &&
334
+ data->ctr[k].ctr_key_len == len &&
335
+ memcmp(data->ctr[k].ctr_key,key,len) == 0)
336
+ {
337
+ return k;
338
+ }
339
+
340
+ n = 1;
341
+ for (i =0; i < 32; i++)
342
+ {
343
+ k = (h + n) % COUNTER_TABLE_SIZE;
344
+ probes++;
345
+ if (data->ctr[k].ctr_allocation_status == ALLOCATION_STATUS_FREE)
346
+ {
347
+ return k;
348
+ }
349
+ else if (data->ctr[k].ctr_allocation_status == ALLOCATION_STATUS_ALLOCATED &&
350
+ data->ctr[k].ctr_key_len == len &&
351
+ memcmp(data->ctr[k].ctr_key,key,len) == 0)
352
+ {
353
+ return k;
354
+ }
355
+ n = n * 2;
356
+ }
357
+
358
+ return -1;
359
+ }
360
+
361
+ int stats_reset_counters(struct stats *stats)
362
+ {
363
+ int i;
364
+ struct stats_data *data;
365
+
366
+ if (!stats || stats->magic != STATS_MAGIC || stats->data == NULL)
367
+ return ERROR_INVALID_PARAMETERS;
368
+
369
+ data = stats->data;
370
+
371
+ lock_acquire(&stats->lock);
372
+
373
+ for (i = 0; i < COUNTER_TABLE_SIZE; i++)
374
+ {
375
+ if (data->ctr[i].ctr_allocation_status == ALLOCATION_STATUS_ALLOCATED)
376
+ {
377
+ __sync_lock_test_and_set(&data->ctr[i].ctr_value.val64,0ll);
378
+ }
379
+ }
380
+
381
+ lock_release(&stats->lock);
382
+
383
+ return S_OK;
384
+ }
385
+
386
+ int stats_get_counter_list(struct stats *stats, struct stats_counter_list *cl)
387
+ {
388
+ int err = S_OK;
389
+ int i, n;
390
+ struct stats_data *data;
391
+
392
+ if (!stats || stats->magic != STATS_MAGIC || stats->data == NULL)
393
+ return ERROR_INVALID_PARAMETERS;
394
+
395
+ if (!cl)
396
+ return ERROR_INVALID_PARAMETERS;
397
+
398
+ data = stats->data;
399
+ memset(cl, 0, sizeof(struct stats_counter_list));
400
+ n = 0;
401
+ i = 0;
402
+
403
+ lock_acquire(&stats->lock);
404
+
405
+ while (i < COUNTER_TABLE_SIZE)
406
+ {
407
+ if (data->ctr[i].ctr_allocation_status == ALLOCATION_STATUS_ALLOCATED)
408
+ {
409
+ cl->cl_ctr[n] = data->ctr + i;
410
+ n++;
411
+ }
412
+ i++;
413
+ }
414
+
415
+ cl->cl_seq_no = data->hdr.stats_sequence_number;
416
+
417
+ lock_release(&stats->lock);
418
+
419
+ cl->cl_count = n;
420
+ qsort(cl->cl_ctr,n,sizeof(struct stats_counter *),ctr_compare);
421
+
422
+ return err;
423
+ }
424
+
425
+
426
+ /**
427
+ * stats_counter_list functions
428
+ */
429
+
430
+ int stats_cl_create(struct stats_counter_list **cl_out)
431
+ {
432
+ struct stats_counter_list *cl;
433
+
434
+ if (cl_out == NULL)
435
+ return ERROR_INVALID_PARAMETERS;
436
+
437
+ cl = (struct stats_counter_list *)malloc(sizeof(struct stats_counter_list));
438
+ if (!cl)
439
+ return ERROR_FAIL;
440
+
441
+ stats_cl_init(cl);
442
+ *cl_out = cl;
443
+
444
+ return S_OK;
445
+ }
446
+
447
+ void stats_cl_init(struct stats_counter_list *cl)
448
+ {
449
+ memset(cl,0,sizeof(struct stats_counter_list));
450
+ }
451
+
452
+ void stats_cl_free(struct stats_counter_list *cl)
453
+ {
454
+ free(cl);
455
+ }
456
+
457
+ int stats_cl_is_updated(struct stats *stats, struct stats_counter_list *cl)
458
+ {
459
+ return cl->cl_seq_no != stats->data->hdr.stats_sequence_number;
460
+ }
461
+
462
+
463
+
464
+ /**
465
+ * stats_sample functions
466
+ *
467
+ */
468
+
469
+ int stats_sample_create(struct stats_sample **sample_out)
470
+ {
471
+ struct stats_sample *sample;
472
+
473
+ if (sample_out == NULL)
474
+ return ERROR_INVALID_PARAMETERS;
475
+
476
+ sample = (struct stats_sample *)malloc(sizeof(struct stats_sample));
477
+ if (!sample)
478
+ return ERROR_FAIL;
479
+
480
+ stats_sample_init(sample);
481
+ *sample_out = sample;
482
+
483
+ return S_OK;
484
+ }
485
+
486
+ void stats_sample_init(struct stats_sample *sample)
487
+ {
488
+ memset(sample,0,sizeof(struct stats_sample));
489
+ }
490
+
491
+ void stats_sample_free(struct stats_sample *sample)
492
+ {
493
+ free(sample);
494
+ }
495
+
496
+ int stats_get_sample(struct stats *stats, struct stats_counter_list *cl, struct stats_sample *sample)
497
+ {
498
+ long long sample_time;
499
+ int i, err;
500
+
501
+ if (stats == NULL || cl == NULL || sample == NULL)
502
+ return ERROR_INVALID_PARAMETERS;
503
+
504
+ /* get the sample time */
505
+ sample_time = current_time();
506
+
507
+ /* if the counter list has been updated, update the passed in counter list */
508
+ if (stats_cl_is_updated(stats,cl))
509
+ {
510
+ /* sequence number has changed. this means there might be new counter definitions.
511
+ reload the counter list */
512
+ err = stats_get_counter_list(stats, cl);
513
+ if (err != S_OK)
514
+ return err;
515
+ }
516
+
517
+ /* save the sequence number */
518
+ sample->sample_seq_no = cl->cl_seq_no;
519
+
520
+ /* save the sample time */
521
+ sample->sample_time = sample_time;
522
+
523
+ /* save the sample data */
524
+ for (i = 0; i < cl->cl_count; i++)
525
+ {
526
+ sample->sample_value[i] = cl->cl_ctr[i]->ctr_value;
527
+ }
528
+
529
+ sample->sample_count = cl->cl_count;
530
+
531
+ return S_OK;
532
+ }
533
+
534
+ long long stats_sample_get_value(struct stats_sample *sample, int index)
535
+ {
536
+ if (sample == NULL || index > sample->sample_count)
537
+ return 0;
538
+ return sample->sample_value[index].val64;
539
+ }
540
+
541
+
542
+ long long stats_sample_get_delta(struct stats_sample *sample, struct stats_sample *prev_sample, int index)
543
+ {
544
+ if (sample == NULL || index > sample->sample_count || prev_sample == NULL || index > prev_sample->sample_count)
545
+ return 0;
546
+ return sample->sample_value[index].val64 - prev_sample->sample_value[index].val64;
547
+ }
548
+
549
+ /**
550
+ * counter functions
551
+ */
552
+
553
+ void counter_get_key(struct stats_counter *ctr, char *buf, int buflen)
554
+ {
555
+ if (buflen >= ctr->ctr_key_len+1)
556
+ {
557
+ memcpy(buf,ctr->ctr_key,ctr->ctr_key_len);
558
+ buf[ctr->ctr_key_len] = '\0';
559
+ }
560
+ else
561
+ {
562
+ memcpy(buf,ctr->ctr_key,buflen-1);
563
+ buf[buflen-1] = '\0';
564
+ }
565
+ }
566
+
567
+ void counter_increment(struct stats_counter *ctr)
568
+ {
569
+ if (ctr != NULL)
570
+ {
571
+ __sync_fetch_and_add(&ctr->ctr_value.val64,1ll);
572
+ }
573
+ }
574
+
575
+ void counter_increment_by(struct stats_counter *ctr, long long val)
576
+ {
577
+ if (ctr != NULL)
578
+ {
579
+ __sync_fetch_and_add(&ctr->ctr_value.val64,val);
580
+ }
581
+ }
582
+
583
+ void counter_clear(struct stats_counter *ctr)
584
+ {
585
+ if (ctr != NULL)
586
+ {
587
+ __sync_lock_test_and_set(&ctr->ctr_value.val64,0ll);
588
+ }
589
+ }
590
+
591
+ void counter_set(struct stats_counter *ctr, long long val)
592
+ {
593
+ if (ctr != NULL)
594
+ {
595
+ __sync_lock_test_and_set(&ctr->ctr_value.val64,val);
596
+ }
597
+ }
@@ -0,0 +1,71 @@
1
+ /* $OpenBSD: strlcat.c,v 1.2 1999/06/17 16:28:58 millert Exp $ */
2
+
3
+ /*
4
+ * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
5
+ * All rights reserved.
6
+ *
7
+ * Redistribution and use in source and binary forms, with or without
8
+ * modification, are permitted provided that the following conditions
9
+ * are met:
10
+ * 1. Redistributions of source code must retain the above copyright
11
+ * notice, this list of conditions and the following disclaimer.
12
+ * 2. Redistributions in binary form must reproduce the above copyright
13
+ * notice, this list of conditions and the following disclaimer in the
14
+ * documentation and/or other materials provided with the distribution.
15
+ * 3. The name of the author may not be used to endorse or promote products
16
+ * derived from this software without specific prior written permission.
17
+ *
18
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
19
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
20
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21
+ * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
24
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
27
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
+ */
29
+
30
+ #ifdef LINUX
31
+
32
+ #include <sys/types.h>
33
+ #include <string.h>
34
+
35
+ /*
36
+ * Appends src to string dst of size siz (unlike strncat, siz is the
37
+ * full size of dst, not space left). At most siz-1 characters
38
+ * will be copied. Always NUL terminates (unless siz == 0).
39
+ * Returns strlen(src); if retval >= siz, truncation occurred.
40
+ */
41
+ size_t strlcat(dst, src, siz)
42
+ char *dst;
43
+ const char *src;
44
+ size_t siz;
45
+ {
46
+ register char *d = dst;
47
+ register const char *s = src;
48
+ register size_t n = siz;
49
+ size_t dlen;
50
+
51
+ /* Find the end of dst and adjust bytes left but don't go past end */
52
+ while (*d != '\0' && n-- != 0)
53
+ d++;
54
+ dlen = d - dst;
55
+ n = siz - dlen;
56
+
57
+ if (n == 0)
58
+ return(dlen + strlen(s));
59
+ while (*s != '\0') {
60
+ if (n != 1) {
61
+ *d++ = *s;
62
+ n--;
63
+ }
64
+ s++;
65
+ }
66
+ *d = '\0';
67
+
68
+ return(dlen + (s - src)); /* count does not include NUL */
69
+ }
70
+
71
+ #endif