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"
37 #include "util-profiling-locks.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 
45 static pthread_mutex_t packet_profile_lock;
46 static FILE *packet_profile_csv_fp = NULL;
47 
48 extern int profiling_locks_enabled;
50 extern char *profiling_locks_file_name;
51 extern const char *profiling_locks_file_mode;
52 
53 typedef 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
68 SCProfilePacketData packet_profile_data4[257]; /**< all proto's + tunnel */
69 SCProfilePacketData packet_profile_data6[257]; /**< all proto's + tunnel */
70 
71 /* each module, each proto */
74 
77 
80 
83 
86 
90 };
91 
93 
96 
97 static int profiling_packets_csv_enabled = 0;
98 static int profiling_packets_output_to_file = 0;
99 static char *profiling_file_name;
100 static char profiling_packets_file_name[PATH_MAX];
101 static char *profiling_csv_file_name;
102 static const char *profiling_packets_file_mode = "a";
103 
104 static int rate = 1;
105 static SC_ATOMIC_DECLARE(uint64_t, samples);
106 
107 /**
108  * Used as a check so we don't double enter a profiling run.
109  */
110 thread_local int profiling_rules_entered = 0;
111 
112 void SCProfilingDumpPacketStats(void);
115 static void PrintCSVHeader(void);
116 
117 static 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  */
132 void
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
239  SCLogWarning(
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  */
275 void
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 
310 void
312 {
314  SCLogPerf("Done dumping profiling data.");
315 }
316 
317 static 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 
341 static 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 
372  if (profiling_packets_enabled == 0)
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++) {
508  SCProfilePacketData *pd = &packet_profile_app_data4[a * 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++) {
517  SCProfilePacketData *pd = &packet_profile_app_data4[a * 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++) {
536  SCProfilePacketData *pd = &packet_profile_app_data6[a * 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 
584  pd = &packet_profile_detect_data6[m][p];
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;
714  pd = &packet_profile_detect_data6[m][p];
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 
756 static 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 ",", PcapPacketCntGet(p), delta);
794 
795  for (int i = 0; i < TMM_SIZE; i++) {
796  const PktProfilingTmmData *pdt = &p->profile->tmm[i];
797  uint64_t tmm_delta = pdt->ticks_end - pdt->ticks_start;
798 
800  if (tmm_delta) {
801  receive = tmm_delta;
802  }
803  continue;
804 
805  } else if (tmm_modules[i].flags & TM_FLAG_DECODE_TM) {
806  if (tmm_delta) {
807  decode = tmm_delta;
808  }
809  continue;
810  }
811 
812  tmm_total += tmm_delta;
813  }
814  fprintf(packet_profile_csv_fp, "%"PRIu64",", receive);
815  fprintf(packet_profile_csv_fp, "%"PRIu64",", decode);
817  fprintf(packet_profile_csv_fp, "%"PRIu64",", fw_pdt->ticks_end - fw_pdt->ticks_start);
818  fprintf(packet_profile_csv_fp, "%"PRIu64",", delta - tmm_total);
819 
820  /* count ticks for app layer */
821  uint64_t app_total = 0;
822  for (AppProto i = 0; i < g_alproto_max; i++) {
823  const PktProfilingAppData *pdt = &p->profile->app[i];
824 
825  if (p->proto == IPPROTO_TCP) {
826  app_total += pdt->ticks_spent;
827  }
828  }
829 
830  fprintf(packet_profile_csv_fp, "%"PRIu64",", p->profile->proto_detect);
831 
832  /* print flowworker steps */
833  for (enum ProfileFlowWorkerId fwi = 0; fwi < PROFILE_FLOWWORKER_SIZE; fwi++) {
834  const PktProfilingData *pd = &p->profile->flowworker[fwi];
835  uint64_t ticks_spent = pd->ticks_end - pd->ticks_start;
836  if (fwi == PROFILE_FLOWWORKER_STREAM) {
837  ticks_spent -= app_total;
838  } else if (fwi == PROFILE_FLOWWORKER_APPLAYERUDP && app_total) {
839  ticks_spent = app_total;
840  }
841 
842  fprintf(packet_profile_csv_fp, "%"PRIu64",", ticks_spent);
843  }
844 
845  /* count loggers cost and print as a single cost */
846  uint64_t loggers = 0;
847  for (LoggerId i = 0; i < LOGGER_SIZE; i++) {
848  const PktProfilingLoggerData *pd = &p->profile->logger[i];
849  loggers += pd->ticks_spent;
850  }
851  fprintf(packet_profile_csv_fp, "%"PRIu64",", loggers);
852 
853  /* detect steps */
854  for (int i = 0; i < PROF_DETECT_SIZE; i++) {
855  const PktProfilingDetectData *pdt = &p->profile->detect[i];
856 
857  fprintf(packet_profile_csv_fp,"%"PRIu64",", pdt->ticks_spent);
858  }
859 
860  /* print individual loggers */
861  for (LoggerId i = 0; i < LOGGER_SIZE; i++) {
862  const PktProfilingLoggerData *pd = &p->profile->logger[i];
863  fprintf(packet_profile_csv_fp, "%"PRIu64",", pd->ticks_spent);
864  }
865 
866  fprintf(packet_profile_csv_fp,"\n");
867 }
868 
869 static void SCProfilingUpdatePacketDetectRecord(PacketProfileDetectId id, uint8_t ipproto, PktProfilingDetectData *pdt, int ipver)
870 {
871  if (pdt == NULL) {
872  return;
873  }
874 
876  if (ipver == 4)
877  pd = &packet_profile_detect_data4[id][ipproto];
878  else
879  pd = &packet_profile_detect_data6[id][ipproto];
880 
881  if (pd->min == 0 || pdt->ticks_spent < pd->min) {
882  pd->min = pdt->ticks_spent;
883  }
884  if (pd->max < pdt->ticks_spent) {
885  pd->max = pdt->ticks_spent;
886  }
887 
888  pd->tot += pdt->ticks_spent;
889  pd->cnt ++;
890 }
891 
892 static void SCProfilingUpdatePacketDetectRecords(Packet *p)
893 {
895  for (i = 0; i < PROF_DETECT_SIZE; i++) {
896  PktProfilingDetectData *pdt = &p->profile->detect[i];
897 
898  if (pdt->ticks_spent > 0) {
899  if (PacketIsIPv4(p)) {
900  SCProfilingUpdatePacketDetectRecord(i, p->proto, pdt, 4);
901  } else {
902  SCProfilingUpdatePacketDetectRecord(i, p->proto, pdt, 6);
903  }
904  }
905  }
906 }
907 
908 static void SCProfilingUpdatePacketAppPdRecord(uint8_t ipproto, uint32_t ticks_spent, int ipver)
909 {
911  if (ipver == 4)
912  pd = &packet_profile_app_pd_data4[ipproto];
913  else
914  pd = &packet_profile_app_pd_data6[ipproto];
915 
916  if (pd->min == 0 || ticks_spent < pd->min) {
917  pd->min = ticks_spent;
918  }
919  if (pd->max < ticks_spent) {
920  pd->max = ticks_spent;
921  }
922 
923  pd->tot += ticks_spent;
924  pd->cnt ++;
925 }
926 
927 static void SCProfilingUpdatePacketAppRecord(int alproto, uint8_t ipproto, PktProfilingAppData *pdt, int ipver)
928 {
929  if (pdt == NULL) {
930  return;
931  }
932 
934  if (ipver == 4)
935  pd = &packet_profile_app_data4[alproto * 257 + ipproto];
936  else
937  pd = &packet_profile_app_data6[alproto * 257 + ipproto];
938 
939  if (pd->min == 0 || pdt->ticks_spent < pd->min) {
940  pd->min = pdt->ticks_spent;
941  }
942  if (pd->max < pdt->ticks_spent) {
943  pd->max = pdt->ticks_spent;
944  }
945 
946  pd->tot += pdt->ticks_spent;
947  pd->cnt ++;
948 }
949 
950 static void SCProfilingUpdatePacketAppRecords(Packet *p)
951 {
952  int i;
953  for (i = 0; i < g_alproto_max; i++) {
954  PktProfilingAppData *pdt = &p->profile->app[i];
955 
956  if (pdt->ticks_spent > 0) {
957  if (PacketIsIPv4(p)) {
958  SCProfilingUpdatePacketAppRecord(i, p->proto, pdt, 4);
959  } else {
960  SCProfilingUpdatePacketAppRecord(i, p->proto, pdt, 6);
961  }
962  }
963  }
964 
965  if (p->profile->proto_detect > 0) {
966  if (PacketIsIPv4(p)) {
967  SCProfilingUpdatePacketAppPdRecord(p->proto, p->profile->proto_detect, 4);
968  } else {
969  SCProfilingUpdatePacketAppPdRecord(p->proto, p->profile->proto_detect, 6);
970  }
971  }
972 }
973 
974 static void SCProfilingUpdatePacketTmmRecord(int module, uint8_t proto, PktProfilingTmmData *pdt, int ipver)
975 {
976  if (pdt == NULL) {
977  return;
978  }
979 
981  if (ipver == 4)
982  pd = &packet_profile_tmm_data4[module][proto];
983  else
984  pd = &packet_profile_tmm_data6[module][proto];
985 
986  uint32_t delta = (uint32_t)pdt->ticks_end - pdt->ticks_start;
987  if (pd->min == 0 || delta < pd->min) {
988  pd->min = delta;
989  }
990  if (pd->max < delta) {
991  pd->max = delta;
992  }
993 
994  pd->tot += (uint64_t)delta;
995  pd->cnt ++;
996 
997 #ifdef PROFILE_LOCKING
998  pd->lock += pdt->mutex_lock_cnt;
999  pd->ticks += pdt->mutex_lock_wait_ticks;
1000  pd->contention += pdt->mutex_lock_contention;
1001  pd->slock += pdt->spin_lock_cnt;
1002  pd->sticks += pdt->spin_lock_wait_ticks;
1003  pd->scontention += pdt->spin_lock_contention;
1004 #endif
1005 }
1006 
1007 static void SCProfilingUpdatePacketTmmRecords(Packet *p)
1008 {
1009  int i;
1010  for (i = 0; i < TMM_SIZE; i++) {
1011  PktProfilingTmmData *pdt = &p->profile->tmm[i];
1012 
1013  if (pdt->ticks_start == 0 || pdt->ticks_end == 0 || pdt->ticks_start > pdt->ticks_end) {
1014  continue;
1015  }
1016 
1017  if (PacketIsIPv4(p)) {
1018  SCProfilingUpdatePacketTmmRecord(i, p->proto, pdt, 4);
1019  } else {
1020  SCProfilingUpdatePacketTmmRecord(i, p->proto, pdt, 6);
1021  }
1022  }
1023 }
1024 
1025 static inline void SCProfilingUpdatePacketGenericRecord(PktProfilingData *pdt,
1026  SCProfilePacketData *pd)
1027 {
1028  if (pdt == NULL || pd == NULL) {
1029  return;
1030  }
1031 
1032  uint64_t delta = pdt->ticks_end - pdt->ticks_start;
1033  if (pd->min == 0 || delta < pd->min) {
1034  pd->min = delta;
1035  }
1036  if (pd->max < delta) {
1037  pd->max = delta;
1038  }
1039 
1040  pd->tot += delta;
1041  pd->cnt ++;
1042 }
1043 
1044 static void SCProfilingUpdatePacketGenericRecords(Packet *p, PktProfilingData *pd,
1045  struct ProfileProtoRecords *records, int size)
1046 {
1047  int i;
1048  for (i = 0; i < size; i++) {
1049  PktProfilingData *pdt = &pd[i];
1050 
1051  if (pdt->ticks_start == 0 || pdt->ticks_end == 0 || pdt->ticks_start > pdt->ticks_end) {
1052  continue;
1053  }
1054 
1055  struct ProfileProtoRecords *r = &records[i];
1056  SCProfilePacketData *store = NULL;
1057 
1058  if (PacketIsIPv4(p)) {
1059  store = &(r->records4[p->proto]);
1060  } else {
1061  store = &(r->records6[p->proto]);
1062  }
1063 
1064  SCProfilingUpdatePacketGenericRecord(pdt, store);
1065  }
1066 }
1067 
1068 static void SCProfilingUpdatePacketLogRecord(LoggerId id,
1069  uint8_t ipproto, PktProfilingLoggerData *pdt, int ipver)
1070 {
1071  if (pdt == NULL) {
1072  return;
1073  }
1074 
1075  SCProfilePacketData *pd;
1076  if (ipver == 4)
1077  pd = &packet_profile_log_data4[id][ipproto];
1078  else
1079  pd = &packet_profile_log_data6[id][ipproto];
1080 
1081  if (pd->min == 0 || pdt->ticks_spent < pd->min) {
1082  pd->min = pdt->ticks_spent;
1083  }
1084  if (pd->max < pdt->ticks_spent) {
1085  pd->max = pdt->ticks_spent;
1086  }
1087 
1088  pd->tot += pdt->ticks_spent;
1089  pd->cnt++;
1090 }
1091 
1092 static void SCProfilingUpdatePacketLogRecords(Packet *p)
1093 {
1094  for (LoggerId i = 0; i < LOGGER_SIZE; i++) {
1095  PktProfilingLoggerData *pdt = &p->profile->logger[i];
1096 
1097  if (pdt->ticks_spent > 0) {
1098  if (PacketIsIPv4(p)) {
1099  SCProfilingUpdatePacketLogRecord(i, p->proto, pdt, 4);
1100  } else {
1101  SCProfilingUpdatePacketLogRecord(i, p->proto, pdt, 6);
1102  }
1103  }
1104  }
1105 }
1106 
1108 {
1109  if (p == NULL || p->profile == NULL ||
1110  p->profile->ticks_start == 0 || p->profile->ticks_end == 0 ||
1112  return;
1113 
1114  pthread_mutex_lock(&packet_profile_lock);
1115  {
1116 
1117  if (PacketIsIPv4(p)) {
1119 
1120  uint64_t delta = p->profile->ticks_end - p->profile->ticks_start;
1121  if (pd->min == 0 || delta < pd->min) {
1122  pd->min = delta;
1123  }
1124  if (pd->max < delta) {
1125  pd->max = delta;
1126  }
1127 
1128  pd->tot += delta;
1129  pd->cnt ++;
1130 
1131  if (PacketIsTunnel(p)) {
1132  pd = &packet_profile_data4[256];
1133 
1134  if (pd->min == 0 || delta < pd->min) {
1135  pd->min = delta;
1136  }
1137  if (pd->max < delta) {
1138  pd->max = delta;
1139  }
1140 
1141  pd->tot += delta;
1142  pd->cnt ++;
1143  }
1144 
1145  SCProfilingUpdatePacketGenericRecords(p, p->profile->flowworker,
1147 
1148  SCProfilingUpdatePacketTmmRecords(p);
1149  SCProfilingUpdatePacketAppRecords(p);
1150  SCProfilingUpdatePacketDetectRecords(p);
1151  SCProfilingUpdatePacketLogRecords(p);
1152 
1153  } else if (PacketIsIPv6(p)) {
1155 
1156  uint64_t delta = p->profile->ticks_end - p->profile->ticks_start;
1157  if (pd->min == 0 || delta < pd->min) {
1158  pd->min = delta;
1159  }
1160  if (pd->max < delta) {
1161  pd->max = delta;
1162  }
1163 
1164  pd->tot += delta;
1165  pd->cnt ++;
1166 
1167  if (PacketIsTunnel(p)) {
1168  pd = &packet_profile_data6[256];
1169 
1170  if (pd->min == 0 || delta < pd->min) {
1171  pd->min = delta;
1172  }
1173  if (pd->max < delta) {
1174  pd->max = delta;
1175  }
1176 
1177  pd->tot += delta;
1178  pd->cnt ++;
1179  }
1180 
1181  SCProfilingUpdatePacketGenericRecords(p, p->profile->flowworker,
1183 
1184  SCProfilingUpdatePacketTmmRecords(p);
1185  SCProfilingUpdatePacketAppRecords(p);
1186  SCProfilingUpdatePacketDetectRecords(p);
1187  SCProfilingUpdatePacketLogRecords(p);
1188  }
1189 
1190  if (profiling_packets_csv_enabled)
1192 
1193  }
1194  pthread_mutex_unlock(&packet_profile_lock);
1195 }
1196 
1198 {
1199  uint64_t sample = SC_ATOMIC_ADD(samples, 1);
1200  if (sample % rate == 0)
1201  return SCCalloc(1, sizeof(PktProfiling) + g_alproto_max * sizeof(PktProfilingAppData));
1202  return NULL;
1203 }
1204 
1205 /* see if we want to profile rules for this packet */
1207 {
1208 #ifdef PROFILE_LOCKING
1209  if (p->profile != NULL) {
1210  p->flags |= PKT_PROFILE;
1211  return 1;
1212  }
1213 #endif
1214  if (p->flags & PKT_PROFILE) {
1215  return 1;
1216  }
1217 
1218  uint64_t sample = SC_ATOMIC_ADD(samples, 1);
1219  if ((sample % rate) == 0) {
1220  p->flags |= PKT_PROFILE;
1221  return 1;
1222  }
1223  return 0;
1224 }
1225 
1226 #define CASE_CODE(E) case E: return #E
1228 /**
1229  * \brief Maps the PacketProfileDetectId, to its string equivalent
1230  *
1231  * \param id PacketProfileDetectId id
1232  *
1233  * \retval string equivalent for the PacketProfileDetectId id
1234  */
1236 {
1237  switch (id) {
1253  default:
1254  return "UNKNOWN";
1255  }
1256 }
1257 
1258 /**
1259  * \brief Maps the LoggerId's to its string equivalent for profiling output.
1260  *
1261  * \param id LoggerId id
1262  *
1263  * \retval string equivalent for the LoggerId id
1264  */
1266 {
1267  switch (id) {
1295 
1296  case LOGGER_SIZE:
1297  return "UNKNOWN";
1298  }
1299  return "UNKNOWN";
1300 }
1301 
1302 #ifdef UNITTESTS
1303 
1304 static int
1305 ProfilingGenericTicksTest01(void)
1306 {
1307 #define TEST_RUNS 1024
1308  uint64_t ticks_start = 0;
1309  uint64_t ticks_end = 0;
1310  void *ptr[TEST_RUNS];
1311  unsigned int i;
1312 
1313  ticks_start = UtilCpuGetTicks();
1314  for (i = 0; i < TEST_RUNS; i++) {
1315  ptr[i] = SCMalloc(1024);
1316  }
1317  ticks_end = UtilCpuGetTicks();
1318  printf("malloc(1024) %"PRIu64"\n", (ticks_end - ticks_start)/TEST_RUNS);
1319 
1320  ticks_start = UtilCpuGetTicks();
1321  for (i = 0; i < TEST_RUNS; i++) {
1322  SCFree(ptr[i]);
1323  }
1324  ticks_end = UtilCpuGetTicks();
1325  printf("SCFree(1024) %"PRIu64"\n", (ticks_end - ticks_start)/TEST_RUNS);
1326 
1327  SCMutex m[TEST_RUNS];
1328 
1329  ticks_start = UtilCpuGetTicks();
1330  for (i = 0; i < TEST_RUNS; i++) {
1331  SCMutexInit(&m[i], NULL);
1332  }
1333  ticks_end = UtilCpuGetTicks();
1334  printf("SCMutexInit() %"PRIu64"\n", (ticks_end - ticks_start)/TEST_RUNS);
1335 
1336  ticks_start = UtilCpuGetTicks();
1337  for (i = 0; i < TEST_RUNS; i++) {
1338  SCMutexLock(&m[i]);
1339  }
1340  ticks_end = UtilCpuGetTicks();
1341  printf("SCMutexLock() %"PRIu64"\n", (ticks_end - ticks_start)/TEST_RUNS);
1342 
1343  ticks_start = UtilCpuGetTicks();
1344  for (i = 0; i < TEST_RUNS; i++) {
1345  SCMutexUnlock(&m[i]);
1346  }
1347  ticks_end = UtilCpuGetTicks();
1348  printf("SCMutexUnlock() %"PRIu64"\n", (ticks_end - ticks_start)/TEST_RUNS);
1349 
1350  ticks_start = UtilCpuGetTicks();
1351  for (i = 0; i < TEST_RUNS; i++) {
1352  SCMutexDestroy(&m[i]);
1353  }
1354  ticks_end = UtilCpuGetTicks();
1355  printf("SCMutexDestroy() %"PRIu64"\n", (ticks_end - ticks_start)/TEST_RUNS);
1356 
1357  SCSpinlock s[TEST_RUNS];
1358 
1359  ticks_start = UtilCpuGetTicks();
1360  for (i = 0; i < TEST_RUNS; i++) {
1361  SCSpinInit(&s[i], 0);
1362  }
1363  ticks_end = UtilCpuGetTicks();
1364  printf("SCSpinInit() %"PRIu64"\n", (ticks_end - ticks_start)/TEST_RUNS);
1365 
1366  ticks_start = UtilCpuGetTicks();
1367  for (i = 0; i < TEST_RUNS; i++) {
1368  SCSpinLock(&s[i]);
1369  }
1370  ticks_end = UtilCpuGetTicks();
1371  printf("SCSpinLock() %"PRIu64"\n", (ticks_end - ticks_start)/TEST_RUNS);
1372 
1373  ticks_start = UtilCpuGetTicks();
1374  for (i = 0; i < TEST_RUNS; i++) {
1375  SCSpinUnlock(&s[i]);
1376  }
1377  ticks_end = UtilCpuGetTicks();
1378  printf("SCSpinUnlock() %"PRIu64"\n", (ticks_end - ticks_start)/TEST_RUNS);
1379 
1380  ticks_start = UtilCpuGetTicks();
1381  for (i = 0; i < TEST_RUNS; i++) {
1382  SCSpinDestroy(&s[i]);
1383  }
1384  ticks_end = UtilCpuGetTicks();
1385  printf("SCSpinDestroy() %"PRIu64"\n", (ticks_end - ticks_start)/TEST_RUNS);
1386 
1387  SC_ATOMIC_DECL_AND_INIT(unsigned int, test);
1388  ticks_start = UtilCpuGetTicks();
1389  for (i = 0; i < TEST_RUNS; i++) {
1390  (void) SC_ATOMIC_ADD(test,1);
1391  }
1392  ticks_end = UtilCpuGetTicks();
1393  printf("SC_ATOMIC_ADD %"PRIu64"\n", (ticks_end - ticks_start)/TEST_RUNS);
1394 
1395  ticks_start = UtilCpuGetTicks();
1396  for (i = 0; i < TEST_RUNS; i++) {
1397  SC_ATOMIC_CAS(&test,i,i+1);
1398  }
1399  ticks_end = UtilCpuGetTicks();
1400  printf("SC_ATOMIC_CAS %"PRIu64"\n", (ticks_end - ticks_start)/TEST_RUNS);
1401  return 1;
1402 }
1403 
1404 #endif /* UNITTESTS */
1405 
1406 void
1408 {
1409 #ifdef UNITTESTS
1410  UtRegisterTest("ProfilingGenericTicksTest01", ProfilingGenericTicksTest01);
1411 #endif /* UNITTESTS */
1412 }
1413 
1415 {
1416 }
1417 
1419 {
1420 }
1421 
1422 #elif PROFILE_RULES
1423 
1424 thread_local int profiling_rules_entered = 0;
1425 int profiling_output_to_file = 0;
1426 static SC_ATOMIC_DECLARE(uint64_t, samples);
1427 static uint64_t rate = 0;
1428 static SC_ATOMIC_DECLARE(bool, profiling_rules_active);
1429 
1430 /**
1431  * \brief Initialize profiling.
1432  */
1433 void SCProfilingInit(void)
1434 {
1435  SC_ATOMIC_INIT(profiling_rules_active);
1436  SC_ATOMIC_INIT(samples);
1437  intmax_t rate_v = 0;
1438  SCConfNode *conf;
1439 
1440  (void)SCConfGetInt("profiling.sample-rate", &rate_v);
1441  if (rate_v > 0 && rate_v < INT_MAX) {
1442  int literal_rate = (int)rate_v;
1443  for (int i = literal_rate; i >= 1; i--) {
1444  /* If i is a power of 2 */
1445  if ((i & (i - 1)) == 0) {
1446  rate = i - 1;
1447  break;
1448  }
1449  }
1450  if (rate != 0)
1451  SCLogInfo("profiling runs for every %luth packet", rate + 1);
1452  else
1453  SCLogInfo("profiling runs for every packet");
1454  }
1455 
1456  conf = SCConfGetNode("profiling.rules");
1457  if (SCConfNodeChildValueIsTrue(conf, "active")) {
1458  SC_ATOMIC_SET(profiling_rules_active, 1);
1459  }
1460 }
1461 
1462 /* see if we want to profile rules for this packet */
1463 int SCProfileRuleStart(Packet *p)
1464 {
1465  /* Move first so we'll always finish even if dynamically disabled */
1466  if (p->flags & PKT_PROFILE)
1467  return 1;
1468 
1469  if (!SC_ATOMIC_GET(profiling_rules_active)) {
1470  return 0;
1471  }
1472 
1473  uint64_t sample = SC_ATOMIC_ADD(samples, 1);
1474  if ((sample & rate) == 0) {
1475  p->flags |= PKT_PROFILE;
1476  return 1;
1477  }
1478  return 0;
1479 }
1480 
1482 {
1483  SC_ATOMIC_SET(profiling_rules_active, true);
1484 }
1485 
1486 void SCProfileRuleStopCollection(void)
1487 {
1488  SC_ATOMIC_SET(profiling_rules_active, false);
1489 }
1490 
1491 #endif /* PROFILING */
SCProfilePacketData
struct SCProfilePacketData_ SCProfilePacketData
util-byte.h
tm-threads.h
Packet_::proto
uint8_t proto
Definition: decode.h:523
PROF_DETECT_GETSGH
@ PROF_DETECT_GETSGH
Definition: suricata-common.h:458
SCConfValIsTrue
int SCConfValIsTrue(const char *val)
Check if a value is true.
Definition: conf.c:552
SCSpinDestroy
#define SCSpinDestroy
Definition: threads-debug.h:240
PktProfilingData_::ticks_end
uint64_t ticks_end
Definition: decode.h:346
LockRecordInitHash
int LockRecordInitHash(void)
profiling_locks_file_mode
const char * profiling_locks_file_mode
SC_ATOMIC_INIT
#define SC_ATOMIC_INIT(name)
wrapper for initializing an atomic variable.
Definition: util-atomic.h:314
PktProfiling_
Per pkt stats storage.
Definition: decode.h:366
TmModuleTmmIdToString
const char * TmModuleTmmIdToString(TmmId id)
Maps the TmmId, to its string equivalent.
Definition: tm-modules.c:170
unlikely
#define unlikely(expr)
Definition: util-optimize.h:35
LOGGER_USER
@ LOGGER_USER
Definition: suricata-common.h:515
SC_ATOMIC_SET
#define SC_ATOMIC_SET(name, val)
Set the value for the atomic variable.
Definition: util-atomic.h:386
PktProfilingTmmData_
Per TMM stats storage.
Definition: decode.h:325
SCProfilePacketData_::max
uint64_t max
Definition: util-profiling.c:55
PROF_DETECT_PF_PAYLOAD
@ PROF_DETECT_PF_PAYLOAD
Definition: suricata-common.h:463
ProfileFlowWorkerIdToString
const char * ProfileFlowWorkerIdToString(enum ProfileFlowWorkerId fwi)
Definition: flow-worker.c:774
UtRegisterTest
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
Definition: util-unittest.c:103
LOGGER_ALERT_SYSLOG
@ LOGGER_ALERT_SYSLOG
Definition: suricata-common.h:496
packet_profile_flowworker_data
struct ProfileProtoRecords packet_profile_flowworker_data[PROFILE_FLOWWORKER_SIZE]
Definition: util-profiling.c:92
LOGGER_FILEDATA
@ LOGGER_FILEDATA
Definition: suricata-common.h:487
LOGGER_JSON_STATS
@ LOGGER_JSON_STATS
Definition: suricata-common.h:506
PcapPacketCntGet
uint64_t PcapPacketCntGet(const Packet *p)
Definition: decode.c:1104
SCProfileRuleStopCollection
void SCProfileRuleStopCollection(void)
Definition: util-profiling.c:1418
packet_profile_app_data6
SCProfilePacketData * packet_profile_app_data6
Definition: util-profiling.c:76
PktProfiling_::ticks_end
uint64_t ticks_end
Definition: decode.h:368
AppProto
uint16_t AppProto
Definition: app-layer-protos.h:86
Packet_::flags
uint32_t flags
Definition: decode.h:544
LOGGER_JSON_ALERT
@ LOGGER_JSON_ALERT
Definition: suricata-common.h:497
ProfileProtoRecords
Definition: util-profiling.c:87
LOGGER_JSON_ARP
@ LOGGER_JSON_ARP
Definition: suricata-common.h:511
PROF_DETECT_ALERT
@ PROF_DETECT_ALERT
Definition: suricata-common.h:469
LoggerId
LoggerId
Definition: suricata-common.h:477
AppProtoToString
const char * AppProtoToString(AppProto alproto)
Maps the ALPROTO_*, to its string equivalent.
Definition: app-layer-protos.c:41
SC_ATOMIC_ADD
#define SC_ATOMIC_ADD(name, val)
add a value to our atomic variable
Definition: util-atomic.h:332
PROF_DETECT_SIZE
@ PROF_DETECT_SIZE
Definition: suricata-common.h:473
packet_profile_data6
SCProfilePacketData packet_profile_data6[257]
Definition: util-profiling.c:69
PktProfilingTmmData_::ticks_end
uint64_t ticks_end
Definition: decode.h:327
PktProfiling_::app
PktProfilingAppData app[]
Definition: decode.h:375
SCConfNodeChildValueIsTrue
int SCConfNodeChildValueIsTrue(const SCConfNode *node, const char *key)
Test if a configuration node has a true value.
Definition: conf.c:899
PROF_DETECT_PF_TX
@ PROF_DETECT_PF_TX
Definition: suricata-common.h:464
SC_ATOMIC_CAS
#define SC_ATOMIC_CAS(name, cmpval, newval)
atomic Compare and Switch
Definition: util-atomic.h:367
PROF_DETECT_CLEANUP
@ PROF_DETECT_CLEANUP
Definition: suricata-common.h:471
SCMutexLock
#define SCMutexLock(mut)
Definition: threads-debug.h:117
SCSpinLock
#define SCSpinLock
Definition: threads-debug.h:236
packet_profile_log_data6
SCProfilePacketData packet_profile_log_data6[LOGGER_SIZE][256]
Definition: util-profiling.c:85
SCProfileRuleStart
int SCProfileRuleStart(Packet *p)
Definition: util-profiling.c:1206
SCProfilingAddPacket
void SCProfilingAddPacket(Packet *p)
Definition: util-profiling.c:1107
packet_profile_app_pd_data4
SCProfilePacketData packet_profile_app_pd_data4[257]
Definition: util-profiling.c:78
proto
uint8_t proto
Definition: decode-template.h:0
m
SCMutex m
Definition: flow-hash.h:6
LOGGER_STATS
@ LOGGER_STATS
Definition: suricata-common.h:505
SCConfNodeLookupChildValue
const char * SCConfNodeLookupChildValue(const SCConfNode *node, const char *name)
Lookup the value of a child configuration node by name.
Definition: conf.c:855
PROFILE_FLOWWORKER_STREAM
@ PROFILE_FLOWWORKER_STREAM
Definition: flow-worker.h:23
SCProfilingDestroy
void SCProfilingDestroy(void)
Free resources used by profiling.
Definition: util-profiling.c:276
PktProfiling_::ticks_start
uint64_t ticks_start
Definition: decode.h:367
profiling_locks_output_to_file
int profiling_locks_output_to_file
util-unittest.h
TEST_RUNS
#define TEST_RUNS
PROF_DETECT_PF_SORT2
@ PROF_DETECT_PF_SORT2
Definition: suricata-common.h:467
PktProfilingAppData_::ticks_spent
uint64_t ticks_spent
Definition: decode.h:356
UtilCpuGetTicks
uint64_t UtilCpuGetTicks(void)
Definition: util-cpu.c:161
PacketProfileLoggerIdToString
const char * PacketProfileLoggerIdToString(LoggerId id)
Maps the LoggerId's to its string equivalent for profiling output.
Definition: util-profiling.c:1265
strlcpy
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: util-strlcpyu.c:43
PROF_DETECT_PF_SORT1
@ PROF_DETECT_PF_SORT1
Definition: suricata-common.h:466
PROF_DETECT_TX_UPDATE
@ PROF_DETECT_TX_UPDATE
Definition: suricata-common.h:470
Packet_::profile
PktProfiling * profile
Definition: decode.h:669
LOGGER_JSON_FLOW
@ LOGGER_JSON_FLOW
Definition: suricata-common.h:503
LOGGER_HTTP
@ LOGGER_HTTP
Definition: suricata-common.h:481
lock
HRLOCK_TYPE lock
Definition: host.h:0
SCProfilingPrintPacketProfile
void SCProfilingPrintPacketProfile(Packet *p)
Definition: util-profiling.c:780
ProfileProtoRecords::records4
SCProfilePacketData records4[257]
Definition: util-profiling.c:88
packet_profile_tmm_data6
SCProfilePacketData packet_profile_tmm_data6[TMM_SIZE][257]
Definition: util-profiling.c:73
packet_profile_detect_data4
SCProfilePacketData packet_profile_detect_data4[PROF_DETECT_SIZE][257]
Definition: util-profiling.c:81
g_alproto_max
AppProto g_alproto_max
Definition: app-layer-protos.c:30
LOGGER_TCP_DATA
@ LOGGER_TCP_DATA
Definition: suricata-common.h:502
packet_profile_tmm_data4
SCProfilePacketData packet_profile_tmm_data4[TMM_SIZE][257]
Definition: util-profiling.c:72
ProfileProtoRecords::records6
SCProfilePacketData records6[257]
Definition: util-profiling.c:89
SCProfileRuleStartCollection
void SCProfileRuleStartCollection(void)
Definition: util-profiling.c:1414
LOGGER_JSON_FILE
@ LOGGER_JSON_FILE
Definition: suricata-common.h:501
PacketProfileDetectId
enum PacketProfileDetectId_ PacketProfileDetectId
SCMutexUnlock
#define SCMutexUnlock(mut)
Definition: threads-debug.h:120
ProfileFlowWorkerId
ProfileFlowWorkerId
Definition: flow-worker.h:21
PROF_DETECT_PF_PKT
@ PROF_DETECT_PF_PKT
Definition: suricata-common.h:462
SCConfGetInt
int SCConfGetInt(const char *name, intmax_t *val)
Retrieve a configuration value as an integer.
Definition: conf.c:415
LOGGER_UNDEFINED
@ LOGGER_UNDEFINED
Definition: suricata-common.h:478
PktProfilingData_
Definition: decode.h:344
packet_profile_log_data4
SCProfilePacketData packet_profile_log_data4[LOGGER_SIZE][256]
Definition: util-profiling.c:84
PktProfiling_::logger
PktProfilingLoggerData logger[LOGGER_SIZE]
Definition: decode.h:373
SCSpinUnlock
#define SCSpinUnlock
Definition: threads-debug.h:238
PROFILE_FLOWWORKER_APPLAYERUDP
@ PROFILE_FLOWWORKER_APPLAYERUDP
Definition: flow-worker.h:24
PktProfilingDetectData_
Definition: decode.h:349
SCLogWarning
#define SCLogWarning(...)
Macro used to log WARNING messages.
Definition: util-debug.h:262
LOGGER_TLS
@ LOGGER_TLS
Definition: suricata-common.h:484
util-profiling.h
LOGGER_SIZE
@ LOGGER_SIZE
Definition: suricata-common.h:518
SC_ATOMIC_DECLARE
#define SC_ATOMIC_DECLARE(type, name)
wrapper for declaring atomic variables.
Definition: util-atomic.h:280
SCProfilePacketData_
Definition: util-profiling.c:53
profiling_packets_enabled
int profiling_packets_enabled
Definition: util-profiling.c:94
packet_profile_app_pd_data6
SCProfilePacketData packet_profile_app_pd_data6[257]
Definition: util-profiling.c:79
Packet_
Definition: decode.h:501
LOGGER_JSON_NETFLOW
@ LOGGER_JSON_NETFLOW
Definition: suricata-common.h:504
TM_FLAG_DECODE_TM
#define TM_FLAG_DECODE_TM
Definition: tm-modules.h:33
tmm_modules
TmModule tmm_modules[TMM_SIZE]
Definition: tm-modules.c:29
SCConfigGetLogDirectory
const char * SCConfigGetLogDirectory(void)
Definition: util-conf.c:38
conf.h
TMM_SIZE
@ TMM_SIZE
Definition: tm-threads-common.h:76
PROF_DETECT_IPONLY
@ PROF_DETECT_IPONLY
Definition: suricata-common.h:459
SCLogInfo
#define SCLogInfo(...)
Macro used to log INFORMATIONAL messages.
Definition: util-debug.h:232
PacketProfileDetectIdToString
const char * PacketProfileDetectIdToString(PacketProfileDetectId id)
Maps the PacketProfileDetectId, to its string equivalent.
Definition: util-profiling.c:1235
SCMutexInit
#define SCMutexInit(mut, mutattrs)
Definition: threads-debug.h:116
TM_FLAG_RECEIVE_TM
#define TM_FLAG_RECEIVE_TM
Definition: tm-modules.h:32
PktProfilingData_::ticks_start
uint64_t ticks_start
Definition: decode.h:345
SCProfilePacketData_::tot
uint64_t tot
Definition: util-profiling.c:56
TMM_FLOWWORKER
@ TMM_FLOWWORKER
Definition: tm-threads-common.h:34
PktProfiling_::detect
PktProfilingDetectData detect[PROF_DETECT_SIZE]
Definition: decode.h:372
util-conf.h
LOGGER_PCAP
@ LOGGER_PCAP
Definition: suricata-common.h:507
LOGGER_JSON_METADATA
@ LOGGER_JSON_METADATA
Definition: suricata-common.h:508
flags
uint8_t flags
Definition: decode-gre.h:0
suricata-common.h
util-path.h
SC_ATOMIC_DECL_AND_INIT
#define SC_ATOMIC_DECL_AND_INIT(type, name)
wrapper for declaring an atomic variable and initializing it.
Definition: util-atomic.h:308
PROF_DETECT_PF_RECORD
@ PROF_DETECT_PF_RECORD
Definition: suricata-common.h:465
PROFILE_FLOWWORKER_SIZE
@ PROFILE_FLOWWORKER_SIZE
Definition: flow-worker.h:29
LOGGER_JSON_DROP
@ LOGGER_JSON_DROP
Definition: suricata-common.h:499
SCLogPerf
#define SCLogPerf(...)
Definition: util-debug.h:241
PROF_DETECT_SETUP
@ PROF_DETECT_SETUP
Definition: suricata-common.h:457
PathIsAbsolute
int PathIsAbsolute(const char *path)
Check if a path is absolute.
Definition: util-path.c:44
LOGGER_ALERT_DEBUG
@ LOGGER_ALERT_DEBUG
Definition: suricata-common.h:494
SCStrdup
#define SCStrdup(s)
Definition: util-mem.h:56
FatalError
#define FatalError(...)
Definition: util-debug.h:517
SCProfilingDump
void SCProfilingDump(void)
Definition: util-profiling.c:311
packet_profile_detect_data6
SCProfilePacketData packet_profile_detect_data6[PROF_DETECT_SIZE][257]
Definition: util-profiling.c:82
SCSpinInit
#define SCSpinInit
Definition: threads-debug.h:239
LOGGER_FILE
@ LOGGER_FILE
Definition: suricata-common.h:486
SCMalloc
#define SCMalloc(sz)
Definition: util-mem.h:47
PROF_DETECT_RULES
@ PROF_DETECT_RULES
Definition: suricata-common.h:460
LOGGER_JSON_TX
@ LOGGER_JSON_TX
Definition: suricata-common.h:485
PROF_DETECT_NONMPMLIST
@ PROF_DETECT_NONMPMLIST
Definition: suricata-common.h:468
str
#define str(s)
Definition: suricata-common.h:308
SCConfGetNode
SCConfNode * SCConfGetNode(const char *name)
Get a SCConfNode by name.
Definition: conf.c:182
SCLogError
#define SCLogError(...)
Macro used to log ERROR messages.
Definition: util-debug.h:274
SCFree
#define SCFree(p)
Definition: util-mem.h:61
packet_profile_data4
SCProfilePacketData packet_profile_data4[257]
Definition: util-profiling.c:68
profiling_locks_file_name
char * profiling_locks_file_name
PktProfilingLoggerData_
Definition: decode.h:359
PktProfiling_::tmm
PktProfilingTmmData tmm[TMM_SIZE]
Definition: decode.h:370
PKT_PROFILE
#define PKT_PROFILE
Definition: decode.h:1293
LockRecordFreeHash
void LockRecordFreeHash(void)
SCSpinlock
#define SCSpinlock
Definition: threads-debug.h:235
LOGGER_FILE_STORE
@ LOGGER_FILE_STORE
Definition: suricata-common.h:500
LOGGER_TLS_STORE_CLIENT
@ LOGGER_TLS_STORE_CLIENT
Definition: suricata-common.h:483
SCProfilePacketData_::min
uint64_t min
Definition: util-profiling.c:54
LOGGER_JSON_FRAME
@ LOGGER_JSON_FRAME
Definition: suricata-common.h:509
profiling_output_to_file
int profiling_output_to_file
Definition: util-profiling.c:95
SCProfilingDumpPacketStats
void SCProfilingDumpPacketStats(void)
Definition: util-profiling.c:366
PROF_DETECT_TX
@ PROF_DETECT_TX
Definition: suricata-common.h:461
PktProfilingTmmData_::ticks_start
uint64_t ticks_start
Definition: decode.h:326
LOGGER_TLS_STORE
@ LOGGER_TLS_STORE
Definition: suricata-common.h:482
PktProfilingLoggerData_::ticks_spent
uint64_t ticks_spent
Definition: decode.h:362
SCProfilingRegisterTests
void SCProfilingRegisterTests(void)
Definition: util-profiling.c:1407
SCProfilePacketData_::cnt
uint64_t cnt
Definition: util-profiling.c:57
SC_ATOMIC_GET
#define SC_ATOMIC_GET(name)
Get the value from the atomic variable.
Definition: util-atomic.h:375
CASE_CODE
#define CASE_CODE(E)
Definition: util-profiling.c:1226
PktProfiling_::flowworker
PktProfilingData flowworker[PROFILE_FLOWWORKER_SIZE]
Definition: decode.h:371
util-profiling-locks.h
PktProfilingAppData_
Definition: decode.h:355
SCCalloc
#define SCCalloc(nm, sz)
Definition: util-mem.h:53
LOGGER_JSON_STREAM
@ LOGGER_JSON_STREAM
Definition: suricata-common.h:510
SCMutexDestroy
#define SCMutexDestroy
Definition: threads-debug.h:121
SCConfNode_
Definition: conf.h:37
PktProfiling_::proto_detect
uint64_t proto_detect
Definition: decode.h:374
profiling_rules_entered
thread_local int profiling_rules_entered
Definition: util-profiling.c:110
LOGGER_ALERT_FAST
@ LOGGER_ALERT_FAST
Definition: suricata-common.h:495
SCMutex
#define SCMutex
Definition: threads-debug.h:114
SCProfilingInit
void SCProfilingInit(void)
Initialize profiling.
Definition: util-profiling.c:133
SCProfilePacketStart
PktProfiling * SCProfilePacketStart(void)
Definition: util-profiling.c:1197
packet_profile_app_data4
SCProfilePacketData * packet_profile_app_data4
Definition: util-profiling.c:75
PktProfilingDetectData_::ticks_spent
uint64_t ticks_spent
Definition: decode.h:352
profiling_locks_enabled
int profiling_locks_enabled
LOGGER_JSON_ANOMALY
@ LOGGER_JSON_ANOMALY
Definition: suricata-common.h:498