suricata
util-profiling-keywords.c
Go to the documentation of this file.
1 /* Copyright (C) 2007-2013 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 rule profiling operations.
25  */
26 
27 #include "suricata-common.h"
28 #include "util-profiling.h"
29 #include "util-profiling-locks.h"
30 
31 #ifdef PROFILING
32 #include "detect-engine.h"
33 #include "tm-threads.h"
34 #include "util-conf.h"
35 #include "util-path.h"
36 
37 /**
38  * Extra data for rule profiling.
39  */
40 typedef struct SCProfileKeywordData_ {
41  uint64_t checks;
42  uint64_t matches;
43  uint64_t max;
44  uint64_t ticks_match;
45  uint64_t ticks_no_match;
47 
49  uint32_t id;
51  pthread_mutex_t data_m;
53 
54 static int profiling_keywords_output_to_file = 0;
56 thread_local int profiling_keyword_entered = 0;
57 static char profiling_file_name[PATH_MAX];
58 static const char *profiling_file_mode = "a";
59 
61 {
62  SCConfNode *conf;
63 
64  conf = SCConfGetNode("profiling.keywords");
65  if (conf != NULL) {
66  if (SCConfNodeChildValueIsTrue(conf, "enabled")) {
68  const char *filename = SCConfNodeLookupChildValue(conf, "filename");
69  if (filename != NULL) {
70  if (PathIsAbsolute(filename)) {
71  strlcpy(profiling_file_name, filename, sizeof(profiling_file_name));
72  } else {
73  const char *log_dir = SCConfigGetLogDirectory();
74  snprintf(profiling_file_name, sizeof(profiling_file_name), "%s/%s", log_dir,
75  filename);
76  }
77 
78  const char *v = SCConfNodeLookupChildValue(conf, "append");
79  if (v == NULL || SCConfValIsTrue(v)) {
80  profiling_file_mode = "a";
81  } else {
82  profiling_file_mode = "w";
83  }
84 
85  profiling_keywords_output_to_file = 1;
86  }
87  }
88  }
89 }
90 
91 static void DoDump(SCProfileKeywordDetectCtx *rules_ctx, FILE *fp, const char *name)
92 {
93  int i;
94  fprintf(fp, " ----------------------------------------------"
95  "------------------------------------------------------"
96  "----------------------------\n");
97  fprintf(fp, " Stats for: %s\n", name);
98  fprintf(fp, " ----------------------------------------------"
99  "------------------------------------------------------"
100  "----------------------------\n");
101  fprintf(fp, " %-16s %-15s %-15s %-15s %-15s %-15s %-15s %-15s\n", "Keyword", "Ticks", "Checks", "Matches", "Max Ticks", "Avg", "Avg Match", "Avg No Match");
102  fprintf(fp, " ---------------- "
103  "--------------- "
104  "--------------- "
105  "--------------- "
106  "--------------- "
107  "--------------- "
108  "--------------- "
109  "--------------- "
110  "\n");
111  for (i = 0; i < DETECT_TBLSIZE; i++) {
112  SCProfileKeywordData *d = &rules_ctx->data[i];
113  if (d == NULL || d->checks == 0)
114  continue;
115 
116  uint64_t ticks = d->ticks_match + d->ticks_no_match;
117  double avgticks = 0;
118  double avgticks_match = 0;
119  double avgticks_no_match = 0;
120  if (ticks && d->checks) {
121  avgticks = (double)(ticks / d->checks);
122 
123  if (d->ticks_match && d->matches)
124  avgticks_match = (double)(d->ticks_match / d->matches);
125  if (d->ticks_no_match && (d->checks - d->matches) != 0)
126  avgticks_no_match = (double)(d->ticks_no_match / (d->checks - d->matches));
127  }
128 
129  fprintf(fp,
130  " %-16s %-15"PRIu64" %-15"PRIu64" %-15"PRIu64" %-15"PRIu64" %-15.2f %-15.2f %-15.2f\n",
131  sigmatch_table[i].name,
132  ticks,
133  d->checks,
134  d->matches,
135  d->max,
136  avgticks,
137  avgticks_match,
138  avgticks_no_match);
139  }
140 }
141 
142 static void
143 SCProfilingKeywordDump(DetectEngineCtx *de_ctx)
144 {
145  int i;
146  FILE *fp;
147  struct timeval tval;
148  struct tm *tms;
149  struct tm local_tm;
150 
151  if (profiling_keyword_enabled == 0)
152  return;
153 
154  const int nlists = de_ctx->buffer_type_id;
155  gettimeofday(&tval, NULL);
156  tms = SCLocalTime(tval.tv_sec, &local_tm);
157 
158  if (profiling_keywords_output_to_file == 1) {
159  SCLogDebug("file %s mode %s", profiling_file_name, profiling_file_mode);
160 
161  fp = fopen(profiling_file_name, profiling_file_mode);
162 
163  if (fp == NULL) {
164  SCLogError("failed to open %s: %s", profiling_file_name, strerror(errno));
165  return;
166  }
167  } else {
168  fp = stdout;
169  }
170 
171  fprintf(fp, " ----------------------------------------------"
172  "------------------------------------------------------"
173  "----------------------------\n");
174  fprintf(fp, " Date: %" PRId32 "/%" PRId32 "/%04d -- "
175  "%02d:%02d:%02d\n", tms->tm_mon + 1, tms->tm_mday, tms->tm_year + 1900,
176  tms->tm_hour,tms->tm_min, tms->tm_sec);
177 
178  /* global stats first */
179  DoDump(de_ctx->profile_keyword_ctx, fp, "total");
180  /* per buffer stats next, but only if there are stats to print */
181  for (i = 0; i < nlists; i++) {
182  int j;
183  uint64_t checks = 0;
184  for (j = 0; j < DETECT_TBLSIZE; j++) {
186  }
187 
188  if (checks) {
189  const char *name = NULL;
192  } else {
194  }
195 
196  DoDump(de_ctx->profile_keyword_ctx_per_list[i], fp, name);
197  }
198  }
199 
200  fprintf(fp,"\n");
201  if (fp != stdout)
202  fclose(fp);
203 
204  SCLogPerf("Done dumping keyword profiling data.");
205 }
206 
207 /**
208  * \brief Update a rule counter.
209  *
210  * \param id The ID of this counter.
211  * \param ticks Number of CPU ticks for this rule.
212  * \param match Did the rule match?
213  */
214 void
215 SCProfilingKeywordUpdateCounter(DetectEngineThreadCtx *det_ctx, int id, uint64_t ticks, int match)
216 {
217  if (det_ctx != NULL && det_ctx->keyword_perf_data != NULL && id < DETECT_TBLSIZE) {
218  SCProfileKeywordData *p = &det_ctx->keyword_perf_data[id];
219 
220  p->checks++;
221  p->matches += match;
222  if (ticks > p->max)
223  p->max = ticks;
224  if (match == 1)
225  p->ticks_match += ticks;
226  else
227  p->ticks_no_match += ticks;
228 
229  /* store per list (buffer type) as well */
230  if (det_ctx->keyword_perf_list >= 0) {// && det_ctx->keyword_perf_list < DETECT_SM_LIST_MAX) {
231  p = &det_ctx->keyword_perf_data_per_list[det_ctx->keyword_perf_list][id];
232  p->checks++;
233  p->matches += match;
234  if (ticks > p->max)
235  p->max = ticks;
236  if (match == 1)
237  p->ticks_match += ticks;
238  else
239  p->ticks_no_match += ticks;
240  }
241  }
242 }
243 
244 static SCProfileKeywordDetectCtx *SCProfilingKeywordInitCtx(void)
245 {
247  if (ctx != NULL) {
248 
249  if (pthread_mutex_init(&ctx->data_m, NULL) != 0) {
250  FatalError("Failed to initialize hash table mutex.");
251  }
252  }
253 
254  return ctx;
255 }
256 
257 static void DetroyCtx(SCProfileKeywordDetectCtx *ctx)
258 {
259  if (ctx) {
260  if (ctx->data != NULL)
261  SCFree(ctx->data);
262  pthread_mutex_destroy(&ctx->data_m);
263  SCFree(ctx);
264  }
265 }
266 
268 {
269  if (de_ctx != NULL) {
270  SCProfilingKeywordDump(de_ctx);
271 
272  DetroyCtx(de_ctx->profile_keyword_ctx);
273 
274  const int nlists = de_ctx->buffer_type_id;
275  int i;
276  for (i = 0; i < nlists; i++) {
277  DetroyCtx(de_ctx->profile_keyword_ctx_per_list[i]);
278  }
280  }
281 }
282 
284 {
285  if (ctx == NULL)
286  return;
287 
289  if (a != NULL) {
290  det_ctx->keyword_perf_data = a;
291  }
292 
293  const int nlists = det_ctx->de_ctx->buffer_type_id;
294  det_ctx->keyword_perf_data_per_list = SCCalloc(nlists, sizeof(SCProfileKeywordData *));
295  BUG_ON(det_ctx->keyword_perf_data_per_list == NULL);
296 
297  int i;
298  for (i = 0; i < nlists; i++) {
300  if (b != NULL) {
301  det_ctx->keyword_perf_data_per_list[i] = b;
302  }
303  }
304 }
305 
306 static void SCProfilingKeywordThreadMerge(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx)
307 {
308  if (de_ctx == NULL || de_ctx->profile_keyword_ctx == NULL ||
309  de_ctx->profile_keyword_ctx->data == NULL || det_ctx == NULL ||
310  det_ctx->keyword_perf_data == NULL)
311  return;
312 
313  int i;
314  for (i = 0; i < DETECT_TBLSIZE; i++) {
319  if (det_ctx->keyword_perf_data[i].max > de_ctx->profile_keyword_ctx->data[i].max)
321  }
322 
323  const int nlists = det_ctx->de_ctx->buffer_type_id;
324  int j;
325  for (j = 0; j < nlists; j++) {
326  for (i = 0; i < DETECT_TBLSIZE; i++) {
333  }
334  }
335 }
336 
338 {
339  if (det_ctx == NULL || det_ctx->de_ctx == NULL || det_ctx->keyword_perf_data == NULL)
340  return;
341 
342  pthread_mutex_lock(&det_ctx->de_ctx->profile_keyword_ctx->data_m);
343  SCProfilingKeywordThreadMerge(det_ctx->de_ctx, det_ctx);
344  pthread_mutex_unlock(&det_ctx->de_ctx->profile_keyword_ctx->data_m);
345 
346  SCFree(det_ctx->keyword_perf_data);
347  det_ctx->keyword_perf_data = NULL;
348 
349  const int nlists = det_ctx->de_ctx->buffer_type_id;
350  int i;
351  for (i = 0; i < nlists; i++) {
352  SCFree(det_ctx->keyword_perf_data_per_list[i]);
353  det_ctx->keyword_perf_data_per_list[i] = NULL;
354  }
356 }
357 
358 /**
359  * \brief Register the keyword profiling counters.
360  *
361  * \param de_ctx The active DetectEngineCtx, used to get at the loaded rules.
362  */
363 void
365 {
366  if (profiling_keyword_enabled == 0)
367  return;
368 
369  const int nlists = de_ctx->buffer_type_id;
370 
371  de_ctx->profile_keyword_ctx = SCProfilingKeywordInitCtx();
373 
376 
379 
380  int i;
381  for (i = 0; i < nlists; i++) {
382  de_ctx->profile_keyword_ctx_per_list[i] = SCProfilingKeywordInitCtx();
387  }
388 
389  SCLogPerf("Registered %"PRIu32" keyword profiling counters.", DETECT_TBLSIZE);
390 }
391 
392 #endif /* PROFILING */
tm-threads.h
DetectEngineThreadCtx_::keyword_perf_data_per_list
struct SCProfileKeywordData_ ** keyword_perf_data_per_list
Definition: detect.h:1485
SCProfileKeywordData_
Definition: util-profiling-keywords.c:40
SCConfValIsTrue
int SCConfValIsTrue(const char *val)
Check if a value is true.
Definition: conf.c:577
detect-engine.h
SCProfilingKeywordDestroyCtx
void SCProfilingKeywordDestroyCtx(DetectEngineCtx *de_ctx)
Definition: util-profiling-keywords.c:267
SCProfilingKeywordThreadCleanup
void SCProfilingKeywordThreadCleanup(DetectEngineThreadCtx *det_ctx)
Definition: util-profiling-keywords.c:337
DetectEngineThreadCtx_::keyword_perf_data
struct SCProfileKeywordData_ * keyword_perf_data
Definition: detect.h:1484
sigmatch_table
SigTableElmt * sigmatch_table
Definition: detect-parse.c:78
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:282
name
const char * name
Definition: detect-engine-proto.c:47
DETECT_SM_LIST_DYNAMIC_START
@ DETECT_SM_LIST_DYNAMIC_START
Definition: detect.h:139
ctx
struct Thresholds ctx
DetectEngineCtx_
main detection engine ctx
Definition: detect.h:995
SCConfNodeChildValueIsTrue
int SCConfNodeChildValueIsTrue(const SCConfNode *node, const char *key)
Test if a configuration node has a true value.
Definition: conf.c:921
DetectEngineThreadCtx_::keyword_perf_list
int keyword_perf_list
Definition: detect.h:1486
DetectEngineBufferTypeGetNameById
const char * DetectEngineBufferTypeGetNameById(const DetectEngineCtx *de_ctx, const int id)
Definition: detect-engine.c:1482
profiling_keyword_entered
thread_local int profiling_keyword_entered
Definition: util-profiling-keywords.c:56
p
Packet * p
Definition: fuzz_dataset.c:30
SCConfNodeLookupChildValue
const char * SCConfNodeLookupChildValue(const SCConfNode *node, const char *name)
Lookup the value of a child configuration node by name.
Definition: conf.c:877
SCProfileKeywordData_::ticks_match
uint64_t ticks_match
Definition: util-profiling-keywords.c:44
SCProfileKeywordData_::checks
uint64_t checks
Definition: util-profiling-keywords.c:41
strlcpy
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: util-strlcpyu.c:43
de_ctx
DetectEngineCtx * de_ctx
Definition: fuzz_siginit.c:22
DetectEngineThreadCtx_
Definition: detect.h:1316
SCProfileKeywordDetectCtx_
Definition: util-profiling-keywords.c:48
SCProfileKeywordDetectCtx
struct SCProfileKeywordDetectCtx_ SCProfileKeywordDetectCtx
SCProfileKeywordDetectCtx_::data_m
pthread_mutex_t data_m
Definition: util-profiling-keywords.c:51
BUG_ON
#define BUG_ON(x)
Definition: suricata-common.h:322
util-profiling.h
SCLocalTime
struct tm * SCLocalTime(time_t timep, struct tm *result)
Definition: util-time.c:267
SCConfigGetLogDirectory
const char * SCConfigGetLogDirectory(void)
Definition: util-conf.c:38
DetectEngineCtx_::profile_keyword_ctx
struct SCProfileKeywordDetectCtx_ * profile_keyword_ctx
Definition: detect.h:1115
SCProfilingKeywordUpdateCounter
void SCProfilingKeywordUpdateCounter(DetectEngineThreadCtx *det_ctx, int id, uint64_t ticks, int match)
Update a rule counter.
Definition: util-profiling-keywords.c:215
DetectSigmatchListEnumToString
const char * DetectSigmatchListEnumToString(enum DetectSigmatchListEnum type)
Definition: detect-engine.c:5298
util-conf.h
suricata-common.h
util-path.h
SCLogPerf
#define SCLogPerf(...)
Definition: util-debug.h:241
PathIsAbsolute
int PathIsAbsolute(const char *path)
Check if a path is absolute.
Definition: util-path.c:45
SCProfileKeywordData_::matches
uint64_t matches
Definition: util-profiling-keywords.c:42
FatalError
#define FatalError(...)
Definition: util-debug.h:517
DetectEngineCtx_::profile_keyword_ctx_per_list
struct SCProfileKeywordDetectCtx_ ** profile_keyword_ctx_per_list
Definition: detect.h:1117
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
DETECT_TBLSIZE
int DETECT_TBLSIZE
Definition: detect-engine-register.c:261
SCFree
#define SCFree(p)
Definition: util-mem.h:61
profiling_keyword_enabled
int profiling_keyword_enabled
Definition: util-profiling-keywords.c:55
SCProfileKeywordData_::max
uint64_t max
Definition: util-profiling-keywords.c:43
SCProfileKeywordDetectCtx_::id
uint32_t id
Definition: util-profiling-keywords.c:49
SCProfileKeywordDetectCtx_::data
SCProfileKeywordData * data
Definition: util-profiling-keywords.c:50
SCProfilingKeywordInitCounters
void SCProfilingKeywordInitCounters(DetectEngineCtx *de_ctx)
Register the keyword profiling counters.
Definition: util-profiling-keywords.c:364
DetectEngineThreadCtx_::de_ctx
DetectEngineCtx * de_ctx
Definition: detect.h:1444
SCProfilingKeywordsGlobalInit
void SCProfilingKeywordsGlobalInit(void)
Definition: util-profiling-keywords.c:60
DetectEngineCtx_::buffer_type_id
uint32_t buffer_type_id
Definition: detect.h:1151
util-profiling-locks.h
SCProfileKeywordData
struct SCProfileKeywordData_ SCProfileKeywordData
SCCalloc
#define SCCalloc(nm, sz)
Definition: util-mem.h:53
SCConfNode_
Definition: conf.h:37
SCProfileKeywordData_::ticks_no_match
uint64_t ticks_no_match
Definition: util-profiling-keywords.c:45
SCProfilingKeywordThreadSetup
void SCProfilingKeywordThreadSetup(SCProfileKeywordDetectCtx *ctx, DetectEngineThreadCtx *det_ctx)
Definition: util-profiling-keywords.c:283