45#define STATS_WUT_TTS 3
48#define STATS_MGMTT_TTS 8
92static void *stats_thread_data = NULL;
94static time_t stats_start_time;
98static bool stats_enabled =
true;
112static StatsTable stats_table = { NULL, NULL, 0, 0, 0, {0 , 0}};
114static int stats_loggers_active = 1;
116static uint16_t counters_global_id = 0;
120 return stats_enabled;
149#if defined (UNITTESTS) || defined (FUZZ)
169#if defined (UNITTESTS) || defined (FUZZ)
189#if defined(UNITTESTS) || defined(FUZZ)
210#if defined (UNITTESTS) || defined (FUZZ)
237 if (strcmp(node->
val,
"stats") == 0) {
238 return node->head.tqh_first;
248static void StatsInitCtxPreOutput(
void)
255 stats_enabled =
false;
261 if (gstats == NULL) {
263 "Stats enabled through legacy stats.log. "
264 "See %s/configuration/suricata-yaml.html#stats",
269 if (interval != NULL)
272 "interval: \"%s\". Resetting to %d.",
287 const char *prefix = NULL;
288 if (
SCConfGet(
"stats.decoder-events-prefix", &prefix) != 1) {
289 prefix =
"decoder.event";
296static void StatsInitCtxPostOutput(
void)
300 time(&stats_start_time);
308 stats_loggers_active = 0;
313 SCLogWarning(
"stats are enabled but no loggers are active");
314 stats_enabled =
false;
326static void StatsReleaseCtx(
void)
328 if (stats_ctx == NULL) {
329 SCLogDebug(
"Counter module has been disabled");
335 sts = stats_ctx->
sts;
337 while (sts != NULL) {
338 if (sts->
head != NULL)
349 counters_global_id = 0;
358 if (stats_table.
tstats != NULL) {
360 stats_table.
tstats = NULL;
363 if (stats_table.
stats != NULL) {
365 stats_table.
stats = NULL;
367 memset(&stats_table, 0,
sizeof(stats_table));
378static void *StatsMgmtThread(
void *arg)
391 if (stats_ctx == NULL) {
393 "StatsInitCounterApi() has to be called first");
400 int r = tm->
ThreadInit(tv_local, NULL, &stats_thread_data);
401 if (r != 0 || stats_thread_data == NULL) {
403 "ThreadInit failed");
407 SCLogDebug(
"stats_thread_data %p", &stats_thread_data);
412 struct timeval cur_timev;
413 gettimeofday(&cur_timev, NULL);
415 cond_time.tv_sec += (stats_tts);
424 StatsOutput(tv_local);
438 "ThreadDeinit failed");
465static void *StatsWakeupThread(
void *arg)
478 if (stats_ctx == NULL) {
480 "StatsInitCounterApi() has to be called first");
489 struct timeval cur_timev;
490 gettimeofday(&cur_timev, NULL);
510 if (
tv->
inq != NULL) {
569static uint16_t StatsRegisterQualifiedCounter(
const char *
name,
const char *tm_name,
571 int type_q, uint64_t (*Func)(
void))
578 if (
name == NULL || pctx == NULL) {
579 SCLogDebug(
"Counter name, StatsPublicThreadContext NULL");
584 while (temp != NULL) {
587 if (strcmp(
name, temp->
name) == 0) {
608 if (strrchr(
name,
'.') != NULL) {
647 void *td = stats_thread_data;
649 if (counters_global_id == 0)
652 if (stats_table.
nstats == 0) {
655 uint32_t nstats = counters_global_id;
657 stats_table.
nstats = nstats;
659 if (stats_table.
stats == NULL) {
661 SCLogError(
"could not alloc memory for stats");
668 if (stats_table.
tstats == NULL) {
670 SCLogError(
"could not alloc memory for stats");
677 const uint16_t max_id = counters_global_id;
683 struct CountersMergeTable {
687 } merge_table[max_id];
688 memset(&merge_table, 0x00,
689 max_id *
sizeof(
struct CountersMergeTable));
691 int thread = stats_ctx->
sts_cnt - 1;
696 sts = stats_ctx->
sts;
698 while (sts != NULL) {
706 struct CountersMergeTable thread_table[max_id];
707 memset(&thread_table, 0x00,
708 max_id *
sizeof(
struct CountersMergeTable));
713 SCLogDebug(
"Counter %s (%u:%u) value %"PRIu64,
716 thread_table[pc->
gid].type = pc->
type;
719 if (pc->
Func != NULL)
720 thread_table[pc->
gid].value = pc->
Func();
724 thread_table[pc->
gid].value = pc->
value;
736 for (uint16_t c = 0; c < max_id; c++) {
737 struct CountersMergeTable *e = &thread_table[c];
745 if (e->value > merge_table[c].value)
746 merge_table[c].value = e->value;
749 merge_table[c].value = e->value;
753 merge_table[c].value += e->value;
756 merge_table[c].updates += e->updates;
757 merge_table[c].type = e->type;
761 for (uint16_t c = 0; c < max_id; c++) {
762 struct CountersMergeTable *e = &thread_table[c];
779 if (e->value > 0 && e->updates > 0) {
780 r->
value = (uint64_t)(e->value / e->updates);
794 for (uint16_t x = 0; x < max_id; x++) {
800 struct CountersMergeTable *
m = &merge_table[x];
803 if (
m->value > table[x].value)
804 table[x].
value =
m->value;
807 if (
m->value > 0 &&
m->updates > 0) {
808 table[x].
value = (uint64_t)(
m->value /
m->updates);
812 table[x].
value +=
m->value;
818 if (stats_loggers_active) {
824#ifdef BUILD_UNIX_SOCKET
827TmEcode StatsOutputCounterSocket(json_t *cmd,
828 json_t *answer,
void *data)
830 json_t *message = NULL;
833 if (!stats_enabled) {
835 message = json_string(
"stats are disabled in the config");
840 message = json_string(
"stats not yet synchronized");
846 json_object_set_new(answer,
"message", message);
851static void StatsLogSummary(
void)
853 if (!stats_enabled) {
860 for (uint32_t u = 0; u < st->
nstats; u++) {
862 if (
name == NULL || strcmp(
name,
"detect.alert") != 0)
878 BUG_ON(stats_ctx != NULL);
880 FatalError(
"Fatal error encountered in StatsInitCtx. Exiting...");
888 StatsInitCtxPreOutput();
893 StatsInitCtxPostOutput();
907 if (!stats_enabled) {
916 StatsWakeupThread, 1);
917 if (tv_wakeup == NULL) {
924 "StatsWakeupThread");
930 if (tv_mgmt == NULL) {
931 FatalError(
"TmThreadCreateMgmtThread failed");
936 "StatsWakeupThread");
954 uint16_t
id = StatsRegisterQualifiedCounter(
name,
974 uint16_t
id = StatsRegisterQualifiedCounter(
name,
994 uint16_t
id = StatsRegisterQualifiedCounter(
name,
1012#if defined (UNITTESTS) || defined (FUZZ)
1013 if (stats_ctx == NULL)
1016 BUG_ON(stats_ctx == NULL);
1018 uint16_t
id = StatsRegisterQualifiedCounter(
name, NULL,
1030static uint32_t CountersIdHashFunc(
HashTable *ht,
void *data, uint16_t datalen)
1036 for (
size_t i = 0; i <
len; i++)
1043static char CountersIdHashCompareFunc(
void *data1, uint16_t datalen1,
1044 void *data2, uint16_t datalen2)
1051 if (t1 == NULL || t2 == NULL)
1057 len1 = strlen(t1->
string);
1058 len2 = strlen(t2->
string);
1060 if (len1 == len2 && memcmp(t1->
string, t2->
string, len1) == 0) {
1067static void CountersIdHashFreeFunc(
void *data)
1084 if (stats_ctx == NULL) {
1085 SCLogDebug(
"Counter module has been disabled");
1089 if (thread_name == NULL || pctx == NULL) {
1090 SCLogDebug(
"supplied argument(s) to StatsThreadRegister NULL");
1097 CountersIdHashCompareFunc,
1098 CountersIdHashFreeFunc);
1102 while (pc != NULL) {
1108 id->id = counters_global_id++;
1109 id->string = pc->
name;
1110#ifdef DEBUG_VALIDATION
1128 temp->
name = thread_name;
1131 stats_ctx->
sts = temp;
1148static int StatsGetCounterArrayRange(uint16_t s_id, uint16_t e_id,
1155 if (pctx == NULL || pca == NULL) {
1160 if (s_id < 1 || e_id < 1 || s_id > e_id) {
1166 SCLogDebug(
"end id is greater than the max id for this tv");
1175 while (pc->
id != s_id)
1179 while ((pc != NULL) && (pc->
id <= e_id)) {
1202 if (pctx == NULL ||
private == NULL)
1205 return StatsGetCounterArrayRange(1, pctx->
curr_id, pctx,
private);
1211 StatsGetAllCountersArray(&(
tv)->perf_public_ctx, &(
tv)->perf_private_ctx);
1214 &(
tv)->perf_public_ctx);
1230 if (pca == NULL || pctx == NULL) {
1231 SCLogDebug(
"pca or pctx is NULL inside StatsUpdateCounterArray");
1237 for (uint32_t i = 1; i <= pca->
size; i++) {
1238 StatsCopyCounterValue(&pcae[i]);
1283 while (
head != NULL) {
1286 StatsReleaseCounter(pc);
1299 if (pca->
head != NULL) {
1330static uint16_t RegisterCounter(
const char *
name,
const char *tm_name,
1333 uint16_t
id = StatsRegisterQualifiedCounter(
name, tm_name, pctx,
1338static int StatsTestCounterReg02(
void)
1344 return RegisterCounter(NULL, NULL, &pctx) == 0;
1347static int StatsTestCounterReg03(
void)
1354 result = RegisterCounter(
"t1",
"c1", &pctx);
1363static int StatsTestCounterReg04(
void)
1370 RegisterCounter(
"t1",
"c1", &pctx);
1371 RegisterCounter(
"t2",
"c2", &pctx);
1372 RegisterCounter(
"t3",
"c3", &pctx);
1374 result = RegisterCounter(
"t1",
"c1", &pctx);
1383static int StatsTestGetCntArray05(
void)
1398static int StatsTestGetCntArray06(
void)
1417static int StatsTestCntArraySize07(
void)
1438 StatsReleasePrivateThreadContext(pca);
1443static int StatsTestUpdateCounter08(
void)
1462 StatsReleasePrivateThreadContext(pca);
1467static int StatsTestUpdateCounter09(
void)
1490 StatsReleasePrivateThreadContext(pca);
1495static int StatsTestUpdateGlobalCounter10(
void)
1501 uint16_t id1, id2, id3;
1525 StatsReleasePrivateThreadContext(pca);
1530static int StatsTestCounterValues11(
void)
1536 uint16_t id1, id2, id3, id4;
1562 StatsReleasePrivateThreadContext(pca);
1575 UtRegisterTest(
"StatsTestGetCntArray05", StatsTestGetCntArray05);
1576 UtRegisterTest(
"StatsTestGetCntArray06", StatsTestGetCntArray06);
1577 UtRegisterTest(
"StatsTestCntArraySize07", StatsTestCntArraySize07);
1578 UtRegisterTest(
"StatsTestUpdateCounter08", StatsTestUpdateCounter08);
1579 UtRegisterTest(
"StatsTestUpdateCounter09", StatsTestUpdateCounter09);
1581 StatsTestUpdateGlobalCounter10);
1582 UtRegisterTest(
"StatsTestCounterValues11", StatsTestCounterValues11);
struct HtpBodyChunk_ * next
SCConfNode * SCConfGetNode(const char *name)
Get a SCConfNode by name.
int SCConfGetChildValueBool(const SCConfNode *base, const char *name, int *val)
const char * SCConfNodeLookupChildValue(const SCConfNode *node, const char *name)
Lookup the value of a child configuration node by name.
int SCConfValIsFalse(const char *val)
Check if a value is false.
int SCConfGet(const char *name, const char **vptr)
Retrieve the value of a configuration node.
void StatsThreadCleanup(ThreadVars *tv)
uint16_t StatsRegisterGlobalCounter(const char *name, uint64_t(*Func)(void))
Registers a counter, which represents a global value.
void StatsDecr(ThreadVars *tv, uint16_t id)
Decrements the local counter.
void StatsSpawnThreads(void)
Spawns the wakeup, and the management thread used by the stats api.
struct StatsThreadStore_ StatsThreadStore
per thread store of counters
void StatsSyncCounters(ThreadVars *tv)
int StatsSetupPrivate(ThreadVars *tv)
uint16_t StatsRegisterMaxCounter(const char *name, struct ThreadVars_ *tv)
Registers a counter, whose value holds the maximum of all the values assigned to it.
void StatsInit(void)
Initializes the perf counter api. Things are hard coded currently. More work to be done when we imple...
uint16_t StatsRegisterCounter(const char *name, struct ThreadVars_ *tv)
Registers a normal, unqualified counter.
struct CountersIdType_ CountersIdType
void StatsSetUI64(ThreadVars *tv, uint16_t id, uint64_t x)
Sets a value of type double to the local counter.
void StatsSyncCountersIfSignalled(ThreadVars *tv)
void StatsSetupPostConfigPostOutput(void)
uint64_t StatsGetLocalCounterValue(ThreadVars *tv, uint16_t id)
Get the value of the local copy of the counter that hold this id.
void StatsIncr(ThreadVars *tv, uint16_t id)
Increments the local counter.
void StatsReleaseResources(void)
Releases the resources allotted by the Stats API.
struct StatsGlobalContext_ StatsGlobalContext
Holds the output interface context for the counter api.
int StatsUpdateCounterArray(StatsPrivateThreadContext *pca, StatsPublicThreadContext *pctx)
the private stats store with the public stats store
void StatsReleaseCounters(StatsCounter *head)
Releases counters.
void StatsSetupPostConfigPreOutput(void)
uint16_t StatsRegisterAvgCounter(const char *name, struct ThreadVars_ *tv)
Registers a counter, whose value holds the average of all the values assigned to it.
void StatsRegisterTests(void)
void StatsAddUI64(ThreadVars *tv, uint16_t id, uint64_t x)
Adds a value of type uint64_t to the local counter.
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
#define FAIL_IF_NOT(expr)
Fail a test if expression evaluates to false.
#define PASS
Pass the test.
#define FAIL_IF(expr)
Fail a test if expression evaluates to true.
const char * stats_decoder_events_prefix
bool stats_decoder_events
json_t * StatsToJSON(const StatsTable *st, uint8_t flags)
turn StatsTable into a json object
#define JSON_STATS_TOTALS
#define JSON_STATS_THREADS
int OutputStatsLoggersRegistered(void)
TmEcode OutputStatsLog(ThreadVars *tv, void *thread_data, StatsTable *st)
struct StatsRecord_ StatsRecord
#define TAILQ_FOREACH(var, head, field)
const char * thread_name_counter_wakeup
const char * thread_name_counter_stats
simple fifo queue for packets with mutex and cond Calling the mutex or triggering the cond is respons...
Container to hold the counter variable.
struct StatsCounter_ * next
Holds the output interface context for the counter api.
HashTable * counters_id_hash
StatsPublicThreadContext global_counter_ctx
Storage for local counters, with a link to the public counter used for syncs.
used to hold the private version of the counters registered
Stats Context for a ThreadVars instance.
per thread store of counters
StatsPublicThreadContext ** head
struct StatsThreadStore_ * next
StatsPublicThreadContext * ctx
Per thread variable structure.
struct ThreadVars_ * next
StatsPublicThreadContext perf_public_ctx
StatsPrivateThreadContext perf_private_ctx
uint8_t thread_setup_flags
TmEcode(* ThreadDeinit)(ThreadVars *, void *)
TmEcode(* ThreadInit)(ThreadVars *, const void *, void **)
const char * GetDocURL(void)
#define SCCtrlCondTimedwait
#define SCCtrlMutexLock(mut)
#define SCMUTEX_INITIALIZER
#define SCMutexUnlock(mut)
#define SCCtrlMutexUnlock(mut)
#define SCMutexInit(mut, mutattrs)
#define SCSetThreadName(n)
TmModule tmm_modules[TMM_SIZE]
int TmThreadsCheckFlag(ThreadVars *tv, uint32_t flag)
Check if a thread flag is set.
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...
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...
ThreadVars * tv_root[TVT_MAX]
bool TmThreadsWaitForUnpause(ThreadVars *tv)
Wait for a thread to become unpaused.
void TmThreadsSetFlag(ThreadVars *tv, uint32_t flag)
Set a thread flag.
TmEcode TmThreadSetupOptions(ThreadVars *tv)
Set the thread options (cpu affinitythread). Priority should be already set by pthread_create.
TmEcode TmThreadSpawn(ThreadVars *tv)
Spawns a thread associated with the ThreadVars instance tv.
#define SC_ATOMIC_GET(name)
Get the value from the atomic variable.
#define SC_ATOMIC_SET(name, val)
Set the value for the atomic variable.
int StringParseUint32(uint32_t *res, int base, size_t len, const char *str)
int ConfUnixSocketIsEnable(void)
#define SCLogWarning(...)
Macro used to log WARNING messages.
#define SCLogInfo(...)
Macro used to log INFORMATIONAL messages.
#define SCLogError(...)
Macro used to log ERROR messages.
int HashTableAdd(HashTable *ht, void *data, uint16_t datalen)
HashTable * HashTableInit(uint32_t size, uint32_t(*Hash)(struct HashTable_ *, void *, uint16_t), char(*Compare)(void *, uint16_t, void *, uint16_t), void(*Free)(void *))
void HashTableFree(HashTable *ht)
void * HashTableLookup(HashTable *ht, void *data, uint16_t datalen)
#define FROM_TIMEVAL(timev)
initialize a 'struct timespec' from a 'struct timeval'.
#define DEBUG_VALIDATE_BUG_ON(exp)