Go to the documentation of this file.
44 #define STATS_WUT_TTS 3
47 #define STATS_MGMTT_TTS 8
87 static void *stats_thread_data = NULL;
89 static time_t stats_start_time;
93 static bool stats_enabled =
true;
108 static StatsTable stats_table = { NULL, NULL, 0, 0, 0, {0 , 0}};
110 static int stats_loggers_active = 1;
112 static uint16_t counters_global_id = 0;
116 return stats_enabled;
129 StatsReleaseCounters(t->
head);
147 #if defined (UNITTESTS) || defined (FUZZ)
154 pca->
head[
id.id].
v += x;
166 #if defined (UNITTESTS) || defined (FUZZ)
173 pca->
head[
id.id].
v++;
185 #if defined(UNITTESTS) || defined(FUZZ)
192 pca->
head[
id.id].
v--;
205 #if defined (UNITTESTS) || defined (FUZZ)
212 pca->
head[
id.id].
v = x;
225 #if defined(UNITTESTS) || defined(FUZZ)
233 if ((int64_t)x > pca->
head[
id.id].
v) {
234 pca->
head[
id.id].
v = x;
241 #if defined(UNITTESTS) || defined(FUZZ)
249 pca->
head[
id.id].
v += x;
250 pca->
head[
id.id + 1].
v++;
263 if (strcmp(node->
val,
"stats") == 0) {
264 return node->head.tqh_first;
274 static void StatsInitCtxPreOutput(
void)
281 stats_enabled =
false;
287 if (gstats == NULL) {
289 "Stats enabled through legacy stats.log. "
290 "See %s/configuration/suricata-yaml.html#stats",
295 if (interval != NULL)
298 "interval: \"%s\". Resetting to %d.",
313 const char *prefix = NULL;
315 prefix =
"decoder.event";
322 static void StatsInitCtxPostOutput(
void)
326 time(&stats_start_time);
334 stats_loggers_active = 0;
339 SCLogWarning(
"stats are enabled but no loggers are active");
340 stats_enabled =
false;
352 static void StatsReleaseCtx(
void)
354 if (stats_ctx == NULL) {
355 SCLogDebug(
"Counter module has been disabled");
361 sts = stats_ctx->
sts;
363 while (sts != NULL) {
372 counters_global_id = 0;
381 if (stats_table.
tstats != NULL) {
383 stats_table.
tstats = NULL;
386 if (stats_table.
stats != NULL) {
388 stats_table.
stats = NULL;
390 memset(&stats_table, 0,
sizeof(stats_table));
401 static void *StatsMgmtThread(
void *arg)
414 if (stats_ctx == NULL) {
416 "StatsInitCounterApi() has to be called first");
423 int r = tm->
ThreadInit(tv_local, NULL, &stats_thread_data);
424 if (r != 0 || stats_thread_data == NULL) {
426 "ThreadInit failed");
430 SCLogDebug(
"stats_thread_data %p", &stats_thread_data);
435 struct timeval cur_timev;
436 gettimeofday(&cur_timev, NULL);
438 cond_time.tv_sec += (stats_tts);
448 if (rc == ETIMEDOUT || rc < 0) {
455 StatsOutput(tv_local);
469 "ThreadDeinit failed");
478 StatsUpdateCounterArray(&stats->
priv, &stats->
pub);
484 StatsUpdateCounterArray(&stats->
priv, &stats->
pub);
496 static void *StatsWakeupThread(
void *arg)
509 if (stats_ctx == NULL) {
511 "StatsInitCounterApi() has to be called first");
520 struct timeval cur_timev;
521 gettimeofday(&cur_timev, NULL);
533 if (rc == ETIMEDOUT || rc < 0) {
549 if (
tv->
inq != NULL) {
603 if (strcmp(
name, c->name) == 0) {
622 enum StatsType type_q, uint64_t (*Func)(
void),
const char *dname1,
const char *dname2)
629 if (
name == NULL || pctx == NULL) {
630 SCLogDebug(
"Counter name, StatsPublicThreadContext NULL");
635 while (temp != NULL) {
638 if (strcmp(
name, temp->
name) == 0) {
652 did1 = GetIdByName(pctx, dname1);
653 did2 = GetIdByName(pctx, dname2);
654 if (did1 == 0 || did2 == 0) {
677 if (strrchr(
name,
'.') != NULL) {
701 void *td = stats_thread_data;
703 if (counters_global_id == 0)
706 if (stats_table.
nstats == 0) {
709 uint32_t nstats = counters_global_id;
711 stats_table.
nstats = nstats;
713 if (stats_table.
stats == NULL) {
715 SCLogError(
"could not alloc memory for stats");
722 if (stats_table.
tstats == NULL) {
724 SCLogError(
"could not alloc memory for stats");
731 const uint16_t max_id = counters_global_id;
737 struct CountersMergeTable {
741 } merge_table[max_id];
742 memset(&merge_table, 0x00,
743 max_id *
sizeof(
struct CountersMergeTable));
745 int thread = stats_ctx->
sts_cnt - 1;
750 sts = stats_ctx->
sts;
752 while (sts != NULL) {
760 struct CountersMergeTable thread_table[max_id];
761 memset(&thread_table, 0x00,
762 max_id *
sizeof(
struct CountersMergeTable));
783 for (uint16_t i = 1; i < table_size; i++) {
793 if (pc->
Func != NULL)
794 thread_table[pc->
gid].value = pc->
Func();
798 thread_table[pc->
gid].value = thread_table_from_private[i].
v;
799 thread_table[pc->
gid].updates = thread_table_from_private[i + 1].
v;
804 SCLogDebug(
"counter %u/%u is derived from counters %u / %u", pc->
id, pc->
gid,
806 thread_table[pc->
gid].value = thread_table_from_private[pc->
did1].
v;
807 thread_table[pc->
gid].updates = thread_table_from_private[pc->
did2].
v;
811 thread_table_from_private[i].v);
813 thread_table[pc->
gid].value = thread_table_from_private[i].
v;
819 for (uint16_t c = 0; c < max_id; c++) {
820 const struct CountersMergeTable *e = &thread_table[c];
828 if (e->value > merge_table[c].value)
829 merge_table[c].value = e->value;
832 merge_table[c].value = e->value;
836 merge_table[c].value += e->value;
839 merge_table[c].updates += e->updates;
840 merge_table[c].type = e->type;
844 for (uint16_t c = 0; c < max_id; c++) {
845 const struct CountersMergeTable *e = &thread_table[c];
863 if (e->value > 0 && e->updates > 0) {
864 r->
value = (uint64_t)(e->value / e->updates);
879 for (uint16_t x = 0; x < max_id; x++) {
885 const struct CountersMergeTable *
m = &merge_table[x];
888 if (
m->value > table[x].value)
889 table[x].
value =
m->value;
893 if (
m->value > 0 &&
m->updates > 0) {
894 table[x].
value = (uint64_t)(
m->value /
m->updates);
898 table[x].
value +=
m->value;
904 if (stats_loggers_active) {
910 #ifdef BUILD_UNIX_SOCKET
913 TmEcode StatsOutputCounterSocket(json_t *cmd,
914 json_t *answer,
void *data)
916 json_t *message = NULL;
919 if (!stats_enabled) {
921 message = json_string(
"stats are disabled in the config");
926 message = json_string(
"stats not yet synchronized");
932 json_object_set_new(answer,
"message", message);
937 static void StatsLogSummary(
void)
939 if (!stats_enabled) {
946 for (uint32_t u = 0; u < st->
nstats; u++) {
948 if (
name == NULL || strcmp(
name,
"detect.alert") != 0)
964 BUG_ON(stats_ctx != NULL);
966 FatalError(
"Fatal error encountered in StatsInitCtx. Exiting...");
974 StatsInitCtxPreOutput();
979 StatsInitCtxPostOutput();
993 if (!stats_enabled) {
1002 StatsWakeupThread, 1);
1003 if (tv_wakeup == NULL) {
1010 "StatsWakeupThread");
1015 StatsMgmtThread, 1);
1016 if (tv_mgmt == NULL) {
1017 FatalError(
"TmThreadCreateMgmtThread failed");
1022 "StatsWakeupThread");
1096 #if defined (UNITTESTS) || defined (FUZZ)
1097 if (stats_ctx == NULL)
1100 BUG_ON(stats_ctx == NULL);
1102 uint16_t
id = StatsRegisterQualifiedCounter(
1125 #if defined(UNITTESTS) || defined(FUZZ)
1126 if (stats_ctx == NULL)
1129 BUG_ON(stats_ctx == NULL);
1131 uint16_t
id = StatsRegisterQualifiedCounter(
1142 static uint32_t CountersIdHashFunc(
HashTable *ht,
void *data, uint16_t datalen)
1148 for (
size_t i = 0; i <
len; i++)
1155 static char CountersIdHashCompareFunc(
void *data1, uint16_t datalen1,
1156 void *data2, uint16_t datalen2)
1161 if (t1 == NULL || t2 == NULL)
1170 static void CountersIdHashFreeFunc(
void *data)
1195 SCLogDebug(
"STATS_TYPE_DERIVE_DIV: pc %s gid %u pc->id %u id %u", pc->
name, pc->
gid,
1202 SCLogDebug(
"array_size %u memory %" PRIu64, (uint32_t)array_size,
1222 if (stats_ctx == NULL) {
1226 if (thread_name == NULL || pctx == NULL) {
1227 SCLogDebug(
"supplied argument(s) to StatsThreadRegister NULL");
1235 CountersIdHashCompareFunc,
1236 CountersIdHashFreeFunc);
1243 while (pc != NULL) {
1249 id->id = counters_global_id++;
1250 id->string = pc->
name;
1262 if (StatsThreadSetupPublic(pctx) != 0) {
1263 SCLogDebug(
"failed to setup StatsThreadSetupPublic");
1275 temp->
name = thread_name;
1278 stats_ctx->
sts = temp;
1295 static int StatsGetAllCountersArray(
1298 if (pctx == NULL ||
private == NULL)
1301 private->size = pctx->
curr_id + 1;
1304 if (private->head == NULL) {
1308 private->initialized = 1;
1314 int r = StatsGetAllCountersArray(&stats->
pub, &stats->
priv);
1319 r = StatsThreadRegister(thread_name, &stats->
pub);
1328 memset(pctx, 0x00,
sizeof(*pctx));
1334 StatsThreadInitPublic(&stats->
pub);
1349 if (pca == NULL || pctx == NULL) {
1350 SCLogDebug(
"pca or pctx is NULL inside StatsUpdateCounterArray");
1381 return pca->
head[
id.id].
v;
1403 while (
head != NULL) {
1406 StatsReleaseCounter(pc);
1419 if (pca->
head != NULL) {
1430 StatsPublicThreadContextCleanup(&stats->
pub);
1431 StatsReleasePrivateThreadContext(&stats->
priv);
1456 static int StatsTestCounterReg02(
void)
1459 StatsThreadInitPublic(&pctx);
1466 static int StatsTestCounterReg03(
void)
1469 StatsThreadInitPublic(&pctx);
1474 StatsReleaseCounters(pctx.
head);
1478 static int StatsTestCounterReg04(
void)
1481 StatsThreadInitPublic(&pctx);
1492 StatsReleaseCounters(pctx.
head);
1496 static int StatsTestGetCntArray05(
void)
1503 int r = StatsGetAllCountersArray(NULL, &
tv.
stats.
priv);
1509 static int StatsTestGetCntArray06(
void)
1523 static int StatsTestCntArraySize07(
void)
1546 static int StatsTestUpdateCounter08(
void)
1564 static int StatsTestUpdateCounter09(
void)
1590 static int StatsTestUpdateGlobalCounter10(
void)
1619 static int StatsTestCounterValues11(
void)
1658 UtRegisterTest(
"StatsTestGetCntArray05", StatsTestGetCntArray05);
1659 UtRegisterTest(
"StatsTestGetCntArray06", StatsTestGetCntArray06);
1660 UtRegisterTest(
"StatsTestCntArraySize07", StatsTestCntArraySize07);
1661 UtRegisterTest(
"StatsTestUpdateCounter08", StatsTestUpdateCounter08);
1662 UtRegisterTest(
"StatsTestUpdateCounter09", StatsTestUpdateCounter09);
1664 StatsTestUpdateGlobalCounter10);
1665 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
#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)
int SCConfGetNonNull(const char *name, const char **vptr)
Retrieve the non-null value of a configuration node.
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