threadman 0.1.0
Header-only C++23 managed threads, dynamic pools, futures, and executors
Loading...
Searching...
No Matches
json.hpp
Go to the documentation of this file.
1#pragma once
2
6
8
9#if !THREADMAN_WITH_NLOHMANN_JSON
10#error "threadman/json.hpp requires THREADMAN_WITH_NLOHMANN_JSON to be enabled"
11#endif
12
13#include <threadman/stats.hpp>
14
15#include <nlohmann/json.hpp>
16
17#include <chrono>
18
19namespace threadman {
20
22 {
23 {ThreadState::Starting, "starting"},
24 {ThreadState::Running, "running"},
25 {ThreadState::Idle, "idle"},
26 {ThreadState::Retiring, "retiring"},
27 {ThreadState::Completed, "completed"},
28 {ThreadState::Failed, "failed"},
29 })
30
32 {
33 {TaskState::Queued, "queued"},
34 {TaskState::Running, "running"},
35 {TaskState::Completed, "completed"},
36 {TaskState::Failed, "failed"},
37 {TaskState::Cancelled, "cancelled"},
38 })
39
41 {
42 {PoolState::Running, "running"},
43 {PoolState::ShuttingDown, "shutting_down"},
44 {PoolState::ShutdownNow, "shutdown_now"},
45 {PoolState::Terminated, "terminated"},
46 })
47
48inline void to_json(nlohmann::json& j, const ThreadSnapshot& s) {
49 j = nlohmann::json{
50 {"id", s.id},
51 {"name", s.name},
52 {"native_id", s.native_id},
53 {"state", s.state},
54 {"run_duration_ns", s.run_duration.count()},
55 {"failed", s.failed},
56 {"is_core", s.is_core},
57 };
58 if (s.pool_id.has_value()) {
59 j["pool_id"] = *s.pool_id;
60 }
61}
62inline void from_json(const nlohmann::json& j, ThreadSnapshot& s) {
63 j.at("id").get_to(s.id);
64 j.at("name").get_to(s.name);
65 j.at("native_id").get_to(s.native_id);
66 j.at("state").get_to(s.state);
67 long long ns = 0;
68 j.at("run_duration_ns").get_to(ns);
69 s.run_duration = std::chrono::nanoseconds{ns};
70 j.at("failed").get_to(s.failed);
71 j.at("is_core").get_to(s.is_core);
72 if (j.contains("pool_id")) {
73 s.pool_id = j.at("pool_id").get<std::uint64_t>();
74 } else {
75 s.pool_id.reset();
76 }
77}
78
79inline void to_json(nlohmann::json& j, const ThreadPoolStats& s) {
80 j = nlohmann::json{
81 {"pool_id", s.pool_id},
82 {"name", s.name},
83 {"state", s.state},
84 {"workers", s.workers},
85 {"core_workers", s.core_workers},
86 {"max_workers", s.max_workers},
87 {"active", s.active},
88 {"idle", s.idle},
89 {"queued", s.queued},
90 {"completed", s.completed},
91 {"failed", s.failed},
92 {"avg_execution_duration_ns", s.avg_execution_duration.count()},
93 {"scale_ups", s.scale_ups},
94 {"scale_downs", s.scale_downs},
95 };
96}
97inline void from_json(const nlohmann::json& j, ThreadPoolStats& s) {
98 j.at("pool_id").get_to(s.pool_id);
99 j.at("name").get_to(s.name);
100 j.at("state").get_to(s.state);
101 j.at("workers").get_to(s.workers);
102 j.at("core_workers").get_to(s.core_workers);
103 j.at("max_workers").get_to(s.max_workers);
104 j.at("active").get_to(s.active);
105 j.at("idle").get_to(s.idle);
106 j.at("queued").get_to(s.queued);
107 j.at("completed").get_to(s.completed);
108 j.at("failed").get_to(s.failed);
109 long long ns = 0;
110 j.at("avg_execution_duration_ns").get_to(ns);
111 s.avg_execution_duration = std::chrono::nanoseconds{ns};
112 j.at("scale_ups").get_to(s.scale_ups);
113 j.at("scale_downs").get_to(s.scale_downs);
114}
115
116namespace detail {
117
118template <class Clock>
119inline long long tp_to_ns(const std::chrono::time_point<Clock>& tp) {
120 return std::chrono::duration_cast<std::chrono::nanoseconds>(tp.time_since_epoch()).count();
121}
122
123template <class Clock>
124inline std::chrono::time_point<Clock> ns_to_tp(const long long ns) {
125 using TpDuration = typename Clock::duration;
126 return std::chrono::time_point<Clock>{
127 std::chrono::duration_cast<TpDuration>(std::chrono::nanoseconds{ns})};
128}
129
130} // namespace detail
131
132inline void to_json(nlohmann::json& j, const TaskSnapshot& s) {
133 j = nlohmann::json{
134 {"id", s.id},
135 {"pool_id", s.pool_id},
136 {"state", s.state},
137 {"created_at_ns", detail::tp_to_ns(s.created_at)},
138 {"failed", s.failed},
139 };
140 if (s.name.has_value()) {
141 j["name"] = *s.name;
142 }
143 if (s.started_at.has_value()) {
144 j["started_at_ns"] = detail::tp_to_ns(*s.started_at);
145 }
146 if (s.finished_at.has_value()) {
147 j["finished_at_ns"] = detail::tp_to_ns(*s.finished_at);
148 }
149}
150inline void from_json(const nlohmann::json& j, TaskSnapshot& s) {
151 j.at("id").get_to(s.id);
152 j.at("pool_id").get_to(s.pool_id);
153 j.at("state").get_to(s.state);
154 long long ns = 0;
155 j.at("created_at_ns").get_to(ns);
156 s.created_at = detail::ns_to_tp<std::chrono::steady_clock>(ns);
157 j.at("failed").get_to(s.failed);
158 if (j.contains("name")) {
159 s.name = j.at("name").get<std::string>();
160 } else {
161 s.name.reset();
162 }
163 if (j.contains("started_at_ns")) {
164 s.started_at =
165 detail::ns_to_tp<std::chrono::steady_clock>(j.at("started_at_ns").get<long long>());
166 } else {
167 s.started_at.reset();
168 }
169 if (j.contains("finished_at_ns")) {
170 s.finished_at =
171 detail::ns_to_tp<std::chrono::steady_clock>(j.at("finished_at_ns").get<long long>());
172 } else {
173 s.finished_at.reset();
174 }
175}
176
177inline void to_json(nlohmann::json& j, const FutureSnapshot& s) {
178 j = nlohmann::json{
179 {"ready", s.ready},
180 {"has_exception", s.has_exception},
181 {"continuation_count", s.continuation_count},
182 {"shared", s.shared},
183 };
184}
185inline void from_json(const nlohmann::json& j, FutureSnapshot& s) {
186 j.at("ready").get_to(s.ready);
187 j.at("has_exception").get_to(s.has_exception);
188 j.at("continuation_count").get_to(s.continuation_count);
189 j.at("shared").get_to(s.shared);
190}
191
192inline void to_json(nlohmann::json& j, const ManagerSummary& s) {
193 j = nlohmann::json{
194 {"wall_clock_ns", detail::tp_to_ns(s.wall_clock)},
195 {"live_threads", s.live_threads},
196 {"total_pools", s.total_pools},
197 {"total_live_workers", s.total_live_workers},
198 {"total_queued", s.total_queued},
199 {"total_completed", s.total_completed},
200 {"total_failed", s.total_failed},
201 {"per_pool_stats", s.per_pool_stats},
202 {"stuck_tasks", s.stuck_tasks},
203 };
204}
205inline void from_json(const nlohmann::json& j, ManagerSummary& s) {
206 long long ns = 0;
207 j.at("wall_clock_ns").get_to(ns);
208 s.wall_clock = detail::ns_to_tp<std::chrono::system_clock>(ns);
209 j.at("live_threads").get_to(s.live_threads);
210 j.at("total_pools").get_to(s.total_pools);
211 j.at("total_live_workers").get_to(s.total_live_workers);
212 j.at("total_queued").get_to(s.total_queued);
213 j.at("total_completed").get_to(s.total_completed);
214 j.at("total_failed").get_to(s.total_failed);
215 j.at("per_pool_stats").get_to(s.per_pool_stats);
216 j.at("stuck_tasks").get_to(s.stuck_tasks);
217}
218
219inline void to_json(nlohmann::json& j, const StuckTaskEvent& s) {
220 j = nlohmann::json{
221 {"task", s.task},
222 {"running_for_ns", s.running_for.count()},
223 {"pool_id", s.pool_id},
224 };
225}
226inline void from_json(const nlohmann::json& j, StuckTaskEvent& s) {
227 j.at("task").get_to(s.task);
228 long long ns = 0;
229 j.at("running_for_ns").get_to(ns);
230 s.running_for = std::chrono::nanoseconds{ns};
231 j.at("pool_id").get_to(s.pool_id);
232}
233
234} // namespace threadman
Central feature-gate header for ThreadMan's optional integrations and tunable defaults.
Definition exceptions.hpp:22
TaskState
Lifecycle state of a TaskHandle.
Definition stats.hpp:31
@ Completed
Body returned normally.
@ Running
Picked up by a worker; body executing.
@ Queued
Submitted, waiting for a worker.
@ Cancelled
Discarded before running (shutdown_now, etc.).
@ Failed
Body threw.
ThreadState
Lifecycle state of a ManagedThread / pool worker.
Definition stats.hpp:21
@ Completed
Body returned normally; thread joined or about to.
@ Retiring
Pool worker stop-requested; will exit on next loop check.
@ Running
User body is actively executing.
@ Starting
Constructed; user body not yet entered.
@ Failed
Body threw an exception; reason captured in ControlBlock.
@ Idle
Pool worker sleeping on the queue, no task.
NLOHMANN_JSON_SERIALIZE_ENUM(ThreadState, { {ThreadState::Starting, "starting"}, {ThreadState::Running, "running"}, {ThreadState::Idle, "idle"}, {ThreadState::Retiring, "retiring"}, {ThreadState::Completed, "completed"}, {ThreadState::Failed, "failed"}, }) NLOHMANN_JSON_SERIALIZE_ENUM(TaskState
PoolState
Lifecycle state of a ThreadPool.
Definition stats.hpp:40
@ ShuttingDown
shutdown() requested; draining queue, no new submits.
@ Running
Accepting submissions.
@ ShutdownNow
shutdown_now() requested; queue cancelled, workers stopping.
@ Terminated
All workers joined.
Plain value snapshots of the live state of the ThreadMan world — threads, pools, tasks,...