Go to the documentation of this file.
45 #define STATS_WUT_TTS 3
48 #define STATS_MGMTT_TTS 8
89 static void *stats_thread_data = NULL;
91 static time_t stats_start_time;
95 static bool stats_enabled =
true;
110 static StatsTable stats_table = { NULL, NULL, 0, 0, 0, {0 , 0}};
112 static int stats_loggers_active = 1;
114 static uint16_t counters_global_id = 0;
118 return stats_enabled;
131 StatsReleaseCounters(t->
head);
149 #if defined (UNITTESTS) || defined (FUZZ)
156 pca->
head[
id.id].
v += x;
168 #if defined (UNITTESTS) || defined (FUZZ)
175 pca->
head[
id.id].
v++;
187 #if defined(UNITTESTS) || defined(FUZZ)
194 pca->
head[
id.id].
v--;
207 #if defined (UNITTESTS) || defined (FUZZ)
214 pca->
head[
id.id].
v = x;
227 #if defined(UNITTESTS) || defined(FUZZ)
235 if ((int64_t)x > pca->
head[
id.id].
v) {
236 pca->
head[
id.id].
v = x;
243 #if defined(UNITTESTS) || defined(FUZZ)
251 pca->
head[
id.id].
v += x;
252 pca->
head[
id.id + 1].
v++;
265 if (strcmp(node->
val,
"stats") == 0) {
266 return node->head.tqh_first;
276 static void StatsInitCtxPreOutput(
void)
283 stats_enabled =
false;
289 if (gstats == NULL) {
291 "Stats enabled through legacy stats.log. "
292 "See %s/configuration/suricata-yaml.html#stats",
297 if (interval != NULL)
300 "interval: \"%s\". Resetting to %d.",
315 const char *prefix = NULL;
316 if (
SCConfGet(
"stats.decoder-events-prefix", &prefix) != 1) {
317 prefix =
"decoder.event";
324 static void StatsInitCtxPostOutput(
void)
328 time(&stats_start_time);
336 stats_loggers_active = 0;
341 SCLogWarning(
"stats are enabled but no loggers are active");
342 stats_enabled =
false;
354 static void StatsReleaseCtx(
void)
356 if (stats_ctx == NULL) {
357 SCLogDebug(
"Counter module has been disabled");
363 sts = stats_ctx->
sts;
365 while (sts != NULL) {
374 counters_global_id = 0;
383 if (stats_table.
tstats != NULL) {
385 stats_table.
tstats = NULL;
388 if (stats_table.
stats != NULL) {
390 stats_table.
stats = NULL;
392 memset(&stats_table, 0,
sizeof(stats_table));
403 static void *StatsMgmtThread(
void *arg)
416 if (stats_ctx == NULL) {
418 "StatsInitCounterApi() has to be called first");
425 int r = tm->
ThreadInit(tv_local, NULL, &stats_thread_data);
426 if (r != 0 || stats_thread_data == NULL) {
428 "ThreadInit failed");
432 SCLogDebug(
"stats_thread_data %p", &stats_thread_data);
437 struct timeval cur_timev;
438 gettimeofday(&cur_timev, NULL);
440 cond_time.tv_sec += (stats_tts);
450 if (rc == ETIMEDOUT || rc < 0) {
457 StatsOutput(tv_local);
471 "ThreadDeinit failed");
480 StatsUpdateCounterArray(&stats->
priv, &stats->
pub);
486 StatsUpdateCounterArray(&stats->
priv, &stats->
pub);
498 static void *StatsWakeupThread(
void *arg)
511 if (stats_ctx == NULL) {
513 "StatsInitCounterApi() has to be called first");
522 struct timeval cur_timev;
523 gettimeofday(&cur_timev, NULL);
535 if (rc == ETIMEDOUT || rc < 0) {
551 if (
tv->
inq != NULL) {
609 static uint16_t StatsRegisterQualifiedCounter(
617 if (
name == NULL || pctx == NULL) {
618 SCLogDebug(
"Counter name, StatsPublicThreadContext NULL");
623 while (temp != NULL) {
626 if (strcmp(
name, temp->
name) == 0) {
652 if (strrchr(
name,
'.') != NULL) {
674 void *td = stats_thread_data;
676 if (counters_global_id == 0)
679 if (stats_table.
nstats == 0) {
682 uint32_t nstats = counters_global_id;
684 stats_table.
nstats = nstats;
686 if (stats_table.
stats == NULL) {
688 SCLogError(
"could not alloc memory for stats");
695 if (stats_table.
tstats == NULL) {
697 SCLogError(
"could not alloc memory for stats");
704 const uint16_t max_id = counters_global_id;
710 struct CountersMergeTable {
714 } merge_table[max_id];
715 memset(&merge_table, 0x00,
716 max_id *
sizeof(
struct CountersMergeTable));
718 int thread = stats_ctx->
sts_cnt - 1;
723 sts = stats_ctx->
sts;
725 while (sts != NULL) {
733 struct CountersMergeTable thread_table[max_id];
734 memset(&thread_table, 0x00,
735 max_id *
sizeof(
struct CountersMergeTable));
756 for (uint16_t i = 1; i < table_size; i++) {
765 if (pc->
Func != NULL)
766 thread_table[pc->
gid].value = pc->
Func();
769 thread_table[pc->
gid].value = thread_table_from_private[i].
v;
770 thread_table[pc->
gid].updates = thread_table_from_private[i + 1].
v;
776 thread_table_from_private[i].v);
778 thread_table[pc->
gid].value = thread_table_from_private[i].
v;
784 for (uint16_t c = 0; c < max_id; c++) {
785 struct CountersMergeTable *e = &thread_table[c];
793 if (e->value > merge_table[c].value)
794 merge_table[c].value = e->value;
797 merge_table[c].value = e->value;
801 merge_table[c].value += e->value;
804 merge_table[c].updates += e->updates;
805 merge_table[c].type = e->type;
809 for (uint16_t c = 0; c < max_id; c++) {
810 struct CountersMergeTable *e = &thread_table[c];
827 if (e->value > 0 && e->updates > 0) {
828 r->
value = (uint64_t)(e->value / e->updates);
843 for (uint16_t x = 0; x < max_id; x++) {
849 struct CountersMergeTable *
m = &merge_table[x];
852 if (
m->value > table[x].value)
853 table[x].
value =
m->value;
856 if (
m->value > 0 &&
m->updates > 0) {
857 table[x].
value = (uint64_t)(
m->value /
m->updates);
861 table[x].
value +=
m->value;
867 if (stats_loggers_active) {
873 #ifdef BUILD_UNIX_SOCKET
876 TmEcode StatsOutputCounterSocket(json_t *cmd,
877 json_t *answer,
void *data)
879 json_t *message = NULL;
882 if (!stats_enabled) {
884 message = json_string(
"stats are disabled in the config");
889 message = json_string(
"stats not yet synchronized");
895 json_object_set_new(answer,
"message", message);
900 static void StatsLogSummary(
void)
902 if (!stats_enabled) {
909 for (uint32_t u = 0; u < st->
nstats; u++) {
911 if (
name == NULL || strcmp(
name,
"detect.alert") != 0)
927 BUG_ON(stats_ctx != NULL);
929 FatalError(
"Fatal error encountered in StatsInitCtx. Exiting...");
937 StatsInitCtxPreOutput();
942 StatsInitCtxPostOutput();
956 if (!stats_enabled) {
965 StatsWakeupThread, 1);
966 if (tv_wakeup == NULL) {
973 "StatsWakeupThread");
979 if (tv_mgmt == NULL) {
980 FatalError(
"TmThreadCreateMgmtThread failed");
985 "StatsWakeupThread");
1056 #if defined (UNITTESTS) || defined (FUZZ)
1057 if (stats_ctx == NULL)
1060 BUG_ON(stats_ctx == NULL);
1062 uint16_t
id = StatsRegisterQualifiedCounter(
1073 static uint32_t CountersIdHashFunc(
HashTable *ht,
void *data, uint16_t datalen)
1079 for (
size_t i = 0; i <
len; i++)
1086 static char CountersIdHashCompareFunc(
void *data1, uint16_t datalen1,
1087 void *data2, uint16_t datalen2)
1094 if (t1 == NULL || t2 == NULL)
1100 len1 = strlen(t1->
string);
1101 len2 = strlen(t2->
string);
1103 if (len1 == len2 && memcmp(t1->
string, t2->
string, len1) == 0) {
1110 static void CountersIdHashFreeFunc(
void *data)
1117 size_t array_size = pctx->
curr_id + 1;
1128 SCLogDebug(
"array_size %u memory %" PRIu64, (uint32_t)array_size,
1148 if (stats_ctx == NULL) {
1152 if (thread_name == NULL || pctx == NULL) {
1153 SCLogDebug(
"supplied argument(s) to StatsThreadRegister NULL");
1161 CountersIdHashCompareFunc,
1162 CountersIdHashFreeFunc);
1169 while (pc != NULL) {
1175 id->id = counters_global_id++;
1176 id->string = pc->
name;
1188 if (StatsThreadSetupPublic(pctx) != 0) {
1189 SCLogDebug(
"failed to setup StatsThreadSetupPublic");
1201 temp->
name = thread_name;
1204 stats_ctx->
sts = temp;
1221 static int StatsGetAllCountersArray(
1224 if (pctx == NULL ||
private == NULL)
1227 private->size = pctx->
curr_id + 1;
1230 if (private->head == NULL) {
1234 private->initialized = 1;
1240 int r = StatsGetAllCountersArray(&stats->
pub, &stats->
priv);
1245 r = StatsThreadRegister(thread_name, &stats->
pub);
1254 memset(pctx, 0x00,
sizeof(*pctx));
1260 StatsThreadInitPublic(&stats->
pub);
1275 if (pca == NULL || pctx == NULL) {
1276 SCLogDebug(
"pca or pctx is NULL inside StatsUpdateCounterArray");
1307 return pca->
head[
id.id].
v;
1329 while (
head != NULL) {
1332 StatsReleaseCounter(pc);
1345 if (pca->
head != NULL) {
1356 StatsPublicThreadContextCleanup(&stats->
pub);
1357 StatsReleasePrivateThreadContext(&stats->
priv);
1382 static int StatsTestCounterReg02(
void)
1385 StatsThreadInitPublic(&pctx);
1392 static int StatsTestCounterReg03(
void)
1395 StatsThreadInitPublic(&pctx);
1400 StatsReleaseCounters(pctx.
head);
1404 static int StatsTestCounterReg04(
void)
1407 StatsThreadInitPublic(&pctx);
1418 StatsReleaseCounters(pctx.
head);
1422 static int StatsTestGetCntArray05(
void)
1429 int r = StatsGetAllCountersArray(NULL, &
tv.
stats.
priv);
1435 static int StatsTestGetCntArray06(
void)
1449 static int StatsTestCntArraySize07(
void)
1472 static int StatsTestUpdateCounter08(
void)
1490 static int StatsTestUpdateCounter09(
void)
1516 static int StatsTestUpdateGlobalCounter10(
void)
1545 static int StatsTestCounterValues11(
void)
1584 UtRegisterTest(
"StatsTestGetCntArray05", StatsTestGetCntArray05);
1585 UtRegisterTest(
"StatsTestGetCntArray06", StatsTestGetCntArray06);
1586 UtRegisterTest(
"StatsTestCntArraySize07", StatsTestCntArraySize07);
1587 UtRegisterTest(
"StatsTestUpdateCounter08", StatsTestUpdateCounter08);
1588 UtRegisterTest(
"StatsTestUpdateCounter09", StatsTestUpdateCounter09);
1590 StatsTestUpdateGlobalCounter10);
1591 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.
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.
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