From 523cb1e7366d1043aa76d8003741fb71bf01fe00 Mon Sep 17 00:00:00 2001 From: alex Date: Tue, 9 Jun 2015 19:54:38 +0100 Subject: [PATCH] v2.6 +multi-threading --- CHANGELOG | 6 + Makefile | 2 +- README.md | 4 +- common.h | 4 +- main.cc | 37 +++- main.hh | 5 + models/itwom3.0.cc | 23 +-- models/los.cc | 448 +++++++++++++++++++++++++-------------------- models/los.hh | 4 +- test.sh | 6 +- 10 files changed, 309 insertions(+), 230 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 5406fd7..6d0d2bc 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,11 @@ SIGNAL SERVER CHANGELOG +2.6 - 9 June 2015 +Multithreading support added by Michael Ramnarine +PlotPropagation() and PlotLOSMap() use four threads by default +Feature can be disabled with -nothreads flag +Static and global variables have been made threadsafe + 2.5 - 27 May 2015 Code refactored by Andrew Clayton / ac000 with header files New Makefile with c / c++ multi mode compilation diff --git a/Makefile b/Makefile index df5bf0a..4266998 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ CC = gcc CXX = g++ CFLAGS = -Wall -O3 -s -ffast-amth CXXFLAGS = -Wall -O3 -s -ffast-math -LIBS = -lm +LIBS = -lm -lpthread VPATH = models objects = main.o cost.o ecc33.o ericsson.o fspl.o hata.o itwom3.0.o \ diff --git a/README.md b/README.md index d3275ea..c348498 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ * * \****************************************************************************/ - -- Signal Server 2.5 -- + -- Signal Server 2.6 -- Compiled for 64 tiles at 1200 pixels/degree -d Directory containing .sdf tiles @@ -52,4 +52,6 @@ -ked Knife edge diffraction (Default for ITM) -ng Normalise Path Profile graph -haf Halve 1 or 2 (optional) + -nothreads Turn off threaded processing (optional) + diff --git a/common.h b/common.h index 354a0df..e98e500 100644 --- a/common.h +++ b/common.h @@ -98,7 +98,7 @@ extern double clutter; extern double dBm; extern double loss; extern double field_strength; -extern double *elev; +extern __thread double *elev; extern char string[]; extern char sdf_path[]; @@ -110,7 +110,7 @@ extern unsigned char metric; extern unsigned char dbm; extern struct dem *dem; -extern struct path path; +extern __thread struct path path; extern struct LR LR; extern struct region region; diff --git a/main.cc b/main.cc index 0c5b8b0..dd04394 100644 --- a/main.cc +++ b/main.cc @@ -1,4 +1,4 @@ -double version = 2.5; +double version = 2.6; /****************************************************************************\ * Signal Server: Server optimised SPLAT! by Alex Farrant * ****************************************************************************** @@ -53,11 +53,11 @@ int min_north = 90, max_north = -90, min_west = 360, max_west = -1, ippd, mpi, unsigned char got_elevation_pattern, got_azimuth_pattern, metric = 0, dbm = 0; -double *elev; - +__thread double *elev; +__thread struct path path; struct site tx_site[2]; struct dem *dem; -struct path path; + struct LR LR; struct region region; @@ -939,7 +939,11 @@ static void free_dem(void) delete [] dem; } -static void free_path(void) +void free_elev(void) { + delete [] elev; +} + +void free_path(void) { delete [] path.lat; delete [] path.lon; @@ -947,6 +951,11 @@ static void free_path(void) delete [] path.distance; } +void alloc_elev(void) +{ + elev = new double[ARRAYSIZE + 10]; +} + static void alloc_dem(void) { int i; @@ -965,7 +974,7 @@ static void alloc_dem(void) } } -static void alloc_path(void) +void alloc_path(void) { path.lat = new double[ARRAYSIZE]; path.lon = new double[ARRAYSIZE]; @@ -980,6 +989,8 @@ int main(int argc, char *argv[]) nortRxHin, nortRxHax, propmodel, winfiles, knifeedge = 0, ppa = 0, normalise = 0, haf = 0, pmenv = 1; + bool use_threads = true; + unsigned char LRmap = 0, txsites = 0, topomap = 0, geo = 0, kml = 0, area_mode = 0, max_txsites, ngs = 0; @@ -1047,6 +1058,7 @@ int main(int argc, char *argv[]) " -ked Knife edge diffraction (Default for ITM)\n"); fprintf(stdout, " -ng Normalise Path Profile graph\n"); fprintf(stdout, " -haf Halve 1 or 2 (optional)\n"); + fprintf(stdout, " -nothreads Turn off threaded processing (optional)\n"); fflush(stdout); @@ -1057,7 +1069,7 @@ int main(int argc, char *argv[]) * Now we know what mode we are running in, we can allocate various * data structures. */ - elev = new double[ARRAYSIZE + 10]; + alloc_elev(); alloc_dem(); alloc_path(); @@ -1422,6 +1434,11 @@ int main(int argc, char *argv[]) } } + //Disable threads + if (strcmp(argv[x], "-nothreads") == 0) { + z = x + 1; + use_threads = false; + } } /* ERROR DETECTION */ @@ -1639,12 +1656,12 @@ int main(int argc, char *argv[]) if (ppa == 0) { if (propmodel == 2) { - PlotLOSMap(tx_site[0], altitudeLR, ano_filename); + PlotLOSMap(tx_site[0], altitudeLR, ano_filename, use_threads); DoLOS(mapfile, geo, kml, ngs, tx_site, txsites); } else { // 90% of effort here PlotPropagation(tx_site[0], altitudeLR, ano_filename, - propmodel, knifeedge, haf, pmenv); + propmodel, knifeedge, haf, pmenv, use_threads); // Near field bugfix PutSignal(tx_site[0].lat, tx_site[0].lon, hottest); @@ -1683,7 +1700,7 @@ int main(int argc, char *argv[]) } fflush(stdout); - delete [] elev; + free_elev(); free_dem(); free_path(); diff --git a/main.hh b/main.hh index 0f9dca6..faeb447 100644 --- a/main.hh +++ b/main.hh @@ -23,4 +23,9 @@ double ReadBearing(char *input); void ObstructionAnalysis(struct site xmtr, struct site rcvr, double f, FILE *outfile); +void free_elev(void); +void free_path(void); +void alloc_elev(void); +void alloc_path(void); + #endif /* _MAIN_HH_ */ diff --git a/models/itwom3.0.cc b/models/itwom3.0.cc index 49c7584..062493a 100644 --- a/models/itwom3.0.cc +++ b/models/itwom3.0.cc @@ -451,7 +451,7 @@ double saalos(double d, prop_type & prop, propa_type & propa) double adiff(double d, prop_type & prop, propa_type & propa) { complex < double >prop_zgnd(prop.zgndreal, prop.zgndimag); - static double wd1, xd1, afo, qk, aht, xht; + static __thread double wd1, xd1, afo, qk, aht, xht; double a, q, pk, ds, th, wa, ar, wd, adiffv; if (d == 0) { @@ -513,7 +513,7 @@ double adiff(double d, prop_type & prop, propa_type & propa) double adiff2(double d, prop_type & prop, propa_type & propa) { complex < double >prop_zgnd(prop.zgndreal, prop.zgndimag); - static double wd1, xd1, qk, aht, xht, toh, toho, roh, roho, dto, dto1, + static __thread double wd1, xd1, qk, aht, xht, toh, toho, roh, roho, dto, dto1, dtro, dro, dro2, drto, dtr, dhh1, dhh2, /* dhec, */ dtof, dto1f, drof, dro2f; double a, q, pk, rd, ds, dsl, /* dfdh, */ th, wa, /* ar, wd, sf1, */ @@ -829,7 +829,7 @@ double adiff2(double d, prop_type & prop, propa_type & propa) double ascat(double d, prop_type & prop, propa_type & propa) { - static double ad, rr, etq, h0s; + static __thread double ad, rr, etq, h0s; double h0, r1, r2, z0, ss, et, ett, th, q; double ascatv, temp; @@ -954,7 +954,7 @@ void qlrps(double fmhz, double zsys, double en0, int ipol, double eps, double alos(double d, prop_type & prop, propa_type & propa) { complex < double >prop_zgnd(prop.zgndreal, prop.zgndimag); - static double wls; + static __thread double wls; complex < double >r; double s, sps, q; double alosv; @@ -1146,8 +1146,8 @@ void qlra(int kst[], int klimx, int mdvarx, prop_type & prop, void lrprop(double d, prop_type & prop, propa_type & propa) { /* PaulM_lrprop used for ITM */ - static bool wlos, wscat; - static double dmin, xae; + static __thread bool wlos, wscat; + static __thread double dmin, xae; complex < double >prop_zgnd(prop.zgndreal, prop.zgndimag); double a0, a1, a2, a3, a4, a5, a6; double d0, d1, d2, d3, d4, d5, d6; @@ -1337,8 +1337,8 @@ void lrprop(double d, prop_type & prop, propa_type & propa) void lrprop2(double d, prop_type & prop, propa_type & propa) { /* ITWOM_lrprop2 */ - static bool wlos, wscat; - static double dmin, xae; + static __thread bool wlos, wscat; + static __thread double dmin, xae; complex < double >prop_zgnd(prop.zgndreal, prop.zgndimag); double pd1; double a0, a1, a2, a3, a4, a5, a6, iw; @@ -1612,8 +1612,8 @@ double curve(double const &c1, double const &c2, double const &x1, double avar(double zzt, double zzl, double zzc, prop_type & prop, propv_type & propv) { - static int kdv; - static double dexa, de, vmd, vs0, sgl, sgtm, sgtp, sgtd, tgtd, + static __thread int kdv; + static __thread double dexa, de, vmd, vs0, sgl, sgtm, sgtp, sgtd, tgtd, gm, gp, cv1, cv2, yv1, yv2, yv3, csm1, csm2, ysm1, ysm2, ysm3, csp1, csp2, ysp1, ysp2, ysp3, csd1, zd, cfm1, cfm2, cfm3, cfp1, cfp2, cfp3; @@ -1650,7 +1650,7 @@ double avar(double zzt, double zzl, double zzc, prop_type & prop, double bfp1[7] = { 1.0, 0.93, 1.0, 0.93, 0.93, 1.0, 1.0 }; double bfp2[7] = { 0.0, 0.31, 0.0, 0.19, 0.31, 0.0, 0.0 }; double bfp3[7] = { 0.0, 2.00, 0.0, 1.79, 2.00, 0.0, 0.0 }; - static bool ws, w1; + static __thread bool ws, w1; double rt = 7.8, rl = 24.0, avarv, q, vs, zt, zl, zc; double sgt, yr, temp1, temp2; int temp_klim = propv.klim - 1; @@ -1974,6 +1974,7 @@ void z1sq1(double z[], const double &x1, const double &x2, double &z0, xa = xb - xa; x = -0.5 * xa; xb += x; + a = 0.5 * (z[ja + 2] + z[jb + 2]); b = 0.5 * (z[ja + 2] - z[jb + 2]) * x; diff --git a/models/los.cc b/models/los.cc index 66bdc8a..64d9c1b 100644 --- a/models/los.cc +++ b/models/los.cc @@ -1,8 +1,8 @@ #include #include -#include "../common.h" #include "../main.hh" +#include "los.hh" #include "cost.hh" #include "ecc33.hh" #include "ericsson.hh" @@ -10,6 +10,154 @@ #include "hata.hh" #include "itwom3.0.hh" #include "sui.hh" +#include + +#define MAXPAGES 64 +#define IPPD 3600 +#define NUM_SECTIONS 4 + +namespace { + pthread_t threads[NUM_SECTIONS]; + unsigned int thread_count = 0; + pthread_mutex_t maskMutex; + + bool processed[MAXPAGES][IPPD][IPPD]; + bool has_init_processed = false; + + struct propagationRange { + int min_west, max_west, min_north, max_north; + double altitude; + bool eastwest, los, use_threads; + site source; + unsigned char mask_value; + FILE *fd; + int propmodel, knifeedge, pmenv; + }; + + void* rangePropagation(void *parameters) + { + propagationRange *v = (propagationRange*)parameters; + if(v->use_threads) { + alloc_elev(); + alloc_path(); + } + + double minwest = dpp + (double)v->min_west; + double lon = v->eastwest ? minwest : v->min_west; + double lat = v->min_north; + int y = 0; + + do { + if (lon >= 360.0) + lon -= 360.0; + + site edge; + edge.lat = lat; + edge.lon = lon; + edge.alt = v->altitude; + + if(v->los) + PlotLOSPath(v->source, edge, v->mask_value, v->fd); + else + PlotPropPath(v->source, edge, v->mask_value, v->fd, v->propmodel, + v->knifeedge, v->pmenv); + + ++y; + if(v->eastwest) + lon = minwest + (dpp * (double)y); + else + lat = (double)v->min_north + (dpp * (double)y); + + + } while ( v->eastwest + ? (LonDiff(lon, (double)v->max_west) <= 0.0) + : (lat < (double)v->max_north) ); + + if(v->use_threads) { + free_elev(); + free_path(); + } + return NULL; + } + + void init_processed() + { + for(int i = 0; i < MAXPAGES; i++) { + for (int x = 0; x < ippd; x++) { + for (int y = 0; y < ippd; y++) { + processed[i][x][y] = false; + } + } + } + } + + bool can_process(double lat, double lon) + { + /* Lines, text, markings, and coverage areas are stored in a + mask that is combined with topology data when topographic + maps are generated by ss. This function sets bits in + the mask based on the latitude and longitude of the area + pointed to. */ + + int x, y, indx; + char found; + bool rtn = false; + + for (indx = 0, found = 0; indx < MAXPAGES && found == 0;) { + x = (int)rint(ppd * (lat - dem[indx].min_north)); + y = mpi - (int)rint(ppd * (LonDiff(dem[indx].max_west, lon))); + + if (x >= 0 && x <= mpi && y >= 0 && y <= mpi) + found = 1; + else + indx++; + } + + if (found) { + /* As long as we only set this without resetting it we can + check outside a mutex first without worrying about race + conditions. But we must lock the mutex before updating the + value. */ + + if(!processed[indx][x][y]) { + pthread_mutex_lock(&maskMutex); + + if(!processed[indx][x][y]) { + rtn = true; + processed[indx][x][y] = true; + } + + pthread_mutex_unlock (&maskMutex); + } + + } + return rtn; + } + + void beginThread(void *arg) + { + if(!has_init_processed) + init_processed(); + + int rc = pthread_create(&threads[thread_count], NULL, rangePropagation, arg); + if (rc) + printf("ERROR; return code from pthread_create() is %d\n", rc); + else + ++thread_count; + } + + void finishThreads() + { + void* status; + for(unsigned int i=0; ilos = true; - minwest = dpp + (double)min_west; - maxnorth = (double)max_north - dpp; + range->eastwest = (range_min_west[i] == range_max_west[i] ? false : true); + range->min_west = range_min_west[i]; + range->max_west = range_max_west[i]; + range->min_north = range_min_north[i]; + range->max_north = range_max_north[i]; - for (lon = minwest, x = 0, y = 0; - (LonDiff(lon, (double)max_west) <= 0.0); - y++, lon = minwest + (dpp * (double)y)) { - if (lon >= 360.0) - lon -= 360.0; + range->use_threads = use_threads; + range->altitude = altitude; + range->source = source; + range->mask_value = mask_value; + range->fd = fd; - edge.lat = max_north; - edge.lon = lon; - edge.alt = altitude; - - PlotLOSPath(source, edge, mask_value, fd); - } - - z = (int)(th * (double)(max_north - min_north)); - - for (lat = maxnorth, x = 0, y = 0; lat >= (double)min_north; - y++, lat = maxnorth - (dpp * (double)y)) { - edge.lat = lat; - edge.lon = min_west; - edge.alt = altitude; - - PlotLOSPath(source, edge, mask_value, fd); + if(use_threads) + beginThread(range); + else + rangePropagation(range); } - z = (int)(th * ReduceAngle(max_west - min_west)); - - for (lon = minwest, x = 0, y = 0; - (LonDiff(lon, (double)max_west) <= 0.0); - y++, lon = minwest + (dpp * (double)y)) { - if (lon >= 360.0) - lon -= 360.0; - - edge.lat = min_north; - edge.lon = lon; - edge.alt = altitude; - - PlotLOSPath(source, edge, mask_value, fd); - - } - - z = (int)(th * (double)(max_north - min_north)); - - for (lat = (double)min_north, x = 0, y = 0; lat < (double)max_north; - y++, lat = (double)min_north + (dpp * (double)y)) { - edge.lat = lat; - edge.lon = max_west; - edge.alt = altitude; - - PlotLOSPath(source, edge, mask_value, fd); + if(use_threads) + finishThreads(); + for(int i = 0; i < NUM_SECTIONS; ++i){ + delete r[i]; } switch (mask_value) { @@ -603,21 +740,14 @@ void PlotLOSMap(struct site source, double altitude, char *plo_filename) } } + void PlotPropagation(struct site source, double altitude, char *plo_filename, - int propmodel, int knifeedge, int haf, int pmenv) + int propmodel, int knifeedge, int haf, int pmenv, bool + use_threads) { - int y, z, count; - struct site edge; - double lat, lon, minwest, maxnorth, th; - unsigned char x; - static unsigned char mask_value = 1; + static __thread unsigned char mask_value = 1; FILE *fd = NULL; - - minwest = dpp + (double)min_west; - maxnorth = (double)max_north - dpp; - - count = 0; - + if (LR.erp == 0.0 && debug) fprintf(stdout, "path loss"); else { @@ -657,139 +787,57 @@ void PlotPropagation(struct site source, double altitude, char *plo_filename, max_west, min_west, max_north, min_north); } - th = ppd / loops; - // Four sections start here + // Process north edge east/west, east edge north/south, + // south edge east/west, west edge north/south + int range_min_west[] = {min_west, min_west, min_west, max_west}; + int range_min_north[] = {max_north, min_north, min_north, min_north}; + int range_max_west[] = {max_west, min_west, max_west, max_west}; + int range_max_north[] = {max_north, max_north, min_north, max_north}; + propagationRange* r[NUM_SECTIONS]; - //S1 - if (haf == 0 || haf == 1) { - z = (int)(th * ReduceAngle(max_west - min_west)); + for(int i = 0; i < NUM_SECTIONS; ++i) { + propagationRange *range = new propagationRange; + r[i] = range; + range->los = false; - for (lon = minwest, x = 0, y = 0; - (LonDiff(lon, (double)max_west) <= 0.0); - y++, lon = minwest + (dpp * (double)y)) { - if (lon >= 360.0) - lon -= 360.0; + // Only process correct half + if((NUM_SECTIONS - i) <= (NUM_SECTIONS / 2) && haf == 1) + continue; + if((NUM_SECTIONS - i) > (NUM_SECTIONS / 2) && haf == 2) + continue; - edge.lat = max_north; - edge.lon = lon; - edge.alt = altitude; - PlotPropPath(source, edge, mask_value, fd, propmodel, - knifeedge, pmenv); - count++; + range->eastwest = (range_min_west[i] == range_max_west[i] ? false : true); + range->min_west = range_min_west[i]; + range->max_west = range_max_west[i]; + range->min_north = range_min_north[i]; + range->max_north = range_max_north[i]; - if (count == z) { - count = 0; + range->use_threads = use_threads; + range->altitude = altitude; + range->source = source; + range->mask_value = mask_value; + range->fd = fd; + range->propmodel = propmodel; + range->knifeedge = knifeedge; + range->pmenv = pmenv; - if (x == 3) - x = 0; - else - x++; - } - } + if(use_threads) + beginThread(range); + else + rangePropagation(range); } - //S2 - if (haf == 0 || haf == 1) { - count = 0; - if (debug) { - fprintf(stdout, "\n25%c to 50%c ", 37, 37); - fflush(stdout); - } - z = (int)(th * (double)(max_north - min_north)); - - for (lat = maxnorth, x = 0, y = 0; lat >= (double)min_north; - y++, lat = maxnorth - (dpp * (double)y)) { - edge.lat = lat; - edge.lon = min_west; - edge.alt = altitude; - - PlotPropPath(source, edge, mask_value, fd, propmodel, - knifeedge, pmenv); - count++; - - if (count == z) { - count = 0; - - if (x == 3) - x = 0; - else - x++; - } - } + if(use_threads) + finishThreads(); + for(int i = 0; i < NUM_SECTIONS; ++i){ + delete r[i]; } - //S3 - if (haf == 0 || haf == 2) { - count = 0; - if (debug) { - fprintf(stdout, "\n50%c to 75%c ", 37, 37); - fflush(stdout); - } - z = (int)(th * ReduceAngle(max_west - min_west)); - - for (lon = minwest, x = 0, y = 0; - (LonDiff(lon, (double)max_west) <= 0.0); - y++, lon = minwest + (dpp * (double)y)) { - if (lon >= 360.0) - lon -= 360.0; - - edge.lat = min_north; - edge.lon = lon; - edge.alt = altitude; - - PlotPropPath(source, edge, mask_value, fd, propmodel, - knifeedge, pmenv); - count++; - if (count == z) { - count = 0; - - if (x == 3) - x = 0; - else - x++; - } - - } - - } - //S4 - if (haf == 0 || haf == 2) { - count = 0; - if (debug) { - fprintf(stdout, "\n75%c to 100%c ", 37, 37); - fflush(stdout); - } - z = (int)(th * (double)(max_north - min_north)); - - for (lat = (double)min_north, x = 0, y = 0; - lat < (double)max_north; - y++, lat = (double)min_north + (dpp * (double)y)) { - edge.lat = lat; - edge.lon = max_west; - edge.alt = altitude; - - PlotPropPath(source, edge, mask_value, fd, propmodel, - knifeedge, pmenv); - count++; - - if (count == z) { - - count = 0; - - if (x == 3) - x = 0; - else - x++; - } - } - - } //S4 - - if (fd != NULL) + if (fd != NULL) fclose(fd); if (mask_value < 30) diff --git a/models/los.hh b/models/los.hh index 795ec3f..991d7a2 100644 --- a/models/los.hh +++ b/models/los.hh @@ -10,9 +10,9 @@ void PlotLOSPath(struct site source, struct site destination, char mask_value, void PlotPropPath(struct site source, struct site destination, unsigned char mask_value, FILE * fd, int propmodel, int knifeedge, int pmenv); -void PlotLOSMap(struct site source, double altitude, char *plo_filename); +void PlotLOSMap(struct site source, double altitude, char *plo_filename, bool use_threads); void PlotPropagation(struct site source, double altitude, char *plo_filename, - int propmodel, int knifeedge, int haf, int pmenv); + int propmodel, int knifeedge, int haf, int pmenv, bool use_threads); void PlotPath(struct site source, struct site destination, char mask_value); #endif /* _LOS_HH_ */ diff --git a/test.sh b/test.sh index 4ffd9e1..8448ce9 100755 --- a/test.sh +++ b/test.sh @@ -1,6 +1,6 @@ -#!/bin/bash +œ#!/bin/bash mkdir test -RAD=5 +RAD=10 MAXRAD=30 FRQ=800 ERP=20 @@ -17,7 +17,7 @@ while [ $RAD -lt $MAXRAD ]; do convert test/$RAD.hd.ppm test/$RAD.hd.png rm test/$RAD.hd.ppm rm test/$RAD.*cf - let RAD=RAD+5 + let RAD=RAD+10 done