From c5ec776d87c6338d704d15828950646d6f5b2c85 Mon Sep 17 00:00:00 2001 From: Christoph Urlacher Date: Tue, 15 Sep 2026 17:38:52 +0200 Subject: [PATCH] Generate query and results and charts in separate directory --- scripts/Modules/Util.pm | 37 +++++++++++------ scripts/explore.pl | 5 ++- scripts/menu.pl | 88 +++++++++++++++++++++++++---------------- scripts/runner.pl | 6 ++- 4 files changed, 88 insertions(+), 48 deletions(-) diff --git a/scripts/Modules/Util.pm b/scripts/Modules/Util.pm index 1a09e92..40a1818 100644 --- a/scripts/Modules/Util.pm +++ b/scripts/Modules/Util.pm @@ -17,6 +17,7 @@ use feature 'say'; my $local_root = '/home/christoph/Notes/TU/MastersThesis/FailNix'; my $local_archive_dir = "$local_root/injections"; +my $local_queries_dir = "$local_root/queries"; my $ntfy_url = 'https://ntfy.vps.chriphost.de'; my $ntfy_token = 'tk_rx8fd6hojuz4ekcb72j7juugkbmga'; # May be public @@ -133,8 +134,8 @@ sub find_subdirs { } sub execute_query { - my ( $experiment, $queryname, $db_conf, $builds_dir, $do_notify_file, - @filter_config_names ) + my ( $experiment, $queryname, $db_conf, $experiment_dir, $output_dir, + $output_prefix, $do_notify_file, @filter_config_names ) = @_; my $module = "$queryname"; @@ -150,7 +151,7 @@ sub execute_query { or die "$module can't postprocess()"; my $querystring = - $query->( $experiment, "$builds_dir/$experiment", @filter_config_names ); + $query->( $experiment, $experiment_dir, @filter_config_names ); my $argsstring = $args->(); my $filenamestring = $filename->(@filter_config_names); @@ -162,14 +163,16 @@ sub execute_query { $postprocess->($result); - system( 'mkdir', '-p', "$builds_dir/$experiment" ); - open( my $results_handle, '>', "$builds_dir/$experiment/$filenamestring" ) + my $resultfile = "$output_dir/${output_prefix}${filenamestring}"; + + system( 'mkdir', '-p', $output_dir ); + open( my $results_handle, '>', $resultfile ) or die "failed to open file: $!"; print $results_handle $result; close($results_handle) or die "failed to close file: $!"; if ( defined $do_notify_file and $do_notify_file == 1 ) { - notify_file("$builds_dir/$experiment/$filenamestring"); + notify_file($resultfile); } return $result; @@ -359,21 +362,31 @@ sub delete_marker_info { "$local_archive_dir/$experiment/markers/$benchmark-$address.info" ); } -sub pick_data_file { - my ( $dir, $prefix ) = @_; +sub pick_query_file { + my ( $experiment, $prefix ) = @_; + + die "No query directory $local_queries_dir\n" + unless -d $local_queries_dir; # \Q...\E treats ... as literal string - my @files = sort grep { /^\Q$prefix\E.*\.csv$/ } find_files($dir); + my @files = + sort grep { /^\Q${experiment}_\E\Q$prefix\E.*\.csv$/ } + find_files($local_queries_dir); - die "No $prefix CSV files found in $dir\n" unless @files; - return $files[0] if @files == 1; + die "No $prefix CSV files found for $experiment in $local_queries_dir\n" + unless @files; + + # Strip the experiment prefix + my @names = map { s/^\Q${experiment}_\E//r } @files; + + return $names[0] if @names == 1; # Make sure the unfiltered file is at the top my @sorted = sort { ( $a eq "$prefix.csv" ) ? -1 : ( $b eq "$prefix.csv" ) ? 1 : $a cmp $b - } @files; + } @names; my @selected = TUI::select_from_list( "Select $prefix CSV file", 0, @sorted ); diff --git a/scripts/explore.pl b/scripts/explore.pl index 7b2725d..5685d6e 100644 --- a/scripts/explore.pl +++ b/scripts/explore.pl @@ -19,12 +19,13 @@ my $local_wamr = '/home/christoph/Notes/TU/MastersThesis/05 WAMR'; my $local_newlib = '/home/christoph/Notes/TU/MastersThesis/07 NewLib'; my $local_root = '/home/christoph/Notes/TU/MastersThesis/FailNix'; my $local_archive_dir = "$local_root/injections"; +my $local_queries_dir = "$local_root/queries"; # Select experiment to open my $selected_experiment = Util::select_experiment(0); my $selected_faults_csv = - Util::pick_data_file( "$local_archive_dir/$selected_experiment", "faults" ); + Util::pick_query_file( $selected_experiment, "faults" ); my $cui = TUI::init_cui(); @@ -98,7 +99,7 @@ sub load_faults_csv { # Schema: benchmark, resulttype, faults, fault_address my $data = Text::CSV_XS::csv( - in => "$local_archive_dir/$selected_experiment/$selected_faults_csv", + in => "$local_queries_dir/${selected_experiment}_$selected_faults_csv", headers => 'auto' ); diff --git a/scripts/menu.pl b/scripts/menu.pl index 4cc37fb..e6c950e 100644 --- a/scripts/menu.pl +++ b/scripts/menu.pl @@ -27,7 +27,9 @@ my $local_wamr = "$local_root/wamr"; my $local_scripts_dir = "$local_root/scripts"; my $local_builds_dir = "$local_root/builds"; my $local_archive_dir = "$local_root/injections"; +my $local_queries_dir = "$local_root/queries"; my $local_charts_dir = "$local_root/scripts/charts"; +my $local_charts_out_dir = "$local_root/charts"; my $local_ghidra_projects = "$local_root/ghidra"; my $local_ghidra_scripts = "$local_root/scripts/ghidra"; my $local_dump_dir = "$local_root/dumps"; @@ -154,9 +156,12 @@ my %handlers = ( ? " (" . join( "+", @filter_configs ) . ")" : ""; say "Running $query$config_label on $db..."; - Util::execute_query( $experiment, - $query, $local_db_conf, $local_archive_dir, 0, - @filter_configs ); + Util::execute_query( + $experiment, $query, + $local_db_conf, "$local_archive_dir/$experiment", + $local_queries_dir, "${experiment}_", + 0, @filter_configs + ); } } }, @@ -195,6 +200,12 @@ my %handlers = ( foreach (@selected_dirs) { my $experiment = $_ =~ s/(.*?)\s+\(.+\)$/$1/r; + my $faults_csv = "$local_queries_dir/${experiment}_faults.csv"; + unless ( -f $faults_csv ) { + say "Skipping $experiment: $faults_csv does not exist"; + next; + } + say "Creating Ghidra project for $experiment..."; system( 'ghidra-analyzeHeadless', @@ -205,7 +216,7 @@ my %handlers = ( '-postScript', 'DWARFLineInfoSourceMapScript', '-postScript', 'DWARFLineInfoCommentScript', '-postScript', 'ImportMarkersAsBookmarks', - "$local_archive_dir/$experiment/faults.csv" + $faults_csv ); } }, @@ -238,19 +249,17 @@ my %handlers = ( ); # Insert results - if ( - -f "$local_archive_dir/$experiment/results_no_native_call_data+no_native_call_instr.txt" - ) - { - open( my $fhandle, '<', -"$local_archive_dir/$experiment/results_no_native_call_data+no_native_call_instr.txt" - ) or return; + my $results_txt = +"$local_queries_dir/${experiment}_results_no_native_call_data+no_native_call_instr.txt"; + + if ( -f $results_txt ) { + open( my $fhandle, '<', $results_txt ) or return; my $results = join "", <$fhandle>; close($fhandle); # Append link to results file system( 'obsidian', 'append', "file=zettel/$experiment", -"content=## Results\n\n[Results File](file://$local_archive_dir/$experiment/results_no_native_call_data+no_native_call_instr.txt)\n\n" +"content=## Results\n\n[Results File](file://$results_txt)\n\n" ); # Append results as markdown block @@ -260,8 +269,7 @@ my %handlers = ( ); } else { - say -"$local_archive_dir/$experiment/results_no_native_call_data+no_native_call_instr.txt does not exist"; + say "$results_txt does not exist"; } # Insert charts @@ -273,9 +281,15 @@ my %handlers = ( my $attach_image = sub { my ($name) = @_; + my $image = "$local_charts_out_dir/${experiment}_$name.svg"; + + unless ( -f $image ) { + say "$image does not exist"; + return; + } + system( 'obsidian', 'append', "file=zettel/$experiment", -"content=![$name](file://$local_archive_dir/$experiment/$name.svg)\n" - ); + "content=![$name](file://$image)\n" ); }; $attach_image->( "single_result_no_native_call_data+no_native_call_instr"); @@ -292,8 +306,7 @@ my %handlers = ( # TODO: Fails silently if not every selected experiment has this datafile my $resultsdata_csv = - Util::pick_data_file( "$local_archive_dir/$selected_experiments[0]", - "resultsdata" ); + Util::pick_query_file( $selected_experiments[0], "resultsdata" ); # Read results my %all_results; @@ -301,7 +314,7 @@ my %handlers = ( # Schema: benchmark, resulttype, faults my $data = Text::CSV_XS::csv( - in => "$local_archive_dir/$experiment/$resultsdata_csv", + in => "$local_queries_dir/${experiment}_$resultsdata_csv", headers => 'auto' ); @@ -365,13 +378,13 @@ my %handlers = ( # # # TODO: Fails silently if not every selected experiment has this datafile # my $resultsdata_csv = - # Util::pick_data_file( "$local_archive_dir/$baseline", "resultsdata" ); + # Util::pick_query_file( $baseline, "resultsdata" ); # # my %all_results; # foreach my $experiment ( $baseline, @selected_experiments ) { # # my $data = Text::CSV_XS::csv( - # in => "$local_archive_dir/$experiment/$resultsdata_csv", + # in => "$local_queries_dir/${experiment}_$resultsdata_csv", # headers => 'auto' # ); # @@ -728,29 +741,35 @@ my %handlers = ( # Select if faults.csv or a filtered variant should be used my $faults_csv; if (@faults_charts) { - $faults_csv = Util::pick_data_file( - "$local_archive_dir/$selected_experiments[0]", "faults" ); + $faults_csv = + Util::pick_query_file( $selected_experiments[0], "faults" ); } # Select if resultsdata.csv or a filtered variant should be used my $resultsdata_csv; if (@resultsdata_charts) { - $resultsdata_csv = Util::pick_data_file( - "$local_archive_dir/$selected_experiments[0]", - "resultsdata" ); + $resultsdata_csv = + Util::pick_query_file( $selected_experiments[0], "resultsdata" ); } + # Chart SVGs are written into a separate output directory + system( 'mkdir', '-p', $local_charts_out_dir ); + # Plot single-experiment charts + # Args: [] + # [datafile] my @single_charts = grep { /single/ } @selected_charts; foreach my $experiment (@selected_experiments) { foreach my $chart (@single_charts) { say " - Generating plot $chart for $experiment..."; my @r_args = ( - 'Rscript', - "$local_charts_dir/$chart.r", - "$local_archive_dir/$experiment" + 'Rscript', "$local_charts_dir/$chart.r", $experiment, + $local_queries_dir, $local_charts_out_dir ); + # single_heatmap also needs the experiment's system.elf + push @r_args, $local_archive_dir if $chart eq 'single_heatmap'; + # If the chart is marked in @faults_charts, # append the $faults_csv to the args push @r_args, $faults_csv @@ -766,15 +785,18 @@ my %handlers = ( } } + # Plot combined charts + # Args: ... + # [datafile] my @combined_charts = grep { /combined/ } @selected_charts; my $print_experiments = join " ", @selected_experiments; - my @path_experiments = - map { "$local_archive_dir/$_" } @selected_experiments; foreach my $chart (@combined_charts) { say " - Generating plot $chart for ($print_experiments)..."; - my @r_args = - ( 'Rscript', "$local_charts_dir/$chart.r", @path_experiments ); + my @r_args = ( + 'Rscript', "$local_charts_dir/$chart.r", @selected_experiments, + $local_queries_dir, $local_charts_out_dir + ); # If the chart is marked in @faults_charts, # append the $faults_csv to the args diff --git a/scripts/runner.pl b/scripts/runner.pl index 960c81d..e1d3004 100644 --- a/scripts/runner.pl +++ b/scripts/runner.pl @@ -284,8 +284,12 @@ sub results { # Keep trying even if a single query fails for my $query (@queries) { eval { + # Remote results stay in the experiment dir so they are archived + my $experiment_dir = "$remote_builds_dir/$experiment"; + Util::execute_query( $experiment, $query, - $remote_db_conf, $remote_builds_dir, 1, @configs ); + $remote_db_conf, $experiment_dir, $experiment_dir, "", 1, + @configs ); 1; } or do { my $error = $@ || 'bullshit error';