+/* Copyright (C) 2016 Ian Kelling */
+
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
+/* See the License for the specific language governing permissions and */
+/* limitations under the License. */
+#include <string.h>
#include <stdio.h>
#include <linux/input.h>
#include <fcntl.h>
#include <signal.h>
+#include <getopt.h>
+#include <unistd.h>
-#define EVENTS 10
+#define EVENTS 400
#define HZ_LIST 64
typedef struct event_s {
- int fd;
- int hz[HZ_LIST];
- int count;
- double prvtime;
+ int fd;
+ int hz[HZ_LIST];
+ int count;
+ int avghz;
+ unsigned long long prev_time;
+ char name[128];
} event_t;
int quit = 0;
void sigint() {
- signal(SIGINT, sigint);
- quit = 1;
+ quit = 1;
}
-int main(int argc, char **argv) {
- int i;
- event_t events[EVENTS];
-
- signal(SIGINT, sigint);
+int main(int argc, char *argv[]) {
+ int optch;
+ int i;
+ event_t events[EVENTS];
+ int verbose = 1;
+ int max_event = 0;
+
+ while((optch = getopt(argc, argv, "hn")) != -1) {
+ switch(optch) {
+ case('h'):
+ printf("Usage: %s [-n|-h]\n", argv[0]);
+ printf("-n nonverbose\n");
+ printf("-h help\n");
+ return 0;
+ break;
+ case('n'):
+ verbose = 0;
+ break;
+ }
+ }
+
+ if(geteuid() != 0) {
+ printf("%s must be used as superuser\n", argv[0]);
+ return 1;
+ }
+
+ signal(SIGINT, sigint);
+
+ printf("Press CTRL-C to exit.\n\n");
+
+ memset(events, 0, sizeof(events));
+
+ // List input devices
+ for(i = 0; i < EVENTS; i++) {
+ // 20 is needed for 3 digits of event devs under the expected format, but
+ // just give it some extra in case.
+ char device[30];
+
+ sprintf(device, "/dev/input/event%i", i);
+ events[i].fd = open(device, O_RDONLY);
+
+ if(events[i].fd != -1) {
+ max_event = i;
+ ioctl(events[i].fd, EVIOCGNAME(sizeof(events[i].name)), events[i].name);
+ if(verbose) printf("event%i: %s\n", i, events[i].name);
+ }
+ }
- printf("Press CTRL-C to exit.\n\n");
+ while(!quit) {
+ fd_set set;
- memset(events, 0, sizeof(events));
+ FD_ZERO(&set);
- for(i = 0; i < EVENTS; i++) {
- char device[18];
+ for(i = 0; i <= max_event; i++) {
+ if(events[i].fd != -1) {
+ FD_SET(events[i].fd, &set);
+ }
+ }
- sprintf(device, "/dev/input/event%i", i);
- events[i].fd = open(device, O_RDONLY);
-
- if(events[i].fd != -1) {
- char name[128];
- ioctl(events[i].fd, EVIOCGNAME(sizeof(name)), name);
- printf("event%i: %s\n", i, name);
- }
- }
+ if(select(FD_SETSIZE, &set, NULL, NULL, NULL) <= 0) {
+ continue;
+ }
- while(!quit) {
- fd_set set;
+ int bytes;
+ struct input_event event;
- FD_ZERO(&set);
+ for(i = 0; i <= max_event; i++) {
+ if(events[i].fd == -1 || !FD_ISSET(events[i].fd, &set)) {
+ continue;
+ }
- for(i = 0; i < EVENTS; i++) {
- if(events[i].fd != -1) {
- FD_SET(events[i].fd, &set);
- }
- }
+ bytes = read(events[i].fd, &event, sizeof(event));
- if(select(FD_SETSIZE, &set, NULL, NULL, NULL) > 0) {
- int bytes;
- struct input_event event;
+ if(bytes != sizeof(event)) {
+ continue;
+ }
- for(i = 0; i < EVENTS; i++) {
- if(events[i].fd == -1) {
- continue;
- }
+ if(event.type == EV_REL || event.type == EV_ABS) {
+ unsigned long long time, timediff;
+ unsigned hz = 0;
- if(!FD_ISSET(events[i].fd, &set)) {
- continue;
- }
+ time = (unsigned long long)event.time.tv_sec * 1000000ULL;
+ time += (unsigned long long)event.time.tv_usec;
- bytes = read(events[i].fd, &event, sizeof(event));
+ timediff = time - events[i].prev_time;
- if(bytes != sizeof(event)) {
- continue;
- }
+ if(timediff != 0)
+ hz = 1000000ULL / timediff;
- if(event.type == EV_REL) {
- double time;
- int hz;
+ if(hz > 0) {
+ unsigned j, maxavg;
- time = event.time.tv_sec * 1000 + event.time.tv_usec / 1000;
- hz = 1000 / (time - events[i].prvtime);
+ events[i].count++;
+ events[i].hz[events[i].count & (HZ_LIST - 1)] = hz;
- if(hz > 0) {
- int avghz;
- int j;
+ events[i].avghz = 0;
- events[i].count++;
- events[i].hz[events[i].count & (HZ_LIST - 1)] = hz;
+ maxavg = (events[i].count > HZ_LIST) ? HZ_LIST : events[i].count;
- avghz = 0;
+ for(j = 0; j < maxavg; j++) {
+ events[i].avghz += events[i].hz[j];
+ }
- for(j = 0; j < HZ_LIST; j++) {
- avghz += events[i].hz[j];
- }
+ events[i].avghz /= maxavg;
- avghz /= (events[i].count > HZ_LIST) ? HZ_LIST : events[i].count;
+ if(verbose) printf("%s: Latest % 5iHz, Average % 5iHz\n", events[i].name, hz, events[i].avghz);
+ }
- printf("event%i: latest hz = %i (average hz = %i)\n", i, hz, avghz);
- }
+ events[i].prev_time = time;
+ }
+ }
+ }
- events[i].prvtime = time;
- }
- }
- }
- }
+ for(i = 0; i < max_event; i++) {
+ if(events[i].fd != -1) {
+ if (events[i].avghz != 0) {
+ printf("\nAverage for %s: % 5iHz\n", events[i].name, events[i].avghz);
+ }
+ close(events[i].fd);
+ }
+ }
- for(i = 0; i < EVENTS; i++) {
- if(events[i].fd != -1) {
- close(events[i].fd);
- }
- }
+ return 0;
}