Go to the documentation of this file.
45 #define STATS_WUT_TTS 3
48 #define STATS_MGMTT_TTS 8
90 static void *stats_thread_data = NULL;
92 static time_t stats_start_time;
96 static bool stats_enabled =
true;
111 static StatsTable stats_table = { NULL, NULL, 0, 0, 0, {0 , 0}};
113 static int stats_loggers_active = 1;
115 static uint16_t counters_global_id = 0;
119 return stats_enabled;
132 StatsReleaseCounters(t->
head);
150 #if defined (UNITTESTS) || defined (FUZZ)
157 pca->
head[
id.id].
v += x;
169 #if defined (UNITTESTS) || defined (FUZZ)
176 pca->
head[
id.id].
v++;
188 #if defined(UNITTESTS) || defined(FUZZ)
195 pca->
head[
id.id].
v--;
208 #if defined (UNITTESTS) || defined (FUZZ)
215 pca->
head[
id.id].
v = x;
228 #if defined(UNITTESTS) || defined(FUZZ)
236 if ((int64_t)x > pca->
head[
id.id].
v) {
237 pca->
head[
id.id].
v = x;
244 #if defined(UNITTESTS) || defined(FUZZ)
252 pca->
head[
id.id].
v += x;
253 pca->
head[
id.id + 1].
v++;
266 if (strcmp(node->
val,
"stats") == 0) {
267 return node->head.tqh_first;
277 static void StatsInitCtxPreOutput(
void)
284 stats_enabled =
false;
290 if (gstats == NULL) {
292 "Stats enabled through legacy stats.log. "
293 "See %s/configuration/suricata-yaml.html#stats",
298 if (interval != NULL)
301 "interval: \"%s\". Resetting to %d.",
316 const char *prefix = NULL;
317 if (
SCConfGet(
"stats.decoder-events-prefix", &prefix) != 1) {
318 prefix =
"decoder.event";
325 static void StatsInitCtxPostOutput(
void)
329 time(&stats_start_time);
337 stats_loggers_active = 0;
342 SCLogWarning(
"stats are enabled but no loggers are active");
343 stats_enabled =
false;
355 static void StatsReleaseCtx(
void)
357 if (stats_ctx == NULL) {
358 SCLogDebug(
"Counter module has been disabled");
364 sts = stats_ctx->
sts;
366 while (sts != NULL) {
375 counters_global_id = 0;
384 if (stats_table.
tstats != NULL) {
386 stats_table.
tstats = NULL;
389 if (stats_table.
stats != NULL) {
391 stats_table.
stats = NULL;
393 memset(&stats_table, 0,
sizeof(stats_table));
404 static void *StatsMgmtThread(
void *arg)
417 if (stats_ctx == NULL) {
419 "StatsInitCounterApi() has to be called first");
426 int r = tm->
ThreadInit(tv_local, NULL, &stats_thread_data);
427 if (r != 0 || stats_thread_data == NULL) {
429 "ThreadInit failed");
433 SCLogDebug(
"stats_thread_data %p", &stats_thread_data);
438 struct timeval cur_timev;
439 gettimeofday(&cur_timev, NULL);
441 cond_time.tv_sec += (stats_tts);
451 if (rc == ETIMEDOUT || rc < 0) {
458 StatsOutput(tv_local);
472 "ThreadDeinit failed");
481 StatsUpdateCounterArray(&stats->
priv, &stats->
pub);
487 StatsUpdateCounterArray(&stats->
priv, &stats->
pub);
499 static void *StatsWakeupThread(
void *arg)
512 if (stats_ctx == NULL) {
514 "StatsInitCounterApi() has to be called first");
523 struct timeval cur_timev;
524 gettimeofday(&cur_timev, NULL);
536 if (rc == ETIMEDOUT || rc < 0) {
552 if (
tv->
inq != NULL) {
606 if (strcmp(
name, c->name) == 0) {
625 enum StatsType type_q, uint64_t (*Func)(
void),
const char *dname1,
const char *dname2)
632 if (
name == NULL || pctx == NULL) {
633 SCLogDebug(
"Counter name, StatsPublicThreadContext NULL");
638 while (temp != NULL) {
641 if (strcmp(
name, temp->
name) == 0) {
655 did1 = GetIdByName(pctx, dname1);
656 did2 = GetIdByName(pctx, dname2);
657 if (did1 == 0 || did2 == 0) {
680 if (strrchr(
name,
'.') != NULL) {
704 void *td = stats_thread_data;
706 if (counters_global_id == 0)
709 if (stats_table.
nstats == 0) {
712 uint32_t nstats = counters_global_id;
714 stats_table.
nstats = nstats;
716 if (stats_table.
stats == NULL) {
718 SCLogError(
"could not alloc memory for stats");
725 if (stats_table.
tstats == NULL) {
727 SCLogError(
"could not alloc memory for stats");
734 const uint16_t max_id = counters_global_id;
740 struct CountersMergeTable {
744 } merge_table[max_id];
745 memset(&merge_table, 0x00,
746 max_id *
sizeof(
struct CountersMergeTable));
748 int thread = stats_ctx->
sts_cnt - 1;
753 sts = stats_ctx->
sts;
755 while (sts != NULL) {
763 struct CountersMergeTable thread_table[max_id];
764 memset(&thread_table, 0x00,
765 max_id *
sizeof(
struct CountersMergeTable));
786 for (uint16_t i = 1; i < table_size; i++) {
795 if (pc->
Func != NULL)
796 thread_table[pc->
gid].value = pc->
Func();
799 thread_table[pc->
gid].value = thread_table_from_private[i].
v;
800 thread_table[pc->
gid].updates = thread_table_from_private[i + 1].
v;
805 SCLogDebug(
"counter %u/%u is derived from counters %u / %u", pc->
id, pc->
gid,
807 thread_table[pc->
gid].value = thread_table_from_private[pc->
did1].
v;
808 thread_table[pc->
gid].updates = thread_table_from_private[pc->
did2].
v;
812 thread_table_from_private[i].v);
814 thread_table[pc->
gid].value = thread_table_from_private[i].
v;
820 for (uint16_t c = 0; c < max_id; c++) {
821 const struct CountersMergeTable *e = &thread_table[c];
829 if (e->value > merge_table[c].value)
830 merge_table[c].value = e->value;
833 merge_table[c].value = e->value;
837 merge_table[c].value += e->value;
840 merge_table[c].updates += e->updates;
841 merge_table[c].type = e->type;
845 for (uint16_t c = 0; c < max_id; c++) {
846 const struct CountersMergeTable *e = &thread_table[c];
864 if (e->value > 0 && e->updates > 0) {
865 r->
value = (uint64_t)(e->value / e->updates);
880 for (uint16_t x = 0; x < max_id; x++) {
886 const struct CountersMergeTable *
m = &merge_table[x];
889 if (
m->value > table[x].value)
890 table[x].
value =
m->value;
894 if (
m->value > 0 &&
m->updates > 0) {
895 table[x].
value = (uint64_t)(
m->value /
m->updates);
899 table[x].
value +=
m->value;
905 if (stats_loggers_active) {
911 #ifdef BUILD_UNIX_SOCKET
914 TmEcode StatsOutputCounterSocket(json_t *cmd,
915 json_t *answer,
void *data)
917 json_t *message = NULL;
920 if (!stats_enabled) {
922 message = json_string(
"stats are disabled in the config");
927 message = json_string(
"stats not yet synchronized");
933 json_object_set_new(answer,
"message", message);
938 static void StatsLogSummary(
void)
940 if (!stats_enabled) {
947 for (uint32_t u = 0; u < st->
nstats; u++) {
949 if (
name == NULL || strcmp(
name,
"detect.alert") != 0)
965 BUG_ON(stats_ctx != NULL);
967 FatalError(
"Fatal error encountered in StatsInitCtx. Exiting...");
975 StatsInitCtxPreOutput();
980 StatsInitCtxPostOutput();
994 if (!stats_enabled) {
1003 StatsWakeupThread, 1);
1004 if (tv_wakeup == NULL) {
1011 "StatsWakeupThread");
1016 StatsMgmtThread, 1);
1017 if (tv_mgmt == NULL) {
1018 FatalError(
"TmThreadCreateMgmtThread failed");
1023 "StatsWakeupThread");
1097 #if defined (UNITTESTS) || defined (FUZZ)
1098 if (stats_ctx == NULL)
1101 BUG_ON(stats_ctx == NULL);
1103 uint16_t
id = StatsRegisterQualifiedCounter(
1126 #if defined(UNITTESTS) || defined(FUZZ)
1127 if (stats_ctx == NULL)
1130 BUG_ON(stats_ctx == NULL);
1132 uint16_t
id = StatsRegisterQualifiedCounter(
1143 static uint32_t CountersIdHashFunc(
HashTable *ht,
void *data, uint16_t datalen)
1149 for (
size_t i = 0; i <
len; i++)
1156 static char CountersIdHashCompareFunc(
void *data1, uint16_t datalen1,
1157 void *data2, uint16_t datalen2)
1162 if (t1 == NULL || t2 == NULL)
1171 static void CountersIdHashFreeFunc(
void *data)
1196 SCLogDebug(
"STATS_TYPE_DERIVE_DIV: pc %s gid %u pc->id %u id %u", pc->
name, pc->
gid,
1203 SCLogDebug(
"array_size %u memory %" PRIu64, (uint32_t)array_size,
1223 if (stats_ctx == NULL) {
1227 if (thread_name == NULL || pctx == NULL) {
1228 SCLogDebug(
"supplied argument(s) to StatsThreadRegister NULL");
1236 CountersIdHashCompareFunc,
1237 CountersIdHashFreeFunc);
1244 while (pc != NULL) {
1250 id->id = counters_global_id++;
1251 id->string = pc->
name;
1263 if (StatsThreadSetupPublic(pctx) != 0) {
1264 SCLogDebug(
"failed to setup StatsThreadSetupPublic");
1276 temp->
name = thread_name;
1279 stats_ctx->
sts = temp;
1296 static int StatsGetAllCountersArray(
1299 if (pctx == NULL ||
private == NULL)
1302 private->size = pctx->
curr_id + 1;
1305 if (private->head == NULL) {
1309 private->initialized = 1;
1315 int r = StatsGetAllCountersArray(&stats->
pub, &stats->
priv);
1320 r = StatsThreadRegister(thread_name, &stats->
pub);
1329 memset(pctx, 0x00,
sizeof(*pctx));
1335 StatsThreadInitPublic(&stats->
pub);
1350 if (pca == NULL || pctx == NULL) {
1351 SCLogDebug(
"pca or pctx is NULL inside StatsUpdateCounterArray");
1382 return pca->
head[
id.id].
v;
1404 while (
head != NULL) {
1407 StatsReleaseCounter(pc);
1420 if (pca->
head != NULL) {
1431 StatsPublicThreadContextCleanup(&stats->
pub);
1432 StatsReleasePrivateThreadContext(&stats->
priv);
1457 static int StatsTestCounterReg02(
void)
1460 StatsThreadInitPublic(&pctx);
1467 static int StatsTestCounterReg03(
void)
1470 StatsThreadInitPublic(&pctx);
1475 StatsReleaseCounters(pctx.
head);
1479 static int StatsTestCounterReg04(
void)
1482 StatsThreadInitPublic(&pctx);
1493 StatsReleaseCounters(pctx.
head);
1497 static int StatsTestGetCntArray05(
void)
1504 int r = StatsGetAllCountersArray(NULL, &
tv.
stats.
priv);
1510 static int StatsTestGetCntArray06(
void)
1524 static int StatsTestCntArraySize07(
void)
1547 static int StatsTestUpdateCounter08(
void)
1565 static int StatsTestUpdateCounter09(
void)
1591 static int StatsTestUpdateGlobalCounter10(
void)
1620 static int StatsTestCounterValues11(
void)
1659 UtRegisterTest(
"StatsTestGetCntArray05", StatsTestGetCntArray05);
1660 UtRegisterTest(
"StatsTestGetCntArray06", StatsTestGetCntArray06);
1661 UtRegisterTest(
"StatsTestCntArraySize07", StatsTestCntArraySize07);
1662 UtRegisterTest(
"StatsTestUpdateCounter08", StatsTestUpdateCounter08);
1663 UtRegisterTest(
"StatsTestUpdateCounter09", StatsTestUpdateCounter09);
1665 StatsTestUpdateGlobalCounter10);
1666 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