// Copyright 2012 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Use trace_analyzer::Query and trace_analyzer::TraceAnalyzer to search for // specific trace events that were generated by the trace_event.h API. // // Basic procedure: // - Get trace events JSON string from base::trace_event::TraceLog. // - Create TraceAnalyzer with JSON string. // - Call TraceAnalyzer::AssociateBeginEndEvents (optional). // - Call TraceAnalyzer::AssociateEvents (zero or more times). // - Call TraceAnalyzer::FindEvents with queries to find specific events. // // A Query is a boolean expression tree that evaluates to true or false for a // given trace event. Queries can be combined into a tree using boolean, // arithmetic and comparison operators that refer to data of an individual trace // event. // // The events are returned as trace_analyzer::TraceEvent objects. // TraceEvent contains a single trace event's data, as well as a pointer to // a related trace event. The related trace event is typically the matching end // of a begin event or the matching begin of an end event. // // The following examples use this basic setup code to construct TraceAnalyzer // with the json trace string retrieved from TraceLog and construct an event // vector for retrieving events: // // TraceAnalyzer analyzer(json_events); // TraceEventVector events; // // EXAMPLE 1: Find events named "my_event". // // analyzer.FindEvents(Query(EVENT_NAME) == "my_event", &events); // // EXAMPLE 2: Find begin events named "my_event" with duration > 1 second. // // Query q = (Query(EVENT_NAME) == Query::String("my_event") && // Query(EVENT_PHASE) == Query::Phase(TRACE_EVENT_PHASE_BEGIN) && // Query(EVENT_DURATION) > Query::Double(1000000.0)); // analyzer.FindEvents(q, &events); // // EXAMPLE 3: Associating event pairs across threads. // // If the test needs to analyze something that starts and ends on different // threads, the test needs to use INSTANT events. The typical procedure is to // specify the same unique ID as a TRACE_EVENT argument on both the start and // finish INSTANT events. Then use the following procedure to associate those // events. // // Step 1: instrument code with custom begin/end trace events. // [Thread 1 tracing code] // TRACE_EVENT_INSTANT1("test_latency", "timing1_begin", "id", 3); // [Thread 2 tracing code] // TRACE_EVENT_INSTANT1("test_latency", "timing1_end", "id", 3); // // Step 2: associate these custom begin/end pairs. // Query begin(Query(EVENT_NAME) == Query::String("timing1_begin")); // Query end(Query(EVENT_NAME) == Query::String("timing1_end")); // Query match(Query(EVENT_ARG, "id") == Query(OTHER_ARG, "id")); // analyzer.AssociateEvents(begin, end, match); // // Step 3: search for "timing1_begin" events with existing other event. // Query q = (Query(EVENT_NAME) == Query::String("timing1_begin") && // Query(EVENT_HAS_OTHER)); // analyzer.FindEvents(q, &events); // // Step 4: analyze events, such as checking durations. // for (size_t i = 0; i < events.size(); ++i) { // double duration; // EXPECT_TRUE(events[i].GetAbsTimeToOtherEvent(&duration)); // EXPECT_LT(duration, 1000000.0/60.0); // expect less than 1/60 second. // } // // There are two helper functions, Start(category_filter_string) and Stop(), for // facilitating the collection of process-local traces and building a // TraceAnalyzer from them. A typical test, that uses the helper functions, // looks like the following: // // TEST_F(...) { // Start("*"); // [Invoke the functions you want to test their traces] // auto analyzer = Stop(); // // [Use the analyzer to verify produced traces, as explained above] // } // // Note: The Stop() function needs a SingleThreadTaskRunner. #ifndef BASE_TEST_TRACE_EVENT_ANALYZER_H_ #define BASE_TEST_TRACE_EVENT_ANALYZER_H_ #include <stddef.h> #include <stdint.h> #include <map> #include <memory> #include <string> #include <vector> #include "base/memory/raw_ptr.h" #include "base/memory/ref_counted.h" #include "base/trace_event/base_tracing.h" namespace base { class Value; } namespace trace_analyzer { class QueryNode; // trace_analyzer::TraceEvent is a more convenient form of the // base::trace_event::TraceEvent class to make tracing-based tests easier to // write. struct TraceEvent { … }; TraceEventVector; class Query { … }; // Implementation detail: // QueryNode allows Query to store a ref-counted query tree. class QueryNode : public base::RefCounted<QueryNode> { … }; // TraceAnalyzer helps tests search for trace events. class TraceAnalyzer { … }; // Utility functions for collecting process-local traces and creating a // |TraceAnalyzer| from the result. Please see comments in trace_config.h to // understand how the |category_filter_string| works. Use "*" to enable all // default categories. void Start(const std::string& category_filter_string); std::unique_ptr<TraceAnalyzer> Stop(); // Utility functions for TraceEventVector. struct RateStats { … }; struct RateStatsOptions { … }; // Calculate min/max/mean and standard deviation from the times between // adjacent events. bool GetRateStats(const TraceEventVector& events, RateStats* stats, const RateStatsOptions* options); // Starting from |position|, find the first event that matches |query|. // Returns true if found, false otherwise. bool FindFirstOf(const TraceEventVector& events, const Query& query, size_t position, size_t* return_index); // Starting from |position|, find the last event that matches |query|. // Returns true if found, false otherwise. bool FindLastOf(const TraceEventVector& events, const Query& query, size_t position, size_t* return_index); // Find the closest events to |position| in time that match |query|. // return_second_closest may be NULL. Closeness is determined by comparing // with the event timestamp. // Returns true if found, false otherwise. If both return parameters are // requested, both must be found for a successful result. bool FindClosest(const TraceEventVector& events, const Query& query, size_t position, size_t* return_closest, size_t* return_second_closest); // Count matches, inclusive of |begin_position|, exclusive of |end_position|. size_t CountMatches(const TraceEventVector& events, const Query& query, size_t begin_position, size_t end_position); // Count all matches. inline size_t CountMatches(const TraceEventVector& events, const Query& query) { … } } // namespace trace_analyzer #endif // BASE_TEST_TRACE_EVENT_ANALYZER_H_