Subastra
Loading...
Searching...
No Matches
scheduler.h
Go to the documentation of this file.
1#ifndef __H__SYSTEMS_SCHEDULER__
2#define __H__SYSTEMS_SCHEDULER__
3
4#include <stdio.h>
5
6#include "../list.h"
7#include "../names.h"
8#include "require.h"
9
10typedef void (*system_runner_f)(system_req_t payload,
11 allocator_t temporary_allocator);
12
16
21
35
37 allocator_t persistent_allocator,
38 allocator_t temporary_allocator) {
39 scheduler_t ret;
40
41 ret.temporary_allocator = temporary_allocator;
42 ret.persistent_allocator = persistent_allocator;
43
44 ret.strategy = strategy;
45 ret.is_requirement_list_set = false;
46 ret.is_ticked = false;
47 ret.is_running = false;
48
49 ret.scheduler_systems = allocator_alloc_ty(list_t, ret.persistent_allocator,
51
52 for (int i = 0; i < SYSTEM_PHASE_count; i++) {
55 }
56
57 return ret;
58}
59
60static void scheduler_add_system(scheduler_t *scheduler, system_req_t req,
61 system_runner_f runner) {
62 scheduler_system_t system;
63 system.runner = runner;
64 system.reqs = req;
65
66 list_push_var(&scheduler->scheduler_systems[req.phase], system);
67
68 scheduler->is_schedule_planned = false;
69}
70
71#define scheduler_declare_system_with_custom_runner( \
72 scheduler, mut, cons, system_name, runner_f, deps_on, dependency_count, \
73 ...) \
74 name_t runner_f##_name = as_name(#system_name); \
75 do { \
76 system_req_t __system_req = __VA_ARGS__; \
77 __system_req.name = runner_f##_name; \
78 __system_req.depends_on = deps_on; \
79 __system_req.depends_on_count = dependency_count; \
80 system_req_entity_kinds_const(&__system_req, cons); \
81 system_req_entity_kinds_mut(&__system_req, mut); \
82 scheduler_add_system(scheduler, __system_req, runner_f); \
83 } while (0)
84
90#define scheduler_declare_system(scheduler, mut, cons, system_name, \
91 depends_on, dependency_count, ...) \
92 scheduler_declare_system_with_custom_runner( \
93 scheduler, mut, cons, system_name, system_##system_name, depends_on, \
94 dependency_count, __VA_ARGS__)
95
96static void scheduler_dump_dependency_graph(scheduler_t *scheduler, FILE *out) {
97 sz capacity = 0;
98 for (int phase_idx = 0; phase_idx < (int)SYSTEM_PHASE_count; phase_idx++)
99 capacity += scheduler->scheduler_systems[phase_idx].size;
100
102 list_t execution_order;
103 list_init_ty_with_capacity(name_t, &execution_order, alloc, capacity);
104
105 fprintf(out, "digraph G {\n\trankdir=\"TB\";\n");
106
107 for (int phase_idx = 0; phase_idx < (int)SYSTEM_PHASE_count; phase_idx++) {
108 list_t *sys_list = &scheduler->scheduler_systems[phase_idx];
109
110 if (sys_list->size == 0)
111 continue;
112
113 const char *sys_name_str = system_phase_to_str((system_phase_t)phase_idx);
114
115 fprintf(out,
116 "\tsubgraph cluster_%d {\n\t\tlabel = \"%s\";\n\t\tstyle = "
117 "filled;\n\t\tcolor = lightgrey;\n",
118 phase_idx, sys_name_str);
119
120 for (sz i = 0; i < sys_list->size; i++) {
121 scheduler_system_t *sys =
123
124 name_t name = sys->reqs.name;
125 const char *name_str = name_as_str(name);
126
127 fprintf(out, "\t\t%ld [label=\"%s #%ld\"];\n", name, name_str, i);
128
129 for (sz j = 0; j < sys->reqs.depends_on_count; j++) {
130 name_t dependency = sys->reqs.depends_on[j];
131 fprintf(out, "\t\t%ld -> %ld;\n", dependency, name);
132 }
133
134 list_push_var(&execution_order, name);
135 }
136
137 fprintf(out, "\t}\n");
138 }
139
140 fprintf(out, "\tstart [color = blue, shape = Mdiamond];\n");
141 fprintf(out, "\tend [color = blue, shape = Mdiamond];\n");
142 fprintf(out, "\t{ rank=\"source\"; \"start\";}\n");
143 fprintf(out, "\t{ rank=\"sink\"; \"end\";}\n");
144
145 fprintf(out, "\tstart -> %ld [color = blue];\n",
146 list_get_ty(name_t, &execution_order, 0));
147 for (sz i = 0; i < execution_order.size - 1; i++) {
148 name_t n1 = list_get_ty(name_t, &execution_order, i);
149 name_t n2 = list_get_ty(name_t, &execution_order, i + 1);
150
151 fprintf(out, "\t%ld -> %ld [color = blue];\n", n1, n2);
152 }
153
154 fprintf(out, "\t%ld -> end [color = blue];\n",
155 list_get_ty(name_t, &execution_order, execution_order.size - 1));
156
157 fprintf(out, "}\n");
158}
159
161 list_t *scheduler_system_list) {
162 ASSERT__(scheduler_system_list->_entry == sizeof(scheduler_system_t));
163
164 map_t coordinate_compression_forward;
165 map_init_ty(sz, &coordinate_compression_forward, alloc);
166 map_t coordinate_compression_reverse;
167 map_init_ty(sz, &coordinate_compression_reverse, alloc);
168
169 for (sz i = 0; i < scheduler_system_list->size; i++) {
170 name_t n = list_get_ty(name_t, scheduler_system_list, i);
171 if (!map_get(&coordinate_compression_forward, n)) {
172 map_insert_ty(sz, &coordinate_compression_forward, n,
173 &coordinate_compression_forward.size);
174 }
175 }
176
177 ASSERT__(coordinate_compression_forward.size == scheduler_system_list->size);
178 ASSERT__(coordinate_compression_reverse.size == scheduler_system_list->size);
179
180 map_cleanup(&coordinate_compression_forward);
181 map_cleanup(&coordinate_compression_reverse);
182}
183
184static void scheduler_plan(scheduler_t *scheduler) {
185 ASSERT_(!scheduler->is_running,
186 "Attempt to change plans while the scheduler is running");
187
188 scheduler->is_schedule_planned = true;
189}
190
192 system_req_t reqs) {
193 scheduler->requirements = reqs;
194 scheduler->is_requirement_list_set = true;
195}
196
199static void scheduler_tick(scheduler_t *scheduler, double delta_time) {
200 scheduler->requirements.delta_time = delta_time;
201 scheduler->is_ticked = true;
202}
203
204static void scheduler_begin_running(scheduler_t *scheduler) {
206 "The requirement list must be set before running");
207 ASSERT_(scheduler->is_schedule_planned,
208 "The scheduler must have planned the system order");
209 ASSERT_(scheduler->is_ticked,
210 "The scheduler must be ticked every time before running");
211 ASSERT_(!scheduler->is_running, "The scheduler is already running");
212
213 for (int phase_idx = 0; phase_idx < (int)SYSTEM_PHASE_count; phase_idx++) {
214 list_t *sys_list = &scheduler->scheduler_systems[phase_idx];
215
216 for (sz i = 0; i < sys_list->size; i++) {
217 scheduler_system_t *system =
219 system_req_fill_in(&system->reqs, scheduler->requirements);
220 }
221 }
222
223 scheduler->is_running = true;
224
225 for (int phase_idx = 0; phase_idx < (int)SYSTEM_PHASE_count; phase_idx++) {
226 list_t *sys_list = &scheduler->scheduler_systems[phase_idx];
227
228 for (sz i = 0; i < sys_list->size; i++) {
229 scheduler_system_t *system =
231 system->runner(system->reqs, scheduler->temporary_allocator);
232 }
233 }
234}
235
236static void scheduler_end_running(scheduler_t *scheduler) {
237 scheduler->is_running = false;
238 scheduler->is_ticked = false;
239}
240
241#endif
#define ASSERT__(expr)
Definition defs.h:21
size_t sz
Definition defs.h:51
#define ASSERT_(expr, msg)
Definition defs.h:29
#define list_get_ty_ptr(ty, ls, idx)
Definition list.h:128
#define list_init_ty(ty, ls, alloc)
Definition list.h:36
#define list_get_ty(ty, ls, idx)
Definition list.h:130
#define list_init_ty_with_capacity(ty, ls, alloc, capacity)
Definition list.h:38
#define list_push_var(ls, var)
Definition list.h:83
#define map_insert_ty(ty, map, key, data)
Definition map.h:196
static allocator_t allocator_new_stack_alloc()
Definition memory.h:113
static const char * name_as_str(name_t name)
Definition names.h:51
u64 name_t
Definition names.h:14
static void system_req_fill_in(system_req_t *target, const system_req_t parent)
Definition require.h:87
static const char * system_phase_to_str(system_phase_t phase)
Definition require.h:21
system_phase_t
Definition require.h:10
@ SYSTEM_PHASE_count
Definition require.h:18
static void scheduler_dump_dependency_graph(scheduler_t *scheduler, FILE *out)
Definition scheduler.h:96
static void scheduler_add_system(scheduler_t *scheduler, system_req_t req, system_runner_f runner)
Definition scheduler.h:60
void(* system_runner_f)(system_req_t payload, allocator_t temporary_allocator)
Definition scheduler.h:10
scheduler_strategy_t
Definition scheduler.h:13
@ SCHEDULER_STRATEGY_RANDOM
Definition scheduler.h:14
static void scheduler_tick(scheduler_t *scheduler, double delta_time)
Definition scheduler.h:199
static void scheduler_end_running(scheduler_t *scheduler)
Definition scheduler.h:236
static void scheduler_set_requirements(scheduler_t *scheduler, system_req_t reqs)
Definition scheduler.h:191
static scheduler_t scheduler_new(scheduler_strategy_t strategy, allocator_t persistent_allocator, allocator_t temporary_allocator)
Definition scheduler.h:36
static void scheduler_plan(scheduler_t *scheduler)
Definition scheduler.h:184
static void scheduler_begin_running(scheduler_t *scheduler)
Definition scheduler.h:204
static void scheduler__topological_sort(allocator_t alloc, list_t *scheduler_system_list)
Definition scheduler.h:160
A generic allocator type passed by value. Contains a fallback allocator and a set of function pointer...
Definition memory.h:30
Definition list.h:13
sz size
Definition list.h:17
sz _entry
Definition list.h:15
Definition map.h:28
sz size
The amount of elements currently in the map.
Definition map.h:38
Definition scheduler.h:17
system_runner_f runner
Definition scheduler.h:19
system_req_t reqs
Definition scheduler.h:18
Definition scheduler.h:22
list_t * scheduler_systems
Definition scheduler.h:33
system_req_t requirements
Definition scheduler.h:32
allocator_t temporary_allocator
Definition scheduler.h:24
bool is_requirement_list_set
Definition scheduler.h:27
bool is_schedule_planned
Definition scheduler.h:28
bool is_running
Definition scheduler.h:30
scheduler_strategy_t strategy
Definition scheduler.h:25
allocator_t persistent_allocator
Definition scheduler.h:23
bool is_ticked
Definition scheduler.h:29
Definition require.h:51
name_t name
Definition require.h:53
system_phase_t phase
Definition require.h:52
u32 depends_on_count
Definition require.h:58
double delta_time
Definition require.h:65
name_t * depends_on
Definition require.h:57