aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp/lwtrace/preprocessor.h
blob: 40865467b2984b084944ab593c48e6dc9e15be91 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
#pragma once

#include "check.h"
#include "perf.h"
#include "symbol.h"

#include <util/generic/hide_ptr.h>
#include <util/system/platform.h>

#include <stddef.h> //size_t

#ifdef _win_
#ifndef LWTRACE_DISABLE
#define LWTRACE_DISABLE
#endif // LWTRACE_DISABLE
#endif // _win_

// Maximum number of executors that can be attached to a probe
#define LWTRACE_MAX_ACTIONS 100

// Maximum number of groups that can be assigned to a probe
#define LWTRACE_MAX_GROUPS 100

#ifndef LWTRACE_DISABLE

/*
 *  WARNING: All macros define in this header must be considered as implementation details and should NOT be used directly
 *  WARNING: See lwtrace/all.h for macros that represent a user interface of lwtrace library
 *
 */

// Use for code generation to handle parameter types. USAGE:
// 1. #define FOREACH_PARAMTYPE_MACRO(n, t, v, your_p1, your_p2) your code snippet
// 2. FOREACH_PARAMTYPE(FOREACH_PARAMTYPE_MACRO, your_p1_value, your_p1_value)
//    FOREACH_PARAMTYPE(FOREACH_PARAMTYPE_MACRO, your_p1_another_value, your_p1_another_value)
// 3. #undef FOREACH_PARAMTYPE_MACRO
// Type order matters!
#define FOREACH_PARAMTYPE(MACRO, ...)                         \
    MACRO("i64", i64, I64, ##__VA_ARGS__)                     \
    MACRO("ui64", ui64, Ui64, ##__VA_ARGS__)                  \
    MACRO("double", double, Double, ##__VA_ARGS__)            \
    MACRO("string", TString, Str, ##__VA_ARGS__)              \
    MACRO("symbol", NLWTrace::TSymbol, Symbol, ##__VA_ARGS__) \
    MACRO("check", NLWTrace::TCheck, Check, ##__VA_ARGS__)    \
    /**/

// Used with FOREACH_PARAMTYPE to handle TNil parameter type also
#define FOR_NIL_PARAMTYPE(MACRO, ...)     \
    MACRO(NULL, TNil, Nil, ##__VA_ARGS__) \
    /**/

// Used for math statements
#define FOR_MATH_PARAMTYPE(MACRO, ...)                     \
    MACRO("i64", i64, I64, ##__VA_ARGS__)                  \
    MACRO("ui64", ui64, Ui64, ##__VA_ARGS__)               \
    MACRO("check", NLWTrace::TCheck, Check, ##__VA_ARGS__) \
    /**/

// Use for code generation to handle parameter lists
// NOTE: this is the only place to change if more parameters needed
#define FOREACH_PARAMNUM(MACRO, ...) \
    MACRO(0, ##__VA_ARGS__)          \
    MACRO(1, ##__VA_ARGS__)          \
    MACRO(2, ##__VA_ARGS__)          \
    MACRO(3, ##__VA_ARGS__)          \
    MACRO(4, ##__VA_ARGS__)          \
    MACRO(5, ##__VA_ARGS__)          \
    MACRO(6, ##__VA_ARGS__)          \
    MACRO(7, ##__VA_ARGS__)          \
    MACRO(8, ##__VA_ARGS__)          \
    MACRO(9, ##__VA_ARGS__)          \
    MACRO(10, ##__VA_ARGS__)         \
    MACRO(11, ##__VA_ARGS__)         \
    MACRO(12, ##__VA_ARGS__)         \
    MACRO(13, ##__VA_ARGS__)         \
    MACRO(14, ##__VA_ARGS__)         \
    MACRO(15, ##__VA_ARGS__)         \
    MACRO(16, ##__VA_ARGS__)         \
    /**/

#define FOREACH_LEFT_TYPE(MACRO, ...) \
    MACRO(__VA_ARGS__, OT_VARIABLE)   \
    MACRO(__VA_ARGS__, OT_LITERAL)    \
    MACRO(__VA_ARGS__, OT_PARAMETER)  \
    /**/

#define FOREACH_RIGHT_TYPE(MACRO, ...) \
    MACRO(__VA_ARGS__, OT_VARIABLE)    \
    MACRO(__VA_ARGS__, OT_LITERAL)     \
    MACRO(__VA_ARGS__, OT_PARAMETER)   \
    /**/

#define FOREACH_DESTINATION_TYPE(MACRO, ...) \
    MACRO(__VA_ARGS__, OT_VARIABLE)          \
    /**/

// Auxilary macros
#define LWTRACE_EXPAND(x) x
#define LWTRACE_EAT(...)

// Eat last/first comma trick
#define LWTRACE_COMMA(bit) LWTRACE_COMMA_##bit()
#define LWTRACE_COMMA_0()
#define LWTRACE_COMMA_1() ,

// Macros to pack/unpack tuples, e.g. (x,y,z)
#define LWTRACE_UNROLL(...) __VA_ARGS__
#define LWTRACE_ENROLL(...) (__VA_ARGS__)

// Param types list handling macros
#define LWTRACE_TEMPLATE_PARAMS_I(i) (1) class TP##i = TNil LWTRACE_COMMA
#define LWTRACE_TEMPLATE_PARAMS LWTRACE_EXPAND(LWTRACE_EAT FOREACH_PARAMNUM(LWTRACE_TEMPLATE_PARAMS_I)(0))
#define LWTRACE_TEMPLATE_PARAMS_NODEF_I(i) (1) class TP##i LWTRACE_COMMA
#define LWTRACE_TEMPLATE_PARAMS_NODEF LWTRACE_EXPAND(LWTRACE_EAT FOREACH_PARAMNUM(LWTRACE_TEMPLATE_PARAMS_NODEF_I)(0))
#define LWTRACE_TEMPLATE_ARGS_I(i) (1) TP##i LWTRACE_COMMA
#define LWTRACE_TEMPLATE_ARGS LWTRACE_EXPAND(LWTRACE_EAT FOREACH_PARAMNUM(LWTRACE_TEMPLATE_ARGS_I)(0))
#define LWTRACE_FUNCTION_PARAMS_I(i) (1) typename ::NLWTrace::TParamTraits<TP##i>::TFuncParam p##i = ERROR_not_enough_parameters() LWTRACE_COMMA
#define LWTRACE_FUNCTION_PARAMS LWTRACE_EXPAND(LWTRACE_EAT FOREACH_PARAMNUM(LWTRACE_FUNCTION_PARAMS_I)(0))
#define LWTRACE_PREPARE_PARAMS_I(i, params) params.Param[i].template CopyConstruct<typename ::NLWTrace::TParamTraits<TP##i>::TStoreType>(::NLWTrace::TParamTraits<TP##i>::ToStoreType(p##i));
#define LWTRACE_PREPARE_PARAMS(params)                     \
    do {                                                   \
        FOREACH_PARAMNUM(LWTRACE_PREPARE_PARAMS_I, params) \
    } while (false)
#define LWTRACE_COUNT_PARAMS_I(i) +(std::is_same<TP##i, ::NLWTrace::TNil>::value ? 0 : 1)
#define LWTRACE_COUNT_PARAMS (0 FOREACH_PARAMNUM(LWTRACE_COUNT_PARAMS_I))
#define LWTRACE_MAX_PARAMS_I(i) +1
#define LWTRACE_MAX_PARAMS (0 FOREACH_PARAMNUM(LWTRACE_MAX_PARAMS_I))

// Determine maximum sizeof(t) over all supported types
#define LWTRACE_MAX_PARAM_SIZE_TA_TAIL_I(n, t, v) v,
#define LWTRACE_MAX_PARAM_SIZE_TA_TAIL                  \
    FOREACH_PARAMTYPE(LWTRACE_MAX_PARAM_SIZE_TA_TAIL_I) \
    0
#define LWTRACE_MAX_PARAM_SIZE_TP_I(n, t, v) , size_t v = 0
#define LWTRACE_MAX_PARAM_SIZE_TP size_t Head = 0 FOREACH_PARAMTYPE(LWTRACE_MAX_PARAM_SIZE_TP_I)
#define LWTRACE_MAX_PARAM_SIZE_TA_I(n, t, v) , sizeof(t)
#define LWTRACE_MAX_PARAM_SIZE_TA 0 FOREACH_PARAMTYPE(LWTRACE_MAX_PARAM_SIZE_TA_I)
#define LWTRACE_MAX_PARAM_SIZE ::NLWTrace::TMaxParamSize<LWTRACE_MAX_PARAM_SIZE_TA>::Result

namespace NLWTrace {
    template <LWTRACE_MAX_PARAM_SIZE_TP>
    struct TMaxParamSize {
        static const size_t Tail = TMaxParamSize<LWTRACE_MAX_PARAM_SIZE_TA_TAIL>::Result;
        static const size_t Result = (Head > Tail ? Head : Tail);
    };

    template <>
    struct TMaxParamSize<> {
        static const size_t Result = 0;
    };

}

// Define stuff that is needed to register probes before main()
#define LWTRACE_REGISTER_PROBES(provider)                                                           \
    namespace LWTRACE_GET_NAMESPACE(provider) {                                                     \
        struct TInitLWTrace##provider {                                                             \
            TInitLWTrace##provider() {                                                              \
                Singleton<NLWTrace::TProbeRegistry>()->AddProbesList(LWTRACE_GET_PROBES(provider)); \
            }                                                                                       \
            /* This may not be in anonymous namespace because otherwise */                          \
            /* it is called twice when .so loaded twice */                                          \
        }* InitLWTrace##provider = Singleton<TInitLWTrace##provider>();                             \
    }                                                                                               \
    /**/

// Macro for TSignature POD structure static initialization
#define LWTRACE_SIGNATURE_CTOR(types, names)                                                                          \
    {                                                                                                                 \
        /* ParamTypes */ ::NLWTrace::TUserSignature<LWTRACE_EXPAND(LWTRACE_UNROLL types)>::ParamTypes,                \
            /* ParamNames */ {LWTRACE_EXPAND(LWTRACE_UNROLL names)},                                                  \
            /* ParamCount */ ::NLWTrace::TUserSignature<LWTRACE_EXPAND(LWTRACE_UNROLL types)>::ParamCount,            \
            /* SerializeParams */ &::NLWTrace::TUserSignature<LWTRACE_EXPAND(LWTRACE_UNROLL types)>::SerializeParams, \
            /* CloneParams */ &::NLWTrace::TUserSignature<LWTRACE_EXPAND(LWTRACE_UNROLL types)>::CloneParams,         \
            /* DestroyParams */ &::NLWTrace::TUserSignature<LWTRACE_EXPAND(LWTRACE_UNROLL types)>::DestroyParams,     \
            /* SerializeToPb */ &::NLWTrace::TUserSignature<LWTRACE_EXPAND(LWTRACE_UNROLL types)>::SerializeToPb,     \
            /* DeserializeFromPb */ &::NLWTrace::TUserSignature<LWTRACE_EXPAND(LWTRACE_UNROLL types)>::DeserializeFromPb\
    }

// Macro for TEvent POD structure static initialization
#define LWTRACE_EVENT_CTOR(name, groups, types, names)                   \
    {                                                                    \
        /* Name */ #name,                                                \
            /* Groups */ {LWTRACE_EXPAND(LWTRACE_UNROLL_GROUPS groups)}, \
            /* Signature */ LWTRACE_SIGNATURE_CTOR(types, names)         \
    }

// Macro for TProbe POD structure static initialization
#define LWTRACE_PROBE_CTOR(name, groups, types, names)              \
    {                                                               \
        /* Event */ LWTRACE_EVENT_CTOR(name, groups, types, names), \
            /* ExecutorsCount */ 0,                                 \
            /* Lock */ {0},                                         \
            /* Executors */ {0},                                    \
            /* Front */ 0,                                          \
            /* Back */ 0                                            \
    }

// Provider static data accessors
#define LWTRACE_GET_NAMESPACE(provider) NLWTrace_##provider
#define LWTRACE_GET_NAME(name) lwtrace_##name
#define LWTRACE_GET_TYPE(name) TLWTrace_##name
#define LWTRACE_GET_PROBES_I(provider) gProbes##provider
#define LWTRACE_GET_EVENTS_I(provider) gEvents##provider

// Declaration of provider static data
#define LWTRACE_DECLARE_PROBE(name, groups, types, names)                                        \
    typedef ::NLWTrace::TUserProbe<LWTRACE_EXPAND(LWTRACE_UNROLL types)> LWTRACE_GET_TYPE(name); \
    extern LWTRACE_GET_TYPE(name) LWTRACE_GET_NAME(name);                                        \
    /**/
#define LWTRACE_DECLARE_EVENT(name, groups, types, names)                                        \
    typedef ::NLWTrace::TUserEvent<LWTRACE_EXPAND(LWTRACE_UNROLL types)> LWTRACE_GET_TYPE(name); \
    extern LWTRACE_GET_TYPE(name) LWTRACE_GET_NAME(name);                                        \
    /**/
#define LWTRACE_DECLARE_PROVIDER_I(provider)                                                                   \
    namespace LWTRACE_GET_NAMESPACE(provider) {                                                                \
        provider(LWTRACE_DECLARE_PROBE, LWTRACE_DECLARE_EVENT, LWTRACE_ENROLL, LWTRACE_ENROLL, LWTRACE_ENROLL) \
    }                                                                                                          \
    extern ::NLWTrace::TProbe* LWTRACE_GET_PROBES_I(provider)[];                                               \
    extern ::NLWTrace::TEvent* LWTRACE_GET_EVENTS_I(provider)[];                                               \
    /**/

// Initialization of provider static data
#define LWTRACE_UNROLL_GROUPS(x) #x, LWTRACE_UNROLL
#define LWTRACE_DEFINE_PROBE(name, groups, types, names)  \
    LWTRACE_GET_TYPE(name)                                \
    LWTRACE_GET_NAME(name) =                              \
        {LWTRACE_PROBE_CTOR(name, groups, types, names)}; \
    /**/
#define LWTRACE_DEFINE_EVENT(name, groups, types, names)  \
    LWTRACE_GET_TYPE(name)                                \
    LWTRACE_GET_NAME(name) =                              \
        {LWTRACE_EVENT_CTOR(name, groups, types, names)}; \
    /**/
#define LWTRACE_PROBE_ADDRESS_I(name, groups, types, names) \
    LWTRACE_GET_NAME(name).Probe, /**/
#define LWTRACE_PROBE_ADDRESS(provider) \
    &LWTRACE_GET_NAMESPACE(provider)::LWTRACE_PROBE_ADDRESS_I /**/
#define LWTRACE_EVENT_ADDRESS_I(name, groups, types, names) \
    LWTRACE_GET_NAME(name).Event, /**/
#define LWTRACE_EVENT_ADDRESS(provider) \
    &LWTRACE_GET_NAMESPACE(provider)::LWTRACE_EVENT_ADDRESS_I /**/
#define LWTRACE_DEFINE_PROVIDER_I(provider)                                                                            \
    namespace LWTRACE_GET_NAMESPACE(provider) {                                                                        \
        provider(LWTRACE_DEFINE_PROBE, LWTRACE_DEFINE_EVENT, (provider)LWTRACE_ENROLL, LWTRACE_ENROLL, LWTRACE_ENROLL) \
    }                                                                                                                  \
    ::NLWTrace::TProbe* LWTRACE_GET_PROBES_I(provider)[] = {                                                           \
        provider(LWTRACE_PROBE_ADDRESS(provider), LWTRACE_EAT, LWTRACE_ENROLL, LWTRACE_ENROLL, LWTRACE_ENROLL)         \
            NULL};                                                                                                     \
    ::NLWTrace::TEvent* LWTRACE_GET_EVENTS_I(provider)[] = {                                                           \
        provider(LWTRACE_EAT, LWTRACE_EVENT_ADDRESS(provider), LWTRACE_ENROLL, LWTRACE_ENROLL, LWTRACE_ENROLL)         \
            NULL};                                                                                                     \
    LWTRACE_REGISTER_PROBES(provider)
    /**/

#define LWPROBE_I(probe, ...)                                       \
    do {                                                            \
        if ((probe).Probe.GetExecutorsCount() > 0) {                \
            ::NLWTrace::TScopedThreadCpuTracker _cpuTracker(probe); \
            TReadSpinLockGuard g((probe).Probe.Lock);               \
            if ((probe).Probe.GetExecutorsCount() > 0) {            \
                (probe)(__VA_ARGS__);                               \
            }                                                       \
        }                                                           \
    } while (false) /**/

#define LWPROBE_ENABLED_I(probe) ((probe).Probe.GetExecutorsCount() > 0)

#define LWPROBE_DURATION_I(probetype, uniqid, probe, ...) probetype ::TScopedDuration uniqid(probe, 0 /* fake P0 - used for duration */, ##__VA_ARGS__);

#define LWTRACK_I(probe, orbit, ...)                                    \
    do {                                                                \
        if ((probe).Probe.GetExecutorsCount() > 0) {                    \
            ::NLWTrace::TScopedThreadCpuTracker _cpuTracker(probe);     \
            TReadSpinLockGuard g((probe).Probe.Lock);                   \
            if ((probe).Probe.GetExecutorsCount() > 0) {                \
                (probe).Run(orbit, ##__VA_ARGS__);                      \
            }                                                           \
        } else {                                                        \
            auto& _orbit = (orbit);                                     \
            if (HasShuttles(_orbit)) {                                  \
                ::NLWTrace::TScopedThreadCpuTracker _cpuTracker(probe); \
                (probe).RunShuttles(_orbit, ##__VA_ARGS__);             \
            }                                                           \
        }                                                               \
    } while (false) /**/

#define LWEVENT_I(event, ...) (event)(__VA_ARGS__)

#else
#define LWTRACE_MAX_PARAM_SIZE sizeof(void*)
#define LWTRACE_MAX_PARAMS 1
#define FOREACH_PARAMTYPE(MACRO, ...)

#endif