| // Copyright 2015 Google Inc. All Rights Reserved. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #ifndef COBALT_TRACE_EVENT_EVENT_PARSER_H_ |
| #define COBALT_TRACE_EVENT_EVENT_PARSER_H_ |
| |
| #include <set> |
| #include <vector> |
| |
| #include "base/debug/trace_event.h" |
| #include "base/debug/trace_event_impl.h" |
| #include "base/memory/ref_counted.h" |
| #include "base/optional.h" |
| #include "base/time.h" |
| |
| namespace cobalt { |
| namespace trace_event { |
| |
| // EventParser is a class responsible for parsing raw base::debug::TraceLog |
| // trace events generated by calls to tracing functions found in trace_event.h. |
| // Example tracing calls include TRACE_EVENT0 and TRACE_EVENT_FLOW_BEGIN0. |
| // It parses raw sequences of base::debug::TraceEvent structures into |
| // high level event trees. |
| // This class will interpret the incoming log data and, as it becomes able to, |
| // will in turn fire its own higher level events such as when an event flow |
| // has ended. This is useful because it compiles all data for flow structures |
| // as it reads the individual raw trace events and only provides it to the |
| // client when entire flows have completed and all relevant information about |
| // them is available and nicely organized. |
| // Using this trace log parse to re-create the program flow structure |
| // makes it much easier to write code that analyzes timing and execution results |
| // available in the trace log. |
| // EventParser can link TRACE_EVENTs across TRACE_EVENT_FLOWs, allowing entire |
| // processing pipelines that span multiple thread boundaries to be linked |
| // together automatically. |
| class EventParser { |
| public: |
| // A ScopedEvent represents some Chromium tracing event that has a duration. |
| // This includes standard TRACE_EVENTs which are scoped and thus have a |
| // beginning and end. It also includes TRACE_EVENT_FLOWs, which necessarily |
| // have an associated beginning and end. |
| class ScopedEvent : public base::RefCountedThreadSafe<ScopedEvent> { |
| public: |
| ScopedEvent(const scoped_refptr<ScopedEvent>& parent, |
| const base::debug::TraceEvent& begin_event, |
| EventParser* event_parser); |
| |
| // Shortcut method to retrieve the event name. This should be the same |
| // amongst begin_event(), end_event() and all instant_events(). |
| const std::string name() const { return begin_event().name(); } |
| |
| // Convenience method for returning the duration of this event's entire |
| // flow. This value may not exist if the trace was terminated before the |
| // end of the scoped event's flow occurs. |
| base::optional<base::TimeDelta> flow_duration() const { |
| if (end_flow_time()) { |
| return *end_flow_time() - begin_event().timestamp(); |
| } else { |
| return base::nullopt; |
| } |
| } |
| |
| // Convenience method for returning the duration of this event's scope. |
| // This value may not exist if the trace was terminated before the |
| // scoped event's end occurs. |
| base::optional<base::TimeDelta> in_scope_duration() const { |
| if (end_event()) { |
| return end_event()->timestamp() - begin_event().timestamp(); |
| } else { |
| return base::nullopt; |
| } |
| } |
| |
| // Returns the event's parent scope. Informally, this is the scope that |
| // was responsible for producing this scope. |
| const scoped_refptr<ScopedEvent>& parent() const { return parent_; } |
| |
| // Return a list of the event's child events. Informally, these are the |
| // events that were produced by this event. |
| const std::vector<scoped_refptr<ScopedEvent> > children() const { |
| return children_; |
| } |
| |
| // Returns the Chromium TraceEvent structure associated with the beginning |
| // of this scoped event (e.g. since the event is scoped, it has a beginning |
| // and end). |
| const base::debug::TraceEvent& begin_event() const { return begin_event_; } |
| |
| // Returns the Chromium TraceEvent structure associated with the end of this |
| // scoped event. If the scoped event has not finished yet, this will return |
| // nullopt. |
| const base::optional<base::debug::TraceEvent>& end_event() const { |
| return end_event_; |
| } |
| |
| // Return a list of instant events that are effectively children of this |
| // scoped event. For example, all TRACE_EVENT_FLOW_STEP calls will attach |
| // the generated TraceEvent structure as an instant event to the |
| // corresponding flow ScopedEvent. |
| const std::vector<base::debug::TraceEvent> instant_events() const { |
| return instant_events_; |
| } |
| |
| // The end flow time is the time when the last of this ScopedEvent's |
| // descendants has ended. This can be much later than the ScopedEvent's |
| // local end time. An example where the end flow time is different from |
| // the end time is if within a TRACE_EVENT, a TRACE_EVENT_FLOW is started |
| // and the TRACE_EVENT_FLOW ends *after* the TRACE_EVENT ends. In this |
| // case, the TRACE_EVENT's end flow time is equal to the TRACE_EVENT_FLOW's |
| // end time, assuming the TRACE_EVENT_FLOW did not spawn any children of its |
| // own that could extend the TRACE_EVENT's end flow time even longer. |
| const base::optional<base::TimeTicks>& end_flow_time() const { |
| return end_flow_time_; |
| } |
| |
| // Returns the latest generated Chromium TraceEvent we've seen so far. |
| // This will return end_event if it exists, otherwise the latest |
| // instant_event, otherwise the begin_event. |
| const base::debug::TraceEvent& LastTraceEvent() const; |
| |
| // The state is used to keep track of what state the ScopedEvent is in. |
| // ScopedEvents may persist for much longer after they have been ended. |
| // Newly started event scopes will begin life in the kState_Active state. |
| enum State { |
| // kState_Active means that the ScopedEvent has not yet received a |
| // end signal (e.g. TRACE_EVENT_FLOW_BEGIN is not yet matched with |
| // TRACE_EVENT_FLOW_END). |
| kActiveState, |
| // kState_Ended means that the ScopedEvent has received an end signal, |
| // but it still has descendants that have not received their end signal |
| // and thus the end flow time for this ScopedEvent is not currently |
| // available. |
| kEndedState, |
| // kState_EndedAndLastTouched exists to handle a bit of a special case |
| // where a TRACE_EVENT_FLOW is ended, and it has no children, but |
| // since it can potentially be linked as a parent to a subsequent |
| // TRACE_EVENT call (e.g. as is done in MessageLoop::RunTask), it should |
| // not be marked as having its flow ended yet. Being "last touched" |
| // means that this event was last on a thread to be modified on any |
| // thread (e.g. started, stepped or ended). |
| kEndedAndLastTouchedState, |
| // kState_FlowEnded indicates that this ScopedEvent and all its |
| // descendants have ended their flows, and the state of the event will |
| // no longer be changing. |
| kFlowEndedState, |
| // kState_Aborted indicates that the ScopedEvent did not end properly |
| // and was instead aborted prematurely. Not all fields (like end_event) |
| // may be available, but the object will no longer be changing. |
| kAbortedState, |
| }; |
| State state() const { return state_; } |
| |
| private: |
| virtual ~ScopedEvent(); |
| friend class base::RefCountedThreadSafe<ScopedEvent>; |
| |
| // Many of these methods will be called by EventParser in response to event |
| // processing. |
| void OnEnd(const base::debug::TraceEvent& end_event); |
| void OnEndFlow(const base::TimeTicks& timestamp); |
| bool AreEndFlowConditionsMet() const; |
| void AddInstantEvent(const base::debug::TraceEvent& event); |
| void OnNotLastTouched(); |
| void Abort(); |
| |
| // Returns a set of all leaf nodes in the event tree rooted at this |
| // ScopedEvent node. If this node is a leaf node, the returned set |
| // will contain this node as the single item. |
| std::set<scoped_refptr<ScopedEvent> > GetLeafEvents(); |
| |
| scoped_refptr<ScopedEvent> parent_; |
| std::vector<scoped_refptr<ScopedEvent> > children_; |
| |
| base::debug::TraceEvent begin_event_; |
| base::optional<base::debug::TraceEvent> end_event_; |
| base::optional<base::TimeTicks> end_flow_time_; |
| |
| std::vector<base::debug::TraceEvent> instant_events_; |
| |
| // How many of our children have flows that have not ended yet? If this |
| // is non-zero, then our flow cannot yet be ended. |
| int flow_active_children_; |
| |
| State state_; |
| |
| // The parent event parser this ScopedEvent is apart of. |
| EventParser* event_parser_; |
| |
| friend class EventParser; |
| }; |
| |
| typedef base::Callback<void(const scoped_refptr<ScopedEvent>& event)> |
| ScopedEventFlowEndCallback; |
| |
| // The passed in scoped_event_flow_end_callback will be run every time we |
| // encounter a ScopedEvent whose flow has ended (e.g. the event is over and |
| // so are all its descendants). It is important to realize that an event's |
| // "flow end" is different from the end of the event's scope. For example, |
| // if a TRACE_EVENT posts a message to a message loop, and then the |
| // TRACE_EVENT goes out of scope, the event's scope has ended but its flow |
| // has not. The flow will only end when the posted message is processed |
| // and that message did not post any messages of its own to extend the flow |
| // farther. |
| explicit EventParser( |
| const ScopedEventFlowEndCallback& scoped_event_flow_end_callback); |
| ~EventParser(); |
| |
| // This is the function that drives the event parser. As raw events are fed |
| // to EventParser from base::debug::TraceLog, the event parser is updated and |
| // may produce its own higher level events. |
| void ParseEvent(const base::debug::TraceEvent& event); |
| |
| private: |
| // Used to keep track of information local to specific threads, such as |
| // which events are currently on the stack for that thread, and what the last |
| // event touched on that thread was. |
| struct ThreadInfo { |
| std::vector<scoped_refptr<ScopedEvent> > event_stack_; |
| scoped_refptr<ScopedEvent> last_touched_event_; |
| }; |
| |
| void UpdateLastTouchedEvent(ThreadInfo* thread_info, |
| const scoped_refptr<ScopedEvent>& event); |
| |
| std::set<scoped_refptr<ScopedEvent> > GetLeafEvents(); |
| |
| friend class ScopedEvent; |
| |
| ScopedEventFlowEndCallback scoped_event_flow_end_callback_; |
| |
| typedef base::hash_map<int, ThreadInfo> ThreadMap; |
| ThreadMap thread_id_to_info_map_; |
| |
| // Keep a mapping of all active flow events (which may span multiple threads) |
| // for easy lookup if we need to process a flow event. |
| typedef base::hash_map<uint64_t, scoped_refptr<ScopedEvent> > FlowEventMap; |
| FlowEventMap flow_id_to_event_map_; |
| }; |
| |
| } // namespace trace_event |
| } // namespace cobalt |
| |
| #endif // COBALT_TRACE_EVENT_EVENT_PARSER_H_ |