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)
237 if (strcmp(node->
val,
"stats") == 0) {
238 return node->head.tqh_first;
248 static 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";
296 static 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;
326 static 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));
378 static 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");
465 static 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) {
569 static 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
827 TmEcode 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);
851 static 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,
1030 static uint32_t CountersIdHashFunc(
HashTable *ht,
void *data, uint16_t datalen)
1036 for (
size_t i = 0; i <
len; i++)
1043 static 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) {
1067 static 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;
1124 temp->
name = thread_name;
1127 stats_ctx->
sts = temp;
1144 static int StatsGetCounterArrayRange(uint16_t s_id, uint16_t e_id,
1151 if (pctx == NULL || pca == NULL) {
1156 if (s_id < 1 || e_id < 1 || s_id > e_id) {
1162 SCLogDebug(
"end id is greater than the max id for this tv");
1171 while (pc->
id != s_id)
1175 while ((pc != NULL) && (pc->
id <= e_id)) {
1198 if (pctx == NULL ||
private == NULL)
1201 return StatsGetCounterArrayRange(1, pctx->
curr_id, pctx,
private);
1207 StatsGetAllCountersArray(&(
tv)->perf_public_ctx, &(
tv)->perf_private_ctx);
1210 &(
tv)->perf_public_ctx);
1226 if (pca == NULL || pctx == NULL) {
1227 SCLogDebug(
"pca or pctx is NULL inside StatsUpdateCounterArray");
1233 for (uint32_t i = 1; i <= pca->
size; i++) {
1234 StatsCopyCounterValue(&pcae[i]);
1279 while (
head != NULL) {
1282 StatsReleaseCounter(pc);
1295 if (pca->
head != NULL) {
1326 static uint16_t RegisterCounter(
const char *
name,
const char *tm_name,
1329 uint16_t
id = StatsRegisterQualifiedCounter(
name, tm_name, pctx,
1334 static int StatsTestCounterReg02(
void)
1340 return RegisterCounter(NULL, NULL, &pctx) == 0;
1343 static int StatsTestCounterReg03(
void)
1350 result = RegisterCounter(
"t1",
"c1", &pctx);
1359 static int StatsTestCounterReg04(
void)
1366 RegisterCounter(
"t1",
"c1", &pctx);
1367 RegisterCounter(
"t2",
"c2", &pctx);
1368 RegisterCounter(
"t3",
"c3", &pctx);
1370 result = RegisterCounter(
"t1",
"c1", &pctx);
1379 static int StatsTestGetCntArray05(
void)
1394 static int StatsTestGetCntArray06(
void)
1413 static int StatsTestCntArraySize07(
void)
1434 StatsReleasePrivateThreadContext(pca);
1439 static int StatsTestUpdateCounter08(
void)
1458 StatsReleasePrivateThreadContext(pca);
1463 static int StatsTestUpdateCounter09(
void)
1486 StatsReleasePrivateThreadContext(pca);
1491 static int StatsTestUpdateGlobalCounter10(
void)
1497 uint16_t id1, id2, id3;
1521 StatsReleasePrivateThreadContext(pca);
1526 static int StatsTestCounterValues11(
void)
1532 uint16_t id1, id2, id3, id4;
1558 StatsReleasePrivateThreadContext(pca);
1571 UtRegisterTest(
"StatsTestGetCntArray05", StatsTestGetCntArray05);
1572 UtRegisterTest(
"StatsTestGetCntArray06", StatsTestGetCntArray06);
1573 UtRegisterTest(
"StatsTestCntArraySize07", StatsTestCntArraySize07);
1574 UtRegisterTest(
"StatsTestUpdateCounter08", StatsTestUpdateCounter08);
1575 UtRegisterTest(
"StatsTestUpdateCounter09", StatsTestUpdateCounter09);
1577 StatsTestUpdateGlobalCounter10);
1578 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...
struct CountersIdType_ CountersIdType
Container to hold the counter variable.
const char * thread_name_counter_stats
#define SCSetThreadName(n)
int SCConfGet(const char *name, const char **vptr)
Retrieve the value of a configuration node.
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 SCConfGetChildValueBool(const SCConfNode *base, const char *name, int *val)
int StatsSetupPrivate(ThreadVars *tv)
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
#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
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
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.
SCConfNode * SCConfGetNode(const char *name)
Get a SCConfNode by name.
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
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)