From 9a720d7160556cdb85d4bce212110598cbe100fe Mon Sep 17 00:00:00 2001 From: Christoph Urlacher Date: Tue, 15 Sep 2026 15:51:48 +0200 Subject: [PATCH] Add alternative resultsdata query that reconstructs fspgroup table instead of depending on it --- scripts/Queries/ResultsDataWriteGroups.pm | 55 +++++ scripts/menu.pl | 263 +++++++++++----------- 2 files changed, 188 insertions(+), 130 deletions(-) create mode 100644 scripts/Queries/ResultsDataWriteGroups.pm diff --git a/scripts/Queries/ResultsDataWriteGroups.pm b/scripts/Queries/ResultsDataWriteGroups.pm new file mode 100644 index 0000000..3b8e69b --- /dev/null +++ b/scripts/Queries/ResultsDataWriteGroups.pm @@ -0,0 +1,55 @@ +package ResultsDataWriteGroups; + +use strict; +use warnings; +use diagnostics; + +use FindBin; +use lib "$FindBin::Bin/../Modules"; +use Filters; + +use feature 'say'; + +sub query { + my ( $experiment, $experiment_dir, @filter_config_names ) = @_; + + my $extra = + Filters::build_filter_clause( $experiment_dir, @filter_config_names ); + + # This query asks the same question as ResultsData.pm: How much faultspace + # area ended up in each possible outcome? + # + # The difference is how the write equivalence classes are treated. + # BasicPruner's write-group INSERT maps every 'W' trace entry to the single + # known_outcome=1 write pilot, but fspgroup has PRIMARY KEY (pilot_id), so + # only the first row lands in the table. + # This query fixes that. + my $querystring = "SELECT +benchmark, resulttype, SUM(t.time2 - t.time1 + 1) AS faults +FROM variant v +JOIN trace t ON v.id = t.variant_id +JOIN fsppilot p ON p.variant_id = t.variant_id + AND ( (p.known_outcome = 1 AND t.accesstype = 'W') + OR (p.known_outcome = 0 AND p.instr2 = t.instr2 AND p.data_physical_address = t.data_physical_address) ) +JOIN result_GenericExperimentMessage r ON r.pilot_id = p.id +WHERE v.variant = '$experiment'$extra +GROUP BY v.id, resulttype +ORDER BY variant, benchmark, resulttype;"; + + say $querystring; + + return $querystring; +} + +sub args { return "--batch --raw"; } + +sub filename { + my @filter_config_names = grep { defined && length } @_; + my $suffix = + @filter_config_names ? "_" . join( "+", sort @filter_config_names ) : ""; + return "resultsdata_writegroups${suffix}.csv"; +} + +sub postprocess { $_[0] =~ s/\t/,/g; } + +1; diff --git a/scripts/menu.pl b/scripts/menu.pl index eda3d0e..2c3e28a 100644 --- a/scripts/menu.pl +++ b/scripts/menu.pl @@ -100,6 +100,9 @@ my %handlers = ( ResultsDataPruned => 'Faults summary per benchmark with resulttype, using the pruned data without expansion (resultsdata_pruned.csv)', + ResultsDataWriteGroups => +'Faults summary per benchmark with resulttype, with write equivalence classes reconstructed from fsppilot (resultsdata_writegroups.csv)', + TargetClass => 'Faults by code type with data type (stack/heap/bss/...) and resulttype -> targetclass.csv', @@ -832,7 +835,7 @@ my %handlers = ( '32. Import Database (Mars)' => sub { - # Import databse dump on mars + # Import database dump on mars die "No dumps in $local_dump_dir" unless -d $local_dump_dir; my @dumps = grep { /\.sql$/ } Util::find_files($local_dump_dir); my @selected_dumps = @@ -861,135 +864,135 @@ my %handlers = ( '<', Util::shell_quote($dump_file) ); }, - '33. Repair fspgroup Write Groups (Mars)' => sub { - - # Retroactively fixes (hopefully) the missing equivalence class - # mappings (EC <-> Pilot) the BasicPruner misses (because it maps - # multiple classes to a single pilot, but uses the pilot as the - # primary key) - my @dbs = Mars::db_list(); - my @dbs_with_notes; - foreach my $db (@dbs) { - my $info = - Util::read_experiment_info( $db =~ s/smchurla_//r =~ s/:/-/gr ); - - push @dbs_with_notes, - ( defined $info && length($info) > 0 ) - ? sprintf( "%-60s (%s)", $db, $info ) - : $db; - } - - my @selected_dbs = TUI::select_from_list( "Select Databases to Repair", - 1, @dbs_with_notes ); - die "No database selected" unless @selected_dbs; - - @selected_dbs = - map { s/(.*?)\s+\(.+\)$/$1/r } @selected_dbs; - - # The PRIMARY KEY gets dropped by the repair and replaced with a KEY. - # To not run this shit on already repaired DBs, check for the PRIMARY - # index as a determinant - my $index_exists = sub { - my ($index) = @_; - my ($count) = Mars::db_selectrow( - "SELECT COUNT(*) FROM information_schema.STATISTICS - WHERE TABLE_SCHEMA = DATABASE() - AND TABLE_NAME = 'fspgroup' - AND INDEX_NAME = '$index'" - ); - return $count; - }; - - foreach my $db (@selected_dbs) { - say "Repairing $db..."; - - # Select the DB so index_exists works - Mars::db_do("use `$db`"); - - # Update the variant names, so the queries still work - my $expected_variant = $db =~ s/^smchurla_//r; - my ($variant_count) = - Mars::db_selectrow("SELECT COUNT(DISTINCT variant) FROM variant"); - my ($current_variant) = - Mars::db_selectrow("SELECT DISTINCT variant FROM variant"); - - if ( !defined $variant_count || $variant_count != 1 ) { - say " - WARNING: $variant_count distinct variants!"; - } - elsif ( $current_variant ne $expected_variant ) { - say " - Variant is '$current_variant' but queries look up" - . " '$expected_variant' (from the database name), renaming..."; - Mars::db_do("UPDATE variant SET variant = '$expected_variant'"); - } - - # Drop the primary key - if ( $index_exists->('PRIMARY') ) { - say " - Dropping PRIMARY KEY (pilot_id)..."; - Mars::db_do("ALTER TABLE fspgroup DROP PRIMARY KEY"); - } - - # Add an index for the columns we actually join on (mostly) - unless ( $index_exists->('eq_class') ) { - say " - Adding eq_class index..."; - Mars::db_do( - "ALTER TABLE fspgroup -ADD KEY eq_class (variant_id, instr2, data_physical_address)" - ); - } - - # I'm currently only using BasicPruner, but don't touch other - # pruning methods for now, for safety - my ($fspmethod_id) = - Mars::db_selectrow( - "SELECT id FROM fspmethod WHERE method = 'basic'"); - die "No 'basic' fspmethod in $db" unless defined $fspmethod_id; - - # The first row succeeded before the duplicate key error, remove it - Mars::db_do( - "DELETE g -FROM fspgroup g -JOIN fsppilot p ON p.id = g.pilot_id -WHERE p.known_outcome = 1 AND p.fspmethod_id = $fspmethod_id" - ); - - my ($expected) = - Mars::db_selectrow( - "SELECT COUNT(*) FROM trace WHERE accesstype = 'W'"); - - # Query from BasicPruner.cc, now ran against the updated DB - say " - Inserting $expected write groups..."; - Mars::db_do( - "INSERT INTO -fspgroup (variant_id, instr2, data_physical_address, bit_pos, fspmethod_id, pilot_id) -SELECT STRAIGHT_JOIN t.variant_id, t.instr2, t.data_physical_address, p.bit_pos, p.fspmethod_id, p.id -FROM fsppilot p -JOIN trace t -ON t.variant_id = p.variant_id AND p.fspmethod_id = $fspmethod_id AND p.known_outcome = 1 -WHERE t.accesstype = 'W'" - ); - - # We expect one row per write group/EC. - # Otherwise no idea what's going on :O - my ($actual) = Mars::db_selectrow( - "SELECT COUNT(*) -FROM fspgroup g -JOIN fsppilot p ON p.id = g.pilot_id -WHERE p.known_outcome = 1 AND p.fspmethod_id = $fspmethod_id" - ); - - if ( $actual == $expected ) { - say " - OK: $actual write groups match the write ECs in trace"; - } - else { - say " - WARNING: inserted $actual, expected $expected." - . " Check for duplicate known_outcome pilots:" - . " SELECT variant_id, COUNT(*) FROM fsppilot" - . " WHERE known_outcome = 1 GROUP BY variant_id;"; - } - } - - say "Queries have to be re-run."; - }, +# '33. Repair fspgroup Write Groups (Mars)' => sub { +# +# # Retroactively fixes (hopefully) the missing equivalence class +# # mappings (EC <-> Pilot) the BasicPruner misses (because it maps +# # multiple classes to a single pilot, but uses the pilot as the +# # primary key) +# my @dbs = Mars::db_list(); +# my @dbs_with_notes; +# foreach my $db (@dbs) { +# my $info = +# Util::read_experiment_info( $db =~ s/smchurla_//r =~ s/:/-/gr ); +# +# push @dbs_with_notes, +# ( defined $info && length($info) > 0 ) +# ? sprintf( "%-60s (%s)", $db, $info ) +# : $db; +# } +# +# my @selected_dbs = TUI::select_from_list( "Select Databases to Repair", +# 1, @dbs_with_notes ); +# die "No database selected" unless @selected_dbs; +# +# @selected_dbs = +# map { s/(.*?)\s+\(.+\)$/$1/r } @selected_dbs; +# +# # The PRIMARY KEY gets dropped by the repair and replaced with a KEY. +# # To not run this shit on already repaired DBs, check for the PRIMARY +# # index as a determinant +# my $index_exists = sub { +# my ($index) = @_; +# my ($count) = Mars::db_selectrow( +# "SELECT COUNT(*) FROM information_schema.STATISTICS +# WHERE TABLE_SCHEMA = DATABASE() +# AND TABLE_NAME = 'fspgroup' +# AND INDEX_NAME = '$index'" +# ); +# return $count; +# }; +# +# foreach my $db (@selected_dbs) { +# say "Repairing $db..."; +# +# # Select the DB so index_exists works +# Mars::db_do("use `$db`"); +# +# # Update the variant names, so the queries still work +# my $expected_variant = $db =~ s/^smchurla_//r; +# my ($variant_count) = +# Mars::db_selectrow("SELECT COUNT(DISTINCT variant) FROM variant"); +# my ($current_variant) = +# Mars::db_selectrow("SELECT DISTINCT variant FROM variant"); +# +# if ( !defined $variant_count || $variant_count != 1 ) { +# say " - WARNING: $variant_count distinct variants!"; +# } +# elsif ( $current_variant ne $expected_variant ) { +# say " - Variant is '$current_variant' but queries look up" +# . " '$expected_variant' (from the database name), renaming..."; +# Mars::db_do("UPDATE variant SET variant = '$expected_variant'"); +# } +# +# # Drop the primary key +# if ( $index_exists->('PRIMARY') ) { +# say " - Dropping PRIMARY KEY (pilot_id)..."; +# Mars::db_do("ALTER TABLE fspgroup DROP PRIMARY KEY"); +# } +# +# # Add an index for the columns we actually join on (mostly) +# unless ( $index_exists->('eq_class') ) { +# say " - Adding eq_class index..."; +# Mars::db_do( +# "ALTER TABLE fspgroup +# ADD KEY eq_class (variant_id, instr2, data_physical_address)" +# ); +# } +# +# # I'm currently only using BasicPruner, but don't touch other +# # pruning methods for now, for safety +# my ($fspmethod_id) = +# Mars::db_selectrow( +# "SELECT id FROM fspmethod WHERE method = 'basic'"); +# die "No 'basic' fspmethod in $db" unless defined $fspmethod_id; +# +# # The first row succeeded before the duplicate key error, remove it +# Mars::db_do( +# "DELETE g +# FROM fspgroup g +# JOIN fsppilot p ON p.id = g.pilot_id +# WHERE p.known_outcome = 1 AND p.fspmethod_id = $fspmethod_id" +# ); +# +# my ($expected) = +# Mars::db_selectrow( +# "SELECT COUNT(*) FROM trace WHERE accesstype = 'W'"); +# +# # Query from BasicPruner.cc, now ran against the updated DB +# say " - Inserting $expected write groups..."; +# Mars::db_do( +# "INSERT INTO +# fspgroup (variant_id, instr2, data_physical_address, bit_pos, fspmethod_id, pilot_id) +# SELECT STRAIGHT_JOIN t.variant_id, t.instr2, t.data_physical_address, p.bit_pos, p.fspmethod_id, p.id +# FROM fsppilot p +# JOIN trace t +# ON t.variant_id = p.variant_id AND p.fspmethod_id = $fspmethod_id AND p.known_outcome = 1 +# WHERE t.accesstype = 'W'" +# ); +# +# # We expect one row per write group/EC. +# # Otherwise no idea what's going on :O +# my ($actual) = Mars::db_selectrow( +# "SELECT COUNT(*) +# FROM fspgroup g +# JOIN fsppilot p ON p.id = g.pilot_id +# WHERE p.known_outcome = 1 AND p.fspmethod_id = $fspmethod_id" +# ); +# +# if ( $actual == $expected ) { +# say " - OK: $actual write groups match the write ECs in trace"; +# } +# else { +# say " - WARNING: inserted $actual, expected $expected." +# . " Check for duplicate known_outcome pilots:" +# . " SELECT variant_id, COUNT(*) FROM fsppilot" +# . " WHERE known_outcome = 1 GROUP BY variant_id;"; +# } +# } +# +# say "Queries have to be re-run."; +# }, '95. Delete Builds' => sub {