Go to the documentation of this file.
45 #define STATS_WUT_TTS 3
48 #define STATS_MGMTT_TTS 8
92 static void *stats_thread_data = NULL;
94 static time_t stats_start_time;
98 static bool stats_enabled =
true;
112 static StatsTable stats_table = { NULL, NULL, 0, 0, 0, {0 , 0}};
114 static int stats_loggers_active = 1;
116 static 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)
236 if (strcmp(node->
val,
"stats") == 0) {
237 return node->head.tqh_first;
247 static void StatsInitCtxPreOutput(
void)
254 stats_enabled =
false;
260 if (gstats == NULL) {
262 "Stats enabled through legacy stats.log. "
263 "See %s/configuration/suricata-yaml.html#stats",
268 if (interval != NULL)
271 "interval: \"%s\". Resetting to %d.",
286 const char *prefix = NULL;
287 if (
ConfGet(
"stats.decoder-events-prefix", &prefix) != 1) {
288 prefix =
"decoder.event";
295 static void StatsInitCtxPostOutput(
void)
299 time(&stats_start_time);
307 stats_loggers_active = 0;
312 SCLogWarning(
"stats are enabled but no loggers are active");
313 stats_enabled =
false;
325 static void StatsReleaseCtx(
void)
327 if (stats_ctx == NULL) {
328 SCLogDebug(
"Counter module has been disabled");
334 sts = stats_ctx->
sts;
336 while (sts != NULL) {
337 if (sts->
head != NULL)
348 counters_global_id = 0;
357 if (stats_table.
tstats != NULL) {
359 stats_table.
tstats = NULL;
362 if (stats_table.
stats != NULL) {
364 stats_table.
stats = NULL;
366 memset(&stats_table, 0,
sizeof(stats_table));
377 static void *StatsMgmtThread(
void *arg)
390 if (stats_ctx == NULL) {
392 "StatsInitCounterApi() has to be called first");
399 int r = tm->
ThreadInit(tv_local, NULL, &stats_thread_data);
400 if (r != 0 || stats_thread_data == NULL) {
402 "ThreadInit failed");
406 SCLogDebug(
"stats_thread_data %p", &stats_thread_data);
411 struct timeval cur_timev;
412 gettimeofday(&cur_timev, NULL);
414 cond_time.tv_sec += (stats_tts);
423 StatsOutput(tv_local);
437 "ThreadDeinit failed");
464 static void *StatsWakeupThread(
void *arg)
477 if (stats_ctx == NULL) {
479 "StatsInitCounterApi() has to be called first");
488 struct timeval cur_timev;
489 gettimeofday(&cur_timev, NULL);
509 if (
tv->
inq != NULL) {
568 static uint16_t StatsRegisterQualifiedCounter(
const char *name,
const char *tm_name,
570 int type_q, uint64_t (*Func)(
void))
577 if (name == NULL || pctx == NULL) {
578 SCLogDebug(
"Counter name, StatsPublicThreadContext NULL");
583 while (temp != NULL) {
586 if (strcmp(name, temp->
name) == 0) {
607 if (strrchr(name,
'.') != NULL) {
608 pc->
short_name = &name[strrchr(name,
'.') - name + 1];
646 void *td = stats_thread_data;
648 if (counters_global_id == 0)
651 if (stats_table.
nstats == 0) {
654 uint32_t nstats = counters_global_id;
656 stats_table.
nstats = nstats;
658 if (stats_table.
stats == NULL) {
660 SCLogError(
"could not alloc memory for stats");
667 if (stats_table.
tstats == NULL) {
669 SCLogError(
"could not alloc memory for stats");
676 const uint16_t max_id = counters_global_id;
682 struct CountersMergeTable {
686 } merge_table[max_id];
687 memset(&merge_table, 0x00,
688 max_id *
sizeof(
struct CountersMergeTable));
690 int thread = stats_ctx->
sts_cnt - 1;
695 sts = stats_ctx->
sts;
697 while (sts != NULL) {
705 struct CountersMergeTable thread_table[max_id];
706 memset(&thread_table, 0x00,
707 max_id *
sizeof(
struct CountersMergeTable));
712 SCLogDebug(
"Counter %s (%u:%u) value %"PRIu64,
715 thread_table[pc->
gid].type = pc->
type;
718 if (pc->
Func != NULL)
719 thread_table[pc->
gid].value = pc->
Func();
723 thread_table[pc->
gid].value = pc->
value;
735 for (uint16_t c = 0; c < max_id; c++) {
736 struct CountersMergeTable *e = &thread_table[c];
744 if (e->value > merge_table[c].value)
745 merge_table[c].value = e->value;
748 merge_table[c].value = e->value;
752 merge_table[c].value += e->value;
755 merge_table[c].updates += e->updates;
756 merge_table[c].type = e->type;
760 for (uint16_t c = 0; c < max_id; c++) {
761 struct CountersMergeTable *e = &thread_table[c];
778 if (e->value > 0 && e->updates > 0) {
779 r->
value = (uint64_t)(e->value / e->updates);
793 for (uint16_t x = 0; x < max_id; x++) {
799 struct CountersMergeTable *
m = &merge_table[x];
802 if (
m->value > table[x].value)
803 table[x].
value =
m->value;
806 if (
m->value > 0 &&
m->updates > 0) {
807 table[x].
value = (uint64_t)(
m->value /
m->updates);
811 table[x].
value +=
m->value;
817 if (stats_loggers_active) {
823 #ifdef BUILD_UNIX_SOCKET
826 TmEcode StatsOutputCounterSocket(json_t *cmd,
827 json_t *answer,
void *data)
829 json_t *message = NULL;
832 if (!stats_enabled) {
834 message = json_string(
"stats are disabled in the config");
839 message = json_string(
"stats not yet synchronized");
845 json_object_set_new(answer,
"message", message);
850 static void StatsLogSummary(
void)
852 if (!stats_enabled) {
859 for (uint32_t u = 0; u < st->
nstats; u++) {
861 if (name == NULL || strcmp(name,
"detect.alert") != 0)
877 BUG_ON(stats_ctx != NULL);
879 FatalError(
"Fatal error encountered in StatsInitCtx. Exiting...");
887 StatsInitCtxPreOutput();
892 StatsInitCtxPostOutput();
906 if (!stats_enabled) {
915 StatsWakeupThread, 1);
916 if (tv_wakeup == NULL) {
923 "StatsWakeupThread");
929 if (tv_mgmt == NULL) {
930 FatalError(
"TmThreadCreateMgmtThread failed");
935 "StatsWakeupThread");
953 uint16_t
id = StatsRegisterQualifiedCounter(name,
973 uint16_t
id = StatsRegisterQualifiedCounter(name,
993 uint16_t
id = StatsRegisterQualifiedCounter(name,
1011 #if defined (UNITTESTS) || defined (FUZZ)
1012 if (stats_ctx == NULL)
1015 BUG_ON(stats_ctx == NULL);
1017 uint16_t
id = StatsRegisterQualifiedCounter(name, NULL,
1029 static uint32_t CountersIdHashFunc(
HashTable *ht,
void *data, uint16_t datalen)
1035 for (
size_t i = 0; i <
len; i++)
1042 static char CountersIdHashCompareFunc(
void *data1, uint16_t datalen1,
1043 void *data2, uint16_t datalen2)
1050 if (t1 == NULL || t2 == NULL)
1056 len1 = strlen(t1->
string);
1057 len2 = strlen(t2->
string);
1059 if (len1 == len2 && memcmp(t1->
string, t2->
string, len1) == 0) {
1066 static void CountersIdHashFreeFunc(
void *data)
1083 if (stats_ctx == NULL) {
1084 SCLogDebug(
"Counter module has been disabled");
1088 if (thread_name == NULL || pctx == NULL) {
1089 SCLogDebug(
"supplied argument(s) to StatsThreadRegister NULL");
1096 CountersIdHashCompareFunc,
1097 CountersIdHashFreeFunc);
1101 while (pc != NULL) {
1107 id->id = counters_global_id++;
1108 id->string = pc->
name;
1123 temp->
name = thread_name;
1126 stats_ctx->
sts = temp;
1143 static int StatsGetCounterArrayRange(uint16_t s_id, uint16_t e_id,
1150 if (pctx == NULL || pca == NULL) {
1155 if (s_id < 1 || e_id < 1 || s_id > e_id) {
1161 SCLogDebug(
"end id is greater than the max id for this tv");
1170 while (pc->
id != s_id)
1174 while ((pc != NULL) && (pc->
id <= e_id)) {
1197 if (pctx == NULL ||
private == NULL)
1200 return StatsGetCounterArrayRange(1, pctx->
curr_id, pctx,
private);
1206 StatsGetAllCountersArray(&(
tv)->perf_public_ctx, &(
tv)->perf_private_ctx);
1209 &(
tv)->perf_public_ctx);
1225 if (pca == NULL || pctx == NULL) {
1226 SCLogDebug(
"pca or pctx is NULL inside StatsUpdateCounterArray");
1232 for (uint32_t i = 1; i <= pca->
size; i++) {
1233 StatsCopyCounterValue(&pcae[i]);
1278 while (
head != NULL) {
1281 StatsReleaseCounter(pc);
1294 if (pca->
head != NULL) {
1325 static uint16_t RegisterCounter(
const char *name,
const char *tm_name,
1328 uint16_t
id = StatsRegisterQualifiedCounter(name, tm_name, pctx,
1333 static int StatsTestCounterReg02(
void)
1339 return RegisterCounter(NULL, NULL, &pctx) == 0;
1342 static int StatsTestCounterReg03(
void)
1349 result = RegisterCounter(
"t1",
"c1", &pctx);
1358 static int StatsTestCounterReg04(
void)
1365 RegisterCounter(
"t1",
"c1", &pctx);
1366 RegisterCounter(
"t2",
"c2", &pctx);
1367 RegisterCounter(
"t3",
"c3", &pctx);
1369 result = RegisterCounter(
"t1",
"c1", &pctx);
1378 static int StatsTestGetCntArray05(
void)
1393 static int StatsTestGetCntArray06(
void)
1412 static int StatsTestCntArraySize07(
void)
1433 StatsReleasePrivateThreadContext(pca);
1438 static int StatsTestUpdateCounter08(
void)
1457 StatsReleasePrivateThreadContext(pca);
1462 static int StatsTestUpdateCounter09(
void)
1485 StatsReleasePrivateThreadContext(pca);
1490 static int StatsTestUpdateGlobalCounter10(
void)
1496 uint16_t id1, id2, id3;
1520 StatsReleasePrivateThreadContext(pca);
1525 static int StatsTestCounterValues11(
void)
1531 uint16_t id1, id2, id3, id4;
1557 StatsReleasePrivateThreadContext(pca);
1570 UtRegisterTest(
"StatsTestGetCntArray05", StatsTestGetCntArray05);
1571 UtRegisterTest(
"StatsTestGetCntArray06", StatsTestGetCntArray06);
1572 UtRegisterTest(
"StatsTestCntArraySize07", StatsTestCntArraySize07);
1573 UtRegisterTest(
"StatsTestUpdateCounter08", StatsTestUpdateCounter08);
1574 UtRegisterTest(
"StatsTestUpdateCounter09", StatsTestUpdateCounter09);
1576 StatsTestUpdateGlobalCounter10);
1577 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.
const char * thread_name_counter_wakeup
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 StatsIncr(ThreadVars *tv, uint16_t id)
Increments the local counter.
per thread store of counters
StatsPublicThreadContext ** head
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
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...
uint16_t StatsRegisterGlobalCounter(const char *name, uint64_t(*Func)(void))
Registers a counter, which represents a global value.
struct HtpBodyChunk_ * next
simple fifo queue for packets with mutex and cond Calling the mutex or triggering the cond is respons...
ConfNode * ConfGetNode(const char *name)
Get a ConfNode by name.
struct CountersIdType_ CountersIdType
Container to hold the counter variable.
const char * thread_name_counter_stats
#define SCSetThreadName(n)
void StatsSetUI64(ThreadVars *tv, uint16_t id, uint64_t x)
Sets a value of type double to the local counter.
#define TAILQ_FOREACH(var, head, field)
int StatsSetupPrivate(ThreadVars *tv)
ThreadVars * tv_root[TVT_MAX]
void StatsInit(void)
Initializes the perf counter api. Things are hard coded currently. More work to be done when we imple...
#define SCMUTEX_INITIALIZER
#define JSON_STATS_TOTALS
#define FAIL_IF_NOT(expr)
Fail a test if expression evaluates to false.
void HashTableFree(HashTable *ht)
StatsPrivateThreadContext perf_private_ctx
TmEcode(* ThreadDeinit)(ThreadVars *, void *)
struct StatsThreadStore_ * next
const char * stats_decoder_events_prefix
int ConfGet(const char *name, const char **vptr)
Retrieve the value of a configuration node.
void StatsDecr(ThreadVars *tv, uint16_t id)
Decrements the local counter.
uint16_t StatsRegisterMaxCounter(const char *name, struct ThreadVars_ *tv)
Registers a counter, whose value holds the maximum of all the values assigned to it.
#define PASS
Pass the test.
struct StatsCounter_ * next
void StatsSetupPostConfigPostOutput(void)
#define SCMutexUnlock(mut)
StatsPublicThreadContext perf_public_ctx
HashTable * counters_id_hash
void * HashTableLookup(HashTable *ht, void *data, uint16_t datalen)
Per thread variable structure.
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.
uint64_t StatsGetLocalCounterValue(ThreadVars *tv, uint16_t id)
Get the value of the local copy of the counter that hold this id.
#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
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
Storage for local counters, with a link to the public counter used for syncs.
#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.
StatsPublicThreadContext * ctx
void StatsSpawnThreads(void)
Spawns the wakeup, and the management thread used by the stats api.
TmEcode(* ThreadInit)(ThreadVars *, const void *, void **)
#define JSON_STATS_THREADS
int ConfGetChildValueBool(const ConfNode *base, const char *name, int *val)
void StatsSyncCounters(ThreadVars *tv)
int ConfUnixSocketIsEnable(void)
void StatsAddUI64(ThreadVars *tv, uint16_t id, uint64_t x)
Adds a value of type uint64_t to the local counter.
int OutputStatsLoggersRegistered(void)
#define SCLogError(...)
Macro used to log ERROR messages.
int StatsUpdateCounterArray(StatsPrivateThreadContext *pca, StatsPublicThreadContext *pctx)
the private stats store with the public stats store
int ConfValIsFalse(const char *val)
Check if a value is false.
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 StatsReleaseCounters(StatsCounter *head)
Releases counters.
const char * GetDocURL(void)
struct StatsGlobalContext_ StatsGlobalContext
Holds the output interface context for the counter api.
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 StatsSyncCountersIfSignalled(ThreadVars *tv)
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.
uint16_t StatsRegisterCounter(const char *name, struct ThreadVars_ *tv)
Registers a normal, unqualified counter.
void StatsThreadCleanup(ThreadVars *tv)
TmEcode OutputStatsLog(ThreadVars *tv, void *thread_data, StatsTable *st)
void StatsRegisterTests(void)
const char * ConfNodeLookupChildValue(const ConfNode *node, const char *name)
Lookup the value of a child configuration node by name.