• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #ifndef SRC_TRACING_AGENT_H_
2 #define SRC_TRACING_AGENT_H_
3 
4 #include "libplatform/v8-tracing.h"
5 #include "uv.h"
6 #include "util.h"
7 #include "node_mutex.h"
8 
9 #include <list>
10 #include <set>
11 #include <string>
12 #include <unordered_map>
13 
14 namespace v8 {
15 class ConvertableToTraceFormat;
16 class TracingController;
17 }  // namespace v8
18 
19 namespace node {
20 namespace tracing {
21 
22 using v8::platform::tracing::TraceConfig;
23 using v8::platform::tracing::TraceObject;
24 
25 class Agent;
26 
27 class AsyncTraceWriter {
28  public:
29   virtual ~AsyncTraceWriter() = default;
30   virtual void AppendTraceEvent(TraceObject* trace_event) = 0;
31   virtual void Flush(bool blocking) = 0;
InitializeOnThread(uv_loop_t * loop)32   virtual void InitializeOnThread(uv_loop_t* loop) {}
33 };
34 
35 class TracingController : public v8::platform::tracing::TracingController {
36  public:
TracingController()37   TracingController() : v8::platform::tracing::TracingController() {}
38 
CurrentTimestampMicroseconds()39   int64_t CurrentTimestampMicroseconds() override {
40     return uv_hrtime() / 1000;
41   }
42   void AddMetadataEvent(
43       const unsigned char* category_group_enabled,
44       const char* name,
45       int num_args,
46       const char** arg_names,
47       const unsigned char* arg_types,
48       const uint64_t* arg_values,
49       std::unique_ptr<v8::ConvertableToTraceFormat>* convertable_values,
50       unsigned int flags);
51 };
52 
53 class AgentWriterHandle {
54  public:
55   inline AgentWriterHandle() = default;
~AgentWriterHandle()56   inline ~AgentWriterHandle() { reset(); }
57 
58   inline AgentWriterHandle(AgentWriterHandle&& other);
59   inline AgentWriterHandle& operator=(AgentWriterHandle&& other);
empty()60   inline bool empty() const { return agent_ == nullptr; }
61   inline void reset();
62 
63   inline void Enable(const std::set<std::string>& categories);
64   inline void Disable(const std::set<std::string>& categories);
65 
66   inline bool IsDefaultHandle();
67 
agent()68   inline Agent* agent() { return agent_; }
69 
70   inline v8::TracingController* GetTracingController();
71 
72   AgentWriterHandle(const AgentWriterHandle& other) = delete;
73   AgentWriterHandle& operator=(const AgentWriterHandle& other) = delete;
74 
75  private:
AgentWriterHandle(Agent * agent,int id)76   inline AgentWriterHandle(Agent* agent, int id) : agent_(agent), id_(id) {}
77 
78   Agent* agent_ = nullptr;
79   int id_;
80 
81   friend class Agent;
82 };
83 
84 class Agent {
85  public:
86   Agent();
87   ~Agent();
88 
GetTracingController()89   TracingController* GetTracingController() {
90     TracingController* controller = tracing_controller_.get();
91     CHECK_NOT_NULL(controller);
92     return controller;
93   }
94 
95   enum UseDefaultCategoryMode {
96     kUseDefaultCategories,
97     kIgnoreDefaultCategories
98   };
99 
100   // Destroying the handle disconnects the client
101   AgentWriterHandle AddClient(const std::set<std::string>& categories,
102                               std::unique_ptr<AsyncTraceWriter> writer,
103                               enum UseDefaultCategoryMode mode);
104   // A handle that is only used for managing the default categories
105   // (which can then implicitly be used through using `USE_DEFAULT_CATEGORIES`
106   // when adding a client later).
107   AgentWriterHandle DefaultHandle();
108 
109   // Returns a comma-separated list of enabled categories.
110   std::string GetEnabledCategories() const;
111 
112   // Writes to all writers registered through AddClient().
113   void AppendTraceEvent(TraceObject* trace_event);
114 
115   void AddMetadataEvent(std::unique_ptr<TraceObject> event);
116   // Flushes all writers registered through AddClient().
117   void Flush(bool blocking);
118 
119   TraceConfig* CreateTraceConfig() const;
120 
121  private:
122   friend class AgentWriterHandle;
123 
124   void InitializeWritersOnThread();
125 
126   void Start();
127   void StopTracing();
128   void Disconnect(int client);
129 
130   void Enable(int id, const std::set<std::string>& categories);
131   void Disable(int id, const std::set<std::string>& categories);
132 
133   uv_thread_t thread_;
134   uv_loop_t tracing_loop_;
135 
136   bool started_ = false;
137   class ScopedSuspendTracing;
138 
139   // Each individual Writer has one id.
140   int next_writer_id_ = 1;
141   enum { kDefaultHandleId = -1 };
142   // These maps store the original arguments to AddClient(), by id.
143   std::unordered_map<int, std::multiset<std::string>> categories_;
144   std::unordered_map<int, std::unique_ptr<AsyncTraceWriter>> writers_;
145   std::unique_ptr<TracingController> tracing_controller_;
146 
147   // Variables related to initializing per-event-loop properties of individual
148   // writers, such as libuv handles.
149   Mutex initialize_writer_mutex_;
150   ConditionVariable initialize_writer_condvar_;
151   uv_async_t initialize_writer_async_;
152   std::set<AsyncTraceWriter*> to_be_initialized_;
153 
154   Mutex metadata_events_mutex_;
155   std::list<std::unique_ptr<TraceObject>> metadata_events_;
156 };
157 
reset()158 void AgentWriterHandle::reset() {
159   if (agent_ != nullptr)
160     agent_->Disconnect(id_);
161   agent_ = nullptr;
162 }
163 
164 AgentWriterHandle& AgentWriterHandle::operator=(AgentWriterHandle&& other) {
165   reset();
166   agent_ = other.agent_;
167   id_ = other.id_;
168   other.agent_ = nullptr;
169   return *this;
170 }
171 
AgentWriterHandle(AgentWriterHandle && other)172 AgentWriterHandle::AgentWriterHandle(AgentWriterHandle&& other) {
173   *this = std::move(other);
174 }
175 
Enable(const std::set<std::string> & categories)176 void AgentWriterHandle::Enable(const std::set<std::string>& categories) {
177   if (agent_ != nullptr) agent_->Enable(id_, categories);
178 }
179 
Disable(const std::set<std::string> & categories)180 void AgentWriterHandle::Disable(const std::set<std::string>& categories) {
181   if (agent_ != nullptr) agent_->Disable(id_, categories);
182 }
183 
IsDefaultHandle()184 bool AgentWriterHandle::IsDefaultHandle() {
185   return agent_ != nullptr && id_ == Agent::kDefaultHandleId;
186 }
187 
GetTracingController()188 inline v8::TracingController* AgentWriterHandle::GetTracingController() {
189   return agent_ != nullptr ? agent_->GetTracingController() : nullptr;
190 }
191 
192 }  // namespace tracing
193 }  // namespace node
194 
195 #endif  // SRC_TRACING_AGENT_H_
196