Introduce a new --stats DELAY option that displays event statistics
tables showing counts by epoll event type. Statistics are printed to
stderr with a minimum delay between updates, and only when events occur.
Signed-off-by: Laurent Vivier
---
conf.c | 8 ++++++++
passt.1 | 5 +++++
passt.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
passt.h | 2 ++
4 files changed, 73 insertions(+)
diff --git a/conf.c b/conf.c
index 02e903b5cf70..66b9e63400ec 100644
--- a/conf.c
+++ b/conf.c
@@ -835,6 +835,8 @@ static void usage(const char *name, FILE *f, int status)
"\n"
" -d, --debug Be verbose\n"
" --trace Be extra verbose, implies --debug\n"
+ " --stats DELAY Display events statistics\n"
+ " minimum DELAY seconds between updates\n"
" -q, --quiet Don't print informational messages\n"
" -f, --foreground Don't run in background\n"
" default: run in background\n"
@@ -1480,6 +1482,7 @@ void conf(struct ctx *c, int argc, char **argv)
{"repair-path", required_argument, NULL, 28 },
{"migrate-exit", no_argument, NULL, 29 },
{"migrate-no-linger", no_argument, NULL, 30 },
+ {"stats", required_argument, NULL, 31 },
{ 0 },
};
const char *optstring = "+dqfel:hs:F:I:p:P:m:a:n:M:g:i:o:D:S:H:461t:u:T:U:";
@@ -1708,6 +1711,11 @@ void conf(struct ctx *c, int argc, char **argv)
die("--migrate-no-linger is for vhost-user mode only");
c->migrate_no_linger = true;
+ break;
+ case 31:
+ if (!c->foreground)
+ die("Can't display statistics if not running in foreground");
+ c->stats = strtol(optarg, NULL, 0);
break;
case 'd':
c->debug = 1;
diff --git a/passt.1 b/passt.1
index af5726a7f1c5..0c17454c3e43 100644
--- a/passt.1
+++ b/passt.1
@@ -84,6 +84,11 @@ Be verbose, don't log to the system logger.
.BR \-\-trace
Be extra verbose, show single packets. Implies \fB--debug\fR.
+.TP
+.BR \-\-stats " " \fIDELAY\fR
+Display events statistics with a minimum \fIDELAY\fR seconds between updates.
+If there is no event, statistics are not displayed.
+
.TP
.BR \-q ", " \-\-quiet
Don't print informational messages.
diff --git a/passt.c b/passt.c
index a4ec115d1784..31fbb75b1b12 100644
--- a/passt.c
+++ b/passt.c
@@ -83,6 +83,14 @@ char *epoll_type_str[] = {
static_assert(ARRAY_SIZE(epoll_type_str) == EPOLL_NUM_TYPES,
"epoll_type_str[] doesn't match enum epoll_type");
+/**
+ * struct passt_stats - Statistics
+ * @events: Event counters for epoll type events
+ */
+struct passt_stats {
+ unsigned long events[EPOLL_NUM_TYPES];
+};
+
/**
* post_handler() - Run periodic and deferred tasks for L4 protocol handlers
* @c: Execution context
@@ -174,6 +182,53 @@ static void exit_handler(int signal)
_exit(EXIT_SUCCESS);
}
+/**
+ * print_stats() - Print event statistics table to stderr
+ * @c: Execution context
+ * @stats: Event counters
+ * @now: Current timestamp
+ */
+static void print_stats(const struct ctx *c, const struct passt_stats *stats,
+ const struct timespec *now)
+{
+ static struct timespec before;
+ static int lines_printed;
+ long long elapsed_ns;
+ int i;
+
+ if (!c->stats)
+ return;
+
+ elapsed_ns = (now->tv_sec - before.tv_sec) * 1000000000LL +
+ (now->tv_nsec - before.tv_nsec);
+
+ if (elapsed_ns < c->stats * 1000000000LL)
+ return;
+
+ before = *now;
+
+ if (!(lines_printed % 20)) {
+ /* Table header */
+ for (i = 1; i < EPOLL_NUM_TYPES; i++) {
+ int j;
+
+ for (j = 0; j < i * (6 + 1); j++) {
+ if (j && !(j % (6 + 1)))
+ FPRINTF(stderr, "|");
+ else
+ FPRINTF(stderr, " ");
+ }
+ FPRINTF(stderr, "%s\n", epoll_type_str[i]);
+ }
+ }
+
+ FPRINTF(stderr, " ");
+ for (i = 1; i < EPOLL_NUM_TYPES; i++)
+ FPRINTF(stderr, " %6lu", stats->events[i]);
+ FPRINTF(stderr, "\n");
+ lines_printed++;
+}
+
/**
* main() - Entry point and main loop
* @argc: Argument count
@@ -191,6 +246,7 @@ static void exit_handler(int signal)
int main(int argc, char **argv)
{
struct epoll_event events[EPOLL_EVENTS];
+ struct passt_stats stats = { 0 };
int nfds, i, devnull_fd = -1;
struct ctx c = { 0 };
struct rlimit limit;
@@ -362,6 +418,8 @@ loop:
/* Can't happen */
ASSERT(0);
}
+ stats.events[ref.type]++;
+ print_stats(&c, &stats, &now);
}
post_handler(&c, &now);
diff --git a/passt.h b/passt.h
index 3ffc19fdae05..0075eb4b3b16 100644
--- a/passt.h
+++ b/passt.h
@@ -187,6 +187,7 @@ struct ip6_ctx {
* @mode: Operation mode, qemu/UNIX domain socket or namespace/tap
* @debug: Enable debug mode
* @trace: Enable tracing (extra debug) mode
+ * @stats: Events statistics delay (0 means disabled)
* @quiet: Don't print informational messages
* @foreground: Run in foreground, don't log to stderr by default
* @nofile: Maximum number of open files (ulimit -n)
@@ -248,6 +249,7 @@ struct ctx {
enum passt_modes mode;
int debug;
int trace;
+ int stats;
int quiet;
int foreground;
int nofile;
--
2.50.1