blob: 3a6f6ac87a202fd83b3159cd20bfa6bfa60c14c2 [file] [log] [blame]
/*
* Copyright (C) 2024 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_REDACTION_PROCESS_THREAD_TIMELINE_H_
#define SRC_TRACE_REDACTION_PROCESS_THREAD_TIMELINE_H_
#include <cstdint>
#include <list>
#include <optional>
#include <vector>
namespace perfetto::trace_redaction {
class ProcessThreadTimeline {
public:
// Opened and closed events are used to mark the start and end of lifespans.
class Event {
public:
enum class Type { kInvalid, kOpen, kClose };
Event()
: type_(ProcessThreadTimeline::Event::Type::kInvalid),
ts_(0),
pid_(0),
ppid_(0),
uid_(0) {}
Type type() const { return type_; }
uint64_t ts() const { return ts_; }
int32_t pid() const { return pid_; }
int32_t ppid() const { return ppid_; }
uint64_t uid() const { return uid_; }
bool operator==(const Event& o) const {
switch (type_) {
case Type::kOpen:
return o.type_ == Type::kOpen && ts_ == o.ts_ && pid_ == o.pid_ &&
ppid_ == o.ppid_ && uid_ == o.uid_;
case Type::kClose:
return o.type_ == Type::kClose && ts_ == o.ts_ && pid_ == o.pid_;
case Type::kInvalid:
return o.type_ == Type::kInvalid;
}
return false;
}
bool operator!=(const Event& o) const { return !(*this == o); }
static Event Open(uint64_t ts, int32_t pid, int32_t ppid, uint64_t uid) {
return Event(ProcessThreadTimeline::Event::Type::kOpen, ts, pid, ppid,
uid);
}
static Event Open(uint64_t ts, int32_t pid, int32_t ppid) {
return Event(ProcessThreadTimeline::Event::Type::kOpen, ts, pid, ppid, 0);
}
static Event Close(uint64_t ts, int32_t pid) {
return Event(ProcessThreadTimeline::Event::Type::kClose, ts, pid, 0, 0);
}
private:
Event(Type type, uint64_t ts, int32_t pid, int32_t ppid, uint64_t uid)
: type_(type), ts_(ts), pid_(pid), ppid_(ppid), uid_(uid) {}
Type type_ = Type::kInvalid;
// Valid: open & close
uint64_t ts_ = 0;
// Valid: open & close
int32_t pid_ = -1;
// Valid: open
int32_t ppid_ = -1;
// Valid: open
uint64_t uid_ = 0;
};
// The state of a process at a specific point in time.
struct Slice {
int32_t pid = -1;
// It is safe to use 0 as the invalid value because that's effectively
// what happening in the trace.
uint64_t uid = 0;
};
ProcessThreadTimeline() = default;
ProcessThreadTimeline(const ProcessThreadTimeline&) = delete;
ProcessThreadTimeline& operator=(const ProcessThreadTimeline&) = delete;
ProcessThreadTimeline(ProcessThreadTimeline&&) = delete;
ProcessThreadTimeline& operator=(ProcessThreadTimeline&&) = delete;
void Append(const Event& event);
// REQUIRED: Sorts all events by pid, making it possible to locate the subset
// of events connected to a pid. Events are not sorted by time because the
// subset of events will, on average, be trivally small.
void Sort();
// OPTIONAL: minimizes the distance between the leaf nodes and the package
// nodes (a node with a uid value not equal to zero).
void Flatten();
// OPTIONAL: Removes events from the timeline that:
//
// 1. Reduces the number of events in the timeline to shrink the search
// space.
//
// 2. Does not invalidate the timeline.
//
// This can only be called after calling Sort(). Calling Reduce() before
// Sort() has undefined behaviour. Calling Reduce() after AppendOpen() if
// AppendClose() (without a call to Sort() call) has undefined behaviour.
void Reduce(uint64_t package_uid);
// Returns a snapshot that contains a process's pid and ppid, but contains the
// first uid found in its parent-child chain. If a uid cannot be found, uid=0
// is returned.
//
// `Sort()` must be called before this.
Slice Search(uint64_t ts, int32_t pid) const;
// Finds the distance between pid and its uid.
//
// Returns -1 it pid has no connection to a uid.
// Returns 0 if pid has an immediately connection to a uid.
//
// Return n where: n is the number of pids between the given pid and the pid
// connected to the uid. For example, assume D() is a
// function that measures the distance between two nodes in
// the same chain:
//
// | pid | depth
// | a : 0
// | b : 1
// | c : 2 --> uid = 98
//
// D(a) = 2
// D(b) = 1
// D(c) = 0
std::optional<size_t> GetDepth(uint64_t ts, int32_t pid) const;
private:
// Effectively this is the same as:
//
// events_for(pid).before(ts).sort_by_time().last()
std::optional<Event> FindPreviousEvent(uint64_t ts, int32_t pid) const;
std::optional<Event> Search(size_t depth, uint64_t ts, int32_t pid) const;
std::optional<size_t> GetDepth(size_t depth, uint64_t ts, int32_t pid) const;
bool TestEvent(std::optional<Event> event) const;
// The number of events are unclear. Use a list when in "write-only" mode and
// then change to a vector for "read-only" mode.
std::list<Event> write_only_events_;
std::vector<Event> read_only_events_;
};
} // namespace perfetto::trace_redaction
#endif // SRC_TRACE_REDACTION_PROCESS_THREAD_TIMELINE_H_