Compare commits

...
19 Commits
Author SHA1 Message Date
Tim Edwards 46394b2000 Merge branch 'master' into netgen-1.5 2021-01-17 03:00:15 -05:00
Tim Edwards 0df6c83df5 Updated VERSION to go along with the merge of pull request #14
from Anton Blanchard.
2021-01-16 12:05:52 -05:00
Anton Blanchard 8996fe03dc Increase OBJHASHSIZE
I have a design that is taking quite a long time for netgen to complete LVS
checking. Profiles show a large chunk of runtime is in the hash functions.

Some of the hashtables are very sparsely populated, but others are
heavily used. One hashtable has chains of over 250. Longer term it would
be worth investigating resizing the hashtables (or perhaps using other
data strutures), but for now I looked at what changing the number of
hash buckets (OBJHASHSIZE) does for performance:

OBJHASHSIZE	time (mm:ss)
997		24:18
10093		 4:42
42073		 3:12
104729		 2:51

I somewhat arbitrarily chose 42073 which gives us a 7.6x improvement in
runtime.
2021-01-15 18:24:34 -07:00
Tim Edwards 3fe3bc4cfa Merge branch 'master' into netgen-1.5 2021-01-09 03:00:32 -05:00
Tim Edwards f3cebd9099 Corrected a potential crash condition while doing series combination. 2021-01-08 09:55:00 -05:00
Tim Edwards 6661910672 Merge branch 'master' into netgen-1.5 2020-12-21 03:00:30 -05:00
Tim Edwards 920c6e6928 Corrected a problem causing a segfault during a property record
copy if the property record does not have a model.class record
(should it always?).
2020-12-20 11:55:20 -05:00
Tim Edwards e7a36630f6 Merge branch 'master' into netgen-1.5 2020-12-16 03:00:54 -05:00
Tim Edwards 69780aa048 Added patch from Mitch Bailey which sorts the objects in a verilog
file input so that pins occur first before nodes, as they do in a
SPICE netlist.  Certain parts of the comparison code depend on pins
being first in the netlist, and reordering them when reading input
is easier than rewriting the rest of the code.
2020-12-15 09:57:49 -05:00
Tim Edwards f32b0b34a3 Merge branch 'master' into netgen-1.5 2020-12-06 03:00:10 -05:00
Tim Edwards 2a0ebfde93 Updated VERSION with the commit. 2020-12-05 15:46:45 -05:00
Tim Edwards 6e9e6abe98 Removed the netgen.sh and netgen.tcl scripts from the repository,
which are generated by ./configure and should not be in the repo.
2020-12-05 15:46:03 -05:00
Tim Edwards 6b731ddd7a Merge branch 'master' into netgen-1.5 2020-12-04 03:00:27 -05:00
Tim Edwards b9769b9f55 Updated version to go along with pull request merge from github. 2020-12-03 20:17:59 -05:00
Tim 'mithro' Ansell 7e42483986 Fix configure script to not clobber CFLAGS.
Signed-off-by: Tim 'mithro' Ansell <[email protected]>
2020-11-29 16:39:28 -08:00
Tim 'mithro' Ansell 97b0d08e4f Rework configure script so exit code works.
The previous script would swallow the exit code of the `./configure`
script and thus it looked like doing a configure always succeeded.

Signed-off-by: Tim 'mithro' Ansell <[email protected]>
2020-11-29 16:35:47 -08:00
Tim Edwards 99e35d8b11 Merge branch 'master' into netgen-1.5 2020-10-09 03:00:25 -04:00
Tim Edwards d2c356f9e2 Added a "-full" switch to the scripted "lvs" command that switches
to the old symmetry breaking method (see previous commit message).
2020-10-08 09:57:01 -04:00
Tim Edwards 5e99fd5ef9 Found a counterexample which shows that the fast symmetry breaking
introduced in revision 150 can result in an incorrect result
reporting a bad match where the match is actually good (as proven
by running the full symmetry breaking on the same netlist).
Because the fast symmetry breaking is orders of magnitude faster
for large circuits, and because the false positive result appears
to be rare, I have introduced a command "symmetry" to switch
methods between fast and full.  So fast symmetry breaking can be
run unless the result fails on symmetry breaking, in which case
the method can be switched to full to see if the problem is a
false positive or not.  This is not an ideal solution, and some
investigation is needed to determine if there is a way to apply
fast symmetry breaking without encountering a false positive
error.
2020-10-08 09:43:25 -04:00
9 changed files with 199 additions and 17 deletions
+1 -1
View File
@@ -1 +1 @@
1.5.156
1.5.163
+102 -8
View File
@@ -158,6 +158,9 @@ int right_col_end = 87;
/* if TRUE, always partition ALL classes */
int ExhaustiveSubdivision = 0;
/* if TRUE, use fast symmetry breaking to resolve automorphisms */
int FastSymmetryBreaking = 1;
#ifdef TEST
static void PrintElement_List(struct Element *E)
{
@@ -5862,7 +5865,81 @@ int ResolveAutomorphsByProperty()
/*
*-------------------------------------------------------------------------
*
* ResolveElementAutomorphisms --
* ResolveAutormorphismsFull --
*
* Arbitrarily equivalence one pair of elements within an automorphic class
*
* Return value is the same as VerifyMatching()
*
*-------------------------------------------------------------------------
*/
int ResolveAutomorphismsFull()
{
struct ElementClass *EC;
struct Element *E;
struct NodeClass *NC;
struct Node *N;
int C1, C2;
for (EC = ElementClasses; EC != NULL; EC = EC->next) {
struct Element *E1, *E2;
C1 = C2 = 0;
E1 = E2 = NULL;
for (E = EC->elements; E != NULL; E = E->next) {
if (E->graph == Circuit1->file) {
C1++;
E1 = E;
}
else {
C2++;
E2 = E;
}
}
if (C1 == C2 && C1 != 1) {
unsigned long newhash;
Magic(newhash);
E1->hashval = newhash;
E2->hashval = newhash;
goto converge;
}
}
for (NC = NodeClasses; NC != NULL; NC = NC->next) {
struct Node *N1, *N2;
C1 = C2 = 0;
N1 = N2 = NULL;
for (N = NC->nodes; N != NULL; N = N->next) {
if (N->graph == Circuit1->file) {
C1++;
N1 = N;
}
else {
C2++;
N2 = N;
}
}
if (C1 == C2 && C1 != 1) {
unsigned long newhash;
Magic(newhash);
N1->hashval = newhash;
N2->hashval = newhash;
goto converge;
}
}
converge:
FractureElementClass(&ElementClasses);
FractureNodeClass(&NodeClasses);
ExhaustiveSubdivision = 1;
while (!Iterate() && VerifyMatching() != -1);
return(VerifyMatching());
}
/*
*-------------------------------------------------------------------------
*
* ResolveElementAutomorphismsFast --
*
* Apply arbitrary symmetry breaking to symmetric element lists, then
* iterate exhaustively to resolve all automorphisms.
@@ -5872,7 +5949,7 @@ int ResolveAutomorphsByProperty()
*-------------------------------------------------------------------------
*/
int ResolveElementAutomorphisms()
int ResolveElementAutomorphismsFast()
{
struct ElementClass *EC;
struct Element *E;
@@ -5924,7 +6001,7 @@ int ResolveElementAutomorphisms()
/*
*-------------------------------------------------------------------------
*
* ResolveNodeAutomorphisms --
* ResolveNodeAutomorphismsFast --
*
* Apply arbitrary symmetry breaking to symmetric node lists, then iterate
* exhaustively to resolve all automorphisms. Normally, all automorphisms
@@ -5937,7 +6014,7 @@ int ResolveElementAutomorphisms()
*
*/
int ResolveNodeAutomorphisms()
int ResolveNodeAutomorphismsFast()
{
struct Node *N;
struct NodeClass *NC;
@@ -5991,7 +6068,20 @@ int ResolveNodeAutomorphisms()
*
* ResolveAutormorphisms --
*
* Arbitrarily equivalence one pair of elements within an automorphic class
* Do symmetry breaking of automorphisms. If FastSymmetryBreaking is
* False (not the default), then run ResolveAutomorphismsFull() (q.v.).
* Otherwise, run the fast symmetry breaking method:
*
* Arbitrarily equivalence all pairs of elements and nodes within all
* automorphic classes, and run to completion. Note that this is a
* fast version of ResolveAutomorphismsFull(), and can run many orders
* of magnitude faster. However, it can also produce an incorrect
* result, declaring a global mismatch where none exists. In that
* case, the matching should be re-run with ResolveAutomorphismsFull().
*
* Some investigation needs to be done to determine if there is a way
* to execute faster symmetry breaking without the possibility of
* producing an incorrect result.
*
* Return value is the same as VerifyMatching()
*
@@ -6002,9 +6092,12 @@ int ResolveAutomorphisms()
{
int result;
result = ResolveElementAutomorphisms();
if (FastSymmetryBreaking == 0)
return ResolveAutomorphismsFull();
result = ResolveElementAutomorphismsFast();
if (result != 0)
result = ResolveNodeAutomorphisms();
result = ResolveNodeAutomorphismsFast();
return result;
}
@@ -7454,7 +7547,8 @@ static void handler(int sig)
/*----------------------------------------------------------------------*/
/* Note that this cover-all routine is not called from the Tcl/Tk */
/* version, which replaces it with the script "lvs". */
/* return 1 if the two are identical. Try to resolve automorphisms. */
/* return 1 if the two are identical. Try to resolve automorphisms */
/* using the original "full" symmetry breaking algorithm. */
/*----------------------------------------------------------------------*/
int Compare(char *cell1, char *cell2)
+1
View File
@@ -7,6 +7,7 @@ extern struct nlist *Circuit1;
extern struct nlist *Circuit2;
extern int ExhaustiveSubdivision;
extern int FastSymmetryBreaking;
extern int left_col_end;
extern int right_col_end;
+4 -3
View File
@@ -2470,7 +2470,8 @@ void CopyProperties(struct objlist *obj_to, struct objlist *obj_from)
kvcur->value.ival = 0;
obj_to->instance.props = kvcopy;
obj_to->model.class = strsave(obj_from->model.class);
if (obj_from->model.class)
obj_to->model.class = strsave(obj_from->model.class);
}
}
@@ -3583,8 +3584,8 @@ int CombineSeries(char *model, int file)
/* Excise the 2nd instance. instlist[i][1] remains as the */
/* only pointer to it. */
for (obp = instlist[i][0]; obp->next->type > FIRSTPIN ||
obp->next->type == PROPERTY; obp = obp->next);
for (obp = instlist[i][0]; obp->next && (obp->next->type > FIRSTPIN ||
obp->next->type == PROPERTY); obp = obp->next);
for (ob2 = obp; ob2 && ob2->next != instlist[i][1]; ob2 = ob2->next);
/* Device may have been moved by the above code. If so, look for */
+1 -2
View File
@@ -192,9 +192,8 @@ struct Permutation {
struct Permutation *next;
};
#define OBJHASHSIZE 997 /* the size of the object and instance hash lists */
#define OBJHASHSIZE 42073 /* the size of the object and instance hash lists */
/* prime numbers are good choices as hash sizes */
/* 101 is a good number for IBMPC */
/* cell definition for hash table */
/* NOTE: "file" must come first for the hash matching by name and file */
+37 -1
View File
@@ -553,9 +553,43 @@ void CleanupModule() {
int maxnode = 0;
int has_submodules = FALSE;
struct objlist *sobj, *nobj, *lobj, *pobj;
struct objlist *myLastPort, *object_it, *myNextObject;
if (CurrentCell == NULL) return;
myLastPort = NULL;
/* Reorder objects so that all ports come first, before nodes, because
* parts of the code depend on it.
*/
for (object_it = CurrentCell->cell; object_it && object_it->type <= 0;
object_it = myNextObject ) {
myNextObject = object_it->next;
if (!myNextObject) // end of list
continue;
if (myLastPort == NULL) {
if (object_it->type == PORT) {
myLastPort = object_it; // port at begining of list
myNextObject = object_it; // otherwise skips one
}
else if (myNextObject->type == PORT) {
object_it->next = myNextObject->next;
myNextObject->next = CurrentCell->cell;
CurrentCell->cell = myNextObject;
myLastPort = myNextObject;
}
}
else if (myNextObject->type == PORT) {
object_it->next = myNextObject->next;
myNextObject->next = myLastPort->next;
myLastPort->next = myNextObject;
myLastPort = myNextObject;
}
}
for (sobj = CurrentCell->cell; sobj; sobj = sobj->next)
if (sobj->node > maxnode)
maxnode = sobj->node + 1;
@@ -1946,7 +1980,9 @@ nextinst:
sprintf(localnet, "_noconnect_%d_", localcount++);
Node(localnet);
join(localnet, obptr->name);
Fprintf(stderr, "Note: Implicit pin %s\n", obpinname);
Fprintf(stderr,
"Note: Implicit pin %s in instance %s of %s in cell %s\n",
obpinname, locinst, modulename, CurrentCell->name);
}
else if (GetBus(scan->net, &wb) == 0) {
char *bptr2;
Vendored
+3 -1
View File
@@ -4,4 +4,6 @@
# all of its config scripts in a different directory than the configure
# script itself.
( CFLAGS="-g" ; export CFLAGS ; cd scripts ; ./configure "$@" )
export CFLAGS="$CFLAGS -g"
cd scripts
exec ./configure "$@"
+3
View File
@@ -382,6 +382,9 @@ proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} {
} elseif {$arg == "-blackbox"} {
puts stdout "Treating empty subcircuits as black-box cells"
netgen::model blackbox on
} elseif {$arg == "-full"} {
puts stdout "Using full symmetry breaking method"
netgen::symmetry full
}
}
+47 -1
View File
@@ -94,6 +94,7 @@ int _netcmp_ignore(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST objv[]);
int _netcmp_permute(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST objv[]);
int _netcmp_property(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST objv[]);
int _netcmp_exhaustive(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST objv[]);
int _netcmp_symmetry(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST objv[]);
int _netcmp_restart(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST objv[]);
int _netcmp_global(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST objv[]);
int _netcmp_convert(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST objv[]);
@@ -244,6 +245,9 @@ Command netcmp_cmds[] = {
{"exhaustive", _netcmp_exhaustive,
"\n "
"toggle exhaustive subdivision"},
{"symmetry", _netcmp_symmetry,
"[fast|full]\n "
"apply method for symmetry breaking"},
{"restart", _netcmp_restart,
"\n "
"start over (reset data structures)"},
@@ -3972,6 +3976,48 @@ _netcmp_permute(ClientData clientData,
return TCL_OK;
}
/*------------------------------------------------------*/
/* Function name: _netcmp_symmetry */
/* Syntax: netgen::symmetry [fast|full] */
/* Formerly: x */
/* Results: */
/* Side Effects: */
/*------------------------------------------------------*/
int
_netcmp_symmetry(ClientData clientData,
Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
{
char *fastfull[] = {
"fast", "full", NULL
};
enum OptionIdx {
FAST_IDX, FULL_IDX
};
int result, index;
if (objc == 1)
index = -1;
else {
if (Tcl_GetIndexFromObj(interp, objv[1], (CONST84 char **)fastfull,
"option", 0, &index) != TCL_OK)
return TCL_ERROR;
}
switch(index) {
case FAST_IDX:
FastSymmetryBreaking = TRUE;
break;
case FULL_IDX:
FastSymmetryBreaking = FALSE;
break;
}
Printf("Symmetry breaking method: %s.\n",
FastSymmetryBreaking ? "FAST" : "FULL");
return TCL_OK;
}
/*------------------------------------------------------*/
/* Function name: _netcmp_exhaustive */
/* Syntax: netgen::exhaustive [on|off] */
@@ -3993,7 +4039,7 @@ _netcmp_exhaustive(ClientData clientData,
int result, index;
if (objc == 1)
index = YES_IDX;
index = -1;
else {
if (Tcl_GetIndexFromObj(interp, objv[1], (CONST84 char **)yesno,
"option", 0, &index) != TCL_OK)