[PATCH libevdev] tools: add an event counter program
Peter Hutterer
peter.hutterer at who-t.net
Mon Jun 23 21:14:19 PDT 2014
A tool to count events and print basic statistics. Example output:
Input device ID: bus 0x3 vendor 0x56a product 0x27
Input device name: "Wacom Intuos5 touch M Pen"
Events received: 630
Axis/key statistics:
EV_ABS:
ABS_X 384 (62.2% of type, 61.0% of total)
ABS_Y 482 (78.1% of type, 76.5% of total)
ABS_PRESSURE 228 (37.0% of type, 36.2% of total)
ABS_DISTANCE 164 (26.6% of type, 26.0% of total)
ABS_TILT_X 160 (25.9% of type, 25.4% of total)
ABS_TILT_Y 80 (13.0% of type, 12.7% of total)
ABS_MISC 1 (0.2% of type, 0.2% of total)
EV_KEY:
BTN_TOOL_PEN 1 (3.7% of type, 0.2% of total)
BTN_TOUCH 26 (96.3% of type, 4.1% of total)
Per event type statistics:
Events with/without EV_ABS data: 13/617 (2.1%/97.9%)
1 EV_ABS events per SYN_REPORT: 114 (18.5% of type, 18.1% of total)
2 EV_ABS events per SYN_REPORT: 220 (35.7% of type, 34.9% of total)
3 EV_ABS events per SYN_REPORT: 198 (32.1% of type, 31.4% of total)
4 EV_ABS events per SYN_REPORT: 77 (12.5% of type, 12.2% of total)
5 EV_ABS events per SYN_REPORT: 7 (1.1% of type, 1.1% of total)
7 EV_ABS events per SYN_REPORT: 1 (0.2% of type, 0.2% of total)
Events with/without EV_KEY data: 603/27 (95.7%/4.3%)
1 EV_KEY events per SYN_REPORT: 27 (100.0% of type, 4.3% of total)
Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
---
Probably not that useful to most people, hence in noinst_PROGRAMS. But if
you're interested in general stats on your device, stuff like this takes the
guesswork out of it.
tools/.gitignore | 1 +
tools/Makefile.am | 5 +-
tools/event-counter.c | 297 ++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 302 insertions(+), 1 deletion(-)
create mode 100644 tools/event-counter.c
diff --git a/tools/.gitignore b/tools/.gitignore
index 8084fed..8339285 100644
--- a/tools/.gitignore
+++ b/tools/.gitignore
@@ -1,2 +1,3 @@
libevdev-events
touchpad-edge-detector
+event-counter
diff --git a/tools/Makefile.am b/tools/Makefile.am
index 5d3600d..70ea389 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -1,4 +1,4 @@
-noinst_PROGRAMS = libevdev-events
+noinst_PROGRAMS = libevdev-events event-counter
bin_PROGRAMS = touchpad-edge-detector
AM_CPPFLAGS = $(GCC_CFLAGS) -I$(top_srcdir) -I$(top_srcdir)/include -I$(top_srcdir)/libevdev
@@ -7,6 +7,9 @@ libevdev_ldadd = $(top_builddir)/libevdev/libevdev.la
libevdev_events_SOURCES = libevdev-events.c
libevdev_events_LDADD = $(libevdev_ldadd)
+event_counter_SOURCES = event-counter.c
+event_counter_LDADD = $(libevdev_ldadd)
+
touchpad_edge_detector_SOURCES = touchpad-edge-detector.c
touchpad_edge_detector_LDADD = $(libevdev_ldadd)
diff --git a/tools/event-counter.c b/tools/event-counter.c
new file mode 100644
index 0000000..0608133
--- /dev/null
+++ b/tools/event-counter.c
@@ -0,0 +1,297 @@
+/*
+ * Copyright © 2014 Red Hat, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. The copyright holders make no representations
+ * about the suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <linux/input.h>
+#include <stdbool.h>
+#include <signal.h>
+#include <unistd.h>
+#include <poll.h>
+#include <sys/signalfd.h>
+
+#include "libevdev.h"
+
+struct counter {
+ unsigned int nevents;
+
+ bool has_abs,
+ has_rel,
+ has_key;
+
+ unsigned int ev[EV_CNT];
+ unsigned int abs[ABS_CNT];
+ unsigned int rel[REL_CNT];
+ unsigned int key[KEY_CNT];
+
+ unsigned int abs_per_ev[ABS_CNT];
+ unsigned int rel_per_ev[REL_CNT];
+ unsigned int key_per_ev[KEY_CNT];
+
+ /* for this event: */
+ unsigned int abscnt;
+ unsigned int relcnt;
+ unsigned int keycnt;
+};
+
+static void
+handle_event(struct counter *counter, const struct input_event *ev)
+{
+ switch (ev->type) {
+ case EV_SYN:
+ counter->nevents++;
+ if (counter->abscnt)
+ counter->ev[EV_ABS]++;
+ if (counter->relcnt)
+ counter->ev[EV_REL]++;
+ if (counter->keycnt)
+ counter->ev[EV_KEY]++;
+
+ counter->abs_per_ev[counter->abscnt]++;
+ counter->rel_per_ev[counter->relcnt]++;
+ counter->key_per_ev[counter->keycnt]++;
+ counter->abscnt = 0;
+ counter->relcnt = 0;
+ counter->keycnt = 0;
+ printf("\rEvents received: %5d", counter->nevents);
+ break;
+ case EV_ABS:
+ counter->has_abs = true;
+ counter->abscnt++;
+ counter->abs[ev->code]++;
+ break;
+ case EV_REL:
+ counter->has_rel = true;
+ counter->relcnt++;
+ counter->rel[ev->code]++;
+ break;
+ case EV_KEY:
+ counter->has_key = true;
+ counter->keycnt++;
+ counter->key[ev->code]++;
+ break;
+ }
+}
+
+static void
+print_event_stat(const struct counter *counter, int type, int code)
+{
+ const unsigned int *data = NULL;
+
+ switch (type) {
+ case EV_ABS: data = counter->abs; break;
+ case EV_REL: data = counter->rel; break;
+ case EV_KEY: data = counter->key; break;
+ default:
+ return;
+ }
+ if (data[code] == 0)
+ return;
+
+ printf("\t\t%-18s %4d (%.1f%% of type, %.1f%% of total)\n",
+ libevdev_event_code_get_name(type, code),
+ data[code],
+ 100.0 * data[code]/counter->ev[type],
+ 100.0 * data[code]/counter->nevents);
+}
+
+static void
+print_per_event_stat(const struct counter *counter, int type)
+{
+ const unsigned int *data = NULL;
+ int i, max;
+
+ switch (type) {
+ case EV_ABS:
+ data = counter->abs_per_ev;
+ break;
+ case EV_REL:
+ data = counter->rel_per_ev;
+ break;
+ case EV_KEY:
+ data = counter->key_per_ev;
+ break;
+ default:
+ return;
+ }
+
+ printf("\tEvents with/without %s data: %d/%d (%.1f%%/%.1f%%)\n",
+ libevdev_event_type_get_name(type),
+ data[0],
+ counter->ev[type],
+ 100.0 * data[0]/counter->nevents,
+ 100.0 * counter->ev[type]/counter->nevents);
+
+ max = libevdev_event_type_get_max(type);
+ for (i = 1; i < max; i++) {
+ if (data[i] == 0)
+ continue;
+
+ printf("\t %d %s events per SYN_REPORT: %4d (%.1f%% of type, %.1f%% of total)\n",
+ i,
+ libevdev_event_type_get_name(type),
+ data[i],
+ 100.0 * data[i]/counter->ev[type],
+ 100.0 * data[i]/counter->nevents);
+ }
+}
+
+static void
+print_stats(struct counter *counter, struct libevdev *dev)
+{
+ int i;
+
+ printf("Axis/key statistics:\n");
+
+ if (counter->has_abs) {
+ printf("\tEV_ABS:\n");
+
+ for (i = 0; i < ABS_CNT; i++)
+ print_event_stat(counter, EV_ABS, i);
+ }
+
+ if (counter->has_rel) {
+ printf("\tEV_REL:\n");
+
+ for (i = 0; i < REL_CNT; i++)
+ print_event_stat(counter, EV_REL, i);
+ }
+
+ if (counter->has_key) {
+ printf("\tEV_KEY:\n");
+
+ for (i = 0; i < KEY_CNT; i++)
+ print_event_stat(counter, EV_KEY, i);
+ }
+
+ printf("Per event type statistics:\n");
+ if (counter->has_abs)
+ print_per_event_stat(counter, EV_ABS);
+ if (counter->has_rel)
+ print_per_event_stat(counter, EV_REL);
+ if (counter->has_key)
+ print_per_event_stat(counter, EV_KEY);
+}
+
+static int
+mainloop(struct counter *counter, struct libevdev *dev)
+{
+ int rc = -1;
+ sigset_t mask;
+ struct pollfd fds[2];
+
+ sigemptyset(&mask);
+ sigaddset(&mask, SIGINT);
+ fds[0].fd = signalfd(-1, &mask, SFD_NONBLOCK);
+ if (fds[0].fd == -1) {
+ fprintf(stderr, "Failed to set up signal handler\n");
+ return -1;
+ }
+
+ if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1) {
+ fprintf(stderr, "Failed to block signals\n");
+ goto out;
+ }
+ fds[0].events = POLLIN;
+ fds[1].fd = libevdev_get_fd(dev);
+ fds[1].events = POLLIN;
+
+ while (poll(fds, 2, -1) != -1) {
+ int rc;
+ struct input_event ev;
+
+ if (fds[0].revents)
+ break;
+
+ rc = libevdev_next_event(dev, LIBEVDEV_READ_FLAG_NORMAL, &ev);
+ if (rc == LIBEVDEV_READ_STATUS_SYNC) {
+ fprintf(stderr, "SYN_DROPPED received. event count unreliable\n");
+ while (rc == LIBEVDEV_READ_STATUS_SYNC) {
+ handle_event(counter, &ev);
+ rc = libevdev_next_event(dev, LIBEVDEV_READ_FLAG_SYNC, &ev);
+ }
+ } else if (rc == LIBEVDEV_READ_STATUS_SUCCESS)
+ handle_event(counter, &ev);
+ else {
+ fprintf(stderr, "Failed to read events\n");
+ goto out;
+ }
+ }
+
+ printf("\r ");
+ printf("\rEvents received: %5d\n", counter->nevents);
+
+ rc = 0;
+out:
+ close(fds[0].fd);
+ return rc;
+}
+
+int
+main(int argc, char **argv)
+{
+ struct libevdev *dev = NULL;
+ const char *file;
+ int fd;
+ int rc = 1;
+ struct counter counter = {0};
+
+ if (argc < 2)
+ goto out;
+
+ file = argv[1];
+ fd = open(file, O_RDONLY);
+ if (fd < 0) {
+ perror("Failed to open device");
+ goto out;
+ }
+
+ rc = libevdev_new_from_fd(fd, &dev);
+ if (rc < 0) {
+ fprintf(stderr, "Failed to init libevdev (%s)\n", strerror(-rc));
+ goto out;
+ }
+
+ printf("Input device ID: bus %#x vendor %#x product %#x\n",
+ libevdev_get_id_bustype(dev),
+ libevdev_get_id_vendor(dev),
+ libevdev_get_id_product(dev));
+ printf("Input device name: \"%s\"\n", libevdev_get_name(dev));
+
+ if (mainloop(&counter, dev) != 0)
+ goto out;
+
+ print_stats(&counter, dev);
+
+ rc = 0;
+out:
+ libevdev_free(dev);
+
+ return rc;
+}
--
1.9.3
More information about the Input-tools
mailing list