shithub: asif

Download patch

ref: 32dbd59557b6b1e476d011d207af4d9b0a8e91dc
parent: 3dc9559c9770afbc525a7e1d5eb24f7b25567904
author: qwx <qwx@sciops.net>
date: Mon Jul 18 21:02:27 EDT 2022

path, a∗: add profiling code, fixes

- nodes now keep track of pnodes to reuse them (bespoke hash table?)
- proper clean up in a∗, avoid leaks

--- a/path/a∗.c
+++ b/path/a∗.c
@@ -19,25 +19,20 @@
 static Zpool *zpool;
 
 static void
-cleanup(Pairheap **queue)
+backtrack(Node *a, Node *b)
 {
-	Pairheap *p;
+	Node *u, *v;
+	PNode *p;
 
-	while((p = popqueue(queue)) != nil){
-		zfree(p->aux);
-		free(p);
+	for(u=b; u!=a; u=v){
+		p = u->aux;
+		stats.cost += p->g;
+		stats.steps++;
+		v = u->from;
+		v->to = u;
 	}
 }
 
-static void
-backtrack(Node *a, Node *b)
-{
-	Node *n;
-
-	for(n=b; n!=a; n=n->from)
-		n->from->to = n;
-}
-
 /* slightly penalize diagonal movement for nicer-looking paths; cf.:
  * https://www.redbloblgames.com/pathfinding/a-star/implementation.html
  * one addition: make cost function to increase at a slower rate to
@@ -73,8 +68,10 @@
 		assert(nv >= grid && nv < grid + gridwidth * gridheight);
 		if(isblocked(nv))
 			continue;
-		v = zalloc(zpool);
-		v->n = nv;
+		if((v = nv->aux) == nil){
+			v = nv->aux = zalloc(zpool);
+			v->n = nv;
+		}
 		v->Δg = movecost(dtab[i], dtab[i+1]);
 		*vp++ = v;
 	}
@@ -109,8 +106,10 @@
 		assert(nv >= grid && nv < grid + gridwidth * gridheight);
 		if(isblocked(nv))
 			continue;
-		v = zalloc(zpool);
-		v->n = nv;
+		if((v = nv->aux) == nil){
+			v = nv->aux = zalloc(zpool);
+			v->n = nv;
+		}
 		v->Δg = movecost(t[i], t[i+1]);
 		*vp++ = v;
 	}
@@ -126,9 +125,8 @@
 	Pairheap *queue, *pn;
 
 	queue = nil;
-	nu = a;
-	u = zalloc(zpool);
-	u->n = a;
+	u = a->aux = zalloc(zpool);
+	nu = u->n = a;
 	u->pq = pushqueue(distfn(a, b), u, &queue);
 	while((pn = popqueue(&queue)) != nil){
 		u = pn->aux;
@@ -137,6 +135,7 @@
 		if(nu == b)
 			break;
 		nu->closed = 1;
+		stats.closed++;
 		dprint(Logtrace, "a∗: closed [%#p,%P] h %.4f g %.4f\n",
 			u, n2p(nu), u->h, u->g);
 		if((vl = successorfn(nu)) == nil)
@@ -143,6 +142,7 @@
 			sysfatal("a∗: %r");
 		for(v=*vl++; v!=nil; v=*vl++){
 			nv = v->n;
+			stats.touched++;
 			if(nv->closed)
 				continue;
 			g = u->g + v->Δg;
@@ -150,6 +150,7 @@
 			if(!nv->open){
 				nv->from = nu;
 				nv->open = 1;
+				stats.opened++;
 				v->h = distfn(nv, b);
 				v->g = g;
 				dprint(Logtrace, "a∗: opened [%#p,%P] h %.4f g %.4f f %.4f\n",
@@ -156,6 +157,7 @@
 					v, n2p(nv), v->h, v->g, v->h + v->g);
 				v->pq = pushqueue(v->g + v->h, v, &queue);
 			}else if(Δg > 0){
+				stats.updated++;
 				dprint(Logtrace, "a∗: decrease [%#p,%P] h %.4f g %.4f Δg %.4f → f %.4f\n",
 					v, n2p(nv), v->h, v->g, Δg, v->h + v->g - Δg);
 				nv->from = u->n;
@@ -165,10 +167,9 @@
 			}
 		}
 	}
-	cleanup(&queue);
+	nukequeue(&queue);
 	if(nu != b)
 		return -1;
-	backtrack(a, b);
 	return 0;
 }
 
@@ -175,6 +176,8 @@
 int
 a∗findpath(Node *a, Node *b)
 {
+	int r;
+
 	assert(a != nil && b != nil && a != b);
 	clearpath();
 	if(zpool == nil)
@@ -182,9 +185,10 @@
 	successorfn = movemode == Move8 ? successors8 : successors4;
 	dprint(Logdebug, "grid::a∗findpath: a∗ from [%#p,%P] to [%#p,%P]\n",
 		a, n2p(a), b, n2p(b));
-	if(a∗(a, b) < 0){
+	if((r = a∗(a, b)) < 0)
 		dprint(Logdebug, "grid::a∗findpath: failed to find a path\n");
-		return -1;
-	}
-	return 0;
+	else
+		backtrack(a, b);
+	znuke(zpool);
+	return r;
 }
--- a/path/grid.c
+++ b/path/grid.c
@@ -7,6 +7,9 @@
 int gridwidth, gridheight;
 double	(*distfn)(Node*, Node*);
 
+int doprof;
+Prof stats;
+
 double
 eucdist(Node *a, Node *b)
 {
@@ -58,6 +61,7 @@
 		return;
 	for(n=grid; n<grid+gridwidth*gridheight; n++)
 		memset(&n->PState, 0, sizeof n->PState);
+	memset(&stats, 0, sizeof stats);
 }
 
 void
@@ -81,6 +85,26 @@
 n2p(Node *n)
 {
 	return (Vertex){(n - grid) % gridwidth, (n - grid) / gridheight};
+}
+
+int
+Vfmt(Fmt *f)
+{
+	Vertex v;
+
+	v = va_arg(f->args, Vertex);
+	return fmtprint(f, "[%d %d]", v.x, v.y);
+}
+
+int
+Nfmt(Fmt *f)
+{
+	Node *n;
+	Vertex v;
+
+	n = va_arg(f->args, Node*);
+	v = n2p(n);
+	return fmtprint(f, "[%#p %V]", n, v);
 }
 
 Node *
--- a/path/path.h
+++ b/path/path.h
@@ -2,6 +2,7 @@
 typedef struct PState PState;
 typedef struct Node Node;
 typedef struct Vertex Vertex;
+typedef struct Prof Prof;
 
 struct Vertex{
 	int x;
@@ -12,6 +13,7 @@
 	int closed;
 	Node *from;
 	Node *to;
+	void *aux;
 };
 struct State{
 	int blocked;
@@ -53,3 +55,18 @@
 int	a∗findpath(Node*, Node*);
 int	bfsfindpath(Node*, Node*);
 int	dijkstrafindpath(Node*, Node*);
+
+struct Prof{
+	double dist;
+	double cost;
+	int steps;
+	int touched;
+	int opened;
+	int updated;
+	int closed;
+};
+extern Prof stats;
+extern int doprof;
+
+#pragma	varargck	type	"N"	Node*
+#pragma	varargck	type	"V"	Vertex