From c2695483723aa995d16392dd988b8cc0ca1bffdb Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Thu, 24 Nov 2022 22:00:34 +0000 Subject: [PATCH] Flatten list of pending events --- src/cgen.c | 4 +- src/jit/jit-exits.c | 18 ++-- src/jit/jit-exits.h | 4 +- src/jit/jit-irgen.c | 4 +- src/rt/model.c | 213 +++++++++++++++++++++++--------------------- src/rt/rt.h | 2 +- src/rt/structs.h | 22 ++--- 7 files changed, 138 insertions(+), 129 deletions(-) diff --git a/src/cgen.c b/src/cgen.c index 1f36d7e5..b18e14fb 100644 --- a/src/cgen.c +++ b/src/cgen.c @@ -2451,7 +2451,7 @@ static void cgen_op_sched_event(int op, cgen_ctx_t *ctx) LLVMBuildExtractValue(builder, sigptr, 0, "sid"), LLVMBuildExtractValue(builder, sigptr, 1, "offset"), cgen_get_arg(op, 1, ctx), - llvm_int1(false), + llvm_int1(true), LLVMConstNull(LLVMPointerType(llvm_signal_shared_struct(), 0)), }; LLVMBuildCall(builder, llvm_fn("_sched_event"), args, ARRAY_LEN(args), ""); @@ -2471,7 +2471,7 @@ static void cgen_op_sched_static(int op, cgen_ctx_t *ctx) LLVMBuildExtractValue(builder, sigptr, 0, "sid"), LLVMBuildExtractValue(builder, sigptr, 1, "offset"), cgen_get_arg(op, 1, ctx), - llvm_int1(true), + llvm_int1(false), wakeptr }; LLVMBuildCall(builder, llvm_fn("_sched_event"), args, ARRAY_LEN(args), ""); diff --git a/src/jit/jit-exits.c b/src/jit/jit-exits.c index 262d36de..41d04828 100644 --- a/src/jit/jit-exits.c +++ b/src/jit/jit-exits.c @@ -702,13 +702,13 @@ void __nvc_do_exit(jit_exit_t which, jit_anchor_t *anchor, jit_scalar_t *args) case JIT_EXIT_SCHED_EVENT: { - sig_shared_t *shared = args[0].pointer; - int32_t offset = args[1].integer; - int32_t count = args[2].integer; - int8_t recur = args[3].integer; - sig_shared_t *wake = args[4].pointer; + sig_shared_t *shared = args[0].pointer; + int32_t offset = args[1].integer; + int32_t count = args[2].integer; + int8_t oneshot = args[3].integer; + sig_shared_t *wake = args[4].pointer; - x_sched_event(shared, offset, count, recur, wake); + x_sched_event(shared, offset, count, oneshot, wake); } break; @@ -1255,10 +1255,10 @@ void _sched_waveform(sig_shared_t *ss, uint32_t offset, void *values, } DLLEXPORT -void _sched_event(sig_shared_t *ss, uint32_t offset, int32_t count, bool recur, - sig_shared_t *wake_ss) +void _sched_event(sig_shared_t *ss, uint32_t offset, int32_t count, + bool oneshot, sig_shared_t *wake_ss) { - x_sched_event(ss, offset, count, recur, wake_ss); + x_sched_event(ss, offset, count, oneshot, wake_ss); } DLLEXPORT diff --git a/src/jit/jit-exits.h b/src/jit/jit-exits.h index d7de562e..d03c7983 100644 --- a/src/jit/jit-exits.h +++ b/src/jit/jit-exits.h @@ -34,8 +34,8 @@ void x_sched_waveform(sig_shared_t *ss, uint32_t offset, void *values, int32_t x_test_net_event(sig_shared_t *ss, uint32_t offset, int32_t count); int32_t x_test_net_active(sig_shared_t *ss, uint32_t offset, int32_t count); -void x_sched_event(sig_shared_t *ss, uint32_t offset, int32_t count, bool recur, - sig_shared_t *wake_ss); +void x_sched_event(sig_shared_t *ss, uint32_t offset, int32_t count, + bool oneshot, sig_shared_t *wake_ss); void x_alias_signal(sig_shared_t *ss, tree_t where); int64_t x_now(void); int x_current_delta(void); diff --git a/src/jit/jit-irgen.c b/src/jit/jit-irgen.c index 1d7ed09d..3aedae5f 100644 --- a/src/jit/jit-irgen.c +++ b/src/jit/jit-irgen.c @@ -2933,7 +2933,7 @@ static void irgen_op_sched_event(jit_irgen_t *g, int op) j_send(g, 0, shared); j_send(g, 1, offset); j_send(g, 2, count); - j_send(g, 3, jit_value_from_int64(false)); + j_send(g, 3, jit_value_from_int64(true)); j_send(g, 4, jit_null_ptr()); macro_exit(g, JIT_EXIT_SCHED_EVENT); } @@ -2951,7 +2951,7 @@ static void irgen_op_sched_static(jit_irgen_t *g, int op) j_send(g, 0, shared); j_send(g, 1, offset); j_send(g, 2, count); - j_send(g, 3, jit_value_from_int64(true)); + j_send(g, 3, jit_value_from_int64(false)); j_send(g, 4, wake); macro_exit(g, JIT_EXIT_SCHED_EVENT); } diff --git a/src/rt/model.c b/src/rt/model.c index 8d676aec..ed42cc5e 100644 --- a/src/rt/model.c +++ b/src/rt/model.c @@ -73,7 +73,6 @@ typedef struct _rt_model { heap_t *eventq_heap; ihash_t *res_memo; rt_alloc_stack_t event_stack; - rt_alloc_stack_t sens_list_stack; rt_alloc_stack_t watch_stack; rt_alloc_stack_t callback_stack; rt_watch_t *watches; @@ -400,10 +399,9 @@ rt_model_t *model_new(tree_t top, jit_t *jit) m->can_create_delta = true; - m->event_stack = rt_alloc_stack_new(sizeof(event_t), "event"); - m->sens_list_stack = rt_alloc_stack_new(sizeof(sens_list_t), "sens_list"); - m->watch_stack = rt_alloc_stack_new(sizeof(rt_watch_t), "watch"); - m->callback_stack = rt_alloc_stack_new(sizeof(callback_t), "callback"); + m->event_stack = rt_alloc_stack_new(sizeof(event_t), "event"); + m->watch_stack = rt_alloc_stack_new(sizeof(rt_watch_t), "watch"); + m->callback_stack = rt_alloc_stack_new(sizeof(callback_t), "callback"); m->root = xcalloc(sizeof(rt_scope_t)); m->root->kind = SCOPE_ROOT; @@ -451,13 +449,12 @@ static void free_waveform(waveform_t *w) free_waveforms = w; } -static void free_sens_list(rt_model_t *m, sens_list_t **l) +static void cleanup_net(rt_net_t *net) { - for (sens_list_t *it = *l, *tmp; it; it = tmp) { - tmp = it->next; - rt_free(m->sens_list_stack, it); + if (net->pending != NULL) { + free(net->pending); + net->pending = NULL; } - *l = NULL; } static void cleanup_nexus(rt_model_t *m, rt_nexus_t *n) @@ -485,7 +482,7 @@ static void cleanup_nexus(rt_model_t *m, rt_nexus_t *n) } if (n->net != NULL) - free_sens_list(m, &(n->net->pending)); + cleanup_net(n->net); } static void cleanup_signal(rt_model_t *m, rt_signal_t *s) @@ -571,7 +568,6 @@ void model_free(rt_model_t *m) } rt_alloc_stack_destroy(m->event_stack); - rt_alloc_stack_destroy(m->sens_list_stack); rt_alloc_stack_destroy(m->watch_stack); rt_alloc_stack_destroy(m->callback_stack); @@ -1309,14 +1305,15 @@ static rt_nexus_t *clone_nexus(rt_model_t *m, rt_nexus_t *old, int offset, new_net->active_delta = old_net->active_delta; new_net->event_delta = old_net->event_delta; - for (sens_list_t *l = old_net->pending; l; l = l->next) { - sens_list_t *lnew = rt_alloc(m->sens_list_stack); - lnew->wake = l->wake; - lnew->wakeup_gen = l->wakeup_gen; - lnew->recur = l->recur; - lnew->next = new_net->pending; + new_net->pend0 = old_net->pend0; + + if (old_net->npending > 0) { + new_net->npending = new_net->maxpend = old_net->npending; + new_net->pending = + xmalloc_array(new_net->maxpend, sizeof(rt_pending_t)); - new_net->pending = lnew; + for (int i = 0; i < old_net->npending; i++) + new_net->pending[i] = old_net->pending[i]; } new->net = net = new_net; @@ -1962,31 +1959,42 @@ static bool is_stale_event(event_t *e) && (e->proc.wakeup_gen != e->proc.proc->wakeable.wakeup_gen); } -static void sched_event(rt_model_t *m, sens_list_t **list, - rt_wakeable_t *obj, bool recur) +static bool is_stale_pending_entry(rt_pending_t *p, rt_wakeable_t *obj) { - // See if there is already a stale entry in the pending list for this - // object - sens_list_t *it = *list; - int count = 0; - for (; it != NULL; it = it->next, ++count) { - if ((it->wake == obj) && (it->wakeup_gen != obj->wakeup_gen)) - break; - } - - if (it == NULL) { - sens_list_t *node = rt_alloc(m->sens_list_stack); - node->wake = obj; - node->wakeup_gen = obj->wakeup_gen; - node->next = *list; - node->recur = recur; + return p->wake == NULL + || (p->wake == obj && p->wakeup_gen != obj->wakeup_gen); +} - *list = node; - } +static void sched_event(rt_model_t *m, rt_net_t *net, + rt_wakeable_t *obj, bool oneshot) +{ + rt_pending_t *p = NULL; + if (is_stale_pending_entry(&(net->pend0), obj)) + p = &(net->pend0); else { - // Reuse the stale entry - it->wakeup_gen = obj->wakeup_gen; + // See if there is already a stale entry in the pending list for this + // object + for (int i = 0; i < net->npending; i++) { + if (is_stale_pending_entry(&(net->pending[i]), obj)) { + p = &(net->pending[i]); + break; + } + } + + if (p == NULL) { + if (net->npending == net->maxpend) { + net->maxpend = MAX(4, net->maxpend * 2); + net->pending = xrealloc_array(net->pending, net->maxpend, + sizeof(rt_pending_t)); + } + + p = &(net->pending[net->npending++]); + } } + + p->wake = obj; + p->wakeup_gen = obj->wakeup_gen; + p->oneshot = oneshot; } static rt_source_t *find_driver(rt_nexus_t *nexus) @@ -2119,71 +2127,70 @@ static void async_run_process(void *context, void *arg) run_process(m, proc); } -static void notify_event(rt_model_t *m, rt_net_t *net) +static void wakeup_one(rt_model_t *m, rt_pending_t *p) { - net->last_event = net->last_active = m->now; - net->event_delta = net->active_delta = m->iteration; - - // Wake up everything on the pending list - for (sens_list_t *it = net->pending, *next, **reenq = &(net->pending); - it; it = next) { - next = it->next; + // To avoid having each process keep a list of the signals it is + // sensitive to, each process has a "wakeup generation" number + // which is incremented after each wait statement and stored in + // the signal sensitivity list. We then ignore any sensitivity + // list elements where the generation doesn't match the current + // process wakeup generation: these correspond to stale "wait on" + // statements that have already resumed. + const bool stale = p->oneshot && p->wakeup_gen != p->wake->wakeup_gen; - // To avoid having each process keep a list of the signals it is - // sensitive to, each process has a "wakeup generation" number - // which is incremented after each wait statement and stored in - // the signal sensitivity list. We then ignore any sensitivity - // list elements where the generation doesn't match the current - // process wakeup generation: these correspond to stale "wait on" - // statements that have already resumed. - const bool stale = !it->recur && it->wakeup_gen != it->wake->wakeup_gen; - - if (!stale && !it->wake->pending) { - workq_t *wq = it->wake->postponed ? m->postponedq : m->procq; - - switch (it->wake->kind) { - case W_PROC: - { - rt_proc_t *proc = container_of(it->wake, rt_proc_t, wakeable); - TRACE("wakeup %sprocess %s", - it->wake->postponed ? "postponed " : "", istr(proc->name)); - workq_do(wq, async_run_process, proc); - } - break; + if (!stale && !p->wake->pending) { + workq_t *wq = p->wake->postponed ? m->postponedq : m->procq; - case W_IMPLICIT: - { - rt_implicit_t *imp = - container_of(it->wake, rt_implicit_t, wakeable); - TRACE("wakeup %svalue change callback %s", - it->wake->postponed ? "postponed " : "", - istr(jit_get_name(m->jit, imp->closure.handle))); - workq_do(m->implicitq, async_update_implicit_signal, imp); - } - break; + switch (p->wake->kind) { + case W_PROC: + { + rt_proc_t *proc = container_of(p->wake, rt_proc_t, wakeable); + TRACE("wakeup %sprocess %s", p->wake->postponed ? "postponed " : "", + istr(proc->name)); + workq_do(wq, async_run_process, proc); + } + break; - case W_WATCH: - { - rt_watch_t *w = container_of(it->wake, rt_watch_t, wakeable); - TRACE("wakeup implicit signal %s", - istr(tree_ident(w->signal->where))); - workq_do(wq, async_watch_callback, w); - } - break; + case W_IMPLICIT: + { + rt_implicit_t *imp = container_of(p->wake, rt_implicit_t, wakeable); + TRACE("wakeup %svalue change callback %s", + p->wake->postponed ? "postponed " : "", + istr(jit_get_name(m->jit, imp->closure.handle))); + workq_do(m->implicitq, async_update_implicit_signal, imp); } + break; - ++(it->wake->wakeup_gen); - it->wake->pending = true; + case W_WATCH: + { + rt_watch_t *w = container_of(p->wake, rt_watch_t, wakeable); + TRACE("wakeup implicit signal %s", + istr(tree_ident(w->signal->where))); + workq_do(wq, async_watch_callback, w); + } + break; } - if (it->recur) { - *reenq = it; - reenq = &(it->next); - } - else { - rt_free(m->sens_list_stack, it); - *reenq = NULL; - } + ++(p->wake->wakeup_gen); + p->wake->pending = true; + } + + if (p->oneshot) + p->wake = NULL; // Mark slot as empty +} + +static void notify_event(rt_model_t *m, rt_net_t *net) +{ + net->last_event = net->last_active = m->now; + net->event_delta = net->active_delta = m->iteration; + + if (net->pend0.wake != NULL) + wakeup_one(m, &(net->pend0)); + + for (int i = 0; i < net->npending; i++) { + rt_pending_t *p = &(net->pending[i]); + if (p->wake != NULL) + wakeup_one(m, p); } } @@ -2645,7 +2652,7 @@ rt_watch_t *model_set_event_cb(rt_model_t *m, rt_signal_t *s, sig_event_fn_t fn, rt_nexus_t *n = &(w->signal->nexus); for (int i = 0; i < s->n_nexus; i++, n = n->chain) - sched_event(m, &(get_net(m, n)->pending), &(w->wakeable), true); + sched_event(m, get_net(m, n), &(w->wakeable), false); return w; } @@ -2834,13 +2841,13 @@ int32_t x_test_net_active(sig_shared_t *ss, uint32_t offset, int32_t count) return 0; } -void x_sched_event(sig_shared_t *ss, uint32_t offset, int32_t count, bool recur, - sig_shared_t *wake_ss) +void x_sched_event(sig_shared_t *ss, uint32_t offset, int32_t count, + bool oneshot, sig_shared_t *wake_ss) { rt_signal_t *s = container_of(ss, rt_signal_t, shared); - TRACE("_sched_event %s+%d count=%d recur=%d proc %s", - istr(tree_ident(s->where)), offset, count, recur, + TRACE("_sched_event %s+%d count=%d oneshot=%d proc %s", + istr(tree_ident(s->where)), offset, count, oneshot, wake_ss ? "(implicit)" : istr(active_proc->name)); rt_wakeable_t *wake; @@ -2852,7 +2859,7 @@ void x_sched_event(sig_shared_t *ss, uint32_t offset, int32_t count, bool recur, rt_model_t *m = get_model(); rt_nexus_t *n = split_nexus(m, s, offset, count); for (; count > 0; n = n->chain) { - sched_event(m, &(get_net(m, n)->pending), wake, recur); + sched_event(m, get_net(m, n), wake, oneshot); count -= n->width; assert(count >= 0); diff --git a/src/rt/rt.h b/src/rt/rt.h index a337e9c6..7b7f0ba2 100644 --- a/src/rt/rt.h +++ b/src/rt/rt.h @@ -23,7 +23,7 @@ #include -#define RT_ABI_VERSION 6 +#define RT_ABI_VERSION 7 #define RT_ALIGN_MASK 0x7 #define TIME_HIGH INT64_MAX // Value of TIME'HIGH diff --git a/src/rt/structs.h b/src/rt/structs.h index b78354c3..47a123fd 100644 --- a/src/rt/structs.h +++ b/src/rt/structs.h @@ -99,20 +99,22 @@ struct waveform { STATIC_ASSERT(sizeof(rt_value_t) <= 24); -struct sens_list { +typedef struct { rt_wakeable_t *wake; - sens_list_t *next; uint32_t wakeup_gen; - bool recur; -}; + bool oneshot; +} rt_pending_t; typedef struct { - sens_list_t *pending; - uint64_t last_event; - uint64_t last_active; - int32_t event_delta; - int32_t active_delta; - uint32_t net_id; + rt_pending_t pend0; + rt_pending_t *pending; + uint64_t last_event; + uint64_t last_active; + int32_t event_delta; + int32_t active_delta; + uint32_t net_id; + uint32_t npending; + uint32_t maxpend; } rt_net_t; STATIC_ASSERT(sizeof(rt_net_t) <= 64); -- 2.39.2