Skip to content

Commit 2ca24e9

Browse files
committed
Multi-threaded unit test for 5x speed-up
1 parent c141d47 commit 2ca24e9

File tree

1 file changed

+83
-47
lines changed

1 file changed

+83
-47
lines changed

unittest/unittest.c

Lines changed: 83 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include <stdio.h>
2323
#include <math.h>
2424
#include <time.h>
25+
#include <pthread.h>
2526

2627
#include "../mapcodelib/mapcoder.c"
2728
#include "../mapcodelib/mapcode_countrynames_short.h"
@@ -31,6 +32,8 @@
3132
extern void test_territories();
3233

3334
#define MAXLINESIZE 1024
35+
#define MAX_THREADS 16
36+
3437

3538
// globals to count tests, errors and warnings
3639
int nrTests = 0;
@@ -230,7 +233,7 @@ static void testEncodeAndDecode(const char *str, double y, double x, int localso
230233
nrTests++;
231234
if (nrresults != localsolutions) {
232235
nrErrors++;
233-
printf("*** ERROR *** encode(%0.8f , %0.8f,%d) does not deliver %d local solutions\n",
236+
printf("*** ERROR *** encode(%0.8f, %0.8f,%d) does not deliver %d local solutions\n",
234237
y, x, tc, localsolutions);
235238
printGeneratedMapcodes("Delivered", &mapcodes);
236239
}
@@ -246,7 +249,7 @@ static void testEncodeAndDecode(const char *str, double y, double x, int localso
246249
}
247250
if (!found) {
248251
nrErrors++;
249-
printf("*** ERROR *** encode(%0.8f , %0.8f) does not deliver \"%s\"\n", y, x, clean);
252+
printf("*** ERROR *** encode(%0.8f, %0.8f) does not deliver \"%s\"\n", y, x, clean);
250253
printGeneratedMapcodes("Delivered", &mapcodes);
251254
}
252255
}
@@ -258,7 +261,7 @@ static void testEncodeAndDecode(const char *str, double y, double x, int localso
258261
nrresults = encodeLatLonToMapcodes(&mapcodes, y, x, 0, precision);
259262
if (nrresults != globalsolutions) {
260263
nrErrors++;
261-
printf("*** ERROR *** encode(%0.8f , %0.8f) does not deliver %d global solutions\n", y, x, globalsolutions);
264+
printf("*** ERROR *** encode(%0.8f, %0.8f) does not deliver %d global solutions\n", y, x, globalsolutions);
262265
printGeneratedMapcodes("Delivered", &mapcodes);
263266
}
264267
}
@@ -274,15 +277,15 @@ static void testEncodeAndDecode(const char *str, double y, double x, int localso
274277
err = decodeMapcodeToLatLon(&lat, &lon, strResult, 0);
275278
if (err) {
276279
nrErrors++;
277-
printf("*** ERROR *** decode('%s') = no result, expected ~(%0.8f , %0.8f)\n", strResult, y, x);
280+
printf("*** ERROR *** decode('%s') = no result, expected ~(%0.8f, %0.8f)\n", strResult, y, x);
278281
} else {
279282
double dm = distanceInMeters(y, x, lat, lon);
280283
double maxerror = maxErrorInMeters(precision);
281284
// check if decode is sufficiently close to the encoded coordinate
282285
nrTests++;
283286
if (dm > maxerror) {
284287
nrErrors++;
285-
printf("*** ERROR *** decode('%s') = (%0.8f , %0.8f), which is %0.4f cm way (>%0.4f cm) from (%0.8f , %0.8f)\n",
288+
printf("*** ERROR *** decode('%s') = (%0.8f, %0.8f), which is %0.4f cm away (>%0.4f cm) from (%0.8f, %0.8f)\n",
286289
strResult, lat, lon,
287290
dm * 100.0, maxerror * 100.0, y, x);
288291
} else {
@@ -423,18 +426,6 @@ static void test_failing_decodes() {
423426
}
424427
}
425428

426-
// perform testEncodeAndDecode for all elements of encode_test[] (from decode_test.h)
427-
void encode_decode_tests() {
428-
int i = 0;
429-
int nr = sizeof(encode_test) / sizeof(encode_test_record) - 1;
430-
printf("%d encodes\n", nr);
431-
for (i = 0; i < nr; i++) {
432-
show_progress(i, nr);
433-
const encode_test_record *t = &encode_test[i];
434-
testEncodeAndDecode(t->mapcode, t->latitude, t->longitude, t->nr_local_mapcodes, t->nr_global_mapcodes);
435-
}
436-
}
437-
438429
// perform tests on alphacodes (designed in test_territories.c)
439430
void test_territory(const char *alphaCode, int tc, int isAlias, int needsParent, int tcParent) {
440431

@@ -491,46 +482,91 @@ static void test_around(double y, double x) {
491482
testEncodeAndDecode("", y - 0.00001, x - 0.00001, 0, 0);
492483
}
493484

485+
486+
void join_threads(pthread_t *threads, int total) {
487+
for (int i = 0; i < total; ++i) {
488+
if (pthread_join(threads[i], 0)) {
489+
nrErrors++;
490+
fprintf(stderr, "*** ERROR *** Error joining thread %d of %d\n", i, total);
491+
return;
492+
493+
}
494+
}
495+
}
496+
497+
// perform testEncodeAndDecode for all elements of encode_test[] (from decode_test.h)
498+
void encode_decode_tests() {
499+
int i = 0;
500+
int nr = sizeof(encode_test) / sizeof(encode_test_record) - 1;
501+
printf("%d encodes\n", nr);
502+
for (i = 0; i < nr; i++) {
503+
show_progress(i, nr);
504+
const encode_test_record *t = &encode_test[i];
505+
testEncodeAndDecode(t->mapcode, t->latitude, t->longitude, t->nr_local_mapcodes, t->nr_global_mapcodes);
506+
}
507+
}
508+
509+
void *execute_test_around(void *context_mminforec) {
510+
double y, x, midx, midy, thirdx;
511+
const mminforec *b = (mminforec *) context_mminforec;
512+
513+
midy = (b->miny + b->maxy) / 2000000.0;
514+
midx = (b->minx + b->maxx) / 2000000.0;
515+
thirdx = (2 * b->minx + b->maxx) / 3000000.0;
516+
test_around(midy, midx);
517+
518+
y = (b->miny) / 1000000.0;
519+
x = (b->minx) / 1000000.0;
520+
test_around(y, x);
521+
test_around(midy, x);
522+
test_around(y, midx);
523+
test_around(y, thirdx);
524+
525+
x = (b->maxx) / 1000000.0;
526+
test_around(y, x);
527+
test_around(midy, x);
528+
529+
y = (b->maxy) / 1000000.0;
530+
x = (b->minx) / 1000000.0;
531+
test_around(y, x);
532+
test_around(y, midx);
533+
534+
x = (b->maxx) / 1000000.0;
535+
test_around(y, x);
536+
test_around(midy, x);
537+
return 0;
538+
}
539+
494540
// test around all centers and corners of all territory rectangles
495541
static void re_encode_tests() {
496-
int ccode, m;
497-
int nrrecords = lastrec(ccode_earth) + 1;
498-
printf("%d records\n", nrrecords);
542+
int ccode = 0;
543+
int m = 0;
544+
int nrRecords = lastrec(ccode_earth) + 1;
545+
int nrThread = 0;
546+
pthread_t threads[MAX_THREADS];
547+
printf("%d records\n", nrRecords);
499548
for (ccode = 0; ccode <= ccode_earth; ccode++) {
500549
show_progress(ccode, ccode_earth);
501550
for (m = firstrec(ccode); m <= lastrec(ccode); m++) {
502-
double y, x, midx, midy, thirdx;
503551
const mminforec *b = boundaries(m);
504-
505-
midy = (b->miny + b->maxy) / 2000000.0;
506-
midx = (b->minx + b->maxx) / 2000000.0;
507-
thirdx = (2 * b->minx + b->maxx) / 3000000.0;
508-
test_around(midy, midx);
509-
510-
y = (b->miny) / 1000000.0;
511-
x = (b->minx) / 1000000.0;
512-
test_around(y, x);
513-
test_around(midy, x);
514-
test_around(y, midx);
515-
test_around(y, thirdx);
516-
517-
x = (b->maxx) / 1000000.0;
518-
test_around(y, x);
519-
test_around(midy, x);
520-
521-
y = (b->maxy) / 1000000.0;
522-
x = (b->minx) / 1000000.0;
523-
test_around(y, x);
524-
test_around(y, midx);
525-
526-
x = (b->maxx) / 1000000.0;
527-
test_around(y, x);
528-
test_around(midy, x);
552+
if (nrThread < MAX_THREADS) {
553+
// Execute the test on a new thread.
554+
if (pthread_create(&threads[nrThread], 0, execute_test_around, (void *) b)) {
555+
nrErrors++;
556+
fprintf(stderr, "*** ERROR *** Cannot create thread\n");
557+
return;
558+
}
559+
nrThread++;
560+
} else {
561+
join_threads(threads, nrThread);
562+
nrThread = 0;
563+
}
529564
}
565+
join_threads(threads, nrThread);
566+
nrThread = 0;
530567
}
531568
}
532569

533-
534570
void distance_tests() {
535571
if (strcmp(mapcode_cversion, "2.1.3") >= 0) {
536572
int i;

0 commit comments

Comments
 (0)