1 /* Copyright (C) 2016 Ian Kelling */
2 
3 /* Licensed under the Apache License, Version 2.0 (the "License"); */
4 /* you may not use this file except in compliance with the License. */
5 /* You may obtain a copy of the License at */
6 
7 /*     http://www.apache.org/licenses/LICENSE-2.0 */
8 
9 /* Unless required by applicable law or agreed to in writing, software */
10 /* distributed under the License is distributed on an "AS IS" BASIS, */
11 /* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
12 /* See the License for the specific language governing permissions and */
13 /* limitations under the License. */
14 #include <string.h>
15 #include <stdio.h>
16 #include <linux/input.h>
17 #include <fcntl.h>
18 #include <signal.h>
19 #include <getopt.h>
20 #include <unistd.h>
21 
22 #define EVENTS 400
23 #define HZ_LIST 64
24 
25 typedef struct event_s {
26     int fd;
27     int hz[HZ_LIST];
28     int count;
29     int avghz;
30     unsigned long long prev_time;
31     char name[128];
32 } event_t;
33 
34 int quit = 0;
35 
sigint()36 void sigint() {
37     quit = 1;
38 }
39 
main(int argc,char * argv[])40 int main(int argc, char *argv[]) {
41     int optch;
42     int i;
43     event_t events[EVENTS];
44     int verbose = 1;
45     int max_event = 0;
46 
47     while((optch = getopt(argc, argv, "hn")) != -1) {
48         switch(optch) {
49         case('h'):
50             printf("Usage: %s [-n|-h]\n", argv[0]);
51             printf("-n     nonverbose\n");
52             printf("-h     help\n");
53             return 0;
54             break;
55         case('n'):
56             verbose = 0;
57             break;
58         }
59     }
60 
61     if(geteuid() != 0) {
62         printf("%s must be used as superuser\n", argv[0]);
63         return 1;
64     }
65 
66     signal(SIGINT, sigint);
67 
68     printf("Press CTRL-C to exit.\n\n");
69 
70     memset(events, 0, sizeof(events));
71 
72     // List input devices
73     for(i = 0; i < EVENTS; i++) {
74         // 20 is needed for 3 digits of event devs under the expected format, but
75         // just give it some extra in case.
76         char device[30];
77 
78         sprintf(device, "/dev/input/event%i", i);
79         events[i].fd = open(device, O_RDONLY);
80 
81         if(events[i].fd != -1) {
82             max_event = i;
83             ioctl(events[i].fd, EVIOCGNAME(sizeof(events[i].name)), events[i].name);
84             if(verbose) printf("event%i: %s\n", i, events[i].name);
85         }
86     }
87 
88     while(!quit) {
89         fd_set set;
90 
91         FD_ZERO(&set);
92 
93         for(i = 0; i <= max_event; i++) {
94             if(events[i].fd != -1) {
95                 FD_SET(events[i].fd, &set);
96             }
97         }
98 
99         if(select(FD_SETSIZE, &set, NULL, NULL, NULL) <= 0) {
100             continue;
101         }
102 
103         int bytes;
104         struct input_event event;
105 
106         for(i = 0; i <= max_event; i++) {
107             if(events[i].fd == -1 || !FD_ISSET(events[i].fd, &set)) {
108                 continue;
109             }
110 
111             bytes = read(events[i].fd, &event, sizeof(event));
112 
113             if(bytes != sizeof(event)) {
114                 continue;
115             }
116 
117             if(event.type == EV_REL || event.type == EV_ABS) {
118                 unsigned long long time, timediff;
119                 unsigned hz = 0;
120 
121                 time = (unsigned long long)event.time.tv_sec * 1000000ULL;
122                 time += (unsigned long long)event.time.tv_usec;
123 
124                 timediff = time - events[i].prev_time;
125 
126                 if(timediff != 0)
127                     hz = 1000000ULL / timediff;
128 
129                 if(hz > 0) {
130                     unsigned j, maxavg;
131 
132                     events[i].count++;
133                     events[i].hz[events[i].count & (HZ_LIST - 1)] = hz;
134 
135                     events[i].avghz = 0;
136 
137                     maxavg = (events[i].count > HZ_LIST) ? HZ_LIST : events[i].count;
138 
139                     for(j = 0; j < maxavg; j++) {
140                         events[i].avghz += events[i].hz[j];
141                     }
142 
143                     events[i].avghz /= maxavg;
144 
145                     if(verbose) printf("%s: Latest % 5iHz, Average % 5iHz\n", events[i].name, hz, events[i].avghz);
146                 }
147 
148                 events[i].prev_time = time;
149             }
150         }
151     }
152 
153     for(i = 0; i < max_event; i++) {
154         if(events[i].fd != -1) {
155             if (events[i].avghz != 0) {
156                 printf("\nAverage for %s: % 5iHz\n", events[i].name, events[i].avghz);
157             }
158             close(events[i].fd);
159         }
160     }
161 
162     return 0;
163 }
164