Stats rearrangement, based on experimental branch changes.

This commit is contained in:
Oliver Jowett 2015-01-20 17:16:35 +00:00
parent e02a2cdd44
commit b9b76da02d
9 changed files with 468 additions and 191 deletions

View file

@ -21,10 +21,10 @@ all: dump1090 view1090
%.o: %.c dump1090.h %.o: %.c dump1090.h
$(CC) $(CPPFLAGS) $(CFLAGS) $(EXTRACFLAGS) -c $< $(CC) $(CPPFLAGS) $(CFLAGS) $(EXTRACFLAGS) -c $<
dump1090: dump1090.o anet.o interactive.o mode_ac.o mode_s.o net_io.o crc.o demod_2000.o demod_2400.o dump1090: dump1090.o anet.o interactive.o mode_ac.o mode_s.o net_io.o crc.o demod_2000.o demod_2400.o stats.o
$(CC) -g -o dump1090 $^ $(LIBS) $(LIBS_RTL) $(LDFLAGS) $(CC) -g -o dump1090 $^ $(LIBS) $(LIBS_RTL) $(LDFLAGS)
view1090: view1090.o anet.o interactive.o mode_ac.o mode_s.o net_io.o crc.o view1090: view1090.o anet.o interactive.o mode_ac.o mode_s.o net_io.o crc.o stats.o
$(CC) -g -o view1090 $^ $(LIBS) $(LDFLAGS) $(CC) -g -o view1090 $^ $(LIBS) $(LDFLAGS)
clean: clean:

View file

@ -347,7 +347,7 @@ void demodulate2000(uint16_t *m, uint32_t mlen) {
useModesMessage(&mm); useModesMessage(&mm);
j += MODEAC_MSG_SAMPLES; j += MODEAC_MSG_SAMPLES;
Modes.stat_ModeAC++; Modes.stats_current.ModeAC++;
continue; continue;
} }
} }
@ -399,7 +399,7 @@ void demodulate2000(uint16_t *m, uint32_t mlen) {
dumpRawMessage("Too high level in samples between 10 and 15", msg, m, j); dumpRawMessage("Too high level in samples between 10 and 15", msg, m, j);
continue; continue;
} }
Modes.stat_valid_preamble++; Modes.stats_current.valid_preamble++;
} }
else { else {
@ -408,7 +408,7 @@ void demodulate2000(uint16_t *m, uint32_t mlen) {
// Make a copy of the Payload, and phase correct the copy // Make a copy of the Payload, and phase correct the copy
memcpy(aux, &pPreamble[-1], sizeof(aux)); memcpy(aux, &pPreamble[-1], sizeof(aux));
applyPhaseCorrection(&aux[1]); applyPhaseCorrection(&aux[1]);
Modes.stat_out_of_phase++; Modes.stats_current.out_of_phase++;
pPayload = &aux[1 + MODES_PREAMBLE_SAMPLES]; pPayload = &aux[1 + MODES_PREAMBLE_SAMPLES];
// TODO ... apply other kind of corrections // TODO ... apply other kind of corrections
} }
@ -476,7 +476,7 @@ void demodulate2000(uint16_t *m, uint32_t mlen) {
msglen = MODES_SHORT_MSG_BITS; msglen = MODES_SHORT_MSG_BITS;
msg[0] ^= theErrs; errorsTy = 0; msg[0] ^= theErrs; errorsTy = 0;
errors = errors56; // revert to the number of errors prior to bit 56 errors = errors56; // revert to the number of errors prior to bit 56
Modes.stat_DF_Len_Corrected++; Modes.stats_current.DF_Len_Corrected++;
} else if (i < MODES_LONG_MSG_BITS) { } else if (i < MODES_LONG_MSG_BITS) {
msglen = MODES_SHORT_MSG_BITS; msglen = MODES_SHORT_MSG_BITS;
@ -518,7 +518,7 @@ void demodulate2000(uint16_t *m, uint32_t mlen) {
if (validDFbits & thisDFbit) { if (validDFbits & thisDFbit) {
// Yep, more likely, so update the main message // Yep, more likely, so update the main message
msg[0] = theByte; msg[0] = theByte;
Modes.stat_DF_Type_Corrected++; Modes.stats_current.DF_Type_Corrected++;
errors--; // decrease the error count so we attempt to use the modified DF. errors--; // decrease the error count so we attempt to use the modified DF.
} }
} }
@ -549,7 +549,7 @@ void demodulate2000(uint16_t *m, uint32_t mlen) {
// Update statistics // Update statistics
if (Modes.stats) { if (Modes.stats) {
struct demod_stats *dstats = (use_correction ? &Modes.stat_demod_phasecorrected : &Modes.stat_demod); struct demod_stats *dstats = (use_correction ? &Modes.stats_current.demod_phasecorrected : &Modes.stats_current.demod);
switch (errors) { switch (errors) {
case 0: dstats->demodulated0++; break; case 0: dstats->demodulated0++; break;

View file

@ -252,19 +252,19 @@ void demodulate2400(uint16_t *m, uint32_t mlen)
preamble[16] >= high || preamble[16] >= high ||
preamble[17] >= high || preamble[17] >= high ||
preamble[18] >= high) { preamble[18] >= high) {
++Modes.stat_preamble_not_quiet; ++Modes.stats_current.preamble_not_quiet;
continue; continue;
} }
// Crosscorrelate against the first few bits to find a likely phase offset // Crosscorrelate against the first few bits to find a likely phase offset
initial_phase = best_phase(&preamble[19]); initial_phase = best_phase(&preamble[19]);
if (initial_phase < 0) { if (initial_phase < 0) {
++Modes.stat_preamble_no_correlation; ++Modes.stats_current.preamble_no_correlation;
continue; // nothing satisfactory continue; // nothing satisfactory
} }
Modes.stat_valid_preamble++; Modes.stats_current.valid_preamble++;
Modes.stat_preamble_phase[initial_phase%MODES_MAX_PHASE_STATS]++; Modes.stats_current.preamble_phase[initial_phase%MODES_MAX_PHASE_STATS]++;
try_phase = initial_phase; try_phase = initial_phase;
@ -395,7 +395,7 @@ void demodulate2400(uint16_t *m, uint32_t mlen)
msglen = MODES_SHORT_MSG_BITS; msglen = MODES_SHORT_MSG_BITS;
msg[0] ^= theErrs; errorsTy = 0; msg[0] ^= theErrs; errorsTy = 0;
errors = errors56; // revert to the number of errors prior to bit 56 errors = errors56; // revert to the number of errors prior to bit 56
Modes.stat_DF_Len_Corrected++; Modes.stats_current.DF_Len_Corrected++;
} else if (i < MODES_LONG_MSG_BITS) { } else if (i < MODES_LONG_MSG_BITS) {
msglen = MODES_SHORT_MSG_BITS; msglen = MODES_SHORT_MSG_BITS;
errors = errors56; errors = errors56;
@ -435,7 +435,7 @@ void demodulate2400(uint16_t *m, uint32_t mlen)
if (validDFbits & thisDFbit) { if (validDFbits & thisDFbit) {
// Yep, more likely, so update the main message // Yep, more likely, so update the main message
msg[0] = theByte; msg[0] = theByte;
Modes.stat_DF_Type_Corrected++; Modes.stats_current.DF_Type_Corrected++;
errors--; // decrease the error count so we attempt to use the modified DF. errors--; // decrease the error count so we attempt to use the modified DF.
} }
} }
@ -466,7 +466,7 @@ void demodulate2400(uint16_t *m, uint32_t mlen)
// Update statistics // Update statistics
if (Modes.stats) { if (Modes.stats) {
struct demod_stats *dstats = (mm.phase_corrected ? &Modes.stat_demod_phasecorrected : &Modes.stat_demod); struct demod_stats *dstats = (mm.phase_corrected ? &Modes.stats_current.demod_phasecorrected : &Modes.stats_current.demod);
switch (errors) { switch (errors) {
case 0: dstats->demodulated0++; break; case 0: dstats->demodulated0++; break;
@ -508,7 +508,7 @@ void demodulate2400(uint16_t *m, uint32_t mlen)
// peak detection // peak detection
if (Modes.phase_enhance && !mm.crcok && !mm.correctedbits) { if (Modes.phase_enhance && !mm.crcok && !mm.correctedbits) {
if (try_phase == initial_phase) if (try_phase == initial_phase)
++Modes.stat_out_of_phase; ++Modes.stats_current.out_of_phase;
try_phase++; try_phase++;
if (try_phase == 9) if (try_phase == 9)
try_phase = 4; try_phase = 4;

View file

@ -586,111 +586,13 @@ void showCopyright(void) {
} }
#endif #endif
static void display_total_stats(void)
static void display_demod_stats(const char *prefix, struct demod_stats *dstats) { {
int j; struct stats added;
add_stats(&Modes.stats_alltime, &Modes.stats_current, &added);
printf("%d %sdemodulated with 0 errors\n", dstats->demodulated0, prefix); display_stats(&added);
printf("%d %sdemodulated with 1 error\n", dstats->demodulated1, prefix);
printf("%d %sdemodulated with 2 errors\n", dstats->demodulated2, prefix);
printf("%d %sdemodulated with > 2 errors\n", dstats->demodulated3, prefix);
printf("%d %swith good crc\n", dstats->goodcrc, prefix);
for (j = 0; j < MODES_MAX_PHASE_STATS; ++j)
if (dstats->goodcrc_byphase[j] > 0)
printf(" %d %swith phase offset %d\n", dstats->goodcrc_byphase[j], prefix, j);
printf("%d %swith bad crc\n", dstats->badcrc, prefix);
printf("%d %serrors corrected\n", dstats->fixed, prefix);
for (j = 0; j < MODES_MAX_BITERRORS; j++) {
printf(" %d %swith %d bit %s\n", dstats->bit_fix[j], prefix, j+1, (j==0)?"error":"errors");
}
} }
static void reset_demod_stats(struct demod_stats *dstats) {
int j;
dstats->demodulated0 =
dstats->demodulated1 =
dstats->demodulated2 =
dstats->goodcrc =
dstats->badcrc =
dstats->fixed = 0;
for (j = 0; j < MODES_MAX_BITERRORS; j++) {
dstats->bit_fix[j] = 0;
}
for (j = 0; j < MODES_MAX_PHASE_STATS; j++) {
dstats->goodcrc_byphase[j] = 0;
}
}
static void display_stats(void) {
int j;
time_t now = time(NULL);
printf("\n\n");
if (Modes.interactive)
interactiveShowData();
printf("Statistics as at %s", ctime(&now));
printf("%d sample blocks processed\n", Modes.stat_blocks_processed);
printf("%d sample blocks dropped\n", Modes.stat_blocks_dropped);
if (Modes.stat_blocks_processed > 0) {
long cpu_millis = (long)Modes.stat_cputime.tv_sec*1000L + Modes.stat_cputime.tv_nsec/1000000L;
long sample_millis = (long) ((uint64_t)Modes.stat_blocks_processed * MODES_ASYNC_BUF_SAMPLES / (Modes.oversample ? 2400 : 2000));
printf("%ld ms CPU time used to process %ld ms samples, %.1f%% load\n",
cpu_millis, sample_millis, 100.0 * cpu_millis / sample_millis);
}
printf("%d ModeA/C detected\n", Modes.stat_ModeAC);
printf("%d Mode-S preambles with poor correlation\n", Modes.stat_preamble_no_correlation);
printf("%d Mode-S preambles with noise in the quiet period\n", Modes.stat_preamble_not_quiet);
printf("%d valid Mode-S preambles\n", Modes.stat_valid_preamble);
for (j = 0; j < MODES_MAX_PHASE_STATS; ++j)
if (Modes.stat_preamble_phase[j] > 0)
printf(" %d with phase offset %d\n", Modes.stat_preamble_phase[j], j);
printf("%d DF-?? fields corrected for length\n", Modes.stat_DF_Len_Corrected);
printf("%d DF-?? fields corrected for type\n", Modes.stat_DF_Type_Corrected);
display_demod_stats("", &Modes.stat_demod);
if (Modes.phase_enhance) {
printf("%d phase enhancement attempts\n", Modes.stat_out_of_phase);
display_demod_stats("phase enhanced ", &Modes.stat_demod_phasecorrected);
}
printf("%d total usable messages\n",
Modes.stat_messages_total);
fflush(stdout);
Modes.stat_cputime.tv_sec = 0;
Modes.stat_cputime.tv_nsec = 0;
Modes.stat_blocks_processed =
Modes.stat_blocks_dropped = 0;
Modes.stat_ModeAC =
Modes.stat_preamble_no_correlation =
Modes.stat_preamble_not_quiet =
Modes.stat_valid_preamble =
Modes.stat_DF_Len_Corrected =
Modes.stat_DF_Type_Corrected =
Modes.stat_out_of_phase = 0;
Modes.stat_messages_total = 0;
for (j = 0; j < MODES_MAX_PHASE_STATS; j++) {
Modes.stat_preamble_phase[j] = 0;
}
reset_demod_stats(&Modes.stat_demod);
reset_demod_stats(&Modes.stat_demod_phasecorrected);
}
// //
//========================================================================= //=========================================================================
// //
@ -699,7 +601,8 @@ static void display_stats(void) {
// from the net, refreshing the screen in interactive mode, and so forth // from the net, refreshing the screen in interactive mode, and so forth
// //
void backgroundTasks(void) { void backgroundTasks(void) {
static time_t next_stats; static time_t next_stats_display;
static time_t next_stats_update;
static time_t next_json, next_history; static time_t next_json, next_history;
time_t now = time(NULL); time_t now = time(NULL);
@ -718,29 +621,68 @@ void backgroundTasks(void) {
interactiveShowData(); interactiveShowData();
} }
if (Modes.stats > 0) { // always update end time so it is current when requests arrive
if (now > next_stats) { Modes.stats_current.end = now;
if (next_stats != 0)
display_stats(); if (now >= next_stats_update) {
next_stats = now + Modes.stats; int i;
if (next_stats_update == 0) {
next_stats_update = now + 60;
} else {
Modes.stats_latest_1min = (Modes.stats_latest_1min + 1) % 15;
Modes.stats_1min[Modes.stats_latest_1min] = Modes.stats_current;
add_stats(&Modes.stats_current, &Modes.stats_alltime, &Modes.stats_alltime);
add_stats(&Modes.stats_current, &Modes.stats_periodic, &Modes.stats_periodic);
reset_stats(&Modes.stats_5min);
for (i = 0; i < 5; ++i)
add_stats(&Modes.stats_1min[(Modes.stats_latest_1min - i + 15) % 15], &Modes.stats_5min, &Modes.stats_5min);
reset_stats(&Modes.stats_15min);
for (i = 0; i < 15; ++i)
add_stats(&Modes.stats_1min[i], &Modes.stats_15min, &Modes.stats_15min);
reset_stats(&Modes.stats_current);
Modes.stats_current.start = Modes.stats_current.end = now;
if (Modes.json_dir)
writeJsonToFile("stats.json", generateStatsJson);
next_stats_update += 60;
} }
} }
if ((Modes.json_dir || Modes.net_http_port) && now >= next_json) { if (Modes.stats > 0 && now >= next_stats_display) {
if (next_stats_display == 0) {
next_stats_display = now + Modes.stats;
} else {
add_stats(&Modes.stats_periodic, &Modes.stats_current, &Modes.stats_periodic);
display_stats(&Modes.stats_periodic);
reset_stats(&Modes.stats_periodic);
next_stats_display += Modes.stats;
}
}
if (Modes.json_dir && now >= next_json) {
writeJsonToFile("aircraft.json", generateAircraftJson); writeJsonToFile("aircraft.json", generateAircraftJson);
next_json = now + Modes.json_interval; next_json = now + Modes.json_interval;
} }
if ((Modes.json_dir || Modes.net_http_port) && now >= next_history) { if ((Modes.json_dir || Modes.net_http_port) && now >= next_history) {
char filebuf[PATH_MAX];
int rewrite_receiver_json = (Modes.json_aircraft_history[HISTORY_SIZE-1].content == NULL); int rewrite_receiver_json = (Modes.json_aircraft_history[HISTORY_SIZE-1].content == NULL);
free(Modes.json_aircraft_history[Modes.json_aircraft_history_next].content); // might be NULL, that's OK. free(Modes.json_aircraft_history[Modes.json_aircraft_history_next].content); // might be NULL, that's OK.
Modes.json_aircraft_history[Modes.json_aircraft_history_next].content = Modes.json_aircraft_history[Modes.json_aircraft_history_next].content =
generateAircraftJson("/data/aircraft.json", &Modes.json_aircraft_history[Modes.json_aircraft_history_next].clen); generateAircraftJson("/data/aircraft.json", &Modes.json_aircraft_history[Modes.json_aircraft_history_next].clen);
if (Modes.json_dir) {
char filebuf[PATH_MAX];
snprintf(filebuf, PATH_MAX, "history_%d.json", Modes.json_aircraft_history_next); snprintf(filebuf, PATH_MAX, "history_%d.json", Modes.json_aircraft_history_next);
writeJsonToFile(filebuf, generateHistoryJson); writeJsonToFile(filebuf, generateHistoryJson);
}
Modes.json_aircraft_history_next = (Modes.json_aircraft_history_next+1) % HISTORY_SIZE; Modes.json_aircraft_history_next = (Modes.json_aircraft_history_next+1) % HISTORY_SIZE;
@ -1002,13 +944,19 @@ int main(int argc, char **argv) {
} }
if (Modes.net) modesInitNet(); if (Modes.net) modesInitNet();
writeJsonToFile("receiver.json", generateReceiverJson); // once on startup // init stats:
Modes.stats_current.start = Modes.stats_current.end = time(NULL);
// write initial json files so they're not missing
writeJsonToFile("receiver.json", generateReceiverJson);
writeJsonToFile("stats.json", generateStatsJson);
writeJsonToFile("aircraft.json", generateAircraftJson);
// If the user specifies --net-only, just run in order to serve network // If the user specifies --net-only, just run in order to serve network
// clients without reading data from the RTL device // clients without reading data from the RTL device
while (Modes.net_only) { while (Modes.net_only) {
if (Modes.exit) { if (Modes.exit) {
display_stats(); display_total_stats();
exit(0); // If we exit net_only nothing further in main() exit(0); // If we exit net_only nothing further in main()
} }
backgroundTasks(); backgroundTasks();
@ -1044,7 +992,7 @@ int main(int argc, char **argv) {
// If we lost some blocks, correct the timestamp // If we lost some blocks, correct the timestamp
if (Modes.iDataLost) { if (Modes.iDataLost) {
Modes.timestampBlk += (MODES_ASYNC_BUF_SAMPLES * 6 * Modes.iDataLost); Modes.timestampBlk += (MODES_ASYNC_BUF_SAMPLES * 6 * Modes.iDataLost);
Modes.stat_blocks_dropped += Modes.iDataLost; Modes.stats_current.blocks_dropped += Modes.iDataLost;
Modes.iDataLost = 0; Modes.iDataLost = 0;
} }
@ -1064,14 +1012,14 @@ int main(int argc, char **argv) {
demodulate2000(Modes.magnitude, MODES_ASYNC_BUF_SAMPLES); demodulate2000(Modes.magnitude, MODES_ASYNC_BUF_SAMPLES);
clock_gettime(CLOCK_THREAD_CPUTIME_ID, &cpu_end_time); clock_gettime(CLOCK_THREAD_CPUTIME_ID, &cpu_end_time);
Modes.stat_cputime.tv_sec += (cpu_end_time.tv_sec - cpu_start_time.tv_sec); Modes.stats_current.cputime.tv_sec += (cpu_end_time.tv_sec - cpu_start_time.tv_sec);
Modes.stat_cputime.tv_nsec += (cpu_end_time.tv_nsec - cpu_start_time.tv_nsec); Modes.stats_current.cputime.tv_nsec += (cpu_end_time.tv_nsec - cpu_start_time.tv_nsec);
if (Modes.stat_cputime.tv_nsec < 0) { if (Modes.stats_current.cputime.tv_nsec < 0) {
Modes.stat_cputime.tv_nsec += 1000000000L; Modes.stats_current.cputime.tv_nsec += 1000000000L;
Modes.stat_cputime.tv_sec--; Modes.stats_current.cputime.tv_sec--;
} else if (Modes.stat_cputime.tv_nsec > 1000000000L) { } else if (Modes.stats_current.cputime.tv_nsec > 1000000000L) {
Modes.stat_cputime.tv_nsec -= 1000000000L; Modes.stats_current.cputime.tv_nsec -= 1000000000L;
Modes.stat_cputime.tv_sec++; Modes.stats_current.cputime.tv_sec++;
} }
// Update the timestamp ready for the next block // Update the timestamp ready for the next block
@ -1079,7 +1027,7 @@ int main(int argc, char **argv) {
Modes.timestampBlk += (MODES_ASYNC_BUF_SAMPLES*5); Modes.timestampBlk += (MODES_ASYNC_BUF_SAMPLES*5);
else else
Modes.timestampBlk += (MODES_ASYNC_BUF_SAMPLES*6); Modes.timestampBlk += (MODES_ASYNC_BUF_SAMPLES*6);
Modes.stat_blocks_processed++; Modes.stats_current.blocks_processed++;
} else { } else {
pthread_cond_signal (&Modes.data_cond); pthread_cond_signal (&Modes.data_cond);
pthread_mutex_unlock(&Modes.data_mutex); pthread_mutex_unlock(&Modes.data_mutex);
@ -1093,7 +1041,7 @@ int main(int argc, char **argv) {
// If --stats were given, print statistics // If --stats were given, print statistics
if (Modes.stats) { if (Modes.stats) {
display_stats(); display_total_stats();
} }
if (Modes.filename == NULL) { if (Modes.filename == NULL) {

View file

@ -89,11 +89,7 @@
#include "winstubs.h" //Put everything Windows specific in here #include "winstubs.h" //Put everything Windows specific in here
#endif #endif
#include "rtl-sdr.h" #include <rtl-sdr.h>
#include "anet.h"
#include "crc.h"
#include "demod_2000.h"
#include "demod_2400.h"
// ============================= #defines =============================== // ============================= #defines ===============================
// //
@ -223,8 +219,18 @@
#define HTMLPATH "./public_html" // default path for gmap.html etc #define HTMLPATH "./public_html" // default path for gmap.html etc
#endif #endif
#define HISTORY_SIZE 120
#define HISTORY_INTERVAL 30
#define MODES_NOTUSED(V) ((void) V) #define MODES_NOTUSED(V) ((void) V)
#include "anet.h"
#include "crc.h"
#include "demod_2000.h"
#include "demod_2400.h"
#include "stats.h"
//======================== structure declarations ========================= //======================== structure declarations =========================
// Structure used to describe a networking client // Structure used to describe a networking client
@ -236,9 +242,6 @@ struct client {
char buf[MODES_CLIENT_BUF_SIZE+1]; // Read buffer char buf[MODES_CLIENT_BUF_SIZE+1]; // Read buffer
}; };
#define HISTORY_SIZE 120
#define HISTORY_INTERVAL 30
// Structure used to describe an aircraft in iteractive mode // Structure used to describe an aircraft in iteractive mode
struct aircraft { struct aircraft {
uint32_t addr; // ICAO address uint32_t addr; // ICAO address
@ -275,22 +278,6 @@ struct aircraft {
struct aircraft *next; // Next aircraft in our linked list struct aircraft *next; // Next aircraft in our linked list
}; };
// Common stats for non-phase-corrected vs phase-corrected cases
struct demod_stats {
unsigned int demodulated0;
unsigned int demodulated1;
unsigned int demodulated2;
unsigned int demodulated3;
unsigned int goodcrc;
unsigned int goodcrc_byphase[MODES_MAX_PHASE_STATS];
unsigned int badcrc;
unsigned int fixed;
// Histogram of fixed bit errors: index 0 for single bit erros,
// index 1 for double bit errors etc.
unsigned int bit_fix[MODES_MAX_BITERRORS];
};
// Common writer state for all output sockets of one type // Common writer state for all output sockets of one type
struct net_writer { struct net_writer {
int socket; // listening socket FD, used to identify the owning service int socket; // listening socket FD, used to identify the owning service
@ -405,28 +392,13 @@ struct { // Internal state
time_t last_cleanup_time; // Last cleanup time in seconds time_t last_cleanup_time; // Last cleanup time in seconds
// Statistics // Statistics
unsigned int stat_preamble_no_correlation; struct stats stats_current;
unsigned int stat_preamble_not_quiet; struct stats stats_alltime;
unsigned int stat_valid_preamble; struct stats stats_periodic;
unsigned int stat_preamble_phase[MODES_MAX_PHASE_STATS]; struct stats stats_1min[15];
int stats_latest_1min;
struct demod_stats stat_demod; struct stats stats_5min;
struct demod_stats stat_demod_phasecorrected; struct stats stats_15min;
unsigned int stat_http_requests;
unsigned int stat_out_of_phase;
unsigned int stat_DF_Len_Corrected;
unsigned int stat_DF_Type_Corrected;
unsigned int stat_ModeAC;
unsigned int stat_blocks_processed;
unsigned int stat_blocks_dropped;
struct timespec stat_cputime;
// total messages:
unsigned int stat_messages_total;
} Modes; } Modes;
// The struct we use to store information about a decoded message. // The struct we use to store information about a decoded message.
@ -518,6 +490,7 @@ void modesNetPeriodicWork (void);
void writeJsonToFile(const char *file, char * (*generator) (const char*,int*)); void writeJsonToFile(const char *file, char * (*generator) (const char*,int*));
char *generateAircraftJson(const char *url_path, int *len); char *generateAircraftJson(const char *url_path, int *len);
char *generateReceiverJson(const char *url_path, int *len); char *generateReceiverJson(const char *url_path, int *len);
char *generateStatsJson(const char *url_path, int *len);
char *generateHistoryJson(const char *url_path, int *len); char *generateHistoryJson(const char *url_path, int *len);
#ifdef __cplusplus #ifdef __cplusplus

View file

@ -935,7 +935,7 @@ void computeMagnitudeVector(uint16_t *p) {
// //
void useModesMessage(struct modesMessage *mm) { void useModesMessage(struct modesMessage *mm) {
if ((Modes.check_crc == 0) || (mm->crcok) || (mm->correctedbits)) { // not checking, ok or fixed if ((Modes.check_crc == 0) || (mm->crcok) || (mm->correctedbits)) { // not checking, ok or fixed
++Modes.stat_messages_total; ++Modes.stats_current.messages_total;
// If we are decoding, track aircraft // If we are decoding, track aircraft
interactiveReceiveData(mm); interactiveReceiveData(mm);

View file

@ -48,6 +48,9 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "dump1090.h" #include "dump1090.h"
#include <assert.h>
// //
// ============================= Networking ============================= // ============================= Networking =============================
// //
@ -699,7 +702,7 @@ char *generateAircraftJson(const char *url_path, int *len) {
"{ \"now\" : %d,\n" "{ \"now\" : %d,\n"
" \"messages\" : %u,\n" " \"messages\" : %u,\n"
" \"aircraft\" : [", " \"aircraft\" : [",
(int)now, Modes.stat_messages_total); (int)now, Modes.stats_current.messages_total);
while(a) { while(a) {
if (a->modeACflags & MODEAC_MSG_FLAG) { // skip any fudged ICAO records Mode A/C if (a->modeACflags & MODEAC_MSG_FLAG) { // skip any fudged ICAO records Mode A/C
@ -750,6 +753,57 @@ char *generateAircraftJson(const char *url_path, int *len) {
return buf; return buf;
} }
static char * appendStatsJson(char *p,
char *end,
struct stats *st,
const char *key)
{
p += snprintf(p, end-p,
" \"%s\" : {\n"
" \"start\" : %d,\n"
" \"end\" : %d,\n"
" \"messages\" : %u,\n",
key,
(int)st->start,
(int)st->end,
st->messages_total);
p += snprintf(p, end-p, "\n }");
return p;
}
char *generateStatsJson(const char *url_path, int *len) {
struct stats add;
char *buf = (char *) malloc(2048), *p = buf, *end = buf + 2048;
MODES_NOTUSED(url_path);
p += snprintf(p, end-p, "{\n");
p = appendStatsJson(p, end, &Modes.stats_current, "latest");
p += snprintf(p, end-p, ",\n");
add_stats(&Modes.stats_1min[Modes.stats_latest_1min], &Modes.stats_current, &add);
p = appendStatsJson(p, end, &add, "last1min");
p += snprintf(p, end-p, ",\n");
add_stats(&Modes.stats_5min, &Modes.stats_current, &add);
p = appendStatsJson(p, end, &add, "last5min");
p += snprintf(p, end-p, ",\n");
add_stats(&Modes.stats_15min, &Modes.stats_current, &add);
p = appendStatsJson(p, end, &add, "last15min");
p += snprintf(p, end-p, ",\n");
add_stats(&Modes.stats_alltime, &Modes.stats_current, &add);
p = appendStatsJson(p, end, &add, "total");
p += snprintf(p, end-p, "\n}\n");
assert(p <= end);
*len = p-buf;
return buf;
}
// //
// Return a description of the receiver in json. // Return a description of the receiver in json.
// //
@ -1046,7 +1100,7 @@ int handleHTTPRequest(struct client *c, char *p) {
return 1; return 1;
} }
free(content); free(content);
Modes.stat_http_requests++; Modes.stats_current.http_requests++;
return !keepalive; return !keepalive;
} }
// //

196
stats.c Normal file
View file

@ -0,0 +1,196 @@
// Part of dump1090, a Mode S message decoder for RTLSDR devices.
//
// stats.c: statistics helpers.
//
// Copyright (c) 2015 Oliver Jowett <oliver@mutability.co.uk>
//
// This file is free software: you may copy, redistribute and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation, either version 2 of the License, or (at your
// option) any later version.
//
// This file is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
// This file incorporates work covered by the following copyright and
// permission notice:
//
// Copyright (C) 2012 by Salvatore Sanfilippo <antirez@gmail.com>
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "dump1090.h"
static void display_demod_stats(const char *prefix, struct demod_stats *dstats) {
int j;
printf("%d %sdemodulated with 0 errors\n", dstats->demodulated0, prefix);
printf("%d %sdemodulated with 1 error\n", dstats->demodulated1, prefix);
printf("%d %sdemodulated with 2 errors\n", dstats->demodulated2, prefix);
printf("%d %sdemodulated with > 2 errors\n", dstats->demodulated3, prefix);
printf("%d %swith good crc\n", dstats->goodcrc, prefix);
for (j = 0; j < MODES_MAX_PHASE_STATS; ++j)
if (dstats->goodcrc_byphase[j] > 0)
printf(" %d %swith phase offset %d\n", dstats->goodcrc_byphase[j], prefix, j);
printf("%d %swith bad crc\n", dstats->badcrc, prefix);
printf("%d %serrors corrected\n", dstats->fixed, prefix);
for (j = 0; j < Modes.nfix_crc; j++) {
printf(" %d %swith %d bit %s\n", dstats->bit_fix[j], prefix, j+1, (j==0)?"error":"errors");
}
}
void display_stats(struct stats *st) {
int j;
struct tm tm_start, tm_end;
char tb_start[30], tb_end[30];
printf("\n\n");
if (Modes.interactive)
interactiveShowData();
localtime_r(&st->start, &tm_start);
strftime(tb_start, sizeof(tb_start), "%c", &tm_start);
localtime_r(&st->end, &tm_end);
strftime(tb_end, sizeof(tb_end), "%c", &tm_end);
printf("Statistics: %s - %s\n", tb_start, tb_end);
if (!Modes.net_only) {
printf("%d sample blocks processed\n", st->blocks_processed);
printf("%d sample blocks dropped\n", st->blocks_dropped);
if (st->blocks_processed > 0) {
long cpu_millis = (long)st->cputime.tv_sec*1000L + st->cputime.tv_nsec/1000000L;
long sample_millis = (long) ((uint64_t)st->blocks_processed * MODES_ASYNC_BUF_SAMPLES / (Modes.oversample ? 2400 : 2000));
printf("%ld ms CPU time used to process %ld ms samples, %.1f%% load\n",
cpu_millis, sample_millis, 100.0 * cpu_millis / sample_millis);
}
printf("%d ModeA/C detected\n", st->ModeAC);
printf("%d Mode-S preambles with poor correlation\n", st->preamble_no_correlation);
printf("%d Mode-S preambles with noise in the quiet period\n", st->preamble_not_quiet);
printf("%d valid Mode-S preambles\n", st->valid_preamble);
for (j = 0; j < MODES_MAX_PHASE_STATS; ++j)
if (st->preamble_phase[j] > 0)
printf(" %d with phase offset %d\n", st->preamble_phase[j], j);
printf("%d DF-?? fields corrected for length\n", st->DF_Len_Corrected);
printf("%d DF-?? fields corrected for type\n", st->DF_Type_Corrected);
display_demod_stats("", &st->demod);
if (Modes.phase_enhance) {
printf("%d phase enhancement attempts\n", st->out_of_phase);
display_demod_stats("phase enhanced ", &st->demod_phasecorrected);
}
}
printf("%d remote messages accepted\n"
"%d remote messages rejected\n",
st->remote_accepted,
st->remote_rejected);
printf("%d total usable messages\n",
st->messages_total);
fflush(stdout);
}
void reset_stats(struct stats *st) {
static struct stats st_zero;
*st = st_zero;
}
static void add_demod_stats(const struct demod_stats *st1, const struct demod_stats *st2, struct demod_stats *target)
{
int i;
target->demodulated0 = st1->demodulated0 + st2->demodulated0;
target->demodulated1 = st1->demodulated1 + st2->demodulated1;
target->demodulated2 = st1->demodulated2 + st2->demodulated2;
target->demodulated3 = st1->demodulated3 + st2->demodulated3;
target->goodcrc = st1->goodcrc + st2->goodcrc;
for (i = 0; i < MODES_MAX_PHASE_STATS; ++i)
target->goodcrc_byphase[i] = st1->goodcrc_byphase[i] + st2->goodcrc_byphase[i];
target->badcrc = st1->badcrc + st2->badcrc;
target->fixed = st1->fixed + st2->fixed;
for (i = 0; i < MODES_MAX_BITERRORS; ++i)
target->bit_fix[i] = st1->bit_fix[i] + st2->bit_fix[i];
}
void add_stats(const struct stats *st1, const struct stats *st2, struct stats *target) {
int i;
if (st1->start == 0)
target->start = st2->start;
else if (st2->start == 0)
target->start = st1->start;
else if (st1->start < st2->start)
target->start = st1->start;
else
target->start = st2->start;
target->end = st1->end > st2->end ? st1->end : st2->end;
target->preamble_no_correlation = st1->preamble_no_correlation + st2->preamble_no_correlation;
target->preamble_not_quiet = st1->preamble_not_quiet + st2->preamble_not_quiet;
target->valid_preamble = st1->valid_preamble + st2->valid_preamble;
for (i = 0; i < MODES_MAX_PHASE_STATS; ++i)
target->preamble_phase[i] = st1->preamble_phase[i] + st2->preamble_phase[i];
add_demod_stats(&st1->demod, &st2->demod, &target->demod);
add_demod_stats(&st1->demod_phasecorrected, &st2->demod_phasecorrected, &target->demod_phasecorrected);
target->http_requests = st1->http_requests + st2->http_requests;
target->out_of_phase = st1->out_of_phase + st2->out_of_phase;
target->DF_Len_Corrected = st1->DF_Len_Corrected + st2->DF_Len_Corrected;
target->DF_Type_Corrected = st1->DF_Type_Corrected + st2->DF_Type_Corrected;
target->ModeAC = st1->ModeAC + st2->ModeAC;
target->blocks_processed = st1->blocks_processed + st2->blocks_processed;
target->blocks_dropped = st1->blocks_dropped + st2->blocks_dropped;
target->cputime.tv_sec = st1->cputime.tv_sec + st2->cputime.tv_sec;
target->cputime.tv_nsec = st1->cputime.tv_nsec + st2->cputime.tv_nsec;
target->cputime.tv_sec += target->cputime.tv_nsec / 1000000000L;
target->cputime.tv_nsec %= 1000000000L;
// remote messages:
target->remote_accepted = st1->remote_accepted + st2->remote_accepted;
target->remote_rejected = st1->remote_rejected + st2->remote_rejected;
// total messages:
target->messages_total = st1->messages_total + st2->messages_total;
}

106
stats.h Normal file
View file

@ -0,0 +1,106 @@
// Part of dump1090, a Mode S message decoder for RTLSDR devices.
//
// stats.c: statistics structures and prototypes.
//
// Copyright (c) 2015 Oliver Jowett <oliver@mutability.co.uk>
//
// This file is free software: you may copy, redistribute and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation, either version 2 of the License, or (at your
// option) any later version.
//
// This file is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
// This file incorporates work covered by the following copyright and
// permission notice:
//
// Copyright (C) 2012 by Salvatore Sanfilippo <antirez@gmail.com>
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef DUMP1090_STATS_H
#define DUMP1090_STATS_H
// Common stats for non-phase-corrected vs phase-corrected cases
struct demod_stats {
unsigned int demodulated0;
unsigned int demodulated1;
unsigned int demodulated2;
unsigned int demodulated3;
unsigned int goodcrc;
unsigned int goodcrc_byphase[MODES_MAX_PHASE_STATS];
unsigned int badcrc;
unsigned int fixed;
// Histogram of fixed bit errors: index 0 for single bit erros,
// index 1 for double bit errors etc.
unsigned int bit_fix[MODES_MAX_BITERRORS];
};
struct stats {
time_t start;
time_t end;
// Statistics
unsigned int preamble_no_correlation;
unsigned int preamble_not_quiet;
unsigned int valid_preamble;
unsigned int preamble_phase[MODES_MAX_PHASE_STATS];
struct demod_stats demod;
struct demod_stats demod_phasecorrected;
unsigned int http_requests;
unsigned int out_of_phase;
unsigned int DF_Len_Corrected;
unsigned int DF_Type_Corrected;
unsigned int ModeAC;
unsigned int blocks_processed;
unsigned int blocks_dropped;
struct timespec cputime;
// remote messages:
unsigned int remote_accepted;
unsigned int remote_rejected;
// total messages:
unsigned int messages_total;
};
void add_stats(const struct stats *st1, const struct stats *st2, struct stats *target);
void display_stats(struct stats *st);
void reset_stats(struct stats *st);
#endif