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.
This commit is contained in:
Giles Atkinson 2023-02-23 17:56:40 +00:00 committed by Holger Vogt
parent 2d0561f386
commit c1659a64c3
13 changed files with 124 additions and 118 deletions

View File

@ -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 */

View File

@ -134,5 +134,6 @@ bool Evtcheck_nodes(
struct INPtables *stab); /* Symbol table. */
struct dvec *EVTfindvec(char *node);
void Evt_purge_free_outputs(void);
#endif

View File

@ -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;

View File

@ -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 */

View File

@ -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)

View File

@ -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 {

View File

@ -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();
}
/*

View File

@ -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);
}

View File

@ -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;

View File

@ -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;
}
}
}
/*

View File

@ -182,6 +182,7 @@ Evt_Udn_Info_t udn_int_info = {
"int",
"integer valued data",
NULL,
udn_int_create,
udn_int_dismantle,

View File

@ -183,6 +183,7 @@ Evt_Udn_Info_t udn_real_info = {
"real",
"real valued data",
NULL,
udn_real_create,
udn_real_dismantle,

View File

@ -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,