Go to the documentation of this file.
45 #define STATS_WUT_TTS 3
48 #define STATS_MGMTT_TTS 8
88 static void *stats_thread_data = NULL;
90 static time_t stats_start_time;
94 static bool stats_enabled =
true;
109 static StatsTable stats_table = { NULL, NULL, 0, 0, 0, {0 , 0}};
111 static int stats_loggers_active = 1;
113 static uint16_t counters_global_id = 0;
117 return stats_enabled;
130 StatsReleaseCounters(t->
head);
148 #if defined (UNITTESTS) || defined (FUZZ)
155 pca->
head[
id.id].
v += x;
167 #if defined (UNITTESTS) || defined (FUZZ)
174 pca->
head[
id.id].
v++;
186 #if defined(UNITTESTS) || defined(FUZZ)
193 pca->
head[
id.id].
v--;
206 #if defined (UNITTESTS) || defined (FUZZ)
213 pca->
head[
id.id].
v = x;
226 #if defined(UNITTESTS) || defined(FUZZ)
234 if ((int64_t)x > pca->
head[
id.id].
v) {
235 pca->
head[
id.id].
v = x;
242 #if defined(UNITTESTS) || defined(FUZZ)
250 pca->
head[
id.id].
v += x;
251 pca->
head[
id.id + 1].
v++;
264 if (strcmp(node->
val,
"stats") == 0) {
265 return node->head.tqh_first;
275 static void StatsInitCtxPreOutput(
void)
282 stats_enabled =
false;
288 if (gstats == NULL) {
290 "Stats enabled through legacy stats.log. "
291 "See %s/configuration/suricata-yaml.html#stats",
296 if (interval != NULL)
299 "interval: \"%s\". Resetting to %d.",
314 const char *prefix = NULL;
315 if (
SCConfGet(
"stats.decoder-events-prefix", &prefix) != 1) {
316 prefix =
"decoder.event";
323 static void StatsInitCtxPostOutput(
void)
327 time(&stats_start_time);
335 stats_loggers_active = 0;
340 SCLogWarning(
"stats are enabled but no loggers are active");
341 stats_enabled =
false;
353 static void StatsReleaseCtx(
void)
355 if (stats_ctx == NULL) {
356 SCLogDebug(
"Counter module has been disabled");
362 sts = stats_ctx->
sts;
364 while (sts != NULL) {
373 counters_global_id = 0;
382 if (stats_table.
tstats != NULL) {
384 stats_table.
tstats = NULL;
387 if (stats_table.
stats != NULL) {
389 stats_table.
stats = NULL;
391 memset(&stats_table, 0,
sizeof(stats_table));
402 static void *StatsMgmtThread(
void *arg)
415 if (stats_ctx == NULL) {
417 "StatsInitCounterApi() has to be called first");
424 int r = tm->
ThreadInit(tv_local, NULL, &stats_thread_data);
425 if (r != 0 || stats_thread_data == NULL) {
427 "ThreadInit failed");
431 SCLogDebug(
"stats_thread_data %p", &stats_thread_data);
436 struct timeval cur_timev;
437 gettimeofday(&cur_timev, NULL);
439 cond_time.tv_sec += (stats_tts);
449 if (rc == ETIMEDOUT || rc < 0) {
456 StatsOutput(tv_local);
470 "ThreadDeinit failed");
479 StatsUpdateCounterArray(&stats->
priv, &stats->
pub);
485 StatsUpdateCounterArray(&stats->
priv, &stats->
pub);
497 static void *StatsWakeupThread(
void *arg)
510 if (stats_ctx == NULL) {
512 "StatsInitCounterApi() has to be called first");
521 struct timeval cur_timev;
522 gettimeofday(&cur_timev, NULL);
534 if (rc == ETIMEDOUT || rc < 0) {
550 if (
tv->
inq != NULL) {
604 if (strcmp(
name, c->name) == 0) {
623 enum StatsType type_q, uint64_t (*Func)(
void),
const char *dname1,
const char *dname2)
630 if (
name == NULL || pctx == NULL) {
631 SCLogDebug(
"Counter name, StatsPublicThreadContext NULL");
636 while (temp != NULL) {
639 if (strcmp(
name, temp->
name) == 0) {
653 did1 = GetIdByName(pctx, dname1);
654 did2 = GetIdByName(pctx, dname2);
655 if (did1 == 0 || did2 == 0) {
678 if (strrchr(
name,
'.') != NULL) {
702 void *td = stats_thread_data;
704 if (counters_global_id == 0)
707 if (stats_table.
nstats == 0) {
710 uint32_t nstats = counters_global_id;
712 stats_table.
nstats = nstats;
714 if (stats_table.
stats == NULL) {
716 SCLogError(
"could not alloc memory for stats");
723 if (stats_table.
tstats == NULL) {
725 SCLogError(
"could not alloc memory for stats");
732 const uint16_t max_id = counters_global_id;
738 struct CountersMergeTable {
742 } merge_table[max_id];
743 memset(&merge_table, 0x00,
744 max_id *
sizeof(
struct CountersMergeTable));
746 int thread = stats_ctx->
sts_cnt - 1;
751 sts = stats_ctx->
sts;
753 while (sts != NULL) {
761 struct CountersMergeTable thread_table[max_id];
762 memset(&thread_table, 0x00,
763 max_id *
sizeof(
struct CountersMergeTable));
784 for (uint16_t i = 1; i < table_size; i++) {
793 if (pc->
Func != NULL)
794 thread_table[pc->
gid].value = pc->
Func();
797 thread_table[pc->
gid].value = thread_table_from_private[i].
v;
798 thread_table[pc->
gid].updates = thread_table_from_private[i + 1].
v;
803 SCLogDebug(
"counter %u/%u is derived from counters %u / %u", pc->
id, pc->
gid,
805 thread_table[pc->
gid].value = thread_table_from_private[pc->
did1].
v;
806 thread_table[pc->
gid].updates = thread_table_from_private[pc->
did2].
v;
810 thread_table_from_private[i].v);
812 thread_table[pc->
gid].value = thread_table_from_private[i].
v;
818 for (uint16_t c = 0; c < max_id; c++) {
819 const struct CountersMergeTable *e = &thread_table[c];
827 if (e->value > merge_table[c].value)
828 merge_table[c].value = e->value;
831 merge_table[c].value = e->value;
835 merge_table[c].value += e->value;
838 merge_table[c].updates += e->updates;
839 merge_table[c].type = e->type;
843 for (uint16_t c = 0; c < max_id; c++) {
844 const struct CountersMergeTable *e = &thread_table[c];
862 if (e->value > 0 && e->updates > 0) {
863 r->
value = (uint64_t)(e->value / e->updates);
878 for (uint16_t x = 0; x < max_id; x++) {
884 const struct CountersMergeTable *
m = &merge_table[x];
887 if (
m->value > table[x].value)
888 table[x].
value =
m->value;
892 if (
m->value > 0 &&
m->updates > 0) {
893 table[x].
value = (uint64_t)(
m->value /
m->updates);
897 table[x].
value +=
m->value;
903 if (stats_loggers_active) {
909 #ifdef BUILD_UNIX_SOCKET
912 TmEcode StatsOutputCounterSocket(json_t *cmd,
913 json_t *answer,
void *data)
915 json_t *message = NULL;
918 if (!stats_enabled) {
920 message = json_string(
"stats are disabled in the config");
925 message = json_string(
"stats not yet synchronized");
931 json_object_set_new(answer,
"message", message);
936 static void StatsLogSummary(
void)
938 if (!stats_enabled) {
945 for (uint32_t u = 0; u < st->
nstats; u++) {
947 if (
name == NULL || strcmp(
name,
"detect.alert") != 0)
963 BUG_ON(stats_ctx != NULL);
965 FatalError(
"Fatal error encountered in StatsInitCtx. Exiting...");
973 StatsInitCtxPreOutput();
978 StatsInitCtxPostOutput();
992 if (!stats_enabled) {
1001 StatsWakeupThread, 1);
1002 if (tv_wakeup == NULL) {
1009 "StatsWakeupThread");
1014 StatsMgmtThread, 1);
1015 if (tv_mgmt == NULL) {
1016 FatalError(
"TmThreadCreateMgmtThread failed");
1021 "StatsWakeupThread");
1095 #if defined (UNITTESTS) || defined (FUZZ)
1096 if (stats_ctx == NULL)
1099 BUG_ON(stats_ctx == NULL);
1101 uint16_t
id = StatsRegisterQualifiedCounter(
1124 #if defined(UNITTESTS) || defined(FUZZ)
1125 if (stats_ctx == NULL)
1128 BUG_ON(stats_ctx == NULL);
1130 uint16_t
id = StatsRegisterQualifiedCounter(
1141 static uint32_t CountersIdHashFunc(
HashTable *ht,
void *data, uint16_t datalen)
1147 for (
size_t i = 0; i <
len; i++)
1154 static char CountersIdHashCompareFunc(
void *data1, uint16_t datalen1,
1155 void *data2, uint16_t datalen2)
1160 if (t1 == NULL || t2 == NULL)
1169 static void CountersIdHashFreeFunc(
void *data)
1194 SCLogDebug(
"STATS_TYPE_DERIVE_DIV: pc %s gid %u pc->id %u id %u", pc->
name, pc->
gid,
1201 SCLogDebug(
"array_size %u memory %" PRIu64, (uint32_t)array_size,
1221 if (stats_ctx == NULL) {
1225 if (thread_name == NULL || pctx == NULL) {
1226 SCLogDebug(
"supplied argument(s) to StatsThreadRegister NULL");
1234 CountersIdHashCompareFunc,
1235 CountersIdHashFreeFunc);
1242 while (pc != NULL) {
1248 id->id = counters_global_id++;
1249 id->string = pc->
name;
1261 if (StatsThreadSetupPublic(pctx) != 0) {
1262 SCLogDebug(
"failed to setup StatsThreadSetupPublic");
1274 temp->
name = thread_name;
1277 stats_ctx->
sts = temp;
1294 static int StatsGetAllCountersArray(
1297 if (pctx == NULL ||
private == NULL)
1300 private->size = pctx->
curr_id + 1;
1303 if (private->head == NULL) {
1307 private->initialized = 1;
1313 int r = StatsGetAllCountersArray(&stats->
pub, &stats->
priv);
1318 r = StatsThreadRegister(thread_name, &stats->
pub);
1327 memset(pctx, 0x00,
sizeof(*pctx));
1333 StatsThreadInitPublic(&stats->
pub);
1348 if (pca == NULL || pctx == NULL) {
1349 SCLogDebug(
"pca or pctx is NULL inside StatsUpdateCounterArray");
1380 return pca->
head[
id.id].
v;
1402 while (
head != NULL) {
1405 StatsReleaseCounter(pc);
1418 if (pca->
head != NULL) {
1429 StatsPublicThreadContextCleanup(&stats->
pub);
1430 StatsReleasePrivateThreadContext(&stats->
priv);
1455 static int StatsTestCounterReg02(
void)
1458 StatsThreadInitPublic(&pctx);
1465 static int StatsTestCounterReg03(
void)
1468 StatsThreadInitPublic(&pctx);
1473 StatsReleaseCounters(pctx.
head);
1477 static int StatsTestCounterReg04(
void)
1480 StatsThreadInitPublic(&pctx);
1491 StatsReleaseCounters(pctx.
head);
1495 static int StatsTestGetCntArray05(
void)
1502 int r = StatsGetAllCountersArray(NULL, &
tv.
stats.
priv);
1508 static int StatsTestGetCntArray06(
void)
1522 static int StatsTestCntArraySize07(
void)
1545 static int StatsTestUpdateCounter08(
void)
1563 static int StatsTestUpdateCounter09(
void)
1589 static int StatsTestUpdateGlobalCounter10(
void)
1618 static int StatsTestCounterValues11(
void)
1657 UtRegisterTest(
"StatsTestGetCntArray05", StatsTestGetCntArray05);
1658 UtRegisterTest(
"StatsTestGetCntArray06", StatsTestGetCntArray06);
1659 UtRegisterTest(
"StatsTestCntArraySize07", StatsTestCntArraySize07);
1660 UtRegisterTest(
"StatsTestUpdateCounter08", StatsTestUpdateCounter08);
1661 UtRegisterTest(
"StatsTestUpdateCounter09", StatsTestUpdateCounter09);
1663 StatsTestUpdateGlobalCounter10);
1664 UtRegisterTest(
"StatsTestCounterValues11", StatsTestCounterValues11);
#define FROM_TIMEVAL(timev)
initialize a 'struct timespec' from a 'struct timeval'.
void StatsReleaseResources(void)
Releases the resources allotted by the Stats API.
StatsCounterGlobalId StatsRegisterGlobalCounter(const char *name, uint64_t(*Func)(void))
Registers a counter, which represents a global value.
const char * thread_name_counter_wakeup
void StatsCounterMaxUpdateI64(StatsThreadContext *stats, StatsCounterMaxId id, int64_t x)
update the value of the localmax counter
TmEcode TmThreadSpawn(ThreadVars *tv)
Spawns a thread associated with the ThreadVars instance tv.
TmEcode TmThreadSetupOptions(ThreadVars *tv)
Set the thread options (cpu affinitythread). Priority should be already set by pthread_create.
void StatsSyncCountersIfSignalled(StatsThreadContext *stats)
per thread store of counters
Holds the output interface context for the counter api.
#define SC_ATOMIC_SET(name, val)
Set the value for the atomic variable.
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
struct StatsRecord_ StatsRecord
StatsCounterId StatsRegisterCounter(const char *name, StatsThreadContext *stats)
Registers a normal, unqualified counter.
void TmThreadsSetFlag(ThreadVars *tv, uint32_t flag)
Set a thread flag.
void StatsSetupPostConfigPreOutput(void)
void TmThreadWaitForFlag(ThreadVars *tv, uint32_t flags)
Waits till the specified flag(s) is(are) set. We don't bother if the kill flag has been set or not on...
struct HtpBodyChunk_ * next
simple fifo queue for packets with mutex and cond Calling the mutex or triggering the cond is respons...
struct CountersIdType_ CountersIdType
Container to hold the counter variable.
const char * thread_name_counter_stats
#define SCSetThreadName(n)
StatsLocalCounter * copy_of_private
int SCConfGet(const char *name, const char **vptr)
Retrieve the value of a configuration node.
#define TAILQ_FOREACH(var, head, field)
int SCConfGetChildValueBool(const SCConfNode *base, const char *name, int *val)
ThreadVars * tv_root[TVT_MAX]
int SCConfValIsFalse(const char *val)
Check if a value is false.
void StatsInit(void)
Initializes the perf counter api. Things are hard coded currently. More work to be done when we imple...
#define SCMUTEX_INITIALIZER
const char * SCConfNodeLookupChildValue(const SCConfNode *node, const char *name)
Lookup the value of a child configuration node by name.
#define JSON_STATS_TOTALS
StatsCounterAvgId StatsRegisterAvgCounter(const char *name, StatsThreadContext *stats)
Registers a counter, whose value holds the average of all the values assigned to it.
void StatsCounterDecr(StatsThreadContext *stats, StatsCounterId id)
Decrements the local counter.
#define FAIL_IF_NOT(expr)
Fail a test if expression evaluates to false.
void HashTableFree(HashTable *ht)
Free a HashTable and all its contents.
TmEcode(* ThreadDeinit)(ThreadVars *, void *)
struct StatsThreadStore_ * next
const char * stats_decoder_events_prefix
void StatsCounterAvgAddI64(StatsThreadContext *stats, StatsCounterAvgId id, int64_t x)
#define PASS
Pass the test.
struct StatsCounter_ * next
void StatsSetupPostConfigPostOutput(void)
#define SCMutexUnlock(mut)
HashTable * counters_id_hash
void * HashTableLookup(HashTable *ht, void *data, uint16_t datalen)
Per thread variable structure.
StatsPublicThreadContext pub
void StatsCounterIncr(StatsThreadContext *stats, StatsCounterId id)
Increments the local counter.
int StringParseUint32(uint32_t *res, int base, size_t len, const char *str)
#define SCLogWarning(...)
Macro used to log WARNING messages.
int HashTableAdd(HashTable *ht, void *data, uint16_t datalen)
struct ThreadVars_ * next
Stats Context for a ThreadVars instance.
#define SCCtrlMutexLock(mut)
json_t * StatsToJSON(const StatsTable *st, uint8_t flags)
turn StatsTable into a json object
TmModule tmm_modules[TMM_SIZE]
uint8_t thread_setup_flags
used to hold the private version of the counters registered
#define SCCtrlCondTimedwait
int StatsSetupPrivate(StatsThreadContext *stats, const char *thread_name)
ThreadVars * TmThreadCreateMgmtThread(const char *name, void *(fn_p)(void *), int mucond)
Creates and returns the TV instance for a Management thread(MGMT). This function supports only custom...
#define SCLogInfo(...)
Macro used to log INFORMATIONAL messages.
#define SCMutexInit(mut, mutattrs)
StatsPublicThreadContext global_counter_ctx
void StatsThreadInit(StatsThreadContext *stats)
counter type for local (private) increments. For AVG counters we use 2 to track values and updates.
#define SCCtrlMutexUnlock(mut)
#define FAIL_IF(expr)
Fail a test if expression evaluates to true.
bool TmThreadsWaitForUnpause(ThreadVars *tv)
Wait for a thread to become unpaused.
const StatsCounter ** pc_array
StatsPublicThreadContext * ctx
void StatsSpawnThreads(void)
Spawns the wakeup, and the management thread used by the stats api.
void StatsSyncCounters(StatsThreadContext *stats)
int64_t StatsCounterGetLocalValue(StatsThreadContext *stats, StatsCounterId id)
Get the value of the local copy of the counter that hold this id.
TmEcode(* ThreadInit)(ThreadVars *, const void *, void **)
#define JSON_STATS_THREADS
int ConfUnixSocketIsEnable(void)
void StatsCounterSetI64(StatsThreadContext *stats, StatsCounterId id, int64_t x)
set, so overwrite, the value of the local counter
SCConfNode * SCConfGetNode(const char *name)
Get a SCConfNode by name.
int OutputStatsLoggersRegistered(void)
#define SCLogError(...)
Macro used to log ERROR messages.
StatsCounterMaxId StatsRegisterMaxCounter(const char *name, StatsThreadContext *stats)
Registers a counter, whose value holds the maximum of all the values assigned to it.
StatsCounterDeriveId StatsRegisterDeriveDivCounter(const char *name, const char *dname1, const char *dname2, StatsThreadContext *stats)
Registers a counter which tracks the result of the calculating the value of counter dname1 divided by...
HashTable * HashTableInit(uint32_t size, uint32_t(*Hash)(struct HashTable_ *, void *, uint16_t), char(*Compare)(void *, uint16_t, void *, uint16_t), void(*Free)(void *))
const char * GetDocURL(void)
struct StatsGlobalContext_ StatsGlobalContext
Holds the output interface context for the counter api.
struct StatsThreadStore_ StatsThreadStore
per thread store of counters
#define SC_ATOMIC_GET(name)
Get the value from the atomic variable.
bool stats_decoder_events
int TmThreadsCheckFlag(ThreadVars *tv, uint32_t flag)
Check if a thread flag is set.
StatsType
Different kinds of qualifier that can be used to modify the behaviour of the counter to be registered...
void StatsCounterAddI64(StatsThreadContext *stats, StatsCounterId id, int64_t x)
Adds a value of type uint64_t to the local counter.
void StatsThreadCleanup(StatsThreadContext *stats)
#define DEBUG_VALIDATE_BUG_ON(exp)
TmEcode OutputStatsLog(ThreadVars *tv, void *thread_data, StatsTable *st)
void StatsRegisterTests(void)
StatsPrivateThreadContext priv