From patchwork Tue Nov 28 19:31:47 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Malcolm X-Patchwork-Id: 842262 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-468118-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="MZ2pDdN7"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3ymYdM4ZpNz9sCZ for ; Wed, 29 Nov 2017 06:29:27 +1100 (AEDT) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id; q=dns; s=default; b=L+QfULik7xip 4vjU84zXOfABkNftnwWO1RVmi8gU46r2BmPCunrVtu4pd1fDWggnMrYDi+HHRoba 2lWE3d/XA97ISp3AWcyLtNxZESiO/Sllihe+DA/+mPIaFUOlyif0xKdcewwqVAAc wgt2Vx4ohI0taT8oEQptVxAw6vfu33A= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id; s=default; bh=AYctx+PPIlyvMInV/Z uZFIqa6Hw=; b=MZ2pDdN7QelEWMqJKG8Wu5zJWPUG9FmenGIZ6Ampc6zm8wJ6VB 8RqKZfX/O1ya2C9VjDAHJpztx4mRfP4Zyan/7GuECmTeRbpIba+Q/JgbjcG9a38D RUM32dvrERfJAeOsNguWohqD7rvYFHI6Mmyz8vBYS+06HPdw49NL9nvAQ= Received: (qmail 31894 invoked by alias); 28 Nov 2017 19:29:17 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 31877 invoked by uid 89); 28 Nov 2017 19:29:17 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-26.7 required=5.0 tests=BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KB_WAM_FROM_NAME_SINGLEWORD, SPF_HELO_PASS, T_RP_MATCHES_RCVD autolearn=ham version=3.3.2 spammy=families, suites, 40218 X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Tue, 28 Nov 2017 19:29:15 +0000 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 2B643358 for ; Tue, 28 Nov 2017 19:29:14 +0000 (UTC) Received: from c64.redhat.com (ovpn-112-13.phx2.redhat.com [10.3.112.13]) by smtp.corp.redhat.com (Postfix) with ESMTP id 3869160600; Tue, 28 Nov 2017 19:29:13 +0000 (UTC) From: David Malcolm To: gcc-patches@gcc.gnu.org Cc: David Malcolm Subject: [PATCH] Expensive selftests: torture testing for fix-it boundary conditions (PR c/82050) Date: Tue, 28 Nov 2017 14:31:47 -0500 Message-Id: <1511897507-26241-1-git-send-email-dmalcolm@redhat.com> X-IsSubscribed: yes This patch adds selftest coverage for the fix for PR c/82050 (r255214). The selftest iterates over various "interesting" column and line-width values to try to shake out bugs in the fix-it printing routines, a kind of "torture" selftest. Unfortunately this selftest is noticably slower than the other selftests; adding it to diagnostic-show-locus.c led to: -fself-test: 40218 pass(es) in 0.172000 seconds slowing down to: -fself-test: 97315 pass(es) in 6.109000 seconds for an unoptimized build (e.g. when hacking with --disable-bootstrap). Given that this affects the compile-edit-test cycle of the "gcc" subdirectory, this felt like an unacceptable amount of overhead to add. I attempted to optimize the test by reducing the amount of coverage, but the test seems useful, and there seems to be a valid role for "torture" selftests. Hence this patch adds a: gcc.dg/plugin/expensive_selftests_plugin.c with the responsibility for running "expensive" selftests, and adds the expensive test there. The patch moves a small amount of code from selftest::run_tests into a helper class so that the plugin can print a useful summary line (to reassure us that the tests are actually being run). With that, the compile-edit-test cycle of the "gcc" subdir is unaffected; the plugin takes: expensive_selftests_plugin: 26641 pass(es) in 3.127000 seconds which seems reasonable within the much longer time taken by "make check" (I optimized some of the overhead away, hence the reduction from 6 seconds above down to 3 seconds). Successfully bootstrapped®rtested on x86_64-pc-linux-gnu. OK for trunk? gcc/ChangeLog: PR c/82050 * selftest-run-tests.c (selftest::run_tests): Move start/finish code to... * selftest.c (selftest::test_runner::test_runner): New ctor. (selftest::test_runner::~test_runner): New dtor. * selftest.h (class selftest::test_runner): New class. gcc/testsuite/ChangeLog: PR c/82050 * gcc.dg/plugin/expensive-selftests-1.c: New file. * gcc.dg/plugin/expensive_selftests_plugin.c: New file. * gcc.dg/plugin/plugin.exp (plugin_test_list): Add the above. --- gcc/selftest-run-tests.c | 11 +- gcc/selftest.c | 22 +++ gcc/selftest.h | 14 ++ .../gcc.dg/plugin/expensive-selftests-1.c | 3 + .../gcc.dg/plugin/expensive_selftests_plugin.c | 175 +++++++++++++++++++++ gcc/testsuite/gcc.dg/plugin/plugin.exp | 2 + 6 files changed, 218 insertions(+), 9 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/plugin/expensive-selftests-1.c create mode 100644 gcc/testsuite/gcc.dg/plugin/expensive_selftests_plugin.c diff --git a/gcc/selftest-run-tests.c b/gcc/selftest-run-tests.c index 6030d3b..f539c66 100644 --- a/gcc/selftest-run-tests.c +++ b/gcc/selftest-run-tests.c @@ -46,7 +46,7 @@ selftest::run_tests () option-handling. */ path_to_selftest_files = flag_self_test; - long start_time = get_run_time (); + test_runner r ("-fself-test"); /* Run all the tests, in hand-coded order of (approximate) dependencies: run the tests for lowest-level code first. */ @@ -106,14 +106,7 @@ selftest::run_tests () failed to be finalized can be detected by valgrind. */ forcibly_ggc_collect (); - /* Finished running tests. */ - long finish_time = get_run_time (); - long elapsed_time = finish_time - start_time; - - fprintf (stderr, - "-fself-test: %i pass(es) in %ld.%06ld seconds\n", - num_passes, - elapsed_time / 1000000, elapsed_time % 1000000); + /* Finished running tests; the test_runner dtor will print a summary. */ } #endif /* #if CHECKING_P */ diff --git a/gcc/selftest.c b/gcc/selftest.c index b41b9f5..ca84bfa 100644 --- a/gcc/selftest.c +++ b/gcc/selftest.c @@ -213,6 +213,28 @@ locate_file (const char *name) return concat (path_to_selftest_files, "/", name, NULL); } +/* selftest::test_runner's ctor. */ + +test_runner::test_runner (const char *name) +: m_name (name), + m_start_time (get_run_time ()) +{ +} + +/* selftest::test_runner's dtor. Print a summary line to stderr. */ + +test_runner::~test_runner () +{ + /* Finished running tests. */ + long finish_time = get_run_time (); + long elapsed_time = finish_time - m_start_time; + + fprintf (stderr, + "%s: %i pass(es) in %ld.%06ld seconds\n", + m_name, num_passes, + elapsed_time / 1000000, elapsed_time % 1000000); +} + /* Selftests for libiberty. */ /* Verify that xstrndup generates EXPECTED when called on SRC and N. */ diff --git a/gcc/selftest.h b/gcc/selftest.h index cdad939..f282055 100644 --- a/gcc/selftest.h +++ b/gcc/selftest.h @@ -168,6 +168,20 @@ extern char *locate_file (const char *path); extern const char *path_to_selftest_files; +/* selftest::test_runner is an implementation detail of selftest::run_tests, + exposed here to allow plugins to run their own suites of tests. */ + +class test_runner +{ + public: + test_runner (const char *name); + ~test_runner (); + + private: + const char *m_name; + long m_start_time; +}; + /* Declarations for specific families of tests (by source file), in alphabetical order. */ extern void bitmap_c_tests (); diff --git a/gcc/testsuite/gcc.dg/plugin/expensive-selftests-1.c b/gcc/testsuite/gcc.dg/plugin/expensive-selftests-1.c new file mode 100644 index 0000000..e464117 --- /dev/null +++ b/gcc/testsuite/gcc.dg/plugin/expensive-selftests-1.c @@ -0,0 +1,3 @@ +int not_empty; + +/* { dg-regexp "expensive_selftests_plugin: .* pass\\(es\\) in .* seconds" } */ diff --git a/gcc/testsuite/gcc.dg/plugin/expensive_selftests_plugin.c b/gcc/testsuite/gcc.dg/plugin/expensive_selftests_plugin.c new file mode 100644 index 0000000..9470764 --- /dev/null +++ b/gcc/testsuite/gcc.dg/plugin/expensive_selftests_plugin.c @@ -0,0 +1,175 @@ +/* Run expensive selftests. */ +/* { dg-options "-O" } */ + +#include "gcc-plugin.h" +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "diagnostic.h" +#include "edit-context.h" +#include "selftest.h" +#include "selftest-diagnostic.h" + +int plugin_is_GPL_compatible; + +#if CHECKING_P + +namespace selftest { + +/* Subroutine of test_fixit_on_very_long_line. + Verify that LOC has the EXPECTED_COLUMN, apart from the various + cases where it can't. */ + +static void +verify_column (location_t loc, + const line_map_ordinary *ord_map, + int line_width, + int expected_column) +{ + ASSERT_TRUE (/* Normal case. */ + LOCATION_COLUMN (loc) == expected_column + /* ord_map can't store columns e.g. due to + max_column_hint being too high. */ + || ord_map->m_column_and_range_bits == 0 + /* Running out of location_t values. */ + || loc > LINE_MAP_MAX_LOCATION_WITH_COLS + /* column exceeds LINE_MAP_MAX_COLUMN_NUMBER. */ + || expected_column > (int)LINE_MAP_MAX_COLUMN_NUMBER + /* column exceeds max_column_hint for ord_map. */ + || expected_column > line_width); +} + +/* Subroutine of test_fixit_on_very_long_line. + Run various things for RICHLOC, but don't check; we just want them + to survive. */ + +static void +test_richloc (rich_location *richloc) +{ + /* Run the diagnostic and fix-it printing code. */ + test_diagnostic_context dc; + diagnostic_show_locus (&dc, richloc, DK_ERROR); + + /* Generate a diff. */ + edit_context ec; + ec.add_fixits (richloc); + char *diff = ec.generate_diff (true); + free (diff); +} + +/* Verify that the fix-it-printing code can cope with very long lines + (PR c/82050). */ + +static void +test_fixit_on_very_long_line (const line_table_case &case_) +{ + /* Various interesting column/line-width values, to try to tickle + out bugs. */ + const int VERY_LONG_LINE = 8192; + const int columns[] = {0, + 1, + 80, + LINE_MAP_MAX_COLUMN_NUMBER - 2, + LINE_MAP_MAX_COLUMN_NUMBER - 1, + LINE_MAP_MAX_COLUMN_NUMBER, + LINE_MAP_MAX_COLUMN_NUMBER + 1, + LINE_MAP_MAX_COLUMN_NUMBER + 2, + VERY_LONG_LINE, + VERY_LONG_LINE + 5}; + for (unsigned int width_idx = 0; width_idx < ARRAY_SIZE (columns); + width_idx++) + { + int line_width = columns[width_idx]; + + /* Create a source file with a very long line. */ + named_temp_file tmp (".c"); + FILE *f = fopen (tmp.get_filename (), "w"); + for (int i = 0; i < line_width; i++) + fputc (' ', f); + fputc ('\n', f); + fclose (f); + + line_table_test ltt (case_); + const line_map_ordinary *ord_map = linemap_check_ordinary + (linemap_add (line_table, LC_ENTER, false, tmp.get_filename (), 0)); + linemap_line_start (line_table, 1, line_width); + + for (unsigned int start_idx = 0; start_idx < ARRAY_SIZE (columns); + start_idx++) + { + int start_col = columns[start_idx]; + location_t start_loc + = linemap_position_for_line_and_column (line_table, ord_map, 1, + start_col); + verify_column (start_loc, ord_map, line_width, start_col); + for (unsigned int finish_idx = 0; finish_idx < ARRAY_SIZE (columns); + finish_idx++) + { + int finish_col = columns[finish_idx]; + location_t finish_loc + = linemap_position_for_line_and_column (line_table, ord_map, 1, + finish_col); + verify_column (finish_loc, ord_map, line_width, finish_col); + + /* Now use start-finish to exercise the fix-it code. + In each case, run the printing code, but don't check; + we just want it to survive. */ + + /* Insertion. */ + { + rich_location richloc (line_table, start_loc); + richloc.add_fixit_insert_after (start_loc, "insertion"); + test_richloc (&richloc); + } + + /* Replacement. */ + { + rich_location richloc (line_table, start_loc); + source_range range + = source_range::from_locations (start_loc, finish_loc); + richloc.add_fixit_replace (range, "replacement"); + test_richloc (&richloc); + } + + /* Deletion. */ + { + rich_location richloc (line_table, start_loc); + source_range range + = source_range::from_locations (start_loc, finish_loc); + richloc.add_fixit_remove (range); + test_richloc (&richloc); + } + } + } + } +} + +/* Callback handler for the PLUGIN_FINISH event. + At this point, all GCC subsystems should be initialized and + "warmed up"; this is where we run our unit tests. */ + +static void +expensive_tests (void */*gcc_data*/, void */*user_data*/) +{ + test_runner r ("expensive_selftests_plugin"); + + for_each_line_table_case (test_fixit_on_very_long_line); +} + +} // namespace selftest + +#endif /* #if CHECKING_P */ + +int +plugin_init (struct plugin_name_args *plugin_info, + struct plugin_gcc_version *version) +{ +#if CHECKING_P + const char *plugin_name = plugin_info->base_name; + register_callback (plugin_info->base_name, + PLUGIN_FINISH, + selftest::expensive_tests, + NULL); /* void *user_data */ + return 0; +#endif /* #if CHECKING_P */ +} diff --git a/gcc/testsuite/gcc.dg/plugin/plugin.exp b/gcc/testsuite/gcc.dg/plugin/plugin.exp index c7a3b4d..ff3c976 100644 --- a/gcc/testsuite/gcc.dg/plugin/plugin.exp +++ b/gcc/testsuite/gcc.dg/plugin/plugin.exp @@ -82,6 +82,8 @@ set plugin_test_list [list \ { must_tail_call_plugin.c \ must-tail-call-1.c \ must-tail-call-2.c } \ + { expensive_selftests_plugin.c \ + expensive-selftests-1.c } \ ] foreach plugin_test $plugin_test_list {