forked from lix-project/lix
wip tracing
This commit is contained in:
parent
1d6fd94cf9
commit
8259d18368
43
src/libtracing/main.cc
Normal file
43
src/libtracing/main.cc
Normal file
|
@ -0,0 +1,43 @@
|
|||
#include "trace-writer.hh"
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
using namespace nix::tracing;
|
||||
class MyInternedRetriever : public InternedRetriever
|
||||
{
|
||||
virtual auto getName(InternedName idx) const -> std::string override
|
||||
{
|
||||
return "meow";
|
||||
}
|
||||
|
||||
virtual auto getPos(InternedPos idx, std::string funcName) const -> TracePos override
|
||||
{
|
||||
return TracePos{
|
||||
.fileName = "file.nix",
|
||||
.functionName = "fun",
|
||||
.lineNumber = 12,
|
||||
};
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
virtual ~MyInternedRetriever() = default;
|
||||
};
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if (argc < 1) {
|
||||
std::cerr << "provide filename pls\n";
|
||||
return 1;
|
||||
}
|
||||
nix::tracing::TraceWriter tw{std::make_unique<MyInternedRetriever>()};
|
||||
|
||||
tw.begin(InternedPos{1}, InternedName{3}, Timestamp{250});
|
||||
tw.end(Timestamp{1235});
|
||||
|
||||
std::ofstream ofs(argv[1]);
|
||||
auto buf = tw.splat();
|
||||
ofs.write(reinterpret_cast<const char *>(buf.data()), buf.size());
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
// Intentionally empty (crbug.com/998165)
|
123429
src/libtracing/meow/protos/perfetto/trace/perfetto_trace.pbzero.h
Normal file
123429
src/libtracing/meow/protos/perfetto/trace/perfetto_trace.pbzero.h
Normal file
File diff suppressed because it is too large
Load diff
47
src/libtracing/meson.build
Normal file
47
src/libtracing/meson.build
Normal file
|
@ -0,0 +1,47 @@
|
|||
libtracing_sources = files(
|
||||
'trace-writer.cc',
|
||||
|
||||
'protozero_src/field.cc',
|
||||
'protozero_src/gen_field_helpers.cc',
|
||||
'protozero_src/message_arena.cc',
|
||||
'protozero_src/message.cc',
|
||||
'protozero_src/packed_repeated_fields.cc',
|
||||
'protozero_src/proto_decoder.cc',
|
||||
'protozero_src/scattered_heap_buffer.cc',
|
||||
'protozero_src/scattered_stream_null_delegate.cc',
|
||||
'protozero_src/scattered_stream_writer.cc',
|
||||
'protozero_src/static_buffer.cc',
|
||||
'protozero_src/virtual_destructors.cc',
|
||||
)
|
||||
|
||||
subdir('perfetto/protozero')
|
||||
|
||||
libtracing_headers = [
|
||||
protozero_headers,
|
||||
files(
|
||||
'trace-writer.hh',
|
||||
),
|
||||
]
|
||||
|
||||
libtracing = library(
|
||||
'lixtracing',
|
||||
libtracing_sources,
|
||||
dependencies : [ ],
|
||||
install : true,
|
||||
# FIXME(Qyriad): is this right?
|
||||
install_rpath : libdir,
|
||||
cpp_args : [ '-DPERFETTO_DISABLE_LOG' ],
|
||||
include_directories : include_directories('./perfetto/base/build_configs/bazel'),
|
||||
)
|
||||
|
||||
liblixtracing = declare_dependency(
|
||||
include_directories : include_directories('.'),
|
||||
link_with : libtracing,
|
||||
)
|
||||
|
||||
tracing_test = executable(
|
||||
'lixtracingtest',
|
||||
files('main.cc'),
|
||||
dependencies : [ liblixtracing ],
|
||||
install : false,
|
||||
)
|
190
src/libtracing/trace-writer.cc
Normal file
190
src/libtracing/trace-writer.cc
Normal file
|
@ -0,0 +1,190 @@
|
|||
#include "meow/protos/perfetto/trace/perfetto_trace.pbzero.h"
|
||||
#include "perfetto/protozero/message.h"
|
||||
#include "perfetto/protozero/message_handle.h"
|
||||
#include "perfetto/protozero/scattered_heap_buffer.h"
|
||||
#include "perfetto/protozero/scattered_stream_writer.h"
|
||||
#include "trace-writer.hh"
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <unordered_map>
|
||||
|
||||
template<>
|
||||
struct std::hash<nix::tracing::InternedPos>
|
||||
{
|
||||
size_t operator()(const nix::tracing::InternedPos p) const
|
||||
{
|
||||
return std::hash<uint32_t>()(p.key);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct std::hash<nix::tracing::InternedName>
|
||||
{
|
||||
size_t operator()(const nix::tracing::InternedName p) const
|
||||
{
|
||||
return std::hash<uint32_t>()(p.key);
|
||||
}
|
||||
};
|
||||
|
||||
namespace nix::tracing {
|
||||
|
||||
using namespace perfetto::protos::pbzero;
|
||||
|
||||
struct ProtoInternedPos
|
||||
{
|
||||
uint32_t key;
|
||||
|
||||
explicit ProtoInternedPos(uint32_t key) : key(key) {}
|
||||
ProtoInternedPos() = delete;
|
||||
};
|
||||
|
||||
struct ProtoInternedName
|
||||
{
|
||||
uint32_t key;
|
||||
|
||||
explicit ProtoInternedName(uint32_t key) : key(key) {}
|
||||
ProtoInternedName() = delete;
|
||||
};
|
||||
|
||||
struct TraceWriter::Impl
|
||||
{
|
||||
std::unique_ptr<InternedRetriever> retriever_;
|
||||
protozero::ScatteredHeapBuffer buf_;
|
||||
protozero::ScatteredStreamWriter writer_;
|
||||
protozero::MessageArena arena_;
|
||||
|
||||
Trace trace_;
|
||||
protozero::MessageHandle<Trace> traceHandle_;
|
||||
|
||||
std::unordered_map<InternedPos, ProtoInternedPos> posMap_;
|
||||
uint64_t posIid_ = 1;
|
||||
|
||||
std::unordered_map<InternedName, ProtoInternedName> nameMap_;
|
||||
uint64_t nameIid_ = 1;
|
||||
|
||||
auto getName(InternedName name, std::optional<std::string> &outName) -> ProtoInternedName;
|
||||
|
||||
auto getPos(InternedPos pos, InternedName funcName, std::optional<TracePos> &outPos) -> ProtoInternedPos;
|
||||
|
||||
Impl(std::unique_ptr<InternedRetriever> retriever)
|
||||
: retriever_(std::move(retriever))
|
||||
, writer_(&this->buf_)
|
||||
, traceHandle_(&this->trace_)
|
||||
{
|
||||
buf_.set_writer(&this->writer_);
|
||||
trace_.Reset(&this->writer_, &this->arena_);
|
||||
|
||||
auto p = protozero::MessageHandle<TracePacket>(trace_.add_packet());
|
||||
auto td = protozero::MessageHandle<TrackDescriptor>(p->set_track_descriptor());
|
||||
td->set_name("track");
|
||||
td->set_uuid(1);
|
||||
|
||||
p->set_trusted_packet_sequence_id(1337);
|
||||
p->set_sequence_flags(perfetto_pbzero_enum_TracePacket::SEQ_INCREMENTAL_STATE_CLEARED);
|
||||
p->set_previous_packet_dropped(true);
|
||||
p->set_first_packet_on_sequence(true);
|
||||
}
|
||||
};
|
||||
|
||||
auto TraceWriter::Impl::getName(InternedName name, std::optional<std::string> &outName) -> ProtoInternedName
|
||||
{
|
||||
if (auto it = nameMap_.find(name); it != nameMap_.end()) {
|
||||
// one already there, return it
|
||||
return it->second;
|
||||
} else {
|
||||
auto nameStr = retriever_->getName(name);
|
||||
outName = nameStr;
|
||||
|
||||
auto newIid = ++nameIid_;
|
||||
nameMap_.insert(std::make_pair(name, newIid));
|
||||
return ProtoInternedName(newIid);
|
||||
}
|
||||
}
|
||||
|
||||
auto TraceWriter::Impl::getPos(InternedPos pos, InternedName funcName, std::optional<TracePos> &outPos) -> ProtoInternedPos
|
||||
{
|
||||
if (auto it = posMap_.find(pos); it != posMap_.end()) {
|
||||
// one already there, return it
|
||||
return it->second;
|
||||
} else {
|
||||
auto nameRetrieved = retriever_->getName(funcName);
|
||||
auto posResolved = retriever_->getPos(pos, nameRetrieved);
|
||||
outPos = posResolved;
|
||||
|
||||
auto newIid = ++posIid_;
|
||||
posMap_.insert(std::make_pair(pos, newIid));
|
||||
return ProtoInternedPos(newIid);
|
||||
}
|
||||
}
|
||||
|
||||
TraceWriter::TraceWriter(std::unique_ptr<InternedRetriever> retriever)
|
||||
: impl_(std::make_unique<Impl>(std::move(retriever)))
|
||||
{
|
||||
}
|
||||
|
||||
TraceWriter::~TraceWriter() = default;
|
||||
|
||||
void TraceWriter::begin(InternedPos pos, InternedName name, Timestamp ts)
|
||||
{
|
||||
|
||||
std::optional<std::string> nameToIntern;
|
||||
std::optional<TracePos> posToIntern;
|
||||
|
||||
auto nameIid = impl_->getName(name, nameToIntern);
|
||||
auto posIid = impl_->getPos(pos, name, posToIntern);
|
||||
|
||||
auto packet = protozero::MessageHandle<TracePacket>(impl_->trace_.add_packet());
|
||||
|
||||
packet->set_sequence_flags(perfetto_pbzero_enum_TracePacket::SEQ_NEEDS_INCREMENTAL_STATE);
|
||||
|
||||
if (nameToIntern.has_value() || posToIntern.has_value()) {
|
||||
auto internedData = protozero::MessageHandle<InternedData>(packet->set_interned_data());
|
||||
|
||||
if (nameToIntern.has_value()) {
|
||||
auto evName = protozero::MessageHandle<EventName>(internedData->add_event_names());
|
||||
evName->set_name(*nameToIntern);
|
||||
evName->set_iid(nameIid.key);
|
||||
}
|
||||
|
||||
if (posToIntern.has_value()) {
|
||||
auto sourceLoc = protozero::MessageHandle<SourceLocation>(internedData->add_source_locations());
|
||||
sourceLoc->set_iid(posIid.key);
|
||||
sourceLoc->set_file_name(posToIntern->fileName);
|
||||
sourceLoc->set_function_name(posToIntern->functionName);
|
||||
sourceLoc->set_line_number(posToIntern->lineNumber);
|
||||
}
|
||||
}
|
||||
|
||||
packet->set_timestamp(ts.monotonic_nanos);
|
||||
packet->set_trusted_packet_sequence_id(1337);
|
||||
auto te = protozero::MessageHandle<TrackEvent>(packet->set_track_event());
|
||||
te->set_type(perfetto_pbzero_enum_TrackEvent::TYPE_SLICE_BEGIN);
|
||||
te->set_name_iid(nameIid.key);
|
||||
te->set_source_location_iid(posIid.key);
|
||||
|
||||
// TODO: make a real value
|
||||
te->set_track_uuid(1);
|
||||
|
||||
// te->set_name_iid(nameIid.key);
|
||||
// te->set_name("meow");
|
||||
// TODO: te->set_source_location_iid();
|
||||
}
|
||||
|
||||
void TraceWriter::end(Timestamp ts)
|
||||
{
|
||||
protozero::MessageHandle<TracePacket> tp(impl_->trace_.add_packet());
|
||||
tp->set_timestamp(ts.monotonic_nanos);
|
||||
tp->set_trusted_packet_sequence_id(1337);
|
||||
|
||||
protozero::MessageHandle<TrackEvent> te(tp->set_track_event());
|
||||
te->set_type(perfetto_pbzero_enum_TrackEvent::TYPE_SLICE_END);
|
||||
te->set_track_uuid(1);
|
||||
}
|
||||
|
||||
auto TraceWriter::splat() const -> std::vector<uint8_t>
|
||||
{
|
||||
impl_->traceHandle_->Finalize();
|
||||
return impl_->buf_.StitchSlices();
|
||||
}
|
||||
|
||||
}
|
67
src/libtracing/trace-writer.hh
Normal file
67
src/libtracing/trace-writer.hh
Normal file
|
@ -0,0 +1,67 @@
|
|||
#pragma once
|
||||
///@file
|
||||
|
||||
#include <stddef.h>
|
||||
#include <memory>
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace nix::tracing {
|
||||
|
||||
struct InternedPos
|
||||
{
|
||||
uint32_t key;
|
||||
|
||||
auto operator<=>(InternedPos const & other) const = default;
|
||||
explicit InternedPos(uint32_t key) : key(key) {}
|
||||
};
|
||||
|
||||
struct InternedName
|
||||
{
|
||||
uint32_t key;
|
||||
|
||||
auto operator<=>(InternedName const & other) const = default;
|
||||
explicit InternedName(uint32_t key) : key(key) {}
|
||||
};
|
||||
|
||||
struct Timestamp
|
||||
{
|
||||
uint64_t monotonic_nanos;
|
||||
};
|
||||
|
||||
struct TracePos
|
||||
{
|
||||
std::string fileName;
|
||||
std::string functionName;
|
||||
uint32_t lineNumber;
|
||||
};
|
||||
|
||||
/** Abstract class that retrieves information about things if they are not
|
||||
* memoized already */
|
||||
struct InternedRetriever
|
||||
{
|
||||
virtual auto getName(InternedName idx) const -> std::string = 0;
|
||||
virtual auto getPos(InternedPos idx, std::string funcName) const -> TracePos = 0;
|
||||
|
||||
virtual ~InternedRetriever() = default;
|
||||
};
|
||||
|
||||
class TraceWriter
|
||||
{
|
||||
struct Impl;
|
||||
std::unique_ptr<Impl> impl_;
|
||||
public:
|
||||
TraceWriter(std::unique_ptr<InternedRetriever> retriever);
|
||||
|
||||
void begin(InternedPos pos, InternedName name, Timestamp ts);
|
||||
void end(Timestamp ts);
|
||||
|
||||
/** Splats the trace out into a buffer */
|
||||
auto splat() const -> std::vector<uint8_t>;
|
||||
|
||||
~TraceWriter();
|
||||
};
|
||||
|
||||
}
|
|
@ -5,6 +5,8 @@ subdir('libutil')
|
|||
subdir('libstore')
|
||||
# libfetchers depends on libstore
|
||||
subdir('libfetchers')
|
||||
# libtracing is self-contained
|
||||
subdir('libtracing')
|
||||
# libexpr depends on all of the above
|
||||
subdir('libexpr')
|
||||
# libmain depends on libutil and libstore
|
||||
|
|
Loading…
Reference in a new issue