include/cc_metric.h (90 lines of code) (raw):
/*
* ccommon - a cache common library.
* Copyright (C) 2013 Twitter, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <cc_define.h>
#include <inttypes.h>
#include <stddef.h>
#if defined CC_STATS && CC_STATS == 1
#define metric_incr_n(_metric, _delta) do { \
if ((_metric).type == METRIC_COUNTER) { \
__atomic_add_fetch(&(_metric).counter, (_delta), __ATOMIC_RELAXED);\
} else if ((_metric).type == METRIC_GAUGE) { \
__atomic_add_fetch(&(_metric).gauge, (_delta), __ATOMIC_RELAXED); \
} else { /* error */ \
} \
} while(0)
#define metric_incr(_metric) metric_incr_n(_metric, 1)
#define INCR_N(_base, _metric, _delta) do { \
if ((_base) != NULL) { \
metric_incr_n((_base)->_metric, _delta); \
} \
} while(0)
#define INCR(_base, _metric) INCR_N(_base, _metric, 1)
#define metric_decr_n(_metric, _delta) do { \
if ((_metric).type == METRIC_GAUGE) { \
__atomic_sub_fetch(&(_metric).gauge, (_delta), __ATOMIC_RELAXED); \
} else { /* error */ \
} \
} while(0)
#define metric_decr(_metric) metric_decr_n(_metric, 1)
#define DECR_N(_base, _metric, _delta) do { \
if ((_base) != NULL) { \
metric_decr_n((_base)->_metric, _delta); \
} \
} while(0)
#define DECR(_base, _metric) DECR_N(_base, _metric, 1)
/**
* Note: there's no gcc built-in atomic primitives to do a straight-up store
* atomically. But so far we only use the UPDATE_* macros for sys metrics, so
* it doesn't matter much.
* We can also use an extra variable to store the current value and use a CAS
* primitive with the value read as well as the value to set, but the extra
* variable is a headache.
* Will revisit this later.
*/
#define metric_update_val(_metric, _val) do { \
if ((_metric).type == METRIC_COUNTER) { \
(_metric).counter = (uint64_t)_val; \
} else if ((_metric).type == METRIC_GAUGE) { \
(_metric).gauge = (int64_t)_val; \
} else if ((_metric).type == METRIC_FPN) { \
(_metric).fpn = (double)_val; \
} else { /* error */ \
} \
} while(0)
#define UPDATE_VAL(_base, _metric, _val) do { \
if ((_base) != NULL) { \
metric_update_val((_base)->_metric, _val); \
} \
} while(0)
#define METRIC_DECLARE(_name, _type, _description) \
struct metric _name;
#define METRIC_INIT(_name, _type, _description) \
._name = {.name = #_name, .desc = _description, .type = _type},
#define METRIC_NAME(_name, _type, _description) \
#_name,
#else
#define INCR(_base, _metric)
#define INCR_N(_base, _metric, _delta)
#define DECR(_base, _metric)
#define DECR_N(_base, _metric, _delta)
#define UPDATE_VAL(_base, _metric, _val)
#define METRIC_DECLARE(_name, _type, _description)
#define METRIC_INIT(_name, _type, _description)
#define METRIC_NAME(_name, _type, _description)
#endif
#define METRIC_CARDINALITY(_o) sizeof(_o) / sizeof(struct metric)
typedef enum metric_type {
METRIC_COUNTER, /* supports INCR/INCR_N/UPDATE_VAL */
METRIC_GAUGE, /* supports INCR/INCR_N/DECR/DECR_N/UPDATE_VAL */
METRIC_FPN /* supports UPDATE_VAL */
} metric_type_e;
extern char *metric_type_str[3];
/* Note: anonymous union does not work with older (<gcc4.7) compilers */
/* TODO(yao): determine if we should dynamically allocate the value field
* during init. The benefit is we don't have to allocate the same amount of
* memory for different types of values, potentially wasting space. */
struct metric {
char *name;
char *desc;
metric_type_e type;
union {
uint64_t counter;
int64_t gauge;
double fpn;
};
};
void metric_reset(struct metric sarr[], unsigned int nmetric);
size_t metric_print(char *buf, size_t nbuf, char *fmt, struct metric *m);
void metric_describe_all(struct metric metrics[], unsigned int nmetric);
#ifdef __cplusplus
}
#endif