xref: /memcached-1.4.29/stats.c (revision 05ca809c)
15b304997SSteven Grimm /* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
25b304997SSteven Grimm /*
35b304997SSteven Grimm  * Detailed statistics management. For simple stats like total number of
45b304997SSteven Grimm  * "get" requests, we use inline code in memcached.c and friends, but when
55b304997SSteven Grimm  * stats detail mode is activated, the code here records more information.
65b304997SSteven Grimm  *
75b304997SSteven Grimm  * Author:
85b304997SSteven Grimm  *   Steven Grimm <[email protected]>
95b304997SSteven Grimm  */
105b304997SSteven Grimm #include "memcached.h"
115b304997SSteven Grimm #include <stdio.h>
125b304997SSteven Grimm #include <stdlib.h>
135b304997SSteven Grimm #include <string.h>
14eb75a0dfSPaul Lindner #include <assert.h>
155b304997SSteven Grimm 
165b304997SSteven Grimm /*
175b304997SSteven Grimm  * Stats are tracked on the basis of key prefixes. This is a simple
185b304997SSteven Grimm  * fixed-size hash of prefixes; we run the prefixes through the same
195b304997SSteven Grimm  * CRC function used by the cache hashtable.
205b304997SSteven Grimm  */
215b304997SSteven Grimm typedef struct _prefix_stats PREFIX_STATS;
225b304997SSteven Grimm struct _prefix_stats {
235b304997SSteven Grimm     char         *prefix;
24eb75a0dfSPaul Lindner     size_t        prefix_len;
25eb75a0dfSPaul Lindner     uint64_t      num_gets;
26eb75a0dfSPaul Lindner     uint64_t      num_sets;
27eb75a0dfSPaul Lindner     uint64_t      num_deletes;
28eb75a0dfSPaul Lindner     uint64_t      num_hits;
295b304997SSteven Grimm     PREFIX_STATS *next;
305b304997SSteven Grimm };
315b304997SSteven Grimm 
325b304997SSteven Grimm #define PREFIX_HASH_SIZE 256
33eb75a0dfSPaul Lindner 
345b304997SSteven Grimm static PREFIX_STATS *prefix_stats[PREFIX_HASH_SIZE];
355b304997SSteven Grimm static int num_prefixes = 0;
365b304997SSteven Grimm static int total_prefix_size = 0;
375b304997SSteven Grimm 
stats_prefix_init()385b304997SSteven Grimm void stats_prefix_init() {
395b304997SSteven Grimm     memset(prefix_stats, 0, sizeof(prefix_stats));
405b304997SSteven Grimm }
415b304997SSteven Grimm 
425b304997SSteven Grimm /*
435b304997SSteven Grimm  * Cleans up all our previously collected stats. NOTE: the stats lock is
445b304997SSteven Grimm  * assumed to be held when this is called.
455b304997SSteven Grimm  */
stats_prefix_clear()465b304997SSteven Grimm void stats_prefix_clear() {
475b304997SSteven Grimm     int i;
485b304997SSteven Grimm 
495b304997SSteven Grimm     for (i = 0; i < PREFIX_HASH_SIZE; i++) {
50eb75a0dfSPaul Lindner         PREFIX_STATS *cur, *next;
515b304997SSteven Grimm         for (cur = prefix_stats[i]; cur != NULL; cur = next) {
525b304997SSteven Grimm             next = cur->next;
535b304997SSteven Grimm             free(cur->prefix);
545b304997SSteven Grimm             free(cur);
555b304997SSteven Grimm         }
565b304997SSteven Grimm         prefix_stats[i] = NULL;
575b304997SSteven Grimm     }
585b304997SSteven Grimm     num_prefixes = 0;
595b304997SSteven Grimm     total_prefix_size = 0;
605b304997SSteven Grimm }
615b304997SSteven Grimm 
625b304997SSteven Grimm /*
635b304997SSteven Grimm  * Returns the stats structure for a prefix, creating it if it's not already
645b304997SSteven Grimm  * in the list.
655b304997SSteven Grimm  */
66eb75a0dfSPaul Lindner /*@null@*/
stats_prefix_find(const char * key,const size_t nkey)6746654a83STrond Norbye static PREFIX_STATS *stats_prefix_find(const char *key, const size_t nkey) {
685b304997SSteven Grimm     PREFIX_STATS *pfs;
69eb75a0dfSPaul Lindner     uint32_t hashval;
70eb75a0dfSPaul Lindner     size_t length;
71b8ff9183SChang Song     bool bailout = true;
72eb75a0dfSPaul Lindner 
73eb75a0dfSPaul Lindner     assert(key != NULL);
745b304997SSteven Grimm 
75b8ff9183SChang Song     for (length = 0; length < nkey && key[length] != '\0'; length++) {
76b8ff9183SChang Song         if (key[length] == settings.prefix_delimiter) {
77b8ff9183SChang Song             bailout = false;
785b304997SSteven Grimm             break;
79b8ff9183SChang Song         }
80b8ff9183SChang Song     }
81b8ff9183SChang Song 
82b8ff9183SChang Song     if (bailout) {
83b8ff9183SChang Song         return NULL;
84b8ff9183SChang Song     }
855b304997SSteven Grimm 
86*05ca809cSdormando     hashval = hash(key, length) % PREFIX_HASH_SIZE;
875b304997SSteven Grimm 
885b304997SSteven Grimm     for (pfs = prefix_stats[hashval]; NULL != pfs; pfs = pfs->next) {
89eb75a0dfSPaul Lindner         if (strncmp(pfs->prefix, key, length) == 0)
905b304997SSteven Grimm             return pfs;
915b304997SSteven Grimm     }
925b304997SSteven Grimm 
935b304997SSteven Grimm     pfs = calloc(sizeof(PREFIX_STATS), 1);
945b304997SSteven Grimm     if (NULL == pfs) {
955b304997SSteven Grimm         perror("Can't allocate space for stats structure: calloc");
965b304997SSteven Grimm         return NULL;
975b304997SSteven Grimm     }
985b304997SSteven Grimm 
995b304997SSteven Grimm     pfs->prefix = malloc(length + 1);
1005b304997SSteven Grimm     if (NULL == pfs->prefix) {
1015b304997SSteven Grimm         perror("Can't allocate space for copy of prefix: malloc");
1025b304997SSteven Grimm         free(pfs);
1035b304997SSteven Grimm         return NULL;
1045b304997SSteven Grimm     }
1055b304997SSteven Grimm 
1065b304997SSteven Grimm     strncpy(pfs->prefix, key, length);
10744ef96eeSPaul Lindner     pfs->prefix[length] = '\0';      /* because strncpy() sucks */
1085b304997SSteven Grimm     pfs->prefix_len = length;
1095b304997SSteven Grimm 
1105b304997SSteven Grimm     pfs->next = prefix_stats[hashval];
1115b304997SSteven Grimm     prefix_stats[hashval] = pfs;
1125b304997SSteven Grimm 
1135b304997SSteven Grimm     num_prefixes++;
1145b304997SSteven Grimm     total_prefix_size += length;
1155b304997SSteven Grimm 
1165b304997SSteven Grimm     return pfs;
1175b304997SSteven Grimm }
1185b304997SSteven Grimm 
1195b304997SSteven Grimm /*
1205b304997SSteven Grimm  * Records a "get" of a key.
1215b304997SSteven Grimm  */
stats_prefix_record_get(const char * key,const size_t nkey,const bool is_hit)12246654a83STrond Norbye void stats_prefix_record_get(const char *key, const size_t nkey, const bool is_hit) {
1235b304997SSteven Grimm     PREFIX_STATS *pfs;
1245b304997SSteven Grimm 
1255b304997SSteven Grimm     STATS_LOCK();
12646654a83STrond Norbye     pfs = stats_prefix_find(key, nkey);
1275b304997SSteven Grimm     if (NULL != pfs) {
1285b304997SSteven Grimm         pfs->num_gets++;
1295b304997SSteven Grimm         if (is_hit) {
1305b304997SSteven Grimm             pfs->num_hits++;
1315b304997SSteven Grimm         }
1325b304997SSteven Grimm     }
1335b304997SSteven Grimm     STATS_UNLOCK();
1345b304997SSteven Grimm }
1355b304997SSteven Grimm 
1365b304997SSteven Grimm /*
1375b304997SSteven Grimm  * Records a "delete" of a key.
1385b304997SSteven Grimm  */
stats_prefix_record_delete(const char * key,const size_t nkey)13946654a83STrond Norbye void stats_prefix_record_delete(const char *key, const size_t nkey) {
1405b304997SSteven Grimm     PREFIX_STATS *pfs;
1415b304997SSteven Grimm 
1425b304997SSteven Grimm     STATS_LOCK();
14346654a83STrond Norbye     pfs = stats_prefix_find(key, nkey);
1445b304997SSteven Grimm     if (NULL != pfs) {
1455b304997SSteven Grimm         pfs->num_deletes++;
1465b304997SSteven Grimm     }
1475b304997SSteven Grimm     STATS_UNLOCK();
1485b304997SSteven Grimm }
1495b304997SSteven Grimm 
1505b304997SSteven Grimm /*
1515b304997SSteven Grimm  * Records a "set" of a key.
1525b304997SSteven Grimm  */
stats_prefix_record_set(const char * key,const size_t nkey)15346654a83STrond Norbye void stats_prefix_record_set(const char *key, const size_t nkey) {
1545b304997SSteven Grimm     PREFIX_STATS *pfs;
1555b304997SSteven Grimm 
1565b304997SSteven Grimm     STATS_LOCK();
15746654a83STrond Norbye     pfs = stats_prefix_find(key, nkey);
1585b304997SSteven Grimm     if (NULL != pfs) {
1595b304997SSteven Grimm         pfs->num_sets++;
1605b304997SSteven Grimm     }
1615b304997SSteven Grimm     STATS_UNLOCK();
1625b304997SSteven Grimm }
1635b304997SSteven Grimm 
1645b304997SSteven Grimm /*
1655b304997SSteven Grimm  * Returns stats in textual form suitable for writing to a client.
1665b304997SSteven Grimm  */
167eb75a0dfSPaul Lindner /*@null@*/
stats_prefix_dump(int * length)1685b304997SSteven Grimm char *stats_prefix_dump(int *length) {
169eb75a0dfSPaul Lindner     const char *format = "PREFIX %s get %llu hit %llu set %llu del %llu\r\n";
1705b304997SSteven Grimm     PREFIX_STATS *pfs;
1715b304997SSteven Grimm     char *buf;
1725b304997SSteven Grimm     int i, pos;
173a4106cf3SDustin Sallings     size_t size = 0, written = 0, total_written = 0;
1745b304997SSteven Grimm 
1755b304997SSteven Grimm     /*
1765b304997SSteven Grimm      * Figure out how big the buffer needs to be. This is the sum of the
1775b304997SSteven Grimm      * lengths of the prefixes themselves, plus the size of one copy of
1785b304997SSteven Grimm      * the per-prefix output with 20-digit values for all the counts,
1795b304997SSteven Grimm      * plus space for the "END" at the end.
1805b304997SSteven Grimm      */
1815b304997SSteven Grimm     STATS_LOCK();
1825b304997SSteven Grimm     size = strlen(format) + total_prefix_size +
1835b304997SSteven Grimm            num_prefixes * (strlen(format) - 2 /* %s */
1845b304997SSteven Grimm                            + 4 * (20 - 4)) /* %llu replaced by 20-digit num */
1855b304997SSteven Grimm                            + sizeof("END\r\n");
1865b304997SSteven Grimm     buf = malloc(size);
1875b304997SSteven Grimm     if (NULL == buf) {
1885b304997SSteven Grimm         perror("Can't allocate stats response: malloc");
1895b304997SSteven Grimm         STATS_UNLOCK();
1905b304997SSteven Grimm         return NULL;
1915b304997SSteven Grimm     }
1925b304997SSteven Grimm 
1935b304997SSteven Grimm     pos = 0;
1945b304997SSteven Grimm     for (i = 0; i < PREFIX_HASH_SIZE; i++) {
1955b304997SSteven Grimm         for (pfs = prefix_stats[i]; NULL != pfs; pfs = pfs->next) {
196a4106cf3SDustin Sallings             written = snprintf(buf + pos, size-pos, format,
1975b304997SSteven Grimm                            pfs->prefix, pfs->num_gets, pfs->num_hits,
1985b304997SSteven Grimm                            pfs->num_sets, pfs->num_deletes);
199a4106cf3SDustin Sallings             pos += written;
200a4106cf3SDustin Sallings             total_written += written;
201a4106cf3SDustin Sallings             assert(total_written < size);
2025b304997SSteven Grimm         }
2035b304997SSteven Grimm     }
2045b304997SSteven Grimm 
2055b304997SSteven Grimm     STATS_UNLOCK();
206eb75a0dfSPaul Lindner     memcpy(buf + pos, "END\r\n", 6);
2075b304997SSteven Grimm 
2085b304997SSteven Grimm     *length = pos + 5;
2095b304997SSteven Grimm     return buf;
2105b304997SSteven Grimm }
2115b304997SSteven Grimm 
2125b304997SSteven Grimm 
2135b304997SSteven Grimm #ifdef UNIT_TEST
2145b304997SSteven Grimm 
2155b304997SSteven Grimm /****************************************************************************
2165b304997SSteven Grimm       To run unit tests, compile with $(CC) -DUNIT_TEST stats.c assoc.o
2175b304997SSteven Grimm       (need assoc.o to get the hash() function).
2185b304997SSteven Grimm ****************************************************************************/
2195b304997SSteven Grimm 
2205b304997SSteven Grimm struct settings settings;
2215b304997SSteven Grimm 
2225b304997SSteven Grimm static char *current_test = "";
2235b304997SSteven Grimm static int test_count = 0;
2245b304997SSteven Grimm static int fail_count = 0;
2255b304997SSteven Grimm 
fail(char * what)2265b304997SSteven Grimm static void fail(char *what) { printf("\tFAIL: %s\n", what); fflush(stdout); fail_count++; }
test_equals_int(char * what,int a,int b)2275b304997SSteven Grimm static void test_equals_int(char *what, int a, int b) { test_count++; if (a != b) fail(what); }
test_equals_ptr(char * what,void * a,void * b)2285b304997SSteven Grimm static void test_equals_ptr(char *what, void *a, void *b) { test_count++; if (a != b) fail(what); }
test_equals_str(char * what,const char * a,const char * b)2295b304997SSteven Grimm static void test_equals_str(char *what, const char *a, const char *b) { test_count++; if (strcmp(a, b)) fail(what); }
test_equals_ull(char * what,uint64_t a,uint64_t b)230eb75a0dfSPaul Lindner static void test_equals_ull(char *what, uint64_t a, uint64_t b) { test_count++; if (a != b) fail(what); }
test_notequals_ptr(char * what,void * a,void * b)2315b304997SSteven Grimm static void test_notequals_ptr(char *what, void *a, void *b) { test_count++; if (a == b) fail(what); }
test_notnull_ptr(char * what,void * a)2325b304997SSteven Grimm static void test_notnull_ptr(char *what, void *a) { test_count++; if (NULL == a) fail(what); }
2335b304997SSteven Grimm 
test_prefix_find()2345b304997SSteven Grimm static void test_prefix_find() {
2355b304997SSteven Grimm     PREFIX_STATS *pfs1, *pfs2;
2365b304997SSteven Grimm 
2375b304997SSteven Grimm     pfs1 = stats_prefix_find("abc");
2385b304997SSteven Grimm     test_notnull_ptr("initial prefix find", pfs1);
2395b304997SSteven Grimm     test_equals_ull("request counts", 0ULL,
2405b304997SSteven Grimm         pfs1->num_gets + pfs1->num_sets + pfs1->num_deletes + pfs1->num_hits);
2415b304997SSteven Grimm     pfs2 = stats_prefix_find("abc");
2425b304997SSteven Grimm     test_equals_ptr("find of same prefix", pfs1, pfs2);
2435b304997SSteven Grimm     pfs2 = stats_prefix_find("abc:");
2445b304997SSteven Grimm     test_equals_ptr("find of same prefix, ignoring delimiter", pfs1, pfs2);
2455b304997SSteven Grimm     pfs2 = stats_prefix_find("abc:d");
2465b304997SSteven Grimm     test_equals_ptr("find of same prefix, ignoring extra chars", pfs1, pfs2);
2475b304997SSteven Grimm     pfs2 = stats_prefix_find("xyz123");
2485b304997SSteven Grimm     test_notequals_ptr("find of different prefix", pfs1, pfs2);
2495b304997SSteven Grimm     pfs2 = stats_prefix_find("ab:");
2505b304997SSteven Grimm     test_notequals_ptr("find of shorter prefix", pfs1, pfs2);
2515b304997SSteven Grimm }
2525b304997SSteven Grimm 
test_prefix_record_get()2535b304997SSteven Grimm static void test_prefix_record_get() {
2545b304997SSteven Grimm     PREFIX_STATS *pfs;
2555b304997SSteven Grimm 
2565b304997SSteven Grimm     stats_prefix_record_get("abc:123", 0);
2575b304997SSteven Grimm     pfs = stats_prefix_find("abc:123");
2585b304997SSteven Grimm     test_equals_ull("get count after get #1", 1, pfs->num_gets);
2595b304997SSteven Grimm     test_equals_ull("hit count after get #1", 0, pfs->num_hits);
2605b304997SSteven Grimm     stats_prefix_record_get("abc:456", 0);
2615b304997SSteven Grimm     test_equals_ull("get count after get #2", 2, pfs->num_gets);
2625b304997SSteven Grimm     test_equals_ull("hit count after get #2", 0, pfs->num_hits);
2635b304997SSteven Grimm     stats_prefix_record_get("abc:456", 1);
2645b304997SSteven Grimm     test_equals_ull("get count after get #3", 3, pfs->num_gets);
2655b304997SSteven Grimm     test_equals_ull("hit count after get #3", 1, pfs->num_hits);
2665b304997SSteven Grimm     stats_prefix_record_get("def:", 1);
2675b304997SSteven Grimm     test_equals_ull("get count after get #4", 3, pfs->num_gets);
2685b304997SSteven Grimm     test_equals_ull("hit count after get #4", 1, pfs->num_hits);
2695b304997SSteven Grimm }
2705b304997SSteven Grimm 
test_prefix_record_delete()2715b304997SSteven Grimm static void test_prefix_record_delete() {
2725b304997SSteven Grimm     PREFIX_STATS *pfs;
2735b304997SSteven Grimm 
2745b304997SSteven Grimm     stats_prefix_record_delete("abc:123");
2755b304997SSteven Grimm     pfs = stats_prefix_find("abc:123");
2765b304997SSteven Grimm     test_equals_ull("get count after delete #1", 0, pfs->num_gets);
2775b304997SSteven Grimm     test_equals_ull("hit count after delete #1", 0, pfs->num_hits);
2785b304997SSteven Grimm     test_equals_ull("delete count after delete #1", 1, pfs->num_deletes);
2795b304997SSteven Grimm     test_equals_ull("set count after delete #1", 0, pfs->num_sets);
2805b304997SSteven Grimm     stats_prefix_record_delete("def:");
2815b304997SSteven Grimm     test_equals_ull("delete count after delete #2", 1, pfs->num_deletes);
2825b304997SSteven Grimm }
2835b304997SSteven Grimm 
test_prefix_record_set()2845b304997SSteven Grimm static void test_prefix_record_set() {
2855b304997SSteven Grimm     PREFIX_STATS *pfs;
2865b304997SSteven Grimm 
2875b304997SSteven Grimm     stats_prefix_record_set("abc:123");
2885b304997SSteven Grimm     pfs = stats_prefix_find("abc:123");
2895b304997SSteven Grimm     test_equals_ull("get count after set #1", 0, pfs->num_gets);
2905b304997SSteven Grimm     test_equals_ull("hit count after set #1", 0, pfs->num_hits);
2915b304997SSteven Grimm     test_equals_ull("delete count after set #1", 0, pfs->num_deletes);
2925b304997SSteven Grimm     test_equals_ull("set count after set #1", 1, pfs->num_sets);
2935b304997SSteven Grimm     stats_prefix_record_delete("def:");
2945b304997SSteven Grimm     test_equals_ull("set count after set #2", 1, pfs->num_sets);
2955b304997SSteven Grimm }
2965b304997SSteven Grimm 
test_prefix_dump()2975b304997SSteven Grimm static void test_prefix_dump() {
298*05ca809cSdormando     int hashval = hash("abc", 3) % PREFIX_HASH_SIZE;
2995b304997SSteven Grimm     char tmp[500];
3005b304997SSteven Grimm     char *expected;
3015b304997SSteven Grimm     int keynum;
3025b304997SSteven Grimm     int length;
3035b304997SSteven Grimm 
3045b304997SSteven Grimm     test_equals_str("empty stats", "END\r\n", stats_prefix_dump(&length));
3055b304997SSteven Grimm     test_equals_int("empty stats length", 5, length);
3065b304997SSteven Grimm     stats_prefix_record_set("abc:123");
3075b304997SSteven Grimm     expected = "PREFIX abc get 0 hit 0 set 1 del 0\r\nEND\r\n";
3085b304997SSteven Grimm     test_equals_str("stats after set", expected, stats_prefix_dump(&length));
3095b304997SSteven Grimm     test_equals_int("stats length after set", strlen(expected), length);
3105b304997SSteven Grimm     stats_prefix_record_get("abc:123", 0);
3115b304997SSteven Grimm     expected = "PREFIX abc get 1 hit 0 set 1 del 0\r\nEND\r\n";
3125b304997SSteven Grimm     test_equals_str("stats after get #1", expected, stats_prefix_dump(&length));
3135b304997SSteven Grimm     test_equals_int("stats length after get #1", strlen(expected), length);
3145b304997SSteven Grimm     stats_prefix_record_get("abc:123", 1);
3155b304997SSteven Grimm     expected = "PREFIX abc get 2 hit 1 set 1 del 0\r\nEND\r\n";
3165b304997SSteven Grimm     test_equals_str("stats after get #2", expected, stats_prefix_dump(&length));
3175b304997SSteven Grimm     test_equals_int("stats length after get #2", strlen(expected), length);
3185b304997SSteven Grimm     stats_prefix_record_delete("abc:123");
3195b304997SSteven Grimm     expected = "PREFIX abc get 2 hit 1 set 1 del 1\r\nEND\r\n";
3205b304997SSteven Grimm     test_equals_str("stats after del #1", expected, stats_prefix_dump(&length));
3215b304997SSteven Grimm     test_equals_int("stats length after del #1", strlen(expected), length);
3225b304997SSteven Grimm 
3235b304997SSteven Grimm     /* The order of results might change if we switch hash functions. */
3245b304997SSteven Grimm     stats_prefix_record_delete("def:123");
3255b304997SSteven Grimm     expected = "PREFIX abc get 2 hit 1 set 1 del 1\r\n"
3265b304997SSteven Grimm                "PREFIX def get 0 hit 0 set 0 del 1\r\n"
3275b304997SSteven Grimm                "END\r\n";
3285b304997SSteven Grimm     test_equals_str("stats after del #2", expected, stats_prefix_dump(&length));
3295b304997SSteven Grimm     test_equals_int("stats length after del #2", strlen(expected), length);
3305b304997SSteven Grimm 
3315b304997SSteven Grimm     /* Find a key that hashes to the same bucket as "abc" */
3325b304997SSteven Grimm     for (keynum = 0; keynum < PREFIX_HASH_SIZE * 100; keynum++) {
33388a68689SDustin Sallings         snprintf(tmp, sizeof(tmp), "%d", keynum);
334*05ca809cSdormando         if (hashval == hash(tmp, strlen(tmp)) % PREFIX_HASH_SIZE) {
3355b304997SSteven Grimm             break;
3365b304997SSteven Grimm         }
3375b304997SSteven Grimm     }
3385b304997SSteven Grimm     stats_prefix_record_set(tmp);
33988a68689SDustin Sallings     snprintf(tmp, sizeof(tmp),
34088a68689SDustin Sallings              "PREFIX %d get 0 hit 0 set 1 del 0\r\n"
3415b304997SSteven Grimm              "PREFIX abc get 2 hit 1 set 1 del 1\r\n"
3425b304997SSteven Grimm              "PREFIX def get 0 hit 0 set 0 del 1\r\n"
3435b304997SSteven Grimm              "END\r\n", keynum);
3445b304997SSteven Grimm     test_equals_str("stats with two stats in one bucket",
3455b304997SSteven Grimm                     tmp, stats_prefix_dump(&length));
3465b304997SSteven Grimm     test_equals_int("stats length with two stats in one bucket",
3475b304997SSteven Grimm                     strlen(tmp), length);
3485b304997SSteven Grimm }
3495b304997SSteven Grimm 
run_test(char * what,void (* func)(void))3505b304997SSteven Grimm static void run_test(char *what, void (*func)(void)) {
3515b304997SSteven Grimm     current_test = what;
3525b304997SSteven Grimm     test_count = fail_count = 0;
3535b304997SSteven Grimm     puts(what);
3545b304997SSteven Grimm     fflush(stdout);
3555b304997SSteven Grimm 
3565b304997SSteven Grimm     stats_prefix_clear();
3575b304997SSteven Grimm     (func)();
3585b304997SSteven Grimm     printf("\t%d / %d pass\n", (test_count - fail_count), test_count);
3595b304997SSteven Grimm }
3605b304997SSteven Grimm 
3615b304997SSteven Grimm /* In case we're compiled in thread mode */
mt_stats_lock()3625b304997SSteven Grimm void mt_stats_lock() { }
mt_stats_unlock()3635b304997SSteven Grimm void mt_stats_unlock() { }
3645b304997SSteven Grimm 
main(int argc,char ** argv)3655b304997SSteven Grimm main(int argc, char **argv) {
3665b304997SSteven Grimm     stats_prefix_init();
3675b304997SSteven Grimm     settings.prefix_delimiter = ':';
3685b304997SSteven Grimm     run_test("stats_prefix_find", test_prefix_find);
3695b304997SSteven Grimm     run_test("stats_prefix_record_get", test_prefix_record_get);
3705b304997SSteven Grimm     run_test("stats_prefix_record_delete", test_prefix_record_delete);
3715b304997SSteven Grimm     run_test("stats_prefix_record_set", test_prefix_record_set);
3725b304997SSteven Grimm     run_test("stats_prefix_dump", test_prefix_dump);
3735b304997SSteven Grimm }
3745b304997SSteven Grimm 
3755b304997SSteven Grimm #endif
376