2021-04-27 15:01:21 +08:00
// SPDX-License-Identifier: GPL-2.0
# include <linux/err.h>
# include <linux/zalloc.h>
# include <errno.h>
# include <sys/types.h>
# include <sys/stat.h>
# include <fcntl.h>
# include <sys/param.h>
# include "evlist.h"
# include "evsel.h"
# include "parse-events.h"
# include "parse-events-hybrid.h"
# include "debug.h"
# include "pmu.h"
# include "pmu-hybrid.h"
# include "perf.h"
static void config_hybrid_attr ( struct perf_event_attr * attr ,
int type , int pmu_type )
{
/*
* attr . config layout for type PERF_TYPE_HARDWARE and
* PERF_TYPE_HW_CACHE
*
* PERF_TYPE_HARDWARE : 0xEEEEEEEE000000AA
* AA : hardware event ID
* EEEEEEEE : PMU type ID
* PERF_TYPE_HW_CACHE : 0xEEEEEEEE00DDCCBB
* BB : hardware cache ID
* CC : hardware cache op ID
* DD : hardware cache op result ID
* EEEEEEEE : PMU type ID
* If the PMU type ID is 0 , the PERF_TYPE_RAW will be applied .
*/
attr - > type = type ;
attr - > config = attr - > config | ( ( __u64 ) pmu_type < < PERF_PMU_TYPE_SHIFT ) ;
}
static int create_event_hybrid ( __u32 config_type , int * idx ,
struct list_head * list ,
struct perf_event_attr * attr , char * name ,
struct list_head * config_terms ,
struct perf_pmu * pmu )
{
struct evsel * evsel ;
__u32 type = attr - > type ;
__u64 config = attr - > config ;
config_hybrid_attr ( attr , config_type , pmu - > type ) ;
evsel = parse_events__add_event_hybrid ( list , idx , attr , name ,
pmu , config_terms ) ;
if ( evsel )
evsel - > pmu_name = strdup ( pmu - > name ) ;
else
return - ENOMEM ;
attr - > type = type ;
attr - > config = config ;
return 0 ;
}
2021-04-27 15:01:24 +08:00
static int pmu_cmp ( struct parse_events_state * parse_state ,
struct perf_pmu * pmu )
{
if ( ! parse_state - > hybrid_pmu_name )
return 0 ;
return strcmp ( parse_state - > hybrid_pmu_name , pmu - > name ) ;
}
2021-04-27 15:01:21 +08:00
static int add_hw_hybrid ( struct parse_events_state * parse_state ,
struct list_head * list , struct perf_event_attr * attr ,
char * name , struct list_head * config_terms )
{
struct perf_pmu * pmu ;
int ret ;
perf_pmu__for_each_hybrid_pmu ( pmu ) {
2021-09-09 15:55:08 +03:00
LIST_HEAD ( terms ) ;
2021-04-27 15:01:24 +08:00
if ( pmu_cmp ( parse_state , pmu ) )
continue ;
2021-09-09 15:55:08 +03:00
copy_config_terms ( & terms , config_terms ) ;
2021-04-27 15:01:21 +08:00
ret = create_event_hybrid ( PERF_TYPE_HARDWARE ,
& parse_state - > idx , list , attr , name ,
2021-09-09 15:55:08 +03:00
& terms , pmu ) ;
free_config_terms ( & terms ) ;
2021-04-27 15:01:21 +08:00
if ( ret )
return ret ;
}
return 0 ;
}
2021-04-27 15:01:23 +08:00
static int create_raw_event_hybrid ( int * idx , struct list_head * list ,
struct perf_event_attr * attr , char * name ,
struct list_head * config_terms ,
struct perf_pmu * pmu )
{
struct evsel * evsel ;
attr - > type = pmu - > type ;
evsel = parse_events__add_event_hybrid ( list , idx , attr , name ,
pmu , config_terms ) ;
if ( evsel )
evsel - > pmu_name = strdup ( pmu - > name ) ;
else
return - ENOMEM ;
return 0 ;
}
static int add_raw_hybrid ( struct parse_events_state * parse_state ,
struct list_head * list , struct perf_event_attr * attr ,
char * name , struct list_head * config_terms )
{
struct perf_pmu * pmu ;
int ret ;
perf_pmu__for_each_hybrid_pmu ( pmu ) {
2021-09-09 15:55:08 +03:00
LIST_HEAD ( terms ) ;
2021-04-27 15:01:24 +08:00
if ( pmu_cmp ( parse_state , pmu ) )
continue ;
2021-09-09 15:55:08 +03:00
copy_config_terms ( & terms , config_terms ) ;
2021-04-27 15:01:23 +08:00
ret = create_raw_event_hybrid ( & parse_state - > idx , list , attr ,
2021-09-09 15:55:08 +03:00
name , & terms , pmu ) ;
free_config_terms ( & terms ) ;
2021-04-27 15:01:23 +08:00
if ( ret )
return ret ;
}
return 0 ;
}
2021-04-27 15:01:21 +08:00
int parse_events__add_numeric_hybrid ( struct parse_events_state * parse_state ,
struct list_head * list ,
struct perf_event_attr * attr ,
char * name , struct list_head * config_terms ,
bool * hybrid )
{
* hybrid = false ;
if ( attr - > type = = PERF_TYPE_SOFTWARE )
return 0 ;
if ( ! perf_pmu__has_hybrid ( ) )
return 0 ;
* hybrid = true ;
if ( attr - > type ! = PERF_TYPE_RAW ) {
return add_hw_hybrid ( parse_state , list , attr , name ,
config_terms ) ;
}
2021-04-27 15:01:23 +08:00
return add_raw_hybrid ( parse_state , list , attr , name ,
config_terms ) ;
2021-04-27 15:01:21 +08:00
}
2021-04-27 15:01:22 +08:00
int parse_events__add_cache_hybrid ( struct list_head * list , int * idx ,
struct perf_event_attr * attr , char * name ,
struct list_head * config_terms ,
2021-04-27 15:01:24 +08:00
bool * hybrid ,
struct parse_events_state * parse_state )
2021-04-27 15:01:22 +08:00
{
struct perf_pmu * pmu ;
int ret ;
* hybrid = false ;
if ( ! perf_pmu__has_hybrid ( ) )
return 0 ;
* hybrid = true ;
perf_pmu__for_each_hybrid_pmu ( pmu ) {
2021-09-09 15:55:08 +03:00
LIST_HEAD ( terms ) ;
2021-04-27 15:01:24 +08:00
if ( pmu_cmp ( parse_state , pmu ) )
continue ;
2021-09-09 15:55:08 +03:00
copy_config_terms ( & terms , config_terms ) ;
2021-04-27 15:01:22 +08:00
ret = create_event_hybrid ( PERF_TYPE_HW_CACHE , idx , list ,
2021-09-09 15:55:08 +03:00
attr , name , & terms , pmu ) ;
free_config_terms ( & terms ) ;
2021-04-27 15:01:22 +08:00
if ( ret )
return ret ;
}
return 0 ;
}