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