day 19, after optimization (8.5s -> 0.06s)

This commit is contained in:
2022-01-22 19:37:25 +01:00
parent c84a37874c
commit 5346b0e7fa
2 changed files with 95 additions and 93 deletions

View File

@@ -27,10 +27,12 @@ export LD_LIBRARY_PATH = $(LIBDIR)
CFLAGS += -std=gnu99 CFLAGS += -std=gnu99
CFLAGS += -O2 CFLAGS += -O2
CFLAGS += -g CFLAGS += -g
#CFLAGS += -pg CFLAGS += -pg
CFLAGS += -Wall CFLAGS += -Wall
CFLAGS += -Wextra CFLAGS += -Wextra
CFLAGS += -march=native CFLAGS += -march=native
# Next one may be useful for valgrind (some invalid instructions)
# CFLAGS += -mno-tbm
CFLAGS += -Wmissing-declarations CFLAGS += -Wmissing-declarations
CFLAGS += -Wno-unused-result CFLAGS += -Wno-unused-result
@@ -40,7 +42,7 @@ CFLAGS += -DDEBUG_POOL # memory pools management
TIME := \time -f "\ttime: %E real, %U user, %S sys\n\tcontext-switch:\t%c+%w, page-faults: %F+%R\n" TIME := \time -f "\ttime: %E real, %U user, %S sys\n\tcontext-switch:\t%c+%w, page-faults: %F+%R\n"
export PATH := .:$(PATH) export PATH := .:$(PATH)
.PHONY: clean all compile memcheck memcheck1 memcheck2 ex1 ex2 .PHONY: clean all compile assembly memcheck memcheck1 memcheck2 ex1 ex2
all: ex1 ex2 all: ex1 ex2
@@ -54,6 +56,8 @@ memcheck2:
compile: aoc-c compile: aoc-c
assembly: aoc-c.s
ex1: aoc-c ex1: aoc-c
@$(TIME) aoc-c -p 1 < $(INPUT) @$(TIME) aoc-c -p 1 < $(INPUT)
@@ -66,3 +70,7 @@ clean:
.c: .c:
@echo compiling $< @echo compiling $<
@$(CC) $(CFLAGS) $(LDFLAGS) -I $(INCDIR) $< $(LDLIB) -o $@ @$(CC) $(CFLAGS) $(LDFLAGS) -I $(INCDIR) $< $(LDLIB) -o $@
.c.s:
@echo generating $@
@$(CC) -S -fverbose-asm $(CFLAGS) -I $(INCDIR) $< -o $@

View File

@@ -23,19 +23,17 @@
#define MAX_SCANNERS 32 /* I know, I know... */ #define MAX_SCANNERS 32 /* I know, I know... */
typedef struct vector { typedef struct vector {
s64 x, y, z; int x, y, z;
} vector_t; } vector_t;
typedef struct beacon { typedef struct beacon {
int scanner; /* original scanner for beacon */
int num; /* original # in original scanner */
int common; /* has common distance with 1st scanner */
vector_t vec; /* beacon coordinates */ vector_t vec; /* beacon coordinates */
struct list_head list_beacons; struct list_head list_beacons;
} beacon_t; } beacon_t;
typedef struct dist { typedef struct dist {
u64 dist; /* square distance... */ int common; /* matched in last dists compare */
uint dist; /* square distance... */
beacon_t *beacon1, *beacon2; /* ... between these beacons */ beacon_t *beacon1, *beacon2; /* ... between these beacons */
struct list_head list_dists; struct list_head list_dists;
} dist_t; } dist_t;
@@ -43,11 +41,10 @@ typedef struct dist {
typedef struct scanner { typedef struct scanner {
int nbeacons, ndists; int nbeacons, ndists;
int adjusted; int adjusted;
beacon_t *ref[3]; /* reference beacons */
vector_t rel; /* relative position to scanner 0 */ vector_t rel; /* relative position to scanner 0 */
struct list_head list_beacons; struct list_head list_beacons;
struct list_head list_dists; struct list_head list_dists;
beacon_t *ref[3]; /* reference beacons */
//vector_t ref[3];
} scanner_t; } scanner_t;
static pool_t *pool_beacon; static pool_t *pool_beacon;
@@ -96,7 +93,7 @@ vector_t rotations[] = {
/* vector_rotate: returns vector rotation vector by "nrot"th rotations matrix /* vector_rotate: returns vector rotation vector by "nrot"th rotations matrix
*/ */
static vector_t vector_rotate(const vector_t *vector, int nrot) static inline vector_t vector_rotate(const vector_t *vector, const int nrot)
{ {
vector_t *rot = &rotations[nrot*3], res; vector_t *rot = &rotations[nrot*3], res;
@@ -108,7 +105,7 @@ static vector_t vector_rotate(const vector_t *vector, int nrot)
/* beacon_diff: returns difference between 2 vectors /* beacon_diff: returns difference between 2 vectors
*/ */
static vector_t vector_diff(const vector_t *vec1, vector_t *vec2) static inline vector_t vector_diff(const vector_t *vec1, const vector_t *vec2)
{ {
vector_t res; vector_t res;
@@ -120,7 +117,7 @@ static vector_t vector_diff(const vector_t *vec1, vector_t *vec2)
/* beacon_diff: calculate sum of two vectors /* beacon_diff: calculate sum of two vectors
*/ */
static vector_t vector_add(const vector_t *vec1, vector_t *vec2) static inline vector_t vector_add(const vector_t *vec1, const vector_t *vec2)
{ {
vector_t res; vector_t res;
@@ -130,19 +127,27 @@ static vector_t vector_add(const vector_t *vec1, vector_t *vec2)
return res; return res;
} }
/* compare two beacons by x, y, and z.
*/
static inline int vector_cmp(const vector_t *v1, const vector_t *v2)
{
if (v1->x < v2->x ||
(v1->x == v2->x && (v1->y < v2->y ||
(v1->y == v2->y && v1->z < v2->z)))) {
return -1;
} else if (v1->x == v2->x && v1->y == v2->y && v1->z == v2->z) {
return 0;
}
return 1;
}
/* insert a new distance in scanner's (sorted) distances list /* insert a new distance in scanner's (sorted) distances list
*/ */
static int insert_dist(scanner_t *scanner, dist_t *dist) static inline int insert_dist(scanner_t *scanner, dist_t *dist)
{ {
dist_t *cur; dist_t *cur;
uint newdist = dist->dist; uint newdist = dist->dist;
cur = list_first_entry_or_null(&scanner->list_dists, dist_t, list_dists);
/* special case: first distance or new dist lower than first dist */
if (!cur || newdist < cur->dist) {
list_add(&dist->list_dists, &scanner->list_dists);
goto end;
}
/* normal case: insert before current when new dist is lower than current dist */ /* normal case: insert before current when new dist is lower than current dist */
list_for_each_entry(cur, &scanner->list_dists, list_dists) { list_for_each_entry(cur, &scanner->list_dists, list_dists) {
if (newdist < cur->dist) { if (newdist < cur->dist) {
@@ -150,15 +155,17 @@ static int insert_dist(scanner_t *scanner, dist_t *dist)
goto end; goto end;
} }
} }
/* special case: we went to end, insert at list's tail */ /* special case: we went to end without inserting, insert at list's tail.
* This includes the case list was empty.
*/
list_add_tail(&dist->list_dists, &scanner->list_dists); list_add_tail(&dist->list_dists, &scanner->list_dists);
end: end:
return ++scanner->ndists; return ++scanner->ndists;
} }
/* add distances between beacon and all others /* add distances between beacon and all other beacons in scanner.
*/ */
static int add_beacon_dists1(scanner_t *scanner, beacon_t *beacon) static int add_beacon_dists(scanner_t *scanner, beacon_t *beacon)
{ {
beacon_t *cur; beacon_t *cur;
dist_t *dist; dist_t *dist;
@@ -180,41 +187,35 @@ static int add_beacon_dists1(scanner_t *scanner, beacon_t *beacon)
return count; return count;
} }
/* compare two beacons by x, y, and z. /* move non common dists from scanner s2 to scanner s1
*/ */
static inline int compare_beacons(beacon_t *b1, beacon_t *b2) static int move_beacon_dists(scanner_t *s1, scanner_t *s2)
{ {
vector_t *v1 = &b1->vec, *v2 = &b2->vec; struct list_head *cur, *tmp;
//u64 m1 = b1->manhattan, m2 = b2->manhattan; int count = 0;
if (v1->x < v2->x || list_for_each_safe(cur, tmp, &s2->list_dists) {
(v1->x == v2->x && (v1->y < v2->y || dist_t *dist = list_entry(cur, dist_t, list_dists);
(v1->y == v2->y && v1->z < v2->z)))) { if (!dist->common) {
return -1; list_del(cur);
} else if (v1->x == v2->x && v1->y == v2->y && v1->z == v2->z) { insert_dist(s1, dist);
return 0; count++;
} }
return 1; }
return count;
} }
/* insert a new beacon in scanner's list. /* insert a new beacon in scanner's list.
* keep the list ordered by: * keep the list ordered by x, y, then z.
* 1) manhattan distance
* 2) x, then y, then z
*/ */
static int insert_unique_beacon(scanner_t *scanner, beacon_t *beacon) static int insert_unique_beacon(scanner_t *scanner, beacon_t *beacon)
{ {
beacon_t *cur; beacon_t *cur;
cur = list_first_entry_or_null(&scanner->list_beacons, beacon_t, list_beacons); /* normal case: insert before current when new dist is lower than current dist
/* special case: first beacon or new beacon lower than first beacon */ */
if (!cur || compare_beacons(beacon, cur) < 0) {
list_add(&beacon->list_beacons, &scanner->list_beacons);
goto end;
}
/* normal case: insert before current when new dist is lower than current dist */
list_for_each_entry(cur, &scanner->list_beacons, list_beacons) { list_for_each_entry(cur, &scanner->list_beacons, list_beacons) {
switch (compare_beacons(beacon, cur)) { switch (vector_cmp(&beacon->vec, &cur->vec)) {
case -1: case -1:
list_add_tail(&beacon->list_beacons, &cur->list_beacons); list_add_tail(&beacon->list_beacons, &cur->list_beacons);
goto end; goto end;
@@ -222,33 +223,36 @@ static int insert_unique_beacon(scanner_t *scanner, beacon_t *beacon)
return -1; return -1;
} }
} }
/* special case: we went to end, insert at list's tail */ /* special case: we went to end without inserting, insert at list's tail.
* This includes the case list was empty.
*/
list_add_tail(&beacon->list_beacons, &scanner->list_beacons); list_add_tail(&beacon->list_beacons, &scanner->list_beacons);
end: end:
return ++scanner->nbeacons; return ++scanner->nbeacons;
} }
/* using scanner's reference points, find the correct rotation and translation /* using scanner's 3 reference beacons, find the correct rotation and translation
*/ */
static int adjust_scanner(scanner_t *ref, scanner_t *s) static int adjust_scanner(scanner_t *ref, scanner_t *scanner)
{ {
beacon_t *beacon_ref[3], *beacon[3], *cur; beacon_t *cur;
int error = -1; int error = -1;
vector_t *vec_ref[3], *vec[3];
for (uint i = 0; i < 3; ++i) { for (uint i = 0; i < 3; ++i) {
beacon_ref[i] = ref->ref[i]; vec_ref[i] = &ref->ref[i]->vec;
beacon[i] = s->ref[i]; vec[i] = &scanner->ref[i]->vec;
} }
for (uint rotnum = 0; rotnum < NROTATIONS; ++rotnum) { for (uint rotnum = 0; rotnum < NROTATIONS; ++rotnum) {
vector_t rot[3], diff[3]; vector_t diff[3];
/* rotate the first beacon and translate to match ref's (x, y, z) /* rotate the first beacon and translate to match ref's (x, y, z)
*/ */
for (int bref = 0; bref < 3; ++bref) { for (int bref = 0; bref < 3; ++bref) {
rot[bref] = vector_rotate(&beacon[bref]->vec, rotnum); diff[bref] = vector_rotate(vec[bref], rotnum);
diff[bref] = vector_diff(&beacon_ref[bref]->vec, rot + bref); diff[bref] = vector_diff(vec_ref[bref], diff + bref);
/* check that rotation/translation works for the 3 reference points /* Does rotation/translation works for the 3 reference points ?
*/ */
if (bref > 0 && (diff[bref].x != diff[0].x || if (bref > 0 && (diff[bref].x != diff[0].x ||
diff[bref].y != diff[0].y || diff[bref].y != diff[0].y ||
@@ -256,14 +260,14 @@ static int adjust_scanner(scanner_t *ref, scanner_t *s)
goto next_rot; goto next_rot;
} }
} }
s->rel = diff[0]; scanner->rel = diff[0]; /* we found a match */
error = 0; error = 0;
/* adjust all beacons */ /* adjust all beacons */
list_for_each_entry(cur, &s->list_beacons, list_beacons) { list_for_each_entry(cur, &scanner->list_beacons, list_beacons) {
cur->vec = vector_rotate(&cur->vec, rotnum); cur->vec = vector_rotate(&cur->vec, rotnum);
cur->vec = vector_add(&cur->vec, &diff[0]); cur->vec = vector_add(&cur->vec, diff);
} }
s->adjusted = 1; scanner->adjusted = 1;
break; break;
next_rot: next_rot:
@@ -274,7 +278,7 @@ static int adjust_scanner(scanner_t *ref, scanner_t *s)
/* merge scanner s2 (already translated) beacons into scanner s1. /* merge scanner s2 (already translated) beacons into scanner s1.
* - ignore duplicate beacons * - ignore duplicate beacons
* - recalculate all distances for new beacons * - move dists lists which were
*/ */
static int merge_scanner(scanner_t *s1, scanner_t *s2) static int merge_scanner(scanner_t *s1, scanner_t *s2)
{ {
@@ -283,14 +287,15 @@ static int merge_scanner(scanner_t *s1, scanner_t *s2)
dist_t *dist; dist_t *dist;
int count = 0; int count = 0;
move_beacon_dists(s1, s2);
list_for_each_safe(cur, tmp, &s2->list_beacons) { list_for_each_safe(cur, tmp, &s2->list_beacons) {
beacon = list_entry(cur, beacon_t, list_beacons); beacon = list_entry(cur, beacon_t, list_beacons);
list_del(cur); list_del(cur);
s2->nbeacons--; s2->nbeacons--;
if (insert_unique_beacon(s1, beacon) > 0) if (insert_unique_beacon(s1, beacon) < 0)
add_beacon_dists1(s1, beacon); pool_add(pool_beacon, beacon);
} }
/* free all dists */ /* free all remaining dists from s2 */
list_for_each_safe(cur, tmp, &s2->list_dists) { list_for_each_safe(cur, tmp, &s2->list_dists) {
dist = list_entry(cur, dist_t, list_dists); dist = list_entry(cur, dist_t, list_dists);
list_del(cur); list_del(cur);
@@ -310,10 +315,8 @@ static int merge_scanner(scanner_t *s1, scanner_t *s2)
static int count_common_distances(scanner_t *s1, scanner_t *s2) static int count_common_distances(scanner_t *s1, scanner_t *s2)
{ {
struct list_head *plist1, *plist2; struct list_head *plist1, *plist2;
dist_t *pdist1, *pdist2; dist_t *pdist1, *pdist2, *tmpdist;
beacon_t *tmpbeacon; uint dist1, dist2;
int cur1 = 0, cur2 = 0;
u64 dist1, dist2;
int nref = 0; int nref = 0;
uint count = 0; uint count = 0;
@@ -333,10 +336,10 @@ static int count_common_distances(scanner_t *s1, scanner_t *s2)
plist1 = s1->list_dists.next; plist1 = s1->list_dists.next;
plist2 = s2->list_dists.next; plist2 = s2->list_dists.next;
/* initialize second scanner common beacons /* initialize second scanner dists
*/ */
list_for_each_entry(tmpbeacon, &s2->list_beacons, list_beacons) { list_for_each_entry(tmpdist, &s2->list_dists, list_dists) {
tmpbeacon->common = 0; tmpdist->common = 0;
} }
while (plist1 != &s1->list_dists && plist2 != &s2->list_dists) { while (plist1 != &s1->list_dists && plist2 != &s2->list_dists) {
@@ -346,15 +349,11 @@ static int count_common_distances(scanner_t *s1, scanner_t *s2)
dist2 = pdist2->dist; dist2 = pdist2->dist;
if (dist1 == dist2) { if (dist1 == dist2) {
pdist2->common = 1;
plist1 = plist1->next; plist1 = plist1->next;
plist2 = plist2->next; plist2 = plist2->next;
cur1++;
cur2++;
count++; count++;
pdist2->beacon1->common++; /* mark beacons as common in 2nd scanner */
pdist2->beacon2->common++;
switch (nref) { switch (nref) {
case 0: /* first 2 reference points */ case 0: /* first 2 reference points */
s1->ref[0] = pdist1->beacon1; s1->ref[0] = pdist1->beacon1;
@@ -424,17 +423,16 @@ static int count_common_distances(scanner_t *s1, scanner_t *s2)
} else if (dist1 < dist2) { } else if (dist1 < dist2) {
plist1 = plist1->next; plist1 = plist1->next;
cur1++;
} else { /* dist1 > dist2 */ } else { /* dist1 > dist2 */
plist2 = plist2->next; plist2 = plist2->next;
cur2++;
} }
} }
return count; return count;
} }
/* match all scanners /* match all scanners with scanner 0.
* When a match is found, merge it into scanner 0.
*/ */
static void match_scanners() static void match_scanners()
{ {
@@ -469,46 +467,44 @@ static int scanners_read()
while ((buflen = getline(&buf, &alloc, stdin)) > 0) { while ((buflen = getline(&buf, &alloc, stdin)) > 0) {
switch (buf[1]) { switch (buf[1]) {
case '-': case '-': /* scanner header */
scanner = scanners + nscanners; scanner = scanners + nscanners;
INIT_LIST_HEAD(&scanner->list_beacons); INIT_LIST_HEAD(&scanner->list_beacons);
INIT_LIST_HEAD(&scanner->list_dists); INIT_LIST_HEAD(&scanner->list_dists);
nscanners++; nscanners++;
scanner->nbeacons = 0; scanner->nbeacons = 0;
break; break;
case '\0': case '\0': /* empty line */
break; break;
default: default:
beacon = pool_get(pool_beacon); beacon = pool_get(pool_beacon);
beacon->scanner = nscanners; sscanf(buf, "%d,%d,%d", &beacon->vec.x, &beacon->vec.y,
beacon->num = scanner->nbeacons;
sscanf(buf, "%ld,%ld,%ld", &beacon->vec.x, &beacon->vec.y,
&beacon->vec.z); &beacon->vec.z);
if (insert_unique_beacon(scanner, beacon) > 0) if (insert_unique_beacon(scanner, beacon) > 0)
add_beacon_dists1(scanner, beacon); add_beacon_dists(scanner, beacon);
} }
} }
free(buf); free(buf);
return nscanners; return nscanners;
} }
static s64 part1() static int part1()
{ {
return (*scanners).nbeacons; return (*scanners).nbeacons;
} }
static s64 part2() static int part2()
{ {
vector_t *v1, *v2; vector_t *v1, *v2;
s64 max = 0, cur; int max = 0, cur;
for (int i = 0; i < nscanners; ++i) { for (int i = 0; i < nscanners; ++i) {
v1 = &scanners[i].rel; v1 = &scanners[i].rel;
for (int j = i + 1; j < nscanners; ++j) { for (int j = i + 1; j < nscanners; ++j) {
v2 = &scanners[j].rel; v2 = &scanners[j].rel;
cur = labs(v2->x - v1->x) cur = abs(v2->x - v1->x)
+ labs(v2->y - v1->y) + abs(v2->y - v1->y)
+ labs(v2->z - v1->z); + abs(v2->z - v1->z);
if (cur > max) { if (cur > max) {
max = cur; max = cur;
} }
@@ -554,10 +550,8 @@ int main(int ac, char **av)
} }
scanners_read(); scanners_read();
match_scanners(); match_scanners();
printf("%s : res=%ld\n", *av, part == 1? part1(): part2());
pool_stats(pool_beacon);
pool_destroy(pool_beacon); pool_destroy(pool_beacon);
pool_stats(pool_dist);
pool_destroy(pool_dist); pool_destroy(pool_dist);
printf("%s : res=%d\n", *av, part == 1? part1(): part2());
exit(0); exit(0);
} }