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.
@@ -0,0 +1,557 @@
1
+ #define RSTRING_NOT_MODIFIED
2
+ #include <ruby.h>
3
+ #include <stdio.h>
4
+ #include <assert.h>
5
+
6
+ #include "stats/error.h"
7
+ #include "stats/stats.h"
8
+ #include "stats/hash.h"
9
+
10
+ static VALUE stats_class = Qnil;
11
+ static VALUE ctr_class = Qnil;
12
+ static VALUE tmr_class = Qnil;
13
+
14
+ #define STATS_MAGIC 'stat'
15
+ #define CTR_MAGIC 'ctr '
16
+
17
+ struct rbstats_counter_entry
18
+ {
19
+ char key[MAX_COUNTER_KEY_LENGTH+1];
20
+ struct stats_counter * ctr;
21
+ };
22
+
23
+ #define TABLE_SIZE 2003
24
+
25
+ struct rbstats
26
+ {
27
+ int magic;
28
+
29
+ struct stats * stats;
30
+ struct rbstats_counter_entry tbl[TABLE_SIZE];
31
+ };
32
+
33
+
34
+ static VALUE rbctr_alloc(struct stats_counter *counter);
35
+ static void rbctr_free(void *p);
36
+
37
+ static VALUE rbtmr_alloc(struct stats_counter *counter);
38
+ static void rbtmr_free(void *p);
39
+
40
+
41
+ static int hash_probe(struct rbstats *stats, const char *key, long len)
42
+ {
43
+ uint32_t h, k, n;
44
+ int i;
45
+
46
+ h = fast_hash(key,(int)len);
47
+ k = h % TABLE_SIZE;
48
+
49
+ if (stats->tbl[k].key[0] == '\0')
50
+ {
51
+ strcpy(stats->tbl[k].key,key);
52
+ return k;
53
+ }
54
+ else if (strcmp(stats->tbl[k].key,key) == 0)
55
+ {
56
+ return k;
57
+ }
58
+
59
+ n = 1;
60
+ for (i =0; i < 32; i++)
61
+ {
62
+ k = (h + n) % TABLE_SIZE;
63
+ if (stats->tbl[k].key[0] == '\0')
64
+ {
65
+ strcpy(stats->tbl[k].key,key);
66
+ return k;
67
+ }
68
+ else if (strcmp(stats->tbl[k].key,key) == 0)
69
+ {
70
+ return k;
71
+ }
72
+ n = n * 2;
73
+ }
74
+
75
+ return -1;
76
+ }
77
+
78
+ /* this simple table keeps track of stats objects so that multiple calls to
79
+ * Stats.new('foo')
80
+ * will return a rbstats object which wraps the same base stats object.
81
+ */
82
+
83
+ struct open_stats_objects {
84
+ char name[STATS_MAX_NAME_LEN + 1];
85
+ int open_count;
86
+ struct stats *stats;
87
+ };
88
+
89
+ #define OPEN_STATS_OBJECTS 8
90
+
91
+ struct open_stats_objects open_stats_object_table[OPEN_STATS_OBJECTS];
92
+ int open_stats_object_table_initialized = 0;
93
+
94
+
95
+ static struct stats *open_stats(const char * name)
96
+ {
97
+ struct stats *stats = NULL;
98
+ int err;
99
+ int i;
100
+
101
+ if (strlen(name) > STATS_MAX_NAME_LEN)
102
+ {
103
+ printf("Stats name is too long\n");
104
+ return NULL;
105
+ }
106
+
107
+ if (open_stats_object_table_initialized == 0)
108
+ {
109
+ memset(open_stats_object_table, 0, sizeof(open_stats_object_table));
110
+ open_stats_object_table_initialized = 1;
111
+ }
112
+
113
+ for (i = 0; i < OPEN_STATS_OBJECTS; i++ )
114
+ {
115
+ if (*open_stats_object_table[i].name == 0)
116
+ break;
117
+ if (strcmp(name,open_stats_object_table[i].name) == 0)
118
+ {
119
+ if (open_stats_object_table[i].stats == NULL)
120
+ {
121
+ /* there is an entry at location i, but it is not open */
122
+ break;
123
+ }
124
+ else
125
+ {
126
+ open_stats_object_table[i].open_count++;
127
+ return open_stats_object_table[i].stats;
128
+ }
129
+ }
130
+ }
131
+
132
+ /* see if the table is all full */
133
+ if (i == OPEN_STATS_OBJECTS)
134
+ {
135
+ printf("Failed to create stats: stats table is full\n");
136
+ return NULL;
137
+ }
138
+
139
+ err = stats_create(name,&stats);
140
+ if (err != S_OK)
141
+ {
142
+ printf("Failed to create stats: %s\n", error_message(err));
143
+ return NULL;
144
+ }
145
+
146
+ err = stats_open(stats);
147
+ if (err != S_OK)
148
+ {
149
+ printf("Failed to open stats: %s\n", error_message(err));
150
+ stats_free(stats);
151
+ return NULL;
152
+ }
153
+
154
+ strcpy(open_stats_object_table[i].name, name);
155
+ open_stats_object_table[i].open_count++;
156
+ open_stats_object_table[i].stats = stats;
157
+
158
+ return stats;
159
+ }
160
+
161
+
162
+ /******************************************************************
163
+ *
164
+ * Ruby Stats object
165
+ *
166
+ */
167
+
168
+
169
+ static void rbstats_free(void *p)
170
+ {
171
+ struct rbstats *s;
172
+ int i;
173
+
174
+ s = (struct rbstats *)p;
175
+ if (s && s->stats)
176
+ {
177
+ /* look for the object in the open table and decrement the open count */
178
+ for (i = 0; i < OPEN_STATS_OBJECTS; i++ )
179
+ {
180
+ if (open_stats_object_table[i].stats == s->stats)
181
+ {
182
+ open_stats_object_table[i].open_count--;
183
+ if (open_stats_object_table[i].open_count == 0)
184
+ {
185
+ open_stats_object_table[i].stats = NULL;
186
+ stats_close(s->stats);
187
+ stats_free(s->stats);
188
+ }
189
+ }
190
+ }
191
+ }
192
+
193
+ free(p);
194
+ }
195
+
196
+ VALUE rbstats_new(VALUE class, VALUE name)
197
+ {
198
+ struct rbstats *stats;
199
+ VALUE tdata;
200
+
201
+ Check_Type(name, T_STRING);
202
+
203
+ stats = (struct rbstats *)malloc(sizeof(struct rbstats));
204
+ memset(stats,0,sizeof(struct rbstats));
205
+ stats->magic = STATS_MAGIC;
206
+
207
+ tdata = Data_Wrap_Struct(class, 0, rbstats_free, stats);
208
+ rb_obj_call_init(tdata, 1, &name);
209
+
210
+ return tdata;
211
+ }
212
+
213
+ static VALUE rbstats_init(VALUE self, VALUE name)
214
+ {
215
+ struct rbstats *stats;
216
+
217
+ Check_Type(name, T_STRING);
218
+ Data_Get_Struct(self, struct rbstats, stats);
219
+
220
+ stats->stats = open_stats(RSTRING_PTR(name));
221
+
222
+ return self;
223
+ }
224
+
225
+
226
+ static struct rbstats *rbstats_get_wrapped_stats(VALUE self)
227
+ {
228
+ struct rbstats *stats;
229
+
230
+ Data_Get_Struct(self, struct rbstats, stats);
231
+ assert(stats != NULL);
232
+ assert(stats->magic == STATS_MAGIC);
233
+
234
+ return stats;
235
+ }
236
+
237
+ static struct stats_counter *rbstats_get_counter(struct rbstats *stats, VALUE rbkey)
238
+ {
239
+ char *key;
240
+ int idx, keylen;
241
+ struct stats_counter *counter = NULL;
242
+
243
+ Check_Type(rbkey, T_STRING);
244
+
245
+ key = RSTRING_PTR(rbkey);
246
+ keylen = RSTRING_LEN(rbkey);
247
+
248
+ idx = hash_probe(stats,key,keylen);
249
+ if (idx != -1)
250
+ {
251
+ counter = stats->tbl[idx].ctr;
252
+ if (counter == NULL)
253
+ {
254
+ if (stats_allocate_counter(stats->stats,key,&counter) == S_OK)
255
+ {
256
+ stats->tbl[idx].ctr = counter;
257
+ }
258
+ else
259
+ {
260
+ /* failed to allocate counter */
261
+ }
262
+ }
263
+ }
264
+ else
265
+ {
266
+ /* table is full, can't create a new counter */
267
+ }
268
+
269
+ return counter;
270
+ }
271
+
272
+ static VALUE rbstats_get(VALUE self, VALUE rbkey)
273
+ {
274
+ struct rbstats *stats;
275
+ struct stats_counter *counter;
276
+ VALUE ret = Qnil;
277
+
278
+ stats = rbstats_get_wrapped_stats(self);
279
+ if (stats)
280
+ {
281
+ counter = rbstats_get_counter(stats, rbkey);
282
+ if (counter)
283
+ {
284
+ ret = rbctr_alloc(counter);
285
+ }
286
+ }
287
+
288
+ return ret;
289
+ }
290
+
291
+
292
+ static VALUE rbstats_get_tmr(VALUE self, VALUE rbkey)
293
+ {
294
+ struct rbstats *stats;
295
+ struct stats_counter *counter;
296
+ VALUE ret = Qnil;
297
+
298
+ stats = rbstats_get_wrapped_stats(self);
299
+ if (stats)
300
+ {
301
+ counter = rbstats_get_counter(stats, rbkey);
302
+ if (counter)
303
+ {
304
+ ret = rbtmr_alloc(counter);
305
+ }
306
+ }
307
+
308
+ return ret;
309
+ }
310
+
311
+ static VALUE rbstats_inc(VALUE self, VALUE rbkey)
312
+ {
313
+ struct rbstats *stats;
314
+ struct stats_counter *counter;
315
+ VALUE ret = Qnil;
316
+
317
+ stats = rbstats_get_wrapped_stats(self);
318
+ if (stats)
319
+ {
320
+ counter = rbstats_get_counter(stats, rbkey);
321
+ if (counter)
322
+ {
323
+ counter_increment(counter);
324
+ ret = Qtrue;
325
+ }
326
+ }
327
+
328
+ return ret;
329
+ }
330
+
331
+
332
+
333
+ static VALUE rbstats_add(VALUE self, VALUE rbkey, VALUE amt)
334
+ {
335
+ struct rbstats *stats;
336
+ struct stats_counter *counter;
337
+ VALUE ret = Qnil;
338
+
339
+ Check_Type(amt,T_FIXNUM);
340
+
341
+ stats = rbstats_get_wrapped_stats(self);
342
+ if (stats)
343
+ {
344
+ counter = rbstats_get_counter(stats, rbkey);
345
+ if (counter)
346
+ {
347
+ counter_increment_by(counter,FIX2LONG(amt));
348
+ ret = Qtrue;
349
+ }
350
+ }
351
+
352
+ return ret;
353
+ }
354
+
355
+ static VALUE rbstats_set(VALUE self, VALUE rbkey, VALUE amt)
356
+ {
357
+ struct rbstats *stats;
358
+ struct stats_counter *counter;
359
+ VALUE ret = Qnil;
360
+
361
+ Check_Type(amt,T_FIXNUM);
362
+
363
+ stats = rbstats_get_wrapped_stats(self);
364
+ if (stats)
365
+ {
366
+ counter = rbstats_get_counter(stats, rbkey);
367
+ if (counter)
368
+ {
369
+ counter_set(counter,FIX2LONG(amt));
370
+ ret = Qtrue;
371
+ }
372
+ }
373
+
374
+ return ret;
375
+ }
376
+
377
+ static VALUE rbstats_clr(VALUE self, VALUE rbkey)
378
+ {
379
+ struct rbstats *stats;
380
+ struct stats_counter *counter;
381
+ VALUE ret = Qnil;
382
+
383
+ stats = rbstats_get_wrapped_stats(self);
384
+ if (stats)
385
+ {
386
+ counter = rbstats_get_counter(stats, rbkey);
387
+ if (counter)
388
+ {
389
+ counter_clear(counter);
390
+ ret = Qtrue;
391
+ }
392
+ }
393
+
394
+ return ret;
395
+ }
396
+
397
+
398
+ /******************************************************************
399
+ *
400
+ * Ruby Counter
401
+ *
402
+ */
403
+
404
+ static VALUE rbctr_alloc(struct stats_counter *counter)
405
+ {
406
+ VALUE tdata;
407
+
408
+ tdata = Data_Wrap_Struct(ctr_class, 0, rbctr_free, counter);
409
+
410
+ return tdata;
411
+ }
412
+
413
+ VALUE rbctr_inc(VALUE self)
414
+ {
415
+ struct stats_counter *counter = NULL;
416
+
417
+ Data_Get_Struct(self, struct stats_counter, counter);
418
+ counter_increment(counter);
419
+ return self;
420
+ }
421
+
422
+ VALUE rbctr_add(VALUE self, VALUE amt)
423
+ {
424
+ struct stats_counter *counter = NULL;
425
+
426
+ Check_Type(amt,T_FIXNUM);
427
+
428
+ Data_Get_Struct(self, struct stats_counter, counter);
429
+ counter_increment_by(counter,FIX2LONG(amt));
430
+ return self;
431
+ }
432
+
433
+ VALUE rbctr_clr(VALUE self)
434
+ {
435
+ struct stats_counter *counter = NULL;
436
+
437
+ Data_Get_Struct(self, struct stats_counter, counter);
438
+ counter_clear(counter);
439
+ return self;
440
+ }
441
+
442
+ VALUE rbctr_set(VALUE self, VALUE amt)
443
+ {
444
+ struct stats_counter *counter = NULL;
445
+
446
+ Check_Type(amt,T_FIXNUM);
447
+
448
+ Data_Get_Struct(self, struct stats_counter, counter);
449
+ counter_set(counter,FIX2LONG(amt));
450
+ return self;
451
+ }
452
+
453
+ static void rbctr_free(void *p)
454
+ {
455
+ }
456
+
457
+
458
+
459
+
460
+ /******************************************************************
461
+ *
462
+ * Ruby Timer
463
+ *
464
+ */
465
+
466
+ struct timer_data
467
+ {
468
+ struct stats_counter *counter;
469
+ long long start_time;
470
+ int depth;
471
+ };
472
+
473
+ static VALUE rbtmr_alloc(struct stats_counter *counter)
474
+ {
475
+ VALUE tdata;
476
+ struct timer_data *td;
477
+
478
+ td = (struct timer_data *)malloc(sizeof(struct timer_data));
479
+ td->counter = counter;
480
+ td->start_time = 0;
481
+ td->depth = 0;
482
+
483
+ tdata = Data_Wrap_Struct(tmr_class, 0, rbtmr_free, td);
484
+
485
+ return tdata;
486
+ }
487
+
488
+ VALUE rbtmr_enter(VALUE self)
489
+ {
490
+ struct timer_data *td;
491
+
492
+ Data_Get_Struct(self, struct timer_data, td);
493
+ if (td->start_time == 0)
494
+ td->start_time = current_time();
495
+ td->depth++;
496
+
497
+ return self;
498
+ }
499
+
500
+ VALUE rbtmr_exit(VALUE self)
501
+ {
502
+ struct timer_data *td;
503
+
504
+ Data_Get_Struct(self, struct timer_data, td);
505
+ if (td->depth > 0)
506
+ td->depth--;
507
+ if (td->start_time > 0 && td->depth == 0)
508
+ {
509
+ counter_increment_by(td->counter,TIME_DELTA_TO_NANOS(td->start_time,current_time()) / 1000ll);
510
+ td->start_time = 0;
511
+ }
512
+ return self;
513
+ }
514
+
515
+ VALUE rbtmr_time(VALUE self)
516
+ {
517
+ struct timer_data *td;
518
+ long long start_time;
519
+ VALUE ret;
520
+
521
+ Data_Get_Struct(self, struct timer_data, td);
522
+ start_time = current_time();
523
+ ret = rb_yield(self);
524
+ counter_increment_by(td->counter,TIME_DELTA_TO_NANOS(start_time,current_time()) / 1000ll);
525
+ return ret;
526
+ }
527
+
528
+
529
+ static void rbtmr_free(void *p)
530
+ {
531
+ free(p);
532
+ }
533
+
534
+ void Init_stats()
535
+ {
536
+ stats_class = rb_define_class("Stats", rb_cObject);
537
+ rb_define_singleton_method(stats_class, "new", rbstats_new, 1);
538
+ rb_define_method(stats_class, "initialize", rbstats_init, 1);
539
+ rb_define_method(stats_class, "get", rbstats_get, 1);
540
+ rb_define_method(stats_class, "timer", rbstats_get_tmr, 1);
541
+ rb_define_method(stats_class, "inc", rbstats_inc, 1);
542
+ rb_define_method(stats_class, "add", rbstats_add, 2);
543
+ rb_define_method(stats_class, "set", rbstats_set, 2);
544
+ rb_define_method(stats_class, "clr", rbstats_clr, 1);
545
+
546
+ ctr_class = rb_define_class("Counter", rb_cObject);
547
+ rb_define_method(ctr_class, "inc", rbctr_inc, 0);
548
+ rb_define_method(ctr_class, "add", rbctr_add, 1);
549
+ rb_define_method(ctr_class, "set", rbctr_set, 1);
550
+ rb_define_method(ctr_class, "clr", rbctr_clr, 0);
551
+
552
+ tmr_class = rb_define_class("Timer", rb_cObject);
553
+ rb_define_method(tmr_class, "enter", rbtmr_enter, 0);
554
+ rb_define_method(tmr_class, "exit", rbtmr_exit, 0);
555
+ rb_define_method(tmr_class, "time", rbtmr_time, 0);
556
+ }
557
+