Generate query and results and charts in separate directory

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