suricata
util-profiling.c
Go to the documentation of this file.
1/* Copyright (C) 2007-2024 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 profiling operations.
25 *
26 * Really just a wrapper around the existing perf counters.
27 */
28
29#include "suricata-common.h"
30#include "util-profiling.h"
31
32#ifdef PROFILING
33#include "tm-threads.h"
34#include "conf.h"
35#include "util-unittest.h"
36#include "util-byte.h"
38#include "util-conf.h"
39#include "util-path.h"
40
41#ifndef MIN
42#define MIN(a, b) (((a) < (b)) ? (a) : (b))
43#endif
44
45static pthread_mutex_t packet_profile_lock;
46static FILE *packet_profile_csv_fp = NULL;
47
50extern char *profiling_locks_file_name;
51extern const char *profiling_locks_file_mode;
52
53typedef struct SCProfilePacketData_ {
54 uint64_t min;
55 uint64_t max;
56 uint64_t tot;
57 uint64_t cnt;
58#ifdef PROFILE_LOCKING
59 uint64_t lock;
60 uint64_t ticks;
61 uint64_t contention;
62
63 uint64_t slock;
64 uint64_t sticks;
65 uint64_t scontention;
66#endif
68SCProfilePacketData packet_profile_data4[257]; /**< all proto's + tunnel */
69SCProfilePacketData packet_profile_data6[257]; /**< all proto's + tunnel */
70
71/* each module, each proto */
74
77
80
83
86
91
93
96
97static int profiling_packets_csv_enabled = 0;
98static int profiling_packets_output_to_file = 0;
99static char *profiling_file_name;
100static char profiling_packets_file_name[PATH_MAX];
101static char *profiling_csv_file_name;
102static const char *profiling_packets_file_mode = "a";
103
104static int rate = 1;
105static SC_ATOMIC_DECLARE(uint64_t, samples);
106
107/**
108 * Used as a check so we don't double enter a profiling run.
109 */
110thread_local int profiling_rules_entered = 0;
111
115static void PrintCSVHeader(void);
116
117static void FormatNumber(uint64_t num, char *str, size_t size)
118{
119 if (num < 1000UL)
120 snprintf(str, size, "%"PRIu64, num);
121 else if (num < 1000000UL)
122 snprintf(str, size, "%3.1fk", (float)num/1000UL);
123 else if (num < 1000000000UL)
124 snprintf(str, size, "%3.1fm", (float)num/1000000UL);
125 else
126 snprintf(str, size, "%3.1fb", (float)num/1000000000UL);
127}
128
129/**
130 * \brief Initialize profiling.
131 */
132void
134{
135 SCConfNode *conf;
136
137 SC_ATOMIC_INIT(samples);
138
139 intmax_t rate_v = 0;
140 (void)SCConfGetInt("profiling.sample-rate", &rate_v);
141 if (rate_v > 0 && rate_v < INT_MAX) {
142 rate = (int)rate_v;
143 if (rate != 1)
144 SCLogInfo("profiling runs for every %dth packet", rate);
145 else
146 SCLogInfo("profiling runs for every packet");
147 }
148
149 conf = SCConfGetNode("profiling.packets");
150 if (conf != NULL) {
151 if (SCConfNodeChildValueIsTrue(conf, "enabled")) {
153
154 if (pthread_mutex_init(&packet_profile_lock, NULL) != 0) {
155 FatalError("Failed to initialize packet profiling mutex.");
156 }
157 memset(&packet_profile_data4, 0, sizeof(packet_profile_data4));
158 memset(&packet_profile_data6, 0, sizeof(packet_profile_data6));
162 if (packet_profile_app_data4 == NULL) {
163 FatalError("Failed to allocate packet_profile_app_data4");
164 }
166 if (packet_profile_app_data6 == NULL) {
167 FatalError("Failed to allocate packet_profile_app_data6");
168 }
176
177 const char *filename = SCConfNodeLookupChildValue(conf, "filename");
178 if (filename != NULL) {
179 if (PathIsAbsolute(filename)) {
180 strlcpy(profiling_packets_file_name, filename,
181 sizeof(profiling_packets_file_name));
182 } else {
183 const char *log_dir = SCConfigGetLogDirectory();
184 snprintf(profiling_packets_file_name, sizeof(profiling_packets_file_name),
185 "%s/%s", log_dir, filename);
186 }
187
188 const char *v = SCConfNodeLookupChildValue(conf, "append");
189 if (v == NULL || SCConfValIsTrue(v)) {
190 profiling_packets_file_mode = "a";
191 } else {
192 profiling_packets_file_mode = "w";
193 }
194
195 profiling_packets_output_to_file = 1;
196 }
197 }
198
199 conf = SCConfGetNode("profiling.packets.csv");
200 if (conf != NULL) {
201 if (SCConfNodeChildValueIsTrue(conf, "enabled")) {
202 const char *filename = SCConfNodeLookupChildValue(conf, "filename");
203 if (filename == NULL) {
204 filename = "packet_profile.csv";
205 }
206 if (PathIsAbsolute(filename)) {
207 profiling_csv_file_name = SCStrdup(filename);
208 if (unlikely(profiling_csv_file_name == NULL)) {
209 FatalError("out of memory");
210 }
211 } else {
212 profiling_csv_file_name = SCMalloc(PATH_MAX);
213 if (unlikely(profiling_csv_file_name == NULL)) {
214 FatalError("out of memory");
215 }
216
217 const char *log_dir = SCConfigGetLogDirectory();
218 snprintf(profiling_csv_file_name, PATH_MAX, "%s/%s", log_dir, filename);
219 }
220
221 packet_profile_csv_fp = fopen(profiling_csv_file_name, "w");
222 if (packet_profile_csv_fp == NULL) {
223 SCFree(profiling_csv_file_name);
224 profiling_csv_file_name = NULL;
225 return;
226 }
227
228 PrintCSVHeader();
229
230 profiling_packets_csv_enabled = 1;
231 }
232 }
233 }
234
235 conf = SCConfGetNode("profiling.locks");
236 if (conf != NULL) {
237 if (SCConfNodeChildValueIsTrue(conf, "enabled")) {
238#ifndef PROFILE_LOCKING
240 "lock profiling not compiled in. Add --enable-profiling-locks to configure.");
241#else
243
245
246 const char *filename = SCConfNodeLookupChildValue(conf, "filename");
247 if (filename != NULL) {
248 const char *log_dir = SCConfigGetLogDirectory();
249
251 if (unlikely(profiling_locks_file_name == NULL)) {
252 FatalError("can't duplicate file name");
253 }
254
255 snprintf(profiling_locks_file_name, PATH_MAX, "%s/%s", log_dir, filename);
256
257 const char *v = SCConfNodeLookupChildValue(conf, "append");
258 if (v == NULL || SCConfValIsTrue(v)) {
260 } else {
262 }
263
265 }
266#endif
267 }
268 }
269
270}
271
272/**
273 * \brief Free resources used by profiling.
274 */
275void
277{
281 }
285 }
286
288 pthread_mutex_destroy(&packet_profile_lock);
289 }
290
291 if (profiling_packets_csv_enabled) {
292 if (packet_profile_csv_fp != NULL)
293 fclose(packet_profile_csv_fp);
294 packet_profile_csv_fp = NULL;
295 }
296
297 if (profiling_csv_file_name != NULL)
298 SCFree(profiling_csv_file_name);
299 profiling_csv_file_name = NULL;
300
301 if (profiling_file_name != NULL)
302 SCFree(profiling_file_name);
303 profiling_file_name = NULL;
304
305#ifdef PROFILE_LOCKING
307#endif
308}
309
310void
312{
314 SCLogPerf("Done dumping profiling data.");
315}
316
317static void DumpFlowWorkerIP(FILE *fp, int ipv, uint64_t total)
318{
319 char totalstr[256];
320
321 enum ProfileFlowWorkerId fwi;
322 for (fwi = 0; fwi < PROFILE_FLOWWORKER_SIZE; fwi++) {
324 for (int p = 0; p < 257; p++) {
325 SCProfilePacketData *pd = ipv == 4 ? &r->records4[p] : &r->records6[p];
326 if (pd->cnt == 0) {
327 continue;
328 }
329
330 FormatNumber(pd->tot, totalstr, sizeof(totalstr));
331 double percent = (long double)pd->tot /
332 (long double)total * 100;
333
334 fprintf(fp, "%-20s IPv%d %3d %12"PRIu64" %12"PRIu64" %12"PRIu64" %12"PRIu64" %12s %-6.2f\n",
335 ProfileFlowWorkerIdToString(fwi), ipv, p, pd->cnt,
336 pd->min, pd->max, (uint64_t)(pd->tot / pd->cnt), totalstr, percent);
337 }
338 }
339}
340
341static void DumpFlowWorker(FILE *fp)
342{
343 uint64_t total = 0;
344
345 enum ProfileFlowWorkerId fwi;
346 for (fwi = 0; fwi < PROFILE_FLOWWORKER_SIZE; fwi++) {
348 for (int p = 0; p < 257; p++) {
349 SCProfilePacketData *pd = &r->records4[p];
350 total += pd->tot;
351 pd = &r->records6[p];
352 total += pd->tot;
353 }
354 }
355
356 fprintf(fp, "\n%-20s %-6s %-5s %-12s %-12s %-12s %-12s\n",
357 "Flow Worker", "IP ver", "Proto", "cnt", "min", "max", "avg");
358 fprintf(fp, "%-20s %-6s %-5s %-12s %-12s %-12s %-12s\n",
359 "--------------------", "------", "-----", "----------", "------------", "------------", "-----------");
360 DumpFlowWorkerIP(fp, 4, total);
361 DumpFlowWorkerIP(fp, 6, total);
362 fprintf(fp, "Note: %s includes app-layer for TCP\n",
364}
365
367{
368 FILE *fp;
369 char totalstr[256];
370 uint64_t total;
371
373 return;
374
375 if (profiling_packets_output_to_file == 1) {
376 fp = fopen(profiling_packets_file_name, profiling_packets_file_mode);
377
378 if (fp == NULL) {
379 SCLogError("failed to open %s: %s", profiling_packets_file_name, strerror(errno));
380 return;
381 }
382 } else {
383 fp = stdout;
384 }
385
386 fprintf(fp, "\n\nPacket profile dump:\n");
387
388 fprintf(fp, "\n%-6s %-5s %-12s %-12s %-12s %-12s %-12s %-3s\n",
389 "IP ver", "Proto", "cnt", "min", "max", "avg", "tot", "%%");
390 fprintf(fp, "%-6s %-5s %-12s %-12s %-12s %-12s %-12s %-3s\n",
391 "------", "-----", "----------", "------------", "------------", "-----------", "-----------", "---");
392 total = 0;
393 for (int i = 0; i < 257; i++) {
395 total += pd->tot;
396 pd = &packet_profile_data6[i];
397 total += pd->tot;
398 }
399
400 for (int i = 0; i < 257; i++) {
402 if (pd->cnt == 0) {
403 continue;
404 }
405
406 FormatNumber(pd->tot, totalstr, sizeof(totalstr));
407 double percent = (long double)pd->tot /
408 (long double)total * 100;
409
410 fprintf(fp, " IPv4 %3d %12"PRIu64" %12"PRIu64" %12"PRIu64" %12"PRIu64" %12s %6.2f\n", i, pd->cnt,
411 pd->min, pd->max, (uint64_t)(pd->tot / pd->cnt), totalstr, percent);
412 }
413
414 for (int i = 0; i < 257; i++) {
416 if (pd->cnt == 0) {
417 continue;
418 }
419
420 FormatNumber(pd->tot, totalstr, sizeof(totalstr));
421 double percent = (long double)pd->tot /
422 (long double)total * 100;
423
424 fprintf(fp, " IPv6 %3d %12"PRIu64" %12"PRIu64" %12"PRIu64" %12"PRIu64" %12s %6.2f\n", i, pd->cnt,
425 pd->min, pd->max, (uint64_t)(pd->tot / pd->cnt), totalstr, percent);
426 }
427 fprintf(fp, "Note: Protocol 256 tracks pseudo/tunnel packets.\n");
428
429 fprintf(fp, "\nPer Thread module stats:\n");
430
431 fprintf(fp, "\n%-24s %-6s %-5s %-12s %-12s %-12s %-12s %-12s %-3s",
432 "Thread Module", "IP ver", "Proto", "cnt", "min", "max", "avg", "tot", "%%");
433#ifdef PROFILE_LOCKING
434 fprintf(fp, " %-10s %-10s %-12s %-12s %-10s %-10s %-12s %-12s\n",
435 "locks", "ticks", "cont.", "cont.avg", "slocks", "sticks", "scont.", "scont.avg");
436#else
437 fprintf(fp, "\n");
438#endif
439 fprintf(fp, "%-24s %-6s %-5s %-12s %-12s %-12s %-12s %-12s %-3s",
440 "------------------------", "------", "-----", "----------", "------------", "------------", "-----------", "-----------", "---");
441#ifdef PROFILE_LOCKING
442 fprintf(fp, " %-10s %-10s %-12s %-12s %-10s %-10s %-12s %-12s\n",
443 "--------", "--------", "----------", "-----------", "--------", "--------", "------------", "-----------");
444#else
445 fprintf(fp, "\n");
446#endif
447 total = 0;
448 for (int m = 0; m < TMM_SIZE; m++) {
449 for (int p = 0; p < 257; p++) {
451 total += pd->tot;
452
453 pd = &packet_profile_tmm_data6[m][p];
454 total += pd->tot;
455 }
456 }
457
458 for (int m = 0; m < TMM_SIZE; m++) {
459 for (int p = 0; p < 257; p++) {
461 if (pd->cnt == 0) {
462 continue;
463 }
464
465 FormatNumber(pd->tot, totalstr, sizeof(totalstr));
466 double percent = (long double)pd->tot /
467 (long double)total * 100;
468
469 fprintf(fp, "%-24s IPv4 %3d %12"PRIu64" %12"PRIu64" %12"PRIu64" %12"PRIu64" %12s %6.2f",
470 TmModuleTmmIdToString(m), p, pd->cnt, pd->min, pd->max, (uint64_t)(pd->tot / pd->cnt), totalstr, percent);
471#ifdef PROFILE_LOCKING
472 fprintf(fp, " %10.2f %12"PRIu64" %12"PRIu64" %10.2f %10.2f %12"PRIu64" %12"PRIu64" %10.2f\n",
473 (float)pd->lock/pd->cnt, (uint64_t)pd->ticks/pd->cnt, pd->contention, (float)pd->contention/pd->cnt, (float)pd->slock/pd->cnt, (uint64_t)pd->sticks/pd->cnt, pd->scontention, (float)pd->scontention/pd->cnt);
474#else
475 fprintf(fp, "\n");
476#endif
477 }
478 }
479
480 for (int m = 0; m < TMM_SIZE; m++) {
481 for (int p = 0; p < 257; p++) {
483 if (pd->cnt == 0) {
484 continue;
485 }
486
487 FormatNumber(pd->tot, totalstr, sizeof(totalstr));
488 double percent = (long double)pd->tot /
489 (long double)total * 100;
490
491 fprintf(fp, "%-24s IPv6 %3d %12"PRIu64" %12"PRIu64" %12"PRIu64" %12"PRIu64" %12s %6.2f\n",
492 TmModuleTmmIdToString(m), p, pd->cnt, pd->min, pd->max, (uint64_t)(pd->tot / pd->cnt), totalstr, percent);
493 }
494 }
495
496 DumpFlowWorker(fp);
497
498 fprintf(fp, "\nPer App layer parser stats:\n");
499
500 fprintf(fp, "\n%-20s %-6s %-5s %-12s %-12s %-12s %-12s\n",
501 "App Layer", "IP ver", "Proto", "cnt", "min", "max", "avg");
502 fprintf(fp, "%-20s %-6s %-5s %-12s %-12s %-12s %-12s\n",
503 "--------------------", "------", "-----", "----------", "------------", "------------", "-----------");
504
505 total = 0;
506 for (AppProto a = 0; a < g_alproto_max; a++) {
507 for (int p = 0; p < 257; p++) {
509 total += pd->tot;
510
511 pd = &packet_profile_app_data6[a * 257 + p];
512 total += pd->tot;
513 }
514 }
515 for (AppProto a = 0; a < g_alproto_max; a++) {
516 for (int p = 0; p < 257; p++) {
518 if (pd->cnt == 0) {
519 continue;
520 }
521
522 FormatNumber(pd->tot, totalstr, sizeof(totalstr));
523 double percent = (long double)pd->tot /
524 (long double)total * 100;
525
526 fprintf(fp,
527 "%-20s IPv4 %3d %12" PRIu64 " %12" PRIu64 " %12" PRIu64
528 " %12" PRIu64 " %12s %-6.2f\n",
529 AppProtoToString(a), p, pd->cnt, pd->min, pd->max,
530 (uint64_t)(pd->tot / pd->cnt), totalstr, percent);
531 }
532 }
533
534 for (AppProto a = 0; a < g_alproto_max; a++) {
535 for (int p = 0; p < 257; p++) {
537 if (pd->cnt == 0) {
538 continue;
539 }
540
541 FormatNumber(pd->tot, totalstr, sizeof(totalstr));
542 double percent = (long double)pd->tot /
543 (long double)total * 100;
544
545 fprintf(fp,
546 "%-20s IPv6 %3d %12" PRIu64 " %12" PRIu64 " %12" PRIu64
547 " %12" PRIu64 " %12s %-6.2f\n",
548 AppProtoToString(a), p, pd->cnt, pd->min, pd->max,
549 (uint64_t)(pd->tot / pd->cnt), totalstr, percent);
550 }
551 }
552
553 /* proto detect output */
554 {
555 for (int p = 0; p < 257; p++) {
557 if (pd->cnt == 0) {
558 continue;
559 }
560
561 FormatNumber(pd->tot, totalstr, sizeof(totalstr));
562 fprintf(fp, "%-20s IPv4 %3d %12"PRIu64" %12"PRIu64" %12"PRIu64" %12"PRIu64" %12s\n",
563 "Proto detect", p, pd->cnt, pd->min, pd->max, (uint64_t)(pd->tot / pd->cnt), totalstr);
564 }
565
566 for (int p = 0; p < 257; p++) {
568 if (pd->cnt == 0) {
569 continue;
570 }
571
572 FormatNumber(pd->tot, totalstr, sizeof(totalstr));
573 fprintf(fp, "%-20s IPv6 %3d %12"PRIu64" %12"PRIu64" %12"PRIu64" %12"PRIu64" %12s\n",
574 "Proto detect", p, pd->cnt, pd->min, pd->max, (uint64_t)(pd->tot / pd->cnt), totalstr);
575 }
576 }
577
578 total = 0;
579 for (int m = 0; m < PROF_DETECT_SIZE; m++) {
580 for (int p = 0; p < 257; p++) {
582 total += pd->tot;
583
585 total += pd->tot;
586 }
587 }
588
589 fprintf(fp, "\n%-24s %-6s %-5s %-12s %-12s %-12s %-12s %-12s %-3s",
590 "Log Thread Module", "IP ver", "Proto", "cnt", "min", "max", "avg", "tot", "%%");
591#ifdef PROFILE_LOCKING
592 fprintf(fp, " %-10s %-10s %-12s %-12s %-10s %-10s %-12s %-12s\n",
593 "locks", "ticks", "cont.", "cont.avg", "slocks", "sticks", "scont.", "scont.avg");
594#else
595 fprintf(fp, "\n");
596#endif
597 fprintf(fp, "%-24s %-6s %-5s %-12s %-12s %-12s %-12s %-12s %-3s",
598 "------------------------", "------", "-----", "----------", "------------", "------------", "-----------", "-----------", "---");
599#ifdef PROFILE_LOCKING
600 fprintf(fp, " %-10s %-10s %-12s %-12s %-10s %-10s %-12s %-12s\n",
601 "--------", "--------", "----------", "-----------", "--------", "--------", "------------", "-----------");
602#else
603 fprintf(fp, "\n");
604#endif
605 total = 0;
606 for (int m = 0; m < TMM_SIZE; m++) {
607 for (int p = 0; p < 257; p++) {
609 total += pd->tot;
610
611 pd = &packet_profile_tmm_data6[m][p];
612 total += pd->tot;
613 }
614 }
615
616 for (int m = 0; m < TMM_SIZE; m++) {
617 for (int p = 0; p < 257; p++) {
619 if (pd->cnt == 0) {
620 continue;
621 }
622
623 FormatNumber(pd->tot, totalstr, sizeof(totalstr));
624 double percent = (long double)pd->tot /
625 (long double)total * 100;
626
627 fprintf(fp, "%-24s IPv4 %3d %12"PRIu64" %12"PRIu64" %12"PRIu64" %12"PRIu64" %12s %6.2f",
628 TmModuleTmmIdToString(m), p, pd->cnt, pd->min, pd->max, (uint64_t)(pd->tot / pd->cnt), totalstr, percent);
629#ifdef PROFILE_LOCKING
630 fprintf(fp, " %10.2f %12"PRIu64" %12"PRIu64" %10.2f %10.2f %12"PRIu64" %12"PRIu64" %10.2f\n",
631 (float)pd->lock/pd->cnt, (uint64_t)pd->ticks/pd->cnt, pd->contention, (float)pd->contention/pd->cnt, (float)pd->slock/pd->cnt, (uint64_t)pd->sticks/pd->cnt, pd->scontention, (float)pd->scontention/pd->cnt);
632#else
633 fprintf(fp, "\n");
634#endif
635 }
636 }
637
638 for (int m = 0; m < TMM_SIZE; m++) {
639 for (int p = 0; p < 257; p++) {
641 if (pd->cnt == 0) {
642 continue;
643 }
644
645 FormatNumber(pd->tot, totalstr, sizeof(totalstr));
646 double percent = (long double)pd->tot /
647 (long double)total * 100;
648
649 fprintf(fp, "%-24s IPv6 %3d %12"PRIu64" %12"PRIu64" %12"PRIu64" %12"PRIu64" %12s %6.2f\n",
650 TmModuleTmmIdToString(m), p, pd->cnt, pd->min, pd->max, (uint64_t)(pd->tot / pd->cnt), totalstr, percent);
651 }
652 }
653
654 fprintf(fp, "\nLogger/output stats:\n");
655
656 total = 0;
657 for (int m = 0; m < LOGGER_SIZE; m++) {
658 for (int p = 0; p < 256; p++) {
660 total += pd->tot;
661 pd = &packet_profile_log_data6[m][p];
662 total += pd->tot;
663 }
664 }
665
666 fprintf(fp, "\n%-24s %-6s %-5s %-12s %-12s %-12s %-12s %-12s\n",
667 "Logger", "IP ver", "Proto", "cnt", "min", "max", "avg", "tot");
668 fprintf(fp, "%-24s %-6s %-5s %-12s %-12s %-12s %-12s %-12s\n",
669 "------------------------", "------", "-----", "----------", "------------", "------------", "-----------", "-----------");
670 for (int m = 0; m < LOGGER_SIZE; m++) {
671 for (int p = 0; p < 256; p++) {
673 if (pd->cnt == 0) {
674 continue;
675 }
676
677 FormatNumber(pd->tot, totalstr, sizeof(totalstr));
678 double percent = (long double)pd->tot /
679 (long double)total * 100;
680
681 fprintf(fp,
682 "%-24s IPv4 %3d %12" PRIu64 " %12" PRIu64 " %12" PRIu64
683 " %12" PRIu64 " %12s %-6.2f\n",
684 PacketProfileLoggerIdToString(m), p, pd->cnt, pd->min, pd->max,
685 (uint64_t)(pd->tot / pd->cnt), totalstr, percent);
686 }
687 }
688 for (int m = 0; m < LOGGER_SIZE; m++) {
689 for (int p = 0; p < 256; p++) {
691 if (pd->cnt == 0) {
692 continue;
693 }
694
695 FormatNumber(pd->tot, totalstr, sizeof(totalstr));
696 double percent = (long double)pd->tot /
697 (long double)total * 100;
698
699 fprintf(fp,
700 "%-24s IPv6 %3d %12" PRIu64 " %12" PRIu64 " %12" PRIu64
701 " %12" PRIu64 " %12s %-6.2f\n",
702 PacketProfileLoggerIdToString(m), p, pd->cnt, pd->min, pd->max,
703 (uint64_t)(pd->tot / pd->cnt), totalstr, percent);
704 }
705 }
706
707 fprintf(fp, "\nGeneral detection engine stats:\n");
708
709 total = 0;
710 for (int m = 0; m < PROF_DETECT_SIZE; m++) {
711 for (int p = 0; p < 257; p++) {
713 total += pd->tot;
715 total += pd->tot;
716 }
717 }
718
719 fprintf(fp, "\n%-24s %-6s %-5s %-12s %-12s %-12s %-12s %-12s\n",
720 "Detection phase", "IP ver", "Proto", "cnt", "min", "max", "avg", "tot");
721 fprintf(fp, "%-24s %-6s %-5s %-12s %-12s %-12s %-12s %-12s\n",
722 "------------------------", "------", "-----", "----------", "------------", "------------", "-----------", "-----------");
723 for (int m = 0; m < PROF_DETECT_SIZE; m++) {
724 for (int p = 0; p < 257; p++) {
726 if (pd->cnt == 0) {
727 continue;
728 }
729
730 FormatNumber(pd->tot, totalstr, sizeof(totalstr));
731 double percent = (long double)pd->tot /
732 (long double)total * 100;
733
734 fprintf(fp, "%-24s IPv4 %3d %12"PRIu64" %12"PRIu64" %12"PRIu64" %12"PRIu64" %12s %-6.2f\n",
735 PacketProfileDetectIdToString(m), p, pd->cnt, pd->min, pd->max, (uint64_t)(pd->tot / pd->cnt), totalstr, percent);
736 }
737 }
738 for (int m = 0; m < PROF_DETECT_SIZE; m++) {
739 for (int p = 0; p < 257; p++) {
741 if (pd->cnt == 0) {
742 continue;
743 }
744
745 FormatNumber(pd->tot, totalstr, sizeof(totalstr));
746 double percent = (long double)pd->tot /
747 (long double)total * 100;
748
749 fprintf(fp, "%-24s IPv6 %3d %12"PRIu64" %12"PRIu64" %12"PRIu64" %12"PRIu64" %12s %-6.2f\n",
750 PacketProfileDetectIdToString(m), p, pd->cnt, pd->min, pd->max, (uint64_t)(pd->tot / pd->cnt), totalstr, percent);
751 }
752 }
753 fclose(fp);
754}
755
756static void PrintCSVHeader(void)
757{
758 fprintf(packet_profile_csv_fp, "pcap_cnt,total,receive,decode,flowworker,");
759 fprintf(packet_profile_csv_fp, "threading,");
760 fprintf(packet_profile_csv_fp, "proto detect,");
761
762 for (enum ProfileFlowWorkerId fwi = 0; fwi < PROFILE_FLOWWORKER_SIZE; fwi++) {
763 fprintf(packet_profile_csv_fp, "%s,", ProfileFlowWorkerIdToString(fwi));
764 }
765 fprintf(packet_profile_csv_fp, "loggers,");
766
767 /* detect stages */
768 for (int i = 0; i < PROF_DETECT_SIZE; i++) {
769 fprintf(packet_profile_csv_fp, "%s,", PacketProfileDetectIdToString(i));
770 }
771
772 /* individual loggers */
773 for (LoggerId i = 0; i < LOGGER_SIZE; i++) {
774 fprintf(packet_profile_csv_fp, "%s,", PacketProfileLoggerIdToString(i));
775 }
776
777 fprintf(packet_profile_csv_fp, "\n");
778}
779
781{
782 if (profiling_packets_csv_enabled == 0 || p == NULL ||
783 packet_profile_csv_fp == NULL || p->profile == NULL) {
784 return;
785 }
786
787 uint64_t tmm_total = 0;
788 uint64_t receive = 0;
789 uint64_t decode = 0;
790
791 /* total cost from acquisition to return to packetpool */
792 uint64_t delta = p->profile->ticks_end - p->profile->ticks_start;
793 fprintf(packet_profile_csv_fp, "%"PRIu64",%"PRIu64",",
794 p->pcap_cnt, delta);
795
796 for (int i = 0; i < TMM_SIZE; i++) {
797 const PktProfilingTmmData *pdt = &p->profile->tmm[i];
798 uint64_t tmm_delta = pdt->ticks_end - pdt->ticks_start;
799
801 if (tmm_delta) {
802 receive = tmm_delta;
803 }
804 continue;
805
806 } else if (tmm_modules[i].flags & TM_FLAG_DECODE_TM) {
807 if (tmm_delta) {
808 decode = tmm_delta;
809 }
810 continue;
811 }
812
813 tmm_total += tmm_delta;
814 }
815 fprintf(packet_profile_csv_fp, "%"PRIu64",", receive);
816 fprintf(packet_profile_csv_fp, "%"PRIu64",", decode);
818 fprintf(packet_profile_csv_fp, "%"PRIu64",", fw_pdt->ticks_end - fw_pdt->ticks_start);
819 fprintf(packet_profile_csv_fp, "%"PRIu64",", delta - tmm_total);
820
821 /* count ticks for app layer */
822 uint64_t app_total = 0;
823 for (AppProto i = 0; i < g_alproto_max; i++) {
824 const PktProfilingAppData *pdt = &p->profile->app[i];
825
826 if (p->proto == IPPROTO_TCP) {
827 app_total += pdt->ticks_spent;
828 }
829 }
830
831 fprintf(packet_profile_csv_fp, "%"PRIu64",", p->profile->proto_detect);
832
833 /* print flowworker steps */
834 for (enum ProfileFlowWorkerId fwi = 0; fwi < PROFILE_FLOWWORKER_SIZE; fwi++) {
835 const PktProfilingData *pd = &p->profile->flowworker[fwi];
836 uint64_t ticks_spent = pd->ticks_end - pd->ticks_start;
837 if (fwi == PROFILE_FLOWWORKER_STREAM) {
838 ticks_spent -= app_total;
839 } else if (fwi == PROFILE_FLOWWORKER_APPLAYERUDP && app_total) {
840 ticks_spent = app_total;
841 }
842
843 fprintf(packet_profile_csv_fp, "%"PRIu64",", ticks_spent);
844 }
845
846 /* count loggers cost and print as a single cost */
847 uint64_t loggers = 0;
848 for (LoggerId i = 0; i < LOGGER_SIZE; i++) {
849 const PktProfilingLoggerData *pd = &p->profile->logger[i];
850 loggers += pd->ticks_spent;
851 }
852 fprintf(packet_profile_csv_fp, "%"PRIu64",", loggers);
853
854 /* detect steps */
855 for (int i = 0; i < PROF_DETECT_SIZE; i++) {
856 const PktProfilingDetectData *pdt = &p->profile->detect[i];
857
858 fprintf(packet_profile_csv_fp,"%"PRIu64",", pdt->ticks_spent);
859 }
860
861 /* print individual loggers */
862 for (LoggerId i = 0; i < LOGGER_SIZE; i++) {
863 const PktProfilingLoggerData *pd = &p->profile->logger[i];
864 fprintf(packet_profile_csv_fp, "%"PRIu64",", pd->ticks_spent);
865 }
866
867 fprintf(packet_profile_csv_fp,"\n");
868}
869
870static void SCProfilingUpdatePacketDetectRecord(PacketProfileDetectId id, uint8_t ipproto, PktProfilingDetectData *pdt, int ipver)
871{
872 if (pdt == NULL) {
873 return;
874 }
875
877 if (ipver == 4)
878 pd = &packet_profile_detect_data4[id][ipproto];
879 else
880 pd = &packet_profile_detect_data6[id][ipproto];
881
882 if (pd->min == 0 || pdt->ticks_spent < pd->min) {
883 pd->min = pdt->ticks_spent;
884 }
885 if (pd->max < pdt->ticks_spent) {
886 pd->max = pdt->ticks_spent;
887 }
888
889 pd->tot += pdt->ticks_spent;
890 pd->cnt ++;
891}
892
893static void SCProfilingUpdatePacketDetectRecords(Packet *p)
894{
896 for (i = 0; i < PROF_DETECT_SIZE; i++) {
898
899 if (pdt->ticks_spent > 0) {
900 if (PacketIsIPv4(p)) {
901 SCProfilingUpdatePacketDetectRecord(i, p->proto, pdt, 4);
902 } else {
903 SCProfilingUpdatePacketDetectRecord(i, p->proto, pdt, 6);
904 }
905 }
906 }
907}
908
909static void SCProfilingUpdatePacketAppPdRecord(uint8_t ipproto, uint32_t ticks_spent, int ipver)
910{
912 if (ipver == 4)
913 pd = &packet_profile_app_pd_data4[ipproto];
914 else
915 pd = &packet_profile_app_pd_data6[ipproto];
916
917 if (pd->min == 0 || ticks_spent < pd->min) {
918 pd->min = ticks_spent;
919 }
920 if (pd->max < ticks_spent) {
921 pd->max = ticks_spent;
922 }
923
924 pd->tot += ticks_spent;
925 pd->cnt ++;
926}
927
928static void SCProfilingUpdatePacketAppRecord(int alproto, uint8_t ipproto, PktProfilingAppData *pdt, int ipver)
929{
930 if (pdt == NULL) {
931 return;
932 }
933
935 if (ipver == 4)
936 pd = &packet_profile_app_data4[alproto * 257 + ipproto];
937 else
938 pd = &packet_profile_app_data6[alproto * 257 + ipproto];
939
940 if (pd->min == 0 || pdt->ticks_spent < pd->min) {
941 pd->min = pdt->ticks_spent;
942 }
943 if (pd->max < pdt->ticks_spent) {
944 pd->max = pdt->ticks_spent;
945 }
946
947 pd->tot += pdt->ticks_spent;
948 pd->cnt ++;
949}
950
951static void SCProfilingUpdatePacketAppRecords(Packet *p)
952{
953 int i;
954 for (i = 0; i < g_alproto_max; i++) {
955 PktProfilingAppData *pdt = &p->profile->app[i];
956
957 if (pdt->ticks_spent > 0) {
958 if (PacketIsIPv4(p)) {
959 SCProfilingUpdatePacketAppRecord(i, p->proto, pdt, 4);
960 } else {
961 SCProfilingUpdatePacketAppRecord(i, p->proto, pdt, 6);
962 }
963 }
964 }
965
966 if (p->profile->proto_detect > 0) {
967 if (PacketIsIPv4(p)) {
968 SCProfilingUpdatePacketAppPdRecord(p->proto, p->profile->proto_detect, 4);
969 } else {
970 SCProfilingUpdatePacketAppPdRecord(p->proto, p->profile->proto_detect, 6);
971 }
972 }
973}
974
975static void SCProfilingUpdatePacketTmmRecord(int module, uint8_t proto, PktProfilingTmmData *pdt, int ipver)
976{
977 if (pdt == NULL) {
978 return;
979 }
980
982 if (ipver == 4)
983 pd = &packet_profile_tmm_data4[module][proto];
984 else
985 pd = &packet_profile_tmm_data6[module][proto];
986
987 uint32_t delta = (uint32_t)pdt->ticks_end - pdt->ticks_start;
988 if (pd->min == 0 || delta < pd->min) {
989 pd->min = delta;
990 }
991 if (pd->max < delta) {
992 pd->max = delta;
993 }
994
995 pd->tot += (uint64_t)delta;
996 pd->cnt ++;
997
998#ifdef PROFILE_LOCKING
999 pd->lock += pdt->mutex_lock_cnt;
1000 pd->ticks += pdt->mutex_lock_wait_ticks;
1001 pd->contention += pdt->mutex_lock_contention;
1002 pd->slock += pdt->spin_lock_cnt;
1003 pd->sticks += pdt->spin_lock_wait_ticks;
1004 pd->scontention += pdt->spin_lock_contention;
1005#endif
1006}
1007
1008static void SCProfilingUpdatePacketTmmRecords(Packet *p)
1009{
1010 int i;
1011 for (i = 0; i < TMM_SIZE; i++) {
1012 PktProfilingTmmData *pdt = &p->profile->tmm[i];
1013
1014 if (pdt->ticks_start == 0 || pdt->ticks_end == 0 || pdt->ticks_start > pdt->ticks_end) {
1015 continue;
1016 }
1017
1018 if (PacketIsIPv4(p)) {
1019 SCProfilingUpdatePacketTmmRecord(i, p->proto, pdt, 4);
1020 } else {
1021 SCProfilingUpdatePacketTmmRecord(i, p->proto, pdt, 6);
1022 }
1023 }
1024}
1025
1026static inline void SCProfilingUpdatePacketGenericRecord(PktProfilingData *pdt,
1028{
1029 if (pdt == NULL || pd == NULL) {
1030 return;
1031 }
1032
1033 uint64_t delta = pdt->ticks_end - pdt->ticks_start;
1034 if (pd->min == 0 || delta < pd->min) {
1035 pd->min = delta;
1036 }
1037 if (pd->max < delta) {
1038 pd->max = delta;
1039 }
1040
1041 pd->tot += delta;
1042 pd->cnt ++;
1043}
1044
1045static void SCProfilingUpdatePacketGenericRecords(Packet *p, PktProfilingData *pd,
1046 struct ProfileProtoRecords *records, int size)
1047{
1048 int i;
1049 for (i = 0; i < size; i++) {
1050 PktProfilingData *pdt = &pd[i];
1051
1052 if (pdt->ticks_start == 0 || pdt->ticks_end == 0 || pdt->ticks_start > pdt->ticks_end) {
1053 continue;
1054 }
1055
1056 struct ProfileProtoRecords *r = &records[i];
1057 SCProfilePacketData *store = NULL;
1058
1059 if (PacketIsIPv4(p)) {
1060 store = &(r->records4[p->proto]);
1061 } else {
1062 store = &(r->records6[p->proto]);
1063 }
1064
1065 SCProfilingUpdatePacketGenericRecord(pdt, store);
1066 }
1067}
1068
1069static void SCProfilingUpdatePacketLogRecord(LoggerId id,
1070 uint8_t ipproto, PktProfilingLoggerData *pdt, int ipver)
1071{
1072 if (pdt == NULL) {
1073 return;
1074 }
1075
1077 if (ipver == 4)
1078 pd = &packet_profile_log_data4[id][ipproto];
1079 else
1080 pd = &packet_profile_log_data6[id][ipproto];
1081
1082 if (pd->min == 0 || pdt->ticks_spent < pd->min) {
1083 pd->min = pdt->ticks_spent;
1084 }
1085 if (pd->max < pdt->ticks_spent) {
1086 pd->max = pdt->ticks_spent;
1087 }
1088
1089 pd->tot += pdt->ticks_spent;
1090 pd->cnt++;
1091}
1092
1093static void SCProfilingUpdatePacketLogRecords(Packet *p)
1094{
1095 for (LoggerId i = 0; i < LOGGER_SIZE; i++) {
1096 PktProfilingLoggerData *pdt = &p->profile->logger[i];
1097
1098 if (pdt->ticks_spent > 0) {
1099 if (PacketIsIPv4(p)) {
1100 SCProfilingUpdatePacketLogRecord(i, p->proto, pdt, 4);
1101 } else {
1102 SCProfilingUpdatePacketLogRecord(i, p->proto, pdt, 6);
1103 }
1104 }
1105 }
1106}
1107
1109{
1110 if (p == NULL || p->profile == NULL ||
1111 p->profile->ticks_start == 0 || p->profile->ticks_end == 0 ||
1113 return;
1114
1115 pthread_mutex_lock(&packet_profile_lock);
1116 {
1117
1118 if (PacketIsIPv4(p)) {
1120
1121 uint64_t delta = p->profile->ticks_end - p->profile->ticks_start;
1122 if (pd->min == 0 || delta < pd->min) {
1123 pd->min = delta;
1124 }
1125 if (pd->max < delta) {
1126 pd->max = delta;
1127 }
1128
1129 pd->tot += delta;
1130 pd->cnt ++;
1131
1132 if (PacketIsTunnel(p)) {
1133 pd = &packet_profile_data4[256];
1134
1135 if (pd->min == 0 || delta < pd->min) {
1136 pd->min = delta;
1137 }
1138 if (pd->max < delta) {
1139 pd->max = delta;
1140 }
1141
1142 pd->tot += delta;
1143 pd->cnt ++;
1144 }
1145
1146 SCProfilingUpdatePacketGenericRecords(p, p->profile->flowworker,
1148
1149 SCProfilingUpdatePacketTmmRecords(p);
1150 SCProfilingUpdatePacketAppRecords(p);
1151 SCProfilingUpdatePacketDetectRecords(p);
1152 SCProfilingUpdatePacketLogRecords(p);
1153
1154 } else if (PacketIsIPv6(p)) {
1156
1157 uint64_t delta = p->profile->ticks_end - p->profile->ticks_start;
1158 if (pd->min == 0 || delta < pd->min) {
1159 pd->min = delta;
1160 }
1161 if (pd->max < delta) {
1162 pd->max = delta;
1163 }
1164
1165 pd->tot += delta;
1166 pd->cnt ++;
1167
1168 if (PacketIsTunnel(p)) {
1169 pd = &packet_profile_data6[256];
1170
1171 if (pd->min == 0 || delta < pd->min) {
1172 pd->min = delta;
1173 }
1174 if (pd->max < delta) {
1175 pd->max = delta;
1176 }
1177
1178 pd->tot += delta;
1179 pd->cnt ++;
1180 }
1181
1182 SCProfilingUpdatePacketGenericRecords(p, p->profile->flowworker,
1184
1185 SCProfilingUpdatePacketTmmRecords(p);
1186 SCProfilingUpdatePacketAppRecords(p);
1187 SCProfilingUpdatePacketDetectRecords(p);
1188 SCProfilingUpdatePacketLogRecords(p);
1189 }
1190
1191 if (profiling_packets_csv_enabled)
1193
1194 }
1195 pthread_mutex_unlock(&packet_profile_lock);
1196}
1197
1199{
1200 uint64_t sample = SC_ATOMIC_ADD(samples, 1);
1201 if (sample % rate == 0)
1202 return SCCalloc(1, sizeof(PktProfiling) + g_alproto_max * sizeof(PktProfilingAppData));
1203 return NULL;
1204}
1205
1206/* see if we want to profile rules for this packet */
1208{
1209#ifdef PROFILE_LOCKING
1210 if (p->profile != NULL) {
1211 p->flags |= PKT_PROFILE;
1212 return 1;
1213 }
1214#endif
1215 if (p->flags & PKT_PROFILE) {
1216 return 1;
1217 }
1218
1219 uint64_t sample = SC_ATOMIC_ADD(samples, 1);
1220 if ((sample % rate) == 0) {
1221 p->flags |= PKT_PROFILE;
1222 return 1;
1223 }
1224 return 0;
1225}
1226
1227#define CASE_CODE(E) case E: return #E
1228
1229/**
1230 * \brief Maps the PacketProfileDetectId, to its string equivalent
1231 *
1232 * \param id PacketProfileDetectId id
1233 *
1234 * \retval string equivalent for the PacketProfileDetectId id
1235 */
1258
1259/**
1260 * \brief Maps the LoggerId's to its string equivalent for profiling output.
1261 *
1262 * \param id LoggerId id
1263 *
1264 * \retval string equivalent for the LoggerId id
1265 */
1302
1303#ifdef UNITTESTS
1304
1305static int
1306ProfilingGenericTicksTest01(void)
1307{
1308#define TEST_RUNS 1024
1309 uint64_t ticks_start = 0;
1310 uint64_t ticks_end = 0;
1311 void *ptr[TEST_RUNS];
1312 unsigned int i;
1313
1314 ticks_start = UtilCpuGetTicks();
1315 for (i = 0; i < TEST_RUNS; i++) {
1316 ptr[i] = SCMalloc(1024);
1317 }
1318 ticks_end = UtilCpuGetTicks();
1319 printf("malloc(1024) %"PRIu64"\n", (ticks_end - ticks_start)/TEST_RUNS);
1320
1321 ticks_start = UtilCpuGetTicks();
1322 for (i = 0; i < TEST_RUNS; i++) {
1323 SCFree(ptr[i]);
1324 }
1325 ticks_end = UtilCpuGetTicks();
1326 printf("SCFree(1024) %"PRIu64"\n", (ticks_end - ticks_start)/TEST_RUNS);
1327
1329
1330 ticks_start = UtilCpuGetTicks();
1331 for (i = 0; i < TEST_RUNS; i++) {
1332 SCMutexInit(&m[i], NULL);
1333 }
1334 ticks_end = UtilCpuGetTicks();
1335 printf("SCMutexInit() %"PRIu64"\n", (ticks_end - ticks_start)/TEST_RUNS);
1336
1337 ticks_start = UtilCpuGetTicks();
1338 for (i = 0; i < TEST_RUNS; i++) {
1339 SCMutexLock(&m[i]);
1340 }
1341 ticks_end = UtilCpuGetTicks();
1342 printf("SCMutexLock() %"PRIu64"\n", (ticks_end - ticks_start)/TEST_RUNS);
1343
1344 ticks_start = UtilCpuGetTicks();
1345 for (i = 0; i < TEST_RUNS; i++) {
1346 SCMutexUnlock(&m[i]);
1347 }
1348 ticks_end = UtilCpuGetTicks();
1349 printf("SCMutexUnlock() %"PRIu64"\n", (ticks_end - ticks_start)/TEST_RUNS);
1350
1351 ticks_start = UtilCpuGetTicks();
1352 for (i = 0; i < TEST_RUNS; i++) {
1353 SCMutexDestroy(&m[i]);
1354 }
1355 ticks_end = UtilCpuGetTicks();
1356 printf("SCMutexDestroy() %"PRIu64"\n", (ticks_end - ticks_start)/TEST_RUNS);
1357
1359
1360 ticks_start = UtilCpuGetTicks();
1361 for (i = 0; i < TEST_RUNS; i++) {
1362 SCSpinInit(&s[i], 0);
1363 }
1364 ticks_end = UtilCpuGetTicks();
1365 printf("SCSpinInit() %"PRIu64"\n", (ticks_end - ticks_start)/TEST_RUNS);
1366
1367 ticks_start = UtilCpuGetTicks();
1368 for (i = 0; i < TEST_RUNS; i++) {
1369 SCSpinLock(&s[i]);
1370 }
1371 ticks_end = UtilCpuGetTicks();
1372 printf("SCSpinLock() %"PRIu64"\n", (ticks_end - ticks_start)/TEST_RUNS);
1373
1374 ticks_start = UtilCpuGetTicks();
1375 for (i = 0; i < TEST_RUNS; i++) {
1376 SCSpinUnlock(&s[i]);
1377 }
1378 ticks_end = UtilCpuGetTicks();
1379 printf("SCSpinUnlock() %"PRIu64"\n", (ticks_end - ticks_start)/TEST_RUNS);
1380
1381 ticks_start = UtilCpuGetTicks();
1382 for (i = 0; i < TEST_RUNS; i++) {
1383 SCSpinDestroy(&s[i]);
1384 }
1385 ticks_end = UtilCpuGetTicks();
1386 printf("SCSpinDestroy() %"PRIu64"\n", (ticks_end - ticks_start)/TEST_RUNS);
1387
1388 SC_ATOMIC_DECL_AND_INIT(unsigned int, test);
1389 ticks_start = UtilCpuGetTicks();
1390 for (i = 0; i < TEST_RUNS; i++) {
1391 (void) SC_ATOMIC_ADD(test,1);
1392 }
1393 ticks_end = UtilCpuGetTicks();
1394 printf("SC_ATOMIC_ADD %"PRIu64"\n", (ticks_end - ticks_start)/TEST_RUNS);
1395
1396 ticks_start = UtilCpuGetTicks();
1397 for (i = 0; i < TEST_RUNS; i++) {
1398 SC_ATOMIC_CAS(&test,i,i+1);
1399 }
1400 ticks_end = UtilCpuGetTicks();
1401 printf("SC_ATOMIC_CAS %"PRIu64"\n", (ticks_end - ticks_start)/TEST_RUNS);
1402 return 1;
1403}
1404
1405#endif /* UNITTESTS */
1406
1407void
1409{
1410#ifdef UNITTESTS
1411 UtRegisterTest("ProfilingGenericTicksTest01", ProfilingGenericTicksTest01);
1412#endif /* UNITTESTS */
1413}
1414
1416{
1417}
1418
1420{
1421}
1422
1423#elif PROFILE_RULES
1424
1425thread_local int profiling_rules_entered = 0;
1427static SC_ATOMIC_DECLARE(uint64_t, samples);
1428static uint64_t rate = 0;
1429static SC_ATOMIC_DECLARE(bool, profiling_rules_active);
1430
1431/**
1432 * \brief Initialize profiling.
1433 */
1434void SCProfilingInit(void)
1435{
1436 SC_ATOMIC_INIT(profiling_rules_active);
1437 SC_ATOMIC_INIT(samples);
1438 intmax_t rate_v = 0;
1439 SCConfNode *conf;
1440
1441 (void)SCConfGetInt("profiling.sample-rate", &rate_v);
1442 if (rate_v > 0 && rate_v < INT_MAX) {
1443 int literal_rate = (int)rate_v;
1444 for (int i = literal_rate; i >= 1; i--) {
1445 /* If i is a power of 2 */
1446 if ((i & (i - 1)) == 0) {
1447 rate = i - 1;
1448 break;
1449 }
1450 }
1451 if (rate != 0)
1452 SCLogInfo("profiling runs for every %luth packet", rate + 1);
1453 else
1454 SCLogInfo("profiling runs for every packet");
1455 }
1456
1457 conf = SCConfGetNode("profiling.rules");
1458 if (SCConfNodeChildValueIsTrue(conf, "active")) {
1459 SC_ATOMIC_SET(profiling_rules_active, 1);
1460 }
1461}
1462
1463/* see if we want to profile rules for this packet */
1465{
1466 /* Move first so we'll always finish even if dynamically disabled */
1467 if (p->flags & PKT_PROFILE)
1468 return 1;
1469
1470 if (!SC_ATOMIC_GET(profiling_rules_active)) {
1471 return 0;
1472 }
1473
1474 uint64_t sample = SC_ATOMIC_ADD(samples, 1);
1475 if ((sample & rate) == 0) {
1476 p->flags |= PKT_PROFILE;
1477 return 1;
1478 }
1479 return 0;
1480}
1481
1483{
1484 SC_ATOMIC_SET(profiling_rules_active, true);
1485}
1486
1488{
1489 SC_ATOMIC_SET(profiling_rules_active, false);
1490}
1491
1492#endif /* PROFILING */
AppProto g_alproto_max
const char * AppProtoToString(AppProto alproto)
Maps the ALPROTO_*, to its string equivalent.
uint16_t AppProto
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
int SCConfGetInt(const char *name, intmax_t *val)
Retrieve a configuration value as an integer.
Definition conf.c:414
const char * SCConfNodeLookupChildValue(const SCConfNode *node, const char *name)
Lookup the value of a child configuration node by name.
Definition conf.c:824
uint8_t flags
Definition decode-gre.h:0
uint8_t proto
#define PKT_PROFILE
Definition decode.h:1292
uint32_t id
SCMutex m
Definition flow-hash.h:6
const char * ProfileFlowWorkerIdToString(enum ProfileFlowWorkerId fwi)
ProfileFlowWorkerId
Definition flow-worker.h:21
@ PROFILE_FLOWWORKER_SIZE
Definition flow-worker.h:29
@ PROFILE_FLOWWORKER_APPLAYERUDP
Definition flow-worker.h:24
@ PROFILE_FLOWWORKER_STREAM
Definition flow-worker.h:23
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
HRLOCK_TYPE lock
Definition host.h:0
uint64_t pcap_cnt
Definition decode.h:626
PktProfiling * profile
Definition decode.h:673
uint32_t flags
Definition decode.h:544
uint8_t proto
Definition decode.h:523
uint64_t ticks_spent
Definition decode.h:356
uint64_t ticks_start
Definition decode.h:345
uint64_t ticks_end
Definition decode.h:346
Per TMM stats storage.
Definition decode.h:325
uint64_t ticks_start
Definition decode.h:326
uint64_t ticks_end
Definition decode.h:327
Per pkt stats storage.
Definition decode.h:366
uint64_t ticks_start
Definition decode.h:367
PktProfilingData flowworker[PROFILE_FLOWWORKER_SIZE]
Definition decode.h:371
PktProfilingTmmData tmm[TMM_SIZE]
Definition decode.h:370
uint64_t proto_detect
Definition decode.h:374
uint64_t ticks_end
Definition decode.h:368
PktProfilingAppData app[]
Definition decode.h:375
PktProfilingLoggerData logger[LOGGER_SIZE]
Definition decode.h:373
PktProfilingDetectData detect[PROF_DETECT_SIZE]
Definition decode.h:372
SCProfilePacketData records6[257]
SCProfilePacketData records4[257]
@ PROF_DETECT_PF_SORT1
@ PROF_DETECT_PF_RECORD
@ PROF_DETECT_TX_UPDATE
@ PROF_DETECT_GETSGH
@ PROF_DETECT_NONMPMLIST
@ PROF_DETECT_CLEANUP
@ PROF_DETECT_SETUP
@ PROF_DETECT_RULES
@ PROF_DETECT_PF_PAYLOAD
@ PROF_DETECT_PF_SORT2
@ PROF_DETECT_PF_PKT
@ PROF_DETECT_IPONLY
@ PROF_DETECT_PF_TX
@ PROF_DETECT_ALERT
@ PROF_DETECT_SIZE
@ PROF_DETECT_TX
enum PacketProfileDetectId_ PacketProfileDetectId
@ LOGGER_JSON_FRAME
@ LOGGER_ALERT_DEBUG
@ LOGGER_HTTP
@ LOGGER_USER
@ LOGGER_TLS_STORE_CLIENT
@ LOGGER_TCP_DATA
@ LOGGER_JSON_METADATA
@ LOGGER_JSON_NETFLOW
@ LOGGER_PCAP
@ LOGGER_SIZE
@ LOGGER_JSON_ALERT
@ LOGGER_ALERT_FAST
@ LOGGER_JSON_DROP
@ LOGGER_ALERT_SYSLOG
@ LOGGER_FILEDATA
@ LOGGER_TLS
@ LOGGER_TLS_STORE
@ LOGGER_JSON_ARP
@ LOGGER_JSON_ANOMALY
@ LOGGER_FILE_STORE
@ LOGGER_JSON_FLOW
@ LOGGER_UNDEFINED
@ LOGGER_STATS
@ LOGGER_FILE
@ LOGGER_JSON_STATS
@ LOGGER_JSON_STREAM
@ LOGGER_JSON_TX
@ LOGGER_JSON_FILE
#define str(s)
size_t strlcpy(char *dst, const char *src, size_t siz)
#define SCMutexDestroy
#define SCSpinlock
#define SCSpinInit
#define SCSpinUnlock
#define SCMutex
#define SCMutexUnlock(mut)
#define SCSpinDestroy
#define SCSpinLock
#define SCMutexInit(mut, mutattrs)
#define SCMutexLock(mut)
const char * TmModuleTmmIdToString(TmmId id)
Maps the TmmId, to its string equivalent.
Definition tm-modules.c:170
TmModule tmm_modules[TMM_SIZE]
Definition tm-modules.c:29
#define TM_FLAG_RECEIVE_TM
Definition tm-modules.h:32
#define TM_FLAG_DECODE_TM
Definition tm-modules.h:33
@ TMM_FLOWWORKER
@ TMM_SIZE
#define SC_ATOMIC_ADD(name, val)
add a value to our atomic variable
#define SC_ATOMIC_CAS(name, cmpval, newval)
atomic Compare and Switch
#define SC_ATOMIC_INIT(name)
wrapper for initializing an atomic variable.
#define SC_ATOMIC_DECL_AND_INIT(type, name)
wrapper for declaring an atomic variable and initializing it.
#define SC_ATOMIC_DECLARE(type, name)
wrapper for declaring atomic variables.
#define SC_ATOMIC_GET(name)
Get the value from the atomic variable.
#define SC_ATOMIC_SET(name, val)
Set the value for the atomic variable.
const char * SCConfigGetLogDirectory(void)
Definition util-conf.c:38
uint64_t UtilCpuGetTicks(void)
Definition util-cpu.c:161
#define FatalError(...)
Definition util-debug.h:510
#define SCLogPerf(...)
Definition util-debug.h:234
#define SCLogWarning(...)
Macro used to log WARNING messages.
Definition util-debug.h:255
#define SCLogInfo(...)
Macro used to log INFORMATIONAL messages.
Definition util-debug.h:225
#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 SCStrdup(s)
Definition util-mem.h:56
#define unlikely(expr)
int PathIsAbsolute(const char *path)
Check if a path is absolute.
Definition util-path.c:44
void LockRecordFreeHash(void)
int LockRecordInitHash(void)
void SCProfilingDestroy(void)
Free resources used by profiling.
struct ProfileProtoRecords packet_profile_flowworker_data[PROFILE_FLOWWORKER_SIZE]
SCProfilePacketData packet_profile_data6[257]
int profiling_locks_output_to_file
void SCProfilingInit(void)
Initialize profiling.
void SCProfilingPrintPacketProfile(Packet *p)
const char * profiling_locks_file_mode
SCProfilePacketData packet_profile_data4[257]
SCProfilePacketData * packet_profile_app_data6
void SCProfilingDumpPacketStats(void)
void SCProfileRuleStartCollection(void)
void SCProfileRuleStopCollection(void)
void SCProfilingAddPacket(Packet *p)
const char * PacketProfileLoggerIdToString(LoggerId id)
Maps the LoggerId's to its string equivalent for profiling output.
SCProfilePacketData packet_profile_log_data4[LOGGER_SIZE][256]
PktProfiling * SCProfilePacketStart(void)
SCProfilePacketData packet_profile_app_pd_data6[257]
#define CASE_CODE(E)
void SCProfilingRegisterTests(void)
char * profiling_locks_file_name
#define TEST_RUNS
SCProfilePacketData packet_profile_tmm_data6[TMM_SIZE][257]
SCProfilePacketData packet_profile_detect_data4[PROF_DETECT_SIZE][257]
int profiling_locks_enabled
int profiling_packets_enabled
void SCProfilingDump(void)
int SCProfileRuleStart(Packet *p)
struct SCProfilePacketData_ SCProfilePacketData
SCProfilePacketData * packet_profile_app_data4
int profiling_output_to_file
SCProfilePacketData packet_profile_app_pd_data4[257]
SCProfilePacketData packet_profile_tmm_data4[TMM_SIZE][257]
SCProfilePacketData packet_profile_detect_data6[PROF_DETECT_SIZE][257]
SCProfilePacketData packet_profile_log_data6[LOGGER_SIZE][256]
const char * PacketProfileDetectIdToString(PacketProfileDetectId id)
Maps the PacketProfileDetectId, to its string equivalent.
thread_local int profiling_rules_entered