~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/counter/counter_watch_events.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0-only
  2 /*
  3  * Counter Watch Events - Test various counter watch events in a userspace application
  4  *
  5  * Copyright (C) STMicroelectronics 2023 - All Rights Reserved
  6  * Author: Fabrice Gasnier <fabrice.gasnier@foss.st.com>.
  7  */
  8 
  9 #include <errno.h>
 10 #include <fcntl.h>
 11 #include <getopt.h>
 12 #include <linux/counter.h>
 13 #include <linux/kernel.h>
 14 #include <stdlib.h>
 15 #include <stdio.h>
 16 #include <string.h>
 17 #include <sys/ioctl.h>
 18 #include <unistd.h>
 19 
 20 static struct counter_watch simple_watch[] = {
 21         {
 22                 /* Component data: Count 0 count */
 23                 .component.type = COUNTER_COMPONENT_COUNT,
 24                 .component.scope = COUNTER_SCOPE_COUNT,
 25                 .component.parent = 0,
 26                 /* Event type: overflow or underflow */
 27                 .event = COUNTER_EVENT_OVERFLOW_UNDERFLOW,
 28                 /* Device event channel 0 */
 29                 .channel = 0,
 30         },
 31 };
 32 
 33 static const char * const counter_event_type_name[] = {
 34         "COUNTER_EVENT_OVERFLOW",
 35         "COUNTER_EVENT_UNDERFLOW",
 36         "COUNTER_EVENT_OVERFLOW_UNDERFLOW",
 37         "COUNTER_EVENT_THRESHOLD",
 38         "COUNTER_EVENT_INDEX",
 39         "COUNTER_EVENT_CHANGE_OF_STATE",
 40         "COUNTER_EVENT_CAPTURE",
 41 };
 42 
 43 static const char * const counter_component_type_name[] = {
 44         "COUNTER_COMPONENT_NONE",
 45         "COUNTER_COMPONENT_SIGNAL",
 46         "COUNTER_COMPONENT_COUNT",
 47         "COUNTER_COMPONENT_FUNCTION",
 48         "COUNTER_COMPONENT_SYNAPSE_ACTION",
 49         "COUNTER_COMPONENT_EXTENSION",
 50 };
 51 
 52 static const char * const counter_scope_name[] = {
 53         "COUNTER_SCOPE_DEVICE",
 54         "COUNTER_SCOPE_SIGNAL",
 55         "COUNTER_SCOPE_COUNT",
 56 };
 57 
 58 static void print_watch(struct counter_watch *watch, int nwatch)
 59 {
 60         int i;
 61 
 62         /* prints the watch array in C-like structure */
 63         printf("watch[%d] = {\n", nwatch);
 64         for (i = 0; i < nwatch; i++) {
 65                 printf(" [%d] =\t{\n"
 66                        "\t\t.component.type = %s\n"
 67                        "\t\t.component.scope = %s\n"
 68                        "\t\t.component.parent = %d\n"
 69                        "\t\t.component.id = %d\n"
 70                        "\t\t.event = %s\n"
 71                        "\t\t.channel = %d\n"
 72                        "\t},\n",
 73                        i,
 74                        counter_component_type_name[watch[i].component.type],
 75                        counter_scope_name[watch[i].component.scope],
 76                        watch[i].component.parent,
 77                        watch[i].component.id,
 78                        counter_event_type_name[watch[i].event],
 79                        watch[i].channel);
 80         }
 81         printf("};\n");
 82 }
 83 
 84 static void print_usage(void)
 85 {
 86         fprintf(stderr, "Usage:\n\n"
 87                 "counter_watch_events [options] [-w <watchoptions>]\n"
 88                 "counter_watch_events [options] [-w <watch1 options>] [-w <watch2 options>]...\n"
 89                 "\n"
 90                 "When no --watch option has been provided, simple watch example is used:\n"
 91                 "counter_watch_events [options] -w comp_count,scope_count,evt_ovf_udf\n"
 92                 "\n"
 93                 "Test various watch events for given counter device.\n"
 94                 "\n"
 95                 "Options:\n"
 96                 "  -d, --debug                Prints debug information\n"
 97                 "  -h, --help                 Prints usage\n"
 98                 "  -n, --device-num <n>       Use /dev/counter<n> [default: /dev/counter0]\n"
 99                 "  -l, --loop <n>             Loop for <n> events [default: 0 (forever)]\n"
100                 "  -w, --watch <watchoptions> comma-separated list of watch options\n"
101                 "\n"
102                 "Watch options:\n"
103                 "  scope_device               (COUNTER_SCOPE_DEVICE) [default: scope_device]\n"
104                 "  scope_signal               (COUNTER_SCOPE_SIGNAL)\n"
105                 "  scope_count                (COUNTER_SCOPE_COUNT)\n"
106                 "\n"
107                 "  comp_none                  (COUNTER_COMPONENT_NONE) [default: comp_none]\n"
108                 "  comp_signal                (COUNTER_COMPONENT_SIGNAL)\n"
109                 "  comp_count                 (COUNTER_COMPONENT_COUNT)\n"
110                 "  comp_function              (COUNTER_COMPONENT_FUNCTION)\n"
111                 "  comp_synapse_action        (COUNTER_COMPONENT_SYNAPSE_ACTION)\n"
112                 "  comp_extension             (COUNTER_COMPONENT_EXTENSION)\n"
113                 "\n"
114                 "  evt_ovf                    (COUNTER_EVENT_OVERFLOW) [default: evt_ovf]\n"
115                 "  evt_udf                    (COUNTER_EVENT_UNDERFLOW)\n"
116                 "  evt_ovf_udf                (COUNTER_EVENT_OVERFLOW_UNDERFLOW)\n"
117                 "  evt_threshold              (COUNTER_EVENT_THRESHOLD)\n"
118                 "  evt_index                  (COUNTER_EVENT_INDEX)\n"
119                 "  evt_change_of_state        (COUNTER_EVENT_CHANGE_OF_STATE)\n"
120                 "  evt_capture                (COUNTER_EVENT_CAPTURE)\n"
121                 "\n"
122                 "  chan=<n>                   channel <n> for this watch [default: 0]\n"
123                 "  id=<n>                     component id <n> for this watch [default: 0]\n"
124                 "  parent=<n>                 component parent <n> for this watch [default: 0]\n"
125                 "\n"
126                 "Example with two watched events:\n\n"
127                 "counter_watch_events -d \\\n"
128                 "\t-w comp_count,scope_count,evt_ovf_udf \\\n"
129                 "\t-w comp_extension,scope_count,evt_capture,id=7,chan=3\n"
130                 );
131 }
132 
133 static const struct option longopts[] = {
134         { "debug",              no_argument,       0, 'd' },
135         { "help",               no_argument,       0, 'h' },
136         { "device-num",         required_argument, 0, 'n' },
137         { "loop",               required_argument, 0, 'l' },
138         { "watch",              required_argument, 0, 'w' },
139         { },
140 };
141 
142 /* counter watch subopts */
143 enum {
144         WATCH_SCOPE_DEVICE,
145         WATCH_SCOPE_SIGNAL,
146         WATCH_SCOPE_COUNT,
147         WATCH_COMPONENT_NONE,
148         WATCH_COMPONENT_SIGNAL,
149         WATCH_COMPONENT_COUNT,
150         WATCH_COMPONENT_FUNCTION,
151         WATCH_COMPONENT_SYNAPSE_ACTION,
152         WATCH_COMPONENT_EXTENSION,
153         WATCH_EVENT_OVERFLOW,
154         WATCH_EVENT_UNDERFLOW,
155         WATCH_EVENT_OVERFLOW_UNDERFLOW,
156         WATCH_EVENT_THRESHOLD,
157         WATCH_EVENT_INDEX,
158         WATCH_EVENT_CHANGE_OF_STATE,
159         WATCH_EVENT_CAPTURE,
160         WATCH_CHANNEL,
161         WATCH_ID,
162         WATCH_PARENT,
163         WATCH_SUBOPTS_MAX,
164 };
165 
166 static char * const counter_watch_subopts[WATCH_SUBOPTS_MAX + 1] = {
167         /* component.scope */
168         [WATCH_SCOPE_DEVICE] = "scope_device",
169         [WATCH_SCOPE_SIGNAL] = "scope_signal",
170         [WATCH_SCOPE_COUNT] = "scope_count",
171         /* component.type */
172         [WATCH_COMPONENT_NONE] = "comp_none",
173         [WATCH_COMPONENT_SIGNAL] = "comp_signal",
174         [WATCH_COMPONENT_COUNT] = "comp_count",
175         [WATCH_COMPONENT_FUNCTION] = "comp_function",
176         [WATCH_COMPONENT_SYNAPSE_ACTION] = "comp_synapse_action",
177         [WATCH_COMPONENT_EXTENSION] = "comp_extension",
178         /* event */
179         [WATCH_EVENT_OVERFLOW] = "evt_ovf",
180         [WATCH_EVENT_UNDERFLOW] = "evt_udf",
181         [WATCH_EVENT_OVERFLOW_UNDERFLOW] = "evt_ovf_udf",
182         [WATCH_EVENT_THRESHOLD] = "evt_threshold",
183         [WATCH_EVENT_INDEX] = "evt_index",
184         [WATCH_EVENT_CHANGE_OF_STATE] = "evt_change_of_state",
185         [WATCH_EVENT_CAPTURE] = "evt_capture",
186         /* channel, id, parent */
187         [WATCH_CHANNEL] = "chan",
188         [WATCH_ID] = "id",
189         [WATCH_PARENT] = "parent",
190         /* Empty entry ends the opts array */
191         NULL
192 };
193 
194 int main(int argc, char **argv)
195 {
196         int c, fd, i, ret, rc = 0, debug = 0, loop = 0, dev_num = 0, nwatch = 0;
197         struct counter_event event_data;
198         char *device_name = NULL, *subopts, *value;
199         struct counter_watch *watches;
200 
201         /*
202          * 1st pass:
203          * - list watch events number to allocate the watch array.
204          * - parse normal options (other than watch options)
205          */
206         while ((c = getopt_long(argc, argv, "dhn:l:w:", longopts, NULL)) != -1) {
207                 switch (c) {
208                 case 'd':
209                         debug = 1;
210                         break;
211                 case 'h':
212                         print_usage();
213                         return EXIT_SUCCESS;
214                 case 'n':
215                         dev_num = strtoul(optarg, NULL, 10);
216                         if (errno) {
217                                 perror("strtol failed: --device-num <n>\n");
218                                 return EXIT_FAILURE;
219                         }
220                         break;
221                 case 'l':
222                         loop = strtol(optarg, NULL, 10);
223                         if (errno) {
224                                 perror("strtol failed: --loop <n>\n");
225                                 return EXIT_FAILURE;
226                         }
227                         break;
228                 case 'w':
229                         nwatch++;
230                         break;
231                 default:
232                         return EXIT_FAILURE;
233                 }
234         }
235 
236         if (nwatch) {
237                 watches = calloc(nwatch, sizeof(*watches));
238                 if (!watches) {
239                         perror("Error allocating watches\n");
240                         return EXIT_FAILURE;
241                 }
242         } else {
243                 /* default to simple watch example */
244                 watches = simple_watch;
245                 nwatch = ARRAY_SIZE(simple_watch);
246         }
247 
248         /* 2nd pass: parse watch sub-options to fill in watch array */
249         optind = 1;
250         i = 0;
251         while ((c = getopt_long(argc, argv, "dhn:l:w:", longopts, NULL)) != -1) {
252                 switch (c) {
253                 case 'w':
254                         subopts = optarg;
255                         while (*subopts != '\0') {
256                                 ret = getsubopt(&subopts, counter_watch_subopts, &value);
257                                 switch (ret) {
258                                 case WATCH_SCOPE_DEVICE:
259                                 case WATCH_SCOPE_SIGNAL:
260                                 case WATCH_SCOPE_COUNT:
261                                         /* match with counter_scope */
262                                         watches[i].component.scope = ret;
263                                         break;
264                                 case WATCH_COMPONENT_NONE:
265                                 case WATCH_COMPONENT_SIGNAL:
266                                 case WATCH_COMPONENT_COUNT:
267                                 case WATCH_COMPONENT_FUNCTION:
268                                 case WATCH_COMPONENT_SYNAPSE_ACTION:
269                                 case WATCH_COMPONENT_EXTENSION:
270                                         /* match counter_component_type: subtract enum value */
271                                         ret -= WATCH_COMPONENT_NONE;
272                                         watches[i].component.type = ret;
273                                         break;
274                                 case WATCH_EVENT_OVERFLOW:
275                                 case WATCH_EVENT_UNDERFLOW:
276                                 case WATCH_EVENT_OVERFLOW_UNDERFLOW:
277                                 case WATCH_EVENT_THRESHOLD:
278                                 case WATCH_EVENT_INDEX:
279                                 case WATCH_EVENT_CHANGE_OF_STATE:
280                                 case WATCH_EVENT_CAPTURE:
281                                         /* match counter_event_type: subtract enum value */
282                                         ret -= WATCH_EVENT_OVERFLOW;
283                                         watches[i].event = ret;
284                                         break;
285                                 case WATCH_CHANNEL:
286                                         if (!value) {
287                                                 fprintf(stderr, "Invalid chan=<number>\n");
288                                                 rc = EXIT_FAILURE;
289                                                 goto err_free_watches;
290                                         }
291                                         watches[i].channel = strtoul(value, NULL, 10);
292                                         if (errno) {
293                                                 perror("strtoul failed: chan=<number>\n");
294                                                 rc = EXIT_FAILURE;
295                                                 goto err_free_watches;
296                                         }
297                                         break;
298                                 case WATCH_ID:
299                                         if (!value) {
300                                                 fprintf(stderr, "Invalid id=<number>\n");
301                                                 rc = EXIT_FAILURE;
302                                                 goto err_free_watches;
303                                         }
304                                         watches[i].component.id = strtoul(value, NULL, 10);
305                                         if (errno) {
306                                                 perror("strtoul failed: id=<number>\n");
307                                                 rc = EXIT_FAILURE;
308                                                 goto err_free_watches;
309                                         }
310                                         break;
311                                 case WATCH_PARENT:
312                                         if (!value) {
313                                                 fprintf(stderr, "Invalid parent=<number>\n");
314                                                 rc = EXIT_FAILURE;
315                                                 goto err_free_watches;
316                                         }
317                                         watches[i].component.parent = strtoul(value, NULL, 10);
318                                         if (errno) {
319                                                 perror("strtoul failed: parent=<number>\n");
320                                                 rc = EXIT_FAILURE;
321                                                 goto err_free_watches;
322                                         }
323                                         break;
324                                 default:
325                                         fprintf(stderr, "Unknown suboption '%s'\n", value);
326                                         rc = EXIT_FAILURE;
327                                         goto err_free_watches;
328                                 }
329                         }
330                         i++;
331                         break;
332                 }
333         }
334 
335         if (debug)
336                 print_watch(watches, nwatch);
337 
338         ret = asprintf(&device_name, "/dev/counter%d", dev_num);
339         if (ret < 0) {
340                 fprintf(stderr, "asprintf failed\n");
341                 rc = EXIT_FAILURE;
342                 goto err_free_watches;
343         }
344 
345         if (debug)
346                 printf("Opening %s\n", device_name);
347 
348         fd = open(device_name, O_RDWR);
349         if (fd == -1) {
350                 fprintf(stderr, "Unable to open %s: %s\n", device_name, strerror(errno));
351                 free(device_name);
352                 rc = EXIT_FAILURE;
353                 goto err_free_watches;
354         }
355         free(device_name);
356 
357         for (i = 0; i < nwatch; i++) {
358                 ret = ioctl(fd, COUNTER_ADD_WATCH_IOCTL, watches + i);
359                 if (ret == -1) {
360                         fprintf(stderr, "Error adding watches[%d]: %s\n", i,
361                                 strerror(errno));
362                         rc = EXIT_FAILURE;
363                         goto err_close;
364                 }
365         }
366 
367         ret = ioctl(fd, COUNTER_ENABLE_EVENTS_IOCTL);
368         if (ret == -1) {
369                 perror("Error enabling events");
370                 rc = EXIT_FAILURE;
371                 goto err_close;
372         }
373 
374         for (i = 0; loop <= 0 || i < loop; i++) {
375                 ret = read(fd, &event_data, sizeof(event_data));
376                 if (ret == -1) {
377                         perror("Failed to read event data");
378                         rc = EXIT_FAILURE;
379                         goto err_close;
380                 }
381 
382                 if (ret != sizeof(event_data)) {
383                         fprintf(stderr, "Failed to read event data (got: %d)\n", ret);
384                         rc = EXIT_FAILURE;
385                         goto err_close;
386                 }
387 
388                 printf("Timestamp: %llu\tData: %llu\t event: %s\tch: %d\n",
389                        event_data.timestamp, event_data.value,
390                        counter_event_type_name[event_data.watch.event],
391                        event_data.watch.channel);
392 
393                 if (event_data.status) {
394                         fprintf(stderr, "Error %d: %s\n", event_data.status,
395                                 strerror(event_data.status));
396                 }
397         }
398 
399 err_close:
400         close(fd);
401 err_free_watches:
402         if (watches != simple_watch)
403                 free(watches);
404 
405         return rc;
406 }
407 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php