Continued optimizing poorly written routines in "extresist".

Changed the "ResDissolveContacts()" routine to avoid running both
redundant and useless code.  Changed the breakpoint sorting
routine from a bubble sort to a merge sort for linked lists
longer than 16, as merge sort is more efficient for long lists.
This commit is contained in:
R. Timothy Edwards 2026-05-20 19:02:22 -04:00
parent 29447a35cd
commit a062fdcfe0
4 changed files with 321 additions and 45 deletions

View File

@ -1 +1 @@
8.3.645
8.3.646

View File

@ -148,29 +148,32 @@ void
ResDissolveContacts(contacts)
ResContactPoint *contacts;
{
TileType t, oldtype;
TileType t, oldtype, lasttype = TT_SPACE;
Tile *tp;
TileTypeBitMask residues;
for (; contacts != (ResContactPoint *)NULL; contacts = contacts->cp_nextcontact)
{
oldtype=contacts->cp_type;
oldtype = contacts->cp_type;
#ifdef PARANOID
if (oldtype == TT_SPACE)
TxError("Error in Contact Dissolving for %s \n",ResCurrentNode);
#endif
DBFullResidueMask(oldtype, &residues);
if (oldtype != lasttype)
{
lasttype = oldtype;
DBFullResidueMask(oldtype, &residues);
}
DBErase(ResUse->cu_def, &(contacts->cp_rect), oldtype);
for (t = TT_TECHDEPBASE; t < DBNumTypes; t++)
if (TTMaskHasType(&residues, t))
DBPaint(ResUse->cu_def, &(contacts->cp_rect), t);
#ifdef PARANOID
tp = PlaneGetHint(ResDef->cd_planes[DBPlane(contacts->cp_type)]);
GOTOPOINT(tp, &(contacts->cp_rect.r_ll));
#ifdef PARANOID
if (TiGetTypeExact(tp) == contacts->cp_type)
TxError("Error in Contact Preprocess Routines\n");
#endif
@ -378,13 +381,14 @@ ResAddBreakpointFunc(tile, dinfo, node)
*
* ResFindNewContactTiles --
*
* Dissolving contacts eliminated the tiles that contacts->nextcontact
* pointed to. This procedure finds the tile now under center and sets
* that tile's ti_client field to point to the contact. The old value
* of clientdata is set to nextTilecontact.
*
* Results: none
*
* Side Effects: dissolving contacts eliminated the tiles that
* contacts->nextcontact pointed to. This procedure finds the tile now under
* center and sets that tile's ti_client field to point to the contact. The
* old value of clientdata is set to nextTilecontact.
* Side Effects: modifies information in the contact records.
*
*----------------------------------------------------------------------------
*/
@ -396,27 +400,37 @@ ResFindNewContactTiles(contacts)
int pNum;
Tile *tile;
TileTypeBitMask mask;
TileType lastType = TT_SPACE;
for (; contacts != (ResContactPoint *) NULL; contacts = contacts->cp_nextcontact)
{
DBFullResidueMask(contacts->cp_type, &mask);
/* Watch for types that connect to the substrate plane or well; */
/* e.g., psubstratepdiff connects to nwell but not through a */
/* contact. */
if (ExtCurStyle->exts_globSubstratePlane != -1)
/* Avoid re-running the following code for the same contact type */
if (contacts->cp_type != lastType)
{
TileTypeBitMask cMask;
TTMaskAndMask3(&cMask, &DBConnectTbl[contacts->cp_type],
&DBPlaneTypes[ExtCurStyle->exts_globSubstratePlane]);
lastType = contacts->cp_type;
DBFullResidueMask(contacts->cp_type, &mask);
if (!TTMaskIsZero(&cMask))
TTMaskSetMask(&mask, &cMask);
/* Watch for types that connect to the substrate plane or well; */
/* e.g., psubstratepdiff connects to nwell but not through a */
/* contact. */
if (ExtCurStyle->exts_globSubstratePlane != -1)
{
TileTypeBitMask cMask;
TTMaskAndMask3(&cMask, &DBConnectTbl[contacts->cp_type],
&DBPlaneTypes[ExtCurStyle->exts_globSubstratePlane]);
if (!TTMaskIsZero(&cMask))
TTMaskSetMask(&mask, &cMask);
}
}
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
{
if (!DBTypeOnPlane(contacts->cp_type, pNum) &&
(pNum != ExtCurStyle->exts_globSubstratePlane))
continue;
tile = PlaneGetHint(ResDef->cd_planes[pNum]);
GOTOPOINT(tile, &(contacts->cp_center));
#ifdef PARANOID
@ -476,10 +490,11 @@ ResFindNewContactTiles(contacts)
/*
*--------------------------------------------------------------------------
*
* ResProcessTiles--Calls ResEachTile with processed tiles belonging to
* nodes in ResNodeQueue. When all the tiles corresponding
* to a node have been processed, the node is moved to
* ResNodeList.
* ResProcessTiles --
*
* Calls ResEachTile with processed tiles belonging to nodes in ResNodeQueue.
* When all the tiles corresponding to a node have been processed, the node
* is moved to ResNodeList.
*
* Results: Return 1 if any error occurred, 0 otherwise.
*

View File

@ -525,7 +525,7 @@ ResCalcNearDevice(tile, pendingList, doneList, resList)
(devedge & TOPEDGE) == devedge ||
(devedge & BOTTOMEDGE) == devedge)
{
ResSortBreaks(&info->breakList,TRUE);
ResSortBreaks(&info->breakList, TRUE);
p2 = NULL;
for (p1 = info->breakList; p1 != NULL; p1 = p1->br_next)
{
@ -916,11 +916,182 @@ ResDoContacts(contact, nodes, resList)
}
}
/*
*-------------------------------------------------------------------------
*
* BreakCompare --
*
* Helper routine for MergeSortBreaks() (below). Simple
* comparison of the breakpoint position. Comparison is
* done for the X position if "xsort" is TRUE, and the Y
* position if "xsort" is FALSE.
*
* Return value:
* Return -1 if the (x or y) position of a is less than the
* (x or y) position of b; return +1 if the position of a is
* greater than the position of b; and return 0 if they have
* equal positions.
*
* Side effect:
* None.
*
*-------------------------------------------------------------------------
*/
int
BreakCompare(
Breakpoint *a,
Breakpoint *b,
int xsort)
{
if (xsort == TRUE)
{
if (a->br_loc.p_x < b->br_loc.p_x) return -1;
if (a->br_loc.p_x > b->br_loc.p_x) return 1;
}
else
{
if (a->br_loc.p_y < b->br_loc.p_y) return -1;
if (a->br_loc.p_y > b->br_loc.p_y) return 1;
}
return 0;
}
/*
*-------------------------------------------------------------------------
*
* MergeSorted --
*
* Helper routine for MergeSortBreaks() (below). Merge sort
* merging routine.
*
*-------------------------------------------------------------------------
*/
Breakpoint *
MergeSorted(
Breakpoint *a,
Breakpoint *b,
int xsort)
{
Breakpoint head;
Breakpoint *tail = &head;
head.br_next = NULL;
while (a != NULL && b != NULL)
{
if (BreakCompare(a, b, xsort) <= 0)
{
tail->br_next = a;
a = a->br_next;
}
else
{
tail->br_next = b;
b = b->br_next;
}
tail = tail->br_next;
}
tail->br_next = (a != NULL) ? a : b;
return head.br_next;
}
/*
*-------------------------------------------------------------------------
*
* SplitList --
*
* Helper routine for MergeSortBreaks() (below). Merge sort
* splitting routine.
*
* Results:
* None.
*
*-------------------------------------------------------------------------
*/
void
SplitList(
Breakpoint *source,
Breakpoint **front,
Breakpoint **back)
{
Breakpoint *slow;
Breakpoint *fast;
if (source == NULL || source->br_next == NULL)
{
*front = source;
*back = NULL;
return;
}
slow = source;
fast = source->br_next;
while (fast != NULL)
{
fast = fast->br_next;
if (fast != NULL)
{
slow = slow->br_next;
fast = fast->br_next;
}
}
*front = source;
*back = slow->br_next;
slow->br_next = NULL;
}
/*
*-------------------------------------------------------------------------
*
* MergeSortBreaks --
*
* See "ResSortBreaks" below. Alternative to bubble sort for long
* linked lists.
*
* Results:
* Pointer to a sorted breakpoint list.
*
* Side effects:
* The breakpoints are sorted.
*
*-------------------------------------------------------------------------
*/
Breakpoint *
MergeSortBreaks(Breakpoint *list, int xsort)
{
Breakpoint *a, *b;
if (list == NULL || list->br_next == NULL)
return list;
SplitList(list, &a, &b);
a = MergeSortBreaks(a, xsort);
b = MergeSortBreaks(b, xsort);
return MergeSorted(a, b, xsort);
}
/*
*-------------------------------------------------------------------------
*
* ResSortBreaks --
*
* Sort breakpoints, either in the X direction (if "xsort" is TRUE)
* or in the Y direction (if "xsort" is FALSE). For short lists
* (< 16 elements), a simple bubble sort is used. For larger lists,
* a merge sort is used. Most resistor networks are short, but
* power/ground networks can be huge and cause a performance
* bottleneck.
*
* Results:
* None
*
@ -934,6 +1105,19 @@ ResSortBreaks(masterlist, xsort)
{
Breakpoint *p1, *p2, *p3, *p4;
bool changed;
int count = 0;
for (p1 = *masterlist; p1; p1 = p1->br_next)
{
count++;
if (count > 16)
{
*masterlist = MergeSortBreaks(*masterlist, xsort);
return;
}
}
/* Simple bubble sort */
changed = TRUE;
while (changed == TRUE)

View File

@ -12,6 +12,7 @@
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/resis/ResSimple.c,v 1.1.1.1 2008/02/03 20:43:50 tim Exp $";
#endif /* not lint */
#include <stdio.h>
#include <stdlib.h> /* for qsort() */
#include <string.h>
#include <ctype.h>
#include <math.h>
@ -401,6 +402,29 @@ ResMoveDevices(node1, node2)
node1->rn_te = NULL;
}
/*
*-------------------------------------------------------------------------
*
* qrescompare ---
*
* Sort routine for qsort() to be used by ResScrunchNet(). Sorts in
* order of the resistor value, smallest to largest.
*-------------------------------------------------------------------------
*/
int
qrescompare(const void *one, const void *two)
{
int cval;
resResistor *r1 = *((resResistor **)one);
resResistor *r2 = *((resResistor **)two);
if (r1->rr_value < r2->rr_value) return -1;
else if (r1->rr_value == r2->rr_value) return 0;
else return 1;
}
/*
*-------------------------------------------------------------------------
*
@ -424,29 +448,82 @@ ResScrunchNet(reslist, pendingList, biglist, tolerance)
float tolerance;
{
resResistor *locallist = NULL, *current, *working;
resResistor *current, *working;
resNode *node1, *node2;
resElement *rcell1;
int c1, c2;
int c1, c2, count = 0;
/* Sort resistors by size */
current = *reslist;
while (current != NULL)
/* Method used to sort resistors by size depends on list length */
for (current = *reslist; current; current = current->rr_nextResistor)
{
working = current;
current = current->rr_nextResistor;
if (working == *reslist)
*reslist = current;
else
working->rr_lastResistor->rr_nextResistor = current;
count++;
if (count >= 10) break;
}
/* Sort resistors by size */
if (current != NULL)
current->rr_lastResistor = working->rr_lastResistor;
if (count >= 10)
{
int i;
resResistor **resSortList;
ResAddResistorToList(working, &locallist);
/* For long lists, sort using qsort() */
/* NOTE: It might be better to use the same merge sort used for
* MergeSortBreaks() in ResMakeRes.c, as it does not incur the
* overhead of allocating memory and populating the array.
*/
count = 0;
for (current = *reslist; current; current = current->rr_nextResistor)
count++;
resSortList = (resResistor **)mallocMagic(count * sizeof(resResistor *));
count = 0;
for (current = *reslist; current; current = current->rr_nextResistor)
{
resSortList[count] = current;
count++;
}
/* Sort the list */
qsort(resSortList, count, sizeof(resResistor *), qrescompare);
/* Regenerate links on sorted list */
for (i = 0; i < count; i++)
{
current = resSortList[i];
current->rr_nextResistor = (i == count - 1) ? NULL : resSortList[i + 1];
current->rr_lastResistor = (i == 0) ? NULL : resSortList[i - 1];
}
*reslist = resSortList[0];
freeMagic(resSortList);
}
else
{
/* Original method: Walk the linked list and re-sort by size. */
resResistor *locallist = NULL;
current = *reslist;
while (current != NULL)
{
working = current;
current = current->rr_nextResistor;
if (working == *reslist)
*reslist = current;
else
working->rr_lastResistor->rr_nextResistor = current;
if (current != NULL)
current->rr_lastResistor = working->rr_lastResistor;
ResAddResistorToList(working, &locallist);
}
*reslist = locallist;
}
*reslist = locallist;
while (*reslist != NULL && (*reslist)->rr_value < tolerance)
{
current = *reslist;
@ -501,8 +578,8 @@ ResScrunchNet(reslist, pendingList, biglist, tolerance)
}
}
/*
* If the current resistor isn't a deadend, add its value and
* area to that of the next smallest one. If it is a deadend,
* If the current resistor isn't a dead end, add its value and
* area to that of the next smallest one. If it is a dead end,
* simply add its area to its node.
*/
if (c1 != 0 && c2 != 0)
@ -567,7 +644,7 @@ ResAddResistorToList(resistor, locallist)
resResistor *resistor, **locallist;
{
resResistor *local,*last=NULL;
resResistor *local, *last = NULL;
for (local = *locallist; local != NULL; local = local->rr_nextResistor)
{