Received: by 2002:a25:ef43:0:0:0:0:0 with SMTP id w3csp1048883ybm; Wed, 27 May 2020 14:53:56 -0700 (PDT) X-Google-Smtp-Source: ABdhPJx+WP1Y4lOea9qJQjEjAmGJGSl4HCCHMIQztHL/Tb7BOHS1ZrFlU4Re4HCD92ZuQvwMtxlC X-Received: by 2002:a17:906:eb44:: with SMTP id mc4mr353006ejb.234.1590616436639; Wed, 27 May 2020 14:53:56 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1590616436; cv=none; d=google.com; s=arc-20160816; b=F/crqAgnc3b9I2VIKzG/p5ZIWqJ9bl+DWvZ29TrSzX5v+SncTvNDHJT0aU9ixXK8f5 vHktCGzYzd1hT59S1TxYJDBeaRLfOOJYv3ZRb83MJRr4JTN5NN4KCIFUiO2B4k0qeCPP dataDceON9QJ5AwE75EVmZScKeeFN4OU7iOXm+PnpiPrH1GbVSyha5on9HINp3CeaBHn Ja7GXs4QNayH31cKPBgI0NzvEKZ4rpINLIZYlzaqqxhiuzWRjxZPEi5hJy5ffHWHn0lQ zgWkc7RZo2zeZDhupDKefmOVIfRbvyDQpt4shMlIjbuM7HKVrHe6QZTaFlxPWgcwb40v RJaQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:dkim-signature; bh=G+Ul9irVcaprbCeDWtOMnjYBauHXZ6a0rA9sdsV4kgo=; b=tP90Y5WEGG8NpdnfhAspkLaCbswEbO876ZXsyyj0W0VZUHNcOhA8VDMxRb0ZZmD/A1 +ugctEJDAzZKqHuImxujMMATgM1y9dJ1NpsH0MDKiginK8kzrN6j4zS51vbp6gx7qDEH 85Mb7PrkC42MLQWe+elYwloQ7tMiKSB054zxy7+EH8JbAUa6fDJHH5v8k/k5bl0OIds2 ImHcD9RwK9RYbH+lx2JLk+3ArK/MC4lt5iogoAIu+MXOQA9czMcT11JBe4oFQQ/8DGTA YirtK2vEoN3e16Z55ywPl7bdl9uAXzjwXnkbQvla8J2E6u5ezbvh2LW8HyCKandEgfsq QP6Q== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20161025 header.b=TeZqOPrO; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id h7si2351405edt.259.2020.05.27.14.53.32; Wed, 27 May 2020 14:53:56 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20161025 header.b=TeZqOPrO; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727102AbgE0TBF (ORCPT + 99 others); Wed, 27 May 2020 15:01:05 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58780 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725766AbgE0TBD (ORCPT ); Wed, 27 May 2020 15:01:03 -0400 Received: from mail-yb1-xb41.google.com (mail-yb1-xb41.google.com [IPv6:2607:f8b0:4864:20::b41]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 3775AC08C5C1 for ; Wed, 27 May 2020 12:01:03 -0700 (PDT) Received: by mail-yb1-xb41.google.com with SMTP id u73so9660762ybi.2 for ; Wed, 27 May 2020 12:01:03 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=mime-version:references:in-reply-to:from:date:message-id:subject:to :cc; bh=G+Ul9irVcaprbCeDWtOMnjYBauHXZ6a0rA9sdsV4kgo=; b=TeZqOPrOzMX1lDyB58T5ucfUwEGaVbGl3O1ONlabFRhX2fuWmQ8YeHui0TIcK8h5a3 BcrzjrpODT6xGqafH74+1uBAMBbwd7sjfGmaBe+zaQFbVmQhm3oQKRyTFCLcau4CkHjh oo21eSE9Qmh1P9OwjflrjJnF/9YtawtrIyVht7GgKhXbN7/BhWCoGyEQ/QUMVrYBcffj pexaJFH3w9rzA0VO1xLhlBmzJrNe7QsYhfNExhNrj/FqUB/L/f2SAL16/bU4J5JB4K0M /pcYFD3i0FhXu4oiJdFkyGEk+Jq9zLXaRq1/KRBdJwTk40WYtSWL83rJm1Zz07VD1x1A zUSA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:references:in-reply-to:from:date :message-id:subject:to:cc; bh=G+Ul9irVcaprbCeDWtOMnjYBauHXZ6a0rA9sdsV4kgo=; b=Q3fnmZQ6SrSPN7yop2tHOyJO7CfSMhpWFfRPRhpxNHfWwOybK3mjJUvs6mcp/nqOZr 5vuDIUZdk0VvTzaBLd/+sdW7HyZGgetoKgRJJb2wR0NhSokgj51gKA47wg09MkCbt3Fz OFdjvRkD4P7z0QP0RwP167vsYZLqYnBheZt7rC5p1eG5hcigoX084VeIriOR1gABk927 16lDoGtkrw8eOhkEBqCmnN1sVw4yTwkqo96kPjUtaCrp1SsaKBQI9PEY2n3A1toYunN3 NkW5WKthIXDrSo/zBs0MIu1OL380s133HlyDTTxULc3IENHUsWvlshEyawppBBsnBLyx I4ng== X-Gm-Message-State: AOAM532QyJY3ZrG5VJ/X8V73wNIHlANJ22UH4CtwxAf6xoP1YSpuKEY9 6HfxZ0B9ofkVU3Q4gS97fEs5NUhtCtCXi6HJ2STb2A== X-Received: by 2002:a25:dc14:: with SMTP id y20mr12048003ybe.383.1590606062115; Wed, 27 May 2020 12:01:02 -0700 (PDT) MIME-Version: 1.0 References: <1590544271-125795-1-git-send-email-steve.maclean@linux.microsoft.com> In-Reply-To: <1590544271-125795-1-git-send-email-steve.maclean@linux.microsoft.com> From: Ian Rogers Date: Wed, 27 May 2020 12:00:50 -0700 Message-ID: Subject: Re: [PATCH v4] perf inject --jit: Remove //anon mmap events To: Steve MacLean Cc: Steve MacLean , Peter Zijlstra , Ingo Molnar , Arnaldo Carvalho de Melo , Mark Rutland , Alexander Shishkin , Jiri Olsa , Namhyung Kim , Stephane Eranian , LKML Content-Type: text/plain; charset="UTF-8" Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On Tue, May 26, 2020 at 6:52 PM Steve MacLean wrote: > > From: Steve MacLean > > **perf-.map and jit-.dump designs: > > When a JIT generates code to be executed, it must allocate memory and > mark it executable using an mmap call. > > *** perf-.map design > > The perf-.map assumes that any sample recorded in an anonymous > memory page is JIT code. It then tries to resolve the symbol name by > looking at the process' perf-.map. > > *** jit-.dump design > > The jit-.dump mechanism takes a different approach. It requires a JIT > to write a `/jit-.dump` file. This file must also be mmapped > so that perf inject -jit can find the file. The JIT must also add > JIT_CODE_LOAD records for any functions it generates. The records are > timestamped using a clock which can be correlated to the perf record > clock. > > After perf record, the `perf inject -jit` pass parses the recording > looking for a `/jit-.dump` file. When it finds the file, it > parses it and for each JIT_CODE_LOAD record: > * creates an elf file `/jitted--.so > * injects a new mmap record mapping the new elf file into the process. > > *** Coexistence design > > The kernel and perf support both of these mechanisms. We need to make > sure perf works on an app supporting either or both of these mechanisms. > Both designs rely on mmap records to determine how to resolve an ip > address. > > The mmap records of both techniques by definition overlap. When the JIT > compiles a method, it must: > * allocate memory (mmap) > * add execution privilege (mprotect or mmap. either will > generate an mmap event form the kernel to perf) > * compile code into memory > * add a function record to perf-.map and/or jit-.dump > > Because the jit-.dump mechanism supports greater capabilities, perf > prefers the symbols from jit-.dump. It implements this based on > timestamp ordering of events. There is an implicit ASSUMPTION that the > JIT_CODE_LOAD record timestamp will be after the // anon mmap event that > was generated during memory allocation or adding the execution privilege setting. > > *** Problems with the ASSUMPTION > > The ASSUMPTION made in the Coexistence design section above is violated > in the following scenario. > > *** Scenario > > While a JIT is jitting code it will eventually need to commit more > pages and change these pages to executable permissions. Typically the > JIT will want these collocated to minimize branch displacements. > > The kernel will coalesce these anonymous mapping with identical > permissions before sending an MMAP event for the new pages. The address > range of the new mmap will not be just the most recently mmap pages. > It will include the entire coalesced mmap region. > > See mm/mmap.c > > unsigned long mmap_region(struct file *file, unsigned long addr, > unsigned long len, vm_flags_t vm_flags, unsigned long pgoff, > struct list_head *uf) > { > ... > /* > * Can we just expand an old mapping? > */ > ... > perf_event_mmap(vma); > ... > } > > *** Symptoms > > The coalesced // anon mmap event will be timestamped after the > JIT_CODE_LOAD records. This means it will be used as the most recent > mapping for that entire address range. For remaining events it will look at the > inferior perf-.map for symbols. > > If both mechanisms are supported, the symbol will appear twice with > different module names. This causes weird behavior in reporting. > > If only jit-.dump is supported, the symbol will no longer be resolved. > > ** Implemented solution > > This patch solves the issue by removing // anon mmap events for any > process which has a valid jit-.dump file. > > It tracks on a per process basis to handle the case where some running > apps support jit-.dump, but some only support perf-.map. > > It adds new assumptions: > * // anon mmap events are only required for perf-.map support. > * An app that uses jit-.dump, no longer needs > perf-.map support. It assumes that any perf-.map info is > inferior. Thanks Steve this is an important fix! As //anon could be for malloc or other uses, should the stripping behavior be behind a flag? Ian > *** Details > > Use thread->priv to store whether a jitdump file has been processed > > During "perf inject --jit", discard "//anon*" mmap events for any pid which > has sucessfully processed a jitdump file. > > ** Committer testing: > > // jitdump case > perf record > perf inject --jit --input perf.data --output perfjit.data > // verify mmap "//anon" events present initially > perf script --input perf.data --show-mmap-events | grep '//anon' > // verify mmap "//anon" events removed > perf script --input perfjit.data --show-mmap-events | grep '//anon' > // no jitdump case > perf record > perf inject --jit --input perf.data --output perfjit.data > // verify mmap "//anon" events present initially > perf script --input perf.data --show-mmap-events | grep '//anon' > // verify mmap "//anon" events not removed > perf script --input perfjit.data --show-mmap-events | grep '//anon' > > ** Repro: > > This issue was discovered while testing the initial CoreCLR jitdump > implementation. https://github.com/dotnet/coreclr/pull/26897. > > ** Alternate solutions considered > > These were also briefly considered > * Change kernel to not coalesce mmap regions. > * Change kernel reporting of coalesced mmap regions to perf. Only > include newly mapped memory. > * Only strip parts of // anon mmap events overlapping existing > jitted--.so mmap events. > > Cc: Peter Zijlstra > Cc: Ingo Molnar > Cc: Arnaldo Carvalho de Melo > Cc: Mark Rutland > Cc: Alexander Shishkin > Cc: Jiri Olsa > Cc: Namhyung Kim > Cc: Stephane Eranian > Cc: linux-kernel@vger.kernel.org > Signed-off-by: Steve MacLean > --- > tools/perf/builtin-inject.c | 4 ++-- > tools/perf/util/jitdump.c | 31 ++++++++++++++++++++++++++++++- > 2 files changed, 32 insertions(+), 3 deletions(-) > > diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c > index 372ecb3..0f38862 100644 > --- a/tools/perf/builtin-inject.c > +++ b/tools/perf/builtin-inject.c > @@ -263,7 +263,7 @@ static int perf_event__jit_repipe_mmap(struct perf_tool *tool, > * if jit marker, then inject jit mmaps and generate ELF images > */ > ret = jit_process(inject->session, &inject->output, machine, > - event->mmap.filename, sample->pid, &n); > + event->mmap.filename, event->mmap.pid, &n); > if (ret < 0) > return ret; > if (ret) { > @@ -301,7 +301,7 @@ static int perf_event__jit_repipe_mmap2(struct perf_tool *tool, > * if jit marker, then inject jit mmaps and generate ELF images > */ > ret = jit_process(inject->session, &inject->output, machine, > - event->mmap2.filename, sample->pid, &n); > + event->mmap2.filename, event->mmap2.pid, &n); > if (ret < 0) > return ret; > if (ret) { > diff --git a/tools/perf/util/jitdump.c b/tools/perf/util/jitdump.c > index e3ccb0c..d18596e 100644 > --- a/tools/perf/util/jitdump.c > +++ b/tools/perf/util/jitdump.c > @@ -26,6 +26,7 @@ > #include "jit.h" > #include "jitdump.h" > #include "genelf.h" > +#include "thread.h" > > #include > #include > @@ -749,6 +750,28 @@ static int jit_repipe_debug_info(struct jit_buf_desc *jd, union jr_entry *jr) > return 0; > } > > +static void jit_add_pid(struct machine *machine, pid_t pid) > +{ > + struct thread *thread = machine__findnew_thread(machine, pid, pid); > + > + if (!thread) { > + pr_err("%s: thread %d not found or created\n", __func__, pid); > + return; > + } > + > + thread->priv = (void *)1; > +} > + > +static bool jit_has_pid(struct machine *machine, pid_t pid) > +{ > + struct thread *thread = machine__find_thread(machine, pid, pid); > + > + if (!thread) > + return 0; > + > + return (bool)thread->priv; > +} > + > int > jit_process(struct perf_session *session, > struct perf_data *output, > @@ -764,8 +787,13 @@ static int jit_repipe_debug_info(struct jit_buf_desc *jd, union jr_entry *jr) > /* > * first, detect marker mmap (i.e., the jitdump mmap) > */ > - if (jit_detect(filename, pid)) > + if (jit_detect(filename, pid)) { > + // Strip //anon* mmaps if we processed a jitdump for this pid > + if (jit_has_pid(machine, pid) && (strncmp(filename, "//anon", 6) == 0)) > + return 1; > + > return 0; > + } > > memset(&jd, 0, sizeof(jd)); > > @@ -784,6 +812,7 @@ static int jit_repipe_debug_info(struct jit_buf_desc *jd, union jr_entry *jr) > > ret = jit_inject(&jd, filename); > if (!ret) { > + jit_add_pid(machine, pid); > *nbytes = jd.bytes_written; > ret = 1; > } > -- > 1.8.3.1 >