blob: dc9093ccfc0683b560b522d1a694a91ea7725f96 [file] [log] [blame]
/*
* Copyright (C) 2020 The Android Open Source Project
*
* 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 SRC_TRACE_PROCESSOR_IMPORTERS_COMMON_ASYNC_TRACK_SET_TRACKER_H_
#define SRC_TRACE_PROCESSOR_IMPORTERS_COMMON_ASYNC_TRACK_SET_TRACKER_H_
#include "src/trace_processor/storage/trace_storage.h"
namespace perfetto {
namespace trace_processor {
class TraceProcessorContext;
class AsyncTrackSetTrackerUnittest;
// Tracker used to reduce the number of trace processor tracks corresponding
// to a single "UI track".
//
// UIs using trace processor want to display all slices in the same context
// (e.g. same upid) and same name into a single track. However, because trace
// processor does not allow parallel slices on a single track (because it breaks
// things like span join, self time computation etc.), at the trace processor
// level these parallel slices are put on different tracks.
//
// Creating a new track for every event, however, leads to an explosion of
// tracks which is undesirable. This class exists to multiplex slices so that
// n events correspond to a single track in a way which minimises the number of
// tracks which needs to be merged by the UI.
//
// The intended usage of this class is for callers to first call one of the
// Intern* methods to obtain a TrackSetId followed by Begin/End just before
// calling into SliceTracker's Begin/End respectively. For example:
// TrackSetId set_id = track_set_tracker->InternProcessTrackSet(upid, name);
// if (event.begin) {
// TrackId id = track_set_tracker->Begin(set_id, cookie);
// slice_tracker->Begin(ts, id, ...)
// } else {
// ... (same thing with end)
// }
// Alternatively, instead of Begin/End, Scoped can also be called if supported
// by the track type.
class AsyncTrackSetTracker {
public:
using TrackSetId = uint32_t;
explicit AsyncTrackSetTracker(TraceProcessorContext* context);
~AsyncTrackSetTracker() = default;
// Interns a set of global async slice tracks associated with the given name.
TrackSetId InternGlobalTrackSet(StringId name);
// Interns a set of process async slice tracks associated with the given name
// and upid.
TrackSetId InternProcessTrackSet(UniquePid, StringId name);
// Interns a set of Android legacy unnesteable async slice tracks
// associated with the given upid and name.
// Scoped is *not* supported for this track set type.
TrackSetId InternAndroidLegacyUnnestableTrackSet(UniquePid, StringId name);
// Starts a new slice on the given async track set which has the given cookie.
TrackId Begin(TrackSetId id, int64_t cookie);
// Ends a new slice on the given async track set which has the given cookie.
TrackId End(TrackSetId id, int64_t cookie);
// Creates a scoped slice on the given async track set.
// This method makes sure that any other slice in this track set does
// not happen simultaneously on the returned track.
// Only supported on selected track set types; read the documentation for
// the Intern* method for your track type to check if supported.
TrackId Scoped(TrackSetId id, int64_t ts, int64_t dur);
private:
friend class AsyncTrackSetTrackerUnittest;
struct ProcessTuple {
UniquePid upid;
StringId name;
friend bool operator<(const ProcessTuple& l, const ProcessTuple& r) {
return std::tie(l.upid, l.name) < std::tie(r.upid, r.name);
}
};
// Indicates the nesting behaviour of slices associated to a single slice
// stack.
enum class NestingBehaviour {
// Indicates that slices are nestable; that is, a stack of slices with
// the same cookie should stack correctly (but are not allowed to overlap).
// This pattern should be the default behaviour that most async slices
// should use.
kNestable,
// Indicates that slices are unnestable but also saturating; that is
// calling Begin -> Begin only causes a single Begin to be recorded.
// This is only really useful for Android async slices which have this
// behaviour for legacy reasons. See the comment in
// SystraceParser::ParseSystracePoint for information on why
// this behaviour exists.
kLegacySaturatingUnnestable,
};
enum class TrackSetScope {
kGlobal,
kProcess,
};
struct TrackState {
TrackId id;
enum class SliceType { kCookie, kTimestamp };
SliceType slice_type;
union {
// Only valid for |slice_type| == |SliceType::kCookie|.
int64_t cookie;
// Only valid for |slice_type| == |SliceType::kTimestamp|.
int64_t ts_end;
};
// Only used for |slice_type| == |SliceType::kCookie|.
uint32_t nest_count;
};
struct TrackSet {
TrackSetScope scope;
union {
// Only set when |scope| == |TrackSetScope::kGlobal|.
StringId global_track_name;
// Only set when |scope| == |TrackSetScope::kFrameTimeline| or
// |TrackSetScope::kAndroidLegacyUnnestable|.
ProcessTuple process_tuple;
};
NestingBehaviour nesting_behaviour;
std::vector<TrackState> tracks;
};
// Returns the state for a track using the following algorithm:
// 1. If a track exists with the given cookie in the track set, returns
// that track.
// 2. Otherwise, looks for any track in the set which is "open" (i.e.
// does not have another slice currently scheduled).
// 3. Otherwise, creates a new track and associates it with the set.
TrackState& GetOrCreateTrackForCookie(TrackSet& set, int64_t cookie);
TrackId CreateTrackForSet(const TrackSet& set);
std::map<StringId, TrackSetId> global_track_set_ids_;
std::map<ProcessTuple, TrackSetId> process_track_set_ids_;
std::map<ProcessTuple, TrackSetId> android_legacy_unnestable_track_set_ids_;
std::vector<TrackSet> track_sets_;
const StringId android_source_ = kNullStringId;
TraceProcessorContext* const context_;
};
} // namespace trace_processor
} // namespace perfetto
#endif // SRC_TRACE_PROCESSOR_IMPORTERS_COMMON_ASYNC_TRACK_SET_TRACKER_H_