1 /* Copyright (C) 2007-2012 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 
25 #ifndef __UTIL_PROFILE_H__
26 #define __UTIL_PROFILE_H__
27 
28 #ifdef PROFILING
29 
30 #include "util-profiling-locks.h"
31 #include "util-cpu.h"
32 
33 extern int profiling_rules_enabled;
34 extern int profiling_packets_enabled;
35 extern int profiling_sghs_enabled;
36 extern thread_local int profiling_rules_entered;
37 
38 void SCProfilingPrintPacketProfile(Packet *);
39 void SCProfilingAddPacket(Packet *);
40 int SCProfileRuleStart(Packet *p);
41 
42 #define RULE_PROFILING_START(p) \
43     uint64_t profile_rule_start_ = 0; \
44     uint64_t profile_rule_end_ = 0; \
45     if (profiling_rules_enabled && SCProfileRuleStart((p))) { \
46         if (profiling_rules_entered > 0) { \
47             SCLogError(SC_ERR_FATAL, "Re-entered profiling, exiting."); \
48             exit(1); \
49         } \
50         profiling_rules_entered++; \
51         profile_rule_start_ = UtilCpuGetTicks(); \
52     }
53 
54 #define RULE_PROFILING_END(ctx, r, m, p) \
55     if (profiling_rules_enabled && ((p)->flags & PKT_PROFILE)) { \
56         profile_rule_end_ = UtilCpuGetTicks(); \
57         SCProfilingRuleUpdateCounter(ctx, r->profiling_id, \
58             profile_rule_end_ - profile_rule_start_, m); \
59         profiling_rules_entered--; \
60     }
61 
62 extern int profiling_keyword_enabled;
63 extern thread_local int profiling_keyword_entered;
64 
65 #define KEYWORD_PROFILING_SET_LIST(ctx, list) { \
66     (ctx)->keyword_perf_list = (list); \
67 }
68 
69 #define KEYWORD_PROFILING_START \
70     uint64_t profile_keyword_start_ = 0; \
71     uint64_t profile_keyword_end_ = 0; \
72     if (profiling_keyword_enabled) { \
73         if (profiling_keyword_entered > 0) { \
74             SCLogError(SC_ERR_FATAL, "Re-entered profiling, exiting."); \
75             abort(); \
76         } \
77         profiling_keyword_entered++; \
78         profile_keyword_start_ = UtilCpuGetTicks(); \
79     }
80 
81 /* we allow this macro to be called if profiling_keyword_entered == 0,
82  * so that we don't have to refactor some of the detection code. */
83 #define KEYWORD_PROFILING_END(ctx, type, m) \
84     if (profiling_keyword_enabled && profiling_keyword_entered) { \
85         profile_keyword_end_ = UtilCpuGetTicks(); \
86         SCProfilingKeywordUpdateCounter((ctx),(type),(profile_keyword_end_ - profile_keyword_start_),(m)); \
87         profiling_keyword_entered--; \
88     }
89 
90 PktProfiling *SCProfilePacketStart(void);
91 
92 #define PACKET_PROFILING_START(p)                                   \
93     if (profiling_packets_enabled) {                                \
94         (p)->profile = SCProfilePacketStart();                      \
95         if ((p)->profile != NULL)                                   \
96             (p)->profile->ticks_start = UtilCpuGetTicks();          \
97     }
98 
99 #define PACKET_PROFILING_RESTART(p)                                 \
100     if (profiling_packets_enabled) {                                \
101         if ((p)->profile != NULL)                                   \
102             (p)->profile->ticks_start = UtilCpuGetTicks();          \
103     }
104 
105 #define PACKET_PROFILING_END(p)                                     \
106     if (profiling_packets_enabled && (p)->profile != NULL) {        \
107         (p)->profile->ticks_end = UtilCpuGetTicks();                \
108         SCProfilingAddPacket((p));                                  \
109     }
110 
111 #ifdef PROFILE_LOCKING
112 #define PACKET_PROFILING_RESET_LOCKS do {                           \
113         mutex_lock_cnt = 0;                                         \
114         mutex_lock_wait_ticks = 0;                                  \
115         mutex_lock_contention = 0;                                  \
116         spin_lock_cnt = 0;                                          \
117         spin_lock_wait_ticks = 0;                                   \
118         spin_lock_contention = 0;                                   \
119         rww_lock_cnt = 0;                                           \
120         rww_lock_wait_ticks = 0;                                    \
121         rww_lock_contention = 0;                                    \
122         rwr_lock_cnt = 0;                                           \
123         rwr_lock_wait_ticks = 0;                                    \
124         rwr_lock_contention = 0;                                    \
125         locks_idx = 0;                                              \
126         record_locks = 1;\
127     } while (0)
128 
129 #define PACKET_PROFILING_COPY_LOCKS(p, id) do {                     \
130             (p)->profile->tmm[(id)].mutex_lock_cnt = mutex_lock_cnt;                \
131             (p)->profile->tmm[(id)].mutex_lock_wait_ticks = mutex_lock_wait_ticks;  \
132             (p)->profile->tmm[(id)].mutex_lock_contention = mutex_lock_contention;  \
133             (p)->profile->tmm[(id)].spin_lock_cnt = spin_lock_cnt;                  \
134             (p)->profile->tmm[(id)].spin_lock_wait_ticks = spin_lock_wait_ticks;    \
135             (p)->profile->tmm[(id)].spin_lock_contention = spin_lock_contention;    \
136             (p)->profile->tmm[(id)].rww_lock_cnt = rww_lock_cnt;                    \
137             (p)->profile->tmm[(id)].rww_lock_wait_ticks = rww_lock_wait_ticks;      \
138             (p)->profile->tmm[(id)].rww_lock_contention = rww_lock_contention;      \
139             (p)->profile->tmm[(id)].rwr_lock_cnt = rwr_lock_cnt;                    \
140             (p)->profile->tmm[(id)].rwr_lock_wait_ticks = rwr_lock_wait_ticks;      \
141             (p)->profile->tmm[(id)].rwr_lock_contention = rwr_lock_contention;      \
142         record_locks = 0;                                                           \
143         SCProfilingAddPacketLocks((p));                                             \
144     } while(0)
145 #else
146 #define PACKET_PROFILING_RESET_LOCKS
147 #define PACKET_PROFILING_COPY_LOCKS(p, id)
148 #endif
149 
150 #define PACKET_PROFILING_TMM_START(p, id)                           \
151     if (profiling_packets_enabled && (p)->profile != NULL) {        \
152         if ((id) < TMM_SIZE) {                                      \
153             (p)->profile->tmm[(id)].ticks_start = UtilCpuGetTicks();\
154             PACKET_PROFILING_RESET_LOCKS;                           \
155         }                                                           \
156     }
157 
158 #define PACKET_PROFILING_TMM_END(p, id)                             \
159     if (profiling_packets_enabled && (p)->profile != NULL) {        \
160         if ((id) < TMM_SIZE) {                                      \
161             PACKET_PROFILING_COPY_LOCKS((p), (id));                 \
162             (p)->profile->tmm[(id)].ticks_end = UtilCpuGetTicks();  \
163         }                                                           \
164     }
165 
166 #define FLOWWORKER_PROFILING_START(p, id)                           \
167     if (profiling_packets_enabled && (p)->profile != NULL) {        \
168         if ((id) < PROFILE_FLOWWORKER_SIZE) {                       \
169             (p)->profile->flowworker[(id)].ticks_start = UtilCpuGetTicks();\
170         }                                                           \
171     }
172 
173 #define FLOWWORKER_PROFILING_END(p, id)                             \
174     if (profiling_packets_enabled && (p)->profile != NULL) {        \
175         if ((id) < PROFILE_FLOWWORKER_SIZE) {                       \
176             (p)->profile->flowworker[(id)].ticks_end = UtilCpuGetTicks();  \
177         }                                                           \
178     }
179 
180 #define PACKET_PROFILING_RESET(p)                                   \
181     if (profiling_packets_enabled && (p)->profile != NULL) {        \
182         SCFree((p)->profile);                                       \
183         (p)->profile = NULL;                                        \
184     }
185 
186 #define PACKET_PROFILING_APP_START(dp, id)                          \
187     if (profiling_packets_enabled) {                                \
188         (dp)->ticks_start = UtilCpuGetTicks();                      \
189         (dp)->alproto = (id);                                       \
190     }
191 
192 #define PACKET_PROFILING_APP_END(dp, id)                            \
193     if (profiling_packets_enabled) {                                \
194         BUG_ON((id) != (dp)->alproto);                              \
195         (dp)->ticks_end = UtilCpuGetTicks();                        \
196         if ((dp)->ticks_start != 0 && (dp)->ticks_start < ((dp)->ticks_end)) {  \
197             (dp)->ticks_spent = ((dp)->ticks_end - (dp)->ticks_start);  \
198         }                                                           \
199     }
200 
201 #define PACKET_PROFILING_APP_PD_START(dp)                           \
202     if (profiling_packets_enabled) {                                \
203         (dp)->proto_detect_ticks_start = UtilCpuGetTicks();         \
204     }
205 
206 #define PACKET_PROFILING_APP_PD_END(dp)                             \
207     if (profiling_packets_enabled) {                                \
208         (dp)->proto_detect_ticks_end = UtilCpuGetTicks();           \
209         if ((dp)->proto_detect_ticks_start != 0 && (dp)->proto_detect_ticks_start < ((dp)->proto_detect_ticks_end)) {  \
210             (dp)->proto_detect_ticks_spent =                        \
211                 ((dp)->proto_detect_ticks_end - (dp)->proto_detect_ticks_start);  \
212         }                                                           \
213     }
214 
215 #define PACKET_PROFILING_APP_RESET(dp)                              \
216     if (profiling_packets_enabled) {                                \
217         (dp)->ticks_start = 0;                                      \
218         (dp)->ticks_end = 0;                                        \
219         (dp)->ticks_spent = 0;                                      \
220         (dp)->alproto = 0;                                          \
221         (dp)->proto_detect_ticks_start = 0;                         \
222         (dp)->proto_detect_ticks_end = 0;                           \
223         (dp)->proto_detect_ticks_spent = 0;                         \
224     }
225 
226 #define PACKET_PROFILING_APP_STORE(dp, p)                           \
227     if (profiling_packets_enabled && (p)->profile != NULL) {        \
228         if ((dp)->alproto < ALPROTO_MAX) {                          \
229             (p)->profile->app[(dp)->alproto].ticks_spent += (dp)->ticks_spent;   \
230             (p)->profile->proto_detect += (dp)->proto_detect_ticks_spent;        \
231         }                                                           \
232     }
233 
234 #define PACKET_PROFILING_DETECT_START(p, id)                        \
235     if (profiling_packets_enabled && (p)->profile != NULL) {        \
236         if ((id) < PROF_DETECT_SIZE) {                              \
237             (p)->profile->detect[(id)].ticks_start = UtilCpuGetTicks(); \
238         }                                                           \
239     }
240 
241 #define PACKET_PROFILING_DETECT_END(p, id)                          \
242     if (profiling_packets_enabled  && (p)->profile != NULL) {       \
243         if ((id) < PROF_DETECT_SIZE) {                              \
244             (p)->profile->detect[(id)].ticks_end = UtilCpuGetTicks();\
245             if ((p)->profile->detect[(id)].ticks_start != 0 &&       \
246                     (p)->profile->detect[(id)].ticks_start < (p)->profile->detect[(id)].ticks_end) {  \
247                 (p)->profile->detect[(id)].ticks_spent +=            \
248                 ((p)->profile->detect[(id)].ticks_end - (p)->profile->detect[(id)].ticks_start);  \
249             }                                                       \
250         }                                                           \
251     }
252 
253 #define PACKET_PROFILING_LOGGER_START(p, id)                        \
254     if (profiling_packets_enabled && (p)->profile != NULL) {        \
255         if ((id) < LOGGER_SIZE) {                              \
256             (p)->profile->logger[(id)].ticks_start = UtilCpuGetTicks(); \
257         }                                                           \
258     }
259 
260 #define PACKET_PROFILING_LOGGER_END(p, id)                          \
261     if (profiling_packets_enabled  && (p)->profile != NULL) {       \
262         if ((id) < LOGGER_SIZE) {                              \
263             (p)->profile->logger[(id)].ticks_end = UtilCpuGetTicks();\
264             if ((p)->profile->logger[(id)].ticks_start != 0 &&       \
265                     (p)->profile->logger[(id)].ticks_start < (p)->profile->logger[(id)].ticks_end) {  \
266                 (p)->profile->logger[(id)].ticks_spent +=            \
267                 ((p)->profile->logger[(id)].ticks_end - (p)->profile->logger[(id)].ticks_start);  \
268             }                                                       \
269         }                                                           \
270     }
271 
272 #define SGH_PROFILING_RECORD(det_ctx, sgh)                          \
273     if (profiling_sghs_enabled) {                                   \
274         SCProfilingSghUpdateCounter((det_ctx), (sgh));              \
275     }
276 
277 extern int profiling_prefilter_enabled;
278 extern thread_local int profiling_prefilter_entered;
279 
280 #define PREFILTER_PROFILING_START \
281     uint64_t profile_prefilter_start_ = 0; \
282     uint64_t profile_prefilter_end_ = 0; \
283     if (profiling_prefilter_enabled) { \
284         if (profiling_prefilter_entered > 0) { \
285             SCLogError(SC_ERR_FATAL, "Re-entered profiling, exiting."); \
286             abort(); \
287         } \
288         profiling_prefilter_entered++; \
289         profile_prefilter_start_ = UtilCpuGetTicks(); \
290     }
291 
292 /* we allow this macro to be called if profiling_prefilter_entered == 0,
293  * so that we don't have to refactor some of the detection code. */
294 #define PREFILTER_PROFILING_END(ctx, profile_id) \
295     if (profiling_prefilter_enabled && profiling_prefilter_entered) { \
296         profile_prefilter_end_ = UtilCpuGetTicks(); \
297         if (profile_prefilter_end_ > profile_prefilter_start_) \
298             SCProfilingPrefilterUpdateCounter((ctx),(profile_id),(profile_prefilter_end_ - profile_prefilter_start_)); \
299         profiling_prefilter_entered--; \
300     }
301 
302 void SCProfilingRulesGlobalInit(void);
303 void SCProfilingRuleDestroyCtx(struct SCProfileDetectCtx_ *);
304 void SCProfilingRuleInitCounters(DetectEngineCtx *);
305 void SCProfilingRuleUpdateCounter(DetectEngineThreadCtx *, uint16_t, uint64_t, int);
306 void SCProfilingRuleThreadSetup(struct SCProfileDetectCtx_ *, DetectEngineThreadCtx *);
307 void SCProfilingRuleThreadCleanup(DetectEngineThreadCtx *);
308 
309 void SCProfilingKeywordsGlobalInit(void);
310 void SCProfilingKeywordDestroyCtx(DetectEngineCtx *);//struct SCProfileKeywordDetectCtx_ *);
311 void SCProfilingKeywordInitCounters(DetectEngineCtx *);
312 void SCProfilingKeywordUpdateCounter(DetectEngineThreadCtx *det_ctx, int id, uint64_t ticks, int match);
313 void SCProfilingKeywordThreadSetup(struct SCProfileKeywordDetectCtx_ *, DetectEngineThreadCtx *);
314 void SCProfilingKeywordThreadCleanup(DetectEngineThreadCtx *);
315 
316 struct SCProfilePrefilterDetectCtx_;
317 void SCProfilingPrefilterGlobalInit(void);
318 void SCProfilingPrefilterDestroyCtx(DetectEngineCtx *);
319 void SCProfilingPrefilterInitCounters(DetectEngineCtx *);
320 void SCProfilingPrefilterUpdateCounter(DetectEngineThreadCtx *det_ctx, int id, uint64_t ticks);
321 void SCProfilingPrefilterThreadSetup(struct SCProfilePrefilterDetectCtx_ *, DetectEngineThreadCtx *);
322 void SCProfilingPrefilterThreadCleanup(DetectEngineThreadCtx *);
323 
324 void SCProfilingSghsGlobalInit(void);
325 void SCProfilingSghDestroyCtx(DetectEngineCtx *);
326 void SCProfilingSghInitCounters(DetectEngineCtx *);
327 void SCProfilingSghUpdateCounter(DetectEngineThreadCtx *det_ctx, const SigGroupHead *sgh);
328 void SCProfilingSghThreadSetup(struct SCProfileSghDetectCtx_ *, DetectEngineThreadCtx *);
329 void SCProfilingSghThreadCleanup(DetectEngineThreadCtx *);
330 
331 void SCProfilingInit(void);
332 void SCProfilingDestroy(void);
333 void SCProfilingRegisterTests(void);
334 void SCProfilingDump(void);
335 
336 #else
337 
338 #define RULE_PROFILING_START(p)
339 #define RULE_PROFILING_END(a,b,c,p)
340 
341 #define KEYWORD_PROFILING_SET_LIST(a,b)
342 #define KEYWORD_PROFILING_START
343 #define KEYWORD_PROFILING_END(a,b,c)
344 
345 #define PACKET_PROFILING_START(p)
346 #define PACKET_PROFILING_RESTART(p)
347 #define PACKET_PROFILING_END(p)
348 
349 #define PACKET_PROFILING_TMM_START(p, id)
350 #define PACKET_PROFILING_TMM_END(p, id)
351 
352 #define PACKET_PROFILING_RESET(p)
353 
354 #define PACKET_PROFILING_APP_START(dp, id)
355 #define PACKET_PROFILING_APP_END(dp, id)
356 #define PACKET_PROFILING_APP_RESET(dp)
357 #define PACKET_PROFILING_APP_STORE(dp, p)
358 
359 #define PACKET_PROFILING_APP_PD_START(dp)
360 #define PACKET_PROFILING_APP_PD_END(dp)
361 
362 #define PACKET_PROFILING_DETECT_START(p, id)
363 #define PACKET_PROFILING_DETECT_END(p, id)
364 
365 #define PACKET_PROFILING_LOGGER_START(p, id)
366 #define PACKET_PROFILING_LOGGER_END(p, id)
367 
368 #define SGH_PROFILING_RECORD(det_ctx, sgh)
369 
370 #define FLOWWORKER_PROFILING_START(p, id)
371 #define FLOWWORKER_PROFILING_END(p, id)
372 
373 #define PREFILTER_PROFILING_START
374 #define PREFILTER_PROFILING_END(ctx, profile_id)
375 
376 #endif /* PROFILING */
377 
378 #endif /* ! __UTIL_PROFILE_H__ */
379