blob: f0f59da8b6c09fc4c18f8cbb6dca766262d1ac7d [file] [log] [blame]
/*
* Copyright (C) 2018 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_SLICE_TRACKER_H_
#define SRC_TRACE_PROCESSOR_IMPORTERS_COMMON_SLICE_TRACKER_H_
#include <stdint.h>
#include "perfetto/ext/base/flat_hash_map.h"
#include "src/trace_processor/importers/common/args_tracker.h"
#include "src/trace_processor/importers/common/slice_translation_table.h"
#include "src/trace_processor/storage/trace_storage.h"
namespace perfetto {
namespace trace_processor {
class ArgsTracker;
class TraceProcessorContext;
class SliceTracker {
public:
using SetArgsCallback = std::function<void(ArgsTracker::BoundInserter*)>;
using OnSliceBeginCallback = std::function<void(TrackId, SliceId)>;
explicit SliceTracker(TraceProcessorContext*);
virtual ~SliceTracker();
// virtual for testing
virtual std::optional<SliceId> Begin(
int64_t timestamp,
TrackId track_id,
StringId category,
StringId raw_name,
SetArgsCallback args_callback = SetArgsCallback());
// Unnestable slices are slices which do not have any concept of nesting so
// starting a new slice when a slice already exists leads to no new slice
// being added. The number of times a begin event is seen is tracked as well
// as the latest time we saw a begin event. For legacy Android use only. See
// the comment in SystraceParser::ParseSystracePoint for information on why
// this method exists.
void BeginLegacyUnnestable(tables::SliceTable::Row row,
SetArgsCallback args_callback);
template <typename Table>
std::optional<SliceId> BeginTyped(
Table* table,
typename Table::Row row,
SetArgsCallback args_callback = SetArgsCallback()) {
// Ensure that the duration is pending for this row.
row.dur = kPendingDuration;
if (row.name) {
row.name = context_->slice_translation_table->TranslateName(*row.name);
}
return StartSlice(row.ts, row.track_id, args_callback,
[table, &row]() { return table->Insert(row).id; });
}
// virtual for testing
virtual std::optional<SliceId> Scoped(
int64_t timestamp,
TrackId track_id,
StringId category,
StringId raw_name,
int64_t duration,
SetArgsCallback args_callback = SetArgsCallback());
template <typename Table>
std::optional<SliceId> ScopedTyped(
Table* table,
typename Table::Row row,
SetArgsCallback args_callback = SetArgsCallback()) {
PERFETTO_DCHECK(row.dur >= 0);
if (row.name) {
row.name = context_->slice_translation_table->TranslateName(*row.name);
}
return StartSlice(row.ts, row.track_id, args_callback,
[table, &row]() { return table->Insert(row).id; });
}
// virtual for testing
virtual std::optional<SliceId> End(
int64_t timestamp,
TrackId track_id,
StringId opt_category = {},
StringId opt_raw_name = {},
SetArgsCallback args_callback = SetArgsCallback());
// Usually args should be added in the Begin or End args_callback but this
// method is for the situation where new args need to be added to an
// in-progress slice.
std::optional<uint32_t> AddArgs(TrackId track_id,
StringId category,
StringId name,
SetArgsCallback args_callback);
void FlushPendingSlices();
void SetOnSliceBeginCallback(OnSliceBeginCallback callback);
std::optional<SliceId> GetTopmostSliceOnTrack(TrackId track_id) const;
private:
// Slices which have been opened but haven't been closed yet will be marked
// with this duration placeholder.
static constexpr int64_t kPendingDuration = -1;
struct SliceInfo {
tables::SliceTable::RowNumber row;
ArgsTracker args_tracker;
};
using SlicesStack = std::vector<SliceInfo>;
struct TrackInfo {
SlicesStack slice_stack;
// These field is only valid for legacy unnestable slices.
bool is_legacy_unnestable = false;
uint32_t legacy_unnestable_begin_count = 0;
int64_t legacy_unnestable_last_begin_ts = 0;
};
using StackMap = base::FlatHashMap<TrackId, TrackInfo>;
// Args pending translation.
struct TranslatableArgs {
SliceId slice_id;
ArgsTracker::CompactArgSet compact_arg_set;
};
// virtual for testing.
virtual std::optional<SliceId> StartSlice(int64_t timestamp,
TrackId track_id,
SetArgsCallback args_callback,
std::function<SliceId()> inserter);
std::optional<SliceId> CompleteSlice(
int64_t timestamp,
TrackId track_id,
SetArgsCallback args_callback,
std::function<std::optional<uint32_t>(const SlicesStack&)> finder);
void MaybeCloseStack(int64_t end_ts, const SlicesStack&, TrackId track_id);
std::optional<uint32_t> MatchingIncompleteSliceIndex(const SlicesStack& stack,
StringId name,
StringId category);
int64_t GetStackHash(const SlicesStack&);
void StackPop(TrackId track_id);
void StackPush(TrackId track_id, tables::SliceTable::RowReference);
void FlowTrackerUpdate(TrackId track_id);
// If args need translation, adds them to a list of pending translatable args,
// so that they are translated at the end of the trace. Takes ownership of the
// arg set for the slice. Otherwise, this is a noop, and the args are added to
// the args table immediately when the slice is popped.
void MaybeAddTranslatableArgs(SliceInfo& slice_info);
OnSliceBeginCallback on_slice_begin_callback_;
// Timestamp of the previous event. Used to discard events arriving out
// of order.
int64_t prev_timestamp_ = std::numeric_limits<int64_t>::min();
const StringId legacy_unnestable_begin_count_string_id_;
const StringId legacy_unnestable_last_begin_ts_string_id_;
TraceProcessorContext* const context_;
StackMap stacks_;
std::vector<TranslatableArgs> translatable_args_;
};
} // namespace trace_processor
} // namespace perfetto
#endif // SRC_TRACE_PROCESSOR_IMPORTERS_COMMON_SLICE_TRACKER_H_