blob: eba37b64e51a4003d45e27ac1f44d8bb51c95460 [file] [log] [blame]
/*
* Copyright (C) 2025 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_DATAFRAME_CURSOR_H_
#define SRC_TRACE_PROCESSOR_DATAFRAME_CURSOR_H_
#include <cstddef>
#include <cstdint>
#include <limits>
#include <utility>
#include "perfetto/base/logging.h"
#include "perfetto/public/compiler.h"
#include "src/trace_processor/containers/null_term_string_view.h"
#include "src/trace_processor/containers/string_pool.h"
#include "src/trace_processor/dataframe/impl/bytecode_interpreter.h"
#include "src/trace_processor/dataframe/impl/query_plan.h"
#include "src/trace_processor/dataframe/impl/types.h"
#include "src/trace_processor/dataframe/specs.h"
#include "src/trace_processor/dataframe/value_fetcher.h"
namespace perfetto::trace_processor::dataframe {
// Callback for receiving cell values
struct CellCallback {
void OnCell(int64_t);
void OnCell(double);
void OnCell(NullTermStringView);
void OnCell(std::nullptr_t);
void OnCell(uint32_t);
void OnCell(int32_t);
};
// Cursor provides a mechanism to iterate through dataframe query results
// and access column values.
template <typename FilterValueFetcherImpl>
class Cursor {
public:
static_assert(std::is_base_of_v<ValueFetcher, FilterValueFetcherImpl>,
"FilterValueFetcherImpl must be a subclass of ValueFetcher");
// Constructs a cursor from a query plan and dataframe columns.
Cursor(impl::QueryPlan plan,
const impl::Column* const* column_ptrs,
const impl::Storage::DataPointer* storage_data_ptrs,
const StringPool* pool)
: interpreter_(std::move(plan.bytecode), column_ptrs, pool),
params_(plan.params),
storage_data_ptrs_(storage_data_ptrs),
pool_(pool) {}
// Executes the query and prepares the cursor for iteration.
// This initializes the cursor's position to the first row of results.
//
// Parameters:
// fvf: A subclass of `ValueFetcher` that defines the logic for fetching
// filter values for each filter spec.
PERFETTO_ALWAYS_INLINE void Execute(
FilterValueFetcherImpl& filter_value_fetcher) {
using S = impl::Span<uint32_t>;
interpreter_.Execute(filter_value_fetcher);
const auto& span =
*interpreter_.template GetRegisterValue<S>(params_.output_register);
pos_ = span.b;
end_ = span.e;
}
// Returns the index of the row in the table this cursor is pointing to.
PERFETTO_ALWAYS_INLINE uint32_t RowIndex() { return *pos_; }
// Advances the cursor to the next row of results.
PERFETTO_ALWAYS_INLINE void Next() {
PERFETTO_DCHECK(pos_ < end_);
pos_ += params_.output_per_row;
}
// Returns true if the cursor has reached the end of the result set.
PERFETTO_ALWAYS_INLINE bool Eof() const { return pos_ == end_; }
// Returns the value of the column at the current cursor position.
// The visitor pattern allows type-safe access to heterogeneous column types.
//
// Parameters:
// col: The index of the column to access.
// callback: A subclass of `CellCallback` that defines the logic for
// processing the value of the column at the current cursor
// position.
template <typename CellCallbackImpl>
PERFETTO_ALWAYS_INLINE void Cell(uint32_t col,
CellCallbackImpl& cell_callback_impl) {
static_assert(std::is_base_of_v<CellCallback, CellCallbackImpl>,
"CellCallbackImpl must be a subclass of CellCallback");
const impl::Storage::DataPointer& p = storage_data_ptrs_[col];
uint32_t idx = pos_[params_.col_to_output_offset[col]];
if (idx == std::numeric_limits<uint32_t>::max()) {
cell_callback_impl.OnCell(nullptr);
return;
}
switch (p.index()) {
case StorageType::GetTypeIndex<Id>():
cell_callback_impl.OnCell(idx);
break;
case StorageType::GetTypeIndex<Uint32>():
cell_callback_impl.OnCell(impl::Storage::CastDataPtr<Uint32>(p)[idx]);
break;
case StorageType::GetTypeIndex<Int32>():
cell_callback_impl.OnCell(impl::Storage::CastDataPtr<Int32>(p)[idx]);
break;
case StorageType::GetTypeIndex<Int64>():
cell_callback_impl.OnCell(impl::Storage::CastDataPtr<Int64>(p)[idx]);
break;
case StorageType::GetTypeIndex<Double>():
cell_callback_impl.OnCell(impl::Storage::CastDataPtr<Double>(p)[idx]);
break;
case StorageType::GetTypeIndex<String>():
cell_callback_impl.OnCell(
pool_->Get(impl::Storage::CastDataPtr<String>(p)[idx]));
break;
default:
PERFETTO_FATAL("Invalid storage spec");
}
}
private:
// Bytecode interpreter that executes the query.
impl::bytecode::Interpreter<FilterValueFetcherImpl> interpreter_;
// Parameters for query execution.
impl::QueryPlan::ExecutionParams params_;
// Pointer to the storage data pointers.
const impl::Storage::DataPointer* storage_data_ptrs_;
// String pool for string values.
const StringPool* pool_;
// Current position in the result set.
const uint32_t* pos_;
// End position in the result set.
const uint32_t* end_;
};
} // namespace perfetto::trace_processor::dataframe
#endif // SRC_TRACE_PROCESSOR_DATAFRAME_CURSOR_H_