From patchwork Mon Aug 8 17:03:31 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Martin_Li=C5=A1ka?= X-Patchwork-Id: 656890 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 3s7Nzg0vPjz9ryZ for ; Tue, 9 Aug 2016 03:03:58 +1000 (AEST) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b=rQeGoybT; 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 :subject:to:references:cc:from:message-id:date:mime-version :in-reply-to:content-type; q=dns; s=default; b=lYV3J506ungJ9Q0+b 393GqB+41LnLtWhCPJEsO+OQ4SWBqNZcI6fCIjWJZx5M3VR72V5/MP5ZhFIsItwD LPA1AacJFON/FCuA+QEB1OkMv4RxyWwWXrjbiAIwSJ5sdUCqFIqVEPoPlT11RKDX gSWgDT9FggBXDe1PwCC66tSHWY= 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 :subject:to:references:cc:from:message-id:date:mime-version :in-reply-to:content-type; s=default; bh=YYInebgNYfehMicHFunjcow 2OxM=; b=rQeGoybT8jUnqtjxIIAMKmCnqVODIuF3Xgu5w4cdHNUcQQUI7YA16lN GiItaNCjN3O6n7Fp5tZs6sUc+mJg6lYlwm6y+FYebW8hsuCU0TX2MvqkLO96snEP 9HoB0Zo+4XOSyr/rwUdAhp0dUvpYgt169CWUegJd4vn9nYrTLzI8= Received: (qmail 124537 invoked by alias); 8 Aug 2016 17:03:51 -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 124527 invoked by uid 89); 8 Aug 2016 17:03:51 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.9 required=5.0 tests=BAYES_00, SPF_PASS autolearn=ham version=3.3.2 spammy=visit X-HELO: mx2.suse.de Received: from mx2.suse.de (HELO mx2.suse.de) (195.135.220.15) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (CAMELLIA256-SHA encrypted) ESMTPS; Mon, 08 Aug 2016 17:03:40 +0000 Received: from relay1.suse.de (charybdis-ext.suse.de [195.135.220.254]) by mx2.suse.de (Postfix) with ESMTP id E15F1AC55; Mon, 8 Aug 2016 17:03:36 +0000 (UTC) Subject: Re: [PATCH 5/N] Add new *_atomic counter update function, (-fprofile-update=atomic) To: Nathan Sidwell , gcc-patches@gcc.gnu.org References: <53c4f874443d63de99393a9816041ba75f1d605e.1470041316.git.mliska@suse.cz> <95628fa2-8719-bb82-d1ab-ca8d46355020@acm.org> <0ec1ad3f-0fc7-507e-878c-907adae1c011@suse.cz> <0e248978-3717-1d78-b3b1-9fc60ded5c8e@suse.cz> <882f0f98-9b33-a764-833b-ca61796f3143@acm.org> <87f2bc4f-c4df-eadd-aec6-a937ed0ccaba@acm.org> <1253ac69-3301-f185-e43a-a34cadf8f51e@suse.cz> <67fda6d2-9b3e-a0d1-effc-34e1115030b2@acm.org> <1ff3cc75-7cee-79f3-395b-ef7a4d286a3d@acm.org> <04a05835-4666-4d7d-c1a9-d4bcc4ea924a@suse.cz> <2a6eb389-5504-1cea-851f-78d0dcb34776@suse.cz> <05a42409-f924-878d-3558-abe6a2c84425@acm.org> <3da55a5e-673b-1fed-7b4f-f68e44ddaf40@suse.cz> Cc: jh@suse.cz From: =?UTF-8?Q?Martin_Li=c5=a1ka?= Message-ID: <3685d4c7-3227-f981-2d7f-d6475956ad9c@suse.cz> Date: Mon, 8 Aug 2016 19:03:31 +0200 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Thunderbird/45.2 MIME-Version: 1.0 In-Reply-To: <3da55a5e-673b-1fed-7b4f-f68e44ddaf40@suse.cz> X-IsSubscribed: yes On 08/08/2016 06:50 PM, Martin Liška wrote: > On 08/08/2016 05:24 PM, Nathan Sidwell wrote: >> On 08/08/16 09:59, Martin Liška wrote: >>> Hello. >>> >>> This patch is follow-up of the series where I introduce a set of counter update >>> function that are thread-safe. I originally thought that majority of profile corruptions are >>> caused by non-atomic updated of CFG (-fprofile-arc). But there are multiple counters that compare >>> it's count to a number of execution of a basic block: >>> >>> blake2s.cpp:150:40: error: corrupted value profile: value profile counter (11301120 out of 11314388) inconsistent with basic-block count (11555117) >>> memcpy( S->buf + left, in, fill ); // Fill buffer >>> >>> This can be seen for unrar binary: PR58306. I'm also adding a simple test-case which reveals the inconsistency: val-profiler-threads-1.c. >>> >>> I've been running regression tests, ready to install after it finishes? >> >> >> + fn_name = concat ("__gcov_interval_profiler", fn_suffix, NULL); >> + tree_interval_profiler_fn = build_fn_decl (fn_name, >> + interval_profiler_fn_type); >> >> I like this idiom, but doesn't 'concat' call for a following 'free'? > > Fixed in the second version of patch. > > >> >> +__gcov_pow2_profiler_atomic (gcov_type *counters, gcov_type value) >> +{ >> + if (value & (value - 1)) >> + __atomic_fetch_add (&counters[0], 1, MEMMODEL_RELAXED); >> >> This seems to think '0' is a power of 2. (I suspect a bug in the existing code, not something you've introduced) > > I'll send separate email for that issue. > >> >> -__gcov_one_value_profiler_body (gcov_type *counters, gcov_type value) >> +__gcov_one_value_profiler_body (gcov_type *counters, gcov_type value, >> + int use_atomic) >> { >> if (value == counters[0]) >> >> This function should be commented along the lines of the email discussion we had last week. the 'atomic' param doesn't make it completely thread safe. > > Done, with a link to this mailing list thread. > >> >> /* Counter for first visit of each function. */ >> -static gcov_type function_counter; >> +gcov_type function_counter; >> >> why is this no longer static? If it must be globally visible, it'll need a suitable rename. (perhaps it's simpler to put the 2(?) fns that access it into a single object file?) > > Yeah, I'm putting these 2 functions to the same object. > > Martin > >> >> nathan > v3: fixed wrong defines in libgcc/Makefine.in Martin From 7f442afa98e037ee9839fad1ced8a0055842b4e6 Mon Sep 17 00:00:00 2001 From: marxin Date: Mon, 8 Aug 2016 15:44:28 +0200 Subject: [PATCH 5/5] Add new *_atomic counter update function (-fprofile-update=atomic) libgcc/ChangeLog: 2016-08-08 Martin Liska PR gcov-profile/58306 * Makefile.in: New functions (modules) are added. * libgcov-profiler.c (__gcov_interval_profiler_atomic): New function. (__gcov_pow2_profiler_atomic): New function. (__gcov_one_value_profiler_body): New argument is instroduced. (__gcov_one_value_profiler): Call with the new argument. (__gcov_one_value_profiler_atomic): Likewise. (__gcov_indirect_call_profiler_v2): Likewise. (__gcov_time_profiler_atomic): New function. (__gcov_average_profiler_atomic): Likewise. (__gcov_ior_profiler_atomic): Likewise. * libgcov.h: Declare the aforementioned functions. gcc/testsuite/ChangeLog: 2016-08-08 Martin Liska PR gcov-profile/58306 * gcc.dg/tree-prof/val-profiler-threads-1.c: New test. gcc/ChangeLog: 2016-08-08 Martin Liska PR gcov-profile/58306 * tree-profile.c (gimple_init_edge_profiler): Create conditionally atomic variants of profile update functions. --- .../gcc.dg/tree-prof/val-profiler-threads-1.c | 41 ++++++++ gcc/tree-profile.c | 42 +++++---- libgcc/Makefile.in | 15 ++- libgcc/libgcov-profiler.c | 103 ++++++++++++++++++++- libgcc/libgcov.h | 7 ++ 5 files changed, 182 insertions(+), 26 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/tree-prof/val-profiler-threads-1.c diff --git a/gcc/testsuite/gcc.dg/tree-prof/val-profiler-threads-1.c b/gcc/testsuite/gcc.dg/tree-prof/val-profiler-threads-1.c new file mode 100644 index 0000000..0f7477e --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-prof/val-profiler-threads-1.c @@ -0,0 +1,41 @@ +/* { dg-options "-O0 -pthread -fprofile-update=atomic" } */ +#include + +#define NUM_THREADS 8 +#define SIZE 1024 +#define ITERATIONS (1000 * 1000) + +char buffer[SIZE]; +char buffer2[SIZE]; + +void *copy_memory(char *dst, char *src, unsigned size) +{ + for (unsigned i = 0; i < ITERATIONS; i++) + { + dst[size % 10] = src[size % 20]; + } +} + +void *foo(void *d) +{ + copy_memory (buffer, buffer2, SIZE); +} + +int main(int argc, char *argv[]) +{ + pthread_t threads[NUM_THREADS]; + int rc; + long t; + for(t=0;t, then increases the + corresponding counter in COUNTERS. If the VALUE is above or below + the interval, COUNTERS[STEPS] or COUNTERS[STEPS + 1] is increased + instead. Function is thread-safe. */ + +void +__gcov_interval_profiler_atomic (gcov_type *counters, gcov_type value, + int start, unsigned steps) +{ + gcov_type delta = value - start; + if (delta < 0) + __atomic_fetch_add (&counters[steps + 1], 1, MEMMODEL_RELAXED); + else if (delta >= steps) + __atomic_fetch_add (&counters[steps], 1, MEMMODEL_RELAXED); + else + __atomic_fetch_add (&counters[delta], 1, MEMMODEL_RELAXED); +} +#endif + #ifdef L_gcov_pow2_profiler /* If VALUE is a power of two, COUNTERS[1] is incremented. Otherwise COUNTERS[0] is incremented. */ @@ -60,6 +80,21 @@ __gcov_pow2_profiler (gcov_type *counters, gcov_type value) } #endif +#ifdef L_gcov_pow2_profiler_atomic +/* If VALUE is a power of two, COUNTERS[1] is incremented. Otherwise + COUNTERS[0] is incremented. Function is thread-safe. */ + +void +__gcov_pow2_profiler_atomic (gcov_type *counters, gcov_type value) +{ + if (value == 0 || (value & (value - 1))) + __atomic_fetch_add (&counters[0], 1, MEMMODEL_RELAXED); + else + __atomic_fetch_add (&counters[1], 1, MEMMODEL_RELAXED); +} +#endif + + /* Tries to determine the most common value among its inputs. Checks if the value stored in COUNTERS[0] matches VALUE. If this is the case, COUNTERS[1] is incremented. If this is not the case and COUNTERS[1] is not zero, @@ -68,10 +103,12 @@ __gcov_pow2_profiler (gcov_type *counters, gcov_type value) function is called more than 50% of the time with one value, this value will be in COUNTERS[0] in the end. - In any case, COUNTERS[2] is incremented. */ + In any case, COUNTERS[2] is incremented. If USE_ATOMIC is set to 1, + COUNTERS[2] is updated with an atomic instruction. */ static inline void -__gcov_one_value_profiler_body (gcov_type *counters, gcov_type value) +__gcov_one_value_profiler_body (gcov_type *counters, gcov_type value, + int use_atomic) { if (value == counters[0]) counters[1]++; @@ -82,14 +119,36 @@ __gcov_one_value_profiler_body (gcov_type *counters, gcov_type value) } else counters[1]--; - counters[2]++; + + if (use_atomic) + __atomic_fetch_add (&counters[2], 1, MEMMODEL_RELAXED); + else + counters[2]++; } #ifdef L_gcov_one_value_profiler void __gcov_one_value_profiler (gcov_type *counters, gcov_type value) { - __gcov_one_value_profiler_body (counters, value); + __gcov_one_value_profiler_body (counters, value, 0); +} +#endif + +#ifdef L_gcov_one_value_profiler_atomic + +/* Update one value profilers (COUNTERS) for a given VALUE. + + CAVEAT: Following function is not thread-safe, only total number + of executions (COUNTERS[2]) is update with an atomic instruction. + Problem is that one cannot atomically update two counters + (COUNTERS[0] and COUNTERS[1]), for more information please read + following email thread: + https://gcc.gnu.org/ml/gcc-patches/2016-08/msg00024.html. */ + +void +__gcov_one_value_profiler_atomic (gcov_type *counters, gcov_type value) +{ + __gcov_one_value_profiler_body (counters, value, 1); } #endif @@ -265,7 +324,7 @@ __gcov_indirect_call_profiler_v2 (gcov_type value, void* cur_func) if (cur_func == __gcov_indirect_call_callee || (__LIBGCC_VTABLE_USES_DESCRIPTORS__ && __gcov_indirect_call_callee && *(void **) cur_func == *(void **) __gcov_indirect_call_callee)) - __gcov_one_value_profiler_body (__gcov_indirect_call_counters, value); + __gcov_one_value_profiler_body (__gcov_indirect_call_counters, value, 0); } #endif @@ -282,8 +341,19 @@ __gcov_time_profiler (gcov_type* counters) if (!counters[0]) counters[0] = ++function_counter; } + +/* Sets corresponding COUNTERS if there is no value. + Function is thread-safe. */ + +void +__gcov_time_profiler_atomic (gcov_type* counters) +{ + if (!counters[0]) + counters[0] = __atomic_add_fetch (&function_counter, 1, MEMMODEL_RELAXED); +} #endif + #ifdef L_gcov_average_profiler /* Increase corresponding COUNTER by VALUE. FIXME: Perhaps we want to saturate up. */ @@ -296,6 +366,18 @@ __gcov_average_profiler (gcov_type *counters, gcov_type value) } #endif +#ifdef L_gcov_average_profiler_atomic +/* Increase corresponding COUNTER by VALUE. FIXME: Perhaps we want + to saturate up. Function is thread-safe. */ + +void +__gcov_average_profiler_atomic (gcov_type *counters, gcov_type value) +{ + __atomic_fetch_add (&counters[0], value, MEMMODEL_RELAXED); + __atomic_fetch_add (&counters[1], 1, MEMMODEL_RELAXED); +} +#endif + #ifdef L_gcov_ior_profiler /* Bitwise-OR VALUE into COUNTER. */ @@ -306,4 +388,15 @@ __gcov_ior_profiler (gcov_type *counters, gcov_type value) } #endif +#ifdef L_gcov_ior_profiler_atomic +/* Bitwise-OR VALUE into COUNTER. Function is thread-safe. */ + +void +__gcov_ior_profiler_atomic (gcov_type *counters, gcov_type value) +{ + __atomic_fetch_or (&counters[0], value, MEMMODEL_RELAXED); +} +#endif + + #endif /* inhibit_libc */ diff --git a/libgcc/libgcov.h b/libgcc/libgcov.h index 80f13e2..25147de 100644 --- a/libgcc/libgcov.h +++ b/libgcc/libgcov.h @@ -268,12 +268,19 @@ extern void __gcov_merge_icall_topn (gcov_type *, unsigned) ATTRIBUTE_HIDDEN; /* The profiler functions. */ extern void __gcov_interval_profiler (gcov_type *, gcov_type, int, unsigned); +extern void __gcov_interval_profiler_atomic (gcov_type *, gcov_type, int, + unsigned); extern void __gcov_pow2_profiler (gcov_type *, gcov_type); +extern void __gcov_pow2_profiler_atomic (gcov_type *, gcov_type); extern void __gcov_one_value_profiler (gcov_type *, gcov_type); +extern void __gcov_one_value_profiler_atomic (gcov_type *, gcov_type); extern void __gcov_indirect_call_profiler_v2 (gcov_type, void *); extern void __gcov_time_profiler (gcov_type *); +extern void __gcov_time_profiler_atomic (gcov_type *); extern void __gcov_average_profiler (gcov_type *, gcov_type); +extern void __gcov_average_profiler_atomic (gcov_type *, gcov_type); extern void __gcov_ior_profiler (gcov_type *, gcov_type); +extern void __gcov_ior_profiler_atomic (gcov_type *, gcov_type); extern void __gcov_indirect_call_topn_profiler (gcov_type, void *); extern void gcov_sort_n_vals (gcov_type *, int); -- 2.9.2