1/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2/*
3 *     Copyright 2016 Couchbase, Inc
4 *
5 *   Licensed under the Apache License, Version 2.0 (the "License");
6 *   you may not use this file except in compliance with the License.
7 *   You may obtain a copy of the License at
8 *
9 *       http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *   Unless required by applicable law or agreed to in writing, software
12 *   distributed under the License is distributed on an "AS IS" BASIS,
13 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *   See the License for the specific language governing permissions and
15 *   limitations under the License.
16 */
17/** \file
18 * This file is internal to the inner workings of
19 * Phosphor and is not intended for public consumption.
20 */
21
22#include <atomic>
23
24/*
25 * Generates a variable name that will be unique per-line for the given prefix
26 */
27#define PHOSPHOR_INTERNAL_UID3(a, b) \
28    phosphor_internal_ ##a##_##b
29
30#define PHOSPHOR_INTERNAL_UID2(a, b) \
31    PHOSPHOR_INTERNAL_UID3(a, b)
32
33#define PHOSPHOR_INTERNAL_UID(prefix) \
34    PHOSPHOR_INTERNAL_UID2(prefix, __LINE__)
35
36/*
37 * Sets up the category status variables
38 *
39 * This makes a slight optimisation by storing the result of loading
40 * category_enabled into category_enabled_temp which saves a second
41 * load in the calling macro.
42 */
43#define PHOSPHOR_INTERNAL_CATEGORY_INFO                                      \
44    static std::atomic<const phosphor::AtomicCategoryStatus*>                \
45            PHOSPHOR_INTERNAL_UID(category_enabled);                         \
46    const phosphor::AtomicCategoryStatus* PHOSPHOR_INTERNAL_UID(             \
47            category_enabled_temp) = PHOSPHOR_INTERNAL_UID(category_enabled) \
48                                             .load(std::memory_order_acquire);
49
50#define PHOSPHOR_INTERNAL_INITIALIZE_TPI(tpi_name, category, name, argA, argB) \
51    constexpr static phosphor::tracepoint_info PHOSPHOR_INTERNAL_UID(          \
52            tpi_name) = {category, name, {{argA, argB}}};
53
54#define PHOSPHOR_INTERNAL_INITIALIZE_TRACEPOINT(category, name, argA, argB) \
55    PHOSPHOR_INTERNAL_INITIALIZE_TPI(tpi, category, name, argA, argB);      \
56    PHOSPHOR_INTERNAL_INITIALIZE_CATEGORY_ENABLED(category)
57
58#define PHOSPHOR_INTERNAL_INITIALIZE_CATEGORY_ENABLED(category)      \
59    if (unlikely(!PHOSPHOR_INTERNAL_UID(category_enabled_temp))) {   \
60        PHOSPHOR_INTERNAL_UID(category_enabled_temp) =               \
61                &PHOSPHOR_INSTANCE.getCategoryStatus(category);      \
62        PHOSPHOR_INTERNAL_UID(category_enabled)                      \
63                .store(PHOSPHOR_INTERNAL_UID(category_enabled_temp), \
64                       std::memory_order_release);                   \
65    }
66
67/*
68 * Traces an event of a specified type with one or more arguments
69 *
70 * This compares '!=' to disabled instead of '==' to enabled as it allows
71 * for comparison to 0 rather than comparison to 1 which saves an instruction
72 * on the disabled path when compiled.
73 */
74#define PHOSPHOR_INTERNAL_TRACE_EVENT(category, name, argA, argB, type, ...) \
75    PHOSPHOR_INTERNAL_CATEGORY_INFO \
76    PHOSPHOR_INTERNAL_INITIALIZE_TRACEPOINT(category, name, argA, argB) \
77    if (PHOSPHOR_INTERNAL_UID(category_enabled_temp)->load(std::memory_order_acquire) \
78          != phosphor::CategoryStatus::Disabled) { \
79        PHOSPHOR_INSTANCE.logEvent(&PHOSPHOR_INTERNAL_UID(tpi), type, __VA_ARGS__); \
80    }
81
82/*
83 * Traces an event of a specified type with zero arguments
84 */
85#define PHOSPHOR_INTERNAL_TRACE_EVENT0(category, name, type) \
86    PHOSPHOR_INTERNAL_CATEGORY_INFO \
87    PHOSPHOR_INTERNAL_INITIALIZE_TRACEPOINT(category, name, "arg1", "arg2") \
88    if (PHOSPHOR_INTERNAL_UID(category_enabled_temp)->load(std::memory_order_relaxed) \
89          != phosphor::CategoryStatus::Disabled) { \
90        PHOSPHOR_INSTANCE.logEvent(&PHOSPHOR_INTERNAL_UID(tpi), type); \
91    }
92
93/*
94 * For when additional trace events are created in the same scope.
95 * Therefore the tpi name must be made unique i.e. second_tpi, third_tpi.
96 * Note PHOSPHOR_INTERNAL_CATEGORY_INFO need not be called as the
97 * category_enabled and category_enabled_temp are defined when creating the
98 * first trace event.
99 */
100#define PHOSPHOR_INTERNAL_ADDITIONAL_TRACE_EVENT0(tpi_name, category, name, type) \
101    PHOSPHOR_INTERNAL_INITIALIZE_TPI(tpi_name, category, name, "arg1", "arg2") \
102    if (PHOSPHOR_INTERNAL_UID(category_enabled_temp)->load(std::memory_order_relaxed) \
103          != phosphor::CategoryStatus::Disabled) { \
104        PHOSPHOR_INSTANCE.logEvent(&PHOSPHOR_INTERNAL_UID(tpi_name), type); \
105    }
106