suricata
util-profiling-prefilter.c
Go to the documentation of this file.
1 /* Copyright (C) 2007-2022 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 
30 #ifdef PROFILING
32 #include "util-conf.h"
33 #include "util-path.h"
34 
35 typedef struct SCProfilePrefilterData_ {
36  uint64_t called;
37  uint64_t total;
38  uint64_t max;
39  uint64_t total_bytes;
40  uint64_t max_bytes;
41  uint64_t bytes_called; /**< number of times total_bytes was updated. Differs from `called` as a
42  prefilter engine may skip mpm if the smallest pattern is bigger than
43  the buffer to inspect. */
44  const char *name;
46 
48  uint32_t id;
49  uint32_t size; /**< size in elements */
51  pthread_mutex_t data_m;
53 
54 static int profiling_prefilter_output_to_file = 0;
56 thread_local int profiling_prefilter_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.prefilter");
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_prefilter_output_to_file = 1;
86  }
87  }
88  }
89 }
90 
91 static void DoDump(SCProfilePrefilterDetectCtx *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, " %-32s %-15s %-15s %-15s %-15s %-15s %-15s %-15s %-15s %-15s\n", "Prefilter",
102  "Ticks", "Called", "Max Ticks", "Avg", "Bytes", "Called", "Max Bytes", "Avg Bytes",
103  "Ticks/Byte");
104  fprintf(fp, " -------------------------------- "
105  "--------------- "
106  "--------------- "
107  "--------------- "
108  "--------------- "
109  "--------------- "
110  "--------------- "
111  "--------------- "
112  "--------------- "
113  "--------------- "
114  "\n");
115  for (i = 0; i < (int)rules_ctx->size; i++) {
116  SCProfilePrefilterData *d = &rules_ctx->data[i];
117  if (d == NULL || d->called== 0)
118  continue;
119 
120  uint64_t ticks = d->total;
121  double avgticks = 0;
122  if (ticks && d->called) {
123  avgticks = (double)(ticks / d->called);
124  }
125  double avgbytes = 0;
126  if (d->total_bytes && d->bytes_called) {
127  avgbytes = (double)(d->total_bytes / d->bytes_called);
128  }
129  double ticks_per_byte = 0;
130  if (ticks && d->total_bytes) {
131  ticks_per_byte = (double)(ticks / d->total_bytes);
132  }
133 
134  fprintf(fp,
135  " %-32s %-15" PRIu64 " %-15" PRIu64 " %-15" PRIu64 " %-15.2f %-15" PRIu64
136  " %-15" PRIu64 " %-15" PRIu64 " %-15.2f %-15.2f\n",
137  d->name, ticks, d->called, d->max, avgticks, d->total_bytes, d->bytes_called,
138  d->max_bytes, avgbytes, ticks_per_byte);
139  }
140 }
141 
142 static void
143 SCProfilingPrefilterDump(DetectEngineCtx *de_ctx)
144 {
145  FILE *fp;
146  struct timeval tval;
147  struct tm *tms;
148  struct tm local_tm;
149 
151  return;
152 
153  gettimeofday(&tval, NULL);
154  tms = SCLocalTime(tval.tv_sec, &local_tm);
155 
156  if (profiling_prefilter_output_to_file == 1) {
157  SCLogDebug("file %s mode %s", profiling_file_name, profiling_file_mode);
158 
159  fp = fopen(profiling_file_name, profiling_file_mode);
160 
161  if (fp == NULL) {
162  SCLogError("failed to open %s: %s", profiling_file_name, strerror(errno));
163  return;
164  }
165  } else {
166  fp = stdout;
167  }
168 
169  fprintf(fp, " ----------------------------------------------"
170  "------------------------------------------------------"
171  "----------------------------\n");
172  fprintf(fp, " Date: %" PRId32 "/%" PRId32 "/%04d -- "
173  "%02d:%02d:%02d\n", tms->tm_mon + 1, tms->tm_mday, tms->tm_year + 1900,
174  tms->tm_hour,tms->tm_min, tms->tm_sec);
175 
176  /* global stats first */
177  DoDump(de_ctx->profile_prefilter_ctx, fp, "total");
178 
179  fprintf(fp,"\n");
180  if (fp != stdout)
181  fclose(fp);
182 
183  SCLogPerf("Done dumping prefilter profiling data.");
184 }
185 
186 /**
187  * \brief Update a rule counter.
188  *
189  * \param id The ID of this counter.
190  * \param ticks Number of CPU ticks for this rule.
191  * \param match Did the rule match?
192  */
193 void SCProfilingPrefilterUpdateCounter(DetectEngineThreadCtx *det_ctx, int id, uint64_t ticks,
194  uint64_t bytes, uint64_t bytes_called)
195 {
196  if (det_ctx != NULL && det_ctx->prefilter_perf_data != NULL &&
197  id < (int)det_ctx->de_ctx->prefilter_id)
198  {
200 
201  p->called++;
202  if (ticks > p->max)
203  p->max = ticks;
204  p->total += ticks;
205 
206  p->bytes_called += bytes_called;
207  if (bytes > p->max_bytes)
208  p->max_bytes = bytes;
209  p->total_bytes += bytes;
210  }
211 }
212 
213 static SCProfilePrefilterDetectCtx *SCProfilingPrefilterInitCtx(void)
214 {
216  if (ctx != NULL) {
217  if (pthread_mutex_init(&ctx->data_m, NULL) != 0) {
218  FatalError("Failed to initialize hash table mutex.");
219  }
220  }
221 
222  return ctx;
223 }
224 
225 static void DetroyCtx(SCProfilePrefilterDetectCtx *ctx)
226 {
227  if (ctx) {
228  if (ctx->data != NULL)
229  SCFree(ctx->data);
230  pthread_mutex_destroy(&ctx->data_m);
231  SCFree(ctx);
232  }
233 }
234 
236 {
237  if (de_ctx != NULL) {
238  SCProfilingPrefilterDump(de_ctx);
239 
240  DetroyCtx(de_ctx->profile_prefilter_ctx);
241  }
242 }
243 
245 {
246  if (ctx == NULL)
247  return;
248 
249  const uint32_t size = det_ctx->de_ctx->prefilter_id;
250 
252  if (a != NULL) {
253  det_ctx->prefilter_perf_data = a;
254  }
255 }
256 
257 static void SCProfilingPrefilterThreadMerge(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx)
258 {
259  if (de_ctx == NULL || de_ctx->profile_prefilter_ctx == NULL ||
260  de_ctx->profile_prefilter_ctx->data == NULL || det_ctx == NULL ||
261  det_ctx->prefilter_perf_data == NULL)
262  return;
263 
264  for (uint32_t i = 0; i < de_ctx->prefilter_id; i++) {
270  det_ctx->prefilter_perf_data[i].total_bytes;
271  if (det_ctx->prefilter_perf_data[i].max_bytes >
274  det_ctx->prefilter_perf_data[i].max_bytes;
276  det_ctx->prefilter_perf_data[i].bytes_called;
277  }
278 }
279 
281 {
282  if (det_ctx == NULL || det_ctx->de_ctx == NULL || det_ctx->prefilter_perf_data == NULL)
283  return;
284 
285  pthread_mutex_lock(&det_ctx->de_ctx->profile_prefilter_ctx->data_m);
286  SCProfilingPrefilterThreadMerge(det_ctx->de_ctx, det_ctx);
287  pthread_mutex_unlock(&det_ctx->de_ctx->profile_prefilter_ctx->data_m);
288 
289  SCFree(det_ctx->prefilter_perf_data);
290  det_ctx->prefilter_perf_data = NULL;
291 }
292 
293 /**
294  * \brief Register the prefilter profiling counters.
295  *
296  * \param de_ctx The active DetectEngineCtx, used to get at the loaded rules.
297  */
298 void
300 {
302  return;
303 
304  const uint32_t size = de_ctx->prefilter_id;
305  if (size == 0)
306  return;
307 
308  de_ctx->profile_prefilter_ctx = SCProfilingPrefilterInitCtx();
311 
314 
316  for ( ; hb != NULL; hb = HashListTableGetListNext(hb)) {
318  de_ctx->profile_prefilter_ctx->data[ctx->id].name = ctx->name;
319  SCLogDebug("prefilter %s set up", de_ctx->profile_prefilter_ctx->data[ctx->id].name);
320  }
321  SCLogDebug("size alloc'd %u", (uint32_t)size * (uint32_t)sizeof(SCProfilePrefilterData));
322 
323  SCLogPerf("Registered %"PRIu32" prefilter profiling counters.", size);
324 }
325 
326 #endif /* PROFILING */
HashListTableGetListData
#define HashListTableGetListData(hb)
Definition: util-hashlist.h:56
SCProfilePrefilterDetectCtx_::size
uint32_t size
Definition: util-profiling-prefilter.c:49
SCConfValIsTrue
int SCConfValIsTrue(const char *val)
Check if a value is true.
Definition: conf.c:577
profiling_prefilter_entered
thread_local int profiling_prefilter_entered
Definition: util-profiling-prefilter.c:56
PrefilterStore_
Definition: detect-engine-prefilter.h:51
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:282
name
const char * name
Definition: detect-engine-proto.c:47
SCProfilePrefilterDetectCtx_::data
SCProfilePrefilterData * data
Definition: util-profiling-prefilter.c:50
SCProfilePrefilterDetectCtx_::id
uint32_t id
Definition: util-profiling-prefilter.c:48
ctx
struct Thresholds ctx
DetectEngineCtx_
main detection engine ctx
Definition: detect.h:995
SCProfilePrefilterDetectCtx_
Definition: util-profiling-prefilter.c:47
SCProfilePrefilterData_::name
const char * name
Definition: util-profiling-prefilter.c:44
SCConfNodeChildValueIsTrue
int SCConfNodeChildValueIsTrue(const SCConfNode *node, const char *key)
Test if a configuration node has a true value.
Definition: conf.c:921
HashListTableGetListHead
HashListTableBucket * HashListTableGetListHead(HashListTable *ht)
Definition: util-hashlist.c:286
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
SCProfilePrefilterDetectCtx
struct SCProfilePrefilterDetectCtx_ SCProfilePrefilterDetectCtx
detect-engine-prefilter.h
strlcpy
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: util-strlcpyu.c:43
DetectEngineCtx_::prefilter_id
uint32_t prefilter_id
Definition: detect.h:1165
profiling_prefilter_enabled
int profiling_prefilter_enabled
Definition: util-profiling-prefilter.c:55
HashListTableGetListNext
#define HashListTableGetListNext(hb)
Definition: util-hashlist.h:55
DetectEngineCtx_::prefilter_hash_table
HashListTable * prefilter_hash_table
Definition: detect.h:1166
SCProfilePrefilterData_::total
uint64_t total
Definition: util-profiling-prefilter.c:37
de_ctx
DetectEngineCtx * de_ctx
Definition: fuzz_siginit.c:22
SCProfilingPrefilterDestroyCtx
void SCProfilingPrefilterDestroyCtx(DetectEngineCtx *de_ctx)
Definition: util-profiling-prefilter.c:235
DetectEngineThreadCtx_
Definition: detect.h:1316
SCProfilingPrefilterInitCounters
void SCProfilingPrefilterInitCounters(DetectEngineCtx *de_ctx)
Register the prefilter profiling counters.
Definition: util-profiling-prefilter.c:299
SCProfilingPrefilterGlobalInit
void SCProfilingPrefilterGlobalInit(void)
Definition: util-profiling-prefilter.c:60
BUG_ON
#define BUG_ON(x)
Definition: suricata-common.h:322
util-profiling.h
SCProfilePrefilterData_::max_bytes
uint64_t max_bytes
Definition: util-profiling-prefilter.c:40
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
SCProfilingPrefilterThreadCleanup
void SCProfilingPrefilterThreadCleanup(DetectEngineThreadCtx *det_ctx)
Definition: util-profiling-prefilter.c:280
SCProfilePrefilterData_::total_bytes
uint64_t total_bytes
Definition: util-profiling-prefilter.c:39
util-conf.h
DetectEngineCtx_::profile_prefilter_ctx
struct SCProfilePrefilterDetectCtx_ * profile_prefilter_ctx
Definition: detect.h:1116
suricata-common.h
util-path.h
SCProfilingPrefilterUpdateCounter
void SCProfilingPrefilterUpdateCounter(DetectEngineThreadCtx *det_ctx, int id, uint64_t ticks, uint64_t bytes, uint64_t bytes_called)
Update a rule counter.
Definition: util-profiling-prefilter.c:193
DetectEngineThreadCtx_::prefilter_perf_data
struct SCProfilePrefilterData_ * prefilter_perf_data
Definition: detect.h:1489
SCLogPerf
#define SCLogPerf(...)
Definition: util-debug.h:241
PathIsAbsolute
int PathIsAbsolute(const char *path)
Check if a path is absolute.
Definition: util-path.c:44
FatalError
#define FatalError(...)
Definition: util-debug.h:517
SCProfilePrefilterData_::max
uint64_t max
Definition: util-profiling-prefilter.c:38
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
SCProfilePrefilterData_::called
uint64_t called
Definition: util-profiling-prefilter.c:36
SCFree
#define SCFree(p)
Definition: util-mem.h:61
HashListTableBucket_
Definition: util-hashlist.h:28
SCProfilePrefilterDetectCtx_::data_m
pthread_mutex_t data_m
Definition: util-profiling-prefilter.c:51
SCProfilePrefilterData_
Definition: util-profiling-prefilter.c:35
DetectEngineThreadCtx_::de_ctx
DetectEngineCtx * de_ctx
Definition: detect.h:1444
SCProfilePrefilterData
struct SCProfilePrefilterData_ SCProfilePrefilterData
SCCalloc
#define SCCalloc(nm, sz)
Definition: util-mem.h:53
SCConfNode_
Definition: conf.h:37
SCProfilePrefilterData_::bytes_called
uint64_t bytes_called
Definition: util-profiling-prefilter.c:41
SCProfilingPrefilterThreadSetup
void SCProfilingPrefilterThreadSetup(SCProfilePrefilterDetectCtx *ctx, DetectEngineThreadCtx *det_ctx)
Definition: util-profiling-prefilter.c:244