12#include <uni20/config.hpp>
17#include <fmt/format.h>
29 std::string
title{
"Async task registry"};
36template <
typename Value> [[nodiscard]] std::string task_registry_join_ids(std::vector<Value>
const& values)
38 if (values.empty())
return "-";
41 for (
auto const value : values)
43 if (!result.empty()) result +=
", ";
44 result += fmt::format(
"{}",
value);
49[[nodiscard]]
inline std::string task_registry_awaits(std::vector<TaskRegistryGraphAwaitDependency>
const& dependencies)
51 if (dependencies.empty())
return "-";
54 for (
auto const& dependency : dependencies)
56 if (!result.empty()) result +=
", ";
63[[nodiscard]]
inline std::string task_registry_task_source(TaskRegistryGraphTask
const& task)
65 if (task.state ==
"suspended" && !task.last_await_site.location.empty())
66 return "await: " + task.last_await_site.location;
67 if (!task.schedule_site.location.empty())
return "scheduled: " + task.schedule_site.location;
68 if (!task.creation_site.location.empty())
return "created: " + task.creation_site.location;
69 if (!task.creation_timestamp.empty())
return task.creation_timestamp;
73[[nodiscard]]
inline std::string task_registry_active_awaits(TaskRegistryGraphTask
const& task)
75 auto awaits = task_registry_awaits(task.await_dependencies);
76 if (task.waiting_on.empty())
return awaits;
77 return awaits ==
"-" ? task.waiting_on : fmt::format(
"{}; {}", awaits, task.waiting_on);
80[[nodiscard]]
inline std::string task_registry_data_state(TaskRegistryGraphDataNode
const& node,
81 TaskRegistryGraphDiagnostics
const& diagnostics)
83 std::string state = node.state;
84 if (std::ranges::find(diagnostics.missing_writer_node_ids, node.id) != diagnostics.missing_writer_node_ids.end())
85 state +=
"; missing writer";
86 if (std::ranges::find(diagnostics.cycle_node_ids, node.id) != diagnostics.cycle_node_ids.end())
87 state +=
"; dependency cycle";
91[[nodiscard]]
inline std::string task_registry_task_state(TaskRegistryGraphTask
const& task,
92 TaskRegistryGraphDiagnostics
const& diagnostics)
94 std::string state = task.state;
95 if (std::ranges::find(diagnostics.blocked_read_task_ids, task.id) != diagnostics.blocked_read_task_ids.end())
96 state +=
"; blocked read";
97 if (std::ranges::find(diagnostics.blocked_write_task_ids, task.id) != diagnostics.blocked_write_task_ids.end())
98 state +=
"; blocked write";
99 if (std::ranges::find(diagnostics.cycle_task_ids, task.id) != diagnostics.cycle_task_ids.end())
100 state +=
"; dependency cycle";
125 snapshot.
unavailable_reason.empty() ?
"snapshot unavailable" : snapshot.unavailable_reason);
150#if !UNI20_HAS_STACKTRACE
154 report.field(
"tracked async values", snapshot.
data_nodes.size())
155 .field(
"tracked epoch contexts", snapshot.
epochs.size())
156 .field(
"tracked coroutine tasks", snapshot.
tasks.size())
161 if (!diagnostics.
notes.empty())
163 auto&
table = report.table(
"Diagnostics");
165 for (
auto const& note : diagnostics.notes)
171 auto&
table = report.table(
"Async values");
178 for (
auto const& node : snapshot.data_nodes)
181 node.label.empty() ? fmt::format(
"data {}", node.id) :
fmt::format(
"data {}: {}", node.id, node.label);
182 table.
row(name, node.type.empty() ?
"-" : node.type, detail::task_registry_data_state(node, diagnostics),
183 node.
value.empty() ?
"-" : node.
value, node.storage_address.empty() ?
"-" : node.storage_address);
187 if (!snapshot.
epochs.empty())
189 auto&
table = report.table(
"Epoch contexts");
198 for (
auto const& epoch : snapshot.epochs)
200 auto const epoch_label = fmt::format(
"{} (gen {})", epoch.id, epoch.generation);
201 auto const phase = epoch.snapshot_available ? epoch.phase :
"snapshot unavailable";
202 auto const value = epoch.has_node ? fmt::format(
"data {}", epoch.node_id) :
"-";
203 auto const next = epoch.has_next_epoch ? fmt::format(
"epoch {}", epoch.next_epoch_id) :
"-";
204 auto const created = !epoch.creation_site.location.empty()
205 ? epoch.creation_site.location
206 : (!epoch.creation_timestamp.empty() ? epoch.creation_timestamp :
"-");
207 table.
row(epoch_label, phase,
value, detail::task_registry_join_ids(epoch.reader_task_ids),
208 detail::task_registry_join_ids(epoch.writer_task_ids), next, created);
212 if (!snapshot.
tasks.empty())
214 if (std::ranges::any_of(snapshot.
tasks, [](
auto const& task) { return !task.failure.empty(); }))
216 auto& failures = report.table(
"Coroutine failures");
219 for (
auto const& task : snapshot.tasks)
221 if (task.failure.empty())
continue;
223 task.label.empty() ? fmt::format(
"task {}", task.id) :
fmt::format(
"task {}: {}", task.id, task.label);
224 failures.row(name, task.failure);
228 auto&
table = report.table(
"Coroutine tasks");
236 for (
auto const& task : snapshot.tasks)
239 task.label.empty() ? fmt::format(
"task {}", task.id) :
fmt::format(
"task {}: {}", task.id, task.label);
240 auto dependencies = fmt::format(
"read: {}; write: {}", detail::task_registry_join_ids(task.read_dependencies),
241 detail::task_registry_join_ids(task.write_dependencies));
242 table.
row(name, detail::task_registry_task_state(task, diagnostics), task.transition_count, dependencies,
243 detail::task_registry_active_awaits(task), detail::task_registry_task_source(task));
void row(std::vector< formatted_cell > cells, std::source_location where=std::source_location::current())
Emit preformatted cells without discarding their numeric alignment semantics.
Definition display.cpp:448
streaming_table & column(std::string heading, column_width width_spec=width::share(), presentation::table_alignment alignment=presentation::table_alignment::right, column_format format={})
Builder for simple terminal reports with headings, status lines, fields, and tables.
Definition presentation.hpp:602
locale_t value
Definition data_table.cpp:49
streaming_table table(std::string title, stream destination)
Create a schema-first streaming display table.
Definition display.cpp:800
Definition async/async.hpp:26
presentation::report_builder task_registry_report(TaskRegistryGraphSnapshot const &snapshot, TaskRegistryGraphDiagnostics const &diagnostics, TaskRegistryReportOptions const &options={})
Build a presentation-native summary of one async task-registry snapshot.
Definition task_registry_presentation.hpp:115
Diagnostics derived from a structured task-registry graph snapshot.
Definition task_registry_snapshot.hpp:114
std::vector< std::size_t > cycle_task_ids
Definition task_registry_snapshot.hpp:118
std::vector< std::uint64_t > cycle_node_ids
Definition task_registry_snapshot.hpp:119
std::vector< std::size_t > blocked_write_task_ids
Definition task_registry_snapshot.hpp:117
std::vector< std::size_t > missing_writer_epoch_ids
Definition task_registry_snapshot.hpp:121
std::vector< std::size_t > blocked_read_task_ids
Definition task_registry_snapshot.hpp:116
std::vector< std::string > notes
Definition task_registry_snapshot.hpp:115
std::vector< std::uint64_t > missing_writer_node_ids
Definition task_registry_snapshot.hpp:120
std::vector< std::size_t > failed_task_ids
Definition task_registry_snapshot.hpp:122
Structured task-registry graph snapshot.
Definition task_registry_snapshot.hpp:104
std::vector< TaskRegistryGraphEpoch > epochs
Definition task_registry_snapshot.hpp:108
std::string unavailable_reason
Definition task_registry_snapshot.hpp:106
std::vector< TaskRegistryGraphDataNode > data_nodes
Definition task_registry_snapshot.hpp:107
bool snapshot_available
Definition task_registry_snapshot.hpp:105
std::vector< TaskRegistryGraphTask > tasks
Definition task_registry_snapshot.hpp:109
Options controlling an async task-registry summary report.
Definition task_registry_presentation.hpp:28
std::string reason
Definition task_registry_presentation.hpp:30
std::string title
Definition task_registry_presentation.hpp:29
Structured async task-registry graph snapshots and diagnostics.