1/*
2 *  Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
3 *
4 *  Use of this source code is governed by a BSD-style license
5 *  that can be found in the LICENSE file in the root of the source
6 *  tree. An additional intellectual property rights grant can be found
7 *  in the file PATENTS.  All contributing project authors may
8 *  be found in the AUTHORS file in the root of the source tree.
9 */
10
11#ifndef WEBRTC_MODULES_REMOTE_BITRATE_ESTIMATOR_TEST_BWE_TEST_LOGGING_H_
12#define WEBRTC_MODULES_REMOTE_BITRATE_ESTIMATOR_TEST_BWE_TEST_LOGGING_H_
13
14// To enable BWE logging, run this command from trunk/ :
15// build/gyp_chromium --depth=. webrtc/modules/modules.gyp
16//   -Denable_bwe_test_logging=1
17#ifndef BWE_TEST_LOGGING_COMPILE_TIME_ENABLE
18#define BWE_TEST_LOGGING_COMPILE_TIME_ENABLE 0
19#endif  // BWE_TEST_LOGGING_COMPILE_TIME_ENABLE
20
21// BWE logging allows you to insert dynamically named log/plot points in the
22// call tree. E.g. the function:
23//  void f1() {
24//    BWE_TEST_LOGGING_TIME(clock_->TimeInMilliseconds());
25//    BWE_TEST_LOGGING_CONTEXT("stream");
26//    for (uint32_t i=0; i<4; ++i) {
27//      BWE_TEST_LOGGING_ENABLE(i & 1);
28//      BWE_TEST_LOGGING_CONTEXT(i);
29//      BWE_TEST_LOGGING_LOG1("weight", "%f tonnes", weights_[i]);
30//      for (float j=0.0f; j<1.0; j+=0.4f) {
31//        BWE_TEST_LOGGING_PLOT("bps", -1, j);
32//      }
33//    }
34//  }
35//
36// Might produce the output:
37//   stream_00000001_weight 13.000000 tonnes
38//   PLOT  stream_00000001_bps  1.000000  0.000000
39//   PLOT  stream_00000001_bps  1.000000  0.400000
40//   PLOT  stream_00000001_bps  1.000000  0.800000
41//   stream_00000003_weight 39.000000 tonnes
42//   PLOT  stream_00000003_bps  1.000000  0.000000
43//   PLOT  stream_00000003_bps  1.000000  0.400000
44//   PLOT  stream_00000003_bps  1.000000  0.800000
45//
46// Log *contexts* are names concatenated with '_' between them, with the name
47// of the logged/plotted string/value last. Plot *time* is inherited down the
48// tree. A branch is enabled by default but can be *disabled* to reduce output.
49// The difference between the LOG and PLOT macros is that PLOT prefixes the line
50// so it can be easily filtered, plus it outputs the current time.
51
52#if !(BWE_TEST_LOGGING_COMPILE_TIME_ENABLE)
53
54// Set a thread-global base logging context. This name will be prepended to all
55// hierarchical contexts.
56// |name| is a char*, std::string or uint32_t to name the context.
57#define BWE_TEST_LOGGING_GLOBAL_CONTEXT(name)
58
59// Thread-globally allow/disallow logging.
60// |enable| is expected to be a bool.
61#define BWE_TEST_LOGGING_GLOBAL_ENABLE(enabled)
62
63// Insert a (hierarchical) logging context.
64// |name| is a char*, std::string or uint32_t to name the context.
65#define BWE_TEST_LOGGING_CONTEXT(name)
66
67// Allow/disallow logging down the call tree from this point. Logging must be
68// enabled all the way to the root of the call tree to take place.
69// |enable| is expected to be a bool.
70#define BWE_TEST_LOGGING_ENABLE(enabled)
71
72// Set current time (only affects PLOT output). Down the call tree, the latest
73// time set always takes precedence.
74// |time| is an int64_t time in ms, or -1 to inherit time from previous context.
75#define BWE_TEST_LOGGING_TIME(time)
76
77// Print to stdout, e.g.:
78//   Context1_Context2_Name  printf-formated-string
79// |name| is a char*, std::string or uint32_t to name the log line.
80// |format| is a printf format string.
81// |_1...| are arguments for printf.
82#define BWE_TEST_LOGGING_LOG1(name, format, _1)
83#define BWE_TEST_LOGGING_LOG2(name, format, _1, _2)
84#define BWE_TEST_LOGGING_LOG3(name, format, _1, _2, _3)
85#define BWE_TEST_LOGGING_LOG4(name, format, _1, _2, _3, _4)
86#define BWE_TEST_LOGGING_LOG5(name, format, _1, _2, _3, _4, _5)
87
88// Print to stdout in tab-separated format suitable for plotting, e.g.:
89//   PLOT  Context1_Context2_Name  time  value
90// |name| is a char*, std::string or uint32_t to name the plotted value.
91// |time| is an int64_t time in ms, or -1 to inherit time from previous context.
92// |value| is a double precision float to be plotted.
93#define BWE_TEST_LOGGING_PLOT(name, time, value)
94
95#else  // BWE_TEST_LOGGING_COMPILE_TIME_ENABLE
96
97#include <map>
98#include <stack>
99#include <string>
100
101#include "webrtc/base/constructormagic.h"
102#include "webrtc/common_types.h"
103#include "webrtc/system_wrappers/interface/scoped_ptr.h"
104
105#define BWE_TEST_LOGGING_GLOBAL_CONTEXT(name) \
106    do { \
107      webrtc::testing::bwe::Logging::GetInstance()->SetGlobalContext(name); \
108    } while (0);
109
110#define BWE_TEST_LOGGING_GLOBAL_ENABLE(enabled) \
111    do { \
112      webrtc::testing::bwe::Logging::GetInstance()->SetGlobalEnable(enabled); \
113    } while (0);
114
115#define __BWE_TEST_LOGGING_CONTEXT_NAME(ctx, line) ctx ## line
116#define __BWE_TEST_LOGGING_CONTEXT_DECLARE(ctx, line, name, time, enabled) \
117    webrtc::testing::bwe::Logging::Context \
118        __BWE_TEST_LOGGING_CONTEXT_NAME(ctx, line)(name, time, enabled)
119
120#define BWE_TEST_LOGGING_CONTEXT(name) \
121    __BWE_TEST_LOGGING_CONTEXT_DECLARE(__bwe_log_, __LINE__, name, -1, true)
122#define BWE_TEST_LOGGING_ENABLE(enabled) \
123    __BWE_TEST_LOGGING_CONTEXT_DECLARE(__bwe_log_, __LINE__, "", -1, \
124                                       static_cast<bool>(enabled))
125#define BWE_TEST_LOGGING_TIME(time) \
126    __BWE_TEST_LOGGING_CONTEXT_DECLARE(__bwe_log_, __LINE__, "", \
127                                       static_cast<int64_t>(time), true)
128
129#define BWE_TEST_LOGGING_LOG1(name, format, _1) \
130    do { \
131      BWE_TEST_LOGGING_CONTEXT(name); \
132      webrtc::testing::bwe::Logging::GetInstance()->Log(format, _1); \
133    } while (0);
134#define BWE_TEST_LOGGING_LOG2(name, format, _1, _2) \
135    do { \
136      BWE_TEST_LOGGING_CONTEXT(name); \
137      webrtc::testing::bwe::Logging::GetInstance()->Log(format, _1, _2); \
138    } while (0);
139#define BWE_TEST_LOGGING_LOG3(name, format, _1, _2, _3) \
140    do { \
141      BWE_TEST_LOGGING_CONTEXT(name); \
142      webrtc::testing::bwe::Logging::GetInstance()->Log(format, _1, _2, _3); \
143    } while (0);
144#define BWE_TEST_LOGGING_LOG4(name, format, _1, _2, _3, _4) \
145    do { \
146      BWE_TEST_LOGGING_CONTEXT(name); \
147      webrtc::testing::bwe::Logging::GetInstance()->Log(format, _1, _2, _3, \
148                                                        _4); \
149    } while (0);
150#define BWE_TEST_LOGGING_LOG5(name, format, _1, _2, _3, _4, _5) \
151    do {\
152      BWE_TEST_LOGGING_CONTEXT(name); \
153      webrtc::testing::bwe::Logging::GetInstance()->Log(format, _1, _2, _3, \
154                                                        _4, _5); \
155    } while (0);
156
157#define BWE_TEST_LOGGING_PLOT(name, time, value)\
158    do { \
159      __BWE_TEST_LOGGING_CONTEXT_DECLARE(__bwe_log_, __LINE__, name, \
160                                         static_cast<int64_t>(time), true); \
161      webrtc::testing::bwe::Logging::GetInstance()->Plot(value); \
162    } while (0);
163
164namespace webrtc {
165
166class CriticalSectionWrapper;
167
168namespace testing {
169namespace bwe {
170
171class Logging {
172 public:
173  class Context {
174   public:
175    Context(uint32_t name, int64_t timestamp_ms, bool enabled);
176    Context(const std::string& name, int64_t timestamp_ms, bool enabled);
177    Context(const char* name, int64_t timestamp_ms, bool enabled);
178    ~Context();
179   private:
180    DISALLOW_IMPLICIT_CONSTRUCTORS(Context);
181  };
182
183  static Logging* GetInstance();
184
185  void SetGlobalContext(uint32_t name);
186  void SetGlobalContext(const std::string& name);
187  void SetGlobalContext(const char* name);
188  void SetGlobalEnable(bool enabled);
189
190  void Log(const char format[], ...);
191  void Plot(double value);
192
193 private:
194  struct State {
195    State();
196    State(const std::string& new_tag, int64_t timestamp_ms, bool enabled);
197    void MergePrevious(const State& previous);
198
199    std::string tag;
200    int64_t timestamp_ms;
201    bool enabled;
202  };
203  struct ThreadState {
204    State global_state;
205    std::stack<State> stack;
206  };
207  typedef std::map<uint32_t, ThreadState> ThreadMap;
208
209  Logging();
210  void PushState(const std::string& append_to_tag, int64_t timestamp_ms,
211                 bool enabled);
212  void PopState();
213
214  static Logging g_Logging;
215  scoped_ptr<CriticalSectionWrapper> crit_sect_;
216  ThreadMap thread_map_;
217
218  DISALLOW_COPY_AND_ASSIGN(Logging);
219};
220}  // namespace bwe
221}  // namespace testing
222}  // namespace webrtc
223
224#endif  // BWE_TEST_LOGGING_COMPILE_TIME_ENABLE
225#endif  // WEBRTC_MODULES_REMOTE_BITRATE_ESTIMATOR_TEST_BWE_TEST_LOGGING_H_
226