39 typedef struct SCProfileSummary_ {
45 double avgticks_match;
46 double avgticks_no_match;
51 uint64_t ticks_no_match;
56 static char profiling_file_name[PATH_MAX] =
"";
57 static const char *profiling_file_mode =
"a";
58 static int profiling_rule_json = 0;
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,
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,
86 static uint32_t profiling_rules_limit = UINT32_MAX;
90 #define SET_ONE(x) { \
91 profiling_rules_sort_orders[0] = (x); \
92 profiling_rules_sort_orders[1] = -1; \
105 if (strcmp(val,
"ticks") == 0) {
106 SET_ONE(SC_PROFILING_RULES_SORT_BY_TICKS);
108 else if (strcmp(val,
"avgticks") == 0) {
109 SET_ONE(SC_PROFILING_RULES_SORT_BY_AVG_TICKS);
111 else if (strcmp(val,
"avgticks_match") == 0) {
112 SET_ONE(SC_PROFILING_RULES_SORT_BY_AVG_TICKS_MATCH);
114 else if (strcmp(val,
"avgticks_no_match") == 0) {
115 SET_ONE(SC_PROFILING_RULES_SORT_BY_AVG_TICKS_NO_MATCH);
117 else if (strcmp(val,
"checks") == 0) {
118 SET_ONE(SC_PROFILING_RULES_SORT_BY_CHECKS);
120 else if (strcmp(val,
"matches") == 0) {
121 SET_ONE(SC_PROFILING_RULES_SORT_BY_MATCHES);
123 else if (strcmp(val,
"maxticks") == 0) {
124 SET_ONE(SC_PROFILING_RULES_SORT_BY_MAX_TICKS);
127 SCLogError(
"Invalid profiling sort order: %s", val);
135 (uint16_t)strlen(val), val) <= 0) {
141 if (filename != NULL) {
146 snprintf(profiling_file_name,
sizeof(profiling_file_name),
147 "%s/%s", log_dir, filename);
151 profiling_file_mode =
"a";
153 profiling_file_mode =
"w";
159 profiling_rule_json = 1;
170 SCProfileSummarySortByTicks(
const void *a,
const void *b)
172 const SCProfileSummary *s0 = a;
173 const SCProfileSummary *s1 = b;
174 if (s1->ticks == s0->ticks)
177 return s0->ticks > s1->ticks ? -1 : 1;
184 SCProfileSummarySortByAvgTicksMatch(
const void *a,
const void *b)
186 const SCProfileSummary *s0 = a;
187 const SCProfileSummary *s1 = b;
188 if (s1->avgticks_match == s0->avgticks_match)
191 return s0->avgticks_match > s1->avgticks_match ? -1 : 1;
198 SCProfileSummarySortByAvgTicksNoMatch(
const void *a,
const void *b)
200 const SCProfileSummary *s0 = a;
201 const SCProfileSummary *s1 = b;
202 if (s1->avgticks_no_match == s0->avgticks_no_match)
205 return s0->avgticks_no_match > s1->avgticks_no_match ? -1 : 1;
212 SCProfileSummarySortByAvgTicks(
const void *a,
const void *b)
214 const SCProfileSummary *s0 = a;
215 const SCProfileSummary *s1 = b;
216 if (s1->avgticks == s0->avgticks)
219 return s0->avgticks > s1->avgticks ? -1 : 1;
226 SCProfileSummarySortByChecks(
const void *a,
const void *b)
228 const SCProfileSummary *s0 = a;
229 const SCProfileSummary *s1 = b;
230 if (s1->checks == s0->checks)
233 return s0->checks > s1->checks ? -1 : 1;
240 SCProfileSummarySortByMatches(
const void *a,
const void *b)
242 const SCProfileSummary *s0 = a;
243 const SCProfileSummary *s1 = b;
244 if (s1->matches == s0->matches)
247 return s0->matches > s1->matches ? -1 : 1;
254 SCProfileSummarySortByMaxTicks(
const void *a,
const void *b)
256 const SCProfileSummary *s0 = a;
257 const SCProfileSummary *s1 = b;
258 if (s1->max == s0->max)
261 return s0->max > s1->max ? -1 : 1;
264 static json_t *BuildJson(
265 SCProfileSummary *summary, uint32_t count, uint64_t total_ticks,
const char *sort_desc)
272 json_t *js = json_object();
275 json_t *jsa = json_array();
281 gettimeofday(&tval, NULL);
283 json_object_set_new(js,
"timestamp", json_string(timebuf));
284 json_object_set_new(js,
"sort", json_string(sort_desc));
286 for (i = 0; i <
MIN(count, profiling_rules_limit); i++) {
290 if (summary[i].checks == 0)
293 json_t *jsm = json_object();
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));
299 json_object_set_new(jsm,
"checks", json_integer(summary[i].checks));
300 json_object_set_new(jsm,
"matches", json_integer(summary[i].matches));
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));
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);
314 json_object_set_new(js,
"rules", jsa);
318 static void DumpJson(FILE *fp, SCProfileSummary *summary, uint32_t count, uint64_t total_ticks,
319 const char *sort_desc)
321 json_t *js = BuildJson(summary, count, total_ticks, sort_desc);
324 char *js_s = json_dumps(js,
325 JSON_PRESERVE_ORDER|JSON_COMPACT|JSON_ENSURE_ASCII|
330 fprintf(fp,
"%s\n", js_s);
335 static void DumpText(FILE *fp, SCProfileSummary *summary,
336 uint32_t count, uint64_t total_ticks,
337 const char *sort_desc)
342 gettimeofday(&tval, NULL);
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,
" -------- "
368 for (i = 0; i <
MIN(count, profiling_rules_limit); i++) {
373 if (summary[i].checks == 0)
376 double percent = (
long double)summary[i].ticks /
377 (
long double)total_ticks * 100;
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",
390 summary[i].avgticks_match,
391 summary[i].avgticks_no_match);
402 static void *SCProfilingRuleDump(SCProfileDetectCtx *rules_ctx,
int file_output)
407 if (rules_ctx == NULL)
410 if (file_output != 0) {
412 fp = fopen(profiling_file_name, profiling_file_mode);
415 SCLogError(
"failed to open %s: %s", profiling_file_name, strerror(errno));
423 int summary_size =
sizeof(SCProfileSummary) * rules_ctx->size;
424 SCProfileSummary *summary =
SCMalloc(summary_size);
426 SCLogError(
"Error allocating memory for profiling summary");
430 uint32_t count = rules_ctx->size;
431 uint64_t total_ticks = 0;
433 SCLogPerf(
"Dumping profiling data for %u rules.", count);
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;
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;
444 if (summary[i].checks > 0) {
445 summary[i].avgticks = (
long double)summary[i].ticks / (
long double)summary[i].checks;
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;
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);
461 total_ticks += summary[i].ticks;
464 int *order = profiling_rules_sort_orders;
465 while (*order != -1) {
466 const char *sort_desc = NULL;
468 case SC_PROFILING_RULES_SORT_BY_TICKS:
469 qsort(summary, count,
sizeof(SCProfileSummary),
470 SCProfileSummarySortByTicks);
473 case SC_PROFILING_RULES_SORT_BY_AVG_TICKS:
474 qsort(summary, count,
sizeof(SCProfileSummary),
475 SCProfileSummarySortByAvgTicks);
476 sort_desc =
"average ticks";
478 case SC_PROFILING_RULES_SORT_BY_CHECKS:
479 qsort(summary, count,
sizeof(SCProfileSummary),
480 SCProfileSummarySortByChecks);
481 sort_desc =
"number of checks";
483 case SC_PROFILING_RULES_SORT_BY_MATCHES:
484 qsort(summary, count,
sizeof(SCProfileSummary),
485 SCProfileSummarySortByMatches);
486 sort_desc =
"number of matches";
488 case SC_PROFILING_RULES_SORT_BY_MAX_TICKS:
489 qsort(summary, count,
sizeof(SCProfileSummary),
490 SCProfileSummarySortByMaxTicks);
491 sort_desc =
"max ticks";
493 case SC_PROFILING_RULES_SORT_BY_AVG_TICKS_MATCH:
494 qsort(summary, count,
sizeof(SCProfileSummary),
495 SCProfileSummarySortByAvgTicksMatch);
496 sort_desc =
"average ticks (match)";
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)";
504 if (profiling_rule_json) {
505 if (file_output != 1) {
506 json_t *js = BuildJson(summary, count, total_ticks, sort_desc);
510 DumpJson(fp, summary, count, total_ticks, sort_desc);
513 DumpText(fp, summary, count, total_ticks, sort_desc);
518 if (file_output != 0) {
523 SCLogPerf(
"Done dumping profiling data.");
533 SCProfilingRegisterRuleCounter(SCProfileDetectCtx *ctx)
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];
557 p->ticks_match += ticks;
559 p->ticks_no_match += ticks;
563 static SCProfileDetectCtx *SCProfilingRuleInitCtx(
void)
565 SCProfileDetectCtx *ctx =
SCMalloc(
sizeof(SCProfileDetectCtx));
567 memset(ctx, 0x00,
sizeof(SCProfileDetectCtx));
569 if (pthread_mutex_init(&ctx->data_m, NULL) != 0) {
570 FatalError(
"Failed to initialize hash table mutex.");
580 SCProfilingRuleDump(ctx, 1);
581 if (ctx->data != NULL)
583 pthread_mutex_destroy(&ctx->data_m);
590 if (ctx == NULL|| ctx->size == 0)
593 SCProfileData *a =
SCMalloc(
sizeof(SCProfileData) * ctx->size);
595 memset(a, 0x00,
sizeof(SCProfileData) * ctx->size);
597 det_ctx->rule_perf_data = a;
598 det_ctx->rule_perf_data_size = ctx->size;
602 static void SCProfilingRuleThreadMerge(
605 if (
de_ctx == NULL ||
de_ctx->profile_ctx == NULL ||
de_ctx->profile_ctx->data == NULL ||
606 det_ctx == NULL || det_ctx->rule_perf_data == NULL)
609 for (
int i = 0; i < det_ctx->rule_perf_data_size; i++) {
610 de_ctx->profile_ctx->data[i].checks += det_ctx->rule_perf_data[i].checks;
611 de_ctx->profile_ctx->data[i].matches += det_ctx->rule_perf_data[i].matches;
612 de_ctx->profile_ctx->data[i].ticks_match += det_ctx->rule_perf_data[i].ticks_match;
613 de_ctx->profile_ctx->data[i].ticks_no_match += det_ctx->rule_perf_data[i].ticks_no_match;
615 det_ctx->rule_perf_data[i].checks = 0;
616 det_ctx->rule_perf_data[i].matches = 0;
617 det_ctx->rule_perf_data[i].ticks_match = 0;
618 det_ctx->rule_perf_data[i].ticks_no_match = 0;
620 if (det_ctx->rule_perf_data[i].max >
de_ctx->profile_ctx->data[i].max)
621 de_ctx->profile_ctx->data[i].max = det_ctx->rule_perf_data[i].max;
627 if (det_ctx == NULL || det_ctx->
de_ctx == NULL || det_ctx->rule_perf_data == NULL)
630 pthread_mutex_lock(&det_ctx->
de_ctx->profile_ctx->data_m);
631 SCProfilingRuleThreadMerge(det_ctx->
de_ctx, det_ctx,
false);
632 pthread_mutex_unlock(&det_ctx->
de_ctx->profile_ctx->data_m);
634 SCFree(det_ctx->rule_perf_data);
635 det_ctx->rule_perf_data = NULL;
636 det_ctx->rule_perf_data_size = 0;
642 if (det_ctx == NULL || det_ctx->
de_ctx == NULL || det_ctx->
de_ctx->profile_ctx == NULL)
644 pthread_mutex_lock(&det_ctx->
de_ctx->profile_ctx->data_m);
645 SCProfilingRuleThreadMerge(det_ctx->
de_ctx, det_ctx,
true);
646 pthread_mutex_unlock(&det_ctx->
de_ctx->profile_ctx->data_m);
660 de_ctx->profile_ctx = SCProfilingRuleInitCtx();
665 while (sig != NULL) {
666 sig->profiling_id = SCProfilingRegisterRuleCounter(
de_ctx->profile_ctx);
674 memset(
de_ctx->profile_ctx->data, 0x00,
sizeof(SCProfileData) *
de_ctx->profile_ctx->size);
677 while (sig != NULL) {
678 de_ctx->profile_ctx->data[sig->profiling_id].sid = sig->
id;
679 de_ctx->profile_ctx->data[sig->profiling_id].gid = sig->
gid;
680 de_ctx->profile_ctx->data[sig->profiling_id].rev = sig->
rev;
685 SCLogPerf(
"Registered %"PRIu32
" rule profiling counters.", count);
690 return SCProfilingRuleDump(
de_ctx->profile_ctx, 0);