diff --git a/dump1090.c b/dump1090.c index 07c7042..069b8dd 100644 --- a/dump1090.c +++ b/dump1090.c @@ -116,6 +116,7 @@ static void modesInitConfig(void) { Modes.net_heartbeat_interval = MODES_NET_HEARTBEAT_INTERVAL; Modes.interactive_display_ttl = MODES_INTERACTIVE_DISPLAY_TTL; Modes.json_interval = 1000; + Modes.json_stats_interval = 60000; Modes.json_location_accuracy = 1; Modes.maxRange = 1852 * 300; // 300NM default max range Modes.mode_ac_auto = 1; @@ -345,7 +346,8 @@ static void showHelp(void) "--quiet Disable output to stdout. Use for daemon applications\n" "--show-only Show only messages from the given ICAO on stdout\n" "--write-json Periodically write json output to (for serving by a separate webserver)\n" -"--write-json-every Write json output every t seconds (default 1)\n" +"--write-json-every Write json aircraft output every t seconds (default 1)\n" +"--json-stats-every Write json stats output every t seconds (default 60)\n" "--json-location-accuracy Accuracy of receiver location in json metadata: 0=no location, 1=approximate, 2=exact\n" #if 0 "--dcfilter Apply a 1Hz DC filter to input data (requires more CPU)\n" @@ -356,11 +358,16 @@ static void showHelp(void) ); } -static void display_total_stats(void) +// Accumulate stats data from stats_current to stats_periodic, stats_alltime and stats_latest; +// reset stats_current +static void flush_stats(uint64_t now) { - struct stats added; - add_stats(&Modes.stats_alltime, &Modes.stats_current, &added); - display_stats(&added); + add_stats(&Modes.stats_current, &Modes.stats_periodic, &Modes.stats_periodic); + add_stats(&Modes.stats_current, &Modes.stats_alltime, &Modes.stats_alltime); + add_stats(&Modes.stats_current, &Modes.stats_latest, &Modes.stats_latest); + + reset_stats(&Modes.stats_current); + Modes.stats_current.start = Modes.stats_current.end = now; } // @@ -373,6 +380,7 @@ static void display_total_stats(void) static void backgroundTasks(void) { static uint64_t next_stats_display; static uint64_t next_stats_update; + static uint64_t next_json_stats_update; static uint64_t next_json, next_history; uint64_t now = mstime(); @@ -396,41 +404,41 @@ static void backgroundTasks(void) { // always update end time so it is current when requests arrive Modes.stats_current.end = mstime(); + // 1-minute stats update if (now >= next_stats_update) { int i; if (next_stats_update == 0) { next_stats_update = now + 60000; } else { - Modes.stats_latest_1min = (Modes.stats_latest_1min + 1) % 15; - Modes.stats_1min[Modes.stats_latest_1min] = Modes.stats_current; + flush_stats(now); // Ensure stats_latest is up to date - add_stats(&Modes.stats_current, &Modes.stats_alltime, &Modes.stats_alltime); - add_stats(&Modes.stats_current, &Modes.stats_periodic, &Modes.stats_periodic); + // move stats_latest into 1-min ring buffer + Modes.stats_newest_1min = (Modes.stats_newest_1min + 1) % 15; + Modes.stats_1min[Modes.stats_newest_1min] = Modes.stats_latest; + reset_stats(&Modes.stats_latest); + // recalculate 5-min window 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); + add_stats(&Modes.stats_1min[(Modes.stats_newest_1min - i + 15) % 15], &Modes.stats_5min, &Modes.stats_5min); + // recalculate 15-min window 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 += 60000; } } + // --stats-every display if (Modes.stats && 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); + flush_stats(now); // Ensure stats_periodic is up to date + display_stats(&Modes.stats_periodic); reset_stats(&Modes.stats_periodic); @@ -442,6 +450,17 @@ static void backgroundTasks(void) { } } + // json stats update + if (Modes.json_dir && now >= next_json_stats_update) { + if (next_json_stats_update == 0) { + next_json_stats_update = now + Modes.json_stats_interval; + } else { + flush_stats(now); // Ensure everything we'll write is up to date + writeJsonToFile("stats.json", generateStatsJson); + next_json_stats_update += Modes.json_stats_interval; + } + } + if (Modes.json_dir && now >= next_json) { writeJsonToFile("aircraft.json", generateAircraftJson); next_json = now + Modes.json_interval; @@ -631,6 +650,8 @@ int main(int argc, char **argv) { Modes.stats_range_histo = 1; } else if (!strcmp(argv[j],"--stats-every") && more) { Modes.stats = (uint64_t) (1000 * atof(argv[++j])); + } else if (!strcmp(argv[j],"--json-stats-every") && more) { + Modes.json_stats_interval = (uint64_t) (1000 * atof(argv[++j])); } else if (!strcmp(argv[j],"--snip") && more) { snipMode(atoi(argv[++j])); exit(0); @@ -702,6 +723,7 @@ int main(int argc, char **argv) { Modes.stats_current.start = Modes.stats_current.end = Modes.stats_alltime.start = Modes.stats_alltime.end = Modes.stats_periodic.start = Modes.stats_periodic.end = + Modes.stats_latest.start = Modes.stats_latest.end = Modes.stats_5min.start = Modes.stats_5min.end = Modes.stats_15min.start = Modes.stats_15min.end = mstime(); @@ -778,9 +800,10 @@ int main(int argc, char **argv) { interactiveCleanup(); - // If --stats were given, print statistics + // If --stats was given, print final statistics if (Modes.stats) { - display_total_stats(); + flush_stats(0); + display_stats(&Modes.stats_alltime); } sdrClose(); diff --git a/dump1090.h b/dump1090.h index bfdc848..d2c602a 100644 --- a/dump1090.h +++ b/dump1090.h @@ -355,6 +355,7 @@ struct _Modes { // Internal state int mlat; // Use Beast ascii format for raw data output, i.e. @...; iso *...; char *json_dir; // Path to json base directory, or NULL not to write json. uint64_t json_interval; // Interval between rewriting the json aircraft file, in milliseconds; also the advertised map refresh interval + uint64_t json_stats_interval; // Interval between rewriting the json stats file, in milliseconds int json_location_accuracy; // Accuracy of location metadata: 0=none, 1=approx, 2=exact int json_aircraft_history_next; @@ -373,13 +374,14 @@ struct _Modes { // Internal state struct aircraft *aircrafts; // Statistics - struct stats stats_current; - struct stats stats_alltime; - struct stats stats_periodic; - struct stats stats_1min[15]; - int stats_latest_1min; - struct stats stats_5min; - struct stats stats_15min; + struct stats stats_current; // Currently accumulating stats, this is where all stats are initially collected + struct stats stats_alltime; // Accumulated stats since the start of the process + struct stats stats_periodic; // Accumulated stats since the last periodic stats display (--stats-every) + struct stats stats_latest; // Accumulated stats since the end of the last 1-minute period + struct stats stats_1min[15]; // Accumulated stats for a full 1-minute window; this is a ring buffer maintaining a history of 15 minutes + int stats_newest_1min; // Index into stats_1min of the most recent 1-minute window + struct stats stats_5min; // Accumulated stats from the last 5 complete 1-minute windows + struct stats stats_15min; // Accumulated stats from the last 15 complete 1-minute windows }; extern struct _Modes Modes; diff --git a/net_io.c b/net_io.c index e1cb47d..7636087 100644 --- a/net_io.c +++ b/net_io.c @@ -1831,10 +1831,10 @@ char *generateStatsJson(const char *url_path, int *len) { MODES_NOTUSED(url_path); p = safe_snprintf(p, end, "{\n"); - p = appendStatsJson(p, end, &Modes.stats_current, "latest"); + p = appendStatsJson(p, end, &Modes.stats_latest, "latest"); p = safe_snprintf(p, end, ",\n"); - p = appendStatsJson(p, end, &Modes.stats_1min[Modes.stats_latest_1min], "last1min"); + p = appendStatsJson(p, end, &Modes.stats_1min[Modes.stats_newest_1min], "last1min"); p = safe_snprintf(p, end, ",\n"); p = appendStatsJson(p, end, &Modes.stats_5min, "last5min"); @@ -1843,8 +1843,7 @@ char *generateStatsJson(const char *url_path, int *len) { p = appendStatsJson(p, end, &Modes.stats_15min, "last15min"); p = safe_snprintf(p, end, ",\n"); - add_stats(&Modes.stats_alltime, &Modes.stats_current, &add); - p = appendStatsJson(p, end, &add, "total"); + p = appendStatsJson(p, end, &Modes.stats_alltime, "total"); p = safe_snprintf(p, end, "\n}\n"); if (p <= end) {