40 typedef struct SCProfileSummary_ {
46 double avgticks_match;
47 double avgticks_no_match;
52 uint64_t ticks_no_match;
57 static char profiling_file_name[PATH_MAX] =
"";
58 static const char *profiling_file_mode =
"a";
59 static int profiling_rule_json = 0;
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,
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,
87 static uint32_t profiling_rules_limit = UINT32_MAX;
89 void SCProfilingRulesGlobalInit(
void)
91 #define SET_ONE(x) { \
92 profiling_rules_sort_orders[0] = (x); \
93 profiling_rules_sort_orders[1] = -1; \
106 if (strcmp(val,
"ticks") == 0) {
107 SET_ONE(SC_PROFILING_RULES_SORT_BY_TICKS);
109 else if (strcmp(val,
"avgticks") == 0) {
110 SET_ONE(SC_PROFILING_RULES_SORT_BY_AVG_TICKS);
112 else if (strcmp(val,
"avgticks_match") == 0) {
113 SET_ONE(SC_PROFILING_RULES_SORT_BY_AVG_TICKS_MATCH);
115 else if (strcmp(val,
"avgticks_no_match") == 0) {
116 SET_ONE(SC_PROFILING_RULES_SORT_BY_AVG_TICKS_NO_MATCH);
118 else if (strcmp(val,
"checks") == 0) {
119 SET_ONE(SC_PROFILING_RULES_SORT_BY_CHECKS);
121 else if (strcmp(val,
"matches") == 0) {
122 SET_ONE(SC_PROFILING_RULES_SORT_BY_MATCHES);
124 else if (strcmp(val,
"maxticks") == 0) {
125 SET_ONE(SC_PROFILING_RULES_SORT_BY_MAX_TICKS);
128 SCLogError(
"Invalid profiling sort order: %s", val);
136 (uint16_t)strlen(val), val) <= 0) {
142 if (filename != NULL) {
144 strlcpy(profiling_file_name, filename,
sizeof(profiling_file_name));
147 snprintf(profiling_file_name,
sizeof(profiling_file_name),
"%s/%s", log_dir,
153 profiling_file_mode =
"a";
155 profiling_file_mode =
"w";
161 profiling_rule_json = 1;
172 SCProfileSummarySortByTicks(
const void *a,
const void *b)
174 const SCProfileSummary *s0 = a;
175 const SCProfileSummary *s1 = b;
176 if (s1->ticks == s0->ticks)
179 return s0->ticks > s1->ticks ? -1 : 1;
186 SCProfileSummarySortByAvgTicksMatch(
const void *a,
const void *b)
188 const SCProfileSummary *s0 = a;
189 const SCProfileSummary *s1 = b;
190 if (s1->avgticks_match == s0->avgticks_match)
193 return s0->avgticks_match > s1->avgticks_match ? -1 : 1;
200 SCProfileSummarySortByAvgTicksNoMatch(
const void *a,
const void *b)
202 const SCProfileSummary *s0 = a;
203 const SCProfileSummary *s1 = b;
204 if (s1->avgticks_no_match == s0->avgticks_no_match)
207 return s0->avgticks_no_match > s1->avgticks_no_match ? -1 : 1;
214 SCProfileSummarySortByAvgTicks(
const void *a,
const void *b)
216 const SCProfileSummary *s0 = a;
217 const SCProfileSummary *s1 = b;
218 if (s1->avgticks == s0->avgticks)
221 return s0->avgticks > s1->avgticks ? -1 : 1;
228 SCProfileSummarySortByChecks(
const void *a,
const void *b)
230 const SCProfileSummary *s0 = a;
231 const SCProfileSummary *s1 = b;
232 if (s1->checks == s0->checks)
235 return s0->checks > s1->checks ? -1 : 1;
242 SCProfileSummarySortByMatches(
const void *a,
const void *b)
244 const SCProfileSummary *s0 = a;
245 const SCProfileSummary *s1 = b;
246 if (s1->matches == s0->matches)
249 return s0->matches > s1->matches ? -1 : 1;
256 SCProfileSummarySortByMaxTicks(
const void *a,
const void *b)
258 const SCProfileSummary *s0 = a;
259 const SCProfileSummary *s1 = b;
260 if (s1->max == s0->max)
263 return s0->max > s1->max ? -1 : 1;
266 static json_t *BuildJson(
267 SCProfileSummary *summary, uint32_t count, uint64_t total_ticks,
const char *sort_desc)
274 json_t *js = json_object();
277 json_t *jsa = json_array();
283 gettimeofday(&tval, NULL);
285 json_object_set_new(js,
"timestamp", json_string(timebuf));
286 json_object_set_new(js,
"sort", json_string(sort_desc));
288 for (i = 0; i <
MIN(count, profiling_rules_limit); i++) {
292 if (summary[i].checks == 0)
295 json_t *jsm = json_object();
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));
301 json_object_set_new(jsm,
"checks", json_integer(summary[i].checks));
302 json_object_set_new(jsm,
"matches", json_integer(summary[i].matches));
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));
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);
316 json_object_set_new(js,
"rules", jsa);
320 static void DumpJson(FILE *fp, SCProfileSummary *summary, uint32_t count, uint64_t total_ticks,
321 const char *sort_desc)
323 json_t *js = BuildJson(summary, count, total_ticks, sort_desc);
326 char *js_s = json_dumps(js,
327 JSON_PRESERVE_ORDER|JSON_COMPACT|JSON_ENSURE_ASCII|
332 fprintf(fp,
"%s\n", js_s);
337 static void DumpText(FILE *fp, SCProfileSummary *summary,
338 uint32_t count, uint64_t total_ticks,
339 const char *sort_desc)
344 gettimeofday(&tval, NULL);
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,
" -------- "
370 for (i = 0; i <
MIN(count, profiling_rules_limit); i++) {
375 if (summary[i].checks == 0)
378 double percent = (
long double)summary[i].ticks /
379 (
long double)total_ticks * 100;
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",
392 summary[i].avgticks_match,
393 summary[i].avgticks_no_match);
404 static void *SCProfilingRuleDump(SCProfileDetectCtx *rules_ctx,
int file_output)
409 if (rules_ctx == NULL)
412 if (file_output != 0) {
414 fp = fopen(profiling_file_name, profiling_file_mode);
417 SCLogError(
"failed to open %s: %s", profiling_file_name, strerror(errno));
425 int summary_size =
sizeof(SCProfileSummary) * rules_ctx->size;
426 SCProfileSummary *summary =
SCMalloc(summary_size);
428 SCLogError(
"Error allocating memory for profiling summary");
432 uint32_t count = rules_ctx->size;
433 uint64_t total_ticks = 0;
435 SCLogPerf(
"Dumping profiling data for %u rules.", count);
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;
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;
446 if (summary[i].checks > 0) {
447 summary[i].avgticks = (
long double)summary[i].ticks / (
long double)summary[i].checks;
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;
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);
463 total_ticks += summary[i].ticks;
466 int *order = profiling_rules_sort_orders;
467 while (*order != -1) {
468 const char *sort_desc = NULL;
470 case SC_PROFILING_RULES_SORT_BY_TICKS:
471 qsort(summary, count,
sizeof(SCProfileSummary),
472 SCProfileSummarySortByTicks);
475 case SC_PROFILING_RULES_SORT_BY_AVG_TICKS:
476 qsort(summary, count,
sizeof(SCProfileSummary),
477 SCProfileSummarySortByAvgTicks);
478 sort_desc =
"average ticks";
480 case SC_PROFILING_RULES_SORT_BY_CHECKS:
481 qsort(summary, count,
sizeof(SCProfileSummary),
482 SCProfileSummarySortByChecks);
483 sort_desc =
"number of checks";
485 case SC_PROFILING_RULES_SORT_BY_MATCHES:
486 qsort(summary, count,
sizeof(SCProfileSummary),
487 SCProfileSummarySortByMatches);
488 sort_desc =
"number of matches";
490 case SC_PROFILING_RULES_SORT_BY_MAX_TICKS:
491 qsort(summary, count,
sizeof(SCProfileSummary),
492 SCProfileSummarySortByMaxTicks);
493 sort_desc =
"max ticks";
495 case SC_PROFILING_RULES_SORT_BY_AVG_TICKS_MATCH:
496 qsort(summary, count,
sizeof(SCProfileSummary),
497 SCProfileSummarySortByAvgTicksMatch);
498 sort_desc =
"average ticks (match)";
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)";
506 if (profiling_rule_json) {
507 if (file_output != 1) {
508 json_t *js = BuildJson(summary, count, total_ticks, sort_desc);
512 DumpJson(fp, summary, count, total_ticks, sort_desc);
515 DumpText(fp, summary, count, total_ticks, sort_desc);
520 if (file_output != 0) {
525 SCLogPerf(
"Done dumping profiling data.");
535 SCProfilingRegisterRuleCounter(SCProfileDetectCtx *
ctx)
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];
559 p->ticks_match += ticks;
561 p->ticks_no_match += ticks;
565 static SCProfileDetectCtx *SCProfilingRuleInitCtx(
void)
567 SCProfileDetectCtx *
ctx =
SCCalloc(1,
sizeof(SCProfileDetectCtx));
569 if (pthread_mutex_init(&
ctx->data_m, NULL) != 0) {
570 FatalError(
"Failed to initialize hash table mutex.");
577 void SCProfilingRuleDestroyCtx(SCProfileDetectCtx *
ctx)
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 =
SCCalloc(
ctx->size,
sizeof(SCProfileData));
595 det_ctx->rule_perf_data = a;
596 det_ctx->rule_perf_data_size =
ctx->size;
600 static void SCProfilingRuleThreadMerge(
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)
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;
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;
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;
625 if (det_ctx == NULL || det_ctx->
de_ctx == NULL || det_ctx->rule_perf_data == NULL)
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);
632 SCFree(det_ctx->rule_perf_data);
633 det_ctx->rule_perf_data = NULL;
634 det_ctx->rule_perf_data_size = 0;
640 if (det_ctx == NULL || det_ctx->
de_ctx == NULL || det_ctx->
de_ctx->profile_ctx == NULL)
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);
658 de_ctx->profile_ctx = SCProfilingRuleInitCtx();
663 while (sig != NULL) {
664 sig->profiling_id = SCProfilingRegisterRuleCounter(
de_ctx->profile_ctx);
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;
682 SCLogPerf(
"Registered %"PRIu32
" rule profiling counters.", count);
687 return SCProfilingRuleDump(
de_ctx->profile_ctx, 0);