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.
- checksums.yaml +7 -0
- data/Makefile +23 -0
- data/ext/stats/.gitignore +12 -0
- data/ext/stats/error.c +42 -0
- data/ext/stats/extconf.rb +18 -0
- data/ext/stats/hash.c +66 -0
- data/ext/stats/lock.c +39 -0
- data/ext/stats/mt19937.c +209 -0
- data/ext/stats/mt19937.h +16 -0
- data/ext/stats/semaphore.c +278 -0
- data/ext/stats/shared_mem.c +238 -0
- data/ext/stats/stats/debug.h +8 -0
- data/ext/stats/stats/error.h +50 -0
- data/ext/stats/stats/hash.h +10 -0
- data/ext/stats/stats/lock.h +27 -0
- data/ext/stats/stats/omode.h +11 -0
- data/ext/stats/stats/semaphore.h +53 -0
- data/ext/stats/stats/shared_mem.h +46 -0
- data/ext/stats/stats/stats.h +215 -0
- data/ext/stats/stats-ruby.c +557 -0
- data/ext/stats/stats.c +597 -0
- data/ext/stats/strlcat.c +71 -0
- data/ext/stats/strlcpy.c +68 -0
- data/fast-stats.gemspec +17 -0
- data/lib/stats/version.rb +3 -0
- data/lib/stats.rb +8 -0
- data/test/benchmark_stats.rb +101 -0
- data/test/test_stats.rb +11 -0
- metadata +70 -0
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
|
+
}
|
data/ext/stats/strlcat.c
ADDED
@@ -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
|