suricata
util-profiling-rules.c
Go to the documentation of this file.
1 /* Copyright (C) 2007-2012 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 Endace Technology Limited.
22  * \author Victor Julien <victor@inliniac.net>
23  *
24  * An API for rule profiling operations.
25  */
26 
27 #include "suricata-common.h"
28 #include "util-profiling.h"
29 
30 #include "util-byte.h"
31 #include "util-conf.h"
32 #include "util-path.h"
33 #include "util-time.h"
34 
35 #ifdef PROFILE_RULES
36 
37 /**
38  * Used for generating the summary data to print.
39  */
40 typedef struct SCProfileSummary_ {
41  uint32_t sid;
42  uint32_t gid;
43  uint32_t rev;
44  uint64_t ticks;
45  double avgticks;
46  double avgticks_match;
47  double avgticks_no_match;
48  uint64_t checks;
49  uint64_t matches;
50  uint64_t max;
51  uint64_t ticks_match;
52  uint64_t ticks_no_match;
53 } SCProfileSummary;
54 
55 extern int profiling_output_to_file;
57 static char profiling_file_name[PATH_MAX] = "";
58 static const char *profiling_file_mode = "a";
59 static bool profiling_rule_json = true;
60 
61 /**
62  * Sort orders for dumping profiled rules.
63  */
64 enum {
65  SC_PROFILING_RULES_SORT_BY_TICKS = 0,
66  SC_PROFILING_RULES_SORT_BY_AVG_TICKS,
67  SC_PROFILING_RULES_SORT_BY_CHECKS,
68  SC_PROFILING_RULES_SORT_BY_MATCHES,
69  SC_PROFILING_RULES_SORT_BY_MAX_TICKS,
70  SC_PROFILING_RULES_SORT_BY_AVG_TICKS_MATCH,
71  SC_PROFILING_RULES_SORT_BY_AVG_TICKS_NO_MATCH,
72 };
73 
74 static int profiling_rules_sort_orders[8] = {
75  SC_PROFILING_RULES_SORT_BY_TICKS,
76  SC_PROFILING_RULES_SORT_BY_AVG_TICKS,
77  SC_PROFILING_RULES_SORT_BY_AVG_TICKS_MATCH,
78  SC_PROFILING_RULES_SORT_BY_AVG_TICKS_NO_MATCH,
79  SC_PROFILING_RULES_SORT_BY_CHECKS,
80  SC_PROFILING_RULES_SORT_BY_MATCHES,
81  SC_PROFILING_RULES_SORT_BY_MAX_TICKS,
82  -1 };
83 
84 /**
85  * Maximum number of rules to dump.
86  */
87 static uint32_t profiling_rules_limit = UINT32_MAX;
88 
89 void SCProfilingRulesGlobalInit(void)
90 {
91 #define SET_ONE(x) { \
92  profiling_rules_sort_orders[0] = (x); \
93  profiling_rules_sort_orders[1] = -1; \
94  }
95 
96  SCConfNode *conf;
97  const char *val;
98 
99  conf = SCConfGetNode("profiling.rules");
100  if (conf != NULL) {
101  if (SCConfNodeChildValueIsTrue(conf, "enabled")) {
103 
104  val = SCConfNodeLookupChildValue(conf, "sort");
105  if (val != NULL) {
106  if (strcmp(val, "ticks") == 0) {
107  SET_ONE(SC_PROFILING_RULES_SORT_BY_TICKS);
108  }
109  else if (strcmp(val, "avgticks") == 0) {
110  SET_ONE(SC_PROFILING_RULES_SORT_BY_AVG_TICKS);
111  }
112  else if (strcmp(val, "avgticks_match") == 0) {
113  SET_ONE(SC_PROFILING_RULES_SORT_BY_AVG_TICKS_MATCH);
114  }
115  else if (strcmp(val, "avgticks_no_match") == 0) {
116  SET_ONE(SC_PROFILING_RULES_SORT_BY_AVG_TICKS_NO_MATCH);
117  }
118  else if (strcmp(val, "checks") == 0) {
119  SET_ONE(SC_PROFILING_RULES_SORT_BY_CHECKS);
120  }
121  else if (strcmp(val, "matches") == 0) {
122  SET_ONE(SC_PROFILING_RULES_SORT_BY_MATCHES);
123  }
124  else if (strcmp(val, "maxticks") == 0) {
125  SET_ONE(SC_PROFILING_RULES_SORT_BY_MAX_TICKS);
126  }
127  else {
128  SCLogError("Invalid profiling sort order: %s", val);
129  exit(EXIT_FAILURE);
130  }
131  }
132 
133  val = SCConfNodeLookupChildValue(conf, "limit");
134  if (val != NULL) {
135  if (StringParseUint32(&profiling_rules_limit, 10,
136  (uint16_t)strlen(val), val) <= 0) {
137  SCLogError("Invalid limit: %s", val);
138  exit(EXIT_FAILURE);
139  }
140  }
141  const char *filename = SCConfNodeLookupChildValue(conf, "filename");
142  if (filename != NULL) {
143  if (PathIsAbsolute(filename)) {
144  strlcpy(profiling_file_name, filename, sizeof(profiling_file_name));
145  } else {
146  const char *log_dir = SCConfigGetLogDirectory();
147  snprintf(profiling_file_name, sizeof(profiling_file_name), "%s/%s", log_dir,
148  filename);
149  }
150 
151  const char *v = SCConfNodeLookupChildValue(conf, "append");
152  if (v == NULL || SCConfValIsTrue(v)) {
153  profiling_file_mode = "a";
154  } else {
155  profiling_file_mode = "w";
156  }
157 
159  }
160 
161  if (SCConfNodeChildValueIsFalse(conf, "json")) {
162  profiling_rule_json = false;
163  }
164  }
165  }
166 #undef SET_ONE
167 }
168 
169 /**
170  * \brief Qsort comparison function to sort by ticks.
171  */
172 static int
173 SCProfileSummarySortByTicks(const void *a, const void *b)
174 {
175  const SCProfileSummary *s0 = a;
176  const SCProfileSummary *s1 = b;
177  if (s1->ticks == s0->ticks)
178  return 0;
179  else
180  return s0->ticks > s1->ticks ? -1 : 1;
181 }
182 
183 /**
184  * \brief Qsort comparison function to sort by average ticks per match.
185  */
186 static int
187 SCProfileSummarySortByAvgTicksMatch(const void *a, const void *b)
188 {
189  const SCProfileSummary *s0 = a;
190  const SCProfileSummary *s1 = b;
191  if (s1->avgticks_match == s0->avgticks_match)
192  return 0;
193  else
194  return s0->avgticks_match > s1->avgticks_match ? -1 : 1;
195 }
196 
197 /**
198  * \brief Qsort comparison function to sort by average ticks per non match.
199  */
200 static int
201 SCProfileSummarySortByAvgTicksNoMatch(const void *a, const void *b)
202 {
203  const SCProfileSummary *s0 = a;
204  const SCProfileSummary *s1 = b;
205  if (s1->avgticks_no_match == s0->avgticks_no_match)
206  return 0;
207  else
208  return s0->avgticks_no_match > s1->avgticks_no_match ? -1 : 1;
209 }
210 
211 /**
212  * \brief Qsort comparison function to sort by average ticks.
213  */
214 static int
215 SCProfileSummarySortByAvgTicks(const void *a, const void *b)
216 {
217  const SCProfileSummary *s0 = a;
218  const SCProfileSummary *s1 = b;
219  if (s1->avgticks == s0->avgticks)
220  return 0;
221  else
222  return s0->avgticks > s1->avgticks ? -1 : 1;
223 }
224 
225 /**
226  * \brief Qsort comparison function to sort by checks.
227  */
228 static int
229 SCProfileSummarySortByChecks(const void *a, const void *b)
230 {
231  const SCProfileSummary *s0 = a;
232  const SCProfileSummary *s1 = b;
233  if (s1->checks == s0->checks)
234  return 0;
235  else
236  return s0->checks > s1->checks ? -1 : 1;
237 }
238 
239 /**
240  * \brief Qsort comparison function to sort by matches.
241  */
242 static int
243 SCProfileSummarySortByMatches(const void *a, const void *b)
244 {
245  const SCProfileSummary *s0 = a;
246  const SCProfileSummary *s1 = b;
247  if (s1->matches == s0->matches)
248  return 0;
249  else
250  return s0->matches > s1->matches ? -1 : 1;
251 }
252 
253 /**
254  * \brief Qsort comparison function to sort by max ticks.
255  */
256 static int
257 SCProfileSummarySortByMaxTicks(const void *a, const void *b)
258 {
259  const SCProfileSummary *s0 = a;
260  const SCProfileSummary *s1 = b;
261  if (s1->max == s0->max)
262  return 0;
263  else
264  return s0->max > s1->max ? -1 : 1;
265 }
266 
267 static json_t *BuildJson(
268  SCProfileSummary *summary, uint32_t count, uint64_t total_ticks, const char *sort_desc)
269 {
270 
271  char timebuf[64];
272  uint32_t i;
273  struct timeval tval;
274 
275  json_t *js = json_object();
276  if (js == NULL)
277  return js;
278  json_t *jsa = json_array();
279  if (jsa == NULL) {
280  json_decref(js);
281  return js;
282  }
283 
284  gettimeofday(&tval, NULL);
285  CreateIsoTimeString(SCTIME_FROM_TIMEVAL(&tval), timebuf, sizeof(timebuf));
286  json_object_set_new(js, "timestamp", json_string(timebuf));
287  json_object_set_new(js, "sort", json_string(sort_desc));
288 
289  for (i = 0; i < MIN(count, profiling_rules_limit); i++) {
290  /* Stop dumping when we hit our first rule with 0 checks. Due
291  * to sorting this will be the beginning of all the rules with
292  * 0 checks. */
293  if (summary[i].checks == 0)
294  break;
295 
296  json_t *jsm = json_object();
297  if (jsm) {
298  json_object_set_new(jsm, "signature_id", json_integer(summary[i].sid));
299  json_object_set_new(jsm, "gid", json_integer(summary[i].gid));
300  json_object_set_new(jsm, "rev", json_integer(summary[i].rev));
301 
302  json_object_set_new(jsm, "checks", json_integer(summary[i].checks));
303  json_object_set_new(jsm, "matches", json_integer(summary[i].matches));
304 
305  json_object_set_new(jsm, "ticks_total", json_integer(summary[i].ticks));
306  json_object_set_new(jsm, "ticks_max", json_integer(summary[i].max));
307  json_object_set_new(jsm, "ticks_avg", json_integer(summary[i].avgticks));
308  json_object_set_new(jsm, "ticks_avg_match", json_integer(summary[i].avgticks_match));
309  json_object_set_new(jsm, "ticks_avg_nomatch", json_integer(summary[i].avgticks_no_match));
310 
311  double percent = (long double)summary[i].ticks /
312  (long double)total_ticks * 100;
313  json_object_set_new(jsm, "percent", json_integer(percent));
314  json_array_append_new(jsa, jsm);
315  }
316  }
317  json_object_set_new(js, "rules", jsa);
318  return js;
319 }
320 
321 static void DumpJson(FILE *fp, SCProfileSummary *summary, uint32_t count, uint64_t total_ticks,
322  const char *sort_desc)
323 {
324  json_t *js = BuildJson(summary, count, total_ticks, sort_desc);
325  if (unlikely(js == NULL))
326  return;
327  char *js_s = json_dumps(js,
328  JSON_PRESERVE_ORDER|JSON_COMPACT|JSON_ENSURE_ASCII|
330 
331  if (unlikely(js_s == NULL))
332  return;
333  fprintf(fp, "%s\n", js_s);
334  free(js_s);
335  json_decref(js);
336 }
337 
338 static void DumpText(FILE *fp, SCProfileSummary *summary,
339  uint32_t count, uint64_t total_ticks,
340  const char *sort_desc)
341 {
342  uint32_t i;
343  struct timeval tval;
344  struct tm *tms;
345  gettimeofday(&tval, NULL);
346  struct tm local_tm;
347  tms = SCLocalTime(tval.tv_sec, &local_tm);
348 
349  fprintf(fp, " ----------------------------------------------"
350  "----------------------------\n");
351  fprintf(fp, " Date: %" PRId32 "/%" PRId32 "/%04d -- "
352  "%02d:%02d:%02d.", tms->tm_mon + 1, tms->tm_mday, tms->tm_year + 1900,
353  tms->tm_hour,tms->tm_min, tms->tm_sec);
354  fprintf(fp, " Sorted by: %s.\n", sort_desc);
355  fprintf(fp, " ----------------------------------------------"
356  "----------------------------\n");
357  fprintf(fp, " %-8s %-12s %-8s %-8s %-12s %-6s %-8s %-8s %-11s %-11s %-11s %-11s\n", "Num", "Rule", "Gid", "Rev", "Ticks", "%", "Checks", "Matches", "Max Ticks", "Avg Ticks", "Avg Match", "Avg No Match");
358  fprintf(fp, " -------- "
359  "------------ "
360  "-------- "
361  "-------- "
362  "------------ "
363  "------ "
364  "-------- "
365  "-------- "
366  "----------- "
367  "----------- "
368  "----------- "
369  "-------------- "
370  "\n");
371  for (i = 0; i < MIN(count, profiling_rules_limit); i++) {
372 
373  /* Stop dumping when we hit our first rule with 0 checks. Due
374  * to sorting this will be the beginning of all the rules with
375  * 0 checks. */
376  if (summary[i].checks == 0)
377  break;
378 
379  double percent = (long double)summary[i].ticks /
380  (long double)total_ticks * 100;
381  fprintf(fp,
382  " %-8"PRIu32" %-12u %-8"PRIu32" %-8"PRIu32" %-12"PRIu64" %-6.2f %-8"PRIu64" %-8"PRIu64" %-11"PRIu64" %-11.2f %-11.2f %-11.2f\n",
383  i + 1,
384  summary[i].sid,
385  summary[i].gid,
386  summary[i].rev,
387  summary[i].ticks,
388  percent,
389  summary[i].checks,
390  summary[i].matches,
391  summary[i].max,
392  summary[i].avgticks,
393  summary[i].avgticks_match,
394  summary[i].avgticks_no_match);
395  }
396 
397  fprintf(fp,"\n");
398 }
399 
400 /**
401  * \brief Dump rule profiling information to file
402  *
403  * \param de_ctx The active DetectEngineCtx, used to get at the loaded rules.
404  */
405 static void *SCProfilingRuleDump(SCProfileDetectCtx *rules_ctx, int file_output)
406 {
407  uint32_t i;
408  FILE *fp = NULL;
409 
410  if (rules_ctx == NULL)
411  return NULL;
412 
413  if (file_output != 0) {
414  if (profiling_output_to_file == 1) {
415  fp = fopen(profiling_file_name, profiling_file_mode);
416 
417  if (fp == NULL) {
418  SCLogError("failed to open %s: %s", profiling_file_name, strerror(errno));
419  return NULL;
420  }
421  } else {
422  fp = stdout;
423  }
424  }
425 
426  int summary_size = sizeof(SCProfileSummary) * rules_ctx->size;
427  SCProfileSummary *summary = SCMalloc(summary_size);
428  if (unlikely(summary == NULL)) {
429  SCLogError("Error allocating memory for profiling summary");
430  return NULL;
431  }
432 
433  uint32_t count = rules_ctx->size;
434  uint64_t total_ticks = 0;
435 
436  SCLogPerf("Dumping profiling data for %u rules.", count);
437 
438  memset(summary, 0, summary_size);
439  for (i = 0; i < count; i++) {
440  summary[i].sid = rules_ctx->data[i].sid;
441  summary[i].rev = rules_ctx->data[i].rev;
442  summary[i].gid = rules_ctx->data[i].gid;
443 
444  summary[i].ticks = rules_ctx->data[i].ticks_match + rules_ctx->data[i].ticks_no_match;
445  summary[i].checks = rules_ctx->data[i].checks;
446 
447  if (summary[i].checks > 0) {
448  summary[i].avgticks = (long double)summary[i].ticks / (long double)summary[i].checks;
449  }
450 
451  summary[i].matches = rules_ctx->data[i].matches;
452  summary[i].max = rules_ctx->data[i].max;
453  summary[i].ticks_match = rules_ctx->data[i].ticks_match;
454  summary[i].ticks_no_match = rules_ctx->data[i].ticks_no_match;
455  if (summary[i].ticks_match > 0) {
456  summary[i].avgticks_match = (long double)summary[i].ticks_match /
457  (long double)summary[i].matches;
458  }
459 
460  if (summary[i].ticks_no_match > 0) {
461  summary[i].avgticks_no_match = (long double)summary[i].ticks_no_match /
462  ((long double)summary[i].checks - (long double)summary[i].matches);
463  }
464  total_ticks += summary[i].ticks;
465  }
466 
467  int *order = profiling_rules_sort_orders;
468  while (*order != -1) {
469  const char *sort_desc = NULL;
470  switch (*order) {
471  case SC_PROFILING_RULES_SORT_BY_TICKS:
472  qsort(summary, count, sizeof(SCProfileSummary),
473  SCProfileSummarySortByTicks);
474  sort_desc = "ticks";
475  break;
476  case SC_PROFILING_RULES_SORT_BY_AVG_TICKS:
477  qsort(summary, count, sizeof(SCProfileSummary),
478  SCProfileSummarySortByAvgTicks);
479  sort_desc = "average ticks";
480  break;
481  case SC_PROFILING_RULES_SORT_BY_CHECKS:
482  qsort(summary, count, sizeof(SCProfileSummary),
483  SCProfileSummarySortByChecks);
484  sort_desc = "number of checks";
485  break;
486  case SC_PROFILING_RULES_SORT_BY_MATCHES:
487  qsort(summary, count, sizeof(SCProfileSummary),
488  SCProfileSummarySortByMatches);
489  sort_desc = "number of matches";
490  break;
491  case SC_PROFILING_RULES_SORT_BY_MAX_TICKS:
492  qsort(summary, count, sizeof(SCProfileSummary),
493  SCProfileSummarySortByMaxTicks);
494  sort_desc = "max ticks";
495  break;
496  case SC_PROFILING_RULES_SORT_BY_AVG_TICKS_MATCH:
497  qsort(summary, count, sizeof(SCProfileSummary),
498  SCProfileSummarySortByAvgTicksMatch);
499  sort_desc = "average ticks (match)";
500  break;
501  case SC_PROFILING_RULES_SORT_BY_AVG_TICKS_NO_MATCH:
502  qsort(summary, count, sizeof(SCProfileSummary),
503  SCProfileSummarySortByAvgTicksNoMatch);
504  sort_desc = "average ticks (no match)";
505  break;
506  }
507  if (profiling_rule_json) {
508  if (file_output != 1) {
509  json_t *js = BuildJson(summary, count, total_ticks, sort_desc);
510  SCFree(summary);
511  return js;
512  } else {
513  DumpJson(fp, summary, count, total_ticks, sort_desc);
514  }
515  } else {
516  DumpText(fp, summary, count, total_ticks, sort_desc);
517  }
518  order++;
519  }
520 
521  if (file_output != 0) {
522  if (fp != stdout)
523  fclose(fp);
524  }
525  SCFree(summary);
526  SCLogPerf("Done dumping profiling data.");
527  return NULL;
528 }
529 
530 /**
531  * \brief Register a rule profiling counter.
532  *
533  * \retval Returns the ID of the counter on success, 0 on failure.
534  */
535 static uint16_t
536 SCProfilingRegisterRuleCounter(SCProfileDetectCtx *ctx)
537 {
538  ctx->size++;
539  return ctx->id++;
540 }
541 
542 /**
543  * \brief Update a rule counter.
544  *
545  * \param id The ID of this counter.
546  * \param ticks Number of CPU ticks for this rule.
547  * \param match Did the rule match?
548  */
549 void
550 SCProfilingRuleUpdateCounter(DetectEngineThreadCtx *det_ctx, uint16_t id, uint64_t ticks, int match)
551 {
552  if (det_ctx != NULL && det_ctx->rule_perf_data != NULL && det_ctx->rule_perf_data_size > id) {
553  SCProfileData *p = &det_ctx->rule_perf_data[id];
554 
555  p->checks++;
556  p->matches += match;
557  if (ticks > p->max)
558  p->max = ticks;
559  if (match == 1)
560  p->ticks_match += ticks;
561  else
562  p->ticks_no_match += ticks;
563  }
564 }
565 
566 static SCProfileDetectCtx *SCProfilingRuleInitCtx(void)
567 {
568  SCProfileDetectCtx *ctx = SCCalloc(1, sizeof(SCProfileDetectCtx));
569  if (ctx != NULL) {
570  if (pthread_mutex_init(&ctx->data_m, NULL) != 0) {
571  FatalError("Failed to initialize hash table mutex.");
572  }
573  }
574 
575  return ctx;
576 }
577 
578 void SCProfilingRuleDestroyCtx(SCProfileDetectCtx *ctx)
579 {
580  if (ctx != NULL) {
581  SCProfilingRuleDump(ctx, 1);
582  if (ctx->data != NULL)
583  SCFree(ctx->data);
584  pthread_mutex_destroy(&ctx->data_m);
585  SCFree(ctx);
586  }
587 }
588 
589 void SCProfilingRuleThreadSetup(SCProfileDetectCtx *ctx, DetectEngineThreadCtx *det_ctx)
590 {
591  if (ctx == NULL|| ctx->size == 0)
592  return;
593 
594  SCProfileData *a = SCCalloc(ctx->size, sizeof(SCProfileData));
595  if (a != NULL) {
596  det_ctx->rule_perf_data = a;
597  det_ctx->rule_perf_data_size = ctx->size;
598  }
599 }
600 
601 static void SCProfilingRuleThreadMerge(
602  DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, bool reset)
603 {
604  if (de_ctx == NULL || de_ctx->profile_ctx == NULL || de_ctx->profile_ctx->data == NULL ||
605  det_ctx == NULL || det_ctx->rule_perf_data == NULL)
606  return;
607 
608  for (int i = 0; i < det_ctx->rule_perf_data_size; i++) {
609  de_ctx->profile_ctx->data[i].checks += det_ctx->rule_perf_data[i].checks;
610  de_ctx->profile_ctx->data[i].matches += det_ctx->rule_perf_data[i].matches;
611  de_ctx->profile_ctx->data[i].ticks_match += det_ctx->rule_perf_data[i].ticks_match;
612  de_ctx->profile_ctx->data[i].ticks_no_match += det_ctx->rule_perf_data[i].ticks_no_match;
613  if (reset) {
614  det_ctx->rule_perf_data[i].checks = 0;
615  det_ctx->rule_perf_data[i].matches = 0;
616  det_ctx->rule_perf_data[i].ticks_match = 0;
617  det_ctx->rule_perf_data[i].ticks_no_match = 0;
618  }
619  if (det_ctx->rule_perf_data[i].max > de_ctx->profile_ctx->data[i].max)
620  de_ctx->profile_ctx->data[i].max = det_ctx->rule_perf_data[i].max;
621  }
622 }
623 
624 void SCProfilingRuleThreadCleanup(DetectEngineThreadCtx *det_ctx)
625 {
626  if (det_ctx == NULL || det_ctx->de_ctx == NULL || det_ctx->rule_perf_data == NULL)
627  return;
628 
629  pthread_mutex_lock(&det_ctx->de_ctx->profile_ctx->data_m);
630  SCProfilingRuleThreadMerge(det_ctx->de_ctx, det_ctx, false);
631  pthread_mutex_unlock(&det_ctx->de_ctx->profile_ctx->data_m);
632 
633  SCFree(det_ctx->rule_perf_data);
634  det_ctx->rule_perf_data = NULL;
635  det_ctx->rule_perf_data_size = 0;
636 }
637 
638 void SCProfilingRuleThreatAggregate(DetectEngineThreadCtx *det_ctx)
639 {
640 
641  if (det_ctx == NULL || det_ctx->de_ctx == NULL || det_ctx->de_ctx->profile_ctx == NULL)
642  return;
643  pthread_mutex_lock(&det_ctx->de_ctx->profile_ctx->data_m);
644  SCProfilingRuleThreadMerge(det_ctx->de_ctx, det_ctx, true);
645  pthread_mutex_unlock(&det_ctx->de_ctx->profile_ctx->data_m);
646 }
647 
648 /**
649  * \brief Register the rule profiling counters.
650  *
651  * \param de_ctx The active DetectEngineCtx, used to get at the loaded rules.
652  */
653 void
654 SCProfilingRuleInitCounters(DetectEngineCtx *de_ctx)
655 {
656  if (profiling_rules_enabled == 0)
657  return;
658 
659  de_ctx->profile_ctx = SCProfilingRuleInitCtx();
660  BUG_ON(de_ctx->profile_ctx == NULL);
661 
662  Signature *sig = de_ctx->sig_list;
663  uint32_t count = 0;
664  while (sig != NULL) {
665  sig->profiling_id = SCProfilingRegisterRuleCounter(de_ctx->profile_ctx);
666  sig = sig->next;
667  count++;
668  }
669 
670  if (count > 0) {
671  de_ctx->profile_ctx->data = SCCalloc(de_ctx->profile_ctx->size, sizeof(SCProfileData));
672  BUG_ON(de_ctx->profile_ctx->data == NULL);
673 
674  sig = de_ctx->sig_list;
675  while (sig != NULL) {
676  de_ctx->profile_ctx->data[sig->profiling_id].sid = sig->id;
677  de_ctx->profile_ctx->data[sig->profiling_id].gid = sig->gid;
678  de_ctx->profile_ctx->data[sig->profiling_id].rev = sig->rev;
679  sig = sig->next;
680  }
681  }
682 
683  SCLogPerf("Registered %"PRIu32" rule profiling counters.", count);
684 }
685 
686 json_t *SCProfileRuleTriggerDump(DetectEngineCtx *de_ctx)
687 {
688  return SCProfilingRuleDump(de_ctx->profile_ctx, 0);
689 }
690 
691 #endif /* PROFILING */
692 
util-byte.h
SCConfValIsTrue
int SCConfValIsTrue(const char *val)
Check if a value is true.
Definition: conf.c:551
CreateIsoTimeString
void CreateIsoTimeString(const SCTime_t ts, char *str, size_t size)
Definition: util-time.c:209
unlikely
#define unlikely(expr)
Definition: util-optimize.h:35
ctx
struct Thresholds ctx
DetectEngineCtx_
main detection engine ctx
Definition: detect.h:933
SCConfNodeChildValueIsTrue
int SCConfNodeChildValueIsTrue(const SCConfNode *node, const char *key)
Test if a configuration node has a true value.
Definition: conf.c:868
MIN
#define MIN(x, y)
Definition: suricata-common.h:408
JSON_ESCAPE_SLASH
#define JSON_ESCAPE_SLASH
Definition: suricata-common.h:290
SCConfNodeLookupChildValue
const char * SCConfNodeLookupChildValue(const SCConfNode *node, const char *name)
Lookup the value of a child configuration node by name.
Definition: conf.c:824
strlcpy
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: util-strlcpyu.c:43
Signature_::gid
uint32_t gid
Definition: detect.h:714
Signature_::next
struct Signature_ * next
Definition: detect.h:750
de_ctx
DetectEngineCtx * de_ctx
Definition: fuzz_siginit.c:19
DetectEngineThreadCtx_
Definition: detect.h:1245
SCTIME_FROM_TIMEVAL
#define SCTIME_FROM_TIMEVAL(tv)
Definition: util-time.h:79
SCConfNodeChildValueIsFalse
int SCConfNodeChildValueIsFalse(const SCConfNode *node, const char *key)
Test if a configuration node has a false value.
Definition: conf.c:888
StringParseUint32
int StringParseUint32(uint32_t *res, int base, size_t len, const char *str)
Definition: util-byte.c:269
util-time.h
BUG_ON
#define BUG_ON(x)
Definition: suricata-common.h:317
util-profiling.h
SCLocalTime
struct tm * SCLocalTime(time_t timep, struct tm *result)
Definition: util-time.c:267
SCConfigGetLogDirectory
const char * SCConfigGetLogDirectory(void)
Definition: util-conf.c:38
util-conf.h
suricata-common.h
util-path.h
SCLogPerf
#define SCLogPerf(...)
Definition: util-debug.h:241
PathIsAbsolute
int PathIsAbsolute(const char *path)
Check if a path is absolute.
Definition: util-path.c:44
Signature_::rev
uint32_t rev
Definition: detect.h:715
FatalError
#define FatalError(...)
Definition: util-debug.h:517
DetectEngineCtx_::sig_list
Signature * sig_list
Definition: detect.h:942
SCMalloc
#define SCMalloc(sz)
Definition: util-mem.h:47
SCConfGetNode
SCConfNode * SCConfGetNode(const char *name)
Get a SCConfNode by name.
Definition: conf.c:181
SCLogError
#define SCLogError(...)
Macro used to log ERROR messages.
Definition: util-debug.h:274
SCFree
#define SCFree(p)
Definition: util-mem.h:61
Signature_::id
uint32_t id
Definition: detect.h:713
Signature_
Signature container.
Definition: detect.h:668
profiling_output_to_file
int profiling_output_to_file
Definition: util-profiling.c:95
DetectEngineThreadCtx_::de_ctx
DetectEngineCtx * de_ctx
Definition: detect.h:1363
profiling_rules_enabled
int profiling_rules_enabled
id
uint32_t id
Definition: detect-flowbits.c:944
SCCalloc
#define SCCalloc(nm, sz)
Definition: util-mem.h:53
SCConfNode_
Definition: conf.h:37