From c1659a64c33df46bd313e8d1f07cdbfce2b5461c Mon Sep 17 00:00:00 2001 From: Giles Atkinson <“gatk555@gmail.com”> Date: Thu, 23 Feb 2023 17:56:40 +0000 Subject: [PATCH] Change output event setup in evtload.c so that, when making an event call to a code model, there is no longer a reference to the value of the event at the head of the free list. That allows all such free lists (with the same data type) to be combined, probably improving performance. This is in preparation for full implementation of inertial delay for digital nodes. --- src/include/ngspice/evt.h | 2 +- src/include/ngspice/evtproto.h | 1 + src/include/ngspice/evtudn.h | 26 +++--- src/include/ngspice/mifcmdat.h | 1 + src/xspice/evt/evtaccept.c | 7 +- src/xspice/evt/evtbackup.c | 7 +- src/xspice/evt/evtdest.c | 10 +- src/xspice/evt/evtinit.c | 3 +- src/xspice/evt/evtload.c | 126 +++++++++++--------------- src/xspice/evt/evtsetup.c | 56 +++++++++--- src/xspice/icm/xtraevt/int/udnfunc.c | 1 + src/xspice/icm/xtraevt/real/udnfunc.c | 1 + src/xspice/idn/idndig.c | 1 + 13 files changed, 124 insertions(+), 118 deletions(-) diff --git a/src/include/ngspice/evt.h b/src/include/ngspice/evt.h index 2917b76a5..7dfb35c27 100644 --- a/src/include/ngspice/evt.h +++ b/src/include/ngspice/evt.h @@ -172,7 +172,7 @@ struct Evt_Output_Queue { Evt_Output_Event_t **head; /* Beginning of linked lists */ Evt_Output_Event_t ***current; /* Beginning of pending events */ Evt_Output_Event_t ***last_step; /* Values of 'current' at last accepted timepoint */ - Evt_Output_Event_t **free; /* Linked lists of items freed by backups */ + Evt_Output_Event_t ***free_list; /* Pointers to linked lists of items freed by backups */ double last_time; /* Time at which last_step was set */ double next_time; /* Earliest next event time in queue */ int num_modified; /* Number modified since last accepted timepoint */ diff --git a/src/include/ngspice/evtproto.h b/src/include/ngspice/evtproto.h index 359133801..f37bb0fa7 100644 --- a/src/include/ngspice/evtproto.h +++ b/src/include/ngspice/evtproto.h @@ -134,5 +134,6 @@ bool Evtcheck_nodes( struct INPtables *stab); /* Symbol table. */ struct dvec *EVTfindvec(char *node); +void Evt_purge_free_outputs(void); #endif diff --git a/src/include/ngspice/evtudn.h b/src/include/ngspice/evtudn.h index 936c44daf..0e941a5b5 100644 --- a/src/include/ngspice/evtudn.h +++ b/src/include/ngspice/evtudn.h @@ -99,20 +99,22 @@ NON-STANDARD FEATURES void **evt_ipc_val, \ int *evt_ipc_val_size +/* Information about each Digital/User-defined type of node value. */ typedef struct { - char *name; - char *description; - void ((*create)(CREATE_ARGS)); - void ((*dismantle)(DISMANTLE_ARGS)); - void ((*initialize)(INITIALIZE_ARGS)); - void ((*invert)(INVERT_ARGS)); - void ((*copy)(COPY_ARGS)); - void ((*resolve)(RESOLVE_ARGS)); - void ((*compare)(COMPARE_ARGS)); - void ((*plot_val)(PLOT_VAL_ARGS)); - void ((*print_val)(PRINT_VAL_ARGS)); - void ((*ipc_val)(IPC_VAL_ARGS)); + char *name; + char *description; + Evt_Output_Event_t *free_list; /* Event structs for these values. */ + void ((*create)(CREATE_ARGS)); + void ((*dismantle)(DISMANTLE_ARGS)); + void ((*initialize)(INITIALIZE_ARGS)); + void ((*invert)(INVERT_ARGS)); + void ((*copy)(COPY_ARGS)); + void ((*resolve)(RESOLVE_ARGS)); + void ((*compare)(COMPARE_ARGS)); + void ((*plot_val)(PLOT_VAL_ARGS)); + void ((*print_val)(PRINT_VAL_ARGS)); + void ((*ipc_val)(IPC_VAL_ARGS)); } Evt_Udn_Info_t; diff --git a/src/include/ngspice/mifcmdat.h b/src/include/ngspice/mifcmdat.h index 213713c6c..4196c8ee0 100644 --- a/src/include/ngspice/mifcmdat.h +++ b/src/include/ngspice/mifcmdat.h @@ -226,6 +226,7 @@ typedef struct Mif_Port_Data_s { Mif_Boolean_t is_null; /* Set to true if null in SPICE deck */ Mif_Value_t input; /* The input value */ Mif_Value_t output; /* The output value */ + struct Evt_Output_Event *next_event; Mif_Partial_t *partial; /* Partials for this port wrt inputs */ Mif_AC_Gain_t *ac_gain; /* AC gains for this port wrt inputs */ int old_input; /* Index into CKTstate for old input */ diff --git a/src/xspice/evt/evtaccept.c b/src/xspice/evt/evtaccept.c index 1d031d7ed..0e68c26e6 100644 --- a/src/xspice/evt/evtaccept.c +++ b/src/xspice/evt/evtaccept.c @@ -126,13 +126,14 @@ void EVTaccept( num_modified = output_queue->num_modified; /* Loop through list of items modified since last time */ for(i = 0; i < num_modified; i++) { - Evt_Output_Event_t *stale, *next; + Evt_Output_Event_t *stale, *next, **free_list; /* Get the index of the output modified */ index = output_queue->modified_index[i]; /* Reset the modified flag */ output_queue->modified[index] = MIF_FALSE; /* Move stale entries to the free list. */ + free_list = output_queue->free_list[index]; next = output_queue->head[index]; while (next) { if (next->event_time >= time || @@ -141,8 +142,8 @@ void EVTaccept( } stale = next; next = next->next; - stale->next = output_queue->free[index]; - output_queue->free[index] = stale; + stale->next = *free_list; + *free_list = stale; } output_queue->head[index] = next; if (!next) diff --git a/src/xspice/evt/evtbackup.c b/src/xspice/evt/evtbackup.c index fe1e02784..f857c6816 100644 --- a/src/xspice/evt/evtbackup.c +++ b/src/xspice/evt/evtbackup.c @@ -530,7 +530,7 @@ static void EVTbackup_output_queue( Evt_Output_Queue_t *output_queue; - Evt_Output_Event_t **output_ptr; + Evt_Output_Event_t **output_ptr, **free_list; Evt_Output_Event_t *output; double next_time; @@ -554,12 +554,13 @@ static void EVTbackup_output_queue( output_ptr = output_queue->last_step[output_index]; output = *output_ptr; + free_list = output_queue->free_list[output_index]; while(output) { if(output->posted_time > new_time) { *output_ptr = output->next; - output->next = output_queue->free[output_index]; - output_queue->free[output_index] = output; + output->next = *free_list; + *free_list = output; output = *output_ptr; } else { diff --git a/src/xspice/evt/evtdest.c b/src/xspice/evt/evtdest.c index 454f1a94e..c80367686 100644 --- a/src/xspice/evt/evtdest.c +++ b/src/xspice/evt/evtdest.c @@ -82,18 +82,11 @@ Evt_Queue_destroy(Evt_Ckt_Data_t *evt, Evt_Queue_t *queue) tfree(event); event = next; } - event = output_queue->free[i]; - while (event) { - Evt_Output_Event_t *next = event->next; - tfree(event->value); - tfree(event); - event = next; - } } tfree(output_queue->head); tfree(output_queue->current); tfree(output_queue->last_step); - tfree(output_queue->free); + tfree(output_queue->free_list); tfree(output_queue->modified_index); tfree(output_queue->modified); @@ -101,6 +94,7 @@ Evt_Queue_destroy(Evt_Ckt_Data_t *evt, Evt_Queue_t *queue) tfree(output_queue->pending); tfree(output_queue->changed_index); tfree(output_queue->changed); + Evt_purge_free_outputs(); } /* diff --git a/src/xspice/evt/evtinit.c b/src/xspice/evt/evtinit.c index 1f2b1a041..283c1ea79 100644 --- a/src/xspice/evt/evtinit.c +++ b/src/xspice/evt/evtinit.c @@ -325,7 +325,7 @@ static int EVTinit_queue( CKALLOC(output_queue->head, num_outputs, Evt_Output_Event_t *) CKALLOC(output_queue->current, num_outputs, Evt_Output_Event_t **) CKALLOC(output_queue->last_step, num_outputs, Evt_Output_Event_t **) - CKALLOC(output_queue->free, num_outputs, Evt_Output_Event_t *) + CKALLOC(output_queue->free_list, num_outputs, Evt_Output_Event_t **) CKALLOC(output_queue->modified_index, num_outputs, int) CKALLOC(output_queue->modified, num_outputs, Mif_Boolean_t) CKALLOC(output_queue->pending_index, num_outputs, int) @@ -333,7 +333,6 @@ static int EVTinit_queue( CKALLOC(output_queue->changed_index, num_outputs, int) CKALLOC(output_queue->changed, num_outputs, Mif_Boolean_t) - /* Return */ return(OK); } diff --git a/src/xspice/evt/evtload.c b/src/xspice/evt/evtload.c index f65353743..557eea16d 100644 --- a/src/xspice/evt/evtload.c +++ b/src/xspice/evt/evtload.c @@ -61,20 +61,13 @@ static void EVTadd_msg( int port_index, char *msg_text); -static void EVTcreate_output_event( - CKTcircuit *ckt, - int node_index, - int output_index, - void **value_ptr); +static Evt_Output_Event_t *EVTget_output_event( + CKTcircuit *ckt, + Mif_Port_Data_t *port); static void EVTprocess_output( CKTcircuit *ckt, - Mif_Boolean_t changed, - int output_index, - Mif_Boolean_t invert, - double delay); - - + Mif_Port_Data_t *port); /* EVTload @@ -101,14 +94,10 @@ int EVTload( Mif_Conn_Data_t *conn; Mif_Port_Data_t *port; - - Mif_Private_t cm_data; - + Evt_Node_Data_t *node_data; MIFinstance *inst; - Evt_Node_Data_t *node_data; - - void *value_ptr; + Mif_Private_t cm_data; /* ***************************** */ @@ -191,17 +180,16 @@ int EVTload( port->load = 0.0; port->total_load = node_data->total_load[port->evt_data.node_index]; - /* If connection is an output, initialize changed to true */ - /* and create a new output event object in the free list */ - /* if transient analysis mode */ + /* If connection is an output and transient analysis, + * initialize changed to true and ensure an output location. + */ if(conn->is_output) { port->changed = MIF_TRUE; - if(g_mif_info.circuit.anal_type == MIF_TRAN) { - EVTcreate_output_event(ckt, - port->evt_data.node_index, - port->evt_data.output_index, - &value_ptr); - port->output.pvalue = value_ptr; + if (g_mif_info.circuit.anal_type == MIF_TRAN) { + if (port->next_event == NULL) { + port->next_event = EVTget_output_event(ckt, port); + } + port->output.pvalue = port->next_event->value; } } } @@ -276,9 +264,9 @@ int EVTload( continue; /* If output changed, process it */ - EVTprocess_output(ckt, port->changed, - port->evt_data.output_index, - port->invert, port->delay); + + if (port->changed) + EVTprocess_output(ckt, port); /* And prevent erroneous models from overwriting it during */ /* analog iterations */ @@ -369,43 +357,40 @@ static void EVTcreate_state( /* -EVTcreate_output_event +EVTget_output_event This function creates a new output event. */ -static void EVTcreate_output_event( - CKTcircuit *ckt, /* The circuit structure */ - int node_index, /* The node type port is on */ - int output_index, /* The output index for this port */ - void **value_ptr) /* The event created */ +static Evt_Output_Event_t *EVTget_output_event( + CKTcircuit *ckt, /* The circuit structure */ + Mif_Port_Data_t *port) /* The output port. */ { int udn_index; Evt_Node_Info_t **node_table; Evt_Output_Queue_t *output_queue; - Evt_Output_Event_t *event; + Evt_Output_Event_t *event, **free_list; /* Check the output queue free list and use the structure */ /* at the head of the list if non-null. Otherwise, create a new one. */ + output_queue = &(ckt->evt->queue.output); - if(output_queue->free[output_index]) { - *value_ptr = output_queue->free[output_index]->value; - } - else { + free_list = output_queue->free_list[port->evt_data.output_index]; + if (*free_list) { + event = *free_list; + *free_list = event->next; + } else { /* Create a new event */ event = TMALLOC(Evt_Output_Event_t, 1); event->next = NULL; /* Initialize the value */ node_table = ckt->evt->info.node_table; - udn_index = node_table[node_index]->udn_index; + udn_index = node_table[port->evt_data.node_index]->udn_index; g_evt_udn_info[udn_index]->create (&(event->value)); - - /* Put the event onto the free list and return the value pointer */ - output_queue->free[output_index] = event; - *value_ptr = event->value; } + return event; } @@ -482,16 +467,14 @@ the event is processed immediately. static void EVTprocess_output( - CKTcircuit *ckt, /* The circuit structure */ - Mif_Boolean_t changed, /* Has output changed? */ - int output_index, /* The output of interest */ - Mif_Boolean_t invert, /* Does output need to be inverted? */ - double delay) /* The output delay in transient analysis */ + CKTcircuit *ckt, /* The circuit structure */ + Mif_Port_Data_t *port) { int num_outputs; int node_index; int udn_index; + int output_index; int output_subindex; Evt_Output_Info_t **output_table; @@ -503,33 +486,35 @@ static void EVTprocess_output( Evt_Output_Queue_t *output_queue; Evt_Output_Event_t *output_event; - Mif_Boolean_t equal; - + Mif_Boolean_t invert, equal; + double delay; output_queue = &(ckt->evt->queue.output); output_table = ckt->evt->info.output_table; node_table = ckt->evt->info.node_table; + output_index = port->evt_data.output_index; node_index = output_table[output_index]->node_index; udn_index = node_table[node_index]->udn_index; - + invert = port->invert; /* if transient analysis, just put the output event on the queue */ /* to be processed at a later time */ - if(g_mif_info.circuit.anal_type == MIF_TRAN) { - /* If model signaled that output was not posted, */ - /* leave the event struct on the free list and return */ - if(!changed) - return; + + if (g_mif_info.circuit.anal_type == MIF_TRAN) { + delay = port->delay; if(delay <= 0.0) { printf("\nERROR - Output delay <= 0 not allowed - output ignored!\n"); printf(" Instance: %s\n Node: %s\n Time: %f \n", - g_mif_info.instance->MIFname, node_table[node_index]->name, g_mif_info.ckt->CKTtime); + g_mif_info.instance->MIFname, node_table[node_index]->name, + g_mif_info.ckt->CKTtime); return; } - /* Remove the (now used) struct from the head of the free list */ - output_event = output_queue->free[output_index]; - output_queue->free[output_index] = output_event->next; + /* Remove the (now used) struct from the port data struct. */ + + output_event = port->next_event; + port->next_event = NULL; + /* Invert the output value if necessary */ if(invert) g_evt_udn_info[udn_index]->invert @@ -539,20 +524,11 @@ static void EVTprocess_output( g_mif_info.circuit.evt_step, g_mif_info.circuit.evt_step + delay); return; - } - /* If not transient analysis, process immediately. */ - /* Determine if output has changed from rhsold value */ - /* and put entry in output queue changed list if so */ - else { + } else { + /* If not transient analysis, process immediately. */ + /* Determine if output has changed from rhsold value */ + /* and put entry in output queue changed list if so */ - /* If model signaled that output was not posted, */ - /* just return */ - if(! changed) - return; -/* - if(delay > 0.0) - printf("\nWARNING - Non-zero output delay not allowed in DCOP - delay ignored!\n"); -*/ rhs = ckt->evt->data.node->rhs; rhsold = ckt->evt->data.node->rhsold; diff --git a/src/xspice/evt/evtsetup.c b/src/xspice/evt/evtsetup.c index 606c7959e..761a40bba 100644 --- a/src/xspice/evt/evtsetup.c +++ b/src/xspice/evt/evtsetup.c @@ -183,7 +183,6 @@ static int EVTsetup_queues( Evt_Inst_Event_t *inst_event; Evt_Output_Event_t *output_event; - void *ptr; /* ************************ */ @@ -255,16 +254,9 @@ static int EVTsetup_queues( output_event = output_event->next; FREE(ptr); } - output_event = output_queue->free[i]; - while(output_event) { - ptr = output_event; - output_event = output_event->next; - FREE(ptr); - } output_queue->head[i] = NULL; output_queue->current[i] = &(output_queue->head[i]); output_queue->last_step[i] = &(output_queue->head[i]); - output_queue->free[i] = NULL; } output_queue->next_time = 0.0; @@ -274,15 +266,51 @@ static int EVTsetup_queues( output_queue->num_pending = 0; output_queue->num_changed = 0; - for(i = 0; i < num_outputs; i++) { - output_queue->modified[i] = MIF_FALSE; - output_queue->pending[i] = MIF_FALSE; - output_queue->changed[i] = MIF_FALSE; - } + if (num_outputs > 0) { + for (i = 0; i < num_outputs; i++) { + output_queue->modified[i] = MIF_FALSE; + output_queue->pending[i] = MIF_FALSE; + output_queue->changed[i] = MIF_FALSE; + } - return(OK); + if (output_queue->free_list[0]) { + Evt_purge_free_outputs(); + } else { + Evt_Output_Info_t *output_info; + Evt_Node_Info_t *node; + + /* ********************************************************* * + * On first call for this circuit, set the free-list pointer + * for each output queue. + * ********************************************************* */ + + output_info = ckt->evt->info.output_list; + for (i = 0; i < num_outputs; i++) { + node = ckt->evt->info.node_table[output_info->node_index]; + output_queue->free_list[i] = + &g_evt_udn_info[node->udn_index]->free_list; + output_info = output_info->next; + } + } + } + return OK; } +void Evt_purge_free_outputs(void) +{ + Evt_Output_Event_t *output_event, *next; + int i; + + for (i = 0; i < g_evt_num_udn_types; ++i) { + output_event = g_evt_udn_info[i]->free_list; + while (output_event) { + next = output_event->next; + tfree(output_event->value); + tfree(output_event); + output_event = next; + } + } +} /* diff --git a/src/xspice/icm/xtraevt/int/udnfunc.c b/src/xspice/icm/xtraevt/int/udnfunc.c index 8a279f519..4c568d74f 100644 --- a/src/xspice/icm/xtraevt/int/udnfunc.c +++ b/src/xspice/icm/xtraevt/int/udnfunc.c @@ -182,6 +182,7 @@ Evt_Udn_Info_t udn_int_info = { "int", "integer valued data", + NULL, udn_int_create, udn_int_dismantle, diff --git a/src/xspice/icm/xtraevt/real/udnfunc.c b/src/xspice/icm/xtraevt/real/udnfunc.c index baacfad97..c0ba212dd 100644 --- a/src/xspice/icm/xtraevt/real/udnfunc.c +++ b/src/xspice/icm/xtraevt/real/udnfunc.c @@ -183,6 +183,7 @@ Evt_Udn_Info_t udn_real_info = { "real", "real valued data", + NULL, udn_real_create, udn_real_dismantle, diff --git a/src/xspice/idn/idndig.c b/src/xspice/idn/idndig.c index 25870229b..53c21dbad 100644 --- a/src/xspice/idn/idndig.c +++ b/src/xspice/idn/idndig.c @@ -345,6 +345,7 @@ Evt_Udn_Info_t idn_digital_info = { "d", "12 state digital data", +NULL, idn_digital_create, idn_digital_dismantle, idn_digital_initialize,