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