Skip to content

Commit

Permalink
Update CHERI perfetto interface.
Browse files Browse the repository at this point in the history
 - Use the same protobuf descriptor for instructions as the one used
 by the protobuf backend.
 - Use the CHERI context track implementation to embed context
 identifiers in the trace instead of using the Track name.
  • Loading branch information
qwattash committed Jan 19, 2022
1 parent 299a60a commit d9b1577
Show file tree
Hide file tree
Showing 6 changed files with 99 additions and 98 deletions.
2 changes: 1 addition & 1 deletion trace_extra/cheri-perfetto
Submodule cheri-perfetto updated 26 files
+2 −1 protos/perfetto/trace/track_event/BUILD.gn
+11 −9 protos/perfetto/trace/track_event/cheri_context_descriptor.proto
+32 −67 protos/perfetto/trace/track_event/qemu_event_info.proto
+148 −0 protos/perfetto/trace/track_event/qemu_log_entry.proto
+2 −2 protos/perfetto/trace/track_event/track_descriptor.proto
+1,324 −705 sdk/perfetto.cc
+1,943 −1,030 sdk/perfetto.h
+19 −0 src/trace_processor/db/column.cc
+15 −0 src/trace_processor/db/column.h
+57 −0 src/trace_processor/importers/common/process_tracker.cc
+23 −0 src/trace_processor/importers/common/process_tracker.h
+17 −0 src/trace_processor/importers/common/process_tracker_unittest.cc
+19 −0 src/trace_processor/importers/common/track_tracker.cc
+18 −0 src/trace_processor/importers/common/track_tracker.h
+30 −0 src/trace_processor/importers/proto/proto_trace_parser_unittest.cc
+10 −10 src/trace_processor/importers/proto/track_event_parser.cc
+1 −1 src/trace_processor/importers/proto/track_event_parser.h
+22 −6 src/trace_processor/importers/proto/track_event_tokenizer.cc
+90 −0 src/trace_processor/importers/proto/track_event_tracker.cc
+32 −2 src/trace_processor/importers/proto/track_event_tracker.h
+21 −0 src/trace_processor/storage/trace_storage.h
+19 −0 src/trace_processor/tables/metadata_tables.h
+2 −0 src/trace_processor/tables/table_destructors.cc
+19 −0 src/trace_processor/tables/track_tables.h
+14 −0 src/trace_processor/trace_processor_impl.cc
+45 −0 src/trace_processor/types/cheri.h
22 changes: 11 additions & 11 deletions trace_extra/guest_context_tracker.cc
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,9 @@ namespace cheri
*/
std::mutex tracks_lock;
std::unordered_map<qemu_context_track::qemu_ctx_id,
std::shared_ptr<qemu_context_track>,
cheri::tuple_hasher<qemu_context_track::qemu_ctx_id>>
tracks;
std::shared_ptr<qemu_context_track>,
cheri::tuple_hasher<qemu_context_track::qemu_ctx_id>>
tracks;

/* Helper to generate unique IDs for dynamic tracks */
unsigned long gen_track_uuid()
Expand All @@ -53,12 +53,12 @@ unsigned long gen_track_uuid()
return (next_track_id++);
}

perfetto::protos::pbzero::ModeSwitch
perfetto::protos::pbzero::QEMULogEntryModeSwitch
qemu_cpu_mode_to_trace(qemu_log_instr_cpu_mode_t mode)
{
// NOTE: We rely on the fact that the protobuf enum ModeSwitch
// uses the same numbering as qemu_log_instr_cpu_mode_t
return static_cast<perfetto::protos::pbzero::ModeSwitch>(mode);
return static_cast<perfetto::protos::pbzero::QEMULogEntryModeSwitch>(mode);
}

/* static */
Expand All @@ -76,11 +76,11 @@ qemu_context_track::qemu_ctx_id qemu_context_track::get_id() const
perfetto::protos::gen::TrackDescriptor qemu_context_track::Serialize() const
{
auto desc = Track::Serialize();
auto qemu_desc = desc.mutable_qemu_context();
qemu_desc->set_pid(pid);
qemu_desc->set_tid(tid);
qemu_desc->set_cid(cid);
// qemu_desc->set_mode(mode); // TODO not yet in cheri-perfetto
auto cheri_desc = desc.mutable_cheri_context();
cheri_desc->set_pid(pid);
cheri_desc->set_tid(tid);
cheri_desc->set_cid(cid);
cheri_desc->set_el(mode);
return desc;
}

Expand All @@ -106,7 +106,7 @@ guest_context_tracker::guest_context_tracker(int cpu_id)
}

void guest_context_tracker::mode_update(
perfetto::protos::pbzero::ModeSwitch new_mode)
perfetto::protos::pbzero::QEMULogEntryModeSwitch new_mode)
{
if (ctx_track_ == nullptr)
return;
Expand Down
6 changes: 3 additions & 3 deletions trace_extra/guest_context_tracker.hh
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ struct qemu_context_data {

struct qemu_context_track : public perfetto::Track {

using cpu_mode_type = perfetto::protos::pbzero::ModeSwitch;
using cpu_mode_type = perfetto::protos::pbzero::QEMULogEntryModeSwitch;
/* (pid, tid, cid, mode) */
using qemu_ctx_id = std::tuple<uint64_t, uint64_t, uint64_t, cpu_mode_type>;

Expand Down Expand Up @@ -105,7 +105,7 @@ class guest_context_tracker
public:
guest_context_tracker(int cpu_id);
void context_update(const log_event_ctx_update_t *evt);
void mode_update(perfetto::protos::pbzero::ModeSwitch new_mode);
void mode_update(perfetto::protos::pbzero::QEMULogEntryModeSwitch new_mode);
void flush_all_ctx_data();
perfetto::Track &get_cpu_track();
perfetto::Track &get_ctx_track();
Expand All @@ -119,7 +119,7 @@ class guest_context_tracker
*/
unsigned long gen_track_uuid();

perfetto::protos::pbzero::ModeSwitch
perfetto::protos::pbzero::QEMULogEntryModeSwitch
qemu_cpu_mode_to_trace(qemu_log_instr_cpu_mode_t mode);

} // namespace cheri
142 changes: 69 additions & 73 deletions trace_extra/trace_perfetto.cc
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
#include <perfetto.h>
#include <boost/filesystem.hpp>

// #include "qemu/cpu-defs.h"
#include "qemu/log_instr.h"
#include "exec/log_instr_internal.h"
#include "exec/log_instr_perfetto.h"
Expand Down Expand Up @@ -163,14 +164,14 @@ void perfetto_tracing_stop(void)
session->StopBlocking();
}

void trace_cap_register(perfetto::protos::pbzero::Capability *cap,
void trace_cap_register(perfetto::protos::pbzero::QEMULogEntryCapability *cap,
cap_register_handle chandle)
{
cap->set_valid(perfetto_cap_tag(chandle));
cap->set_sealed(perfetto_cap_sealed(chandle));
cap->set_base(perfetto_cap_base(chandle));
cap->set_length(perfetto_cap_length(chandle));
cap->set_cursor(perfetto_cap_cursor(chandle));
cap->set_cap_base(perfetto_cap_base(chandle));
cap->set_cap_length(perfetto_cap_length(chandle));
cap->set_cap_cursor(perfetto_cap_cursor(chandle));
cap->set_perms(perfetto_cap_perms(chandle));
cap->set_otype(perfetto_cap_otype(chandle));
}
Expand All @@ -189,55 +190,51 @@ void process_events(perfetto_backend_data *data, cpu_log_entry_handle entry)
for (int i = 0; i < nevents; i++) {
log_event_t *evt = perfetto_log_event(entry, i);
switch (evt->id) {
case LOG_EVENT_STATE:
{
switch (evt->state.next_state) {
case LOG_EVENT_STATE_FLUSH:
TRACE_EVENT_INSTANT("ctrl", "flush", data->ctrl_track_);
data->ctx_tracker_.flush_all_ctx_data();
perfetto::TrackEvent::Flush();
break;
case LOG_EVENT_STATE_START:
ctx_data->stats.unpause(*ctx_track, evt->state.pc);
TRACE_EVENT_BEGIN("ctrl", "tracing", data->ctrl_track_);
have_startstop_event = true;
break;
case LOG_EVENT_STATE_STOP:
ctx_data->stats.pause(*ctx_track, evt->state.pc);
TRACE_EVENT_END("ctrl", data->ctrl_track_);
have_startstop_event = true;
break;
default:
assert(false && "Invalid state event");
}
}
case LOG_EVENT_STATE: {
switch (evt->state.next_state) {
case LOG_EVENT_STATE_FLUSH:
TRACE_EVENT_INSTANT("ctrl", "flush", data->ctrl_track_);
data->ctx_tracker_.flush_all_ctx_data();
perfetto::TrackEvent::Flush();
break;
case LOG_EVENT_CTX_UPDATE:
{
/* Swap current context. */
if (evt->ctx_update.op == LOG_EVENT_CTX_OP_SETUP ||
evt->ctx_update.op == LOG_EVENT_CTX_OP_SWITCH) {
ctx_data->stats.pause(*ctx_track, perfetto_log_entry_pc(entry));
data->ctx_tracker_.context_update(&evt->ctx_update);
/* Reload data and track as context_update will have changed them */
ctx_data = &data->ctx_tracker_.get_ctx_data();
ctx_track = &data->ctx_tracker_.get_ctx_track();
ctx_data->stats.unpause(*ctx_track, perfetto_log_entry_pc(entry));
}
}
case LOG_EVENT_STATE_START:
ctx_data->stats.unpause(*ctx_track, evt->state.pc);
TRACE_EVENT_BEGIN("ctrl", "tracing", data->ctrl_track_);
have_startstop_event = true;
break;
case LOG_EVENT_MARKER:
{
auto cpu_track = data->ctx_tracker_.get_cpu_track();
TRACE_EVENT_INSTANT("marker", "guest", cpu_track,
[&](perfetto::EventContext ctx) {
auto *qemu_arg = ctx.event()->set_qemu();
qemu_arg->set_marker(evt->marker);
});
}
case LOG_EVENT_STATE_STOP:
ctx_data->stats.pause(*ctx_track, evt->state.pc);
TRACE_EVENT_END("ctrl", data->ctrl_track_);
have_startstop_event = true;
break;
default:
assert(false && "Invalid event identifier");
assert(false && "Invalid state event");
}
} break;
case LOG_EVENT_CTX_UPDATE: {
/* Swap current context. */
if (evt->ctx_update.op == LOG_EVENT_CTX_OP_SETUP ||
evt->ctx_update.op == LOG_EVENT_CTX_OP_SWITCH) {
ctx_data->stats.pause(*ctx_track, perfetto_log_entry_pc(entry));
data->ctx_tracker_.context_update(&evt->ctx_update);
/* Reload data and track as context_update will have changed
* them */
ctx_data = &data->ctx_tracker_.get_ctx_data();
ctx_track = &data->ctx_tracker_.get_ctx_track();
ctx_data->stats.unpause(*ctx_track,
perfetto_log_entry_pc(entry));
}
} break;
case LOG_EVENT_MARKER: {
auto cpu_track = data->ctx_tracker_.get_cpu_track();
TRACE_EVENT_INSTANT("marker", "guest", cpu_track,
[&](perfetto::EventContext ctx) {
auto *qemu_arg = ctx.event()->set_qemu();
qemu_arg->set_marker(evt->marker);
});
} break;
default:
assert(false && "Invalid event identifier");
}
}
if (perfetto_log_entry_flags(entry) & LI_FLAG_MODE_SWITCH) {
Expand Down Expand Up @@ -272,7 +269,8 @@ void process_instr(perfetto_backend_data *data, cpu_log_entry_handle entry)
* same track/category: e.g. mode swtich, interrupt information and modified
* registers?
*/
TRACE_EVENT_INSTANT("instructions", "stream", data->ctx_tracker_.get_ctx_track(),
TRACE_EVENT_INSTANT(
"instructions", "stream", data->ctx_tracker_.get_ctx_track(),
[&](perfetto::EventContext ctx) {
auto *qemu_arg = ctx.event()->set_qemu();
auto *instr = qemu_arg->set_instr();
Expand All @@ -295,16 +293,8 @@ void process_instr(perfetto_backend_data *data, cpu_log_entry_handle entry)
const char *bytes = perfetto_log_entry_insn_bytes(entry);
int size = perfetto_log_entry_insn_size(entry);
int nitems;
std::stringstream ss;

// XXX-AM: We can not use a bytes field in the protobuf because
// perfetto lacks support. This is slightly sad as this is an
// high-frequency event.
for (int i = 0; i < size; i++) {
ss << std::hex << std::setw(2) << std::setfill('0')
<< (static_cast<unsigned int>(bytes[i]) & 0xff) << " ";
}
instr->set_opcode(ss.str());

instr->set_opcode((const uint8_t *)bytes, size);
instr->set_pc(perfetto_log_entry_pc(entry));

nitems = perfetto_log_entry_regs(entry);
Expand All @@ -315,10 +305,10 @@ void process_instr(perfetto_backend_data *data, cpu_log_entry_handle entry)
if ((flags & LRI_CAP_REG) && (flags & LRI_HOLDS_CAP)) {
cap_register_handle cap_handle =
perfetto_reg_info_cap(entry, i);
auto *capinfo = reginfo->set_cap_val();
auto *capinfo = reginfo->set_cap_value();
trace_cap_register(capinfo, cap_handle);
} else {
reginfo->set_int_val(perfetto_reg_info_gpr(entry, i));
reginfo->set_int_value(perfetto_reg_info_gpr(entry, i));
}
}
nitems = perfetto_log_entry_mem(entry);
Expand All @@ -328,45 +318,51 @@ void process_instr(perfetto_backend_data *data, cpu_log_entry_handle entry)
meminfo->set_addr(perfetto_mem_info_addr(entry, i));
switch (flags) {
case LMI_LD:
meminfo->set_op(perfetto::protos::pbzero::MemInfo::LOAD);
meminfo->set_op(
perfetto::protos::pbzero::QEMULogEntryMem::LOAD);
break;
case LMI_LD | LMI_CAP:
meminfo->set_op(perfetto::protos::pbzero::MemInfo::CLOAD);
meminfo->set_op(
perfetto::protos::pbzero::QEMULogEntryMem::CLOAD);
break;
case LMI_ST:
meminfo->set_op(perfetto::protos::pbzero::MemInfo::STORE);
meminfo->set_op(
perfetto::protos::pbzero::QEMULogEntryMem::STORE);
break;
case LMI_ST | LMI_CAP:
meminfo->set_op(perfetto::protos::pbzero::MemInfo::CSTORE);
meminfo->set_op(
perfetto::protos::pbzero::QEMULogEntryMem::CSTORE);
break;
default:
// XXX Notify error somehow?
break;
}
if (flags & LMI_CAP) {
auto *capinfo = meminfo->set_cap_val();
auto *capinfo = meminfo->set_cap_value();
cap_register_handle cap_handle =
perfetto_reg_info_cap(entry, i);
trace_cap_register(capinfo, cap_handle);
} else {
meminfo->set_int_val(perfetto_mem_info_value(entry, i));
meminfo->set_int_value(perfetto_mem_info_value(entry, i));
}
}

if (flags & LI_FLAG_INTR_MASK) {
// interrupt
auto *trap = instr->set_trap();
auto *exc = instr->set_exception();
if (flags & LI_FLAG_INTR_TRAP)
trap->set_type(perfetto::protos::pbzero::Trap::EXCEPTION);
exc->set_type(
perfetto::protos::pbzero::QEMULogEntryExcType::TRAP);
else {
trap->set_type(perfetto::protos::pbzero::Trap::INTERRUPT);
exc->set_type(
perfetto::protos::pbzero::QEMULogEntryExcType::INTR);
}
trap->set_trap_number(perfetto_log_entry_intr_code(entry));
exc->set_code(perfetto_log_entry_intr_code(entry));
}
if (flags & LI_FLAG_MODE_SWITCH) {
auto mode = cheri::qemu_cpu_mode_to_trace(
perfetto_log_entry_next_cpu_mode(entry));
instr->set_mode(mode);
instr->set_mode_code(mode);
}
});
}
Expand Down
3 changes: 2 additions & 1 deletion trace_extra/trace_stats.hh
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ class qemu_stats
* Post-processing must be used to distinguish between function
* calls and conditional branches.
*/
std::unordered_map<branch_map_id, uint64_t, tuple_hasher<branch_map_id>> branch_map_;
std::unordered_map<branch_map_id, uint64_t, tuple_hasher<branch_map_id>>
branch_map_;
/*
* PC-tracking info to detect branches.
*/
Expand Down
22 changes: 13 additions & 9 deletions trace_extra/tuple_index.hh
Original file line number Diff line number Diff line change
Expand Up @@ -35,17 +35,21 @@

namespace cheri
{
template<typename T> struct is_tuple_impl: std::false_type {};
template<typename ...T> struct is_tuple_impl<std::tuple<T...>>: std::true_type {};
template<typename T> struct is_tuple : is_tuple_impl<std::decay_t<T>> {};
template <typename T> struct is_tuple_impl : std::false_type {
};
template <typename... T>
struct is_tuple_impl<std::tuple<T...>> : std::true_type {
};
template <typename T> struct is_tuple : is_tuple_impl<std::decay_t<T>> {
};

template<typename T, typename Enable=void> struct tuple_hasher;
template <typename T, typename Enable = void> struct tuple_hasher;

template<typename T>
struct tuple_hasher<T, typename std::enable_if<is_tuple<T>::value>::type>
{
std::size_t operator()(const T& tuple) const {
template <typename T>
struct tuple_hasher<T, typename std::enable_if<is_tuple<T>::value>::type> {
std::size_t operator()(const T &tuple) const
{
return boost::hash_value(tuple);
}
};
}
} // namespace cheri

0 comments on commit d9b1577

Please sign in to comment.