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 += -O2
CFLAGS += -g
#CFLAGS += -pg
CFLAGS += -pg
CFLAGS += -Wall
CFLAGS += -Wextra
CFLAGS += -march=native
# Next one may be useful for valgrind (some invalid instructions)
# CFLAGS += -mno-tbm
CFLAGS += -Wmissing-declarations
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"
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
@@ -54,6 +56,8 @@ memcheck2:
compile: aoc-c
assembly: aoc-c.s
ex1: aoc-c
@$(TIME) aoc-c -p 1 < $(INPUT)
@@ -66,3 +70,7 @@ clean:
.c:
@echo compiling $<
@$(CC) $(CFLAGS) $(LDFLAGS) -I $(INCDIR) $< $(LDLIB) -o $@
.c.s:
@echo generating $@
@$(CC) -S -fverbose-asm $(CFLAGS) -I $(INCDIR) $< -o $@

View File

@@ -23,31 +23,28 @@
#define MAX_SCANNERS 32 /* I know, I know... */
typedef struct vector {
s64 x, y, z;
int x, y, z;
} vector_t;
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 */
struct list_head list_beacons;
} beacon_t;
typedef struct dist {
u64 dist; /* square distance... */
beacon_t *beacon1, *beacon2; /* ... between these beacons */
int common; /* matched in last dists compare */
uint dist; /* square distance... */
beacon_t *beacon1, *beacon2; /* ... between these beacons */
struct list_head list_dists;
} dist_t;
typedef struct scanner {
int nbeacons, ndists;
int adjusted;
beacon_t *ref[3]; /* reference beacons */
vector_t rel; /* relative position to scanner 0 */
struct list_head list_beacons;
struct list_head list_dists;
beacon_t *ref[3]; /* reference beacons */
//vector_t ref[3];
} scanner_t;
static pool_t *pool_beacon;
@@ -96,7 +93,7 @@ vector_t rotations[] = {
/* 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;
@@ -108,7 +105,7 @@ static vector_t vector_rotate(const vector_t *vector, int nrot)
/* 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;
@@ -120,7 +117,7 @@ static vector_t vector_diff(const vector_t *vec1, vector_t *vec2)
/* 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;
@@ -130,19 +127,27 @@ static vector_t vector_add(const vector_t *vec1, vector_t *vec2)
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
*/
static int insert_dist(scanner_t *scanner, dist_t *dist)
static inline int insert_dist(scanner_t *scanner, dist_t *dist)
{
dist_t *cur;
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 */
list_for_each_entry(cur, &scanner->list_dists, list_dists) {
if (newdist < cur->dist) {
@@ -150,15 +155,17 @@ static int insert_dist(scanner_t *scanner, dist_t *dist)
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);
end:
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;
dist_t *dist;
@@ -180,41 +187,35 @@ static int add_beacon_dists1(scanner_t *scanner, beacon_t *beacon)
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;
//u64 m1 = b1->manhattan, m2 = b2->manhattan;
struct list_head *cur, *tmp;
int count = 0;
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;
list_for_each_safe(cur, tmp, &s2->list_dists) {
dist_t *dist = list_entry(cur, dist_t, list_dists);
if (!dist->common) {
list_del(cur);
insert_dist(s1, dist);
count++;
}
}
return 1;
return count;
}
/* insert a new beacon in scanner's list.
* keep the list ordered by:
* 1) manhattan distance
* 2) x, then y, then z
* keep the list ordered by x, y, then z.
*/
static int insert_unique_beacon(scanner_t *scanner, beacon_t *beacon)
{
beacon_t *cur;
cur = list_first_entry_or_null(&scanner->list_beacons, beacon_t, list_beacons);
/* 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 */
/* normal case: insert before current when new dist is lower than current dist
*/
list_for_each_entry(cur, &scanner->list_beacons, list_beacons) {
switch (compare_beacons(beacon, cur)) {
switch (vector_cmp(&beacon->vec, &cur->vec)) {
case -1:
list_add_tail(&beacon->list_beacons, &cur->list_beacons);
goto end;
@@ -222,33 +223,36 @@ static int insert_unique_beacon(scanner_t *scanner, beacon_t *beacon)
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);
end:
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;
vector_t *vec_ref[3], *vec[3];
for (uint i = 0; i < 3; ++i) {
beacon_ref[i] = ref->ref[i];
beacon[i] = s->ref[i];
vec_ref[i] = &ref->ref[i]->vec;
vec[i] = &scanner->ref[i]->vec;
}
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)
*/
for (int bref = 0; bref < 3; ++bref) {
rot[bref] = vector_rotate(&beacon[bref]->vec, rotnum);
diff[bref] = vector_diff(&beacon_ref[bref]->vec, rot + bref);
diff[bref] = vector_rotate(vec[bref], rotnum);
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 ||
diff[bref].y != diff[0].y ||
@@ -256,14 +260,14 @@ static int adjust_scanner(scanner_t *ref, scanner_t *s)
goto next_rot;
}
}
s->rel = diff[0];
scanner->rel = diff[0]; /* we found a match */
error = 0;
/* 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_add(&cur->vec, &diff[0]);
cur->vec = vector_add(&cur->vec, diff);
}
s->adjusted = 1;
scanner->adjusted = 1;
break;
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.
* - ignore duplicate beacons
* - recalculate all distances for new beacons
* - move dists lists which were
*/
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;
int count = 0;
move_beacon_dists(s1, s2);
list_for_each_safe(cur, tmp, &s2->list_beacons) {
beacon = list_entry(cur, beacon_t, list_beacons);
list_del(cur);
s2->nbeacons--;
if (insert_unique_beacon(s1, beacon) > 0)
add_beacon_dists1(s1, beacon);
if (insert_unique_beacon(s1, beacon) < 0)
pool_add(pool_beacon, beacon);
}
/* free all dists */
/* free all remaining dists from s2 */
list_for_each_safe(cur, tmp, &s2->list_dists) {
dist = list_entry(cur, dist_t, list_dists);
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)
{
struct list_head *plist1, *plist2;
dist_t *pdist1, *pdist2;
beacon_t *tmpbeacon;
int cur1 = 0, cur2 = 0;
u64 dist1, dist2;
dist_t *pdist1, *pdist2, *tmpdist;
uint dist1, dist2;
int nref = 0;
uint count = 0;
@@ -333,10 +336,10 @@ static int count_common_distances(scanner_t *s1, scanner_t *s2)
plist1 = s1->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) {
tmpbeacon->common = 0;
list_for_each_entry(tmpdist, &s2->list_dists, list_dists) {
tmpdist->common = 0;
}
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;
if (dist1 == dist2) {
pdist2->common = 1;
plist1 = plist1->next;
plist2 = plist2->next;
cur1++;
cur2++;
count++;
pdist2->beacon1->common++; /* mark beacons as common in 2nd scanner */
pdist2->beacon2->common++;
switch (nref) {
case 0: /* first 2 reference points */
s1->ref[0] = pdist1->beacon1;
@@ -424,17 +423,16 @@ static int count_common_distances(scanner_t *s1, scanner_t *s2)
} else if (dist1 < dist2) {
plist1 = plist1->next;
cur1++;
} else { /* dist1 > dist2 */
plist2 = plist2->next;
cur2++;
}
}
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()
{
@@ -469,46 +467,44 @@ static int scanners_read()
while ((buflen = getline(&buf, &alloc, stdin)) > 0) {
switch (buf[1]) {
case '-':
case '-': /* scanner header */
scanner = scanners + nscanners;
INIT_LIST_HEAD(&scanner->list_beacons);
INIT_LIST_HEAD(&scanner->list_dists);
nscanners++;
scanner->nbeacons = 0;
break;
case '\0':
case '\0': /* empty line */
break;
default:
beacon = pool_get(pool_beacon);
beacon->scanner = nscanners;
beacon->num = scanner->nbeacons;
sscanf(buf, "%ld,%ld,%ld", &beacon->vec.x, &beacon->vec.y,
sscanf(buf, "%d,%d,%d", &beacon->vec.x, &beacon->vec.y,
&beacon->vec.z);
if (insert_unique_beacon(scanner, beacon) > 0)
add_beacon_dists1(scanner, beacon);
add_beacon_dists(scanner, beacon);
}
}
free(buf);
return nscanners;
}
static s64 part1()
static int part1()
{
return (*scanners).nbeacons;
}
static s64 part2()
static int part2()
{
vector_t *v1, *v2;
s64 max = 0, cur;
int max = 0, cur;
for (int i = 0; i < nscanners; ++i) {
v1 = &scanners[i].rel;
for (int j = i + 1; j < nscanners; ++j) {
v2 = &scanners[j].rel;
cur = labs(v2->x - v1->x)
+ labs(v2->y - v1->y)
+ labs(v2->z - v1->z);
cur = abs(v2->x - v1->x)
+ abs(v2->y - v1->y)
+ abs(v2->z - v1->z);
if (cur > max) {
max = cur;
}
@@ -554,10 +550,8 @@ int main(int ac, char **av)
}
scanners_read();
match_scanners();
printf("%s : res=%ld\n", *av, part == 1? part1(): part2());
pool_stats(pool_beacon);
pool_destroy(pool_beacon);
pool_stats(pool_dist);
pool_destroy(pool_dist);
printf("%s : res=%d\n", *av, part == 1? part1(): part2());
exit(0);
}