package Filters; use strict; use warnings; use diagnostics; use FindBin; use lib $FindBin::Bin; use Util; my %CONFIGS = ( no_aot_instr => { label => "Exclude WAMR AOT array (instr)", regions => [ [ '_wamr_aot_start', '_wamr_aot_end', 'p.injection_instr_absolute' ] ], }, no_aot_data => { label => "Exclude WAMR AOT array (data)", regions => [ [ '_wamr_aot_start', '_wamr_aot_end', 'g.data_physical_address' ] ], }, no_mmap_instr => { label => "Exclude WAMR mmap (instr)", regions => [ [ '_wamr_mmap_start', '_wamr_mmap_end', 'p.injection_instr_absolute' ] ], }, no_mmap_data => { label => "Exclude WAMR mmap (data)", regions => [ [ '_wamr_mmap_start', '_wamr_mmap_end', 'g.data_physical_address' ] ], }, no_runtime_pool_instr => { label => "Exclude WAMR runtime pool (instr)", regions => [ [ '_wamr_runtime_pool_start', '_wamr_runtime_pool_end', 'p.injection_instr_absolute' ] ], }, no_runtime_pool_data => { label => "Exclude WAMR runtime pool (data)", regions => [ [ '_wamr_runtime_pool_start', '_wamr_runtime_pool_end', 'g.data_physical_address' ] ], }, no_linear_pool_instr => { label => "Exclude WAMR linear pool (instr)", regions => [ [ '_wamr_linear_pool_start', '_wamr_linear_pool_end', 'p.injection_instr_absolute' ] ], }, no_linear_pool_data => { label => "Exclude WAMR linear pool (data)", regions => [ [ '_wamr_linear_pool_start', '_wamr_linear_pool_end', 'g.data_physical_address' ] ], }, no_global_heap_instr => { label => "Exclude WAMR global heap (instr)", regions => [ [ '_wamr_global_heap_start', '_wamr_global_heap_end', 'p.injection_instr_absolute' ] ], }, no_global_heap_data => { label => "Exclude WAMR global heap (data)", regions => [ [ '_wamr_global_heap_start', '_wamr_global_heap_end', 'g.data_physical_address' ] ], }, ); # All entries are functions part of the native call chain my @NATIVE_CALL_FUNCS = ( 'aot_invoke_native', # imported-function dispatch (AOT) 'aot_call_indirect', # call_indirect dispatch (AOT) 'wasm_interp_call_func_native', # native dispatch (Interp) 'wasm_runtime_invoke_native', # common 'invokeNative', # common # Imported functions: 'host_fail_start_trace', 'host_fail_stop_trace', 'host_fail_marker_positive', 'host_fail_marker_negative', 'host_fail_marker_detected', 'host_print', ); $CONFIGS{no_native_call_instr} = { label => "Exclude WAMR native call chain (instr)", regions => [ map { { func => $_, col => 'p.injection_instr_absolute' } } @NATIVE_CALL_FUNCS ], }; $CONFIGS{no_native_call_data} = { label => "Exclude WAMR native call chain (data)", regions => [ map { { func => $_, col => 'g.data_physical_address' } } @NATIVE_CALL_FUNCS ], }; # Generate the inverse filters to the regions defined above for my $name ( keys %CONFIGS ) { next unless $name =~ /^no_/; ( my $only_name = $name ) =~ s/^no_/only_/; my $src = $CONFIGS{$name}; my $label = $src->{label} // $name; $label =~ s/^Exclude/Keep only/; $CONFIGS{$only_name} = { label => $label, invert => 1, regions => $src->{regions}, }; } # Those will be executed automatically by runner.pl (+ no filter at all) # my @DEFAULT_CONFIGS = ('no_aot_data'); my @DEFAULT_CONFIGS = (); sub get_configs { return \%CONFIGS; } sub get_default_configs { return @DEFAULT_CONFIGS; } # Builds the filters for regions whose column matches $col_filter. # Queries that aggreate separately have to apply the data and instruction # filters separately as well. sub build_filter_clause_restricted { my ( $experiment_dir, $col_filter, @config_names ) = @_; # Drop empty ones, rest is combined @config_names = grep { defined && length } @config_names; return "" unless @config_names; return "" unless defined $experiment_dir && -f "$experiment_dir/system.elf"; my $elf = "$experiment_dir/system.elf"; # Produce ($start, $end, $col)-tuple from a defined region my $resolve = sub { my ($region) = @_; my ( $start, $end, $col ); if ( ref($region) eq 'HASH' ) { # Symbol + size definition (e.g., native call function list) $col = $region->{col}; ( $start, $end ) = Util::elf_sym_range( $elf, $region->{func} ); } else { # Linker script definition (e.g., AOT region) my ( $start_sym, $end_sym ); ( $start_sym, $end_sym, $col ) = @$region; $start = Util::elf_sym_addr( $elf, $start_sym ); $end = Util::elf_sym_addr( $elf, $end_sym ); } return unless defined $start && defined $end && $end > $start; return ( $start, $end, $col ); }; my @excl_filters; my @keep_terms; for my $config_name (@config_names) { my $config = $CONFIGS{$config_name}; next unless defined $config; my $regions = $config->{regions}; next unless defined $regions; my $invert = $config->{invert}; for my $region (@$regions) { my ( $start, $end, $col ) = $resolve->($region); next unless defined $start; next unless $col =~ $col_filter; if ($invert) { push @keep_terms, "$col BETWEEN $start AND @{[$end - 1]}"; } else { push @excl_filters, "$col NOT BETWEEN $start AND @{[$end - 1]}"; } } } # Including filters are combined with OR... my @filters = @excl_filters; push @filters, "(" . join( " OR ", @keep_terms ) . ")" if @keep_terms; # ...excluding filters are combined with AND return "" unless @filters; return "\nAND " . join( "\nAND ", @filters ); } sub build_filter_clause { my ( $experiment_dir, @config_names ) = @_; return build_filter_clause_restricted( $experiment_dir, qr//, @config_names ); } 1;