From patchwork Tue Oct 27 19:49:07 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Malcolm X-Patchwork-Id: 536825 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org 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 A7B0E14134E for ; Wed, 28 Oct 2015 06:49:01 +1100 (AEDT) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b=Q0qARU3s; dkim-atps=neutral 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:in-reply-to:references; q=dns; s= default; b=M29LiTD3tbHb761VpUOC9O271BYrQ/SEB73LMMlzlviEJy5tAcY80 s4+Tvo2PF32/DI/B4tLTjCtD9fbSDmD9uZwHLebnvyVjUMDDR7hKMSw2o1XWALDy oKdSsAh1aW49llO2ZXBruSDXNcA8I9hghzQZcMr5pBB0J8c4U9hswo= 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:in-reply-to:references; s= default; bh=eSOLB6VYV6c0JOH1DrmGCr+a1EY=; b=Q0qARU3s7v2FOwD+sgwU HDWjiXzRRo2Ao7gJqqDXrlz/ac327RrN7ySToMUAb5SQL59ZemrAfCDkIw4ZS2gY rjhPDRMRHbJ+NgPCv8MLEnCn7ffFoxThCU9sARC2teCmXLRL56ZS8V/ZoWtjCq3T UP36snZpoWDxYQorsjfBQJ4= Received: (qmail 69644 invoked by alias); 27 Oct 2015 19:48:53 -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 69629 invoked by uid 89); 27 Oct 2015 19:48:52 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.8 required=5.0 tests=AWL, BAYES_00 autolearn=ham version=3.3.2 X-HELO: eggs.gnu.org Received: from eggs.gnu.org (HELO eggs.gnu.org) (208.118.235.92) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES256-SHA encrypted) ESMTPS; Tue, 27 Oct 2015 19:48:50 +0000 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Zr9y8-0002rN-SX for gcc-patches@gcc.gnu.org; Tue, 27 Oct 2015 15:31:43 -0400 Received: from mx1.redhat.com ([209.132.183.28]:42529) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Zr9y8-0002qz-JS for gcc-patches@gcc.gnu.org; Tue, 27 Oct 2015 15:31:40 -0400 Received: from int-mx13.intmail.prod.int.phx2.redhat.com (int-mx13.intmail.prod.int.phx2.redhat.com [10.5.11.26]) by mx1.redhat.com (Postfix) with ESMTPS id 56DB9C0B5923 for ; Tue, 27 Oct 2015 19:31:40 +0000 (UTC) Received: from c64.redhat.com (vpn-230-173.phx2.redhat.com [10.3.230.173]) by int-mx13.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id t9RJVW5i018778; Tue, 27 Oct 2015 15:31:39 -0400 From: David Malcolm To: gcc-patches@gcc.gnu.org Cc: David Malcolm Subject: [PATCH 08/16] Add test-ggc.c to unittests Date: Tue, 27 Oct 2015 15:49:07 -0400 Message-Id: <1445975355-37660-9-git-send-email-dmalcolm@redhat.com> In-Reply-To: <1445975355-37660-1-git-send-email-dmalcolm@redhat.com> References: <5589B2FB.8010500@redhat.com> <1445975355-37660-1-git-send-email-dmalcolm@redhat.com> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x X-Received-From: 209.132.183.28 X-IsSubscribed: yes gcc/testsuite/ChangeLog: * unittests/test-ggc.c: New file. --- gcc/testsuite/unittests/test-ggc.c | 299 +++++++++++++++++++++++++++++++++++++ 1 file changed, 299 insertions(+) create mode 100644 gcc/testsuite/unittests/test-ggc.c diff --git a/gcc/testsuite/unittests/test-ggc.c b/gcc/testsuite/unittests/test-ggc.c new file mode 100644 index 0000000..7a16977 --- /dev/null +++ b/gcc/testsuite/unittests/test-ggc.c @@ -0,0 +1,299 @@ +/* Unit tests for GCC's garbage collector (and gengtype etc). + Copyright (C) 2015 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#include "config.h" +#include "gtest/gtest.h" +#include "system.h" +#include "coretypes.h" +#include "opts.h" +#include "signop.h" +#include "hash-set.h" +#include "fixed-value.h" +#include "alias.h" +#include "symtab.h" +#include "tree-core.h" +#include "stor-layout.h" +#include "tree.h" +#include "stringpool.h" +#include "stor-layout.h" +#include "predict.h" +#include "vec.h" +#include "hashtab.h" +#include "hash-set.h" +#include "machmode.h" +#include "ggc-internal.h" /* (for ggc_force_collect). */ + +/* The various GTY markers must be outside of a namespace to be seen by + gengtype, so we don't put this file within an anonymous namespace. */ + +/* A test fixture for writing ggc tests. */ +class ggc_test : public ::testing::Test +{ + protected: + void + forcibly_ggc_collect () + { + ggc_force_collect = true; + ggc_collect (); + ggc_force_collect = false; + } +}; + +/* Smoketest to ensure that a GC root is marked ("tree" type). */ + +static GTY(()) tree dummy_unittesting_tree; + +TEST_F (ggc_test, tree_marking) +{ + dummy_unittesting_tree = build_int_cst (integer_type_node, 1066); + + forcibly_ggc_collect (); + + EXPECT_TRUE (ggc_marked_p (dummy_unittesting_tree)); +} + +/* Verify that a simple custom struct works, and that it can + own references to non-roots, and have them be marked. */ + +struct GTY(()) test_struct +{ + test_struct *other; +}; + +static GTY(()) test_struct *root_test_struct; + +TEST_F (ggc_test, custom_struct) +{ + root_test_struct = ggc_cleared_alloc (); + root_test_struct->other = ggc_cleared_alloc (); + + forcibly_ggc_collect (); + + EXPECT_TRUE (ggc_marked_p (root_test_struct)); + EXPECT_TRUE (ggc_marked_p (root_test_struct->other)); +} + +/* Verify that destructors get run when instances are collected. */ + +struct GTY(()) test_struct_with_dtor +{ + /* This struct has a destructor; it *ought* to be called + by the ggc machinery when instances are collected. */ + ~test_struct_with_dtor () { dtor_call_count++; } + + static int dtor_call_count; +}; + +int test_struct_with_dtor::dtor_call_count; + +TEST_F (ggc_test, finalization) +{ + EXPECT_FALSE (need_finalization_p ()); + EXPECT_TRUE (need_finalization_p ()); + + /* Create some garbage. */ + const int count = 10; + for (int i = 0; i < count; i++) + ggc_cleared_alloc (); + + test_struct_with_dtor::dtor_call_count = 0; + + forcibly_ggc_collect (); + + /* Verify that the destructor was run for each instance. */ + EXPECT_EQ (count, test_struct_with_dtor::dtor_call_count); +} + +/* Verify that a global can be marked as "deletable". */ + +static GTY((deletable)) test_struct *test_of_deletable; + +/* FIXME: we can't do this test via a plugin as it stands. + The list of deletable roots is fixed by the main gengtype + run; there isn't yet a way to add extra + deletable roots (PLUGIN_REGISTER_GGC_ROOTS is for regular + roots). */ +#if 0 +TEST_F (ggc_test, deletable_global) +{ + test_of_deletable = ggc_cleared_alloc (); + EXPECT_TRUE (test_of_deletable != NULL); + + forcibly_ggc_collect (); + + EXPECT_EQ (NULL, test_of_deletable); +} +#endif + +/* Verify that gengtype etc can cope with inheritance. */ + +class GTY((desc("%h.m_kind"), tag("0"))) example_base +{ + public: + example_base () + : m_kind (0), + m_a (ggc_cleared_alloc ()) + {} + + void * + operator new (size_t sz) + { + return ggc_internal_cleared_alloc (sz); + } + + protected: + example_base (int kind) + : m_kind (kind), + m_a (ggc_cleared_alloc ()) + {} + + public: + int m_kind; + test_struct *m_a; +}; + +class GTY((tag("1"))) some_subclass : public example_base +{ + public: + some_subclass () + : example_base (1), + m_b (ggc_cleared_alloc ()) + {} + + test_struct *m_b; +}; + +class GTY((tag("2"))) some_other_subclass : public example_base +{ + public: + some_other_subclass () + : example_base (2), + m_c (ggc_cleared_alloc ()) + {} + + test_struct *m_c; +}; + +/* Various test roots, both expressed as a ptr to the actual class, and + as a ptr to the base class. */ +static GTY(()) example_base *test_example_base; +static GTY(()) some_subclass *test_some_subclass; +static GTY(()) some_other_subclass *test_some_other_subclass; +static GTY(()) example_base *test_some_subclass_as_base_ptr; +static GTY(()) example_base *test_some_other_subclass_as_base_ptr; + +TEST_F (ggc_test, inheritance) +{ + test_example_base = new example_base (); + test_some_subclass = new some_subclass (); + test_some_other_subclass = new some_other_subclass (); + test_some_subclass_as_base_ptr = new some_subclass (); + test_some_other_subclass_as_base_ptr = new some_other_subclass (); + + forcibly_ggc_collect (); + + /* Verify that the roots and everything referenced by them got marked + (both for fields in the base class and those in subclasses). */ + EXPECT_TRUE (ggc_marked_p (test_example_base)); + EXPECT_TRUE (ggc_marked_p (test_example_base->m_a)); + + EXPECT_TRUE (ggc_marked_p (test_some_subclass)); + EXPECT_TRUE (ggc_marked_p (test_some_subclass->m_a)); + EXPECT_TRUE (ggc_marked_p (test_some_subclass->m_b)); + + EXPECT_TRUE (ggc_marked_p (test_some_other_subclass)); + EXPECT_TRUE (ggc_marked_p (test_some_other_subclass->m_a)); + EXPECT_TRUE (ggc_marked_p (test_some_other_subclass->m_c)); + + EXPECT_TRUE (ggc_marked_p (test_some_subclass_as_base_ptr)); + EXPECT_TRUE (ggc_marked_p (test_some_subclass_as_base_ptr->m_a)); + EXPECT_TRUE (ggc_marked_p (((some_subclass *) + test_some_subclass_as_base_ptr)->m_b)); + + EXPECT_TRUE (ggc_marked_p (test_some_other_subclass_as_base_ptr)); + EXPECT_TRUE (ggc_marked_p (test_some_other_subclass_as_base_ptr->m_a)); + EXPECT_TRUE (ggc_marked_p (((some_other_subclass *) + test_some_other_subclass_as_base_ptr)->m_c)); +} + +/* Test of chain_next/chain_prev + + Construct a very long linked list, so that without + the chain_next/chain_prev optimization we'd have + a stack overflow when gt_ggc_mx_test_node recurses. */ + +struct GTY(( chain_next ("%h.m_next"), + chain_prev ("%h.m_prev") )) test_node +{ + test_node *m_prev; + test_node *m_next; + int m_idx; +}; + +static GTY(()) test_node *root_test_node; + +TEST_F (ggc_test, chain_next) +{ + /* 2 million nodes (and thus the same number of stack frames) ought + to be deep enough to crash if gengtype has created something + that recurses. + + This length reliably causes the test to segfault without the + chain_next/prev optimization on this box (Fedora 20 x86_64 with 128GB + of RAM), but causes this test to take about 0.5s, dominating the time + taken by the overall testsuite. + + We could perhaps lower this by not increasing the stack size so much + in toplev.c, or perhaps reducing the stack size when running this + testcase. */ + const int count = 2000000; + + /* Build the linked list. */ + root_test_node = ggc_cleared_alloc (); + test_node *tail_node = root_test_node; + for (int i = 0; i < count; i++) + { + test_node *new_node = ggc_cleared_alloc (); + tail_node->m_next = new_node; + new_node->m_prev = tail_node; + new_node->m_idx = i; + tail_node = new_node; + } + + forcibly_ggc_collect (); + + /* If we got here, we survived. */ + + /* Verify that all nodes in the list were marked. */ + EXPECT_TRUE (ggc_marked_p (root_test_node)); + test_node *iter_node = root_test_node->m_next; + for (int i = 0; i < count; i++) + { + EXPECT_TRUE (ggc_marked_p (iter_node)); + EXPECT_EQ (i, iter_node->m_idx); + iter_node = iter_node->m_next; + } +} + +/* Ideas for other tests: + - pch-handling */ + +/* Generated by unittests-plugin.c's use of the + "dg-plugin-run-gengtype" directive. */ +#include "gt-unittests-test-ggc.h"