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