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