tools/counter: add a flexible watch events tool
This adds a new counter tool to be able to test various watch events.
A flexible watch array can be populated from command line, each field
may be tuned with a dedicated command line sub-option in "--watch" string.
Several watch events can be defined, each can have specific watch options,
by using "--watch <watch 1 options> --watch <watch 2 options>".
Watch options is a comma separated list.
It also comes with a simple default watch (to monitor overflow/underflow
events), used when no watch parameters are provided. It's equivalent to:
counter_watch_events -w comp_count,scope_count,evt_ovf_udf
The print_usage() routine proposes another example, from the command line,
which generates a 2 elements watch array, to monitor:
- overflow underflow events
- capture events, on channel 3, that reads read captured data by
specifying the component id (capture3_component_id being 7 here).
Signed-off-by: Fabrice Gasnier <fabrice.gasnier@foss.st.com>
Link: https://lore.kernel.org/r/20231213173117.4174511-2-fabrice.gasnier@foss.st.com
Signed-off-by: William Breathitt Gray <william.gray@linaro.org>
2023-12-13 18:31:16 +01:00
// SPDX-License-Identifier: GPL-2.0-only
/*
* Counter Watch Events - Test various counter watch events in a userspace application
*
* Copyright ( C ) STMicroelectronics 2023 - All Rights Reserved
* Author : Fabrice Gasnier < fabrice . gasnier @ foss . st . com > .
*/
# include <errno.h>
# include <fcntl.h>
# include <getopt.h>
# include <linux/counter.h>
# include <linux/kernel.h>
# include <stdlib.h>
# include <stdio.h>
# include <string.h>
# include <sys/ioctl.h>
# include <unistd.h>
static struct counter_watch simple_watch [ ] = {
{
/* Component data: Count 0 count */
. component . type = COUNTER_COMPONENT_COUNT ,
. component . scope = COUNTER_SCOPE_COUNT ,
. component . parent = 0 ,
/* Event type: overflow or underflow */
. event = COUNTER_EVENT_OVERFLOW_UNDERFLOW ,
/* Device event channel 0 */
. channel = 0 ,
} ,
} ;
static const char * const counter_event_type_name [ ] = {
" COUNTER_EVENT_OVERFLOW " ,
" COUNTER_EVENT_UNDERFLOW " ,
" COUNTER_EVENT_OVERFLOW_UNDERFLOW " ,
" COUNTER_EVENT_THRESHOLD " ,
" COUNTER_EVENT_INDEX " ,
" COUNTER_EVENT_CHANGE_OF_STATE " ,
" COUNTER_EVENT_CAPTURE " ,
} ;
static const char * const counter_component_type_name [ ] = {
" COUNTER_COMPONENT_NONE " ,
" COUNTER_COMPONENT_SIGNAL " ,
" COUNTER_COMPONENT_COUNT " ,
" COUNTER_COMPONENT_FUNCTION " ,
" COUNTER_COMPONENT_SYNAPSE_ACTION " ,
" COUNTER_COMPONENT_EXTENSION " ,
} ;
static const char * const counter_scope_name [ ] = {
" COUNTER_SCOPE_DEVICE " ,
" COUNTER_SCOPE_SIGNAL " ,
" COUNTER_SCOPE_COUNT " ,
} ;
static void print_watch ( struct counter_watch * watch , int nwatch )
{
int i ;
/* prints the watch array in C-like structure */
printf ( " watch[%d] = { \n " , nwatch ) ;
for ( i = 0 ; i < nwatch ; i + + ) {
printf ( " [%d] = \t { \n "
" \t \t .component.type = %s \n "
" \t \t .component.scope = %s \n "
" \t \t .component.parent = %d \n "
" \t \t .component.id = %d \n "
" \t \t .event = %s \n "
" \t \t .channel = %d \n "
" \t }, \n " ,
i ,
counter_component_type_name [ watch [ i ] . component . type ] ,
counter_scope_name [ watch [ i ] . component . scope ] ,
watch [ i ] . component . parent ,
watch [ i ] . component . id ,
counter_event_type_name [ watch [ i ] . event ] ,
watch [ i ] . channel ) ;
}
printf ( " }; \n " ) ;
}
static void print_usage ( void )
{
fprintf ( stderr , " Usage: \n \n "
" counter_watch_events [options] [-w <watchoptions>] \n "
" counter_watch_events [options] [-w <watch1 options>] [-w <watch2 options>]... \n "
" \n "
" When no --watch option has been provided, simple watch example is used: \n "
" counter_watch_events [options] -w comp_count,scope_count,evt_ovf_udf \n "
" \n "
" Test various watch events for given counter device. \n "
" \n "
" Options: \n "
" -d, --debug Prints debug information \n "
" -h, --help Prints usage \n "
" -n, --device-num <n> Use /dev/counter<n> [default: /dev/counter0] \n "
" -l, --loop <n> Loop for <n> events [default: 0 (forever)] \n "
" -w, --watch <watchoptions> comma-separated list of watch options \n "
" \n "
" Watch options: \n "
" scope_device (COUNTER_SCOPE_DEVICE) [default: scope_device] \n "
" scope_signal (COUNTER_SCOPE_SIGNAL) \n "
" scope_count (COUNTER_SCOPE_COUNT) \n "
" \n "
" comp_none (COUNTER_COMPONENT_NONE) [default: comp_none] \n "
" comp_signal (COUNTER_COMPONENT_SIGNAL) \n "
" comp_count (COUNTER_COMPONENT_COUNT) \n "
" comp_function (COUNTER_COMPONENT_FUNCTION) \n "
" comp_synapse_action (COUNTER_COMPONENT_SYNAPSE_ACTION) \n "
" comp_extension (COUNTER_COMPONENT_EXTENSION) \n "
" \n "
" evt_ovf (COUNTER_EVENT_OVERFLOW) [default: evt_ovf] \n "
" evt_udf (COUNTER_EVENT_UNDERFLOW) \n "
" evt_ovf_udf (COUNTER_EVENT_OVERFLOW_UNDERFLOW) \n "
" evt_threshold (COUNTER_EVENT_THRESHOLD) \n "
" evt_index (COUNTER_EVENT_INDEX) \n "
" evt_change_of_state (COUNTER_EVENT_CHANGE_OF_STATE) \n "
" evt_capture (COUNTER_EVENT_CAPTURE) \n "
" \n "
" chan=<n> channel <n> for this watch [default: 0] \n "
2023-12-19 13:30:15 +00:00
" id=<n> component id <n> for this watch [default: 0] \n "
" parent=<n> component parent <n> for this watch [default: 0] \n "
tools/counter: add a flexible watch events tool
This adds a new counter tool to be able to test various watch events.
A flexible watch array can be populated from command line, each field
may be tuned with a dedicated command line sub-option in "--watch" string.
Several watch events can be defined, each can have specific watch options,
by using "--watch <watch 1 options> --watch <watch 2 options>".
Watch options is a comma separated list.
It also comes with a simple default watch (to monitor overflow/underflow
events), used when no watch parameters are provided. It's equivalent to:
counter_watch_events -w comp_count,scope_count,evt_ovf_udf
The print_usage() routine proposes another example, from the command line,
which generates a 2 elements watch array, to monitor:
- overflow underflow events
- capture events, on channel 3, that reads read captured data by
specifying the component id (capture3_component_id being 7 here).
Signed-off-by: Fabrice Gasnier <fabrice.gasnier@foss.st.com>
Link: https://lore.kernel.org/r/20231213173117.4174511-2-fabrice.gasnier@foss.st.com
Signed-off-by: William Breathitt Gray <william.gray@linaro.org>
2023-12-13 18:31:16 +01:00
" \n "
" Example with two watched events: \n \n "
" counter_watch_events -d \\ \n "
" \t -w comp_count,scope_count,evt_ovf_udf \\ \n "
" \t -w comp_extension,scope_count,evt_capture,id=7,chan=3 \n "
) ;
}
static const struct option longopts [ ] = {
{ " debug " , no_argument , 0 , ' d ' } ,
{ " help " , no_argument , 0 , ' h ' } ,
{ " device-num " , required_argument , 0 , ' n ' } ,
{ " loop " , required_argument , 0 , ' l ' } ,
{ " watch " , required_argument , 0 , ' w ' } ,
{ } ,
} ;
/* counter watch subopts */
enum {
WATCH_SCOPE_DEVICE ,
WATCH_SCOPE_SIGNAL ,
WATCH_SCOPE_COUNT ,
WATCH_COMPONENT_NONE ,
WATCH_COMPONENT_SIGNAL ,
WATCH_COMPONENT_COUNT ,
WATCH_COMPONENT_FUNCTION ,
WATCH_COMPONENT_SYNAPSE_ACTION ,
WATCH_COMPONENT_EXTENSION ,
WATCH_EVENT_OVERFLOW ,
WATCH_EVENT_UNDERFLOW ,
WATCH_EVENT_OVERFLOW_UNDERFLOW ,
WATCH_EVENT_THRESHOLD ,
WATCH_EVENT_INDEX ,
WATCH_EVENT_CHANGE_OF_STATE ,
WATCH_EVENT_CAPTURE ,
WATCH_CHANNEL ,
WATCH_ID ,
WATCH_PARENT ,
WATCH_SUBOPTS_MAX ,
} ;
static char * const counter_watch_subopts [ WATCH_SUBOPTS_MAX + 1 ] = {
/* component.scope */
[ WATCH_SCOPE_DEVICE ] = " scope_device " ,
[ WATCH_SCOPE_SIGNAL ] = " scope_signal " ,
[ WATCH_SCOPE_COUNT ] = " scope_count " ,
/* component.type */
[ WATCH_COMPONENT_NONE ] = " comp_none " ,
[ WATCH_COMPONENT_SIGNAL ] = " comp_signal " ,
[ WATCH_COMPONENT_COUNT ] = " comp_count " ,
[ WATCH_COMPONENT_FUNCTION ] = " comp_function " ,
[ WATCH_COMPONENT_SYNAPSE_ACTION ] = " comp_synapse_action " ,
[ WATCH_COMPONENT_EXTENSION ] = " comp_extension " ,
/* event */
[ WATCH_EVENT_OVERFLOW ] = " evt_ovf " ,
[ WATCH_EVENT_UNDERFLOW ] = " evt_udf " ,
[ WATCH_EVENT_OVERFLOW_UNDERFLOW ] = " evt_ovf_udf " ,
[ WATCH_EVENT_THRESHOLD ] = " evt_threshold " ,
[ WATCH_EVENT_INDEX ] = " evt_index " ,
[ WATCH_EVENT_CHANGE_OF_STATE ] = " evt_change_of_state " ,
[ WATCH_EVENT_CAPTURE ] = " evt_capture " ,
/* channel, id, parent */
[ WATCH_CHANNEL ] = " chan " ,
[ WATCH_ID ] = " id " ,
[ WATCH_PARENT ] = " parent " ,
/* Empty entry ends the opts array */
NULL
} ;
int main ( int argc , char * * argv )
{
int c , fd , i , ret , rc = 0 , debug = 0 , loop = 0 , dev_num = 0 , nwatch = 0 ;
struct counter_event event_data ;
char * device_name = NULL , * subopts , * value ;
struct counter_watch * watches ;
/*
* 1 st pass :
* - list watch events number to allocate the watch array .
* - parse normal options ( other than watch options )
*/
while ( ( c = getopt_long ( argc , argv , " dhn:l:w: " , longopts , NULL ) ) ! = - 1 ) {
switch ( c ) {
case ' d ' :
debug = 1 ;
break ;
case ' h ' :
print_usage ( ) ;
return EXIT_SUCCESS ;
case ' n ' :
dev_num = strtoul ( optarg , NULL , 10 ) ;
if ( errno ) {
perror ( " strtol failed: --device-num <n> \n " ) ;
return EXIT_FAILURE ;
}
break ;
case ' l ' :
loop = strtol ( optarg , NULL , 10 ) ;
if ( errno ) {
perror ( " strtol failed: --loop <n> \n " ) ;
return EXIT_FAILURE ;
}
break ;
case ' w ' :
nwatch + + ;
break ;
default :
return EXIT_FAILURE ;
2023-12-20 08:51:43 +08:00
}
}
tools/counter: add a flexible watch events tool
This adds a new counter tool to be able to test various watch events.
A flexible watch array can be populated from command line, each field
may be tuned with a dedicated command line sub-option in "--watch" string.
Several watch events can be defined, each can have specific watch options,
by using "--watch <watch 1 options> --watch <watch 2 options>".
Watch options is a comma separated list.
It also comes with a simple default watch (to monitor overflow/underflow
events), used when no watch parameters are provided. It's equivalent to:
counter_watch_events -w comp_count,scope_count,evt_ovf_udf
The print_usage() routine proposes another example, from the command line,
which generates a 2 elements watch array, to monitor:
- overflow underflow events
- capture events, on channel 3, that reads read captured data by
specifying the component id (capture3_component_id being 7 here).
Signed-off-by: Fabrice Gasnier <fabrice.gasnier@foss.st.com>
Link: https://lore.kernel.org/r/20231213173117.4174511-2-fabrice.gasnier@foss.st.com
Signed-off-by: William Breathitt Gray <william.gray@linaro.org>
2023-12-13 18:31:16 +01:00
if ( nwatch ) {
watches = calloc ( nwatch , sizeof ( * watches ) ) ;
if ( ! watches ) {
perror ( " Error allocating watches \n " ) ;
return EXIT_FAILURE ;
}
} else {
/* default to simple watch example */
watches = simple_watch ;
nwatch = ARRAY_SIZE ( simple_watch ) ;
}
/* 2nd pass: parse watch sub-options to fill in watch array */
optind = 1 ;
i = 0 ;
while ( ( c = getopt_long ( argc , argv , " dhn:l:w: " , longopts , NULL ) ) ! = - 1 ) {
switch ( c ) {
case ' w ' :
subopts = optarg ;
while ( * subopts ! = ' \0 ' ) {
ret = getsubopt ( & subopts , counter_watch_subopts , & value ) ;
switch ( ret ) {
case WATCH_SCOPE_DEVICE :
case WATCH_SCOPE_SIGNAL :
case WATCH_SCOPE_COUNT :
/* match with counter_scope */
watches [ i ] . component . scope = ret ;
break ;
case WATCH_COMPONENT_NONE :
case WATCH_COMPONENT_SIGNAL :
case WATCH_COMPONENT_COUNT :
case WATCH_COMPONENT_FUNCTION :
case WATCH_COMPONENT_SYNAPSE_ACTION :
case WATCH_COMPONENT_EXTENSION :
/* match counter_component_type: subtract enum value */
ret - = WATCH_COMPONENT_NONE ;
watches [ i ] . component . type = ret ;
break ;
case WATCH_EVENT_OVERFLOW :
case WATCH_EVENT_UNDERFLOW :
case WATCH_EVENT_OVERFLOW_UNDERFLOW :
case WATCH_EVENT_THRESHOLD :
case WATCH_EVENT_INDEX :
case WATCH_EVENT_CHANGE_OF_STATE :
case WATCH_EVENT_CAPTURE :
/* match counter_event_type: subtract enum value */
ret - = WATCH_EVENT_OVERFLOW ;
watches [ i ] . event = ret ;
break ;
case WATCH_CHANNEL :
if ( ! value ) {
fprintf ( stderr , " Invalid chan=<number> \n " ) ;
rc = EXIT_FAILURE ;
goto err_free_watches ;
}
watches [ i ] . channel = strtoul ( value , NULL , 10 ) ;
if ( errno ) {
perror ( " strtoul failed: chan=<number> \n " ) ;
rc = EXIT_FAILURE ;
goto err_free_watches ;
}
break ;
case WATCH_ID :
if ( ! value ) {
fprintf ( stderr , " Invalid id=<number> \n " ) ;
rc = EXIT_FAILURE ;
goto err_free_watches ;
}
watches [ i ] . component . id = strtoul ( value , NULL , 10 ) ;
if ( errno ) {
perror ( " strtoul failed: id=<number> \n " ) ;
rc = EXIT_FAILURE ;
goto err_free_watches ;
}
break ;
case WATCH_PARENT :
if ( ! value ) {
fprintf ( stderr , " Invalid parent=<number> \n " ) ;
rc = EXIT_FAILURE ;
goto err_free_watches ;
}
watches [ i ] . component . parent = strtoul ( value , NULL , 10 ) ;
if ( errno ) {
perror ( " strtoul failed: parent=<number> \n " ) ;
rc = EXIT_FAILURE ;
goto err_free_watches ;
}
break ;
default :
fprintf ( stderr , " Unknown suboption '%s' \n " , value ) ;
rc = EXIT_FAILURE ;
goto err_free_watches ;
}
}
i + + ;
break ;
}
2023-12-20 08:51:43 +08:00
}
tools/counter: add a flexible watch events tool
This adds a new counter tool to be able to test various watch events.
A flexible watch array can be populated from command line, each field
may be tuned with a dedicated command line sub-option in "--watch" string.
Several watch events can be defined, each can have specific watch options,
by using "--watch <watch 1 options> --watch <watch 2 options>".
Watch options is a comma separated list.
It also comes with a simple default watch (to monitor overflow/underflow
events), used when no watch parameters are provided. It's equivalent to:
counter_watch_events -w comp_count,scope_count,evt_ovf_udf
The print_usage() routine proposes another example, from the command line,
which generates a 2 elements watch array, to monitor:
- overflow underflow events
- capture events, on channel 3, that reads read captured data by
specifying the component id (capture3_component_id being 7 here).
Signed-off-by: Fabrice Gasnier <fabrice.gasnier@foss.st.com>
Link: https://lore.kernel.org/r/20231213173117.4174511-2-fabrice.gasnier@foss.st.com
Signed-off-by: William Breathitt Gray <william.gray@linaro.org>
2023-12-13 18:31:16 +01:00
if ( debug )
print_watch ( watches , nwatch ) ;
ret = asprintf ( & device_name , " /dev/counter%d " , dev_num ) ;
if ( ret < 0 ) {
fprintf ( stderr , " asprintf failed \n " ) ;
rc = EXIT_FAILURE ;
goto err_free_watches ;
}
if ( debug )
printf ( " Opening %s \n " , device_name ) ;
fd = open ( device_name , O_RDWR ) ;
if ( fd = = - 1 ) {
fprintf ( stderr , " Unable to open %s: %s \n " , device_name , strerror ( errno ) ) ;
free ( device_name ) ;
rc = EXIT_FAILURE ;
goto err_free_watches ;
}
free ( device_name ) ;
for ( i = 0 ; i < nwatch ; i + + ) {
ret = ioctl ( fd , COUNTER_ADD_WATCH_IOCTL , watches + i ) ;
if ( ret = = - 1 ) {
fprintf ( stderr , " Error adding watches[%d]: %s \n " , i ,
strerror ( errno ) ) ;
rc = EXIT_FAILURE ;
goto err_close ;
}
}
ret = ioctl ( fd , COUNTER_ENABLE_EVENTS_IOCTL ) ;
if ( ret = = - 1 ) {
perror ( " Error enabling events " ) ;
rc = EXIT_FAILURE ;
goto err_close ;
}
for ( i = 0 ; loop < = 0 | | i < loop ; i + + ) {
ret = read ( fd , & event_data , sizeof ( event_data ) ) ;
if ( ret = = - 1 ) {
perror ( " Failed to read event data " ) ;
rc = EXIT_FAILURE ;
goto err_close ;
}
if ( ret ! = sizeof ( event_data ) ) {
fprintf ( stderr , " Failed to read event data (got: %d) \n " , ret ) ;
rc = EXIT_FAILURE ;
goto err_close ;
}
printf ( " Timestamp: %llu \t Data: %llu \t event: %s \t ch: %d \n " ,
event_data . timestamp , event_data . value ,
counter_event_type_name [ event_data . watch . event ] ,
event_data . watch . channel ) ;
if ( event_data . status ) {
fprintf ( stderr , " Error %d: %s \n " , event_data . status ,
strerror ( event_data . status ) ) ;
}
}
err_close :
close ( fd ) ;
err_free_watches :
if ( watches ! = simple_watch )
free ( watches ) ;
return rc ;
}