Add foundation tracing and platform build wrapper

This commit is contained in:
2026-05-31 23:51:41 +02:00
parent e0ea4597e6
commit ec5ecbdb54
10 changed files with 376 additions and 13 deletions

98
src/foundation/trace.cpp Normal file
View File

@@ -0,0 +1,98 @@
#include "foundation/trace.h"
#include <limits>
namespace pp::foundation {
Result<TraceSpanId> TraceRecorder::begin_span(TraceSpanDesc desc, std::uint64_t start_us)
{
if (desc.component.empty()) {
return Result<TraceSpanId>::failure(
Status::invalid_argument("trace component must not be empty"));
}
if (desc.name.empty()) {
return Result<TraceSpanId>::failure(
Status::invalid_argument("trace span name must not be empty"));
}
if (next_id_ == std::numeric_limits<TraceSpanId>::max()) {
return Result<TraceSpanId>::failure(
Status::out_of_range("trace span id space is exhausted"));
}
const auto id = next_id_++;
ActiveSpan span;
span.id = id;
span.component.assign(desc.component);
span.name.assign(desc.name);
span.desc = desc;
span.desc.component = span.component;
span.desc.name = span.name;
span.start_us = start_us;
span.active = true;
active_spans_.push_back(span);
return Result<TraceSpanId>::success(id);
}
Status TraceRecorder::end_span(TraceSpanId id, std::uint64_t end_us)
{
ActiveSpan* span = find_active_span(id);
if (span == nullptr) {
return Status::out_of_range("trace span id is not active");
}
if (end_us < span->start_us) {
return Status::invalid_argument("trace span cannot end before it starts");
}
TraceEvent event;
event.component = span->component;
event.name = span->name;
event.thread_id = span->desc.thread_id;
event.frame_id = span->desc.frame_id;
event.stroke_id = span->desc.stroke_id;
event.start_us = span->start_us;
event.duration_us = end_us - span->start_us;
events_.push_back(event);
span->active = false;
return Status::success();
}
std::span<const TraceEvent> TraceRecorder::events() const noexcept
{
return events_;
}
std::size_t TraceRecorder::active_span_count() const noexcept
{
std::size_t count = 0;
for (const auto& span : active_spans_) {
if (span.active) {
++count;
}
}
return count;
}
void TraceRecorder::clear() noexcept
{
active_spans_.clear();
events_.clear();
next_id_ = 1;
}
TraceRecorder::ActiveSpan* TraceRecorder::find_active_span(TraceSpanId id) noexcept
{
for (auto& span : active_spans_) {
if (span.active && span.id == id) {
return &span;
}
}
return nullptr;
}
}

60
src/foundation/trace.h Normal file
View File

@@ -0,0 +1,60 @@
#pragma once
#include "foundation/result.h"
#include <cstdint>
#include <span>
#include <string>
#include <string_view>
#include <vector>
namespace pp::foundation {
using TraceSpanId = std::uint64_t;
struct TraceSpanDesc {
std::string_view component;
std::string_view name;
std::uint64_t thread_id = 0;
std::uint64_t frame_id = 0;
std::uint64_t stroke_id = 0;
};
struct TraceEvent {
std::string component;
std::string name;
std::uint64_t thread_id = 0;
std::uint64_t frame_id = 0;
std::uint64_t stroke_id = 0;
std::uint64_t start_us = 0;
std::uint64_t duration_us = 0;
};
class TraceRecorder {
public:
[[nodiscard]] Result<TraceSpanId> begin_span(TraceSpanDesc desc, std::uint64_t start_us);
[[nodiscard]] Status end_span(TraceSpanId id, std::uint64_t end_us);
[[nodiscard]] std::span<const TraceEvent> events() const noexcept;
[[nodiscard]] std::size_t active_span_count() const noexcept;
void clear() noexcept;
private:
struct ActiveSpan {
TraceSpanId id = 0;
TraceSpanDesc desc;
std::string component;
std::string name;
std::uint64_t start_us = 0;
bool active = false;
};
[[nodiscard]] ActiveSpan* find_active_span(TraceSpanId id) noexcept;
std::vector<ActiveSpan> active_spans_;
std::vector<TraceEvent> events_;
TraceSpanId next_id_ = 1;
};
}