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#include "util-time.h"
35
37 uint64_t called;
38 uint64_t total;
39 uint64_t max;
40 uint64_t total_bytes;
41 uint64_t max_bytes;
42 uint64_t bytes_called; /**< number of times total_bytes was updated. Differs from `called` as a
43 prefilter engine may skip mpm if the smallest pattern is bigger than
44 the buffer to inspect. */
45 const char *name;
47
49 uint32_t id;
50 uint32_t size; /**< size in elements */
52 pthread_mutex_t data_m;
54
55static int profiling_prefilter_output_to_file = 0;
57thread_local int profiling_prefilter_entered = 0;
58static char profiling_file_name[PATH_MAX];
59static const char *profiling_file_mode = "a";
60
62{
63 SCConfNode *conf;
64
65 conf = SCConfGetNode("profiling.prefilter");
66 if (conf != NULL) {
67 if (SCConfNodeChildValueIsTrue(conf, "enabled")) {
69 const char *filename = SCConfNodeLookupChildValue(conf, "filename");
70 if (filename != NULL) {
71 if (PathIsAbsolute(filename)) {
72 strlcpy(profiling_file_name, filename, sizeof(profiling_file_name));
73 } else {
74 const char *log_dir = SCConfigGetLogDirectory();
75 snprintf(profiling_file_name, sizeof(profiling_file_name), "%s/%s", log_dir,
76 filename);
77 }
78
79 const char *v = SCConfNodeLookupChildValue(conf, "append");
80 if (v == NULL || SCConfValIsTrue(v)) {
81 profiling_file_mode = "a";
82 } else {
83 profiling_file_mode = "w";
84 }
85
86 profiling_prefilter_output_to_file = 1;
87 }
88 }
89 }
90}
91
92static void DoDump(SCProfilePrefilterDetectCtx *rules_ctx, FILE *fp, const char *name)
93{
94 int i;
95 fprintf(fp, " ----------------------------------------------"
96 "------------------------------------------------------"
97 "----------------------------\n");
98 fprintf(fp, " Stats for: %s\n", name);
99 fprintf(fp, " ----------------------------------------------"
100 "------------------------------------------------------"
101 "----------------------------\n");
102 fprintf(fp, " %-32s %-15s %-15s %-15s %-15s %-15s %-15s %-15s %-15s %-15s\n", "Prefilter",
103 "Ticks", "Called", "Max Ticks", "Avg", "Bytes", "Called", "Max Bytes", "Avg Bytes",
104 "Ticks/Byte");
105 fprintf(fp, " -------------------------------- "
106 "--------------- "
107 "--------------- "
108 "--------------- "
109 "--------------- "
110 "--------------- "
111 "--------------- "
112 "--------------- "
113 "--------------- "
114 "--------------- "
115 "\n");
116 for (i = 0; i < (int)rules_ctx->size; i++) {
117 SCProfilePrefilterData *d = &rules_ctx->data[i];
118 if (d == NULL || d->called== 0)
119 continue;
120
121 uint64_t ticks = d->total;
122 double avgticks = 0;
123 if (ticks && d->called) {
124 avgticks = (double)(ticks / d->called);
125 }
126 double avgbytes = 0;
127 if (d->total_bytes && d->bytes_called) {
128 avgbytes = (double)(d->total_bytes / d->bytes_called);
129 }
130 double ticks_per_byte = 0;
131 if (ticks && d->total_bytes) {
132 ticks_per_byte = (double)(ticks / d->total_bytes);
133 }
134
135 fprintf(fp,
136 " %-32s %-15" PRIu64 " %-15" PRIu64 " %-15" PRIu64 " %-15.2f %-15" PRIu64
137 " %-15" PRIu64 " %-15" PRIu64 " %-15.2f %-15.2f\n",
138 d->name, ticks, d->called, d->max, avgticks, d->total_bytes, d->bytes_called,
139 d->max_bytes, avgbytes, ticks_per_byte);
140 }
141}
142
143static void
144SCProfilingPrefilterDump(DetectEngineCtx *de_ctx)
145{
146 FILE *fp;
147 struct timeval tval;
148 struct tm *tms;
149 struct tm local_tm;
150
152 return;
153
154 gettimeofday(&tval, NULL);
155 tms = SCLocalTime(tval.tv_sec, &local_tm);
156
157 if (profiling_prefilter_output_to_file == 1) {
158 SCLogDebug("file %s mode %s", profiling_file_name, profiling_file_mode);
159
160 fp = fopen(profiling_file_name, profiling_file_mode);
161
162 if (fp == NULL) {
163 SCLogError("failed to open %s: %s", profiling_file_name, strerror(errno));
164 return;
165 }
166 } else {
167 fp = stdout;
168 }
169
170 fprintf(fp, " ----------------------------------------------"
171 "------------------------------------------------------"
172 "----------------------------\n");
173 fprintf(fp, " Date: %" PRId32 "/%" PRId32 "/%04d -- "
174 "%02d:%02d:%02d\n", tms->tm_mon + 1, tms->tm_mday, tms->tm_year + 1900,
175 tms->tm_hour,tms->tm_min, tms->tm_sec);
176
177 /* global stats first */
178 DoDump(de_ctx->profile_prefilter_ctx, fp, "total");
179
180 fprintf(fp,"\n");
181 if (fp != stdout)
182 fclose(fp);
183
184 SCLogPerf("Done dumping prefilter profiling data.");
185}
186
187/**
188 * \brief Update a rule counter.
189 *
190 * \param id The ID of this counter.
191 * \param ticks Number of CPU ticks for this rule.
192 * \param match Did the rule match?
193 */
194void SCProfilingPrefilterUpdateCounter(DetectEngineThreadCtx *det_ctx, int id, uint64_t ticks,
195 uint64_t bytes, uint64_t bytes_called)
196{
197 if (det_ctx != NULL && det_ctx->prefilter_perf_data != NULL &&
198 id < (int)det_ctx->de_ctx->prefilter_id)
199 {
201
202 p->called++;
203 if (ticks > p->max)
204 p->max = ticks;
205 p->total += ticks;
206
207 p->bytes_called += bytes_called;
208 if (bytes > p->max_bytes)
209 p->max_bytes = bytes;
210 p->total_bytes += bytes;
211 }
212}
213
214static SCProfilePrefilterDetectCtx *SCProfilingPrefilterInitCtx(void)
215{
217 if (ctx != NULL) {
218 if (pthread_mutex_init(&ctx->data_m, NULL) != 0) {
219 FatalError("Failed to initialize hash table mutex.");
220 }
221 }
222
223 return ctx;
224}
225
226static void DetroyCtx(SCProfilePrefilterDetectCtx *ctx)
227{
228 if (ctx) {
229 if (ctx->data != NULL)
230 SCFree(ctx->data);
231 pthread_mutex_destroy(&ctx->data_m);
232 SCFree(ctx);
233 }
234}
235
237{
238 if (de_ctx != NULL) {
239 SCProfilingPrefilterDump(de_ctx);
240
241 DetroyCtx(de_ctx->profile_prefilter_ctx);
242 }
243}
244
246{
247 if (ctx == NULL)
248 return;
249
250 const uint32_t size = det_ctx->de_ctx->prefilter_id;
251
253 if (a != NULL) {
254 det_ctx->prefilter_perf_data = a;
255 }
256}
257
258static void SCProfilingPrefilterThreadMerge(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx)
259{
260 if (de_ctx == NULL || de_ctx->profile_prefilter_ctx == NULL ||
261 de_ctx->profile_prefilter_ctx->data == NULL || det_ctx == NULL ||
262 det_ctx->prefilter_perf_data == NULL)
263 return;
264
265 for (uint32_t i = 0; i < de_ctx->prefilter_id; i++) {
272 if (det_ctx->prefilter_perf_data[i].max_bytes >
275 det_ctx->prefilter_perf_data[i].max_bytes;
278 }
279}
280
282{
283 if (det_ctx == NULL || det_ctx->de_ctx == NULL || det_ctx->prefilter_perf_data == NULL)
284 return;
285
286 pthread_mutex_lock(&det_ctx->de_ctx->profile_prefilter_ctx->data_m);
287 SCProfilingPrefilterThreadMerge(det_ctx->de_ctx, det_ctx);
288 pthread_mutex_unlock(&det_ctx->de_ctx->profile_prefilter_ctx->data_m);
289
290 SCFree(det_ctx->prefilter_perf_data);
291 det_ctx->prefilter_perf_data = NULL;
292}
293
294/**
295 * \brief Register the prefilter profiling counters.
296 *
297 * \param de_ctx The active DetectEngineCtx, used to get at the loaded rules.
298 */
299void
301{
303 return;
304
305 const uint32_t size = de_ctx->prefilter_id;
306 if (size == 0)
307 return;
308
309 de_ctx->profile_prefilter_ctx = SCProfilingPrefilterInitCtx();
312
315
317 for ( ; hb != NULL; hb = HashListTableGetListNext(hb)) {
320 SCLogDebug("prefilter %s set up", de_ctx->profile_prefilter_ctx->data[ctx->id].name);
321 }
322 SCLogDebug("size alloc'd %u", (uint32_t)size * (uint32_t)sizeof(SCProfilePrefilterData));
323
324 SCLogPerf("Registered %"PRIu32" prefilter profiling counters.", size);
325}
326
327#endif /* PROFILING */
SCConfNode * SCConfGetNode(const char *name)
Get a SCConfNode by name.
Definition conf.c:181
int SCConfNodeChildValueIsTrue(const SCConfNode *node, const char *key)
Test if a configuration node has a true value.
Definition conf.c:868
int SCConfValIsTrue(const char *val)
Check if a value is true.
Definition conf.c:551
const char * SCConfNodeLookupChildValue(const SCConfNode *node, const char *name)
Lookup the value of a child configuration node by name.
Definition conf.c:824
uint32_t id
DetectEngineCtx * de_ctx
struct Thresholds ctx
main detection engine ctx
Definition detect.h:932
HashListTable * prefilter_hash_table
Definition detect.h:1096
uint32_t prefilter_id
Definition detect.h:1095
struct SCProfilePrefilterDetectCtx_ * profile_prefilter_ctx
Definition detect.h:1046
struct SCProfilePrefilterData_ * prefilter_perf_data
Definition detect.h:1409
DetectEngineCtx * de_ctx
Definition detect.h:1364
#define BUG_ON(x)
size_t strlcpy(char *dst, const char *src, size_t siz)
const char * name
const char * SCConfigGetLogDirectory(void)
Definition util-conf.c:38
#define FatalError(...)
Definition util-debug.h:510
#define SCLogPerf(...)
Definition util-debug.h:234
#define SCLogDebug(...)
Definition util-debug.h:275
#define SCLogError(...)
Macro used to log ERROR messages.
Definition util-debug.h:267
HashListTableBucket * HashListTableGetListHead(HashListTable *ht)
#define HashListTableGetListData(hb)
#define HashListTableGetListNext(hb)
#define SCFree(p)
Definition util-mem.h:61
#define SCCalloc(nm, sz)
Definition util-mem.h:53
int PathIsAbsolute(const char *path)
Check if a path is absolute.
Definition util-path.c:44
void SCProfilingPrefilterInitCounters(DetectEngineCtx *de_ctx)
Register the prefilter profiling counters.
void SCProfilingPrefilterUpdateCounter(DetectEngineThreadCtx *det_ctx, int id, uint64_t ticks, uint64_t bytes, uint64_t bytes_called)
Update a rule counter.
struct SCProfilePrefilterDetectCtx_ SCProfilePrefilterDetectCtx
int profiling_prefilter_enabled
void SCProfilingPrefilterThreadCleanup(DetectEngineThreadCtx *det_ctx)
void SCProfilingPrefilterThreadSetup(SCProfilePrefilterDetectCtx *ctx, DetectEngineThreadCtx *det_ctx)
thread_local int profiling_prefilter_entered
struct SCProfilePrefilterData_ SCProfilePrefilterData
void SCProfilingPrefilterGlobalInit(void)
void SCProfilingPrefilterDestroyCtx(DetectEngineCtx *de_ctx)
struct tm * SCLocalTime(time_t timep, struct tm *result)
Definition util-time.c:267