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