suricata
counters.c
Go to the documentation of this file.
1 /* Copyright (C) 2007-2025 Open Information Security Foundation
2  *
3  * You can copy, redistribute or modify this Program under the terms of
4  * the GNU General Public License version 2 as published by the Free
5  * Software Foundation.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * version 2 along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15  * 02110-1301, USA.
16  */
17 
18 /**
19  * \file
20  *
21  * \author Anoop Saldanha <anoopsaldanha@gmail.com>
22  * \author Victor Julien <victor@inliniac.net>
23  *
24  * Engine stats API
25  */
26 
27 #include "suricata-common.h"
28 #include "counters.h"
29 
30 #include "suricata.h"
31 #include "threadvars.h"
32 
33 #include "output.h"
34 #include "output-json-stats.h"
35 
36 #include "util-byte.h"
37 #include "util-conf.h"
38 #include "util-hash.h"
39 #include "util-time.h"
40 
41 #include "tm-threads.h"
42 #include "util-privs.h"
43 
44 /* Time interval for syncing the local counters with the global ones */
45 #define STATS_WUT_TTS 3
46 
47 /* Time interval at which the mgmt thread o/p the stats */
48 #define STATS_MGMTT_TTS 8
49 
50 /**
51  * \brief Different kinds of qualifier that can be used to modify the behaviour
52  * of the counter to be registered
53  */
54 enum StatsType {
60 };
61 
62 /**
63  * \brief per thread store of counters
64  */
65 typedef struct StatsThreadStore_ {
66  /** thread name used in output */
67  const char *name;
68 
70 
73 
74 /**
75  * \brief Holds the output interface context for the counter api
76  */
77 typedef struct StatsGlobalContext_ {
78  /** list of thread stores: one per thread plus one global */
81  int sts_cnt;
82 
84 
87 
88 static void *stats_thread_data = NULL;
89 static StatsGlobalContext *stats_ctx = NULL;
90 static time_t stats_start_time;
91 /** refresh interval in seconds */
92 static uint32_t stats_tts = STATS_MGMTT_TTS;
93 /** is the stats counter enabled? */
94 static bool stats_enabled = true;
95 
96 /**< add decoder events as stats? enabled by default */
98 const char *stats_decoder_events_prefix = "decoder.event";
99 /**< add stream events as stats? disabled by default */
100 bool stats_stream_events = false;
101 
102 static int StatsOutput(ThreadVars *tv);
103 static int StatsThreadRegister(const char *thread_name, StatsPublicThreadContext *);
104 static void StatsReleaseCounters(StatsCounter *head);
105 static int StatsUpdateCounterArray(StatsPrivateThreadContext *pca, StatsPublicThreadContext *pctx);
106 
107 /** stats table is filled each interval and passed to the
108  * loggers. Initialized at first use. */
109 static StatsTable stats_table = { NULL, NULL, 0, 0, 0, {0 , 0}};
110 static SCMutex stats_table_mutex = SCMUTEX_INITIALIZER;
111 static int stats_loggers_active = 1;
112 
113 static uint16_t counters_global_id = 0;
114 
115 bool StatsEnabled(void)
116 {
117  return stats_enabled;
118 }
119 
120 static void StatsPublicThreadContextInit(StatsPublicThreadContext *t)
121 {
122  SCSpinInit(&t->lock, 0);
123 }
124 
125 static void StatsPublicThreadContextCleanup(StatsPublicThreadContext *t)
126 {
127  SCSpinLock(&t->lock);
129  SCFree(t->pc_array);
130  StatsReleaseCounters(t->head);
131  t->head = NULL;
132  SC_ATOMIC_SET(t->sync_now, false);
133  t->curr_id = 0;
134  SCSpinUnlock(&t->lock);
135  SCSpinDestroy(&t->lock);
136 }
137 
138 /**
139  * \brief Adds a value of type uint64_t to the local counter.
140  *
141  * \param id ID of the counter as set by the API
142  * \param pca Counter array that holds the local counter for this TM
143  * \param x Value to add to this local counter
144  */
146 {
147  StatsPrivateThreadContext *pca = &stats->priv;
148 #if defined (UNITTESTS) || defined (FUZZ)
149  if (pca->initialized == 0)
150  return;
151 #endif
152 #ifdef DEBUG
153  BUG_ON((id.id < 1) || (id.id > pca->size));
154 #endif
155  pca->head[id.id].v += x;
156 }
157 
158 /**
159  * \brief Increments the local counter
160  *
161  * \param id Index of the counter in the counter array
162  * \param pca Counter array that holds the local counters for this TM
163  */
165 {
166  StatsPrivateThreadContext *pca = &stats->priv;
167 #if defined (UNITTESTS) || defined (FUZZ)
168  if (pca->initialized == 0)
169  return;
170 #endif
171 #ifdef DEBUG
172  BUG_ON((id.id < 1) || (id.id > pca->size));
173 #endif
174  pca->head[id.id].v++;
175 }
176 
177 /**
178  * \brief Decrements the local counter
179  *
180  * \param stats per thread counter structure
181  * \param id Index of the counter in the counter array
182  */
184 {
185  StatsPrivateThreadContext *pca = &stats->priv;
186 #if defined(UNITTESTS) || defined(FUZZ)
187  if (pca->initialized == 0)
188  return;
189 #endif
190 #ifdef DEBUG
191  BUG_ON((id.id < 1) || (id.id > pca->size));
192 #endif
193  pca->head[id.id].v--;
194 }
195 
196 /**
197  * \brief set, so overwrite, the value of the local counter
198  *
199  * \param stats per thread counter structure
200  * \param id Index of the local counter in the counter array
201  * \param x The value to set for the counter
202  */
204 {
205  StatsPrivateThreadContext *pca = &stats->priv;
206 #if defined (UNITTESTS) || defined (FUZZ)
207  if (pca->initialized == 0)
208  return;
209 #endif
210 #ifdef DEBUG
211  BUG_ON((id.id < 1) || (id.id > pca->size));
212 #endif
213  pca->head[id.id].v = x;
214 }
215 
216 /**
217  * \brief update the value of the localmax counter
218  *
219  * \param stats per thread counter structure
220  * \param id Index of the local counter in the counter array
221  * \param x The value to set for the counter
222  */
224 {
225  StatsPrivateThreadContext *pca = &stats->priv;
226 #if defined(UNITTESTS) || defined(FUZZ)
227  if (pca->initialized == 0)
228  return;
229 #endif
230 #ifdef DEBUG
231  BUG_ON((id.id < 1) || (id.id > pca->size));
232 #endif
233 
234  if ((int64_t)x > pca->head[id.id].v) {
235  pca->head[id.id].v = x;
236  }
237 }
238 
240 {
241  StatsPrivateThreadContext *pca = &stats->priv;
242 #if defined(UNITTESTS) || defined(FUZZ)
243  if (pca->initialized == 0)
244  return;
245 #endif
246 #ifdef DEBUG
247  BUG_ON((id.id < 1) || (id.id > pca->size));
248 #endif
249 
250  pca->head[id.id].v += x;
251  pca->head[id.id + 1].v++;
252 }
253 
254 static SCConfNode *GetConfig(void)
255 {
256  SCConfNode *stats = SCConfGetNode("stats");
257  if (stats != NULL)
258  return stats;
259 
260  SCConfNode *root = SCConfGetNode("outputs");
261  SCConfNode *node = NULL;
262  if (root != NULL) {
263  TAILQ_FOREACH(node, &root->head, next) {
264  if (strcmp(node->val, "stats") == 0) {
265  return node->head.tqh_first;
266  }
267  }
268  }
269  return NULL;
270 }
271 
272 /**
273  * \brief Initializes stats context
274  */
275 static void StatsInitCtxPreOutput(void)
276 {
277  SCEnter();
278  SCConfNode *stats = GetConfig();
279  if (stats != NULL) {
280  const char *enabled = SCConfNodeLookupChildValue(stats, "enabled");
281  if (enabled != NULL && SCConfValIsFalse(enabled)) {
282  stats_enabled = false;
283  SCLogDebug("Stats module has been disabled");
284  SCReturn;
285  }
286  /* warn if we are using legacy config to enable stats */
287  SCConfNode *gstats = SCConfGetNode("stats");
288  if (gstats == NULL) {
289  SCLogWarning("global stats config is missing. "
290  "Stats enabled through legacy stats.log. "
291  "See %s/configuration/suricata-yaml.html#stats",
292  GetDocURL());
293  }
294 
295  const char *interval = SCConfNodeLookupChildValue(stats, "interval");
296  if (interval != NULL)
297  if (StringParseUint32(&stats_tts, 10, 0, interval) < 0) {
298  SCLogWarning("Invalid value for "
299  "interval: \"%s\". Resetting to %d.",
300  interval, STATS_MGMTT_TTS);
301  stats_tts = STATS_MGMTT_TTS;
302  }
303 
304  int b;
305  int ret = SCConfGetChildValueBool(stats, "decoder-events", &b);
306  if (ret) {
307  stats_decoder_events = (b == 1);
308  }
309  ret = SCConfGetChildValueBool(stats, "stream-events", &b);
310  if (ret) {
311  stats_stream_events = (b == 1);
312  }
313 
314  const char *prefix = NULL;
315  if (SCConfGet("stats.decoder-events-prefix", &prefix) != 1) {
316  prefix = "decoder.event";
317  }
319  }
320  SCReturn;
321 }
322 
323 static void StatsInitCtxPostOutput(void)
324 {
325  SCEnter();
326  /* Store the engine start time */
327  time(&stats_start_time);
328 
329  /* init the lock used by StatsThreadStore */
330  if (SCMutexInit(&stats_ctx->sts_lock, NULL) != 0) {
331  FatalError("error initializing sts mutex");
332  }
333 
334  if (stats_enabled && !OutputStatsLoggersRegistered()) {
335  stats_loggers_active = 0;
336 
337  /* if the unix command socket is enabled we do the background
338  * stats sync just in case someone runs 'dump-counters' */
339  if (!ConfUnixSocketIsEnable()) {
340  SCLogWarning("stats are enabled but no loggers are active");
341  stats_enabled = false;
342  SCReturn;
343  }
344  }
345 
346  SCReturn;
347 }
348 
349 /**
350  * \brief Releases the resources allotted to the output context of the
351  * Stats API
352  */
353 static void StatsReleaseCtx(void)
354 {
355  if (stats_ctx == NULL) {
356  SCLogDebug("Counter module has been disabled");
357  return;
358  }
359 
360  StatsThreadStore *sts = NULL;
361  StatsThreadStore *temp = NULL;
362  sts = stats_ctx->sts;
363 
364  while (sts != NULL) {
365  temp = sts->next;
366  SCFree(sts);
367  sts = temp;
368  }
369 
370  if (stats_ctx->counters_id_hash != NULL) {
371  HashTableFree(stats_ctx->counters_id_hash);
372  stats_ctx->counters_id_hash = NULL;
373  counters_global_id = 0;
374  }
375 
376  StatsPublicThreadContextCleanup(&stats_ctx->global_counter_ctx);
377  SCFree(stats_ctx);
378  stats_ctx = NULL;
379 
380  SCMutexLock(&stats_table_mutex);
381  /* free stats table */
382  if (stats_table.tstats != NULL) {
383  SCFree(stats_table.tstats);
384  stats_table.tstats = NULL;
385  }
386 
387  if (stats_table.stats != NULL) {
388  SCFree(stats_table.stats);
389  stats_table.stats = NULL;
390  }
391  memset(&stats_table, 0, sizeof(stats_table));
392  SCMutexUnlock(&stats_table_mutex);
393 }
394 
395 /**
396  * \brief management thread. This thread is responsible for writing the stats
397  *
398  * \param arg thread var
399  *
400  * \retval NULL This is the value that is always returned
401  */
402 static void *StatsMgmtThread(void *arg)
403 {
404  ThreadVars *tv_local = (ThreadVars *)arg;
405 
406  SCSetThreadName(tv_local->name);
407 
408  if (tv_local->thread_setup_flags != 0)
409  TmThreadSetupOptions(tv_local);
410 
411  /* Set the threads capability */
412  tv_local->cap_flags = 0;
413  SCDropCaps(tv_local);
414 
415  if (stats_ctx == NULL) {
416  SCLogError("Stats API not init"
417  "StatsInitCounterApi() has to be called first");
419  return NULL;
420  }
421 
423  BUG_ON(tm->ThreadInit == NULL);
424  int r = tm->ThreadInit(tv_local, NULL, &stats_thread_data);
425  if (r != 0 || stats_thread_data == NULL) {
426  SCLogError("Stats API "
427  "ThreadInit failed");
429  return NULL;
430  }
431  SCLogDebug("stats_thread_data %p", &stats_thread_data);
432 
434  bool run = TmThreadsWaitForUnpause(tv_local);
435  while (run) {
436  struct timeval cur_timev;
437  gettimeofday(&cur_timev, NULL);
438  struct timespec cond_time = FROM_TIMEVAL(cur_timev);
439  cond_time.tv_sec += (stats_tts);
440 
441  /* wait for the set time, or until we are woken up by
442  * the shutdown procedure */
443  SCCtrlMutexLock(tv_local->ctrl_mutex);
444  while (1) {
445  if (TmThreadsCheckFlag(tv_local, THV_KILL)) {
446  break;
447  }
448  int rc = SCCtrlCondTimedwait(tv_local->ctrl_cond, tv_local->ctrl_mutex, &cond_time);
449  if (rc == ETIMEDOUT || rc < 0) {
450  break;
451  }
452  }
453  SCCtrlMutexUnlock(tv_local->ctrl_mutex);
454 
455  SCMutexLock(&stats_table_mutex);
456  StatsOutput(tv_local);
457  SCMutexUnlock(&stats_table_mutex);
458 
459  if (TmThreadsCheckFlag(tv_local, THV_KILL)) {
460  break;
461  }
462  }
463 
465  TmThreadWaitForFlag(tv_local, THV_DEINIT);
466 
467  r = tm->ThreadDeinit(tv_local, stats_thread_data);
468  if (r != TM_ECODE_OK) {
469  SCLogError("Stats Counter API "
470  "ThreadDeinit failed");
471  }
472 
473  TmThreadsSetFlag(tv_local, THV_CLOSED);
474  return NULL;
475 }
476 
478 {
479  StatsUpdateCounterArray(&stats->priv, &stats->pub);
480 }
481 
483 {
484  if (SC_ATOMIC_GET(stats->pub.sync_now)) {
485  StatsUpdateCounterArray(&stats->priv, &stats->pub);
486  }
487 }
488 
489 /**
490  * \brief Wake up thread. This thread wakes up every TTS(time to sleep) seconds
491  * and sets the flag for every ThreadVars' StatsPublicThreadContext
492  *
493  * \param arg is NULL always
494  *
495  * \retval NULL This is the value that is always returned
496  */
497 static void *StatsWakeupThread(void *arg)
498 {
499  ThreadVars *tv_local = (ThreadVars *)arg;
500 
501  SCSetThreadName(tv_local->name);
502 
503  if (tv_local->thread_setup_flags != 0)
504  TmThreadSetupOptions(tv_local);
505 
506  /* Set the threads capability */
507  tv_local->cap_flags = 0;
508  SCDropCaps(tv_local);
509 
510  if (stats_ctx == NULL) {
511  SCLogError("Stats API not init"
512  "StatsInitCounterApi() has to be called first");
514  return NULL;
515  }
516 
518  bool run = TmThreadsWaitForUnpause(tv_local);
519 
520  while (run) {
521  struct timeval cur_timev;
522  gettimeofday(&cur_timev, NULL);
523  struct timespec cond_time = FROM_TIMEVAL(cur_timev);
524  cond_time.tv_sec += STATS_WUT_TTS;
525 
526  /* wait for the set time, or until we are woken up by
527  * the shutdown procedure */
528  SCCtrlMutexLock(tv_local->ctrl_mutex);
529  while (1) {
530  if (TmThreadsCheckFlag(tv_local, THV_KILL)) {
531  break;
532  }
533  int rc = SCCtrlCondTimedwait(tv_local->ctrl_cond, tv_local->ctrl_mutex, &cond_time);
534  if (rc == ETIMEDOUT || rc < 0) {
535  break;
536  }
537  }
538  SCCtrlMutexUnlock(tv_local->ctrl_mutex);
539 
542  while (tv != NULL) {
543  if (tv->stats.pub.head == NULL) {
544  tv = tv->next;
545  continue;
546  }
547 
548  SC_ATOMIC_SET(tv->stats.pub.sync_now, true);
549 
550  if (tv->inq != NULL) {
551  PacketQueue *q = tv->inq->pq;
552  SCMutexLock(&q->mutex_q);
553  SCCondSignal(&q->cond_q);
554  SCMutexUnlock(&q->mutex_q);
555  }
556 
557  tv = tv->next;
558  }
559 
560  /* mgt threads for flow manager */
561  tv = tv_root[TVT_MGMT];
562  while (tv != NULL) {
563  if (tv->stats.pub.head == NULL) {
564  tv = tv->next;
565  continue;
566  }
567 
568  SC_ATOMIC_SET(tv->stats.pub.sync_now, true);
569 
570  tv = tv->next;
571  }
573 
574  if (TmThreadsCheckFlag(tv_local, THV_KILL)) {
575  break;
576  }
577  }
578 
580  TmThreadWaitForFlag(tv_local, THV_DEINIT);
581  TmThreadsSetFlag(tv_local, THV_CLOSED);
582  return NULL;
583 }
584 
585 /**
586  * \brief Releases a counter
587  *
588  * \param pc Pointer to the StatsCounter to be freed
589  */
590 static void StatsReleaseCounter(StatsCounter *pc)
591 {
592  if (pc != NULL) {
593  SCFree(pc);
594  }
595 }
596 
597 /** \internal
598  * \brief Get ID for counters referenced in a derive counter
599  * \retval id (>=1) or 0 on error
600  */
601 static uint16_t GetIdByName(const StatsPublicThreadContext *pctx, const char *name)
602 {
603  for (const StatsCounter *c = pctx->head; c != NULL; c = c->next) {
604  if (strcmp(name, c->name) == 0) {
605  return c->id;
606  }
607  }
608  return 0;
609 }
610 
611 /**
612  * \brief Registers a counter.
613  *
614  * \param name Name of the counter, to be registered
615  * \param pctx StatsPublicThreadContext for this tm-tv instance
616  * \param type_q Qualifier describing the type of counter to be registered
617  *
618  * \retval the counter id for the newly registered counter, or the already
619  * present counter on success
620  * \retval 0 on failure
621  */
622 static uint16_t StatsRegisterQualifiedCounter(const char *name, StatsPublicThreadContext *pctx,
623  enum StatsType type_q, uint64_t (*Func)(void), const char *dname1, const char *dname2)
624 {
625  StatsCounter **head = &pctx->head;
626  StatsCounter *temp = NULL;
627  StatsCounter *prev = NULL;
628  StatsCounter *pc = NULL;
629 
630  if (name == NULL || pctx == NULL) {
631  SCLogDebug("Counter name, StatsPublicThreadContext NULL");
632  return 0;
633  }
634 
635  temp = prev = *head;
636  while (temp != NULL) {
637  prev = temp;
638 
639  if (strcmp(name, temp->name) == 0) {
640  break;
641  }
642 
643  temp = temp->next;
644  }
645 
646  /* We already have a counter registered by this name */
647  if (temp != NULL)
648  return(temp->id);
649 
650  uint16_t did1 = 0;
651  uint16_t did2 = 0;
652  if (type_q == STATS_TYPE_DERIVE_DIV) {
653  did1 = GetIdByName(pctx, dname1);
654  did2 = GetIdByName(pctx, dname2);
655  if (did1 == 0 || did2 == 0) {
656  return 0;
657  }
658  }
659 
660  /* if we reach this point we don't have a counter registered by this name */
661  if ((pc = SCCalloc(1, sizeof(StatsCounter))) == NULL)
662  return 0;
663 
664  /* assign a unique id to this StatsCounter. The id is local to this
665  * thread context. Please note that the id start from 1, and not 0 */
666  if (type_q == STATS_TYPE_DERIVE_DIV) {
667  pc->id = ++pctx->derive_id;
668  } else {
669  pc->id = ++(pctx->curr_id);
670  }
671  /* for AVG counters we use 2 indices into the tables: one for values,
672  * the other to track updates. */
673  if (type_q == STATS_TYPE_AVERAGE)
674  ++(pctx->curr_id);
675  pc->name = name;
676 
677  /* Precalculate the short name */
678  if (strrchr(name, '.') != NULL) {
679  pc->short_name = &name[strrchr(name, '.') - name + 1];
680  }
681 
682  pc->type = type_q;
683  pc->Func = Func;
684  pc->did1 = did1;
685  pc->did2 = did2;
686 
687  /* we now add the counter to the list */
688  if (prev == NULL)
689  *head = pc;
690  else
691  prev->next = pc;
692 
693  return pc->id;
694 }
695 
696 /**
697  * \brief The output interface for the Stats API
698  */
699 static int StatsOutput(ThreadVars *tv)
700 {
701  const StatsThreadStore *sts = NULL;
702  void *td = stats_thread_data;
703 
704  if (counters_global_id == 0)
705  return -1;
706 
707  if (stats_table.nstats == 0) {
708  StatsThreadRegister("Global", &stats_ctx->global_counter_ctx);
709 
710  uint32_t nstats = counters_global_id;
711 
712  stats_table.nstats = nstats;
713  stats_table.stats = SCCalloc(stats_table.nstats, sizeof(StatsRecord));
714  if (stats_table.stats == NULL) {
715  stats_table.nstats = 0;
716  SCLogError("could not alloc memory for stats");
717  return -1;
718  }
719 
720  stats_table.ntstats = stats_ctx->sts_cnt;
721  uint32_t array_size = stats_table.nstats * sizeof(StatsRecord);
722  stats_table.tstats = SCCalloc(stats_table.ntstats, array_size);
723  if (stats_table.tstats == NULL) {
724  stats_table.ntstats = 0;
725  SCLogError("could not alloc memory for stats");
726  return -1;
727  }
728 
729  stats_table.start_time = stats_start_time;
730  }
731 
732  const uint16_t max_id = counters_global_id;
733  if (max_id == 0)
734  return -1;
735 
736  /** temporary local table to merge the per thread counters,
737  * especially needed for the average counters */
738  struct CountersMergeTable {
739  enum StatsType type;
740  int64_t value;
741  uint64_t updates;
742  } merge_table[max_id];
743  memset(&merge_table, 0x00,
744  max_id * sizeof(struct CountersMergeTable));
745 
746  int thread = stats_ctx->sts_cnt - 1;
747  StatsRecord *table = stats_table.stats;
748 
749  /* Loop through the thread counter stores. The global counters
750  * are in a separate store inside this list. */
751  sts = stats_ctx->sts;
752  SCLogDebug("sts %p", sts);
753  while (sts != NULL) {
754  DEBUG_VALIDATE_BUG_ON(thread < 0);
755 
756  SCLogDebug("Thread %d %s ctx %p", thread, sts->name, sts->ctx);
757 
758  /* temporary table for quickly storing the counters for this
759  * thread store, so that we can post process them outside
760  * of the thread store lock */
761  struct CountersMergeTable thread_table[max_id];
762  memset(&thread_table, 0x00,
763  max_id * sizeof(struct CountersMergeTable));
764 
765  StatsLocalCounter thread_table_from_private[max_id];
766  memset(&thread_table_from_private, 0x00, max_id * sizeof(StatsLocalCounter));
767 
768  /* copy private table to a local variable to loop it w/o lock */
769  bool skip = false;
770  SCSpinLock(&sts->ctx->lock);
771  const uint16_t table_size = sts->ctx->curr_id + sts->ctx->derive_id + 1;
772  if (sts->ctx->copy_of_private == NULL) {
773  skip = true;
774  } else {
775  memcpy(&thread_table_from_private, sts->ctx->copy_of_private,
776  table_size * sizeof(StatsLocalCounter));
777  }
778  SCSpinUnlock(&sts->ctx->lock);
779  if (skip)
780  goto next;
781 
782  /* loop counters and handle them. This includes the global counters, which
783  * access the StatsCounters but don't modify them. */
784  for (uint16_t i = 1; i < table_size; i++) {
785  const StatsCounter *pc = sts->ctx->pc_array[i];
786  thread_table[pc->gid].type = pc->type;
787 
788  table[pc->gid].name = pc->name;
789  table[pc->gid].short_name = pc->short_name;
790 
791  switch (pc->type) {
792  case STATS_TYPE_FUNC:
793  if (pc->Func != NULL)
794  thread_table[pc->gid].value = pc->Func();
795  break;
796  case STATS_TYPE_AVERAGE:
797  thread_table[pc->gid].value = thread_table_from_private[i].v;
798  thread_table[pc->gid].updates = thread_table_from_private[i + 1].v;
799  /* skip updates row */
800  i++;
801  break;
803  SCLogDebug("counter %u/%u is derived from counters %u / %u", pc->id, pc->gid,
804  pc->did1, pc->did2);
805  thread_table[pc->gid].value = thread_table_from_private[pc->did1].v;
806  thread_table[pc->gid].updates = thread_table_from_private[pc->did2].v;
807  break;
808  default:
809  SCLogDebug("Counter %s (%u:%u) value %" PRIu64, pc->name, pc->id, pc->gid,
810  thread_table_from_private[i].v);
811 
812  thread_table[pc->gid].value = thread_table_from_private[i].v;
813  break;
814  }
815  }
816 
817  /* update merge table */
818  for (uint16_t c = 0; c < max_id; c++) {
819  const struct CountersMergeTable *e = &thread_table[c];
820  /* thread only sets type if it has a counter
821  * of this type. */
822  if (e->type == 0)
823  continue;
824 
825  switch (e->type) {
826  case STATS_TYPE_MAXIMUM:
827  if (e->value > merge_table[c].value)
828  merge_table[c].value = e->value;
829  break;
830  case STATS_TYPE_FUNC:
831  merge_table[c].value = e->value;
832  break;
833  case STATS_TYPE_AVERAGE:
834  default:
835  merge_table[c].value += e->value;
836  break;
837  }
838  merge_table[c].updates += e->updates;
839  merge_table[c].type = e->type;
840  }
841 
842  /* update per thread stats table */
843  for (uint16_t c = 0; c < max_id; c++) {
844  const struct CountersMergeTable *e = &thread_table[c];
845  /* thread only sets type if it has a counter
846  * of this type. */
847  if (e->type == 0)
848  continue;
849 
850  uint32_t offset = (thread * stats_table.nstats) + c;
851  StatsRecord *r = &stats_table.tstats[offset];
852  /* xfer previous value to pvalue and reset value */
853  r->pvalue = r->value;
854  r->value = 0;
855  r->name = table[c].name;
856  r->short_name = table[c].short_name;
857  r->tm_name = sts->name;
858 
859  switch (e->type) {
860  case STATS_TYPE_AVERAGE:
862  if (e->value > 0 && e->updates > 0) {
863  r->value = (uint64_t)(e->value / e->updates);
864  }
865  break;
866  default:
867  r->value = e->value;
868  break;
869  }
870  }
871 
872  next:
873  sts = sts->next;
874  thread--;
875  }
876 
877  /* transfer 'merge table' to final stats table */
878  for (uint16_t x = 0; x < max_id; x++) {
879  /* xfer previous value to pvalue and reset value */
880  table[x].pvalue = table[x].value;
881  table[x].value = 0;
882  table[x].tm_name = "Total";
883 
884  const struct CountersMergeTable *m = &merge_table[x];
885  switch (m->type) {
886  case STATS_TYPE_MAXIMUM:
887  if (m->value > table[x].value)
888  table[x].value = m->value;
889  break;
890  case STATS_TYPE_AVERAGE:
892  if (m->value > 0 && m->updates > 0) {
893  table[x].value = (uint64_t)(m->value / m->updates);
894  }
895  break;
896  default:
897  table[x].value += m->value;
898  break;
899  }
900  }
901 
902  /* invoke logger(s) */
903  if (stats_loggers_active) {
904  OutputStatsLog(tv, td, &stats_table);
905  }
906  return 1;
907 }
908 
909 #ifdef BUILD_UNIX_SOCKET
910 /** \brief callback for getting stats into unix socket
911  */
912 TmEcode StatsOutputCounterSocket(json_t *cmd,
913  json_t *answer, void *data)
914 {
915  json_t *message = NULL;
916  TmEcode r = TM_ECODE_OK;
917 
918  if (!stats_enabled) {
919  r = TM_ECODE_FAILED;
920  message = json_string("stats are disabled in the config");
921  } else {
922  SCMutexLock(&stats_table_mutex);
923  if (stats_table.start_time == 0) {
924  r = TM_ECODE_FAILED;
925  message = json_string("stats not yet synchronized");
926  } else {
927  message = StatsToJSON(&stats_table, JSON_STATS_TOTALS|JSON_STATS_THREADS);
928  }
929  SCMutexUnlock(&stats_table_mutex);
930  }
931  json_object_set_new(answer, "message", message);
932  return r;
933 }
934 #endif /* BUILD_UNIX_SOCKET */
935 
936 static void StatsLogSummary(void)
937 {
938  if (!stats_enabled) {
939  return;
940  }
941  uint64_t alerts = 0;
942  SCMutexLock(&stats_table_mutex);
943  if (stats_table.start_time != 0) {
944  const StatsTable *st = &stats_table;
945  for (uint32_t u = 0; u < st->nstats; u++) {
946  const char *name = st->stats[u].name;
947  if (name == NULL || strcmp(name, "detect.alert") != 0)
948  continue;
949  alerts = st->stats[u].value;
950  break;
951  }
952  }
953  SCMutexUnlock(&stats_table_mutex);
954  SCLogInfo("Alerts: %"PRIu64, alerts);
955 }
956 
957 /**
958  * \brief Initializes the perf counter api. Things are hard coded currently.
959  * More work to be done when we implement multiple interfaces
960  */
961 void StatsInit(void)
962 {
963  BUG_ON(stats_ctx != NULL);
964  if ((stats_ctx = SCCalloc(1, sizeof(StatsGlobalContext))) == NULL) {
965  FatalError("Fatal error encountered in StatsInitCtx. Exiting...");
966  }
967 
968  StatsPublicThreadContextInit(&stats_ctx->global_counter_ctx);
969 }
970 
972 {
973  StatsInitCtxPreOutput();
974 }
975 
977 {
978  StatsInitCtxPostOutput();
979 }
980 
981 
982 /**
983  * \brief Spawns the wakeup, and the management thread used by the stats api
984  *
985  * The threads use the condition variable in the thread vars to control
986  * their wait loops to make sure the main thread can quickly kill them.
987  */
989 {
990  SCEnter();
991 
992  if (!stats_enabled) {
993  SCReturn;
994  }
995 
996  ThreadVars *tv_wakeup = NULL;
997  ThreadVars *tv_mgmt = NULL;
998 
999  /* spawn the stats wakeup thread */
1001  StatsWakeupThread, 1);
1002  if (tv_wakeup == NULL) {
1003  FatalError("TmThreadCreateMgmtThread "
1004  "failed");
1005  }
1006 
1007  if (TmThreadSpawn(tv_wakeup) != 0) {
1008  FatalError("TmThreadSpawn failed for "
1009  "StatsWakeupThread");
1010  }
1011 
1012  /* spawn the stats mgmt thread */
1014  StatsMgmtThread, 1);
1015  if (tv_mgmt == NULL) {
1016  FatalError("TmThreadCreateMgmtThread failed");
1017  }
1018 
1019  if (TmThreadSpawn(tv_mgmt) != 0) {
1020  FatalError("TmThreadSpawn failed for "
1021  "StatsWakeupThread");
1022  }
1023 
1024  SCReturn;
1025 }
1026 
1027 /**
1028  * \brief Registers a normal, unqualified counter
1029  *
1030  * \param name Name of the counter, to be registered
1031  * \param tv Pointer to the ThreadVars instance for which the counter would
1032  * be registered
1033  *
1034  * \retval id Counter id for the newly registered counter, or the already
1035  * present counter
1036  */
1038 {
1039  uint16_t id =
1040  StatsRegisterQualifiedCounter(name, &stats->pub, STATS_TYPE_NORMAL, NULL, NULL, NULL);
1041  StatsCounterId s = { .id = id };
1042  return s;
1043 }
1044 
1045 /**
1046  * \brief Registers a counter, whose value holds the average of all the values
1047  * assigned to it.
1048  *
1049  * \param name Name of the counter, to be registered
1050  * \param tv Pointer to the ThreadVars instance for which the counter would
1051  * be registered
1052  *
1053  * \retval id Counter id for the newly registered counter, or the already
1054  * present counter
1055  */
1057 {
1058  uint16_t id =
1059  StatsRegisterQualifiedCounter(name, &stats->pub, STATS_TYPE_AVERAGE, NULL, NULL, NULL);
1060  StatsCounterAvgId s = { .id = id };
1061  return s;
1062 }
1063 
1064 /**
1065  * \brief Registers a counter, whose value holds the maximum of all the values
1066  * assigned to it.
1067  *
1068  * \param name Name of the counter, to be registered
1069  * \param tv Pointer to the ThreadVars instance for which the counter would
1070  * be registered
1071  *
1072  * \retval the counter id for the newly registered counter, or the already
1073  * present counter
1074  */
1076 {
1077  uint16_t id =
1078  StatsRegisterQualifiedCounter(name, &stats->pub, STATS_TYPE_MAXIMUM, NULL, NULL, NULL);
1079  StatsCounterMaxId s = { .id = id };
1080  return s;
1081 }
1082 
1083 /**
1084  * \brief Registers a counter, which represents a global value
1085  *
1086  * \param name Name of the counter, to be registered
1087  * \param Func Function Pointer returning a uint64_t
1088  *
1089  * \retval id Counter id for the newly registered counter, or the already
1090  * present counter
1091  */
1092 StatsCounterGlobalId StatsRegisterGlobalCounter(const char *name, uint64_t (*Func)(void))
1093 {
1094  StatsCounterGlobalId s = { .id = 0 };
1095 #if defined (UNITTESTS) || defined (FUZZ)
1096  if (stats_ctx == NULL)
1097  return s;
1098 #else
1099  BUG_ON(stats_ctx == NULL);
1100 #endif
1101  uint16_t id = StatsRegisterQualifiedCounter(
1102  name, &(stats_ctx->global_counter_ctx), STATS_TYPE_FUNC, Func, NULL, NULL);
1103  s.id = id;
1104  return s;
1105 }
1106 
1107 /**
1108  * \brief Registers a counter which tracks the result of the calculating the value
1109  * of counter dname1 divided by the value of the counter dname2
1110  *
1111  * \param name Name of the counter, to be registered
1112  * \param dname1 First counter name
1113  * \param dname2 Second counter name
1114  *
1115  * Both counters need to already be registered in this thread.
1116  *
1117  * \retval id Counter id for the newly registered counter, or the already
1118  * present counter
1119  */
1121  const char *name, const char *dname1, const char *dname2, StatsThreadContext *stats)
1122 {
1123  StatsCounterDeriveId s = { .id = 0 };
1124 #if defined(UNITTESTS) || defined(FUZZ)
1125  if (stats_ctx == NULL)
1126  return s;
1127 #else
1128  BUG_ON(stats_ctx == NULL);
1129 #endif
1130  uint16_t id = StatsRegisterQualifiedCounter(
1131  name, &stats->pub, STATS_TYPE_DERIVE_DIV, NULL, dname1, dname2);
1132  s.id = id;
1133  return s;
1134 }
1135 
1136 typedef struct CountersIdType_ {
1137  uint16_t id;
1138  const char *string;
1140 
1141 static uint32_t CountersIdHashFunc(HashTable *ht, void *data, uint16_t datalen)
1142 {
1143  CountersIdType *t = (CountersIdType *)data;
1144  uint32_t hash = 0;
1145  size_t len = strlen(t->string);
1146 
1147  for (size_t i = 0; i < len; i++)
1148  hash += u8_tolower((unsigned char)t->string[i]);
1149 
1150  hash = hash % ht->array_size;
1151  return hash;
1152 }
1153 
1154 static char CountersIdHashCompareFunc(void *data1, uint16_t datalen1,
1155  void *data2, uint16_t datalen2)
1156 {
1157  CountersIdType *t1 = (CountersIdType *)data1;
1158  CountersIdType *t2 = (CountersIdType *)data2;
1159 
1160  if (t1 == NULL || t2 == NULL)
1161  return 0;
1162 
1163  if (t1->string == NULL || t2->string == NULL)
1164  return 0;
1165 
1166  return strcmp(t1->string, t2->string) == 0;
1167 }
1168 
1169 static void CountersIdHashFreeFunc(void *data)
1170 {
1171  SCFree(data);
1172 }
1173 
1174 static int StatsThreadSetupPublic(StatsPublicThreadContext *pctx)
1175 {
1176  size_t array_size = pctx->curr_id + pctx->derive_id + 1;
1177  pctx->pc_array = SCCalloc(array_size, sizeof(StatsCounter *));
1178  if (pctx->pc_array == NULL) {
1179  return -1;
1180  }
1181  /* regular counters that get direct updates by their id as idx */
1182  for (StatsCounter *pc = pctx->head; pc != NULL; pc = pc->next) {
1183  if (pc->type != STATS_TYPE_DERIVE_DIV) {
1184  SCLogDebug("pc %s gid %u id %u", pc->name, pc->gid, pc->id);
1185  BUG_ON(pctx->pc_array[pc->id] != NULL);
1186  pctx->pc_array[pc->id] = pc;
1187  }
1188  }
1189  /* derive counters are not updated by the thread itself and will be put
1190  * at the end of the array */
1191  for (StatsCounter *pc = pctx->head; pc != NULL; pc = pc->next) {
1192  if (pc->type == STATS_TYPE_DERIVE_DIV) {
1193  uint16_t id = pctx->curr_id + pc->id;
1194  SCLogDebug("STATS_TYPE_DERIVE_DIV: pc %s gid %u pc->id %u id %u", pc->name, pc->gid,
1195  pc->id, id);
1196  BUG_ON(pctx->pc_array[id] != NULL);
1197  pctx->pc_array[id] = pc;
1198  }
1199  }
1200 
1201  SCLogDebug("array_size %u memory %" PRIu64, (uint32_t)array_size,
1202  (uint64_t)(array_size * sizeof(StatsLocalCounter)));
1203  pctx->copy_of_private = SCCalloc(array_size, sizeof(StatsLocalCounter));
1204  if (pctx->copy_of_private == NULL) {
1205  return -1;
1206  }
1207  return 0;
1208 }
1209 
1210 /** \internal
1211  * \brief Adds a TM to the clubbed TM table. Multiple instances of the same TM
1212  * are stacked together in a PCTMI container.
1213  *
1214  * \param tm_name Name of the tm to be added to the table
1215  * \param pctx StatsPublicThreadContext associated with the TM tm_name
1216  *
1217  * \retval 1 on success, 0 on failure
1218  */
1219 static int StatsThreadRegister(const char *thread_name, StatsPublicThreadContext *pctx)
1220 {
1221  if (stats_ctx == NULL) {
1222  return 1;
1223  }
1224 
1225  if (thread_name == NULL || pctx == NULL) {
1226  SCLogDebug("supplied argument(s) to StatsThreadRegister NULL");
1227  return 0;
1228  }
1229 
1230  SCMutexLock(&stats_ctx->sts_lock);
1231  SCLogDebug("thread %s", thread_name);
1232  if (stats_ctx->counters_id_hash == NULL) {
1233  stats_ctx->counters_id_hash = HashTableInit(256, CountersIdHashFunc,
1234  CountersIdHashCompareFunc,
1235  CountersIdHashFreeFunc);
1236  if (stats_ctx->counters_id_hash == NULL) {
1237  SCMutexUnlock(&stats_ctx->sts_lock);
1238  return 0;
1239  }
1240  }
1241  StatsCounter *pc = pctx->head;
1242  while (pc != NULL) {
1243  CountersIdType t = { 0, pc->name }, *id = NULL;
1244  id = HashTableLookup(stats_ctx->counters_id_hash, &t, sizeof(t));
1245  if (id == NULL) {
1246  id = SCCalloc(1, sizeof(*id));
1247  BUG_ON(id == NULL);
1248  id->id = counters_global_id++;
1249  id->string = pc->name;
1250  int r = HashTableAdd(stats_ctx->counters_id_hash, id, sizeof(*id));
1251  DEBUG_VALIDATE_BUG_ON(r < 0);
1252  if (r < 0) {
1253  SCMutexUnlock(&stats_ctx->sts_lock);
1254  return 0;
1255  }
1256  }
1257  pc->gid = id->id;
1258  pc = pc->next;
1259  }
1260 
1261  if (StatsThreadSetupPublic(pctx) != 0) {
1262  SCLogDebug("failed to setup StatsThreadSetupPublic");
1263  SCMutexUnlock(&stats_ctx->sts_lock);
1264  return 0;
1265  }
1266 
1267  StatsThreadStore *temp = NULL;
1268  if ((temp = SCCalloc(1, sizeof(StatsThreadStore))) == NULL) {
1269  SCMutexUnlock(&stats_ctx->sts_lock);
1270  return 0;
1271  }
1272 
1273  temp->ctx = pctx;
1274  temp->name = thread_name;
1275 
1276  temp->next = stats_ctx->sts;
1277  stats_ctx->sts = temp;
1278  stats_ctx->sts_cnt++;
1279  SCLogDebug("stats_ctx->sts %p", stats_ctx->sts);
1280 
1281  SCMutexUnlock(&stats_ctx->sts_lock);
1282  return 1;
1283 }
1284 
1285 /** \internal
1286  * \brief Returns a counter array for all counters registered for this tm
1287  * instance
1288  *
1289  * \param pctx Pointer to the tv's StatsPublicThreadContext
1290  *
1291  * \retval pca Pointer to a counter-array for all counter of this tm instance
1292  * on success; NULL on failure
1293  */
1294 static int StatsGetAllCountersArray(
1296 {
1297  if (pctx == NULL || private == NULL)
1298  return -1;
1299 
1300  private->size = pctx->curr_id + 1;
1301 
1302  private->head = SCCalloc(private->size, sizeof(StatsLocalCounter));
1303  if (private->head == NULL) {
1304  return -1;
1305  }
1306 
1307  private->initialized = 1;
1308  return 0;
1309 }
1310 
1311 int StatsSetupPrivate(StatsThreadContext *stats, const char *thread_name)
1312 {
1313  int r = StatsGetAllCountersArray(&stats->pub, &stats->priv);
1314  if (r < 0) {
1315  return -1;
1316  }
1317 
1318  r = StatsThreadRegister(thread_name, &stats->pub);
1319  if (r != 1) {
1320  return -2;
1321  }
1322  return 0;
1323 }
1324 
1325 static void StatsThreadInitPublic(StatsPublicThreadContext *pctx)
1326 {
1327  memset(pctx, 0x00, sizeof(*pctx));
1328  SCSpinInit(&pctx->lock, 0);
1329 }
1330 
1332 {
1333  StatsThreadInitPublic(&stats->pub);
1334 }
1335 
1336 /**
1337  * \brief the private stats store with the public stats store
1338  *
1339  * \param pca Pointer to the StatsPrivateThreadContext
1340  * \param pctx Pointer the tv's StatsPublicThreadContext
1341  *
1342  * \retval 1 on success
1343  * \retval -1 on error
1344  */
1345 static int StatsUpdateCounterArray(StatsPrivateThreadContext *pca, StatsPublicThreadContext *pctx)
1346 {
1347 
1348  if (pca == NULL || pctx == NULL) {
1349  SCLogDebug("pca or pctx is NULL inside StatsUpdateCounterArray");
1350  return -1;
1351  }
1352 
1353  if (pca->size > 0 && pctx->copy_of_private != NULL) {
1354  /* copy the whole table under lock to the public section
1355  * and release the lock. The stats thread will copy it from
1356  * there. */
1357  SCSpinLock(&pctx->lock);
1358  memcpy(pctx->copy_of_private, pca->head, pca->size * sizeof(StatsLocalCounter));
1359  SCSpinUnlock(&pctx->lock);
1360  }
1361  SC_ATOMIC_SET(pctx->sync_now, false);
1362  return 1;
1363 }
1364 
1365 /**
1366  * \brief Get the value of the local copy of the counter that hold this id.
1367  *
1368  * \param tv threadvars
1369  * \param id The counter id.
1370  *
1371  * \retval 0 on success.
1372  * \retval -1 on error.
1373  */
1375 {
1376  StatsPrivateThreadContext *pca = &stats->priv;
1377 #ifdef DEBUG
1378  BUG_ON((id.id < 1) || (id.id > pca->size));
1379 #endif
1380  return pca->head[id.id].v;
1381 }
1382 
1383 /**
1384  * \brief Releases the resources allotted by the Stats API
1385  */
1387 {
1388  StatsLogSummary();
1389  StatsReleaseCtx();
1390 }
1391 
1392 /**
1393  * \brief Releases counters
1394  *
1395  * \param head Pointer to the head of the list of perf counters that have to
1396  * be freed
1397  */
1398 static void StatsReleaseCounters(StatsCounter *head)
1399 {
1400  StatsCounter *pc = NULL;
1401 
1402  while (head != NULL) {
1403  pc = head;
1404  head = head->next;
1405  StatsReleaseCounter(pc);
1406  }
1407 }
1408 
1409 /** \internal
1410  * \brief Releases the StatsPrivateThreadContext allocated by the user,
1411  * for storing and updating local counter values
1412  *
1413  * \param pca Pointer to the StatsPrivateThreadContext
1414  */
1415 static void StatsReleasePrivateThreadContext(StatsPrivateThreadContext *pca)
1416 {
1417  if (pca != NULL) {
1418  if (pca->head != NULL) {
1419  SCFree(pca->head);
1420  pca->head = NULL;
1421  pca->size = 0;
1422  }
1423  pca->initialized = 0;
1424  }
1425 }
1426 
1428 {
1429  StatsPublicThreadContextCleanup(&stats->pub);
1430  StatsReleasePrivateThreadContext(&stats->priv);
1431 }
1432 
1433 /*----------------------------------Unit_Tests--------------------------------*/
1434 
1435 #ifdef UNITTESTS
1436 /** \internal
1437  * \brief Registers a normal, unqualified counter
1438  *
1439  * \param name Name of the counter, to be registered
1440  * \param type Datatype of this counter variable
1441  * \param pctx StatsPublicThreadContext corresponding to the tm_name key under which the
1442  * key has to be registered
1443  *
1444  * \retval id Counter id for the newly registered counter, or the already
1445  * present counter
1446  */
1447 static StatsCounterId RegisterCounter(
1448  const char *name, const char *tm_name, StatsPublicThreadContext *pctx)
1449 {
1450  uint16_t id = StatsRegisterQualifiedCounter(name, pctx, STATS_TYPE_NORMAL, NULL, NULL, NULL);
1451  StatsCounterId s = { .id = id };
1452  return s;
1453 }
1454 
1455 static int StatsTestCounterReg02(void)
1456 {
1458  StatsThreadInitPublic(&pctx);
1459 
1460  StatsCounterId id = RegisterCounter(NULL, NULL, &pctx);
1461  FAIL_IF_NOT(id.id == 0);
1462  PASS;
1463 }
1464 
1465 static int StatsTestCounterReg03(void)
1466 {
1468  StatsThreadInitPublic(&pctx);
1469 
1470  StatsCounterId id = RegisterCounter("t1", "c1", &pctx);
1471  FAIL_IF_NOT(id.id == 1);
1472 
1473  StatsReleaseCounters(pctx.head);
1474  PASS;
1475 }
1476 
1477 static int StatsTestCounterReg04(void)
1478 {
1480  StatsThreadInitPublic(&pctx);
1481 
1482  StatsCounterId c1 = RegisterCounter("t1", "c1", &pctx);
1483  FAIL_IF_NOT(c1.id == 1);
1484  StatsCounterId c2 = RegisterCounter("t2", "c2", &pctx);
1485  FAIL_IF_NOT(c2.id == 2);
1486  StatsCounterId c3 = RegisterCounter("t3", "c3", &pctx);
1487  FAIL_IF_NOT(c3.id == 3);
1488  StatsCounterId id = RegisterCounter("t1", "c1", &pctx);
1489  FAIL_IF_NOT(id.id == 1);
1490 
1491  StatsReleaseCounters(pctx.head);
1492  PASS;
1493 }
1494 
1495 static int StatsTestGetCntArray05(void)
1496 {
1497  ThreadVars tv;
1498  memset(&tv, 0, sizeof(ThreadVars));
1500  StatsCounterId c1 = RegisterCounter("t1", "c1", &tv.stats.pub);
1501  FAIL_IF(c1.id != 1);
1502  int r = StatsGetAllCountersArray(NULL, &tv.stats.priv);
1503  FAIL_IF_NOT(r == -1);
1505  PASS;
1506 }
1507 
1508 static int StatsTestGetCntArray06(void)
1509 {
1510  ThreadVars tv;
1511  memset(&tv, 0, sizeof(ThreadVars));
1513  StatsCounterId c1 = RegisterCounter("t1", "c1", &tv.stats.pub);
1514  FAIL_IF(c1.id != 1);
1515  StatsThreadSetupPublic(&tv.stats.pub);
1516  int r = StatsGetAllCountersArray(&tv.stats.pub, &tv.stats.priv);
1517  FAIL_IF_NOT(r == 0);
1519  PASS;
1520 }
1521 
1522 static int StatsTestCntArraySize07(void)
1523 {
1524  ThreadVars tv;
1525  memset(&tv, 0, sizeof(ThreadVars));
1527  StatsPrivateThreadContext *pca = NULL;
1528 
1529  StatsCounterId id1 = RegisterCounter("t1", "c1", &tv.stats.pub);
1530  StatsCounterId id2 = RegisterCounter("t2", "c2", &tv.stats.pub);
1531 
1532  StatsThreadSetupPublic(&tv.stats.pub);
1533  StatsGetAllCountersArray(&tv.stats.pub, &tv.stats.priv);
1534  pca = &tv.stats.priv;
1535 
1536  StatsCounterIncr(&tv.stats, id1);
1537  StatsCounterIncr(&tv.stats, id2);
1538 
1539  FAIL_IF_NOT(pca->size == 3);
1540 
1542  PASS;
1543 }
1544 
1545 static int StatsTestUpdateCounter08(void)
1546 {
1547  ThreadVars tv;
1548  memset(&tv, 0, sizeof(ThreadVars));
1550  StatsCounterId c1 = RegisterCounter("t1", "c1", &tv.stats.pub);
1551  StatsThreadSetupPublic(&tv.stats.pub);
1552  StatsGetAllCountersArray(&tv.stats.pub, &tv.stats.priv);
1554 
1555  StatsCounterIncr(&tv.stats, c1);
1556  StatsCounterAddI64(&tv.stats, c1, 100);
1557  FAIL_IF_NOT(pca->head[c1.id].v == 101);
1558 
1560  PASS;
1561 }
1562 
1563 static int StatsTestUpdateCounter09(void)
1564 {
1565  ThreadVars tv;
1566  memset(&tv, 0, sizeof(ThreadVars));
1568 
1569  StatsCounterId c1 = RegisterCounter("t1", "c1", &tv.stats.pub);
1570  RegisterCounter("t2", "c2", &tv.stats.pub);
1571  RegisterCounter("t3", "c3", &tv.stats.pub);
1572  RegisterCounter("t4", "c4", &tv.stats.pub);
1573  StatsCounterId c5 = RegisterCounter("t5", "c5", &tv.stats.pub);
1574 
1575  StatsThreadSetupPublic(&tv.stats.pub);
1576  StatsGetAllCountersArray(&tv.stats.pub, &tv.stats.priv);
1578 
1579  StatsCounterIncr(&tv.stats, c5);
1580  StatsCounterAddI64(&tv.stats, c5, 100);
1581 
1582  FAIL_IF_NOT(pca->head[c1.id].v == 0);
1583  FAIL_IF_NOT(pca->head[c5.id].v == 101);
1584 
1586  PASS;
1587 }
1588 
1589 static int StatsTestUpdateGlobalCounter10(void)
1590 {
1591  ThreadVars tv;
1592  memset(&tv, 0, sizeof(ThreadVars));
1594 
1595  StatsCounterId c1 = RegisterCounter("t1", "c1", &tv.stats.pub);
1596  StatsCounterId c2 = RegisterCounter("t2", "c2", &tv.stats.pub);
1597  StatsCounterId c3 = RegisterCounter("t3", "c3", &tv.stats.pub);
1598 
1599  StatsThreadSetupPublic(&tv.stats.pub);
1600  StatsGetAllCountersArray(&tv.stats.pub, &tv.stats.priv);
1602 
1603  StatsCounterIncr(&tv.stats, c1);
1604  StatsCounterAddI64(&tv.stats, c2, 100);
1605  StatsCounterIncr(&tv.stats, c3);
1606  StatsCounterAddI64(&tv.stats, c3, 100);
1607 
1608  StatsUpdateCounterArray(pca, &tv.stats.pub);
1609 
1611  FAIL_IF_NOT(100 == tv.stats.pub.copy_of_private[c2.id].v);
1612  FAIL_IF_NOT(101 == tv.stats.pub.copy_of_private[c3.id].v);
1613 
1615  PASS;
1616 }
1617 
1618 static int StatsTestCounterValues11(void)
1619 {
1620  ThreadVars tv;
1621  memset(&tv, 0, sizeof(ThreadVars));
1623 
1624  StatsCounterId c1 = RegisterCounter("t1", "c1", &tv.stats.pub);
1625  StatsCounterId c2 = RegisterCounter("t2", "c2", &tv.stats.pub);
1626  StatsCounterId c3 = RegisterCounter("t3", "c3", &tv.stats.pub);
1627  StatsCounterId c4 = RegisterCounter("t4", "c4", &tv.stats.pub);
1628 
1629  StatsThreadSetupPublic(&tv.stats.pub);
1630  StatsGetAllCountersArray(&tv.stats.pub, &tv.stats.priv);
1632 
1633  StatsCounterIncr(&tv.stats, c1);
1634  StatsCounterAddI64(&tv.stats, c2, 256);
1635  StatsCounterAddI64(&tv.stats, c3, 257);
1636  StatsCounterAddI64(&tv.stats, c4, 16843024);
1637 
1638  StatsUpdateCounterArray(pca, &tv.stats.pub);
1639 
1641  FAIL_IF_NOT(256 == tv.stats.pub.copy_of_private[c2.id].v);
1642  FAIL_IF_NOT(257 == tv.stats.pub.copy_of_private[c3.id].v);
1643  FAIL_IF_NOT(16843024 == tv.stats.pub.copy_of_private[c4.id].v);
1644 
1646  PASS;
1647 }
1648 
1649 #endif
1650 
1652 {
1653 #ifdef UNITTESTS
1654  UtRegisterTest("StatsTestCounterReg02", StatsTestCounterReg02);
1655  UtRegisterTest("StatsTestCounterReg03", StatsTestCounterReg03);
1656  UtRegisterTest("StatsTestCounterReg04", StatsTestCounterReg04);
1657  UtRegisterTest("StatsTestGetCntArray05", StatsTestGetCntArray05);
1658  UtRegisterTest("StatsTestGetCntArray06", StatsTestGetCntArray06);
1659  UtRegisterTest("StatsTestCntArraySize07", StatsTestCntArraySize07);
1660  UtRegisterTest("StatsTestUpdateCounter08", StatsTestUpdateCounter08);
1661  UtRegisterTest("StatsTestUpdateCounter09", StatsTestUpdateCounter09);
1662  UtRegisterTest("StatsTestUpdateGlobalCounter10",
1663  StatsTestUpdateGlobalCounter10);
1664  UtRegisterTest("StatsTestCounterValues11", StatsTestCounterValues11);
1665 #endif
1666 }
StatsPublicThreadContext_::lock
SCSpinlock lock
Definition: counters.h:115
util-byte.h
tm-threads.h
FROM_TIMEVAL
#define FROM_TIMEVAL(timev)
initialize a 'struct timespec' from a 'struct timeval'.
Definition: util-time.h:124
StatsReleaseResources
void StatsReleaseResources(void)
Releases the resources allotted by the Stats API.
Definition: counters.c:1386
StatsRegisterGlobalCounter
StatsCounterGlobalId StatsRegisterGlobalCounter(const char *name, uint64_t(*Func)(void))
Registers a counter, which represents a global value.
Definition: counters.c:1092
thread_name_counter_wakeup
const char * thread_name_counter_wakeup
Definition: runmodes.c:76
StatsTable_::ntstats
uint32_t ntstats
Definition: output-stats.h:43
len
uint8_t len
Definition: app-layer-dnp3.h:2
StatsCounterMaxUpdateI64
void StatsCounterMaxUpdateI64(StatsThreadContext *stats, StatsCounterMaxId id, int64_t x)
update the value of the localmax counter
Definition: counters.c:223
TmThreadSpawn
TmEcode TmThreadSpawn(ThreadVars *tv)
Spawns a thread associated with the ThreadVars instance tv.
Definition: tm-threads.c:1702
SCSpinDestroy
#define SCSpinDestroy
Definition: threads-debug.h:240
TmThreadSetupOptions
TmEcode TmThreadSetupOptions(ThreadVars *tv)
Set the thread options (cpu affinitythread). Priority should be already set by pthread_create.
Definition: tm-threads.c:863
offset
uint64_t offset
Definition: util-streaming-buffer.h:0
ThreadVars_::name
char name[16]
Definition: threadvars.h:65
StatsSyncCountersIfSignalled
void StatsSyncCountersIfSignalled(StatsThreadContext *stats)
Definition: counters.c:482
StatsThreadStore_
per thread store of counters
Definition: counters.c:65
StatsGlobalContext_
Holds the output interface context for the counter api.
Definition: counters.c:77
SC_ATOMIC_SET
#define SC_ATOMIC_SET(name, val)
Set the value for the atomic variable.
Definition: util-atomic.h:386
UtRegisterTest
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
Definition: util-unittest.c:103
StatsRecord
struct StatsRecord_ StatsRecord
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:282
StatsRegisterCounter
StatsCounterId StatsRegisterCounter(const char *name, StatsThreadContext *stats)
Registers a normal, unqualified counter.
Definition: counters.c:1037
TmThreadsSetFlag
void TmThreadsSetFlag(ThreadVars *tv, uint32_t flag)
Set a thread flag.
Definition: tm-threads.c:101
StatsSetupPostConfigPreOutput
void StatsSetupPostConfigPreOutput(void)
Definition: counters.c:971
TmThreadWaitForFlag
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...
Definition: tm-threads.c:1820
STATS_MGMTT_TTS
#define STATS_MGMTT_TTS
Definition: counters.c:48
next
struct HtpBodyChunk_ * next
Definition: app-layer-htp.h:0
StatsCounter_::type
int type
Definition: counters.h:56
stats_stream_events
bool stats_stream_events
Definition: counters.c:100
name
const char * name
Definition: detect-engine-proto.c:48
PacketQueue_
simple fifo queue for packets with mutex and cond Calling the mutex or triggering the cond is respons...
Definition: packet-queue.h:49
TMM_STATSLOGGER
@ TMM_STATSLOGGER
Definition: tm-threads-common.h:61
THV_DEINIT
#define THV_DEINIT
Definition: threadvars.h:45
CountersIdType
struct CountersIdType_ CountersIdType
StatsCounter_
Container to hold the counter variable.
Definition: counters.h:55
thread_name_counter_stats
const char * thread_name_counter_stats
Definition: runmodes.c:75
Tmq_::pq
PacketQueue * pq
Definition: tm-queues.h:35
SCSetThreadName
#define SCSetThreadName(n)
Definition: threads.h:305
util-hash.h
StatsRecord_
Definition: output-stats.h:31
StatsPublicThreadContext_::copy_of_private
StatsLocalCounter * copy_of_private
Definition: counters.h:112
SCConfGet
int SCConfGet(const char *name, const char **vptr)
Retrieve the value of a configuration node.
Definition: conf.c:351
THV_RUNNING
#define THV_RUNNING
Definition: threadvars.h:55
StatsCounter_::name
const char * name
Definition: counters.h:74
TAILQ_FOREACH
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:252
SCConfGetChildValueBool
int SCConfGetChildValueBool(const SCConfNode *base, const char *name, int *val)
Definition: conf.c:516
StatsCounter_::did1
uint16_t did1
Definition: counters.h:66
StatsCounter_::Func
uint64_t(* Func)(void)
Definition: counters.h:71
SCMutexLock
#define SCMutexLock(mut)
Definition: threads-debug.h:117
HashTable_
Definition: util-hash.h:35
u8_tolower
#define u8_tolower(c)
Definition: suricata-common.h:453
tv_root
ThreadVars * tv_root[TVT_MAX]
Definition: tm-threads.c:82
SCSpinLock
#define SCSpinLock
Definition: threads-debug.h:236
SCConfValIsFalse
int SCConfValIsFalse(const char *val)
Check if a value is false.
Definition: conf.c:577
StatsInit
void StatsInit(void)
Initializes the perf counter api. Things are hard coded currently. More work to be done when we imple...
Definition: counters.c:961
STATS_TYPE_AVERAGE
@ STATS_TYPE_AVERAGE
Definition: counters.c:56
util-privs.h
SCMUTEX_INITIALIZER
#define SCMUTEX_INITIALIZER
Definition: threads-debug.h:122
CountersIdType_::string
const char * string
Definition: counters.c:1138
SCDropCaps
#define SCDropCaps(...)
Definition: util-privs.h:89
StatsCounterId
Definition: counters.h:30
m
SCMutex m
Definition: flow-hash.h:6
SCConfNodeLookupChildValue
const char * SCConfNodeLookupChildValue(const SCConfNode *node, const char *name)
Lookup the value of a child configuration node by name.
Definition: conf.c:855
JSON_STATS_TOTALS
#define JSON_STATS_TOTALS
Definition: output-json-stats.h:29
StatsRecord_::pvalue
int64_t pvalue
Definition: output-stats.h:36
TM_ECODE_FAILED
@ TM_ECODE_FAILED
Definition: tm-threads-common.h:82
STATS_TYPE_FUNC
@ STATS_TYPE_FUNC
Definition: counters.c:58
StatsRegisterAvgCounter
StatsCounterAvgId StatsRegisterAvgCounter(const char *name, StatsThreadContext *stats)
Registers a counter, whose value holds the average of all the values assigned to it.
Definition: counters.c:1056
StatsCounterDecr
void StatsCounterDecr(StatsThreadContext *stats, StatsCounterId id)
Decrements the local counter.
Definition: counters.c:183
FAIL_IF_NOT
#define FAIL_IF_NOT(expr)
Fail a test if expression evaluates to false.
Definition: util-unittest.h:82
TM_ECODE_OK
@ TM_ECODE_OK
Definition: tm-threads-common.h:81
HashTableFree
void HashTableFree(HashTable *ht)
Free a HashTable and all its contents.
Definition: util-hash.c:100
ThreadVars_::cap_flags
uint8_t cap_flags
Definition: threadvars.h:80
HashTable_::array_size
uint32_t array_size
Definition: util-hash.h:37
TmModule_::ThreadDeinit
TmEcode(* ThreadDeinit)(ThreadVars *, void *)
Definition: tm-modules.h:53
PacketQueue_::mutex_q
SCMutex mutex_q
Definition: packet-queue.h:56
StatsThreadStore_::next
struct StatsThreadStore_ * next
Definition: counters.c:71
stats_decoder_events_prefix
const char * stats_decoder_events_prefix
Definition: counters.c:98
THV_RUNNING_DONE
#define THV_RUNNING_DONE
Definition: threadvars.h:46
StatsCounterAvgAddI64
void StatsCounterAvgAddI64(StatsThreadContext *stats, StatsCounterAvgId id, int64_t x)
Definition: counters.c:239
STATS_TYPE_MAXIMUM
@ STATS_TYPE_MAXIMUM
Definition: counters.c:57
counters.h
StatsCounter_::short_name
const char * short_name
Definition: counters.h:75
CountersIdType_
Definition: counters.c:1136
PASS
#define PASS
Pass the test.
Definition: util-unittest.h:105
TVT_PPT
@ TVT_PPT
Definition: tm-threads-common.h:88
StatsCounter_::next
struct StatsCounter_ * next
Definition: counters.h:78
StatsCounterMaxId
Definition: counters.h:38
StatsSetupPostConfigPostOutput
void StatsSetupPostConfigPostOutput(void)
Definition: counters.c:976
SCMutexUnlock
#define SCMutexUnlock(mut)
Definition: threads-debug.h:120
StatsGlobalContext_::counters_id_hash
HashTable * counters_id_hash
Definition: counters.c:83
SCEnter
#define SCEnter(...)
Definition: util-debug.h:284
HashTableLookup
void * HashTableLookup(HashTable *ht, void *data, uint16_t datalen)
Definition: util-hash.c:182
StatsRecord_::name
const char * name
Definition: output-stats.h:32
ThreadVars_
Per thread variable structure.
Definition: threadvars.h:58
StatsThreadStore_::name
const char * name
Definition: counters.c:67
THV_KILL
#define THV_KILL
Definition: threadvars.h:40
StatsThreadContext_::pub
StatsPublicThreadContext pub
Definition: counters.h:132
StatsCounterIncr
void StatsCounterIncr(StatsThreadContext *stats, StatsCounterId id)
Increments the local counter.
Definition: counters.c:164
SCSpinUnlock
#define SCSpinUnlock
Definition: threads-debug.h:238
StringParseUint32
int StringParseUint32(uint32_t *res, int base, size_t len, const char *str)
Definition: util-byte.c:269
util-time.h
SCLogWarning
#define SCLogWarning(...)
Macro used to log WARNING messages.
Definition: util-debug.h:262
HashTableAdd
int HashTableAdd(HashTable *ht, void *data, uint16_t datalen)
Definition: util-hash.c:120
ThreadVars_::next
struct ThreadVars_ * next
Definition: threadvars.h:124
StatsPublicThreadContext_
Stats Context for a ThreadVars instance.
Definition: counters.h:92
BUG_ON
#define BUG_ON(x)
Definition: suricata-common.h:317
StatsTable_
Definition: output-stats.h:39
tv_root_lock
SCMutex tv_root_lock
Definition: tm-threads.c:85
StatsRecord_::value
int64_t value
Definition: output-stats.h:35
SCReturn
#define SCReturn
Definition: util-debug.h:286
SCCtrlMutexLock
#define SCCtrlMutexLock(mut)
Definition: threads-debug.h:377
StatsToJSON
json_t * StatsToJSON(const StatsTable *st, uint8_t flags)
turn StatsTable into a json object
Definition: output-json-stats.c:211
CountersIdType_::id
uint16_t id
Definition: counters.c:1137
type
uint16_t type
Definition: decode-vlan.c:106
tmm_modules
TmModule tmm_modules[TMM_SIZE]
Definition: tm-modules.c:29
ThreadVars_::ctrl_cond
SCCtrlCondT * ctrl_cond
Definition: threadvars.h:129
StatsCounterGlobalId::id
uint16_t id
Definition: counters.h:43
StatsCounter_::id
uint16_t id
Definition: counters.h:59
ThreadVars_::thread_setup_flags
uint8_t thread_setup_flags
Definition: threadvars.h:68
TmEcode
TmEcode
Definition: tm-threads-common.h:80
STATS_TYPE_DERIVE_DIV
@ STATS_TYPE_DERIVE_DIV
Definition: counters.c:59
StatsTable_::start_time
time_t start_time
Definition: output-stats.h:44
StatsPrivateThreadContext_
used to hold the private version of the counters registered
Definition: counters.h:121
SCCtrlCondTimedwait
#define SCCtrlCondTimedwait
Definition: threads-debug.h:386
StatsSetupPrivate
int StatsSetupPrivate(StatsThreadContext *stats, const char *thread_name)
Definition: counters.c:1311
PacketQueue_::cond_q
SCCondT cond_q
Definition: packet-queue.h:57
TmThreadCreateMgmtThread
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...
Definition: tm-threads.c:1097
SCLogInfo
#define SCLogInfo(...)
Macro used to log INFORMATIONAL messages.
Definition: util-debug.h:232
SCMutexInit
#define SCMutexInit(mut, mutattrs)
Definition: threads-debug.h:116
STATS_WUT_TTS
#define STATS_WUT_TTS
Definition: counters.c:45
Flow_::next
struct Flow_ * next
Definition: flow.h:394
StatsGlobalContext_::global_counter_ctx
StatsPublicThreadContext global_counter_ctx
Definition: counters.c:85
StatsTable_::stats
StatsRecord * stats
Definition: output-stats.h:40
TmModule_
Definition: tm-modules.h:47
StatsThreadInit
void StatsThreadInit(StatsThreadContext *stats)
Definition: counters.c:1331
StatsCounterGlobalId
Definition: counters.h:42
StatsGlobalContext_::sts_lock
SCMutex sts_lock
Definition: counters.c:80
THV_INIT_DONE
#define THV_INIT_DONE
Definition: threadvars.h:37
StatsLocalCounter_
counter type for local (private) increments. For AVG counters we use 2 to track values and updates.
Definition: counters.h:85
SCCtrlMutexUnlock
#define SCCtrlMutexUnlock(mut)
Definition: threads-debug.h:379
SCCondSignal
#define SCCondSignal
Definition: threads-debug.h:140
ThreadVars_::inq
Tmq * inq
Definition: threadvars.h:89
util-conf.h
StatsGlobalContext_::sts_cnt
int sts_cnt
Definition: counters.c:81
FAIL_IF
#define FAIL_IF(expr)
Fail a test if expression evaluates to true.
Definition: util-unittest.h:71
suricata-common.h
output-json-stats.h
TmThreadsWaitForUnpause
bool TmThreadsWaitForUnpause(ThreadVars *tv)
Wait for a thread to become unpaused.
Definition: tm-threads.c:363
StatsCounterMaxId::id
uint16_t id
Definition: counters.h:39
StatsPublicThreadContext_::pc_array
const StatsCounter ** pc_array
Definition: counters.h:110
StatsThreadStore_::ctx
StatsPublicThreadContext * ctx
Definition: counters.c:69
StatsEnabled
bool StatsEnabled(void)
Definition: counters.c:115
StatsSpawnThreads
void StatsSpawnThreads(void)
Spawns the wakeup, and the management thread used by the stats api.
Definition: counters.c:988
StatsRecord_::tm_name
const char * tm_name
Definition: output-stats.h:34
StatsSyncCounters
void StatsSyncCounters(StatsThreadContext *stats)
Definition: counters.c:477
StatsCounterGetLocalValue
int64_t StatsCounterGetLocalValue(StatsThreadContext *stats, StatsCounterId id)
Get the value of the local copy of the counter that hold this id.
Definition: counters.c:1374
TmModule_::ThreadInit
TmEcode(* ThreadInit)(ThreadVars *, const void *, void **)
Definition: tm-modules.h:51
STATS_TYPE_NORMAL
@ STATS_TYPE_NORMAL
Definition: counters.c:55
JSON_STATS_THREADS
#define JSON_STATS_THREADS
Definition: output-json-stats.h:30
StatsCounterAvgId::id
uint16_t id
Definition: counters.h:35
StatsThreadContext_
Definition: counters.h:131
FatalError
#define FatalError(...)
Definition: util-debug.h:517
StatsTable_::tstats
StatsRecord * tstats
Definition: output-stats.h:41
tv
ThreadVars * tv
Definition: fuzz_decodepcapfile.c:33
threadvars.h
ConfUnixSocketIsEnable
int ConfUnixSocketIsEnable(void)
Definition: util-conf.c:136
SCSpinInit
#define SCSpinInit
Definition: threads-debug.h:239
StatsCounterSetI64
void StatsCounterSetI64(StatsThreadContext *stats, StatsCounterId id, int64_t x)
set, so overwrite, the value of the local counter
Definition: counters.c:203
StatsCounter_::gid
uint16_t gid
Definition: counters.h:62
SCConfGetNode
SCConfNode * SCConfGetNode(const char *name)
Get a SCConfNode by name.
Definition: conf.c:182
OutputStatsLoggersRegistered
int OutputStatsLoggersRegistered(void)
Definition: output-stats.c:177
SCLogError
#define SCLogError(...)
Macro used to log ERROR messages.
Definition: util-debug.h:274
head
Flow * head
Definition: flow-hash.h:1
StatsCounterAvgId
Definition: counters.h:34
SCFree
#define SCFree(p)
Definition: util-mem.h:61
StatsPrivateThreadContext_::initialized
int initialized
Definition: counters.h:128
StatsPrivateThreadContext_::size
uint32_t size
Definition: counters.h:126
StatsCounterId::id
uint16_t id
Definition: counters.h:31
StatsRegisterMaxCounter
StatsCounterMaxId StatsRegisterMaxCounter(const char *name, StatsThreadContext *stats)
Registers a counter, whose value holds the maximum of all the values assigned to it.
Definition: counters.c:1075
StatsRecord_::short_name
const char * short_name
Definition: output-stats.h:33
StatsRegisterDeriveDivCounter
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...
Definition: counters.c:1120
HashTableInit
HashTable * HashTableInit(uint32_t size, uint32_t(*Hash)(struct HashTable_ *, void *, uint16_t), char(*Compare)(void *, uint16_t, void *, uint16_t), void(*Free)(void *))
Definition: util-hash.c:35
TVT_MGMT
@ TVT_MGMT
Definition: tm-threads-common.h:89
suricata.h
StatsPublicThreadContext_::head
StatsCounter * head
Definition: counters.h:94
GetDocURL
const char * GetDocURL(void)
Definition: suricata.c:1175
StatsGlobalContext_::sts
StatsThreadStore * sts
Definition: counters.c:79
StatsGlobalContext
struct StatsGlobalContext_ StatsGlobalContext
Holds the output interface context for the counter api.
ThreadVars_::ctrl_mutex
SCCtrlMutex * ctrl_mutex
Definition: threadvars.h:128
StatsThreadStore
struct StatsThreadStore_ StatsThreadStore
per thread store of counters
SC_ATOMIC_GET
#define SC_ATOMIC_GET(name)
Get the value from the atomic variable.
Definition: util-atomic.h:375
StatsCounter_::did2
uint16_t did2
Definition: counters.h:67
StatsCounterDeriveId
Definition: counters.h:48
stats_decoder_events
bool stats_decoder_events
Definition: counters.c:97
TmThreadsCheckFlag
int TmThreadsCheckFlag(ThreadVars *tv, uint32_t flag)
Check if a thread flag is set.
Definition: tm-threads.c:93
StatsType
StatsType
Different kinds of qualifier that can be used to modify the behaviour of the counter to be registered...
Definition: counters.c:54
StatsPublicThreadContext_::derive_id
uint16_t derive_id
Definition: counters.h:104
StatsPublicThreadContext_::curr_id
uint16_t curr_id
Definition: counters.h:100
THV_CLOSED
#define THV_CLOSED
Definition: threadvars.h:42
StatsCounterDeriveId::id
uint16_t id
Definition: counters.h:49
SCCalloc
#define SCCalloc(nm, sz)
Definition: util-mem.h:53
ThreadVars_::stats
StatsThreadContext stats
Definition: threadvars.h:121
SCConfNode_
Definition: conf.h:37
StatsCounterAddI64
void StatsCounterAddI64(StatsThreadContext *stats, StatsCounterId id, int64_t x)
Adds a value of type uint64_t to the local counter.
Definition: counters.c:145
StatsThreadCleanup
void StatsThreadCleanup(StatsThreadContext *stats)
Definition: counters.c:1427
SCConfNode_::val
char * val
Definition: conf.h:39
StatsTable_::nstats
uint32_t nstats
Definition: output-stats.h:42
SCMutex
#define SCMutex
Definition: threads-debug.h:114
DEBUG_VALIDATE_BUG_ON
#define DEBUG_VALIDATE_BUG_ON(exp)
Definition: util-validate.h:102
StatsPrivateThreadContext_::head
StatsLocalCounter * head
Definition: counters.h:123
OutputStatsLog
TmEcode OutputStatsLog(ThreadVars *tv, void *thread_data, StatsTable *st)
Definition: output-stats.c:77
StatsLocalCounter_::v
int64_t v
Definition: counters.h:86
StatsRegisterTests
void StatsRegisterTests(void)
Definition: counters.c:1651
StatsThreadContext_::priv
StatsPrivateThreadContext priv
Definition: counters.h:133
output.h