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 */
40typedef 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
57static char profiling_file_name[PATH_MAX] = "";
58static const char *profiling_file_mode = "a";
59static int profiling_rule_json = 0;
60
61/**
62 * Sort orders for dumping profiled rules.
63 */
64enum {
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
74static 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 */
87static uint32_t profiling_rules_limit = UINT32_MAX;
88
89void 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 if (SCConfNodeChildValueIsTrue(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 */
171static int
172SCProfileSummarySortByTicks(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 */
185static int
186SCProfileSummarySortByAvgTicksMatch(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 */
199static int
200SCProfileSummarySortByAvgTicksNoMatch(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 */
213static int
214SCProfileSummarySortByAvgTicks(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 */
227static int
228SCProfileSummarySortByChecks(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 */
241static int
242SCProfileSummarySortByMatches(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 */
255static int
256SCProfileSummarySortByMaxTicks(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
266static 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
320static 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
337static 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 */
404static 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 */
534static uint16_t
535SCProfilingRegisterRuleCounter(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 */
548void
549SCProfilingRuleUpdateCounter(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
565static 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
577void 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
588void 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
600static 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
623void SCProfilingRuleThreadCleanup(DetectEngineThreadCtx *det_ctx)
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
637void 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 */
652void
653SCProfilingRuleInitCounters(DetectEngineCtx *de_ctx)
654{
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
685json_t *SCProfileRuleTriggerDump(DetectEngineCtx *de_ctx)
686{
687 return SCProfilingRuleDump(de_ctx->profile_ctx, 0);
688}
689
690#endif /* PROFILING */
691
SCConfNode * SCConfGetNode(const char *name)
Get a SCConfNode by name.
Definition conf.c:181
int SCConfNodeChildValueIsTrue(const SCConfNode *node, const char *key)
Test if a configuration node has a true value.
Definition conf.c:868
int SCConfValIsTrue(const char *val)
Check if a value is true.
Definition conf.c:551
const char * SCConfNodeLookupChildValue(const SCConfNode *node, const char *name)
Lookup the value of a child configuration node by name.
Definition conf.c:824
uint32_t id
DetectEngineCtx * de_ctx
struct Thresholds ctx
main detection engine ctx
Definition detect.h:932
Signature * sig_list
Definition detect.h:941
DetectEngineCtx * de_ctx
Definition detect.h:1364
Signature container.
Definition detect.h:668
uint32_t rev
Definition detect.h:715
uint32_t id
Definition detect.h:713
struct Signature_ * next
Definition detect.h:750
uint32_t gid
Definition detect.h:714
#define BUG_ON(x)
#define JSON_ESCAPE_SLASH
#define MIN(x, y)
size_t strlcpy(char *dst, const char *src, size_t siz)
int StringParseUint32(uint32_t *res, int base, size_t len, const char *str)
Definition util-byte.c:313
const char * SCConfigGetLogDirectory(void)
Definition util-conf.c:38
#define FatalError(...)
Definition util-debug.h:510
#define SCLogPerf(...)
Definition util-debug.h:234
#define SCLogError(...)
Macro used to log ERROR messages.
Definition util-debug.h:267
#define SCMalloc(sz)
Definition util-mem.h:47
#define SCFree(p)
Definition util-mem.h:61
#define SCCalloc(nm, sz)
Definition util-mem.h:53
#define unlikely(expr)
int PathIsAbsolute(const char *path)
Check if a path is absolute.
Definition util-path.c:44
int profiling_output_to_file
int profiling_rules_enabled
struct tm * SCLocalTime(time_t timep, struct tm *result)
Definition util-time.c:267
void CreateIsoTimeString(const SCTime_t ts, char *str, size_t size)
Definition util-time.c:209
#define SCTIME_FROM_TIMEVAL(tv)
Definition util-time.h:79