From 8ef0aece58965b6c3dd551c20dc14f61b9538f0d Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Wed, 18 Oct 2023 14:34:16 +0200 Subject: [PATCH] During setup of the models thre have been search scans in the linked model list modtab. The time used here grows approx. quadratically with the number of models. If the numbers get large, e.g. with the IHP Open PDK, setup time make simulation impractical. Therefore the linked list modtab has been enhanced by a hash table modtabhash, which allows linear search time and makes simulation of a 200k transistor circuit with IHP PDK possible. Already the setup time for 15k transistor circuits has been reduced. --- src/frontend/runcoms.c | 3 +++ src/frontend/runcoms2.c | 5 +++- src/frontend/spiceif.c | 4 +++ src/include/ngspice/ftedefs.h | 2 ++ src/spicelib/parser/inpgmod.c | 30 ++++++++++++++++++++++- src/spicelib/parser/inpkmods.c | 8 ++++++ src/spicelib/parser/inpmkmod.c | 45 +++++++++++++++++++++------------- 7 files changed, 78 insertions(+), 19 deletions(-) diff --git a/src/frontend/runcoms.c b/src/frontend/runcoms.c index 9d52e192e..613be5d9e 100644 --- a/src/frontend/runcoms.c +++ b/src/frontend/runcoms.c @@ -14,6 +14,7 @@ Modified: 2000 AlansFixes #include "ngspice/ftedev.h" #include "ngspice/ftedebug.h" #include "ngspice/dvec.h" +#include "ngspice/hash.h" #include "numparam/numpaif.h" @@ -33,6 +34,7 @@ Modified: 2000 AlansFixes static int dosim(char *what, wordlist *wl); extern struct INPmodel *modtab; +extern NGHASHPTR modtabhash; extern struct dbcomm *dbs; extern void NIresetwarnmsg(void); @@ -107,6 +109,7 @@ com_scirc(wordlist *wl) ft_curckt = p; /* get the model table for the current circuit, store it in the global variable modtab */ modtab = ft_curckt->ci_modtab; + modtabhash = ft_curckt->ci_modtabhash; /* get the database for save, iplot, stop */ dbs = ft_curckt->ci_dbs; /* set the numparam dicos structure for use with measure */ diff --git a/src/frontend/runcoms2.c b/src/frontend/runcoms2.c index ac6c9dead..baf43ee79 100644 --- a/src/frontend/runcoms2.c +++ b/src/frontend/runcoms2.c @@ -14,6 +14,7 @@ Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group #include "ngspice/ftedebug.h" #include "ngspice/dvec.h" #include "ngspice/trandefs.h" +#include "ngspice/hash.h" #include "circuits.h" #include "runcoms2.h" @@ -33,6 +34,7 @@ Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group extern void line_free_x(struct card *deck, bool recurse); extern INPmodel *modtab; +extern NGHASHPTR modtabhash; #ifdef SHARED_MODULE extern void exec_controls(wordlist *newcontrols); @@ -273,10 +275,11 @@ com_remcirc(wordlist *wl) prev = p; } - /* make first entry in ft_circuits the actual circuit (or NULL) */ + /* make first entry in ft_circuits the current circuit (or NULL) */ ft_curckt = ft_circuits; if (ft_curckt) { modtab = ft_curckt->ci_modtab; + modtabhash = ft_curckt->ci_modtabhash; dbs = ft_curckt->ci_dbs; nupa_set_dicoslist(ft_curckt->ci_dicos); } diff --git a/src/frontend/spiceif.c b/src/frontend/spiceif.c index 724e4f879..c135b37db 100644 --- a/src/frontend/spiceif.c +++ b/src/frontend/spiceif.c @@ -54,6 +54,7 @@ CDHW*/ #include "ngspice/inpdefs.h" #include "ngspice/iferrmsg.h" #include "ngspice/ifsim.h" +#include "ngspice/hash.h" #include "circuits.h" #include "spiceif.h" @@ -75,6 +76,7 @@ CDHW*/ #endif extern INPmodel *modtab; +extern NGHASHPTR modtabhash; extern bool ft_batchmode; static struct variable *parmtovar(IFvalue *pv, IFparm *opt); @@ -160,9 +162,11 @@ if_inpdeck(struct card *deck, INPtables **tab) /* Parse the .model lines. Enter the model into the global model table modtab. */ modtab = NULL; + modtabhash = NULL; INPpas1(ckt, deck->nextcard, *tab); /* store the new model table in the current circuit */ ft_curckt->ci_modtab = modtab; + ft_curckt->ci_modtabhash = modtabhash; /* Scan through the instance lines and parse the circuit. */ INPpas2(ckt, deck->nextcard, *tab, ft_curckt->ci_defTask); diff --git a/src/include/ngspice/ftedefs.h b/src/include/ngspice/ftedefs.h index 471f1c9b2..639707250 100644 --- a/src/include/ngspice/ftedefs.h +++ b/src/include/ngspice/ftedefs.h @@ -17,6 +17,7 @@ Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group #include "ngspice/fteparse.h" #include "ngspice/fteinp.h" #include "ngspice/fteoptdefs.h" +#include "ngspice/hash.h" struct ccom; @@ -34,6 +35,7 @@ struct circ { CKTcircuit *ci_ckt; /* The CKTcircuit structure. */ INPtables *ci_symtab; /* The INP symbol table. */ INPmodel *ci_modtab; /* The INP model table. */ + NGHASHPTR ci_modtabhash; /* The INP model hash table. */ struct dbcomm *ci_dbs; /* The database storing save, iplot, stop data */ struct card *ci_deck; /* The input deck. */ struct card *ci_origdeck; /* The input deck, before subckt expansion. */ diff --git a/src/spicelib/parser/inpgmod.c b/src/spicelib/parser/inpgmod.c index 6450abf6d..44dc93989 100644 --- a/src/spicelib/parser/inpgmod.c +++ b/src/spicelib/parser/inpgmod.c @@ -39,6 +39,7 @@ static int INPfindParm(char *name, IFparm *table, int numParms); #endif extern INPmodel *modtab; +extern NGHASHPTR modtabhash; static IFparm * @@ -342,6 +343,33 @@ INPgetMod(CKTcircuit *ckt, char *name, INPmodel **model, INPtables *tab) printf("In INPgetMod, examining model %s ...\n", name); #endif + modtmp = nghash_find(modtabhash, name); + if (modtmp) { + /* found the model in question - now instantiate if necessary */ + /* and return an appropriate pointer to it */ + +/* if illegal device type */ + if (modtmp->INPmodType < 0) { +#ifdef TRACE + printf("In INPgetMod, illegal device type for model %s ...\n", name); +#endif + * model = NULL; + return tprintf("Unknown device type for model %s\n", name); + } + + /* create unless model is already defined */ + if (!modtmp->INPmodfast) { + int error = create_model(ckt, modtmp, tab); + if (error) { + *model = NULL; + return INPerror(error); + } + } + + *model = modtmp; + return NULL; + } +#if (0) for (modtmp = modtab; modtmp; modtmp = modtmp->INPnextModel) { #ifdef TRACE @@ -374,7 +402,7 @@ INPgetMod(CKTcircuit *ckt, char *name, INPmodel **model, INPtables *tab) return NULL; } } - +#endif #ifdef TRACE printf("In INPgetMod, didn't find model for %s, using default ...\n", name); #endif diff --git a/src/spicelib/parser/inpkmods.c b/src/spicelib/parser/inpkmods.c index 8e356a840..40c68be51 100644 --- a/src/spicelib/parser/inpkmods.c +++ b/src/spicelib/parser/inpkmods.c @@ -13,6 +13,7 @@ Author: 1985 Thomas L. Quarles extern INPmodel *modtab; +extern NGHASHPTR modtabhash; void INPkillMods(void) { @@ -28,4 +29,11 @@ void INPkillMods(void) FREE(prev); modtab = NULL; ft_curckt->ci_modtab = NULL; + /* free the hash table */ + if (modtabhash) { + nghash_free(modtabhash, NULL, NULL); + modtabhash = NULL; + } + ft_curckt->ci_modtabhash = NULL; + } diff --git a/src/spicelib/parser/inpmkmod.c b/src/spicelib/parser/inpmkmod.c index 456c4f5e4..055d7a66b 100644 --- a/src/spicelib/parser/inpmkmod.c +++ b/src/spicelib/parser/inpmkmod.c @@ -7,10 +7,14 @@ Author: 1985 Thomas L. Quarles #include #include "ngspice/inpdefs.h" #include "ngspice/iferrmsg.h" +#include "ngspice/hash.h" #include "inpxx.h" /* global input model table. */ INPmodel *modtab = NULL; +/* Global input model hash table. + The modelname is the key, the return value is the pointer to the model. */ +NGHASHPTR modtabhash = NULL; /*-------------------------------------------------------------- * This fcn takes the model name and looks to see if it is already @@ -21,33 +25,40 @@ INPmodel *modtab = NULL; int INPmakeMod(char *token, int type, struct card *line) { - register INPmodel **i; - - /* First cycle through model table and see if model name - already exists in there. If it does, just return. */ - for (i = &modtab; *i != NULL; i = &((*i)->INPnextModel)) { - if (strcmp((*i)->INPmodName, token) == 0) { - return (OK); - } + register INPmodel *newm; + /* Initialze the hash table. The default key type is string. + The default comparison function is strcmp.*/ + if (!modtabhash) { + modtabhash = nghash_init(NGHASH_MIN_SIZE); + nghash_unique(modtabhash, TRUE); } + /* If the model is already there, just return. */ + else if (nghash_find(modtabhash, token)) + return (OK); - /* Model name was not already in model table. Therefore stick - it in the model table. Then return. */ + /* Model name was not already in model table. Therefore stick + it in the front of the model table, also into the model hash table. + Then return. */ #ifdef TRACE /* debug statement */ printf("In INPmakeMod, about to insert new model name = %s . . .\n", token); #endif - *i = TMALLOC(INPmodel, 1); - if (*i == NULL) + newm = TMALLOC(INPmodel, 1); + if (newm == NULL) return (E_NOMEM); - (*i)->INPmodName = token; /* model name */ - (*i)->INPmodType = type; /* model type */ - (*i)->INPnextModel = NULL; /* pointer to next model (end of list) */ - (*i)->INPmodLine = line; /* model line */ - (*i)->INPmodfast = NULL; + newm->INPmodName = token; /* model name */ + newm->INPmodType = type; /* model type */ + newm->INPnextModel = modtab; /* pointer to second model */ + newm->INPmodLine = line; /* model line */ + newm->INPmodfast = NULL; + + nghash_insert(modtabhash, token, newm); + + modtab = newm; + return (OK); }