From patchwork Wed May 24 13:19:55 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: James Clark X-Patchwork-Id: 13253986 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 24B89C77B7A for ; Wed, 24 May 2023 13:20:55 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:Cc:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=uRzMdAmt+ZkcpHN4QvSX93TdwFSaTlrnhAeuS3yr84c=; b=BrkVWqAiGLRWW9 J7KrWBFJm4SsMja4d+DKWvOGcXumFn5sjplkXo2GgpYbSx/n8iO+Vx2eblBrKRMZfEzQNZm31WKpo SULLRfbB6704ri1I4u9a1svaQVNnNKkXs1NAJ9Gha/rdys5+sCNgZrqJhJZoiLiExsGphyegga8XU SpvCJCiAGb6TXx8JS8CCNYmVmgcngmlAf722xqrtylIfH3o/fAm4H8FsLWruCDhfuObBdKjUtjycD 0fvVIKg0krGTKGEj5uZnrS20vrYPrutlKi2KqEXccri63bwZYSO29SgJJqHUIJDGuYU4YRY1gmW3k 8SA+VrLgNFl0gb0rdr6Q==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.96 #2 (Red Hat Linux)) id 1q1oPm-00DYPw-04; Wed, 24 May 2023 13:20:30 +0000 Received: from foss.arm.com ([217.140.110.172]) by bombadil.infradead.org with esmtp (Exim 4.96 #2 (Red Hat Linux)) id 1q1oPa-00DYLX-2b for linux-arm-kernel@lists.infradead.org; Wed, 24 May 2023 13:20:22 +0000 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 327D4113E; Wed, 24 May 2023 06:21:00 -0700 (PDT) Received: from localhost.localdomain (unknown [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 886593F840; Wed, 24 May 2023 06:20:12 -0700 (PDT) From: James Clark To: coresight@lists.linaro.org, denik@chromium.org Cc: James Clark , Suzuki K Poulose , Mike Leach , Leo Yan , Peter Zijlstra , Ingo Molnar , Arnaldo Carvalho de Melo , Mark Rutland , Alexander Shishkin , Jiri Olsa , Namhyung Kim , Ian Rogers , Adrian Hunter , John Garry , Will Deacon , linux-arm-kernel@lists.infradead.org, linux-perf-users@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH 1/4] perf cs-etm: Only track threads instead of PID and TIDs Date: Wed, 24 May 2023 14:19:55 +0100 Message-Id: <20230524131958.2139331-2-james.clark@arm.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230524131958.2139331-1-james.clark@arm.com> References: <20230524131958.2139331-1-james.clark@arm.com> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20230524_062018_945410_B4EC5DC9 X-CRM114-Status: GOOD ( 27.03 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org PIDs and TIDs are already contained within the thread struct, so to avoid inconsistencies drop the extra members on the etm queue and only use the thread struct. At the same time stop using the 'unknown' thread. In a later commit we will be making samples from multiple machines so it will be better to use the idle thread of each machine rather than overlapping unknown threads. Using the idle thread is also better because kernel addresses with a previously unknown thread will now be assigned to a real kernel thread. Signed-off-by: James Clark Reviewed-by: Mike Leach Reviewed-by: Leo Yan Acked-by: Suzuki K Poulose --- tools/perf/util/cs-etm.c | 124 ++++++++++++--------------------------- 1 file changed, 38 insertions(+), 86 deletions(-) diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c index 91299cc56bf7..ebffc9052561 100644 --- a/tools/perf/util/cs-etm.c +++ b/tools/perf/util/cs-etm.c @@ -46,8 +46,6 @@ struct cs_etm_auxtrace { struct auxtrace_heap heap; struct itrace_synth_opts synth_opts; struct perf_session *session; - struct machine *machine; - struct thread *unknown_thread; struct perf_tsc_conversion tc; /* @@ -84,7 +82,6 @@ struct cs_etm_auxtrace { struct cs_etm_traceid_queue { u8 trace_chan_id; - pid_t pid, tid; u64 period_instructions; size_t last_branch_pos; union perf_event *event_buf; @@ -480,9 +477,9 @@ static int cs_etm__init_traceid_queue(struct cs_etm_queue *etmq, cs_etm__clear_packet_queue(&tidq->packet_queue); queue = &etmq->etm->queues.queue_array[etmq->queue_nr]; - tidq->tid = queue->tid; - tidq->pid = -1; tidq->trace_chan_id = trace_chan_id; + tidq->thread = machine__findnew_thread(&etm->session->machines.host, -1, + queue->tid); tidq->packet = zalloc(sizeof(struct cs_etm_packet)); if (!tidq->packet) @@ -863,7 +860,6 @@ static void cs_etm__free(struct perf_session *session) for (i = 0; i < aux->num_cpu; i++) zfree(&aux->metadata[i]); - thread__zput(aux->unknown_thread); zfree(&aux->metadata); zfree(&aux); } @@ -882,7 +878,7 @@ static u8 cs_etm__cpu_mode(struct cs_etm_queue *etmq, u64 address) { struct machine *machine; - machine = etmq->etm->machine; + machine = &etmq->etm->session->machines.host; if (address >= machine__kernel_start(machine)) { if (machine__is_host(machine)) @@ -905,8 +901,6 @@ static u32 cs_etm__mem_access(struct cs_etm_queue *etmq, u8 trace_chan_id, u8 cpumode; u64 offset; int len; - struct thread *thread; - struct machine *machine; struct addr_location al; struct dso *dso; struct cs_etm_traceid_queue *tidq; @@ -914,20 +908,12 @@ static u32 cs_etm__mem_access(struct cs_etm_queue *etmq, u8 trace_chan_id, if (!etmq) return 0; - machine = etmq->etm->machine; cpumode = cs_etm__cpu_mode(etmq, address); tidq = cs_etm__etmq_get_traceid_queue(etmq, trace_chan_id); if (!tidq) return 0; - thread = tidq->thread; - if (!thread) { - if (cpumode != PERF_RECORD_MISC_KERNEL) - return 0; - thread = etmq->etm->unknown_thread; - } - - if (!thread__find_map(thread, cpumode, address, &al)) + if (!thread__find_map(tidq->thread, cpumode, address, &al)) return 0; dso = map__dso(al.map); @@ -942,7 +928,8 @@ static u32 cs_etm__mem_access(struct cs_etm_queue *etmq, u8 trace_chan_id, map__load(al.map); - len = dso__data_read_offset(dso, machine, offset, buffer, size); + len = dso__data_read_offset(dso, maps__machine(tidq->thread->maps), + offset, buffer, size); if (len <= 0) { ui__warning_once("CS ETM Trace: Missing DSO. Use 'perf archive' or debuginfod to export data from the traced system.\n" @@ -1303,39 +1290,31 @@ cs_etm__get_trace(struct cs_etm_queue *etmq) return etmq->buf_len; } -static void cs_etm__set_pid_tid_cpu(struct cs_etm_auxtrace *etm, - struct cs_etm_traceid_queue *tidq) +static void cs_etm__set_thread(struct cs_etm_auxtrace *etm, + struct cs_etm_traceid_queue *tidq, pid_t tid) { - if ((!tidq->thread) && (tidq->tid != -1)) - tidq->thread = machine__find_thread(etm->machine, -1, - tidq->tid); + struct machine *machine = &etm->session->machines.host; + + if (tid != -1) { + thread__zput(tidq->thread); + tidq->thread = machine__find_thread(machine, -1, tid); + } - if (tidq->thread) - tidq->pid = tidq->thread->pid_; + /* Couldn't find a known thread */ + if (!tidq->thread) + tidq->thread = machine__idle_thread(machine); } int cs_etm__etmq_set_tid(struct cs_etm_queue *etmq, pid_t tid, u8 trace_chan_id) { - int cpu, err = -EINVAL; - struct cs_etm_auxtrace *etm = etmq->etm; struct cs_etm_traceid_queue *tidq; tidq = cs_etm__etmq_get_traceid_queue(etmq, trace_chan_id); if (!tidq) - return err; - - if (cs_etm__get_cpu(trace_chan_id, &cpu) < 0) - return err; - - err = machine__set_current_tid(etm->machine, cpu, tid, tid); - if (err) - return err; - - tidq->tid = tid; - thread__zput(tidq->thread); + return -EINVAL; - cs_etm__set_pid_tid_cpu(etm, tidq); + cs_etm__set_thread(etmq->etm, tidq, tid); return 0; } @@ -1412,8 +1391,8 @@ static int cs_etm__synth_instruction_sample(struct cs_etm_queue *etmq, sample.time = cs_etm__resolve_sample_time(etmq, tidq); sample.ip = addr; - sample.pid = tidq->pid; - sample.tid = tidq->tid; + sample.pid = tidq->thread->pid_; + sample.tid = tidq->thread->tid; sample.id = etmq->etm->instructions_id; sample.stream_id = etmq->etm->instructions_id; sample.period = period; @@ -1471,8 +1450,8 @@ static int cs_etm__synth_branch_sample(struct cs_etm_queue *etmq, sample.time = cs_etm__resolve_sample_time(etmq, tidq); sample.ip = ip; - sample.pid = tidq->pid; - sample.tid = tidq->tid; + sample.pid = tidq->thread->pid_; + sample.tid = tidq->thread->tid; sample.addr = cs_etm__first_executed_instr(tidq->packet); sample.id = etmq->etm->branches_id; sample.stream_id = etmq->etm->branches_id; @@ -2466,11 +2445,6 @@ static int cs_etm__process_timeless_queues(struct cs_etm_auxtrace *etm, if (!etmq) continue; - /* - * Per-cpu mode has contextIDs in the trace and the decoder - * calls cs_etm__set_pid_tid_cpu() automatically so no need - * to do this here - */ if (etm->per_thread_decoding) { tidq = cs_etm__etmq_get_traceid_queue( etmq, CS_ETM_PER_THREAD_TRACEID); @@ -2478,10 +2452,8 @@ static int cs_etm__process_timeless_queues(struct cs_etm_auxtrace *etm, if (!tidq) continue; - if ((tid == -1) || (tidq->tid == tid)) { - cs_etm__set_pid_tid_cpu(etm, tidq); + if (tid == -1 || tidq->thread->tid == tid) cs_etm__run_per_thread_timeless_decoder(etmq); - } } else cs_etm__run_per_cpu_timeless_decoder(etmq); } @@ -2611,10 +2583,12 @@ static int cs_etm__process_itrace_start(struct cs_etm_auxtrace *etm, return 0; /* - * Add the tid/pid to the log so that we can get a match when - * we get a contextID from the decoder. + * Add the tid/pid to the log so that we can get a match when we get a + * contextID from the decoder. Only track for the host: only kernel + * trace is supported for guests which wouldn't need pids so this should + * be fine. */ - th = machine__findnew_thread(etm->machine, + th = machine__findnew_thread(&etm->session->machines.host, event->itrace_start.pid, event->itrace_start.tid); if (!th) @@ -2647,10 +2621,12 @@ static int cs_etm__process_switch_cpu_wide(struct cs_etm_auxtrace *etm, return 0; /* - * Add the tid/pid to the log so that we can get a match when - * we get a contextID from the decoder. + * Add the tid/pid to the log so that we can get a match when we get a + * contextID from the decoder. Only track for the host: only kernel + * trace is supported for guests which wouldn't need pids so this should + * be fine. */ - th = machine__findnew_thread(etm->machine, + th = machine__findnew_thread(&etm->session->machines.host, event->context_switch.next_prev_pid, event->context_switch.next_prev_tid); if (!th) @@ -3259,7 +3235,6 @@ int cs_etm__process_auxtrace_info_full(union perf_event *event, } etm->session = session; - etm->machine = &session->machines.host; etm->num_cpu = num_cpu; etm->pmu_type = (unsigned int) ((ptr[CS_PMU_TYPE_CPUS] >> 32) & 0xffffffff); @@ -3286,27 +3261,6 @@ int cs_etm__process_auxtrace_info_full(union perf_event *event, if (err) return err; - etm->unknown_thread = thread__new(999999999, 999999999); - if (!etm->unknown_thread) { - err = -ENOMEM; - goto err_free_queues; - } - - /* - * Initialize list node so that at thread__zput() we can avoid - * segmentation fault at list_del_init(). - */ - INIT_LIST_HEAD(&etm->unknown_thread->node); - - err = thread__set_comm(etm->unknown_thread, "unknown", 0); - if (err) - goto err_delete_thread; - - if (thread__init_maps(etm->unknown_thread, etm->machine)) { - err = -ENOMEM; - goto err_delete_thread; - } - etm->tc.time_shift = tc->time_shift; etm->tc.time_mult = tc->time_mult; etm->tc.time_zero = tc->time_zero; @@ -3318,7 +3272,7 @@ int cs_etm__process_auxtrace_info_full(union perf_event *event, } err = cs_etm__synth_events(etm, session); if (err) - goto err_delete_thread; + goto err_free_queues; /* * Map Trace ID values to CPU metadata. @@ -3348,7 +3302,7 @@ int cs_etm__process_auxtrace_info_full(union perf_event *event, session->header.data_size, cs_etm__process_aux_hw_id_cb, &aux_hw_id_found); if (err) - goto err_delete_thread; + goto err_free_queues; /* if HW ID found then clear any unused metadata ID values */ if (aux_hw_id_found) @@ -3358,17 +3312,15 @@ int cs_etm__process_auxtrace_info_full(union perf_event *event, err = cs_etm__map_trace_ids_metadata(num_cpu, metadata); if (err) - goto err_delete_thread; + goto err_free_queues; err = cs_etm__queue_aux_records(session); if (err) - goto err_delete_thread; + goto err_free_queues; etm->data_queued = etm->queues.populated; return 0; -err_delete_thread: - thread__zput(etm->unknown_thread); err_free_queues: auxtrace_queues__free(&etm->queues); session->auxtrace = NULL; From patchwork Wed May 24 13:19:56 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: James Clark X-Patchwork-Id: 13253987 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id DBA6FC7EE2D for ; Wed, 24 May 2023 13:20:55 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:Cc:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=/fZNwgmZXiPPavl+WKUsXY97tcFYwsZ2S4EoakZcgL4=; b=ZH4bFgDmf8FzJ1 XnllArNKwIVBpfze4s9DqKKUHJCYv3aCCVC7b0TM4lYZcFla9s5trfUaSGO4Q77BCUym5eVnMRDIh 2a13o4pCbX5QcKoKiN2B0U47f6n4DDbIm3Q7oj93dItl1YQmVuhCdVSAazpOhsPJ6BeVI+L/F4J5Z TByVg5BIL26RLf7RwT89IAEjbisoUFVzNzP/SIkWlOSQAQ1zBWKShO0Ks1NyYqjL1AGecslDgEP6r h4zo3soz3MwEm11DqOXbsLa/8xmY7lU9hSxboqL2RGv5gOI9RldGyXvgW+02ZTdhWGCtMfDuWrhFQ V2D3SBIUFWfG8XRg9kZQ==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.96 #2 (Red Hat Linux)) id 1q1oPl-00DYPX-1a; Wed, 24 May 2023 13:20:29 +0000 Received: from foss.arm.com ([217.140.110.172]) by bombadil.infradead.org with esmtp (Exim 4.96 #2 (Red Hat Linux)) id 1q1oPc-00DYMR-2m for linux-arm-kernel@lists.infradead.org; Wed, 24 May 2023 13:20:22 +0000 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 99E691595; Wed, 24 May 2023 06:21:03 -0700 (PDT) Received: from localhost.localdomain (unknown [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id F0F5F3F840; Wed, 24 May 2023 06:20:15 -0700 (PDT) From: James Clark To: coresight@lists.linaro.org, denik@chromium.org Cc: James Clark , Suzuki K Poulose , Mike Leach , Leo Yan , Peter Zijlstra , Ingo Molnar , Arnaldo Carvalho de Melo , Mark Rutland , Alexander Shishkin , Jiri Olsa , Namhyung Kim , Ian Rogers , Adrian Hunter , John Garry , Will Deacon , linux-arm-kernel@lists.infradead.org, linux-perf-users@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH 2/4] perf cs-etm: Use previous thread for branch sample source IP Date: Wed, 24 May 2023 14:19:56 +0100 Message-Id: <20230524131958.2139331-3-james.clark@arm.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230524131958.2139331-1-james.clark@arm.com> References: <20230524131958.2139331-1-james.clark@arm.com> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20230524_062020_945679_F3F0FC5A X-CRM114-Status: GOOD ( 14.54 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org Branch samples currently use the IP of the previous packet as the from IP, and the IP of the current packet as the to IP. But it incorrectly uses the current thread. In some cases like a jump into a different exception level this will attribute to the incorrect process. Fix it by tracking the previous thread in the same way the previous packet is tracked. Signed-off-by: James Clark Reviewed-by: Mike Leach --- tools/perf/util/cs-etm.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c index ebffc9052561..a997fe79d458 100644 --- a/tools/perf/util/cs-etm.c +++ b/tools/perf/util/cs-etm.c @@ -86,6 +86,7 @@ struct cs_etm_traceid_queue { size_t last_branch_pos; union perf_event *event_buf; struct thread *thread; + struct thread *prev_thread; struct branch_stack *last_branch; struct branch_stack *last_branch_rb; struct cs_etm_packet *prev_packet; @@ -480,6 +481,7 @@ static int cs_etm__init_traceid_queue(struct cs_etm_queue *etmq, tidq->trace_chan_id = trace_chan_id; tidq->thread = machine__findnew_thread(&etm->session->machines.host, -1, queue->tid); + tidq->prev_thread = machine__idle_thread(&etm->session->machines.host); tidq->packet = zalloc(sizeof(struct cs_etm_packet)); if (!tidq->packet) @@ -616,6 +618,8 @@ static void cs_etm__packet_swap(struct cs_etm_auxtrace *etm, tmp = tidq->packet; tidq->packet = tidq->prev_packet; tidq->prev_packet = tmp; + thread__put(tidq->prev_thread); + tidq->prev_thread = thread__get(tidq->thread); } } @@ -791,6 +795,7 @@ static void cs_etm__free_traceid_queues(struct cs_etm_queue *etmq) /* Free this traceid_queue from the array */ tidq = etmq->traceid_queues[idx]; thread__zput(tidq->thread); + thread__zput(tidq->prev_thread); zfree(&tidq->event_buf); zfree(&tidq->last_branch); zfree(&tidq->last_branch_rb); @@ -1450,8 +1455,8 @@ static int cs_etm__synth_branch_sample(struct cs_etm_queue *etmq, sample.time = cs_etm__resolve_sample_time(etmq, tidq); sample.ip = ip; - sample.pid = tidq->thread->pid_; - sample.tid = tidq->thread->tid; + sample.pid = tidq->prev_thread->pid_; + sample.tid = tidq->prev_thread->tid; sample.addr = cs_etm__first_executed_instr(tidq->packet); sample.id = etmq->etm->branches_id; sample.stream_id = etmq->etm->branches_id; From patchwork Wed May 24 13:19:57 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: James Clark X-Patchwork-Id: 13253988 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 35DBDC7EE33 for ; Wed, 24 May 2023 13:20:59 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:Cc:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=Q/9E+WLZwlRMKVxYxrOobXbJVNPTOj9MqytSgX6FFQ8=; b=gPmQQfcLSHKzlw 8zut5U36g94yVz4LyTJfbZ1k+Ob0jqFeI3aP97UDs4RSXftEzjSoY3FJY5hqTFl1VDeTudjkjMipL 2OCUkuJVOSbakjqfq/fdj3J1a72YKF47vwuiXyoPmM4WbRRUtS9L2m9HilXA+nBT2S74p8sYZ8zIZ SBpxT8FOqJvbvMztoTZ5cYTcr3oo/fKmLQ05wJkG/CwY4evWwg7ILLodMYQn/cTJNtivxOmTJ/L30 LVE8oZAYt6lZPVhKlpN6Wjp6sIePe+c533HNr6J70gvIHS4SC4+vzRATAYfkA9ABUnWbeaQCM8FYm FkVX3mSHaFey7g3z03vg==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.96 #2 (Red Hat Linux)) id 1q1oPm-00DYQV-1q; Wed, 24 May 2023 13:20:30 +0000 Received: from foss.arm.com ([217.140.110.172]) by bombadil.infradead.org with esmtp (Exim 4.96 #2 (Red Hat Linux)) id 1q1oPf-00DYNd-2K for linux-arm-kernel@lists.infradead.org; Wed, 24 May 2023 13:20:26 +0000 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 0B54A1042; Wed, 24 May 2023 06:21:07 -0700 (PDT) Received: from localhost.localdomain (unknown [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 6204C3F840; Wed, 24 May 2023 06:20:19 -0700 (PDT) From: James Clark To: coresight@lists.linaro.org, denik@chromium.org Cc: James Clark , Suzuki K Poulose , Mike Leach , Leo Yan , Peter Zijlstra , Ingo Molnar , Arnaldo Carvalho de Melo , Mark Rutland , Alexander Shishkin , Jiri Olsa , Namhyung Kim , Ian Rogers , Adrian Hunter , John Garry , Will Deacon , linux-arm-kernel@lists.infradead.org, linux-perf-users@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH 3/4] perf cs-etm: Track exception level Date: Wed, 24 May 2023 14:19:57 +0100 Message-Id: <20230524131958.2139331-4-james.clark@arm.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230524131958.2139331-1-james.clark@arm.com> References: <20230524131958.2139331-1-james.clark@arm.com> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20230524_062023_852442_78725386 X-CRM114-Status: GOOD ( 24.22 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org Currently we assume all trace belongs to the host machine so when the decoder should be looking at the guest kernel maps it can crash because it looks at the host ones instead. Avoid one scenario (guest kernel running at EL1) by assigning the default guest machine to this trace. For userspace trace it's still not possible to determine guest vs host, but the PIDs should help in this case. Signed-off-by: James Clark --- .../perf/util/cs-etm-decoder/cs-etm-decoder.c | 7 +- tools/perf/util/cs-etm.c | 64 ++++++++++++++----- tools/perf/util/cs-etm.h | 5 +- 3 files changed, 56 insertions(+), 20 deletions(-) diff --git a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c index 82a27ab90c8b..ac227cd03eb0 100644 --- a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c +++ b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c @@ -573,12 +573,13 @@ cs_etm_decoder__set_tid(struct cs_etm_queue *etmq, break; } + if (cs_etm__etmq_set_tid_el(etmq, tid, trace_chan_id, + elem->context.exception_level)) + return OCSD_RESP_FATAL_SYS_ERR; + if (tid == -1) return OCSD_RESP_CONT; - if (cs_etm__etmq_set_tid(etmq, tid, trace_chan_id)) - return OCSD_RESP_FATAL_SYS_ERR; - /* * A timestamp is generated after a PE_CONTEXT element so make sure * to rely on that coming one. diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c index a997fe79d458..b9ba19327f26 100644 --- a/tools/perf/util/cs-etm.c +++ b/tools/perf/util/cs-etm.c @@ -14,7 +14,6 @@ #include #include -#include #include #include "auxtrace.h" @@ -87,6 +86,8 @@ struct cs_etm_traceid_queue { union perf_event *event_buf; struct thread *thread; struct thread *prev_thread; + ocsd_ex_level prev_el; + ocsd_ex_level el; struct branch_stack *last_branch; struct branch_stack *last_branch_rb; struct cs_etm_packet *prev_packet; @@ -479,6 +480,7 @@ static int cs_etm__init_traceid_queue(struct cs_etm_queue *etmq, queue = &etmq->etm->queues.queue_array[etmq->queue_nr]; tidq->trace_chan_id = trace_chan_id; + tidq->el = tidq->prev_el = ocsd_EL_unknown; tidq->thread = machine__findnew_thread(&etm->session->machines.host, -1, queue->tid); tidq->prev_thread = machine__idle_thread(&etm->session->machines.host); @@ -618,6 +620,7 @@ static void cs_etm__packet_swap(struct cs_etm_auxtrace *etm, tmp = tidq->packet; tidq->packet = tidq->prev_packet; tidq->prev_packet = tmp; + tidq->prev_el = tidq->el; thread__put(tidq->prev_thread); tidq->prev_thread = thread__get(tidq->thread); } @@ -879,11 +882,34 @@ static bool cs_etm__evsel_is_auxtrace(struct perf_session *session, return evsel->core.attr.type == aux->pmu_type; } -static u8 cs_etm__cpu_mode(struct cs_etm_queue *etmq, u64 address) +static struct machine *cs_etm__get_machine(struct cs_etm_auxtrace *etm, + ocsd_ex_level el) { - struct machine *machine; + /* + * Not perfect, but assume anything in EL1 is the default guest, and + * everything else is the host. nHVE and pKVM may not work with this + * assumption. And distinguishing between guest and host userspaces + * isn't currently supported either. Neither is multiple guest support. + * All this does is reduce the likeliness of decode errors where we look + * into the host kernel maps when it should have been the guest maps. + */ + switch (el) { + case ocsd_EL1: + return machines__find_guest(&etm->session->machines, + DEFAULT_GUEST_KERNEL_ID); + case ocsd_EL3: + case ocsd_EL2: + case ocsd_EL0: + case ocsd_EL_unknown: + default: + return &etm->session->machines.host; + } +} - machine = &etmq->etm->session->machines.host; +static u8 cs_etm__cpu_mode(struct cs_etm_queue *etmq, u64 address, + ocsd_ex_level el) +{ + struct machine *machine = cs_etm__get_machine(etmq->etm, el); if (address >= machine__kernel_start(machine)) { if (machine__is_host(machine)) @@ -893,10 +919,14 @@ static u8 cs_etm__cpu_mode(struct cs_etm_queue *etmq, u64 address) } else { if (machine__is_host(machine)) return PERF_RECORD_MISC_USER; - else if (perf_guest) + else { + /* + * Can't really happen at the moment because + * cs_etm__get_machine() will always return + * machines.host for any non EL1 trace. + */ return PERF_RECORD_MISC_GUEST_USER; - else - return PERF_RECORD_MISC_HYPERVISOR; + } } } @@ -913,11 +943,12 @@ static u32 cs_etm__mem_access(struct cs_etm_queue *etmq, u8 trace_chan_id, if (!etmq) return 0; - cpumode = cs_etm__cpu_mode(etmq, address); tidq = cs_etm__etmq_get_traceid_queue(etmq, trace_chan_id); if (!tidq) return 0; + cpumode = cs_etm__cpu_mode(etmq, address, tidq->el); + if (!thread__find_map(tidq->thread, cpumode, address, &al)) return 0; @@ -1296,9 +1327,10 @@ cs_etm__get_trace(struct cs_etm_queue *etmq) } static void cs_etm__set_thread(struct cs_etm_auxtrace *etm, - struct cs_etm_traceid_queue *tidq, pid_t tid) + struct cs_etm_traceid_queue *tidq, pid_t tid, + ocsd_ex_level el) { - struct machine *machine = &etm->session->machines.host; + struct machine *machine = cs_etm__get_machine(etm, el); if (tid != -1) { thread__zput(tidq->thread); @@ -1308,10 +1340,12 @@ static void cs_etm__set_thread(struct cs_etm_auxtrace *etm, /* Couldn't find a known thread */ if (!tidq->thread) tidq->thread = machine__idle_thread(machine); + + tidq->el = el; } -int cs_etm__etmq_set_tid(struct cs_etm_queue *etmq, - pid_t tid, u8 trace_chan_id) +int cs_etm__etmq_set_tid_el(struct cs_etm_queue *etmq, pid_t tid, u8 trace_chan_id, + ocsd_ex_level el) { struct cs_etm_traceid_queue *tidq; @@ -1319,7 +1353,7 @@ int cs_etm__etmq_set_tid(struct cs_etm_queue *etmq, if (!tidq) return -EINVAL; - cs_etm__set_thread(etmq->etm, tidq, tid); + cs_etm__set_thread(etmq->etm, tidq, tid, el); return 0; } @@ -1389,7 +1423,7 @@ static int cs_etm__synth_instruction_sample(struct cs_etm_queue *etmq, struct perf_sample sample = {.ip = 0,}; event->sample.header.type = PERF_RECORD_SAMPLE; - event->sample.header.misc = cs_etm__cpu_mode(etmq, addr); + event->sample.header.misc = cs_etm__cpu_mode(etmq, addr, tidq->el); event->sample.header.size = sizeof(struct perf_event_header); /* Set time field based on etm auxtrace config. */ @@ -1448,7 +1482,7 @@ static int cs_etm__synth_branch_sample(struct cs_etm_queue *etmq, ip = cs_etm__last_executed_instr(tidq->prev_packet); event->sample.header.type = PERF_RECORD_SAMPLE; - event->sample.header.misc = cs_etm__cpu_mode(etmq, ip); + event->sample.header.misc = cs_etm__cpu_mode(etmq, ip, tidq->prev_el); event->sample.header.size = sizeof(struct perf_event_header); /* Set time field based on etm auxtrace config. */ diff --git a/tools/perf/util/cs-etm.h b/tools/perf/util/cs-etm.h index 70cac0375b34..88e9b25a8a9f 100644 --- a/tools/perf/util/cs-etm.h +++ b/tools/perf/util/cs-etm.h @@ -232,10 +232,11 @@ int cs_etm__process_auxtrace_info(union perf_event *event, struct perf_event_attr *cs_etm_get_default_config(struct perf_pmu *pmu); #ifdef HAVE_CSTRACE_SUPPORT +#include int cs_etm__get_cpu(u8 trace_chan_id, int *cpu); int cs_etm__get_pid_fmt(u8 trace_chan_id, u64 *pid_fmt); -int cs_etm__etmq_set_tid(struct cs_etm_queue *etmq, - pid_t tid, u8 trace_chan_id); +int cs_etm__etmq_set_tid_el(struct cs_etm_queue *etmq, pid_t tid, u8 trace_chan_id, + ocsd_ex_level el); bool cs_etm__etmq_is_timeless(struct cs_etm_queue *etmq); void cs_etm__etmq_set_traceid_queue_timestamp(struct cs_etm_queue *etmq, u8 trace_chan_id); From patchwork Wed May 24 13:19:58 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: James Clark X-Patchwork-Id: 13253989 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 58BE5C77B73 for ; Wed, 24 May 2023 13:21:15 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:Cc:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=rK1CFOAwpzXuFqB9yEwfHkIIKsAeOP4wK29dJ6NM310=; b=P8neXwWc4XgjLN dgPZfVe1CT2CovyuFXJkjougLoebdgTRpy7DhPUx7P4X5Jenxb5ZLIW9oQnq3Uw7giCCTZ0JSpV3n 2fX8Bd1JRuQYyUFWKc0xfTyEr9nCeB0RJfaNVgQbgxCaUiUSGCiEApeJuKvZd4Laxg/YvqZkBVW0n qseP1oo/j2VwjNMmAvII/JSO/qt8zZEjffUygOZiCTxxA5cgvIvczYf0Kk5Jrijxa95hsumgXeHDU gIcHQ7esQx342pzMEQ0tMda2u0OtOR9WsB4jBE14moKexbAl19MTeNBHoQ5yL5yP3n5hDXhr62wxC Gw06MoGyVoEx/RBTzUSQ==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.96 #2 (Red Hat Linux)) id 1q1oQ6-00DYUq-14; Wed, 24 May 2023 13:20:50 +0000 Received: from foss.arm.com ([217.140.110.172]) by bombadil.infradead.org with esmtp (Exim 4.96 #2 (Red Hat Linux)) id 1q1oPj-00DYOn-2D for linux-arm-kernel@lists.infradead.org; Wed, 24 May 2023 13:20:29 +0000 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 6FE00113E; Wed, 24 May 2023 06:21:10 -0700 (PDT) Received: from localhost.localdomain (unknown [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id C68B43F840; Wed, 24 May 2023 06:20:22 -0700 (PDT) From: James Clark To: coresight@lists.linaro.org, denik@chromium.org Cc: James Clark , Suzuki K Poulose , Mike Leach , Leo Yan , Peter Zijlstra , Ingo Molnar , Arnaldo Carvalho de Melo , Mark Rutland , Alexander Shishkin , Jiri Olsa , Namhyung Kim , Ian Rogers , Adrian Hunter , John Garry , Will Deacon , linux-arm-kernel@lists.infradead.org, linux-perf-users@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH 4/4] perf cs-etm: Add exception level consistency check Date: Wed, 24 May 2023 14:19:58 +0100 Message-Id: <20230524131958.2139331-5-james.clark@arm.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230524131958.2139331-1-james.clark@arm.com> References: <20230524131958.2139331-1-james.clark@arm.com> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20230524_062027_820286_384FD179 X-CRM114-Status: GOOD ( 18.54 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org Assert that our own tracking of the exception level matches what OpenCSD provides. OpenCSD doesn't distinguish between EL0 and EL1 in the memory access callback so the extra tracking was required. But a rough assert can still be done. Signed-off-by: James Clark --- .../perf/util/cs-etm-decoder/cs-etm-decoder.c | 6 +-- .../perf/util/cs-etm-decoder/cs-etm-decoder.h | 4 +- tools/perf/util/cs-etm.c | 37 +++++++++++++------ 3 files changed, 32 insertions(+), 15 deletions(-) diff --git a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c index ac227cd03eb0..50b3c248d1e5 100644 --- a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c +++ b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c @@ -52,15 +52,15 @@ struct cs_etm_decoder { static u32 cs_etm_decoder__mem_access(const void *context, const ocsd_vaddr_t address, - const ocsd_mem_space_acc_t mem_space __maybe_unused, + const ocsd_mem_space_acc_t mem_space, const u8 trace_chan_id, const u32 req_size, u8 *buffer) { struct cs_etm_decoder *decoder = (struct cs_etm_decoder *) context; - return decoder->mem_access(decoder->data, trace_chan_id, - address, req_size, buffer); + return decoder->mem_access(decoder->data, trace_chan_id, address, + req_size, buffer, mem_space); } int cs_etm_decoder__add_mem_access_cb(struct cs_etm_decoder *decoder, diff --git a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.h b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.h index 21d403f55d96..272c2efe78ee 100644 --- a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.h +++ b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.h @@ -11,6 +11,7 @@ #define INCLUDE__CS_ETM_DECODER_H__ #include +#include #include struct cs_etm_decoder; @@ -19,7 +20,8 @@ struct cs_etm_packet_queue; struct cs_etm_queue; -typedef u32 (*cs_etm_mem_cb_type)(struct cs_etm_queue *, u8, u64, size_t, u8 *); +typedef u32 (*cs_etm_mem_cb_type)(struct cs_etm_queue *, u8, u64, size_t, u8 *, + const ocsd_mem_space_acc_t); struct cs_etmv3_trace_params { u32 reg_ctrl; diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c index b9ba19327f26..ccf34ed8ddf2 100644 --- a/tools/perf/util/cs-etm.c +++ b/tools/perf/util/cs-etm.c @@ -931,7 +931,8 @@ static u8 cs_etm__cpu_mode(struct cs_etm_queue *etmq, u64 address, } static u32 cs_etm__mem_access(struct cs_etm_queue *etmq, u8 trace_chan_id, - u64 address, size_t size, u8 *buffer) + u64 address, size_t size, u8 *buffer, + const ocsd_mem_space_acc_t mem_space) { u8 cpumode; u64 offset; @@ -947,6 +948,20 @@ static u32 cs_etm__mem_access(struct cs_etm_queue *etmq, u8 trace_chan_id, if (!tidq) return 0; + /* + * We've already tracked EL along side the PID in cs_etm__set_thread() + * so double check that it matches what OpenCSD thinks as well. It + * doesn't distinguish between EL0 and EL1 for this mem access callback + * so we had to do the extra tracking. + */ + if (mem_space & OCSD_MEM_SPACE_EL1N) { + /* Includes both non secure EL1 and EL0 */ + assert(tidq->el == ocsd_EL1 || tidq->el == ocsd_EL0); + } else if (mem_space & OCSD_MEM_SPACE_EL2) + assert(tidq->el == ocsd_EL2); + else if (mem_space & OCSD_MEM_SPACE_EL3) + assert(tidq->el == ocsd_EL3); + cpumode = cs_etm__cpu_mode(etmq, address, tidq->el); if (!thread__find_map(tidq->thread, cpumode, address, &al)) @@ -1195,8 +1210,8 @@ static inline int cs_etm__t32_instr_size(struct cs_etm_queue *etmq, { u8 instrBytes[2]; - cs_etm__mem_access(etmq, trace_chan_id, addr, - ARRAY_SIZE(instrBytes), instrBytes); + cs_etm__mem_access(etmq, trace_chan_id, addr, ARRAY_SIZE(instrBytes), + instrBytes, 0); /* * T32 instruction size is indicated by bits[15:11] of the first * 16-bit word of the instruction: 0b11101, 0b11110 and 0b11111 @@ -1387,8 +1402,8 @@ static void cs_etm__copy_insn(struct cs_etm_queue *etmq, else sample->insn_len = 4; - cs_etm__mem_access(etmq, trace_chan_id, sample->ip, - sample->insn_len, (void *)sample->insn); + cs_etm__mem_access(etmq, trace_chan_id, sample->ip, sample->insn_len, + (void *)sample->insn, 0); } u64 cs_etm__convert_sample_time(struct cs_etm_queue *etmq, u64 cs_timestamp) @@ -1940,8 +1955,8 @@ static bool cs_etm__is_svc_instr(struct cs_etm_queue *etmq, u8 trace_chan_id, * so below only read 2 bytes as instruction size for T32. */ addr = end_addr - 2; - cs_etm__mem_access(etmq, trace_chan_id, addr, - sizeof(instr16), (u8 *)&instr16); + cs_etm__mem_access(etmq, trace_chan_id, addr, sizeof(instr16), + (u8 *)&instr16, 0); if ((instr16 & 0xFF00) == 0xDF00) return true; @@ -1956,8 +1971,8 @@ static bool cs_etm__is_svc_instr(struct cs_etm_queue *etmq, u8 trace_chan_id, * +---------+---------+-------------------------+ */ addr = end_addr - 4; - cs_etm__mem_access(etmq, trace_chan_id, addr, - sizeof(instr32), (u8 *)&instr32); + cs_etm__mem_access(etmq, trace_chan_id, addr, sizeof(instr32), + (u8 *)&instr32, 0); if ((instr32 & 0x0F000000) == 0x0F000000 && (instr32 & 0xF0000000) != 0xF0000000) return true; @@ -1973,8 +1988,8 @@ static bool cs_etm__is_svc_instr(struct cs_etm_queue *etmq, u8 trace_chan_id, * +-----------------------+---------+-----------+ */ addr = end_addr - 4; - cs_etm__mem_access(etmq, trace_chan_id, addr, - sizeof(instr32), (u8 *)&instr32); + cs_etm__mem_access(etmq, trace_chan_id, addr, sizeof(instr32), + (u8 *)&instr32, 0); if ((instr32 & 0xFFE0001F) == 0xd4000001) return true;