From patchwork Sun Jan 15 21:15:38 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 1726821 X-Patchwork-Delegate: trini@ti.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=85.214.62.61; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: legolas.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=chromium.org header.i=@chromium.org header.a=rsa-sha256 header.s=google header.b=gHLtd2JI; dkim-atps=neutral Received: from phobos.denx.de (phobos.denx.de [85.214.62.61]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4Nw7J10dyWz23fk for ; Mon, 16 Jan 2023 08:16:33 +1100 (AEDT) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 7DF67855A4; Sun, 15 Jan 2023 22:16:30 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=chromium.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (1024-bit key; unprotected) header.d=chromium.org header.i=@chromium.org header.b="gHLtd2JI"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id 44661855A6; Sun, 15 Jan 2023 22:16:29 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,SPF_HELO_NONE, SPF_PASS autolearn=ham autolearn_force=no version=3.4.2 Received: from mail-io1-xd33.google.com (mail-io1-xd33.google.com [IPv6:2607:f8b0:4864:20::d33]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id 3EC328554F for ; Sun, 15 Jan 2023 22:16:25 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=chromium.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=sjg@chromium.org Received: by mail-io1-xd33.google.com with SMTP id v65so8555411ioe.4 for ; Sun, 15 Jan 2023 13:16:25 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=LaJCT7lPyUqOmvN+gddSesF/dwdzEM67h+bAPB+qf6s=; b=gHLtd2JIy3cEfAmb3EbKkgOo4vCyXILSuzNA1TdEa5OxbZWLCukTvn6QP31hpHdYKc MRW8xdbZ98z3K/4wNJIFfMvj5S2Pu3HibiygwiXK4pg/gOa9JtfcHkXn8OdX8YcgFjCo xnU+L/WdfnzEn3sFOxNdAVVtqPeW8f+qiZYwQ= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=LaJCT7lPyUqOmvN+gddSesF/dwdzEM67h+bAPB+qf6s=; b=mKS4fVXfoEFfkAm248GD1aU/FWWeWMramNk/FwV2takatHmeKistJbKQJhBea9HrS2 TRh/u/CjnXpidvCwe9BST0lu1PxHusuJeaLhGAt3s2rK7nmRUcDK5WMCdBk4J8tNj1id ONoZRTjxpZWPPqk61UbGHwpaXhGrrh+ptlzu1M4YGdTzFYUoyBFI+cDEezzK6dCbumMI mopeg7DXK+tIjFf1SzgPxKsSQ+Pxu6BGR/B9cD96ZAOMYOUBXN1TtS9YESDlrYWL39dt b4bt+9XJACgdqTzzN7M41ajOtiKhRsnzdvqQzjDNZtNCjRRWUq2IHNRFBnHvfCCFg4b6 QcmA== X-Gm-Message-State: AFqh2ko/OeZjWbnVOAui3jhZ58LLL7eYiGoBfZZsmezImJmjwmiXZ0Vp +8mHMQCkc6/80oQ8naVbNJNXCrTr/thXdPGdGFY= X-Google-Smtp-Source: AMrXdXtzUPcW4pMlD4UiVPhA72YSu8RUTjK/ZxgAHP4gmG9Xc69aNZsNhNK5IqF1gSmlwbIsASAgTQ== X-Received: by 2002:a05:6602:889:b0:704:b687:a854 with SMTP id f9-20020a056602088900b00704b687a854mr1584108ioz.8.1673817383816; Sun, 15 Jan 2023 13:16:23 -0800 (PST) Received: from sjg1.roam.corp.google.com (c-73-14-173-85.hsd1.co.comcast.net. [73.14.173.85]) by smtp.gmail.com with ESMTPSA id j6-20020a6bf906000000b007046e9e138esm4329107iog.22.2023.01.15.13.16.23 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 15 Jan 2023 13:16:23 -0800 (PST) From: Simon Glass To: U-Boot Mailing List Cc: Tom Rini , Heinrich Schuchardt , Simon Glass , Andrey Zhizhikin Subject: [PATCH 01/24] .gitignore: Ignore the moveconfig database Date: Sun, 15 Jan 2023 14:15:38 -0700 Message-Id: <20230115211602.1127661-2-sjg@chromium.org> X-Mailer: git-send-email 2.39.0.314.g84b9a713c41-goog In-Reply-To: <20230115211602.1127661-1-sjg@chromium.org> References: <20230115211602.1127661-1-sjg@chromium.org> MIME-Version: 1.0 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.39 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.103.6 at phobos.denx.de X-Virus-Status: Clean This file is produced by the moveconfig.py tool. It should never be added to the repo, so add it to the .gitignore file. Signed-off-by: Simon Glass --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index eb769f144c3..357bcfe9917 100644 --- a/.gitignore +++ b/.gitignore @@ -104,3 +104,6 @@ __pycache__ # pylint files /pylint.cur /pylint.out/ + +# moveconfig database +/moveconfig.db From patchwork Sun Jan 15 21:15:39 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 1726822 X-Patchwork-Delegate: trini@ti.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=85.214.62.61; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: legolas.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=chromium.org header.i=@chromium.org header.a=rsa-sha256 header.s=google header.b=PskR1mzo; dkim-atps=neutral Received: from phobos.denx.de (phobos.denx.de [85.214.62.61]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4Nw7JD4lf1z23fk for ; Mon, 16 Jan 2023 08:16:44 +1100 (AEDT) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id ABC5F85560; Sun, 15 Jan 2023 22:16:33 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=chromium.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (1024-bit key; unprotected) header.d=chromium.org header.i=@chromium.org header.b="PskR1mzo"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id 553A485514; Sun, 15 Jan 2023 22:16:30 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,SPF_HELO_NONE, SPF_PASS autolearn=ham autolearn_force=no version=3.4.2 Received: from mail-io1-xd36.google.com (mail-io1-xd36.google.com [IPv6:2607:f8b0:4864:20::d36]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id E83C285560 for ; Sun, 15 Jan 2023 22:16:25 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=chromium.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=sjg@chromium.org Received: by mail-io1-xd36.google.com with SMTP id n85so5210061iod.7 for ; Sun, 15 Jan 2023 13:16:25 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=9EBr0mEjXhIkKqjqHyPAuGOBSkrggIoLOVvUCI0ihmE=; b=PskR1mzoT1iLKQkcOj3bkCjuMmeTAWTMvatvnRcrAPxrDGW6RoainTM8CpkE9XUYZ1 whfZWl5U+354yznP3HyjfDqavtjyP3RQFoRcIGdvQqlCIrGZyK7i6co+ndOTza1/yWmi 21RsGGK7EBOLAUXnGNwQeTrje89TMQhFMbpu0= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=9EBr0mEjXhIkKqjqHyPAuGOBSkrggIoLOVvUCI0ihmE=; b=7QUsZl+DC4wjuSclG8UjdHS3y0JPlfeYPOX64kOKZFFgSUZO1eI6OIFP0H7KoAyByI ba2FPqHO/e0waXDuE0BPy639BRaM92fEvwu8uFmnbFEvQOmDajCseLbDbNjMqMKAH1T2 R89UoT27UsDgGy4x8vzZM7VGEji4N4CKHQ+2ZsrejHFOHr7mv6wCG4z10rb+yFqOrUAn hCoGmdLkjaetly1F8toSylX+pPYZ15OVGuuH37/odaR6RzmdsKpWWtGPFIBfwXPtUl3J bV2hoax+Iocv6C07Y+bKl4uHNXgQo1OIWktbIGhvPlHIFB5JXwwUDkkrlW3OWvqLItq7 zQBA== X-Gm-Message-State: AFqh2koizLwiCnToYkq49Zt0hmoqYiyCBhBvr62S14lcBu2fSUipDsQ2 Mg/UhOJqwbcDCwhjR+nCQChCiSl2gqrgmlFZ5Vk= X-Google-Smtp-Source: AMrXdXs5Fr6pTQ4ubKSJ1+gmDGPJ+2DWqN6gSV987kbX+8FKfc1ipKed5YeyJSv0C5OXbDm23vAD7A== X-Received: by 2002:a6b:d118:0:b0:6ec:c7a1:d580 with SMTP id l24-20020a6bd118000000b006ecc7a1d580mr61750214iob.0.1673817384539; Sun, 15 Jan 2023 13:16:24 -0800 (PST) Received: from sjg1.roam.corp.google.com (c-73-14-173-85.hsd1.co.comcast.net. [73.14.173.85]) by smtp.gmail.com with ESMTPSA id j6-20020a6bf906000000b007046e9e138esm4329107iog.22.2023.01.15.13.16.24 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 15 Jan 2023 13:16:24 -0800 (PST) From: Simon Glass To: U-Boot Mailing List Cc: Tom Rini , Heinrich Schuchardt , Simon Glass Subject: [PATCH 02/24] sandbox: Expand the space for sandbox_vpl Date: Sun, 15 Jan 2023 14:15:39 -0700 Message-Id: <20230115211602.1127661-3-sjg@chromium.org> X-Mailer: git-send-email 2.39.0.314.g84b9a713c41-goog In-Reply-To: <20230115211602.1127661-1-sjg@chromium.org> References: <20230115211602.1127661-1-sjg@chromium.org> MIME-Version: 1.0 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.39 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.103.6 at phobos.denx.de X-Virus-Status: Clean This is quite near the limit so add a little more space. Signed-off-by: Simon Glass --- arch/sandbox/dts/sandbox_vpl.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/sandbox/dts/sandbox_vpl.dtsi b/arch/sandbox/dts/sandbox_vpl.dtsi index 1fba537f135..6966eeff7b3 100644 --- a/arch/sandbox/dts/sandbox_vpl.dtsi +++ b/arch/sandbox/dts/sandbox_vpl.dtsi @@ -17,8 +17,8 @@ * provide plenty of space for ELF files with debug info so that * gdb can be used */ - offset = <0x400000>; - size = <0xdffc00>; + offset = <0x500000>; + size = <0xcffc00>; fit { fit,external-offset = <0>; From patchwork Sun Jan 15 21:15:40 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 1726824 X-Patchwork-Delegate: trini@ti.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=2a01:238:438b:c500:173d:9f52:ddab:ee01; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: legolas.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=chromium.org header.i=@chromium.org header.a=rsa-sha256 header.s=google header.b=MMmz4Lyd; dkim-atps=neutral Received: from phobos.denx.de (phobos.denx.de [IPv6:2a01:238:438b:c500:173d:9f52:ddab:ee01]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4Nw7Jl6lJfz23fk for ; Mon, 16 Jan 2023 08:17:11 +1100 (AEDT) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 19AA185565; Sun, 15 Jan 2023 22:16:38 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=chromium.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (1024-bit key; unprotected) header.d=chromium.org header.i=@chromium.org header.b="MMmz4Lyd"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id 3F66F8551E; Sun, 15 Jan 2023 22:16:32 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,SPF_HELO_NONE, SPF_PASS autolearn=unavailable autolearn_force=no version=3.4.2 Received: from mail-io1-xd2c.google.com (mail-io1-xd2c.google.com [IPv6:2607:f8b0:4864:20::d2c]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id C37CB85582 for ; Sun, 15 Jan 2023 22:16:26 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=chromium.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=sjg@chromium.org Received: by mail-io1-xd2c.google.com with SMTP id 203so2201935iou.13 for ; Sun, 15 Jan 2023 13:16:26 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=KXcTfE+i2q4S0j1IYOaCEjMpRJAWufJuV9DcLv2njOs=; b=MMmz4Lydggbm1c6AlBtJyjyPYF97/UxbJ7HzBBEJjTnXRCkGKxoyxLmpoH34ENU0Vd QIx9WtyZGsrxQGyyjFF2lbXerb5XqNR3rDrbTLqORP4Y8J2pUT7eRiDpRbUS4vi6RN7y FDi/epXs/iJnYr8L9heytm+6XBe0cmsphvTCY= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=KXcTfE+i2q4S0j1IYOaCEjMpRJAWufJuV9DcLv2njOs=; b=GxwIIV2CG7lqoKvuFZ9cqb6Lonb7CQdaYFc9dCCigX3RFG+qD3NM6e0aRV5IRNfc5h MtYFa+nbmfcIEYsr2ovqaDHwpV94nvvdh5VVCRxFWnixR4Nd1otnoLQmssMLOmLNrhRh xtPqL8vM9LmzGaxThtz46TdAwEDE7jU+zrGXmkLMRZuaeFtn0qC1bHt9UQAHC8YcN7F6 5F/zre3J0DC4iY9Df7jU/5SPDqnklEvzBkngEt+jo9+KJoP0zA3oEEk56BS8oXt8tuQI ePWTTtqFwVwqlmjlJTq4DDCbYCfip2HN08sMbqZ/VJrwSw6QFg1PoOSyO77q33ImQfs4 +4VA== X-Gm-Message-State: AFqh2kpQrcV8v2DAI5VqQXpacojHyOuuUELCCL76eIx7vcg9x0x6nJec a2kwl4iInuVHGzAFLoXAA1wvgj0WHEDvO8YyIQc= X-Google-Smtp-Source: AMrXdXsjxhrZwkY+Ugkwsw4LYOxXI9WcF2EcpVnVF/K9w+EwIduEMT0OemkTYsHAFul9j7O00+TKPA== X-Received: by 2002:a5d:97d1:0:b0:6e2:e5ee:c437 with SMTP id k17-20020a5d97d1000000b006e2e5eec437mr11413595ios.1.1673817385377; Sun, 15 Jan 2023 13:16:25 -0800 (PST) Received: from sjg1.roam.corp.google.com (c-73-14-173-85.hsd1.co.comcast.net. [73.14.173.85]) by smtp.gmail.com with ESMTPSA id j6-20020a6bf906000000b007046e9e138esm4329107iog.22.2023.01.15.13.16.24 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 15 Jan 2023 13:16:25 -0800 (PST) From: Simon Glass To: U-Boot Mailing List Cc: Tom Rini , Heinrich Schuchardt , Simon Glass , Bin Meng , Michal Suchanek , Ovidiu Panait , =?utf-8?q?Pali_Roh=C3=A1r?= , Rasmus Villemoes , Rick Chen , Stefan Roese Subject: [PATCH 03/24] sandbox: Bring back setting mon_len in global_data Date: Sun, 15 Jan 2023 14:15:40 -0700 Message-Id: <20230115211602.1127661-4-sjg@chromium.org> X-Mailer: git-send-email 2.39.0.314.g84b9a713c41-goog In-Reply-To: <20230115211602.1127661-1-sjg@chromium.org> References: <20230115211602.1127661-1-sjg@chromium.org> MIME-Version: 1.0 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.39 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.103.6 at phobos.denx.de X-Virus-Status: Clean This change was made for the benefit of RISC-V but broke other architectures also. In particular, tracing cannot work without this value. Add it back for architectures which support it. Fixes: 3c9fc23c443 ("sandbox: don't refer to symbol _init") Signed-off-by: Simon Glass --- common/board_f.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/common/board_f.c b/common/board_f.c index 2b4edf30c93..f3c1ab53b1c 100644 --- a/common/board_f.c +++ b/common/board_f.c @@ -290,7 +290,10 @@ static int setup_mon_len(void) { #if defined(__ARM__) || defined(__MICROBLAZE__) gd->mon_len = (ulong)&__bss_end - (ulong)_start; +#elif defined(CONFIG_SANDBOX) && !defined(__riscv) + gd->mon_len = (ulong)&_end - (ulong)_init; #elif defined(CONFIG_SANDBOX) + /* gcc does not provide _init in crti.o on RISC-V */ gd->mon_len = 0; #elif defined(CONFIG_EFI_APP) gd->mon_len = (ulong)&_end - (ulong)_init; From patchwork Sun Jan 15 21:15:41 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 1726825 X-Patchwork-Delegate: trini@ti.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=2a01:238:438b:c500:173d:9f52:ddab:ee01; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: legolas.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=chromium.org header.i=@chromium.org header.a=rsa-sha256 header.s=google header.b=PI2xV/+4; dkim-atps=neutral Received: from phobos.denx.de (phobos.denx.de [IPv6:2a01:238:438b:c500:173d:9f52:ddab:ee01]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4Nw7Jy24Lhz23fk for ; Mon, 16 Jan 2023 08:17:22 +1100 (AEDT) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id DA7248559D; Sun, 15 Jan 2023 22:16:42 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=chromium.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (1024-bit key; unprotected) header.d=chromium.org header.i=@chromium.org header.b="PI2xV/+4"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id 01BA58551E; Sun, 15 Jan 2023 22:16:33 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,SPF_HELO_NONE, SPF_PASS autolearn=unavailable autolearn_force=no version=3.4.2 Received: from mail-io1-xd36.google.com (mail-io1-xd36.google.com [IPv6:2607:f8b0:4864:20::d36]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id 9CA4785531 for ; Sun, 15 Jan 2023 22:16:27 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=chromium.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=sjg@chromium.org Received: by mail-io1-xd36.google.com with SMTP id e129so12857390iof.3 for ; Sun, 15 Jan 2023 13:16:27 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=npNG1+qEcTdsSTiVh7C2n9xddC2f8W3kC1I2CePNgX8=; b=PI2xV/+49k6tkmgGmmvGJax10bWgWSYa2Ud9ED0I+ROdWuSWQB+DnMx54CV1eXh8bJ V8xjz2CVonkbdECFwAqftwteL6Eh4msugQPVJ+HAVkXiA3l7Y4p69kNNpSUcH/Hm7OmL L0vSO67CqFsi8rs9Lv3Csz1AQC9aDArptkoXw= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=npNG1+qEcTdsSTiVh7C2n9xddC2f8W3kC1I2CePNgX8=; b=ouS4vJslZdpmVbKil8cz8qMHrYjxmBawVjM+fRJ1nOCqHyYI/ZEnEagfz2ic7JZxPA Ltsu1/uk/ax0V6BWdpYk2d3CYivtoBNEFSwfL3AwF6hXaY7FVlt2/gJ20OoY5RATkExT G69zR7EtgYeRm1j243SF+AUOmwQrXHpoZNaWuh2gjle+Y/JUnzsPiWaEiCuQu6vFQb3C /WQQepYP+EOb1A+b1R0sR9LKS9c1IOzyoxHbcu7RDSH+ihn2I/XpVknhRTMeEwfy5cTM ywFQ1pV1TZe3BR5rBYbe5cNXwPgxd35IiLLvgZE7Bm8IFFfTclctWgzVnteqC0q3oHH0 j/Cw== X-Gm-Message-State: AFqh2krCQSkH639ASVb6c/Qm3nuTMBv9eIAho2NyRIaKbLHskwHtVVOp R6/B070ElJgmK2e/o4wm3V9AFHWIUBMirZ15oYE= X-Google-Smtp-Source: AMrXdXtGsc/aqc7VHiMFfWc6ABX98+JpG26VdReW3pvyZHepYTR4ILpYq/HMPe+AY7DuUL7KxOBsNw== X-Received: by 2002:a05:6602:1789:b0:6bc:d712:8bbc with SMTP id y9-20020a056602178900b006bcd7128bbcmr64486845iox.4.1673817386219; Sun, 15 Jan 2023 13:16:26 -0800 (PST) Received: from sjg1.roam.corp.google.com (c-73-14-173-85.hsd1.co.comcast.net. [73.14.173.85]) by smtp.gmail.com with ESMTPSA id j6-20020a6bf906000000b007046e9e138esm4329107iog.22.2023.01.15.13.16.25 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 15 Jan 2023 13:16:26 -0800 (PST) From: Simon Glass To: U-Boot Mailing List Cc: Tom Rini , Heinrich Schuchardt , Simon Glass , Dzmitry Sankouski , Marek Vasut , Ovidiu Panait , Pavel Herrmann , Rasmus Villemoes , Stefan Roese Subject: [PATCH 04/24] dm: Allow serial output during the relocation process Date: Sun, 15 Jan 2023 14:15:41 -0700 Message-Id: <20230115211602.1127661-5-sjg@chromium.org> X-Mailer: git-send-email 2.39.0.314.g84b9a713c41-goog In-Reply-To: <20230115211602.1127661-1-sjg@chromium.org> References: <20230115211602.1127661-1-sjg@chromium.org> MIME-Version: 1.0 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.39 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.103.6 at phobos.denx.de X-Virus-Status: Clean Reset the serial flags so that the debug UART can be used (if enabled) in the small window where there is no serial device. This can avoid a hang in some cases. Signed-off-by: Simon Glass --- common/board_r.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/common/board_r.c b/common/board_r.c index 3618acad437..5f3c3db476d 100644 --- a/common/board_r.c +++ b/common/board_r.c @@ -796,6 +796,15 @@ static init_fnc_t init_sequence_r[] = { void board_init_r(gd_t *new_gd, ulong dest_addr) { + /* + * The pre-relocation drivers may be using memory that has now gone + * away. Mark serial as unavailable - this will fall back to the debug + * UART if available. + * + * Do the same with log drivers since the memory may not be available. + */ + gd->flags &= ~(GD_FLG_SERIAL_READY | GD_FLG_LOG_READY); + /* * Set up the new global data pointer. So far only x86 does this * here. From patchwork Sun Jan 15 21:15:42 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 1726823 X-Patchwork-Delegate: trini@ti.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=2a01:238:438b:c500:173d:9f52:ddab:ee01; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: legolas.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=chromium.org header.i=@chromium.org header.a=rsa-sha256 header.s=google header.b=DAjlkCwL; dkim-atps=neutral Received: from phobos.denx.de (phobos.denx.de [IPv6:2a01:238:438b:c500:173d:9f52:ddab:ee01]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4Nw7JS5g9Zz23fk for ; Mon, 16 Jan 2023 08:16:56 +1100 (AEDT) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id D214D85527; Sun, 15 Jan 2023 22:16:35 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=chromium.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (1024-bit key; unprotected) header.d=chromium.org header.i=@chromium.org header.b="DAjlkCwL"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id C3A608551E; Sun, 15 Jan 2023 22:16:31 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,SPF_HELO_NONE, SPF_PASS autolearn=ham autolearn_force=no version=3.4.2 Received: from mail-io1-xd33.google.com (mail-io1-xd33.google.com [IPv6:2607:f8b0:4864:20::d33]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id 85776850D5 for ; Sun, 15 Jan 2023 22:16:27 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=chromium.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=sjg@chromium.org Received: by mail-io1-xd33.google.com with SMTP id v65so8555459ioe.4 for ; Sun, 15 Jan 2023 13:16:27 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=ZHNkOOuL28i2YXkl9eWSzT+cAqH3dIvojnZv5cxJyTM=; b=DAjlkCwLHogg+qn/fFX7va61KEekmkCjhbRAhdSDRr94z/KcpfvuqA2XTxZJcVvgWA ud2uic3gB/XrgTWP6z/xG8l1QooY07lo6xsCaOMUptJtNV8u/S7Nd0NVoz8d2B9qjdEa Aih0ptiFuNJ/WLnPw20PZGBg0crX6fptj2VAM= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=ZHNkOOuL28i2YXkl9eWSzT+cAqH3dIvojnZv5cxJyTM=; b=Ey6wvfC3qum8y+8enhCbCKIujwNtgSdanTS98eHGJ3U6pLm/lFerXdcVNHVcZBDyaj CbXnMjTAQOyE1kuCZwtSvwYcw0hDgxFD9Wj4zQ8nJf3qOM7Ym027qcZEHnCILmO3oJ1L 00yh2YUWdTx94MnSK9xWliqfWWVfD97XalcRsDa7V/JlQycrdCf1a2Zow7rAK4AkNJRs G5cBHGEUjDQEfgz+4hSgLMp+8vvt5BsiBzByq06fvVmcONW2IEPLDKF01F3oY9L2stqU aiat229tbD6ZiAekXI2kYipS5enjMEdNkedxwQk7JnFDzZhVLclKFQAuGlqA+w5Q0zo7 JKPg== X-Gm-Message-State: AFqh2kpCnO2M0zi52Xd0x8AS8Uw4Jf0Xy43up8nbKAG7nuyjeUdni8JS X4WD+Pk0zs5SztTsVNvfDikLMPCBeFkcySWBrEc= X-Google-Smtp-Source: AMrXdXv1NWH6Y3pJIMjQrczUJcF5ZjBJOfje96zz69lO+C3Xa1YbpSTBIbEo/at0gY7DNxErCCTxWg== X-Received: by 2002:a5d:9f57:0:b0:6dd:9df2:504e with SMTP id u23-20020a5d9f57000000b006dd9df2504emr53860863iot.18.1673817386984; Sun, 15 Jan 2023 13:16:26 -0800 (PST) Received: from sjg1.roam.corp.google.com (c-73-14-173-85.hsd1.co.comcast.net. [73.14.173.85]) by smtp.gmail.com with ESMTPSA id j6-20020a6bf906000000b007046e9e138esm4329107iog.22.2023.01.15.13.16.26 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 15 Jan 2023 13:16:26 -0800 (PST) From: Simon Glass To: U-Boot Mailing List Cc: Tom Rini , Heinrich Schuchardt , Simon Glass , Michal Simek , Ovidiu Panait Subject: [PATCH 05/24] timer: Tidy up use of notrace Date: Sun, 15 Jan 2023 14:15:42 -0700 Message-Id: <20230115211602.1127661-6-sjg@chromium.org> X-Mailer: git-send-email 2.39.0.314.g84b9a713c41-goog In-Reply-To: <20230115211602.1127661-1-sjg@chromium.org> References: <20230115211602.1127661-1-sjg@chromium.org> MIME-Version: 1.0 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.39 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.103.6 at phobos.denx.de X-Virus-Status: Clean Tracing is typically enabled by the time driver model starts up, so there is no point in adding a 'notrace' to the timer-init function. However, once the driver model timer is enabled, we do need to be able to access the timer's private data when reading the timer, so add it to the core function needed for that. Update the function's documentation while we are here. Signed-off-by: Simon Glass --- drivers/core/device.c | 3 ++- drivers/timer/timer-uclass.c | 2 +- include/timer.h | 13 +++++++++---- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/drivers/core/device.c b/drivers/core/device.c index d9ce546c0c4..6e26b64fb81 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -654,7 +654,8 @@ void *dev_get_priv(const struct udevice *dev) return dm_priv_to_rw(dev->priv_); } -void *dev_get_uclass_priv(const struct udevice *dev) +/* notrace is needed as this is called by timer_get_rate() */ +notrace void *dev_get_uclass_priv(const struct udevice *dev) { if (!dev) { dm_warn("%s: null device\n", __func__); diff --git a/drivers/timer/timer-uclass.c b/drivers/timer/timer-uclass.c index bb719792135..f4b871ac23a 100644 --- a/drivers/timer/timer-uclass.c +++ b/drivers/timer/timer-uclass.c @@ -136,7 +136,7 @@ u64 timer_conv_64(u32 count) return ((u64)gd->timebase_h << 32) | gd->timebase_l; } -int notrace dm_timer_init(void) +int dm_timer_init(void) { struct udevice *dev = NULL; __maybe_unused ofnode node; diff --git a/include/timer.h b/include/timer.h index d33a26e28fe..311ce6b2c3a 100644 --- a/include/timer.h +++ b/include/timer.h @@ -9,11 +9,16 @@ #define timer_get_ops(dev) ((struct timer_ops *)(dev)->driver->ops) /** - * dm_timer_init() - initialize a timer for time keeping. On success - * initializes gd->timer so that lib/timer can use it for future - * referrence. + * dm_timer_init() - set up a timer for time keeping * - * Return: 0 on success or error number + * Sets up gd->timer if the device is not already bound, making sure it is + * probed and ready for use + * + * On success, inits gd->timer so that lib/timer can use it for future reference + * + * Returns: 0 on success, -EAGAIN if driver model is not ready yet, -ENODEV if + * no timer could be found, other error if the timer could not be bound or + * probed */ int dm_timer_init(void); From patchwork Sun Jan 15 21:15:43 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 1726828 X-Patchwork-Delegate: trini@ti.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=85.214.62.61; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: legolas.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=chromium.org header.i=@chromium.org header.a=rsa-sha256 header.s=google header.b=dQAiGMX1; dkim-atps=neutral Received: from phobos.denx.de (phobos.denx.de [85.214.62.61]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4Nw7Kc0nD0z23fk for ; Mon, 16 Jan 2023 08:17:56 +1100 (AEDT) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 762918555D; Sun, 15 Jan 2023 22:16:51 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=chromium.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (1024-bit key; unprotected) header.d=chromium.org header.i=@chromium.org header.b="dQAiGMX1"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id 57AB985595; Sun, 15 Jan 2023 22:16:35 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,SPF_HELO_NONE, SPF_PASS autolearn=unavailable autolearn_force=no version=3.4.2 Received: from mail-io1-xd2e.google.com (mail-io1-xd2e.google.com [IPv6:2607:f8b0:4864:20::d2e]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id 52EF58554F for ; Sun, 15 Jan 2023 22:16:29 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=chromium.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=sjg@chromium.org Received: by mail-io1-xd2e.google.com with SMTP id z194so1037305iof.10 for ; Sun, 15 Jan 2023 13:16:29 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=Jt3eyNFVHlkNPh+FEFmGTiW0nTGbpFBjQVEP+AzIn6I=; b=dQAiGMX1EJFgBvtTcWlcAuJHrGZS8505patHWwKrMs6uCVdM3jgtu8xqVi2HQLSgy2 7wM99Th0pChKL0pkTl8ltkmOo3kj44oL67/QiC4dn1OqNDMwLx06+Weipi/3LbikmMe5 KmFrNl/AhmZfVLTrrGenPwhoUEBGSi89LA1f0= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=Jt3eyNFVHlkNPh+FEFmGTiW0nTGbpFBjQVEP+AzIn6I=; b=aNxSTmbYRh9VvRG4FGtBHIhRQziuwGUzUc3ezp/RiAg8NurclcLVYPHxl1yhZejmEL /Qih1wt/XhDuThnus2yAWLlRfcyoeeIR80lgTNOMl4y+KimXVTg4YLBFftAOf7kxbS3h oYj/+dgwU5sR8+PISMmB2dOFLVy86yS21E7gxTYcq/H5r5sAA2BXanX9R9ayU2uR/Xch TDZ+zf946q0FN5D7BVo/qqycmhCnm1JQpQHnlDTbAXdlZoxPKQJ/wfF9NWHNXVVByS/e sIUS/+ZnTCmck30iiLKBNGdDBtIXSTCnwoO6WH8t8ytcdXh+qXj9fnrc96KTyEW9lVKw tlow== X-Gm-Message-State: AFqh2krICxtfyiwfceScnUeffsONo20DGFlDjqorKimOLsk+VSGGzFlx C1cT12Yr4E6Px6tzNeOBK4KvgP/VoWHIfFVjL90= X-Google-Smtp-Source: AMrXdXuFcGdmUqNamxlQaz0DVDQ3tHGR118pR0z89ZQrkWA/pSfGpSQmNlkVOTk6/tMzv+aE3GZNog== X-Received: by 2002:a6b:7519:0:b0:6e9:b3cc:f1a with SMTP id l25-20020a6b7519000000b006e9b3cc0f1amr58748634ioh.8.1673817387809; Sun, 15 Jan 2023 13:16:27 -0800 (PST) Received: from sjg1.roam.corp.google.com (c-73-14-173-85.hsd1.co.comcast.net. [73.14.173.85]) by smtp.gmail.com with ESMTPSA id j6-20020a6bf906000000b007046e9e138esm4329107iog.22.2023.01.15.13.16.27 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 15 Jan 2023 13:16:27 -0800 (PST) From: Simon Glass To: U-Boot Mailing List Cc: Tom Rini , Heinrich Schuchardt , Simon Glass , Harald Seiler , Michael Walle , =?utf-8?q?Pali_Roh=C3=A1r?= , Stefan Roese Subject: [PATCH 06/24] time: Tidy up some unnecessary #ifdefs Date: Sun, 15 Jan 2023 14:15:43 -0700 Message-Id: <20230115211602.1127661-7-sjg@chromium.org> X-Mailer: git-send-email 2.39.0.314.g84b9a713c41-goog In-Reply-To: <20230115211602.1127661-1-sjg@chromium.org> References: <20230115211602.1127661-1-sjg@chromium.org> MIME-Version: 1.0 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.39 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.103.6 at phobos.denx.de X-Virus-Status: Clean Avoid using the preprocessor with TIMER_EARLY. Signed-off-by: Simon Glass --- lib/time.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/lib/time.c b/lib/time.c index 0c95d12f614..1ef58f92cd1 100644 --- a/lib/time.c +++ b/lib/time.c @@ -70,15 +70,14 @@ extern unsigned long timer_read_counter(void); ulong notrace get_tbclk(void) { if (!gd->timer) { -#ifdef CONFIG_TIMER_EARLY - return timer_early_get_rate(); -#else int ret; + if (IS_ENABLED(CONFIG_TIMER_EARLY)) + return timer_early_get_rate(); + ret = dm_timer_init(); if (ret) return ret; -#endif } return timer_get_rate(gd->timer); @@ -90,15 +89,14 @@ uint64_t notrace get_ticks(void) int ret; if (!gd->timer) { -#ifdef CONFIG_TIMER_EARLY - return timer_early_get_count(); -#else int ret; + if (IS_ENABLED(CONFIG_TIMER_EARLY)) + return timer_early_get_count(); + ret = dm_timer_init(); if (ret) panic("Could not initialize timer (err %d)\n", ret); -#endif } ret = timer_get_count(gd->timer, &count); From patchwork Sun Jan 15 21:15:44 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 1726826 X-Patchwork-Delegate: trini@ti.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=85.214.62.61; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: legolas.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=chromium.org header.i=@chromium.org header.a=rsa-sha256 header.s=google header.b=PVE9b8b4; dkim-atps=neutral Received: from phobos.denx.de (phobos.denx.de [85.214.62.61]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4Nw7K95xggz23fk for ; Mon, 16 Jan 2023 08:17:33 +1100 (AEDT) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 09CC085582; Sun, 15 Jan 2023 22:16:45 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=chromium.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (1024-bit key; unprotected) header.d=chromium.org header.i=@chromium.org header.b="PVE9b8b4"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id 9A39D8557C; Sun, 15 Jan 2023 22:16:34 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,SPF_HELO_NONE, SPF_PASS autolearn=ham autolearn_force=no version=3.4.2 Received: from mail-io1-xd32.google.com (mail-io1-xd32.google.com [IPv6:2607:f8b0:4864:20::d32]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id 1B09C855A1 for ; Sun, 15 Jan 2023 22:16:29 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=chromium.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=sjg@chromium.org Received: by mail-io1-xd32.google.com with SMTP id p66so12868280iof.1 for ; Sun, 15 Jan 2023 13:16:29 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=ymElxoWrLvK99/mieR22dzVhRM4Jf9k7oaQ9sEdZHGE=; b=PVE9b8b4klogb4VR8HgWiLMbvW77f2j5IztsWfgMMG8jHw6XQnUb9JpX+e7ewWOlN4 C7barKsJx5uMeKMoawR6ktN9RqnwQMV+8fn5U8Kp1I+9Z0bfAeAlXLk98bN9mecu09Ay aTrTuGC1ElJ7fbfmLDK1m+RDeA7DxhoZXyD+4= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=ymElxoWrLvK99/mieR22dzVhRM4Jf9k7oaQ9sEdZHGE=; b=eVnVKNEtmVzHzQdY4nKHiwXRXj/slPhaBhTZyfadUnCSNujl2U+1rAvoF4AE/LWOWQ I5dzW9BgS6icfggF1Aq0FduuxiJyzOBLHsKf0kZtoHRHIO32vFn42Erph9hjJwP7sUh5 VmrUFxy7Vd7QwKpYCxhIv4xgFcB27Gov++GVDkotRc4rLkQNMGA5uZ7PZPtRujx1xCTA hDMbM8FxbC8m2rgrMZZhuqWJeVbIvNal1WhIMLFAD3hbSz8EM56UTSmJaXqUsvc0t5By 6L61ybaCX+r5rHZP3rvga7FFNUY1TA72bNnn1qHNx/DBSkwFvJTkw1WIrF7uPDlDi7EG d9EQ== X-Gm-Message-State: AFqh2krZ//iCvKiCOdc9EbXsoFdDT8GXXbKOBd0qaSpsE74ly5+bW5Bw OXDF/kibsXmq748dvvzkY0q1Z2lXXmwMhIYGl5U= X-Google-Smtp-Source: AMrXdXtz13/Q2wIMwZb2IBoRWD29PJ5ahFqN3GVB2Nf1DT4mT7amaGL7FmOkWWE2e/3xe98P0yPgpw== X-Received: by 2002:a5e:de0a:0:b0:704:bc96:24bd with SMTP id e10-20020a5ede0a000000b00704bc9624bdmr632862iok.19.1673817388626; Sun, 15 Jan 2023 13:16:28 -0800 (PST) Received: from sjg1.roam.corp.google.com (c-73-14-173-85.hsd1.co.comcast.net. [73.14.173.85]) by smtp.gmail.com with ESMTPSA id j6-20020a6bf906000000b007046e9e138esm4329107iog.22.2023.01.15.13.16.28 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 15 Jan 2023 13:16:28 -0800 (PST) From: Simon Glass To: U-Boot Mailing List Cc: Tom Rini , Heinrich Schuchardt , Simon Glass , Ilias Apalodimas , Kautuk Consul , Philippe Reynes , Rasmus Villemoes , Sughosh Ganu Subject: [PATCH 07/24] trace: Reduce the default for TRACE_EARLY_CALL_DEPTH_LIMIT Date: Sun, 15 Jan 2023 14:15:44 -0700 Message-Id: <20230115211602.1127661-8-sjg@chromium.org> X-Mailer: git-send-email 2.39.0.314.g84b9a713c41-goog In-Reply-To: <20230115211602.1127661-1-sjg@chromium.org> References: <20230115211602.1127661-1-sjg@chromium.org> MIME-Version: 1.0 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.39 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.103.6 at phobos.denx.de X-Virus-Status: Clean This is a silly value at present, since U-Boot's call depth never reaches 200. Fix it. Signed-off-by: Simon Glass --- lib/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Kconfig b/lib/Kconfig index a83f32d82a5..11968a0c531 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -368,7 +368,7 @@ config TRACE_EARLY_SIZE config TRACE_EARLY_CALL_DEPTH_LIMIT int "Early trace call depth limit" depends on TRACE_EARLY - default 200 + default 15 help Sets the maximum call depth up to which function calls are recorded during early tracing. From patchwork Sun Jan 15 21:15:45 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 1726827 X-Patchwork-Delegate: trini@ti.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=85.214.62.61; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: legolas.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=chromium.org header.i=@chromium.org header.a=rsa-sha256 header.s=google header.b=SK0Tp3rs; dkim-atps=neutral Received: from phobos.denx.de (phobos.denx.de [85.214.62.61]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4Nw7KN73Kmz23fk for ; Mon, 16 Jan 2023 08:17:44 +1100 (AEDT) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id DD7AE855B7; Sun, 15 Jan 2023 22:16:47 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=chromium.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (1024-bit key; unprotected) header.d=chromium.org header.i=@chromium.org header.b="SK0Tp3rs"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id 84D3A85527; Sun, 15 Jan 2023 22:16:35 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,SPF_HELO_NONE, SPF_PASS autolearn=ham autolearn_force=no version=3.4.2 Received: from mail-io1-xd32.google.com (mail-io1-xd32.google.com [IPv6:2607:f8b0:4864:20::d32]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id C6C518556A for ; Sun, 15 Jan 2023 22:16:29 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=chromium.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=sjg@chromium.org Received: by mail-io1-xd32.google.com with SMTP id p66so12868288iof.1 for ; Sun, 15 Jan 2023 13:16:29 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=fKVUwwOBrBnbKfrtJ6aCH9+nx5StFSYIC9IIrNzx4Qc=; b=SK0Tp3rsDvNkqYWEwaf2MfVZNiK19DaUVtQK827mqWef8vCbt1KTAMjEWbKsW0ollI weWrfTWbn36B2NjGHMnytHAEQyDz3NZfQoRqwQZ8XAyqoaBojNqYyqcLgtVO7MhVHwoa ixnG0DbEHoai8XqunLIHVJJFMtiqO/LKL18vM= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=fKVUwwOBrBnbKfrtJ6aCH9+nx5StFSYIC9IIrNzx4Qc=; b=G6eRsB7YPopeC9efwNNHPyXdcv3CFUK3jGzV8AeB8a92tZVhj/cf3wV37kUHgDtjHp RvtDoLZy3/kV5FI4tUE0uXTAB590r3MT7cfznc+wozm3rvPmZfBPYu5h2fds+d2FYnF+ 4QTudHMg8VsRqYIOr6yNWcXRb5LMZ/TKKlXAHynDHjKC+SVRu6u7fFWD88dW/2UxyFjA VZnhN+1SKjz4v6bOcwcSQytEuR/liXWaw+Aq0oLMrRtL1galFb+FWWJsGMfWFqU8MUUc jiqn6zTpmASCZWjYTFSKbjfu5PvglcY14XbSn8Ly6DAHgHgIpvGfsUaZ+d0pZaslgjFE vKOQ== X-Gm-Message-State: AFqh2kr5I2SacaIQkVdi/GajvEK5NzCda/EuttbLOBHJy8kGeT8fSW4U sz0BBQygTOWmCZXKd8jA03CkO4BrUp/TZWYf5jk= X-Google-Smtp-Source: AMrXdXuRsA0WFkzlOzUPS8KrxmWjQ/sZ9b2r8pv0rW9mMVjCn9O4XXBfYr5nMNCVPxUCBeb7WtE94Q== X-Received: by 2002:a5e:9e0d:0:b0:6df:dc79:a1f2 with SMTP id i13-20020a5e9e0d000000b006dfdc79a1f2mr56960708ioq.11.1673817389341; Sun, 15 Jan 2023 13:16:29 -0800 (PST) Received: from sjg1.roam.corp.google.com (c-73-14-173-85.hsd1.co.comcast.net. [73.14.173.85]) by smtp.gmail.com with ESMTPSA id j6-20020a6bf906000000b007046e9e138esm4329107iog.22.2023.01.15.13.16.28 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 15 Jan 2023 13:16:29 -0800 (PST) From: Simon Glass To: U-Boot Mailing List Cc: Tom Rini , Heinrich Schuchardt , Simon Glass Subject: [PATCH 08/24] abuf: Support use from tools Date: Sun, 15 Jan 2023 14:15:45 -0700 Message-Id: <20230115211602.1127661-9-sjg@chromium.org> X-Mailer: git-send-email 2.39.0.314.g84b9a713c41-goog In-Reply-To: <20230115211602.1127661-1-sjg@chromium.org> References: <20230115211602.1127661-1-sjg@chromium.org> MIME-Version: 1.0 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.39 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.103.6 at phobos.denx.de X-Virus-Status: Clean Update the code slightly so that abuf can be used in U-Boot tools. It will soon be needed for proftool. Signed-off-by: Simon Glass --- lib/abuf.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/lib/abuf.c b/lib/abuf.c index 1635d58682c..bd270467dd4 100644 --- a/lib/abuf.c +++ b/lib/abuf.c @@ -6,11 +6,14 @@ * Written by Simon Glass */ +#ifndef USE_HOSTCC #include -#include #include #include #include +#endif + +#include void abuf_set(struct abuf *abuf, void *data, size_t size) { @@ -19,10 +22,26 @@ void abuf_set(struct abuf *abuf, void *data, size_t size) abuf->size = size; } +#ifndef USE_HOSTCC void abuf_map_sysmem(struct abuf *abuf, ulong addr, size_t size) { abuf_set(abuf, map_sysmem(addr, size), size); } +#else +/* copied from lib/string.c for convenience */ +static char *memdup(const void *src, size_t len) +{ + char *p; + + p = malloc(len); + if (!p) + return NULL; + + memcpy(p, src, len); + + return p; +} +#endif bool abuf_realloc(struct abuf *abuf, size_t new_size) { From patchwork Sun Jan 15 21:15:46 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 1726829 X-Patchwork-Delegate: trini@ti.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=2a01:238:438b:c500:173d:9f52:ddab:ee01; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: legolas.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=chromium.org header.i=@chromium.org header.a=rsa-sha256 header.s=google header.b=bVDDKEEi; dkim-atps=neutral Received: from phobos.denx.de (phobos.denx.de [IPv6:2a01:238:438b:c500:173d:9f52:ddab:ee01]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4Nw7Kq1d1gz23fk for ; Mon, 16 Jan 2023 08:18:07 +1100 (AEDT) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 8B12A85598; Sun, 15 Jan 2023 22:16:53 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=chromium.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (1024-bit key; unprotected) header.d=chromium.org header.i=@chromium.org header.b="bVDDKEEi"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id D311F855BA; Sun, 15 Jan 2023 22:16:36 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,SPF_HELO_NONE, SPF_PASS autolearn=ham autolearn_force=no version=3.4.2 Received: from mail-io1-xd34.google.com (mail-io1-xd34.google.com [IPv6:2607:f8b0:4864:20::d34]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id 7DB39855AF for ; Sun, 15 Jan 2023 22:16:31 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=chromium.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=sjg@chromium.org Received: by mail-io1-xd34.google.com with SMTP id d22so4045921iof.5 for ; Sun, 15 Jan 2023 13:16:31 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=uRtj3eAxz2guJFx2vE0geIfOn20LvkEiQuf8PwzNEJ8=; b=bVDDKEEiqQODjf9ZFBFerfUkYs+fuzvyTWB4EWw85Ea3mV6C/PmEpa/D7hc/kZwICk EJ7pYlkaCPCDwzhSz1/+YSmUAhPbggkCgnPKm0hd+W8PduCxGvOA2LKUvBxHQLrWLcjd CM876mrjG3oABQvn9BSM5PvYsgXGhEiuZ8HAg= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=uRtj3eAxz2guJFx2vE0geIfOn20LvkEiQuf8PwzNEJ8=; b=bWg1BZUl9U/S+2nhHfH3/169ufj+uZkzNUzhV86s6DSyvvCXvH+iQpE7AhRtqVvmxb Af7gWG795kJ3kxbDEPYTF0ZihbBZ2L5UwhgRAwjxtj7DFDCeGEJbhZRp/LsI3ILRCDBv Ltc3aRNjx86KgnUO+6CGZFFbVwWOsEdvKVDq5izG1M1xCXZavo87KrNXLkb0oDHxo03t X1ZlfH96i4CsBpeMH6YCR+5asZoD9pUhijxABuoK7pEi8WN+adU4Bzx2ueSLx/Io5ltl Nl+7v4xSCpZd2V2rAYUKFAVm/Z5Z7zMuh5zdus2HOwsm8hx/AF4/zr3y62g+FfljP2/O NUOg== X-Gm-Message-State: AFqh2kpC1BY6QvYmKM2M7BE+0CAheaOsHD0ldnx16Gu6nRXArhfn7G/a FJXuNQBLaKZvBgpK1kphlVphZpLm4mt8vvHMiGw= X-Google-Smtp-Source: AMrXdXuWsdvWF60Sn/refhzD+KLntVhV8H4OzVlZH+B6LaqzFXodY0gIlroBN9gRS6rS9yLEDHtHoQ== X-Received: by 2002:a05:6602:2489:b0:704:980d:f951 with SMTP id g9-20020a056602248900b00704980df951mr5659942ioe.8.1673817390010; Sun, 15 Jan 2023 13:16:30 -0800 (PST) Received: from sjg1.roam.corp.google.com (c-73-14-173-85.hsd1.co.comcast.net. [73.14.173.85]) by smtp.gmail.com with ESMTPSA id j6-20020a6bf906000000b007046e9e138esm4329107iog.22.2023.01.15.13.16.29 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 15 Jan 2023 13:16:29 -0800 (PST) From: Simon Glass To: U-Boot Mailing List Cc: Tom Rini , Heinrich Schuchardt , Simon Glass Subject: [PATCH 09/24] trace: Update the file header Date: Sun, 15 Jan 2023 14:15:46 -0700 Message-Id: <20230115211602.1127661-10-sjg@chromium.org> X-Mailer: git-send-email 2.39.0.314.g84b9a713c41-goog In-Reply-To: <20230115211602.1127661-1-sjg@chromium.org> References: <20230115211602.1127661-1-sjg@chromium.org> MIME-Version: 1.0 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.39 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.103.6 at phobos.denx.de X-Virus-Status: Clean It seems better to put the TEXT_BASE value in the file header rather than in an entry record. While it is true that there is a separate base for pre-relocation, this can be handled by using offsets in the file. It is useful to have a version number in case we need to change the trace format again. Update the header to make these changes. Signed-off-by: Simon Glass --- include/trace.h | 12 ++++++++++-- lib/trace.c | 19 ++++--------------- 2 files changed, 14 insertions(+), 17 deletions(-) diff --git a/include/trace.h b/include/trace.h index e7aee024f03..2be8d81b515 100644 --- a/include/trace.h +++ b/include/trace.h @@ -6,6 +6,8 @@ #ifndef __TRACE_H #define __TRACE_H +/* this file is included from a tool so uses uint32_t instead of u32, etc. */ + enum { /* * This affects the granularity of our trace. We can bin function @@ -23,6 +25,8 @@ enum { * this value. */ FUNC_SITE_SIZE = 4, /* distance between function sites */ + + TRACE_VERSION = 1, }; enum trace_chunk_type { @@ -39,7 +43,11 @@ struct trace_output_func { /* A header at the start of the trace output buffer */ struct trace_output_hdr { enum trace_chunk_type type; /* Record type */ - size_t rec_count; /* Number of records */ + uint32_t version; /* Version (TRACE_VERSION) */ + uint32_t rec_count; /* Number of records */ + uint32_t spare; /* 0 */ + uint64_t text_base; /* Value of CONFIG_TEXT_BASE */ + uint64_t spare2; /* 0 */ }; /* Print statistics about traced function calls */ @@ -63,7 +71,7 @@ int trace_list_functions(void *buff, size_t buff_size, size_t *needed); enum ftrace_flags { FUNCF_EXIT = 0UL << 30, FUNCF_ENTRY = 1UL << 30, - FUNCF_TEXTBASE = 2UL << 30, + /* two more values are available */ FUNCF_TIMESTAMP_MASK = 0x3fffffff, }; diff --git a/lib/trace.c b/lib/trace.c index b9dc6d2e4b5..2e2c1bed54f 100644 --- a/lib/trace.c +++ b/lib/trace.c @@ -118,18 +118,6 @@ static void notrace add_ftrace(void *func_ptr, void *caller, ulong flags) hdr->ftrace_count++; } -static void notrace add_textbase(void) -{ - if (hdr->ftrace_count < hdr->ftrace_size) { - struct trace_call *rec = &hdr->ftrace[hdr->ftrace_count]; - - rec->func = CONFIG_TEXT_BASE; - rec->caller = 0; - rec->flags = FUNCF_TEXTBASE; - } - hdr->ftrace_count++; -} - /** * __cyg_profile_func_enter() - record function entry * @@ -278,8 +266,11 @@ int trace_list_calls(void *buff, size_t buff_size, size_t *needed) /* Update the header */ if (output_hdr) { + memset(output_hdr, '\0', sizeof(*output_hdr)); output_hdr->rec_count = upto; output_hdr->type = TRACE_CHUNK_CALLS; + output_hdr->version = TRACE_VERSION; + output_hdr->text_base = CONFIG_TEXT_BASE; } /* Work out how must of the buffer we used */ @@ -385,10 +376,9 @@ int notrace trace_init(void *buff, size_t buff_size) /* Use any remaining space for the timed function trace */ hdr->ftrace = (struct trace_call *)(buff + needed); hdr->ftrace_size = (buff_size - needed) / sizeof(*hdr->ftrace); - add_textbase(); + hdr->depth_limit = CONFIG_TRACE_CALL_DEPTH_LIMIT; puts("trace: enabled\n"); - hdr->depth_limit = CONFIG_TRACE_CALL_DEPTH_LIMIT; trace_enabled = 1; trace_inited = 1; @@ -426,7 +416,6 @@ int notrace trace_early_init(void) /* Use any remaining space for the timed function trace */ hdr->ftrace = (struct trace_call *)((char *)hdr + needed); hdr->ftrace_size = (buff_size - needed) / sizeof(*hdr->ftrace); - add_textbase(); hdr->depth_limit = CONFIG_TRACE_EARLY_CALL_DEPTH_LIMIT; printf("trace: early enable at %08x\n", CONFIG_TRACE_EARLY_ADDR); From patchwork Sun Jan 15 21:15:47 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 1726831 X-Patchwork-Delegate: trini@ti.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=85.214.62.61; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: legolas.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=chromium.org header.i=@chromium.org header.a=rsa-sha256 header.s=google header.b=jHaKWKFv; dkim-atps=neutral Received: from phobos.denx.de (phobos.denx.de [85.214.62.61]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4Nw7LH2C9wz23fk for ; Mon, 16 Jan 2023 08:18:31 +1100 (AEDT) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id C3ABB855DE; Sun, 15 Jan 2023 22:16:56 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=chromium.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (1024-bit key; unprotected) header.d=chromium.org header.i=@chromium.org header.b="jHaKWKFv"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id 2FDAB8554E; Sun, 15 Jan 2023 22:16:37 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,SPF_HELO_NONE, SPF_PASS autolearn=ham autolearn_force=no version=3.4.2 Received: from mail-io1-xd36.google.com (mail-io1-xd36.google.com [IPv6:2607:f8b0:4864:20::d36]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id 2512C855BB for ; Sun, 15 Jan 2023 22:16:32 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=chromium.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=sjg@chromium.org Received: by mail-io1-xd36.google.com with SMTP id d22so4045937iof.5 for ; Sun, 15 Jan 2023 13:16:32 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=mwSTqDhx9io4WTT1nLYd1dR5cjYIpqrNkH/0UOQ+3H8=; b=jHaKWKFvmHxqmtCFBtgOM1zB6EcYjT8rl/Xspz4mnxLeuE/CAIasMwmEzwEO/Atm+Z riZFDK54oVoYfnWTYx0iHmiIeuPGNimtQZ3OdKaYfE0pF4gBFmgwiZW1I34E8HwGR/rM 0sUMxnqmLIHhXSON/xbAbHf51/ZIPFs3T6u/A= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=mwSTqDhx9io4WTT1nLYd1dR5cjYIpqrNkH/0UOQ+3H8=; b=te+luEVKDf9YGHCJOC056t35wSSck37MuMmq2/6O9lq/TWpUAU/f15E+s6fogSEFcm kA8JzQnvYCW54Xg39iPeHeKSyaezpDtV+C2XAAZkNz1MzcB0Iy5W0hHpnnE3IEAP0VrK 5qVu5Sm+jhAjSchc6OKqve3LMtE9goVN1P6ywa7wAyEKIoMj5wepsqZ5SY/TRRof9JvX 31fxX9AXDDS/8cKacSRCSwsnqMKiE0GWL6BY6LCmJxfDe6uocINNxZxBaBhEUYGBxo9x p3l3OaaLIsaklu+SVjVpCjpXBAg9VA/aGoPsoxTaJCQVRBfGNlDa/GL3bfDJr04jzldF dVdQ== X-Gm-Message-State: AFqh2kqcMZBmqdECQcLTnEw2reSpb2rY4uOjjmA69VkBGKTrjRnv7iF+ B+a8/3qfO7H9NN7R1ptsaLsY+zer5GtakOBtRT0= X-Google-Smtp-Source: AMrXdXscC+vm73sBvbasyafKAtRJGKnJ/6dDgXMYIvYp4+KIEy7GjV6hYh5IUrYC4KmInXiNtDZ02Q== X-Received: by 2002:a5d:9816:0:b0:6c3:a4b:9c17 with SMTP id a22-20020a5d9816000000b006c30a4b9c17mr56280218iol.5.1673817390694; Sun, 15 Jan 2023 13:16:30 -0800 (PST) Received: from sjg1.roam.corp.google.com (c-73-14-173-85.hsd1.co.comcast.net. [73.14.173.85]) by smtp.gmail.com with ESMTPSA id j6-20020a6bf906000000b007046e9e138esm4329107iog.22.2023.01.15.13.16.30 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 15 Jan 2023 13:16:30 -0800 (PST) From: Simon Glass To: U-Boot Mailing List Cc: Tom Rini , Heinrich Schuchardt , Simon Glass Subject: [PATCH 10/24] trace: Reduce the number of function sites Date: Sun, 15 Jan 2023 14:15:47 -0700 Message-Id: <20230115211602.1127661-11-sjg@chromium.org> X-Mailer: git-send-email 2.39.0.314.g84b9a713c41-goog In-Reply-To: <20230115211602.1127661-1-sjg@chromium.org> References: <20230115211602.1127661-1-sjg@chromium.org> MIME-Version: 1.0 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.39 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.103.6 at phobos.denx.de X-Virus-Status: Clean Given that the compiler adds two function calls into each function, the current spacing is overkill. Drop it down to 16 bytes per function, which is still plenty. This saves some space in the trace buffer. Also move the calculation into a function, so it is common code. Add a check for gd->mon_len being unset, which breaks tracing. Signed-off-by: Simon Glass --- include/trace.h | 6 ++++-- lib/trace.c | 19 +++++++++++++++++-- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/include/trace.h b/include/trace.h index 2be8d81b515..763d6d1255a 100644 --- a/include/trace.h +++ b/include/trace.h @@ -17,14 +17,16 @@ enum { * * The value here assumes a minimum instruction size of 4 bytes, * or that instructions are 2 bytes but there are at least 2 of - * them in every function. + * them in every function. Given that each function needs a call to + * __cyg_profile_func_enter() and __cyg_profile_func_exit() as well, + * we cannot have functions smaller that 16 bytes. * * Increasing this value reduces the number of functions we can * resolve, but reduces the size of the uintptr_t array used for * our function list, which is the length of the code divided by * this value. */ - FUNC_SITE_SIZE = 4, /* distance between function sites */ + FUNC_SITE_SIZE = 16, /* distance between function sites */ TRACE_VERSION = 1, }; diff --git a/lib/trace.c b/lib/trace.c index 2e2c1bed54f..12dae2089a4 100644 --- a/lib/trace.c +++ b/lib/trace.c @@ -321,6 +321,17 @@ void notrace trace_set_enabled(int enabled) trace_enabled = enabled != 0; } +static int get_func_count(void) +{ + /* Detect no support for mon_len since this means tracing cannot work */ + if (IS_ENABLED(CONFIG_SANDBOX) && !gd->mon_len) { + puts("Tracing is not supported on this board\n"); + return -ENOTSUPP; + } + + return gd->mon_len / FUNC_SITE_SIZE; +} + /** * trace_init() - initialize the tracing system and enable it * @@ -330,10 +341,12 @@ void notrace trace_set_enabled(int enabled) */ int notrace trace_init(void *buff, size_t buff_size) { - ulong func_count = gd->mon_len / FUNC_SITE_SIZE; + int func_count = get_func_count(); size_t needed; int was_disabled = !trace_enabled; + if (func_count < 0) + return func_count; trace_save_gd(); if (!was_disabled) { @@ -393,10 +406,12 @@ int notrace trace_init(void *buff, size_t buff_size) */ int notrace trace_early_init(void) { - ulong func_count = gd->mon_len / FUNC_SITE_SIZE; + int func_count = get_func_count(); size_t buff_size = CONFIG_TRACE_EARLY_SIZE; size_t needed; + if (func_count < 0) + return func_count; /* We can ignore additional calls to this function */ if (trace_enabled) return 0; From patchwork Sun Jan 15 21:15:48 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 1726830 X-Patchwork-Delegate: trini@ti.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=2a01:238:438b:c500:173d:9f52:ddab:ee01; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: legolas.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=chromium.org header.i=@chromium.org header.a=rsa-sha256 header.s=google header.b=LYGeJfsD; dkim-atps=neutral Received: from phobos.denx.de (phobos.denx.de [IPv6:2a01:238:438b:c500:173d:9f52:ddab:ee01]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4Nw7L35PBjz23fk for ; Mon, 16 Jan 2023 08:18:19 +1100 (AEDT) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 121C2855D5; Sun, 15 Jan 2023 22:16:55 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=chromium.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (1024-bit key; unprotected) header.d=chromium.org header.i=@chromium.org header.b="LYGeJfsD"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id 1961685514; Sun, 15 Jan 2023 22:16:37 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,SPF_HELO_NONE, SPF_PASS autolearn=ham autolearn_force=no version=3.4.2 Received: from mail-io1-xd2c.google.com (mail-io1-xd2c.google.com [IPv6:2607:f8b0:4864:20::d2c]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id D4962850D5 for ; Sun, 15 Jan 2023 22:16:31 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=chromium.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=sjg@chromium.org Received: by mail-io1-xd2c.google.com with SMTP id 203so2202005iou.13 for ; Sun, 15 Jan 2023 13:16:31 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=IcUZOMcr6d8hXjbP/F8Qx7S9WNIbW9iCCpe/3sYVmIY=; b=LYGeJfsDqsCmPFEbdNwAmZvb68jM38ZkC5GMM1vGpG4Nxkykszy7azgrr9y1sFTI1y jusSDQcW4Kp4lCfgory1CaOLy0Ojdbtrzc91VmSwtDvA5aeHOk5tiiiqXQZno454sJdB pJnnrSaHoieJwFNYQqjknMbX2NYbTt9UotCIs= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=IcUZOMcr6d8hXjbP/F8Qx7S9WNIbW9iCCpe/3sYVmIY=; b=Wa9CGrLZYLonD3LDLJp9p6jgov3wUTzvkMysc4R3AngAtixO+XU0MZL06jw8sMiyEL OvO5JgacFYXz/CIUdMP4D0qb7pkp8yNfcVLztmaCC0ZKHER3oZxiiXrFvinvSp8ZiOHa 6I/FBeSQmgCXAeteFrjP6yaHOXw4sWdGMHKa1kBtqA2H0I4wbxp+RbqTjgZWaszNGsYn OT4ya1oohY2djslGXbgC3UzNfyKrEgR1MMIJDSB2tchibUJWxC/2zUUuaa6r/OB0hwAp KldmTjv1UiEKZusD9YUu5WrCeIbbW0cwqaF/eoAt05/YLLJtQRRgs1m6Lac8ixOdHygm 1YSg== X-Gm-Message-State: AFqh2kqBNadsCLCAjnDd14lmzv68bh1xgIn3LxT8LIcjg1N8oX6uHgsH 86sG8KuYL5+Ua06co28Fjf2oi7n01PsKbsEuj34= X-Google-Smtp-Source: AMrXdXvp+o7CZ0WC1Pz8k+PuuOKzKKsaAD9vhZjVkvQeIhxm0YUzPfEoUe5BpCdwXsqNj0PxC63KHA== X-Received: by 2002:a5e:8347:0:b0:704:8b14:b6ca with SMTP id y7-20020a5e8347000000b007048b14b6camr7008707iom.13.1673817391373; Sun, 15 Jan 2023 13:16:31 -0800 (PST) Received: from sjg1.roam.corp.google.com (c-73-14-173-85.hsd1.co.comcast.net. [73.14.173.85]) by smtp.gmail.com with ESMTPSA id j6-20020a6bf906000000b007046e9e138esm4329107iog.22.2023.01.15.13.16.30 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 15 Jan 2023 13:16:31 -0800 (PST) From: Simon Glass To: U-Boot Mailing List Cc: Tom Rini , Heinrich Schuchardt , Simon Glass Subject: [PATCH 11/24] trace: Track the minimum stack depth Date: Sun, 15 Jan 2023 14:15:48 -0700 Message-Id: <20230115211602.1127661-12-sjg@chromium.org> X-Mailer: git-send-email 2.39.0.314.g84b9a713c41-goog In-Reply-To: <20230115211602.1127661-1-sjg@chromium.org> References: <20230115211602.1127661-1-sjg@chromium.org> MIME-Version: 1.0 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.39 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.103.6 at phobos.denx.de X-Virus-Status: Clean The trace does not necessarily start at the top level, so we can see it go negative. Track this so that we can show an accurate value for the stack depth. Signed-off-by: Simon Glass --- lib/trace.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/lib/trace.c b/lib/trace.c index 12dae2089a4..3551ef3a23c 100644 --- a/lib/trace.c +++ b/lib/trace.c @@ -35,9 +35,10 @@ struct trace_hdr { ulong ftrace_count; /* Num. of ftrace records written */ ulong ftrace_too_deep_count; /* Functions that were too deep */ - int depth; - int depth_limit; - int max_depth; + int depth; /* Depth of function calls */ + int depth_limit; /* Depth limit to trace to */ + int max_depth; /* Maximum depth seen so far */ + int min_depth; /* Minimum depth seen so far */ }; /* Pointer to start of trace buffer */ @@ -142,7 +143,7 @@ void notrace __cyg_profile_func_enter(void *func_ptr, void *caller) hdr->untracked_count++; } hdr->depth++; - if (hdr->depth > hdr->depth_limit) + if (hdr->depth > hdr->max_depth) hdr->max_depth = hdr->depth; trace_swap_gd(); } @@ -158,8 +159,10 @@ void notrace __cyg_profile_func_exit(void *func_ptr, void *caller) { if (trace_enabled) { trace_swap_gd(); - add_ftrace(func_ptr, caller, FUNCF_EXIT); hdr->depth--; + add_ftrace(func_ptr, caller, FUNCF_EXIT); + if (hdr->depth < hdr->min_depth) + hdr->min_depth = hdr->depth; trace_swap_gd(); } } @@ -309,8 +312,10 @@ void trace_print_stats(void) printf(" (%lu dropped due to overflow)", hdr->ftrace_count - hdr->ftrace_size); } - puts("\n"); - printf("%15d maximum observed call depth\n", hdr->max_depth); + + /* Add in minimum depth since the trace did not start at top level */ + printf("\n%15d maximum observed call depth\n", + hdr->max_depth - hdr->min_depth); printf("%15d call depth limit\n", hdr->depth_limit); print_grouped_ull(hdr->ftrace_too_deep_count, 10); puts(" calls not traced due to depth\n"); @@ -381,8 +386,10 @@ int notrace trace_init(void *buff, size_t buff_size) return -ENOSPC; } - if (was_disabled) + if (was_disabled) { memset(hdr, '\0', needed); + hdr->min_depth = INT_MAX; + } hdr->func_count = func_count; hdr->call_accum = (uintptr_t *)(hdr + 1); @@ -427,6 +434,7 @@ int notrace trace_early_init(void) memset(hdr, '\0', needed); hdr->call_accum = (uintptr_t *)(hdr + 1); hdr->func_count = func_count; + hdr->min_depth = INT_MAX; /* Use any remaining space for the timed function trace */ hdr->ftrace = (struct trace_call *)((char *)hdr + needed); From patchwork Sun Jan 15 21:15:49 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 1726832 X-Patchwork-Delegate: trini@ti.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=2a01:238:438b:c500:173d:9f52:ddab:ee01; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: legolas.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=chromium.org header.i=@chromium.org header.a=rsa-sha256 header.s=google header.b=Ij42Yk0w; dkim-atps=neutral Received: from phobos.denx.de (phobos.denx.de [IPv6:2a01:238:438b:c500:173d:9f52:ddab:ee01]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4Nw7LW6CkSz23fk for ; Mon, 16 Jan 2023 08:18:43 +1100 (AEDT) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 4C1A3855E9; Sun, 15 Jan 2023 22:16:58 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=chromium.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (1024-bit key; unprotected) header.d=chromium.org header.i=@chromium.org header.b="Ij42Yk0w"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id C9E30855CB; Sun, 15 Jan 2023 22:16:37 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,SPF_HELO_NONE, SPF_PASS autolearn=ham autolearn_force=no version=3.4.2 Received: from mail-io1-xd34.google.com (mail-io1-xd34.google.com [IPv6:2607:f8b0:4864:20::d34]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id 838A385531 for ; Sun, 15 Jan 2023 22:16:33 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=chromium.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=sjg@chromium.org Received: by mail-io1-xd34.google.com with SMTP id s26so5027855ioa.11 for ; Sun, 15 Jan 2023 13:16:33 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=uSIlXanAxod6NRpd2FFLZtIihRyIMFERb8w3g+Cvpi4=; b=Ij42Yk0wGdYPAYZP0V9bqknrHU4Mx55Z+q6wUUEdG1Q5lF6UJxqf9Fb3Se6K/KAY7h S1ruP7YRDJvkX5FIUj0Wt2ubS3o3GHjeiTvEbUqZohoksOimzyT/zCWk0ij38M6y351+ BNJ2iAeCL7KxbFNJMu+zDjlphB9H5iOi2BIi0= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=uSIlXanAxod6NRpd2FFLZtIihRyIMFERb8w3g+Cvpi4=; b=6gGnOnWiEXSYpyksHjsGzoYigOAz1Rkhye9vBGz1SDjp3G7Dn0yxkHe/yFSrK4u6yD bwTbY6qfvgsJ5hOTFni/b0U861CXtYsDsJZC+Vmnka46DEEz77iXX+xQpoiRsijlB+rM oNPVqe1SxFjUjFBNW6lYyRQ3mHCtFYO5V/Fxvse8XzaOfEzuoNuq9Dk9yVDZbEwFfjLs BJyaPW/bVVvhut6pdPLSw04JYJHRwJPWPJWk64M+oU6eiYHlP3CPi0DexAWrsiA0/ILj mmlltfodRloaJ4c4deWAFXuvqNgGLrItn5dol3YGJDvILOa2fJTdlyTOPefX2uf3RD/4 Hvmg== X-Gm-Message-State: AFqh2kq8onyco4t06GAdiqzlDr7NI+hjYS0xOcxW4hLGGEZhyD7xI+cW LaL0ssMZ6gKB1SIqxEBI//v0Ezhys/nvAJD8U4w= X-Google-Smtp-Source: AMrXdXuCW1Sa7vA2y9eXhDHE6LJ2V8mpIrEkR2V2/ksvhfm4v8YZTnH3tsi+GTgwhLKEw+L04RTXmw== X-Received: by 2002:a6b:d910:0:b0:6df:427:1ecd with SMTP id r16-20020a6bd910000000b006df04271ecdmr12372382ioc.8.1673817392083; Sun, 15 Jan 2023 13:16:32 -0800 (PST) Received: from sjg1.roam.corp.google.com (c-73-14-173-85.hsd1.co.comcast.net. [73.14.173.85]) by smtp.gmail.com with ESMTPSA id j6-20020a6bf906000000b007046e9e138esm4329107iog.22.2023.01.15.13.16.31 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 15 Jan 2023 13:16:31 -0800 (PST) From: Simon Glass To: U-Boot Mailing List Cc: Tom Rini , Heinrich Schuchardt , Simon Glass Subject: [PATCH 12/24] trace: Show a few more stats about tracing Date: Sun, 15 Jan 2023 14:15:49 -0700 Message-Id: <20230115211602.1127661-13-sjg@chromium.org> X-Mailer: git-send-email 2.39.0.314.g84b9a713c41-goog In-Reply-To: <20230115211602.1127661-1-sjg@chromium.org> References: <20230115211602.1127661-1-sjg@chromium.org> MIME-Version: 1.0 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.39 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.103.6 at phobos.denx.de X-Virus-Status: Clean Add a few more useful items into the output. Update the buffers to use hex consistently. Signed-off-by: Simon Glass --- lib/trace.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/trace.c b/lib/trace.c index 3551ef3a23c..c3354a256fb 100644 --- a/lib/trace.c +++ b/lib/trace.c @@ -319,6 +319,10 @@ void trace_print_stats(void) printf("%15d call depth limit\n", hdr->depth_limit); print_grouped_ull(hdr->ftrace_too_deep_count, 10); puts(" calls not traced due to depth\n"); + print_grouped_ull(hdr->ftrace_size, 10); + puts(" max function calls\n"); + printf("\ntrace buffer %lx call records %lx\n", + (ulong)map_to_sysmem(hdr), (ulong)map_to_sysmem(hdr->ftrace)); } void notrace trace_set_enabled(int enabled) @@ -381,7 +385,7 @@ int notrace trace_init(void *buff, size_t buff_size) hdr = (struct trace_hdr *)buff; needed = sizeof(*hdr) + func_count * sizeof(uintptr_t); if (needed > buff_size) { - printf("trace: buffer size %zd bytes: at least %zd needed\n", + printf("trace: buffer size %zx bytes: at least %zx needed\n", buff_size, needed); return -ENOSPC; } @@ -426,7 +430,7 @@ int notrace trace_early_init(void) hdr = map_sysmem(CONFIG_TRACE_EARLY_ADDR, CONFIG_TRACE_EARLY_SIZE); needed = sizeof(*hdr) + func_count * sizeof(uintptr_t); if (needed > buff_size) { - printf("trace: buffer size is %zd bytes, at least %zd needed\n", + printf("trace: buffer size is %zx bytes, at least %zx needed\n", buff_size, needed); return -ENOSPC; } From patchwork Sun Jan 15 21:15:50 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 1726833 X-Patchwork-Delegate: trini@ti.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=2a01:238:438b:c500:173d:9f52:ddab:ee01; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: legolas.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=chromium.org header.i=@chromium.org header.a=rsa-sha256 header.s=google header.b=FpVphAid; dkim-atps=neutral Received: from phobos.denx.de (phobos.denx.de [IPv6:2a01:238:438b:c500:173d:9f52:ddab:ee01]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4Nw7Ll0N9Mz23fk for ; Mon, 16 Jan 2023 08:18:55 +1100 (AEDT) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 13D53855E0; Sun, 15 Jan 2023 22:17:00 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=chromium.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (1024-bit key; unprotected) header.d=chromium.org header.i=@chromium.org header.b="FpVphAid"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id 2CAF985531; Sun, 15 Jan 2023 22:16:38 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,SPF_HELO_NONE, SPF_PASS autolearn=ham autolearn_force=no version=3.4.2 Received: from mail-io1-xd32.google.com (mail-io1-xd32.google.com [IPv6:2607:f8b0:4864:20::d32]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id 5DCB98551E for ; Sun, 15 Jan 2023 22:16:33 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=chromium.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=sjg@chromium.org Received: by mail-io1-xd32.google.com with SMTP id p66so12868336iof.1 for ; Sun, 15 Jan 2023 13:16:33 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=HCixYDUiyo0Qjdkd5Oo2WPpndQQIvF7MCM7Ji71B7FU=; b=FpVphAid+0rh7Kb9MJVj3G84BNhoTOedrj81zq12Pho55AL/IVcW8WUyXiuZVWh0Ff yN7c+mK+Lk/AcDyWa6os1JZ3CdixoO0nzkheDDfclG2OUw3mWaYKU13a53wgY0hSWc7u MQN/Nusl1ZijCfWhHEucUHJ151gTCbTdkV8eY= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=HCixYDUiyo0Qjdkd5Oo2WPpndQQIvF7MCM7Ji71B7FU=; b=6NwNJ5ZVKdSWCC0olPLEGlZlxyXbghjr3o8KJ90IAX3z3eVF4nnG23Pz2og0BNt+fG GN5XAZhz85+zoeE7BCDvhUJ9EODC0NB4r/ZkJrm2su8TZn1tVQgJ5bGEx8cCP3Wk25uT mJ+xRnHc44L7JFFTcDc9XJ8gZ2KO76RU3zp5bIY2pdPJCvpZT6o68tSv0J5HsBzBLr6P p2AIPkV/g8CWH3XPc4t/QgvGoqlg+LXYfTjNRKXH3bojhn6aYVtyKDQL4+FfgsHsKDtd 3oZjkOFlekOsBPL33xgsTQAn7cxauAKzbzhMiwx2IvFDjRgF+5g4A3arW5D+yRIZstBz nVmg== X-Gm-Message-State: AFqh2kptbimzvZoZ97DylrIoQlBkbHy9FJ7q9f5M0AF5nhCHMH93/1Hd gWbF6xGOyqe4GLPK1qLr8+TKpS0WEiCA1fSi/cc= X-Google-Smtp-Source: AMrXdXtx7Kkq9oQQlvWOQDxY1rzzbYChvOTWM11XZIHyWUI8gAIqZMZ+gdRbkF7/PrVlhP5e9RFFtg== X-Received: by 2002:a05:6602:3986:b0:6e3:19f:b3c3 with SMTP id bw6-20020a056602398600b006e3019fb3c3mr71611537iob.0.1673817392843; Sun, 15 Jan 2023 13:16:32 -0800 (PST) Received: from sjg1.roam.corp.google.com (c-73-14-173-85.hsd1.co.comcast.net. [73.14.173.85]) by smtp.gmail.com with ESMTPSA id j6-20020a6bf906000000b007046e9e138esm4329107iog.22.2023.01.15.13.16.32 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 15 Jan 2023 13:16:32 -0800 (PST) From: Simon Glass To: U-Boot Mailing List Cc: Tom Rini , Heinrich Schuchardt , Simon Glass Subject: [PATCH 13/24] trace: Correct the relocation handover with buffer overflow Date: Sun, 15 Jan 2023 14:15:50 -0700 Message-Id: <20230115211602.1127661-14-sjg@chromium.org> X-Mailer: git-send-email 2.39.0.314.g84b9a713c41-goog In-Reply-To: <20230115211602.1127661-1-sjg@chromium.org> References: <20230115211602.1127661-1-sjg@chromium.org> MIME-Version: 1.0 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.39 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.103.6 at phobos.denx.de X-Virus-Status: Clean When the early trace buffer overflows it leaves a gap in the trace buffer between where the actual data finished and where it would have finished if there were enough buffer space. This results in corrupted output. Adjust the logic to resolve this and add a message when the buffer overflows. Signed-off-by: Simon Glass --- lib/trace.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/lib/trace.c b/lib/trace.c index c3354a256fb..bbc316af295 100644 --- a/lib/trace.c +++ b/lib/trace.c @@ -360,8 +360,8 @@ int notrace trace_init(void *buff, size_t buff_size) if (!was_disabled) { #ifdef CONFIG_TRACE_EARLY + ulong used, count; char *end; - ulong used; /* * Copy over the early trace data if we have it. Disable @@ -370,12 +370,19 @@ int notrace trace_init(void *buff, size_t buff_size) trace_enabled = 0; hdr = map_sysmem(CONFIG_TRACE_EARLY_ADDR, CONFIG_TRACE_EARLY_SIZE); - end = (char *)&hdr->ftrace[min(hdr->ftrace_count, - hdr->ftrace_size)]; + count = min(hdr->ftrace_count, hdr->ftrace_size); + end = (char *)&hdr->ftrace[count]; used = end - (char *)hdr; printf("trace: copying %08lx bytes of early data from %x to %08lx\n", used, CONFIG_TRACE_EARLY_ADDR, (ulong)map_to_sysmem(buff)); + printf("%lu traced function calls", count); + if (hdr->ftrace_count > hdr->ftrace_size) { + printf(" (%lu dropped due to overflow)", + hdr->ftrace_count - hdr->ftrace_size); + hdr->ftrace_count = hdr->ftrace_size; + } + puts("\n"); memcpy(buff, hdr, used); #else puts("trace: already enabled\n"); From patchwork Sun Jan 15 21:15:51 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 1726834 X-Patchwork-Delegate: trini@ti.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=2a01:238:438b:c500:173d:9f52:ddab:ee01; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: legolas.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=chromium.org header.i=@chromium.org header.a=rsa-sha256 header.s=google header.b=VYMWzmHc; dkim-atps=neutral Received: from phobos.denx.de (phobos.denx.de [IPv6:2a01:238:438b:c500:173d:9f52:ddab:ee01]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4Nw7Ly2yFlz23fk for ; Mon, 16 Jan 2023 08:19:06 +1100 (AEDT) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 87B3C855DD; Sun, 15 Jan 2023 22:17:03 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=chromium.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (1024-bit key; unprotected) header.d=chromium.org header.i=@chromium.org header.b="VYMWzmHc"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id 710F48555D; Sun, 15 Jan 2023 22:16:39 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,SPF_HELO_NONE, SPF_PASS autolearn=ham autolearn_force=no version=3.4.2 Received: from mail-io1-xd2a.google.com (mail-io1-xd2a.google.com [IPv6:2607:f8b0:4864:20::d2a]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id 1E68F855A1 for ; Sun, 15 Jan 2023 22:16:35 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=chromium.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=sjg@chromium.org Received: by mail-io1-xd2a.google.com with SMTP id h184so3432433iof.9 for ; Sun, 15 Jan 2023 13:16:35 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=H5VlbLOc8IW8O8EMf1+3MuMnfejc2D7JynBanXG+lOQ=; b=VYMWzmHc0InDiWG+tSkcnd939CueYFikg/SPzLd6yeDICgO+vOQCjNEAUZbxhalvcK Dk6v8LO0r3F3U7Ijx5rHnPU5ovNiRD9lL6hfifbPAjfQjpzJWkUKSds3LqfPbL673d+t MxP+ffpYxSOJeiFBhAG3OeVck5LRORj0rcCT8= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=H5VlbLOc8IW8O8EMf1+3MuMnfejc2D7JynBanXG+lOQ=; b=km2ydg6clFG43WNxBqlmV0B9aAF5NR/NcDd0E9TAeH8ztnkq808r+ZfESWgps04r1h Sw4k7F3WeVITJr92ffirZONnNuw/AHFE747N9vC2S80s2iMdRTFeFA0I+ho/AunBh8sD WUfvwlGv3arvLEAdVRhV+ag5DjqSYHGNy/z1o1156u5ejPP5eXJzvOc3sILe3pmyY6B1 V9tWoaOBZNi6LGUEjZvsbGIX660JC+jdHQMUpDZby5eeItobNewzOhJAS7s3tc5DaZQ/ YYH0mGX67Q8yu1SH0JkmCuYqFh/b7UV7QeH79G6IXNqN9fUh8Vui5llm5y6vPnvfUCES Q/OA== X-Gm-Message-State: AFqh2ko5M/C87859SDYitiiO3wijvRTMpgRDb2nG/N7jO7zHOMrTUwPt vm0wWM+daZvhcygZvTUVlhe7mTH4pxn932JPFo0= X-Google-Smtp-Source: AMrXdXugWZb82etjVltoFjj55FwrOzZkv+DG7/nFeUX1IprjyzAGAWSd9ZBIE++y7ghOgdmDk+1+PA== X-Received: by 2002:a5d:9954:0:b0:6ea:558f:6e4b with SMTP id v20-20020a5d9954000000b006ea558f6e4bmr56298820ios.19.1673817393582; Sun, 15 Jan 2023 13:16:33 -0800 (PST) Received: from sjg1.roam.corp.google.com (c-73-14-173-85.hsd1.co.comcast.net. [73.14.173.85]) by smtp.gmail.com with ESMTPSA id j6-20020a6bf906000000b007046e9e138esm4329107iog.22.2023.01.15.13.16.33 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 15 Jan 2023 13:16:33 -0800 (PST) From: Simon Glass To: U-Boot Mailing List Cc: Tom Rini , Heinrich Schuchardt , Simon Glass Subject: [PATCH 14/24] trace: Detect an infinite loop Date: Sun, 15 Jan 2023 14:15:51 -0700 Message-Id: <20230115211602.1127661-15-sjg@chromium.org> X-Mailer: git-send-email 2.39.0.314.g84b9a713c41-goog In-Reply-To: <20230115211602.1127661-1-sjg@chromium.org> References: <20230115211602.1127661-1-sjg@chromium.org> MIME-Version: 1.0 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.39 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.103.6 at phobos.denx.de X-Virus-Status: Clean If something is wrong with a board's timer function such that it calls functions not marked with notrace, U-Boot will hang. Detect this, print a message and disable the trace. Signed-off-by: Simon Glass --- lib/trace.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/trace.c b/lib/trace.c index bbc316af295..1091a5793a1 100644 --- a/lib/trace.c +++ b/lib/trace.c @@ -39,6 +39,7 @@ struct trace_hdr { int depth_limit; /* Depth limit to trace to */ int max_depth; /* Maximum depth seen so far */ int min_depth; /* Minimum depth seen so far */ + bool trace_locked; /* Used to detect recursive tracing */ }; /* Pointer to start of trace buffer */ @@ -133,6 +134,14 @@ void notrace __cyg_profile_func_enter(void *func_ptr, void *caller) if (trace_enabled) { int func; + if (hdr->trace_locked) { + trace_enabled = 0; + puts("trace: recursion detected, disabling\n"); + hdr->trace_locked = false; + return; + } + + hdr->trace_locked = true; trace_swap_gd(); add_ftrace(func_ptr, caller, FUNCF_ENTRY); func = func_ptr_to_num(func_ptr); @@ -146,6 +155,7 @@ void notrace __cyg_profile_func_enter(void *func_ptr, void *caller) if (hdr->depth > hdr->max_depth) hdr->max_depth = hdr->depth; trace_swap_gd(); + hdr->trace_locked = false; } } From patchwork Sun Jan 15 21:15:52 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 1726835 X-Patchwork-Delegate: trini@ti.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=2a01:238:438b:c500:173d:9f52:ddab:ee01; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: legolas.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=chromium.org header.i=@chromium.org header.a=rsa-sha256 header.s=google header.b=mZv0wkML; dkim-atps=neutral Received: from phobos.denx.de (phobos.denx.de [IPv6:2a01:238:438b:c500:173d:9f52:ddab:ee01]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4Nw7M94gtnz23fk for ; Mon, 16 Jan 2023 08:19:17 +1100 (AEDT) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 3621B855F0; Sun, 15 Jan 2023 22:17:06 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=chromium.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (1024-bit key; unprotected) header.d=chromium.org header.i=@chromium.org header.b="mZv0wkML"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id A095E8556B; Sun, 15 Jan 2023 22:16:41 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,SPF_HELO_NONE, SPF_PASS autolearn=ham autolearn_force=no version=3.4.2 Received: from mail-io1-xd2d.google.com (mail-io1-xd2d.google.com [IPv6:2607:f8b0:4864:20::d2d]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id ECA708559D for ; Sun, 15 Jan 2023 22:16:35 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=chromium.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=sjg@chromium.org Received: by mail-io1-xd2d.google.com with SMTP id i70so3632541ioa.12 for ; Sun, 15 Jan 2023 13:16:35 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=WYB7+R15MRlkSifMTLYTt4g160zZO86xJ2Hq/dZW93o=; b=mZv0wkMLG8ZPKNtbUN2hkLP5pkzE70IEpLL+cahb17yCFJVSWfA0WtAKWO0Vgrsx1d zj+eJuhj/1mafd5YnHn8zcvGHdeSEPgjx6yceGobfhiu9Jt5/ePSEt0JwsIPufdlRUr/ ID0VVZjo6v69VGWE9QADVWRUm3Uy2OqDjZ37Q= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=WYB7+R15MRlkSifMTLYTt4g160zZO86xJ2Hq/dZW93o=; b=m0F+htvoHwvzymeBxcJzkZQnZeo2vNOgcrf6s/PV15Tcfoju7OWttY6BsGCIf0Tw7G RcoCsfcLwTg9/NcA57r4lyOTngt5W/9jP/9SOyjmxd03X/ui4b70qJpslNGjTJ3gLDHD SD+ImG1oGVI7YuqLsHoL6cYaml/aSQsWDNFeT41zfFMWBRSGutbEsrOOJ7ftfYikHKhj dA6UZgfRTcPuZ78fJ08x4BN/SoItSar1IRilC3doQ3svxr1c4DpWFHRuY60gm6XW32Ag 6R0okkHP2g4mSxO9H6ChdcOVYQNB6JPkmlJyCeLUK6gequyiOYG5vNAo8AcvW3qU7+ct Drjg== X-Gm-Message-State: AFqh2krmmnB94yUqsuy+QACs1/TGZGZh2IuXURak1Gx4jvsWDVQIlVQr FrVrsg2XG7Pdwfur12EWON/cub+N4rnNm2dJvUM= X-Google-Smtp-Source: AMrXdXv68hFTChbxEFyg/x3ao2GIIy8MYwCcTrZvgJsvUujJ5lmAXAliCMUzAlK6UqE57z2OpUb8UA== X-Received: by 2002:a5d:8410:0:b0:6df:c5e0:31f5 with SMTP id i16-20020a5d8410000000b006dfc5e031f5mr58381488ion.16.1673817394347; Sun, 15 Jan 2023 13:16:34 -0800 (PST) Received: from sjg1.roam.corp.google.com (c-73-14-173-85.hsd1.co.comcast.net. [73.14.173.85]) by smtp.gmail.com with ESMTPSA id j6-20020a6bf906000000b007046e9e138esm4329107iog.22.2023.01.15.13.16.33 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 15 Jan 2023 13:16:34 -0800 (PST) From: Simon Glass To: U-Boot Mailing List Cc: Tom Rini , Heinrich Schuchardt , Simon Glass Subject: [PATCH 15/24] trace: Rename prof to trace and improve comments Date: Sun, 15 Jan 2023 14:15:52 -0700 Message-Id: <20230115211602.1127661-16-sjg@chromium.org> X-Mailer: git-send-email 2.39.0.314.g84b9a713c41-goog In-Reply-To: <20230115211602.1127661-1-sjg@chromium.org> References: <20230115211602.1127661-1-sjg@chromium.org> MIME-Version: 1.0 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.39 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.103.6 at phobos.denx.de X-Virus-Status: Clean The current use of 'profile' in some places is confusing. Update the code to use the word 'trace' consistently. Change the flags to better match their meaning and add some more comments. Signed-off-by: Simon Glass --- tools/proftool.c | 196 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 157 insertions(+), 39 deletions(-) diff --git a/tools/proftool.c b/tools/proftool.c index b66ea556486..6aa157c8b59 100644 --- a/tools/proftool.c +++ b/tools/proftool.c @@ -26,38 +26,62 @@ enum { FUNCF_TRACE = 1 << 0, /* Include this function in trace */ }; +/** + * struct func_info - information recorded for each function + * + * @offset: Function offset in the image, measured from the text_base + * @name: Function name + * @code_size: Total code size of the function + * @flags: Either 0 or FUNCF_TRACE + * @objsection: the section this function is in + */ struct func_info { unsigned long offset; const char *name; unsigned long code_size; - unsigned long call_count; unsigned flags; - /* the section this function is in */ struct objsection_info *objsection; }; +/** + * enum trace_line_type - whether to include or exclude a function + * + * @TRACE_LINE_INCLUDE: Include the function + * @TRACE_LINE_EXCLUDE: Exclude the function + */ enum trace_line_type { TRACE_LINE_INCLUDE, TRACE_LINE_EXCLUDE, }; +/** + * struct trace_configline_info - information about a config-file line + * + * @next: Next line + * @type: Line type + * @name: identifier name / wildcard + * @regex: Regex to use if name starts with '/' + */ struct trace_configline_info { struct trace_configline_info *next; enum trace_line_type type; - const char *name; /* identifier name / wildcard */ - regex_t regex; /* Regex to use if name starts with / */ + const char *name; + regex_t regex; }; /* The contents of the trace config file */ struct trace_configline_info *trace_config_head; +/* list of all functions in System.map file, sorted by offset in the image */ struct func_info *func_list; -int func_count; -struct trace_call *call_list; -int call_count; + +int func_count; /* number of functions */ +struct trace_call *call_list; /* list of all calls in the input trace file */ +int call_count; /* number of calls */ int verbose; /* Verbosity level 0=none, 1=warn, 2=notice, 3=info, 4=debug */ -unsigned long text_offset; /* text address of first function */ +ulong text_offset; /* text address of first function */ +/* debugging helpers */ static void outf(int level, const char *fmt, ...) __attribute__ ((format (__printf__, 2, 3))); #define error(fmt, b...) outf(0, fmt, ##b) @@ -66,7 +90,6 @@ static void outf(int level, const char *fmt, ...) #define info(fmt, b...) outf(3, fmt, ##b) #define debug(fmt, b...) outf(4, fmt, ##b) - static void outf(int level, const char *fmt, ...) { if (verbose >= level) { @@ -84,16 +107,24 @@ static void usage(void) "Usage: proftool [-cmtv] \n" "\n" "Commands\n" - " dump-ftrace\t\tDump out textual data in ftrace format\n" + " dump-ftrace\t\tDump out records in ftrace format for use by trace-cmd\n" "\n" "Options:\n" - " -c \tSpecific config file\n" + " -c \tSpecify config file\n" " -m \tSpecify Systen.map file\n" + " -o \tSpecify output file\n" " -t \tSpecify trace data file (from U-Boot 'trace calls')\n" " -v <0-4>\tSpecify verbosity\n"); exit(EXIT_FAILURE); } +/** + * h_cmp_offset - bsearch() function to compare two functions bny their offset + * + * @v1: Pointer to first function (struct func_info) + * @v2: Pointer to second function (struct func_info) + * Returns: < 0 if v1 offset < v2 offset, 0 if equal, > 0 otherwise + */ static int h_cmp_offset(const void *v1, const void *v2) { const struct func_info *f1 = v1, *f2 = v2; @@ -101,6 +132,15 @@ static int h_cmp_offset(const void *v1, const void *v2) return (f1->offset / FUNC_SITE_SIZE) - (f2->offset / FUNC_SITE_SIZE); } +/** + * read_system_map() - read the System.map file to create a list of functions + * + * This also reads the text_offset value, since we assume that the first text + * symbol is at that address + * + * @fin: File to read + * Returns: 0 if OK, non-zero on error + */ static int read_system_map(FILE *fin) { unsigned long offset, start = 0; @@ -152,6 +192,7 @@ static int read_system_map(FILE *fin) } notice("%d functions found in map file\n", func_count); text_offset = start; + return 0; } @@ -163,13 +204,22 @@ static int read_data(FILE *fin, void *buff, int size) if (!err) return 1; if (err != size) { - error("Cannot read profile file at pos %lx\n", ftell(fin)); + error("Cannot read trace file at pos %lx\n", ftell(fin)); return -1; } return 0; } -static struct func_info *find_func_by_offset(uint32_t offset) +/** + * find_func_by_offset() - Look up a function by its offset + * + * @offset: Offset to search for, from text_base + * Returns: function, if found, else NULL + * + * This does a fast search for a function given its offset from text_base + * + */ +static struct func_info *find_func_by_offset(uint offset) { struct func_info key, *found; @@ -180,8 +230,17 @@ static struct func_info *find_func_by_offset(uint32_t offset) return found; } -/* This finds the function which contains the given offset */ -static struct func_info *find_caller_by_offset(uint32_t offset) +/** + * find_caller_by_offset() - finds the function which contains the given offset + * + * @offset: Offset to search for, from text_base + * Returns: function, if found, else NULL + * + * If the offset falls between two functions, then it is assumed to belong to + * the first function (with the lowest offset). This is a way of figuring out + * which function owns code at a particular offset + */ +static struct func_info *find_caller_by_offset(uint offset) { int low; /* least function that could be a match */ int high; /* greated function that could be a match */ @@ -206,6 +265,15 @@ static struct func_info *find_caller_by_offset(uint32_t offset) return low >= 0 ? &func_list[low] : NULL; } +/** + * read_calls() - Read the list of calls from the trace data + * + * The calls are stored consecutively in the trace output produced by U-Boot + * + * @fin: File to read from + * @count: Number of calls to read + * Returns: 0 if OK, -1 on error + */ static int read_calls(FILE *fin, size_t count) { struct trace_call *call_data; @@ -222,16 +290,24 @@ static int read_calls(FILE *fin, size_t count) call_data = call_list; for (i = 0; i < count; i++, call_data++) { if (read_data(fin, call_data, sizeof(*call_data))) - return 1; + return -1; } return 0; } -static int read_profile(FILE *fin, int *not_found) +/** + * read_trace() - Read the U-Boot trace file + * + * Read in the calls from the trace file. The function list is ignored at + * present + * + * @fin: File to read + * Returns 0 if OK, non-zero on error + */ +static int read_trace(FILE *fin) { struct trace_output_hdr hdr; - *not_found = 0; while (!feof(fin)) { int err; @@ -255,6 +331,14 @@ static int read_profile(FILE *fin, int *not_found) return 0; } +/** + * read_map_file() - Read the System.map file + * + * This reads the file into the func_list array + * + * @fname: Filename to read + * Returns 0 if OK, non-zero on error + */ static int read_map_file(const char *fname) { FILE *fmap; @@ -272,28 +356,30 @@ static int read_map_file(const char *fname) return err; } -static int read_profile_file(const char *fname) +/** + * read_trace_file() - Open and read the U-Boot trace file + * + * Read in the calls from the trace file. The function list is ignored at + * present + * + * @fin: File to read + * Returns 0 if OK, non-zero on error + */ +static int read_trace_file(const char *fname) { - int not_found = INT_MAX; FILE *fprof; int err; fprof = fopen(fname, "rb"); if (!fprof) { - error("Cannot open profile data file '%s'\n", + error("Cannot open trace data file '%s'\n", fname); return 1; } else { - err = read_profile(fprof, ¬_found); + err = read_trace(fprof); fclose(fprof); if (err) return err; - - if (not_found) { - warn("%d profile functions could not be found in the map file - are you sure that your profile data and map file correspond?\n", - not_found); - return 1; - } } return 0; } @@ -344,6 +430,7 @@ static void check_trace_config_line(struct trace_configline_info *item) } } +/** check_trace_config() - Check trace-config file, reporting any problems */ static void check_trace_config(void) { struct trace_configline_info *line; @@ -377,6 +464,21 @@ static void check_functions(void) not_found, removed_code_size); } +/** + * read_trace_config() - read the trace-config file + * + * This file consists of lines like: + * + * include-func + * exclude-func + * + * where is a regular expression matched against function names. It + * allows some functions to be dropped from the trace when producing ftrace + * records + * + * @fin: File to process + * Returns: 0 if OK, -1 on error + */ static int read_trace_config(FILE *fin) { char buff[200]; @@ -400,8 +502,7 @@ static int read_trace_config(FILE *fin) if (!*s || *s == '#') continue; - line = (struct trace_configline_info *)calloc(1, - sizeof(*line)); + line = (struct trace_configline_info *)calloc(1, sizeof(*line)); if (!line) { error("Cannot allocate config line\n"); return -1; @@ -540,15 +641,25 @@ static int make_ftrace(void) return 0; } +/** + * prof_tool() - Performs requested action + * + * @argc: Number of arguments (used to obtain the command + * @argv: List of arguments + * @trace_fname: Filename of input file (trace data from U-Boot) + * @map_fname: Filename of map file (System.map from U-Boot) + * @trace_config_fname: Trace-configuration file, or NULL if none + * @out_fname: Output filename + */ static int prof_tool(int argc, char *const argv[], - const char *prof_fname, const char *map_fname, - const char *trace_config_fname) + const char *trace_fname, const char *map_fname, + const char *trace_config_fname, const char *out_fname) { int err = 0; if (read_map_file(map_fname)) return -1; - if (prof_fname && read_profile_file(prof_fname)) + if (trace_fname && read_trace_file(trace_fname)) return -1; if (trace_config_fname && read_trace_config_file(trace_config_fname)) return -1; @@ -572,27 +683,27 @@ int main(int argc, char *argv[]) const char *map_fname = "System.map"; const char *trace_fname = NULL; const char *config_fname = NULL; + const char *out_fname = NULL; int opt; verbose = 2; - while ((opt = getopt(argc, argv, "c:m:t:v:")) != -1) { + while ((opt = getopt(argc, argv, "c:m:o:t:v:")) != -1) { switch (opt) { case 'c': config_fname = optarg; break; - case 'm': map_fname = optarg; break; - + case 'o': + out_fname = optarg; + break; case 't': trace_fname = optarg; break; - case 'v': verbose = atoi(optarg); break; - default: usage(); } @@ -601,6 +712,13 @@ int main(int argc, char *argv[]) if (argc < 1) usage(); + if (!out_fname || !map_fname || !trace_fname) { + fprintf(stderr, + "Must provide trace data, System.map file and output file\n"); + usage(); + } + debug("Debug enabled\n"); - return prof_tool(argc, argv, trace_fname, map_fname, config_fname); + return prof_tool(argc, argv, trace_fname, map_fname, config_fname, + out_fname); } From patchwork Sun Jan 15 21:15:53 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 1726837 X-Patchwork-Delegate: trini@ti.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=2a01:238:438b:c500:173d:9f52:ddab:ee01; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: legolas.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=chromium.org header.i=@chromium.org header.a=rsa-sha256 header.s=google header.b=oLC7LSJo; dkim-atps=neutral Received: from phobos.denx.de (phobos.denx.de [IPv6:2a01:238:438b:c500:173d:9f52:ddab:ee01]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4Nw7Mc3SGmz23fk for ; Mon, 16 Jan 2023 08:19:40 +1100 (AEDT) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 06E8085604; Sun, 15 Jan 2023 22:17:12 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=chromium.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (1024-bit key; unprotected) header.d=chromium.org header.i=@chromium.org header.b="oLC7LSJo"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id C170A855D6; Sun, 15 Jan 2023 22:16:46 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,SPF_HELO_NONE, SPF_PASS autolearn=ham autolearn_force=no version=3.4.2 Received: from mail-io1-xd34.google.com (mail-io1-xd34.google.com [IPv6:2607:f8b0:4864:20::d34]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id 4D210855B7 for ; Sun, 15 Jan 2023 22:16:36 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=chromium.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=sjg@chromium.org Received: by mail-io1-xd34.google.com with SMTP id s26so5027896ioa.11 for ; Sun, 15 Jan 2023 13:16:36 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=ifFW7UG1XfJVR/VJFXhR84PPSrcpe09F/FdNWUCfyuo=; b=oLC7LSJomuneIU+1b6OCb9svfqZoy6HYryEn+YO/XXMun+u5yjkG3NmbhGPuJhd0q9 SPzzlpfUekWhVctmVI+Tf77DBrRBr3700UX4YvuDGUO3ugWXnst30erOB2VqQ+wm4i7S V+SAHJGCEOAl96SWjnDSwYt5oziCqihPHC+88= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=ifFW7UG1XfJVR/VJFXhR84PPSrcpe09F/FdNWUCfyuo=; b=VgK9JqoKdNsDp4x+aY6zKbnT6TbEaIXCmFTBKRa5PZq878pcIOibiP1ZwaGf8Glo9w 4BLEWYKbXXWABW1BS5Ra9Mmg9hv28SuulGM6lHdJ0D66zDFREZ9LHKFwhs+qFfoVI5Cd bmpvdvlLCW1jL+G/PLq3i2flI9NLGwHCDkNPjTRBcv/ZciYWhwb1ZPgeDmhapwMRVjgB HFJnmt8zNWFV1ab9LUnTVcpy7YxMd6ealknKSeBIy8NQE2QaLeOvAxEkUqDag50z5hAL wbC9kUOjqHEoJFfAk/vP4TdJNej9n/6u+st7VahTwLSGGSK0HbLy33LSOUg+mCZ62LuN CPWQ== X-Gm-Message-State: AFqh2kqSijRpKu+OkkLHnjOUJnVOqqUQSM8KGgiddHbf0BBbqU1Ul0xz kmcQFSAKGGzxI+fDjBHwOQiwk//QPAktfGFI8/4= X-Google-Smtp-Source: AMrXdXuSABDRAAWAqvlvvXdjQ0xxCYCrwiijeoF9iBICsJZ9mjJUxCr5FXKqRqXDRVmxVnSCyMHo4Q== X-Received: by 2002:a05:6602:2083:b0:704:9ab4:ea1c with SMTP id a3-20020a056602208300b007049ab4ea1cmr5605475ioa.6.1673817395330; Sun, 15 Jan 2023 13:16:35 -0800 (PST) Received: from sjg1.roam.corp.google.com (c-73-14-173-85.hsd1.co.comcast.net. [73.14.173.85]) by smtp.gmail.com with ESMTPSA id j6-20020a6bf906000000b007046e9e138esm4329107iog.22.2023.01.15.13.16.34 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 15 Jan 2023 13:16:35 -0800 (PST) From: Simon Glass To: U-Boot Mailing List Cc: Tom Rini , Heinrich Schuchardt , Simon Glass , AKASHI Takahiro , Heiko Thiery , Max Krummenacher , =?utf-8?q?Pali_Roh=C3=A1r?= , Samuel Holland , Stefan Roese Subject: [PATCH 16/24] trace: Update proftool to use new binary format Date: Sun, 15 Jan 2023 14:15:53 -0700 Message-Id: <20230115211602.1127661-17-sjg@chromium.org> X-Mailer: git-send-email 2.39.0.314.g84b9a713c41-goog In-Reply-To: <20230115211602.1127661-1-sjg@chromium.org> References: <20230115211602.1127661-1-sjg@chromium.org> MIME-Version: 1.0 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.39 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.103.6 at phobos.denx.de X-Virus-Status: Clean The old text format is not much used anymore. Instead a new trace-cmd tool has introduced a binary format for trace records. Add support for generating this format. This involves removing the old text format, adding various helpers for the new format and adjusting the code to use an output file instead of stdout. Signed-off-by: Simon Glass --- tools/Makefile | 3 + tools/proftool.c | 896 ++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 854 insertions(+), 45 deletions(-) diff --git a/tools/Makefile b/tools/Makefile index edfa40903d9..269bedd206e 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -225,7 +225,10 @@ HOSTCFLAGS_ubsha1.o := -pedantic hostprogs-$(CONFIG_ARCH_KIRKWOOD) += kwboot hostprogs-$(CONFIG_ARCH_MVEBU) += kwboot + hostprogs-y += proftool +proftool-objs = proftool.o lib/abuf.o + hostprogs-$(CONFIG_STATIC_RELA) += relocate-rela hostprogs-$(CONFIG_RISCV) += prelink-riscv diff --git a/tools/proftool.c b/tools/proftool.c index 6aa157c8b59..feeef55c1b9 100644 --- a/tools/proftool.c +++ b/tools/proftool.c @@ -1,9 +1,15 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * Copyright (c) 2013 Google, Inc + * Copyright 2023 Google LLC + * Written by Simon Glass */ -/* Decode and dump U-Boot profiling information */ +/* + * Decode and dump U-Boot trace information into formats that can be used + * by trace-cmd or kernelshark + * + * See doc/develop/trace.rst for more information + */ #include #include @@ -19,11 +25,67 @@ #include #include +#include + +/* Set to 1 to emit version 7 file (currently this doesn't work) */ +#define VERSION7 0 -#define MAX_LINE_LEN 500 +/* enable some debug features */ +#define _DEBUG 0 + +/* from linux/kernel.h */ +#define __ALIGN_MASK(x, mask) (((x) + (mask)) & ~(mask)) +#define ALIGN(x, a) __ALIGN_MASK((x), (typeof(x))(a) - 1) enum { FUNCF_TRACE = 1 << 0, /* Include this function in trace */ + TRACE_PAGE_SIZE = 4096, /* Assumed page size for trace */ + TRACE_PID = 1, /* PID to use for U-Boot */ + LEN_STACK_SIZE = 4, /* number of nested length fix-ups */ + TRACE_PAGE_MASK = TRACE_PAGE_SIZE - 1, + MAX_STACK_DEPTH = 50, /* Max nested function calls */ + MAX_LINE_LEN = 500, /* Max characters per line */ +}; + +/* Section types for v7 format (trace-cmd format) */ +enum { + SECTION_OPTIONS, +}; + +/* Option types (trace-cmd format) */ +enum { + OPTION_DONE, + OPTION_DATE, + OPTION_CPUSTAT, + OPTION_BUFFER, + OPTION_TRACECLOCK, + OPTION_UNAME, + OPTION_HOOK, + OPTION_OFFSET, + OPTION_CPUCOUNT, + OPTION_VERSION, + OPTION_PROCMAPS, + OPTION_TRACEID, + OPTION_TIME_SHIFT, + OPTION_GUEST, + OPTION_TSC2NSEC, +}; + +/* types of trace records (trace-cmd format) */ +enum trace_type { + __TRACE_FIRST_TYPE = 0, + + TRACE_FN, + TRACE_CTX, + TRACE_WAKE, + TRACE_STACK, + TRACE_PRINT, + TRACE_BPRINT, + TRACE_MMIO_RW, + TRACE_MMIO_MAP, + TRACE_BRANCH, + TRACE_GRAPH_RET, + TRACE_GRAPH_ENT, }; /** @@ -69,6 +131,45 @@ struct trace_configline_info { regex_t regex; }; +/** + * struct tw_len - holds information about a length value that need fix-ups + * + * This is used to record a placeholder for a u32 or u64 length which is written + * to the output file but needs to be updated once the length is actually known + * + * This allows us to write tw->ptr - @len_base to position @ptr in the file + * + * @ptr: Position of the length value in the file + * @base: Base position for the calculation + * @size: Size of the length value, in bytes (4 or 8) + */ +struct tw_len { + int ptr; + int base; + int size; +}; + +/** + * struct twriter - Writer for trace records + * + * Maintains state used when writing the output file in trace-cmd format + * + * @ptr: Current file position + * @len_stack: Stack of length values that need fixing up + * @len: Number of items on @len_stack + * @str_buf: Buffer of strings (for v7 format) + * @str_ptr: Current write-position in the buffer for strings + * @fout: Output file + */ +struct twriter { + int ptr; + struct tw_len len_stack[LEN_STACK_SIZE]; + int len_count; + struct abuf str_buf; + int str_ptr; + FILE *fout; +}; + /* The contents of the trace config file */ struct trace_configline_info *trace_config_head; @@ -569,56 +670,577 @@ static int read_trace_config_file(const char *fname) return err; } -static void out_func(ulong func_offset, int is_caller, const char *suffix) +/** + * tputh() - Write a 16-bit little-endian value to a file + * + * @fout: File to write to + * @val: Value to write + * Returns: number of bytes written (2) + */ +static int tputh(FILE *fout, unsigned int val) { - struct func_info *func; + fputc(val, fout); + fputc(val >> 8, fout); + + return 2; +} - func = (is_caller ? find_caller_by_offset : find_func_by_offset) - (func_offset); +/** + * tputl() - Write a 32-bit little-endian value to a file + * + * @fout: File to write to + * @val: Value to write + * Returns: number of bytes written (4) + */ +static int tputl(FILE *fout, ulong val) +{ + fputc(val, fout); + fputc(val >> 8, fout); + fputc(val >> 16, fout); + fputc(val >> 24, fout); - if (func) - printf("%s%s", func->name, suffix); - else - printf("%lx%s", func_offset, suffix); + return 4; } -/* - * # tracer: function - * # - * # TASK-PID CPU# TIMESTAMP FUNCTION - * # | | | | | - * # bash-4251 [01] 10152.583854: path_put <-path_walk - * # bash-4251 [01] 10152.583855: dput <-path_put - * # bash-4251 [01] 10152.583855: _atomic_dec_and_lock <-dput +/** + * tputh() - Write a 64-bit little-endian value to a file + * + * @fout: File to write to + * @val: Value to write + * Returns: number of bytes written (8) */ -static int make_ftrace(void) +static int tputq(FILE *fout, unsigned long long val) { - struct trace_call *call; + tputl(fout, val); + tputl(fout, val >> 32U); + + return 8; +} + +/** + * tputh() - Write a string to a file + * + * The string is written without its terminator + * + * @fout: File to write to + * @val: Value to write + * Returns: number of bytes written + */ +static int tputs(FILE *fout, const char *str) +{ + fputs(str, fout); + + return strlen(str); +} + +/** + * add_str() - add a name string to the string table + * + * This is used by the v7 format + * + * @tw: Writer context + * @name: String to write + * Returns: Updated value of string pointer, or -1 if out of memory + */ +static int add_str(struct twriter *tw, const char *name) +{ + int str_ptr; + int len; + + len = strlen(name) + 1; + str_ptr = tw->str_ptr; + tw->str_ptr += len; + + if (tw->str_ptr > abuf_size(&tw->str_buf)) { + int new_size; + + new_size = ALIGN(tw->str_ptr, 4096); + if (!abuf_realloc(&tw->str_buf, new_size)) + return -1; + } + + return str_ptr; +} + +/** + * push_len() - Push a new length request onto the stack + * + * @tw: Writer context + * @base: Base position of the length calculation + * @msg: Indicates the type of caller, for debugging + * @size: Size of the length value, either 4 bytes or 8 + * Returns number of bytes written to the file (=@size on success), -ve on error + * + * This marks a place where a length must be written, covering data that is + * about to be written. It writes a placeholder value. + * + * Once the data is written, calling pop_len() will update the placeholder with + * the correct length based on how many bytes have been written + */ +static int push_len(struct twriter *tw, int base, const char *msg, int size) +{ + struct tw_len *lp; + + if (tw->len_count >= LEN_STACK_SIZE) { + fprintf(stderr, "Length-stack overflow: %s\n", msg); + return -1; + } + if (size != 4 && size != 8) { + fprintf(stderr, "Length-stack invalid size %d: %s\n", size, + msg); + return -1; + } + + lp = &tw->len_stack[tw->len_count++]; + lp->base = base; + lp->ptr = tw->ptr; + lp->size = size; + + return size == 8 ? tputq(tw->fout, 0) : tputl(tw->fout, 0); +} + +/** + * pop_len() - Update a length value once the length is known + * + * Pops a value of the length stack and updates the file at that position with + * the number of bytes written between now and then. Once done, the file is + * seeked to the current (tw->ptr) position again, so writing can continue as + * normal. + * + * @tw: Writer context + * @msg: Indicates the type of caller, for debugging + * Returns 0 if OK, -1 on error + */ +static int pop_len(struct twriter *tw, const char *msg) +{ + struct tw_len *lp; + int len, ret; + + if (!tw->len_count) { + fprintf(stderr, "Length-stack underflow: %s\n", msg); + return -1; + } + + lp = &tw->len_stack[--tw->len_count]; + if (fseek(tw->fout, lp->ptr, SEEK_SET)) + return -1; + len = tw->ptr - lp->base; + ret = lp->size == 8 ? tputq(tw->fout, len) : tputl(tw->fout, len); + if (ret < 0) + return -1; + if (fseek(tw->fout, tw->ptr, SEEK_SET)) + return -1; + + return 0; +} + +/** + * start_header() - Start a v7 section + * + * Writes a header in v7 format + * + * @tw: Writer context + * @id: ID of header to write (SECTION_...) + * @flags: Flags value to write + * @name: Name of section + * Returns: number of bytes written + */ +static int start_header(struct twriter *tw, int id, uint flags, + const char *name) +{ + int str_id; + int lptr; + int base; + int ret; + + base = tw->ptr + 16; + lptr = 0; + lptr += tputh(tw->fout, id); + lptr += tputh(tw->fout, flags); + str_id = add_str(tw, name); + if (str_id < 0) + return -1; + lptr += tputl(tw->fout, str_id); + + /* placeholder for size */ + ret = push_len(tw, base, "v7 header", 8); + if (ret < 0) + return -1; + lptr += ret; + + return lptr; +} + +/** + * start_page() - Start a new page of output data + * + * The output is arranged in 4KB pages with a base timestamp at the start of + * each. This starts a new page, making sure it is aligned to 4KB in the output + * file. + * + * @tw: Writer context + * @timestamp: Base timestamp for the page + */ +static int start_page(struct twriter *tw, ulong timestamp) +{ + int start; + int ret; + + /* move to start of next page */ + start = ALIGN(tw->ptr, TRACE_PAGE_SIZE); + ret = fseek(tw->fout, start, SEEK_SET); + if (ret < 0) { + fprintf(stderr, "Cannot seek to page start\n"); + return -1; + } + tw->ptr = start; + + /* page header */ + tw->ptr += tputq(tw->fout, timestamp); + ret = push_len(tw, start + 16, "page", 8); + if (ret < 0) + return ret; + tw->ptr += ret; + + return 0; +} + +/** + * finish_page() - finish a page + * + * Sets the lengths correctly and moves to the start of the next page + * + * @tw: Writer context + * Returns: 0 on success, -1 on error + */ +static int finish_page(struct twriter *tw) +{ + int ret, end; + + ret = pop_len(tw, "page"); + if (ret < 0) + return ret; + end = ALIGN(tw->ptr, TRACE_PAGE_SIZE); + + /* + * Write a byte so that the data actually makes to the file, in the case + * that we never write any more pages + */ + if (tw->ptr != end) { + if (fseek(tw->fout, end - 1, SEEK_SET)) { + fprintf(stderr, "cannot seek to start of next page\n"); + return -1; + } + fputc(0, tw->fout); + tw->ptr = end; + } + + return 0; +} + +/** + * output_headers() - Output v6 headers to the file + * + * Writes out the various formats so that trace-cmd and kernelshark can make + * sense of the data + * + * This updates tw->ptr as it goes + * + * @tw: Writer context + * Returns: 0 on success, -ve on error + */ +static int output_headers(struct twriter *tw) +{ + FILE *fout = tw->fout; + char str[800]; + int len, ret; + + tw->ptr += fprintf(fout, "%c%c%ctracing6%c%c%c", 0x17, 0x08, 0x44, + 0 /* terminator */, 0 /* little endian */, + 4 /* 32-bit long values */); + + /* host-machine page size 4KB */ + tw->ptr += tputl(fout, 4 << 10); + + tw->ptr += fprintf(fout, "header_page%c", 0); + + snprintf(str, sizeof(str), + "\tfield: u64 timestamp;\toffset:0;\tsize:8;\tsigned:0;\n" + "\tfield: local_t commit;\toffset:8;\tsize:8;\tsigned:1;\n" + "\tfield: int overwrite;\toffset:8;\tsize:1;\tsigned:1;\n" + "\tfield: char data;\toffset:16;\tsize:4080;\tsigned:1;\n"); + len = strlen(str); + tw->ptr += tputq(fout, len); + tw->ptr += tputs(fout, str); + + if (VERSION7) { + /* no compression */ + tw->ptr += fprintf(fout, "none%cversion%c\n", 0, 0); + + ret = start_header(tw, SECTION_OPTIONS, 0, "options"); + if (ret < 0) { + fprintf(stderr, "Cannot start option header\n"); + return -1; + } + tw->ptr += ret; + tw->ptr += tputh(fout, OPTION_DONE); + tw->ptr += tputl(fout, 8); + tw->ptr += tputl(fout, 0); + ret = pop_len(tw, "t7 header"); + if (ret < 0) { + fprintf(stderr, "Cannot finish option header\n"); + return -1; + } + } + + tw->ptr += fprintf(fout, "header_event%c", 0); + snprintf(str, sizeof(str), + "# compressed entry header\n" + "\ttype_len : 5 bits\n" + "\ttime_delta : 27 bits\n" + "\tarray : 32 bits\n" + "\n" + "\tpadding : type == 29\n" + "\ttime_extend : type == 30\n" + "\ttime_stamp : type == 31\n" + "\tdata max type_len == 28\n"); + len = strlen(str); + tw->ptr += tputq(fout, len); + tw->ptr += tputs(fout, str); + + /* number of ftrace-event-format files */ + tw->ptr += tputl(fout, 3); + + snprintf(str, sizeof(str), + "name: function\n" + "ID: 1\n" + "format:\n" + "\tfield:unsigned short common_type;\toffset:0;\tsize:2;\tsigned:0;\n" + "\tfield:unsigned char common_flags;\toffset:2;\tsize:1;\tsigned:0;\n" + "\tfield:unsigned char common_preempt_count;\toffset:3;\tsize:1;signed:0;\n" + "\tfield:int common_pid;\toffset:4;\tsize:4;\tsigned:1;\n" + "\n" + "\tfield:unsigned long ip;\toffset:8;\tsize:8;\tsigned:0;\n" + "\tfield:unsigned long parent_ip;\toffset:16;\tsize:8;\tsigned:0;\n" + "\n" + "print fmt: \" %%ps <-- %%ps\", (void *)REC->ip, (void *)REC->parent_ip\n"); + len = strlen(str); + tw->ptr += tputq(fout, len); + tw->ptr += tputs(fout, str); + + snprintf(str, sizeof(str), + "name: funcgraph_entry\n" + "ID: 11\n" + "format:\n" + "\tfield:unsigned short common_type;\toffset:0;\tsize:2;\tsigned:0;\n" + "\tfield:unsigned char common_flags;\toffset:2;\tsize:1;\tsigned:0;\n" + "\tfield:unsigned char common_preempt_count;\toffset:3;\tsize:1;signed:0;\n" + "\tfield:int common_pid;\toffset:4;\tsize:4;\tsigned:1;\n" + "\n" + "\tfield:unsigned long func;\toffset:8;\tsize:8;\tsigned:0;\n" + "\tfield:int depth;\toffset:16;\tsize:4;\tsigned:1;\n" + "\n" + "print fmt: \"--> %%ps (%%d)\", (void *)REC->func, REC->depth\n"); + len = strlen(str); + tw->ptr += tputq(fout, len); + tw->ptr += tputs(fout, str); + + snprintf(str, sizeof(str), + "name: funcgraph_exit\n" + "ID: 10\n" + "format:\n" + "\tfield:unsigned short common_type;\toffset:0;\tsize:2;\tsigned:0;\n" + "\tfield:unsigned char common_flags;\toffset:2;\tsize:1;\tsigned:0;\n" + "\tfield:unsigned char common_preempt_count;\toffset:3;\tsize:1;signed:0;\n" + "\tfield:int common_pid;\toffset:4;\tsize:4;\tsigned:1;\n" + "\n" + "\tfield:unsigned long func;\toffset:8;\tsize:8;\tsigned:0;\n" + "\tfield:int depth;\toffset:16;\tsize:4;\tsigned:1;\n" + "\tfield:unsigned int overrun;\toffset:20;\tsize:4;\tsigned:0;\n" + "\tfield:unsigned long long calltime;\toffset:24;\tsize:8;\tsigned:0;\n" + "\tfield:unsigned long long rettime;\toffset:32;\tsize:8;\tsigned:0;\n" + "\n" + "print fmt: \"<-- %%ps (%%d) (start: %%llx end: %%llx) over: %%d\", (void *)REC->func, REC->depth, REC->calltime, REC->rettime, REC->depth\n"); + len = strlen(str); + tw->ptr += tputq(fout, len); + tw->ptr += tputs(fout, str); + + return 0; +} + +/** + * write_symbols() - Write the symbols out + * + * Writes the symbol information in the following format to mimic the Linux + * /proc/kallsyms file: + * + *
T + * + * This updates tw->ptr as it goes + * + * @tw: Writer context + * Returns: 0 on success, -ve on error + */ +static int write_symbols(struct twriter *tw) +{ + char str[200]; + int ret, i; + + /* write symbols */ + ret = push_len(tw, tw->ptr + 4, "syms", 4); + if (ret < 0) + return -1; + tw->ptr += ret; + for (i = 0; i < func_count; i++) { + struct func_info *func = &func_list[i]; + + snprintf(str, sizeof(str), "%016lx T %s\n", + text_offset + func->offset, func->name); + tw->ptr += tputs(tw->fout, str); + } + ret = pop_len(tw, "syms"); + if (ret < 0) + return -1; + tw->ptr += ret; + + return 0; +} + +/** + * write_options() - Write the options out + * + * Writes various options which are needed or useful. We use OPTION_TSC2NSEC + * to indicates that values in the output need to be multiplied by 1000 since + * U-Boot's trace values are in microseconds. + * + * This updates tw->ptr as it goes + * + * @tw: Writer context + * Returns: 0 on success, -ve on error + */ +static int write_options(struct twriter *tw) +{ + FILE *fout = tw->fout; + char str[200]; + int len; + + /* trace_printk, 0 for now */ + tw->ptr += tputl(fout, 0); + + /* processes */ + snprintf(str, sizeof(str), "%d u-boot\n", TRACE_PID); + len = strlen(str); + tw->ptr += tputq(fout, len); + tw->ptr += tputs(fout, str); + + /* number of CPUs */ + tw->ptr += tputl(fout, 1); + + tw->ptr += fprintf(fout, "options %c", 0); + + /* traceclock */ + tw->ptr += tputh(fout, OPTION_TRACECLOCK); + tw->ptr += tputl(fout, 0); + + /* uname */ + tw->ptr += tputh(fout, OPTION_UNAME); + snprintf(str, sizeof(str), "U-Boot"); + len = strlen(str); + tw->ptr += tputl(fout, len); + tw->ptr += tputs(fout, str); + + /* version */ + tw->ptr += tputh(fout, OPTION_VERSION); + snprintf(str, sizeof(str), "unknown"); + len = strlen(str); + tw->ptr += tputl(fout, len); + tw->ptr += tputs(fout, str); + + /* trace ID */ + tw->ptr += tputh(fout, OPTION_TRACEID); + tw->ptr += tputl(fout, 8); + tw->ptr += tputq(fout, 0x123456780abcdef0); + + /* time conversion */ + tw->ptr += tputh(fout, OPTION_TSC2NSEC); + tw->ptr += tputl(fout, 16); + tw->ptr += tputl(fout, 1000); /* multiplier */ + tw->ptr += tputl(fout, 0); /* shift */ + tw->ptr += tputq(fout, 0); /* offset */ + + /* cpustat - bogus data for now, but at least it mentions the CPU */ + tw->ptr += tputh(fout, OPTION_CPUSTAT); + snprintf(str, sizeof(str), + "CPU: 0\n" + "entries: 100\n" + "overrun: 43565\n" + "commit overrun: 0\n" + "bytes: 3360\n" + "oldest event ts: 963732.447752\n" + "now ts: 963832.146824\n" + "dropped events: 0\n" + "read events: 42379\n"); + len = strlen(str); + tw->ptr += tputl(fout, len); + tw->ptr += tputs(fout, str); + + tw->ptr += tputh(fout, OPTION_DONE); + + return 0; +} + +/** + * write_pages() - Write the pages of trace data + * + * This works through all the calls, writing out as many pages of data as are + * needed. + * + * @tw: Writer context + * @missing_countp: Returns number of missing functions (not found in function + * list) + * @skip_countp: Returns number of skipped functions (excluded from trace) + * + * Returns: 0 on success, -ve on error + */ +static int write_pages(struct twriter *tw, int *missing_countp, + int *skip_countp) +{ + int stack_ptr; /* next free position in stack */ + int upto, page_upto, i; int missing_count = 0, skip_count = 0; - int i; + struct trace_call *call; + ulong last_timestamp; + FILE *fout = tw->fout; + int last_delta = 0; + int err_count; + bool in_page; + + in_page = false; + last_timestamp = 0; + upto = 0; + page_upto = 0; + err_count = 0; + + /* maintain a stack of start times for calling functions */ + stack_ptr = 0; - printf("# tracer: function\n" - "#\n" - "# entries-in-buffer/entries-written: 140080/250280 #P:4\n" - "#\n" - "# _-----=> irqs-off\n" - "# / _----=> need-resched\n" - "# | / _---=> hardirq/softirq\n" - "# || / _--=> preempt-depth\n" - "# ||| / delay\n" - "# TASK-PID CPU# |||| TIMESTAMP FUNCTION\n" - "# | | | |||| | |\n"); for (i = 0, call = call_list; i < call_count; i++, call++) { - struct func_info *func = find_func_by_offset(call->func); - ulong time = call->flags & FUNCF_TIMESTAMP_MASK; + struct func_info *caller_func; + struct func_info *func; + ulong timestamp; + uint rec_words; + int delta; - if (TRACE_CALL_TYPE(call) != FUNCF_ENTRY && - TRACE_CALL_TYPE(call) != FUNCF_EXIT) - continue; + func = find_func_by_offset(call->func); if (!func) { warn("Cannot find function at %lx\n", text_offset + call->func); missing_count++; + if (missing_count > 20) { + /* perhaps trace does not match System.map */ + fprintf(stderr, "Too many missing functions\n"); + return -1; + } continue; } @@ -629,12 +1251,186 @@ static int make_ftrace(void) continue; } - printf("%16s-%-5d [000] .... %lu.%06lu: ", "uboot", 1, - time / 1000000, time % 1000000); + rec_words = 6; - out_func(call->func, 0, " <- "); - out_func(call->caller, 1, "\n"); + /* convert timestamp from us to ns */ + timestamp = call->flags & FUNCF_TIMESTAMP_MASK; + if (in_page) { + if (page_upto + rec_words * 4 > TRACE_PAGE_SIZE) { + if (finish_page(tw)) + return -1; + in_page = false; + } + } + if (!in_page) { + if (start_page(tw, timestamp)) + return -1; + in_page = true; + last_timestamp = timestamp; + last_delta = 0; + page_upto = tw->ptr & TRACE_PAGE_MASK; + if (_DEBUG) { + fprintf(stderr, + "new page, last_timestamp=%ld, upto=%d\n", + last_timestamp, upto); + } + } + + delta = timestamp - last_timestamp; + if (delta < 0) { + fprintf(stderr, "Time went backwards\n"); + err_count++; + } + + if (err_count > 20) { + fprintf(stderr, "Too many errors, giving up\n"); + return -1; + } + + if (delta > 0x07fffff) { + /* + * hard to imagine how this could happen since it means + * that no function calls were made for a long time + */ + fprintf(stderr, "cannot represent time delta %x\n", + delta); + return -1; + } + + if (_DEBUG) { + fprintf(stderr, "%d: delta=%d, stamp=%ld\n", + upto, delta, timestamp); + fprintf(stderr, + " last_delta %x to %x: last_timestamp=%lx, timestamp=%lx, call->flags=%x, upto=%d\n", + last_delta, delta, last_timestamp, timestamp, call->flags, upto); + } + + /* type_len is 6, meaning 4 * 6 = 24 bytes */ + tw->ptr += tputl(fout, rec_words | (uint)delta << 5); + tw->ptr += tputh(fout, TRACE_FN); + tw->ptr += tputh(fout, 0); /* flags */ + tw->ptr += tputl(fout, TRACE_PID); /* PID */ + /* function */ + tw->ptr += tputq(fout, text_offset + func->offset); + caller_func = find_caller_by_offset(call->caller); + /* caller */ + tw->ptr += tputq(fout, text_offset + caller_func->offset); + + last_delta = delta; + last_timestamp = timestamp; + page_upto += 4 + rec_words * 4; + upto++; + if (stack_ptr == MAX_STACK_DEPTH) + break; } + if (in_page && finish_page(tw)) + return -1; + *missing_countp = missing_count; + *skip_countp = skip_count; + + return 0; +} + +/** + * write_flyrecord() - Write the flyrecord information + * + * Writes the header and pages of data for the "flyrecord" section. It also + * writes out the counter-type info, selecting "[local]" + * + * @tw: Writer context + * @missing_countp: Returns number of missing functions (not found in function + * list) + * @skip_countp: Returns number of skipped functions (excluded from trace) + * + * Returns: 0 on success, -ve on error + */ +static int write_flyrecord(struct twriter *tw, int *missing_countp, + int *skip_countp) +{ + int start, ret, len; + FILE *fout = tw->fout; + char str[200]; + + tw->ptr += fprintf(fout, "flyrecord%c", 0); + + /* trace data */ + start = ALIGN(tw->ptr + 16, TRACE_PAGE_SIZE); + tw->ptr += tputq(fout, start); + + /* use a placeholder for the size */ + ret = push_len(tw, start, "flyrecord", 8); + if (ret < 0) + return -1; + tw->ptr += ret; + + snprintf(str, sizeof(str), + "[local] global counter uptime perf mono mono_raw boot x86-tsc\n"); + len = strlen(str); + tw->ptr += tputq(fout, len); + tw->ptr += tputs(fout, str); + + ret = write_pages(tw, missing_countp, skip_countp); + if (ret < 0) { + fprintf(stderr, "Cannot output pages\n"); + return -1; + } + + ret = pop_len(tw, "flyrecord"); + if (ret < 0) { + fprintf(stderr, "Cannot finish flyrecord header\n"); + return -1; + } + + return 0; +} + +/** + * make_ftrace() - Write out an ftrace file + * + * See here for format: + * + * https://github.com/rostedt/trace-cmd/blob/master/Documentation/trace-cmd/trace-cmd.dat.v7.5.txt + * + * @fout: Output file + * Returns: 0 on success, -ve on error + */ +static int make_ftrace(FILE *fout) +{ + int missing_count, skip_count; + struct twriter tws, *tw = &tws; + int ret; + + memset(tw, '\0', sizeof(*tw)); + abuf_init(&tw->str_buf); + tw->fout = fout; + + tw->ptr = 0; + ret = output_headers(tw); + if (ret < 0) { + fprintf(stderr, "Cannot output headers\n"); + return -1; + } + /* number of event systems files */ + tw->ptr += tputl(fout, 0); + + ret = write_symbols(tw); + if (ret < 0) { + fprintf(stderr, "Cannot write symbols\n"); + return -1; + } + + ret = write_options(tw); + if (ret < 0) { + fprintf(stderr, "Cannot write options\n"); + return -1; + } + + ret = write_flyrecord(tw, &missing_count, &skip_count); + if (ret < 0) { + fprintf(stderr, "Cannot write flyrecord\n"); + return -1; + } + info("ftrace: %d functions not found, %d excluded\n", missing_count, skip_count); @@ -669,10 +1465,20 @@ static int prof_tool(int argc, char *const argv[], for (; argc; argc--, argv++) { const char *cmd = *argv; - if (0 == strcmp(cmd, "dump-ftrace")) - err = make_ftrace(); - else + if (!strcmp(cmd, "dump-ftrace")) { + FILE *fout; + + fout = fopen(out_fname, "w"); + if (!fout) { + fprintf(stderr, "Cannot write file '%s'\n", + out_fname); + return -1; + } + err = make_ftrace(fout); + fclose(fout); + } else { warn("Unknown command '%s'\n", cmd); + } } return err; From patchwork Sun Jan 15 21:15:54 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 1726839 X-Patchwork-Delegate: trini@ti.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=85.214.62.61; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: legolas.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=chromium.org header.i=@chromium.org header.a=rsa-sha256 header.s=google header.b=k8DqbLV9; dkim-atps=neutral Received: from phobos.denx.de (phobos.denx.de [85.214.62.61]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4Nw7N35N2Nz23fk for ; Mon, 16 Jan 2023 08:20:03 +1100 (AEDT) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 49C0F85611; Sun, 15 Jan 2023 22:17:18 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=chromium.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (1024-bit key; unprotected) header.d=chromium.org header.i=@chromium.org header.b="k8DqbLV9"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id F27F7855D6; Sun, 15 Jan 2023 22:16:47 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,SPF_HELO_NONE, SPF_PASS autolearn=ham autolearn_force=no version=3.4.2 Received: from mail-io1-xd35.google.com (mail-io1-xd35.google.com [IPv6:2607:f8b0:4864:20::d35]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id 8DC7C855D5 for ; Sun, 15 Jan 2023 22:16:37 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=chromium.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=sjg@chromium.org Received: by mail-io1-xd35.google.com with SMTP id j1so4590113iob.6 for ; Sun, 15 Jan 2023 13:16:37 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=BuRhzBIwjhF92pqpj7CwEvhiEXfKaKtmP+vlrFwCDGw=; b=k8DqbLV9ZOZI+jOFj5b5XViNq3DVNn9kOxYfGkS+1ODG6lakQD056Agu3kAthxnne+ n6IXQQDLW9xVWwuY5rKYX8eMA2yYbYrvh23baGgYdF5xNsdiHSRL3Q2AG5vakdgBd0Im QEI9LitbVT1oVUHseuAIz4xROTLiA0pjTxq1E= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=BuRhzBIwjhF92pqpj7CwEvhiEXfKaKtmP+vlrFwCDGw=; b=PVuMdHfFhRGUWTMobB7PIgzMDvfe7vt+FDwwHnqGBXdnoTEUqyUD3eE1+c7pZWyRqQ GspcPHuzydGs9Sxr/4fM/ZGkdNjm1PnklyzFsKfLTIPgqA1VEztZbR7VgoyRB2s2LhT9 /sW3W3jobVCqkqoWOsmQ/u+geVLtPLrv5QEtzGaNghOBr9zWCuNTtlgpGN/T0kDEdQqT K8W5fMNCcrI1gBy/5uQa6vSWSNaq/t5SIosjijKHKR5ygm3SxMMWduf6yKre6eASosiE qjJ7ik2wgDfKyS2A/F+vFgDb/nkIy+XDpRabnDiSvxPb6C1VjsIjAAlnHZ0EXjZL2ZBf OJOw== X-Gm-Message-State: AFqh2kqwF/kgyLS+ZlMuyAFy2uXjCqj9NUNo7+b9U6Ltt9MfaHs5q4O9 2hHPe89PWHwMiE7YX3xLMeRrawBsw17Khh+eYjY= X-Google-Smtp-Source: AMrXdXvDhlW4G01E7el2dq5JXh8epqFVwyYv13mriquz/SXsqRTWt/RTGj633UUK8lNAfdrGfmsMcA== X-Received: by 2002:a5d:93c7:0:b0:6e2:ceed:fd49 with SMTP id j7-20020a5d93c7000000b006e2ceedfd49mr61706012ioo.7.1673817396066; Sun, 15 Jan 2023 13:16:36 -0800 (PST) Received: from sjg1.roam.corp.google.com (c-73-14-173-85.hsd1.co.comcast.net. [73.14.173.85]) by smtp.gmail.com with ESMTPSA id j6-20020a6bf906000000b007046e9e138esm4329107iog.22.2023.01.15.13.16.35 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 15 Jan 2023 13:16:35 -0800 (PST) From: Simon Glass To: U-Boot Mailing List Cc: Tom Rini , Heinrich Schuchardt , Simon Glass Subject: [PATCH 17/24] trace: Drop use of objsection Date: Sun, 15 Jan 2023 14:15:54 -0700 Message-Id: <20230115211602.1127661-18-sjg@chromium.org> X-Mailer: git-send-email 2.39.0.314.g84b9a713c41-goog In-Reply-To: <20230115211602.1127661-1-sjg@chromium.org> References: <20230115211602.1127661-1-sjg@chromium.org> MIME-Version: 1.0 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.39 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.103.6 at phobos.denx.de X-Virus-Status: Clean This feature was only partly implemented and serves no current purpose. Drop it. Signed-off-by: Simon Glass --- tools/proftool.c | 29 +---------------------------- 1 file changed, 1 insertion(+), 28 deletions(-) diff --git a/tools/proftool.c b/tools/proftool.c index feeef55c1b9..0d74e1169a9 100644 --- a/tools/proftool.c +++ b/tools/proftool.c @@ -95,14 +95,12 @@ enum trace_type { * @name: Function name * @code_size: Total code size of the function * @flags: Either 0 or FUNCF_TRACE - * @objsection: the section this function is in */ struct func_info { unsigned long offset; const char *name; unsigned long code_size; unsigned flags; - struct objsection_info *objsection; }; /** @@ -540,31 +538,6 @@ static void check_trace_config(void) check_trace_config_line(line); } -/** - * Check the functions to see if they each have an objsection. If not, then - * the linker must have eliminated them. - */ -static void check_functions(void) -{ - struct func_info *func, *end; - unsigned long removed_code_size = 0; - int not_found = 0; - - /* Look for missing functions */ - for (func = func_list, end = func + func_count; func < end; func++) { - if (!func->objsection) { - removed_code_size += func->code_size; - not_found++; - } - } - - /* Figure out what functions we want to trace */ - check_trace_config(); - - warn("%d functions removed by linker, %ld code size\n", - not_found, removed_code_size); -} - /** * read_trace_config() - read the trace-config file * @@ -1460,7 +1433,7 @@ static int prof_tool(int argc, char *const argv[], if (trace_config_fname && read_trace_config_file(trace_config_fname)) return -1; - check_functions(); + check_trace_config(); for (; argc; argc--, argv++) { const char *cmd = *argv; From patchwork Sun Jan 15 21:15:55 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 1726838 X-Patchwork-Delegate: trini@ti.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=85.214.62.61; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: legolas.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=chromium.org header.i=@chromium.org header.a=rsa-sha256 header.s=google header.b=X0+0sCqH; dkim-atps=neutral Received: from phobos.denx.de (phobos.denx.de [85.214.62.61]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4Nw7Mr0B4hz23fk for ; Mon, 16 Jan 2023 08:19:52 +1100 (AEDT) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 04AA085601; Sun, 15 Jan 2023 22:17:15 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=chromium.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (1024-bit key; unprotected) header.d=chromium.org header.i=@chromium.org header.b="X0+0sCqH"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id C48E5855D3; Sun, 15 Jan 2023 22:16:47 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,SPF_HELO_NONE, SPF_PASS autolearn=ham autolearn_force=no version=3.4.2 Received: from mail-io1-xd34.google.com (mail-io1-xd34.google.com [IPv6:2607:f8b0:4864:20::d34]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id 491A8855BA for ; Sun, 15 Jan 2023 22:16:37 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=chromium.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=sjg@chromium.org Received: by mail-io1-xd34.google.com with SMTP id d22so4046007iof.5 for ; Sun, 15 Jan 2023 13:16:37 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=c6WJNL3E4etRH69sbYHhnnsdO6Sgk474f6IwhI2ZthY=; b=X0+0sCqHNBt9/rHi9h7v8ZtC+QtKXoKT1rCdDUe+kyTE+r8l1KieSVvo/00BOf2mrw Q0wlsDyzYyeQVz0mpdLmZAz+DnGDP94sCnfu4o0UroKfmNGvZwlCvj4y12yR9aukD4Do ImI70U34CBDGejMVx8yRd7pV3fm/nW2n3p53Y= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=c6WJNL3E4etRH69sbYHhnnsdO6Sgk474f6IwhI2ZthY=; b=A83B8fCUYbrPWJuWn3XAwl+2W3KspJy/dz5BuZPZZp8MS69FaYWZwCtHiK3MrmqINQ Huv5D1Ln9IQ7Fp1gy5EDcaTa4NSddfwfddLt55CWeJgTWVYXA8XbN7gahah1LWnJIIwz 4lXaXqWAKMParbWoLUsCQK9MJlxXFRlSFOrVBWDuehEFXyCA651rRwqBd+2RazX1Aqjm f9ZXUuSvDlcd7YkxeDAlsclAopLGTuY+gg6MNl/LgqwY71CkyfFcWes85EeOGka7JR7B wVG2cTtOnLvpxU9FWayKwVfrAPNzNOVy9xFyrfOqLZo00HWYjKRF0No8dam9w2GCIIup QtFQ== X-Gm-Message-State: AFqh2kpGjwhbXENBCQ68AZHswhvoSv80nW8eoKXHi6BSWxAw4wbCc2Lj N/eHW2Np6jmx33/Bc8Z+LvxQQbVnKBG50z5A2oM= X-Google-Smtp-Source: AMrXdXvcJILgAabXZ5MvCtgdvIEelGBGvEzuNpwCDWuG4BzuiBQB8N4C3xsR2zlU9J+Hak2bkZO28g== X-Received: by 2002:a05:6602:18a:b0:6e1:58c5:9dc with SMTP id m10-20020a056602018a00b006e158c509dcmr57715317ioo.6.1673817396791; Sun, 15 Jan 2023 13:16:36 -0800 (PST) Received: from sjg1.roam.corp.google.com (c-73-14-173-85.hsd1.co.comcast.net. [73.14.173.85]) by smtp.gmail.com with ESMTPSA id j6-20020a6bf906000000b007046e9e138esm4329107iog.22.2023.01.15.13.16.36 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 15 Jan 2023 13:16:36 -0800 (PST) From: Simon Glass To: U-Boot Mailing List Cc: Tom Rini , Heinrich Schuchardt , Simon Glass Subject: [PATCH 18/24] trace: Use text_base from the trace header Date: Sun, 15 Jan 2023 14:15:55 -0700 Message-Id: <20230115211602.1127661-19-sjg@chromium.org> X-Mailer: git-send-email 2.39.0.314.g84b9a713c41-goog In-Reply-To: <20230115211602.1127661-1-sjg@chromium.org> References: <20230115211602.1127661-1-sjg@chromium.org> MIME-Version: 1.0 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.39 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.103.6 at phobos.denx.de X-Virus-Status: Clean Use the information in the trace header instead of reading it from the trace records. Add debugging to check that System.map and the trace header agree on this value. Signed-off-by: Simon Glass --- tools/proftool.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tools/proftool.c b/tools/proftool.c index 0d74e1169a9..b5b8a9f7938 100644 --- a/tools/proftool.c +++ b/tools/proftool.c @@ -179,6 +179,7 @@ struct trace_call *call_list; /* list of all calls in the input trace file */ int call_count; /* number of calls */ int verbose; /* Verbosity level 0=none, 1=warn, 2=notice, 3=info, 4=debug */ ulong text_offset; /* text address of first function */ +ulong text_base; /* CONFIG_TEXT_BASE from trace file */ /* debugging helpers */ static void outf(int level, const char *fmt, ...) @@ -289,7 +290,8 @@ static int read_system_map(FILE *fin) if (func_count > 1) func[-1].code_size = func->offset - func[-1].offset; } - notice("%d functions found in map file\n", func_count); + notice("%d functions found in map file, start addr %lx\n", func_count, + start); text_offset = start; return 0; @@ -415,6 +417,7 @@ static int read_trace(FILE *fin) break; /* EOF */ else if (err) return 1; + text_base = hdr.text_base; switch (hdr.type) { case TRACE_CHUNK_FUNCS: @@ -1342,6 +1345,8 @@ static int write_flyrecord(struct twriter *tw, int *missing_countp, tw->ptr += tputq(fout, len); tw->ptr += tputs(fout, str); + debug("trace text base %lx, map file %lx\n", text_base, text_offset); + ret = write_pages(tw, missing_countp, skip_countp); if (ret < 0) { fprintf(stderr, "Cannot output pages\n"); From patchwork Sun Jan 15 21:15:56 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 1726836 X-Patchwork-Delegate: trini@ti.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=85.214.62.61; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: legolas.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=chromium.org header.i=@chromium.org header.a=rsa-sha256 header.s=google header.b=BIofFG1e; dkim-atps=neutral Received: from phobos.denx.de (phobos.denx.de [85.214.62.61]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4Nw7MN6GJbz23fk for ; Mon, 16 Jan 2023 08:19:28 +1100 (AEDT) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 8F1838559B; Sun, 15 Jan 2023 22:17:09 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=chromium.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (1024-bit key; unprotected) header.d=chromium.org header.i=@chromium.org header.b="BIofFG1e"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id 8152C855D3; Sun, 15 Jan 2023 22:16:46 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,SPF_HELO_NONE, SPF_PASS autolearn=ham autolearn_force=no version=3.4.2 Received: from mail-io1-xd2d.google.com (mail-io1-xd2d.google.com [IPv6:2607:f8b0:4864:20::d2d]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id 3F4AD855B3 for ; Sun, 15 Jan 2023 22:16:38 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=chromium.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=sjg@chromium.org Received: by mail-io1-xd2d.google.com with SMTP id i70so3632582ioa.12 for ; Sun, 15 Jan 2023 13:16:38 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=QWe8me6Gcm7CSsBAvECqAAy7Bd8uxajlFoYvaIGGkeY=; b=BIofFG1eH98W6MSdwZqqfUr5ZuFvLo3shlk39L9omT1j8VJwGiEmZegOyR1vKSYdUk GlDHeyoy+NSZvV1Qf0pH+5+giZ1ArbEkwmBL3ul7d+36XyS7FSYuZEbGYGpH/tumZwvR 22s5odBuDazFnhVFEyZQsuA2Mqr/wCMsoppQk= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=QWe8me6Gcm7CSsBAvECqAAy7Bd8uxajlFoYvaIGGkeY=; b=f/uG+7yUNXp5LNboAKWrIZ//u0vKDNHmrx90/OLft9VUyXFB0xPXnPMeaUdZ3FiSmG IzXcc44GyOHAz3B2HwizkSd4sE/JbkeCeXf8sLPsCwXWx/nMVneweyV8QpNOqFE01XN0 vfjj4zLsX1QDmUtb/05rrLaBbyHISMtv+7jv2JBVgwvWySYnzxJLQmxU0wRqwVqCr5q9 k5Hdi1tPIuZ9e1S7lEPK9BbkAYoszMQbYnWMjCqENopIO6mMTPpv1dMgrB1txHzkUYI+ MAjKU/G8HlugiLhvwEh38nmF4WY3ypblJSrgLYS0rLc+NUiXej6H2FfHfvek/vv4dk8G hpdQ== X-Gm-Message-State: AFqh2krvGJNJ02t5MxLBuKhQg3ikQsL8GLa0VKxLan256U25ywxS7OEu OMCAUojbOpUKXgwalpoHHYOHaHojp9JcH47cA5U= X-Google-Smtp-Source: AMrXdXuA1NRIqxgCCGTT4+sNS3sTo1kAOSJ3DWLZkdopefVjm0eV+4HVFxRWQHfyrEgC0sDWRcDb6A== X-Received: by 2002:a05:6602:154:b0:6bc:d71a:2b47 with SMTP id v20-20020a056602015400b006bcd71a2b47mr53811360iot.8.1673817397549; Sun, 15 Jan 2023 13:16:37 -0800 (PST) Received: from sjg1.roam.corp.google.com (c-73-14-173-85.hsd1.co.comcast.net. [73.14.173.85]) by smtp.gmail.com with ESMTPSA id j6-20020a6bf906000000b007046e9e138esm4329107iog.22.2023.01.15.13.16.37 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 15 Jan 2023 13:16:37 -0800 (PST) From: Simon Glass To: U-Boot Mailing List Cc: Tom Rini , Heinrich Schuchardt , Simon Glass Subject: [PATCH 19/24] trace: Support output of funcgraph records Date: Sun, 15 Jan 2023 14:15:56 -0700 Message-Id: <20230115211602.1127661-20-sjg@chromium.org> X-Mailer: git-send-email 2.39.0.314.g84b9a713c41-goog In-Reply-To: <20230115211602.1127661-1-sjg@chromium.org> References: <20230115211602.1127661-1-sjg@chromium.org> MIME-Version: 1.0 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.39 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.103.6 at phobos.denx.de X-Virus-Status: Clean Add support for writing ftrace records in the 'funcgraph' format, which shows function entry and exit points as well as the time taken by each function. Signed-off-by: Simon Glass --- tools/proftool.c | 182 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 150 insertions(+), 32 deletions(-) diff --git a/tools/proftool.c b/tools/proftool.c index b5b8a9f7938..588ae48a0c8 100644 --- a/tools/proftool.c +++ b/tools/proftool.c @@ -47,6 +47,19 @@ enum { MAX_LINE_LEN = 500, /* Max characters per line */ }; +/** + * enum out_format_t - supported output formats + * + * @OUT_FMT_DEFAULT: Use the default for the output file + * @OUT_FMT_FUNCTION: Write ftrace 'function' records + * @OUT_FMT_FUNCGRAPH: Write ftrace funcgraph_entry and funcgraph_exit records + */ +enum out_format_t { + OUT_FMT_DEFAULT, + OUT_FMT_FUNCTION, + OUT_FMT_FUNCGRAPH, +}; + /* Section types for v7 format (trace-cmd format) */ enum { SECTION_OPTIONS, @@ -211,10 +224,15 @@ static void usage(void) "\n" "Options:\n" " -c \tSpecify config file\n" + " -f \tSpecify output subtype\n" " -m \tSpecify Systen.map file\n" " -o \tSpecify output file\n" " -t \tSpecify trace data file (from U-Boot 'trace calls')\n" - " -v <0-4>\tSpecify verbosity\n"); + " -v <0-4>\tSpecify verbosity\n" + "\n" + "Subtypes for dump-ftrace:\n" + " function - write function-call records (caller/callee)\n" + " funcgraph - write function entry/exit records (graph)\n"); exit(EXIT_FAILURE); } @@ -1165,6 +1183,43 @@ static int write_options(struct twriter *tw) return 0; } +/** + * calc_min_depth() - Calculate the minimum call depth from the call list + * + * Starting with a depth of 0, this works through the call list, adding 1 for + * each function call and subtracting 1 for each function return. Most likely + * the value ends up being negative, since the trace does not start at the + * very top of the call stack, e.g. main(), but some function called by that. + * + * This value can be used to calculate the depth value for the first call, + * such that it never goes negative for subsequent returns. + * + * Returns: minimum call depth (e.g. -2) + */ +static int calc_min_depth(void) +{ + struct trace_call *call; + int depth, min_depth, i; + + /* Calculate minimum depth */ + depth = 0; + min_depth = 0; + for (i = 0, call = call_list; i < call_count; i++, call++) { + switch (TRACE_CALL_TYPE(call)) { + case FUNCF_ENTRY: + depth++; + break; + case FUNCF_EXIT: + depth--; + if (depth < min_depth) + min_depth = depth; + break; + } + } + + return min_depth; +} + /** * write_pages() - Write the pages of trace data * @@ -1172,17 +1227,19 @@ static int write_options(struct twriter *tw) * needed. * * @tw: Writer context + * @out_format: Output format to use * @missing_countp: Returns number of missing functions (not found in function * list) * @skip_countp: Returns number of skipped functions (excluded from trace) * * Returns: 0 on success, -ve on error */ -static int write_pages(struct twriter *tw, int *missing_countp, - int *skip_countp) +static int write_pages(struct twriter *tw, enum out_format_t out_format, + int *missing_countp, int *skip_countp) { + ulong func_stack[MAX_STACK_DEPTH]; int stack_ptr; /* next free position in stack */ - int upto, page_upto, i; + int upto, depth, page_upto, i; int missing_count = 0, skip_count = 0; struct trace_call *call; ulong last_timestamp; @@ -1200,8 +1257,13 @@ static int write_pages(struct twriter *tw, int *missing_countp, /* maintain a stack of start times for calling functions */ stack_ptr = 0; + /* + * The first thing in the trace may not be the top-level function, so + * set the initial depth so that no function goes below depth 0 + */ + depth = -calc_min_depth(); for (i = 0, call = call_list; i < call_count; i++, call++) { - struct func_info *caller_func; + bool entry = TRACE_CALL_TYPE(call) == FUNCF_ENTRY; struct func_info *func; ulong timestamp; uint rec_words; @@ -1227,7 +1289,10 @@ static int write_pages(struct twriter *tw, int *missing_countp, continue; } - rec_words = 6; + if (out_format == OUT_FMT_FUNCTION) + rec_words = 6; + else /* 2 header words and then 3 or 8 others */ + rec_words = 2 + (entry ? 3 : 8); /* convert timestamp from us to ns */ timestamp = call->flags & FUNCF_TIMESTAMP_MASK; @@ -1273,24 +1338,59 @@ static int write_pages(struct twriter *tw, int *missing_countp, return -1; } - if (_DEBUG) { - fprintf(stderr, "%d: delta=%d, stamp=%ld\n", - upto, delta, timestamp); - fprintf(stderr, - " last_delta %x to %x: last_timestamp=%lx, timestamp=%lx, call->flags=%x, upto=%d\n", - last_delta, delta, last_timestamp, timestamp, call->flags, upto); - } + if (out_format == OUT_FMT_FUNCTION) { + struct func_info *caller_func; - /* type_len is 6, meaning 4 * 6 = 24 bytes */ - tw->ptr += tputl(fout, rec_words | (uint)delta << 5); - tw->ptr += tputh(fout, TRACE_FN); - tw->ptr += tputh(fout, 0); /* flags */ - tw->ptr += tputl(fout, TRACE_PID); /* PID */ - /* function */ - tw->ptr += tputq(fout, text_offset + func->offset); - caller_func = find_caller_by_offset(call->caller); - /* caller */ - tw->ptr += tputq(fout, text_offset + caller_func->offset); + if (_DEBUG) { + fprintf(stderr, "%d: delta=%d, stamp=%ld\n", + upto, delta, timestamp); + fprintf(stderr, + " last_delta %x to %x: last_timestamp=%lx, " + "timestamp=%lx, call->flags=%x, upto=%d\n", + last_delta, delta, last_timestamp, + timestamp, call->flags, upto); + } + + /* type_len is 6, meaning 4 * 6 = 24 bytes */ + tw->ptr += tputl(fout, rec_words | (uint)delta << 5); + tw->ptr += tputh(fout, TRACE_FN); + tw->ptr += tputh(fout, 0); /* flags */ + tw->ptr += tputl(fout, TRACE_PID); /* PID */ + /* function */ + tw->ptr += tputq(fout, text_offset + func->offset); + caller_func = find_caller_by_offset(call->caller); + /* caller */ + tw->ptr += tputq(fout, + text_offset + caller_func->offset); + } else { + tw->ptr += tputl(fout, rec_words | delta << 5); + tw->ptr += tputh(fout, entry ? TRACE_GRAPH_ENT + : TRACE_GRAPH_RET); + tw->ptr += tputh(fout, 0); /* flags */ + tw->ptr += tputl(fout, TRACE_PID); /* PID */ + /* function */ + tw->ptr += tputq(fout, text_offset + func->offset); + tw->ptr += tputl(fout, depth); /* depth */ + if (entry) { + depth++; + if (stack_ptr < MAX_STACK_DEPTH) + func_stack[stack_ptr] = timestamp; + stack_ptr++; + } else { + ulong func_duration = 0; + + depth--; + if (stack_ptr && stack_ptr <= MAX_STACK_DEPTH) { + ulong start = func_stack[--stack_ptr]; + + func_duration = timestamp - start; + } + tw->ptr += tputl(fout, 0); /* overrun */ + tw->ptr += tputq(fout, 0); /* calltime */ + /* rettime */ + tw->ptr += tputq(fout, func_duration); + } + } last_delta = delta; last_timestamp = timestamp; @@ -1314,14 +1414,15 @@ static int write_pages(struct twriter *tw, int *missing_countp, * writes out the counter-type info, selecting "[local]" * * @tw: Writer context + * @out_format: Output format to use * @missing_countp: Returns number of missing functions (not found in function * list) * @skip_countp: Returns number of skipped functions (excluded from trace) * * Returns: 0 on success, -ve on error */ -static int write_flyrecord(struct twriter *tw, int *missing_countp, - int *skip_countp) +static int write_flyrecord(struct twriter *tw, enum out_format_t out_format, + int *missing_countp, int *skip_countp) { int start, ret, len; FILE *fout = tw->fout; @@ -1347,7 +1448,7 @@ static int write_flyrecord(struct twriter *tw, int *missing_countp, debug("trace text base %lx, map file %lx\n", text_base, text_offset); - ret = write_pages(tw, missing_countp, skip_countp); + ret = write_pages(tw, out_format, missing_countp, skip_countp); if (ret < 0) { fprintf(stderr, "Cannot output pages\n"); return -1; @@ -1370,9 +1471,10 @@ static int write_flyrecord(struct twriter *tw, int *missing_countp, * https://github.com/rostedt/trace-cmd/blob/master/Documentation/trace-cmd/trace-cmd.dat.v7.5.txt * * @fout: Output file + * @out_format: Output format to use * Returns: 0 on success, -ve on error */ -static int make_ftrace(FILE *fout) +static int make_ftrace(FILE *fout, enum out_format_t out_format) { int missing_count, skip_count; struct twriter tws, *tw = &tws; @@ -1403,7 +1505,7 @@ static int make_ftrace(FILE *fout) return -1; } - ret = write_flyrecord(tw, &missing_count, &skip_count); + ret = write_flyrecord(tw, out_format, &missing_count, &skip_count); if (ret < 0) { fprintf(stderr, "Cannot write flyrecord\n"); return -1; @@ -1427,7 +1529,8 @@ static int make_ftrace(FILE *fout) */ static int prof_tool(int argc, char *const argv[], const char *trace_fname, const char *map_fname, - const char *trace_config_fname, const char *out_fname) + const char *trace_config_fname, const char *out_fname, + enum out_format_t out_format) { int err = 0; @@ -1446,13 +1549,16 @@ static int prof_tool(int argc, char *const argv[], if (!strcmp(cmd, "dump-ftrace")) { FILE *fout; + if (out_format != OUT_FMT_FUNCTION && + out_format != OUT_FMT_FUNCGRAPH) + out_format = OUT_FMT_FUNCTION; fout = fopen(out_fname, "w"); if (!fout) { fprintf(stderr, "Cannot write file '%s'\n", out_fname); return -1; } - err = make_ftrace(fout); + err = make_ftrace(fout, out_format); fclose(fout); } else { warn("Unknown command '%s'\n", cmd); @@ -1464,6 +1570,7 @@ static int prof_tool(int argc, char *const argv[], int main(int argc, char *argv[]) { + enum out_format_t out_format = OUT_FMT_DEFAULT; const char *map_fname = "System.map"; const char *trace_fname = NULL; const char *config_fname = NULL; @@ -1471,11 +1578,22 @@ int main(int argc, char *argv[]) int opt; verbose = 2; - while ((opt = getopt(argc, argv, "c:m:o:t:v:")) != -1) { + while ((opt = getopt(argc, argv, "c:f:m:o:t:v:")) != -1) { switch (opt) { case 'c': config_fname = optarg; break; + case 'f': + if (!strcmp("function", optarg)) { + out_format = OUT_FMT_FUNCTION; + } else if (!strcmp("funcgraph", optarg)) { + out_format = OUT_FMT_FUNCGRAPH; + } else { + fprintf(stderr, + "Invalid format: use function, funcgraph, calls, timing\n"); + exit(1); + } + break; case 'm': map_fname = optarg; break; @@ -1504,5 +1622,5 @@ int main(int argc, char *argv[]) debug("Debug enabled\n"); return prof_tool(argc, argv, trace_fname, map_fname, config_fname, - out_fname); + out_fname, out_format); } From patchwork Sun Jan 15 21:15:57 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 1726840 X-Patchwork-Delegate: trini@ti.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=2a01:238:438b:c500:173d:9f52:ddab:ee01; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: legolas.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=chromium.org header.i=@chromium.org header.a=rsa-sha256 header.s=google header.b=CtNNJExc; dkim-atps=neutral Received: from phobos.denx.de (phobos.denx.de [IPv6:2a01:238:438b:c500:173d:9f52:ddab:ee01]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4Nw7NH3bWwz23fT for ; Mon, 16 Jan 2023 08:20:15 +1100 (AEDT) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 1075285621; Sun, 15 Jan 2023 22:17:20 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=chromium.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (1024-bit key; unprotected) header.d=chromium.org header.i=@chromium.org header.b="CtNNJExc"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id 081D1855B3; Sun, 15 Jan 2023 22:16:48 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,SPF_HELO_NONE, SPF_PASS autolearn=ham autolearn_force=no version=3.4.2 Received: from mail-io1-xd2e.google.com (mail-io1-xd2e.google.com [IPv6:2607:f8b0:4864:20::d2e]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id C62F785592 for ; Sun, 15 Jan 2023 22:16:39 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=chromium.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=sjg@chromium.org Received: by mail-io1-xd2e.google.com with SMTP id p189so890558iod.0 for ; Sun, 15 Jan 2023 13:16:39 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=kfmjwUxYyGurlRnFX3OnCJ7ERr+MTkr13eiK/2mvTWw=; b=CtNNJExcx05b2DrbAYOazhDribed4GwpULaRT8K/DZI3pSKRl5EcbG1mRnqAyLxeCj 7t7kMxLbZ8ep45Y7yMRRpZiuEOzwj0JF0oFWpC1buvDD71i6ByAzoWuJoYITJCb1q5RX OPIbHIR/I+p+yI5UZHSpMs+jBe1V/ODNPKJ8U= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=kfmjwUxYyGurlRnFX3OnCJ7ERr+MTkr13eiK/2mvTWw=; b=OmeHmienvi6i3FKpJH4clQFcRzfgKzLzF/fVIJ1ZbZ3/OV5S/NAGfpqDPVZCQD96jz QjL+FC/pxxRrnUz94fp30TqK4VVxHecutPq4uw9KLk6hG4YrrnH8AIMnL2vBx6XT+p1f 8dCW9aqVAQyN+HwNolSQ4ThOrz8sVktIJiwfUXDMV1HUtqv/UIZd5gcj+TLdF6bY7t5p Zy4rNPkb3B/MiexK0AOKzlzhakZUe9TkhwIBHWsd6N5EZ0mQWe7rkIyMNkzm8TkiJ5d7 faNkg4vGhcQYhVEgjF/MIb8z4OQoKrBgDllYUG96yU0RtKcYB3orknhukGPgpddX+BKx jVSg== X-Gm-Message-State: AFqh2kpjRI1esI2rI5Kdu1cq79gRNkTmY5HQAIOtclymJKtowT3JLXEZ tBE3BEFL9pAxfSB67846NRZpIw5Q/iqFKvHCIIM= X-Google-Smtp-Source: AMrXdXuqJX69X3ErSXIpwAsFe4SqX43VqXqyPaYUbP2O8O4VGMVpvlm0VOq33XMzzc6z/dGxYmuaTw== X-Received: by 2002:a5d:9ac5:0:b0:704:9bc7:d0b9 with SMTP id x5-20020a5d9ac5000000b007049bc7d0b9mr5082864ion.4.1673817398332; Sun, 15 Jan 2023 13:16:38 -0800 (PST) Received: from sjg1.roam.corp.google.com (c-73-14-173-85.hsd1.co.comcast.net. [73.14.173.85]) by smtp.gmail.com with ESMTPSA id j6-20020a6bf906000000b007046e9e138esm4329107iog.22.2023.01.15.13.16.37 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 15 Jan 2023 13:16:38 -0800 (PST) From: Simon Glass To: U-Boot Mailing List Cc: Tom Rini , Heinrich Schuchardt , Simon Glass Subject: [PATCH 20/24] trace: Support output of a flamegraph Date: Sun, 15 Jan 2023 14:15:57 -0700 Message-Id: <20230115211602.1127661-21-sjg@chromium.org> X-Mailer: git-send-email 2.39.0.314.g84b9a713c41-goog In-Reply-To: <20230115211602.1127661-1-sjg@chromium.org> References: <20230115211602.1127661-1-sjg@chromium.org> MIME-Version: 1.0 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.39 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.103.6 at phobos.denx.de X-Virus-Status: Clean It is useful to see how many times each function is called, particularly in the context of its callers. A flamegraph is a way of showing this. Support output in this format which can be used by the flamegraph.pl script, to generate an SVG image for browsing. Signed-off-by: Simon Glass --- tools/proftool.c | 272 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 271 insertions(+), 1 deletion(-) diff --git a/tools/proftool.c b/tools/proftool.c index 588ae48a0c8..844ff3d0d06 100644 --- a/tools/proftool.c +++ b/tools/proftool.c @@ -6,7 +6,7 @@ /* * Decode and dump U-Boot trace information into formats that can be used - * by trace-cmd or kernelshark + * by trace-cmd, kernelshark or flamegraph.pl * * See doc/develop/trace.rst for more information */ @@ -27,6 +27,8 @@ #include #include +#include + /* Set to 1 to emit version 7 file (currently this doesn't work) */ #define VERSION7 0 @@ -37,6 +39,18 @@ #define __ALIGN_MASK(x, mask) (((x) + (mask)) & ~(mask)) #define ALIGN(x, a) __ALIGN_MASK((x), (typeof(x))(a) - 1) +/** + * container_of - cast a member of a structure out to the containing structure + * @ptr: the pointer to the member. + * @type: the type of the container struct this is embedded in. + * @member: the name of the member within the struct. + * + * (this is needed by list.h) + */ +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) + enum { FUNCF_TRACE = 1 << 0, /* Include this function in trace */ TRACE_PAGE_SIZE = 4096, /* Assumed page size for trace */ @@ -101,6 +115,38 @@ enum trace_type { TRACE_GRAPH_ENT, }; +/** + * struct flame_node - a node in the call-stack tree + * + * Each stack frame detected in the trace is given a node corresponding to a + * function call in the call stack. Functions can appear multiple times when + * they are called by a different set of parent functions. + * + * @parent: Parent node (the call stack for the function that called this one) + * @child_head: List of children of this node (functions called from here) + * @sibling: Next node in the list of children + * @func: Function this node refers to (NULL for root node) + * @count: Number of times this call-stack occurred + */ +struct flame_node { + struct flame_node *parent; + struct list_head child_head; + struct list_head sibling_node; + struct func_info *func; + int count; +}; + +/** + * struct flame_state - state information for building the flame graph + * + * @node: Current node being processed (corresponds to a function call) + * @nodes: Number of nodes created (running count) + */ +struct flame_state { + struct flame_node *node; + int nodes; +}; + /** * struct func_info - information recorded for each function * @@ -221,6 +267,7 @@ static void usage(void) "\n" "Commands\n" " dump-ftrace\t\tDump out records in ftrace format for use by trace-cmd\n" + " dump-flamegraph\tWrite a file for use with flamegraph.pl\n" "\n" "Options:\n" " -c \tSpecify config file\n" @@ -1517,6 +1564,218 @@ static int make_ftrace(FILE *fout, enum out_format_t out_format) return 0; } +/** + * create_node() - Create a new node in the flamegraph tree + * + * @msg: Message to use for debugging if something goes wrong + * Returns: Pointer to newly created node, or NULL on error + */ +static struct flame_node *create_node(const char *msg) +{ + struct flame_node *node; + + node = calloc(1, sizeof(*node)); + if (!node) { + fprintf(stderr, "Out of memory for %s\n", msg); + return NULL; + } + INIT_LIST_HEAD(&node->child_head); + + return node; +} + +/** + * process_call(): Add a call to the flamegraph info + * + * For function calls, if this call stack has been seen before, this increments + * the call count, creating a new node if needed. + * + * For function returns, it adds up the time spent in this call stack, + * subtracting the time spent by child functions. + * + * @state: Current flamegraph state + * @entry: true if this is a function entry, false if a function exit + * @timestamp: Timestamp from the trace file (in microseconds) + * @func: Function that was called/returned from + * + * Returns: 0 on success, -ve on error + */ +static int process_call(struct flame_state *state, bool entry, ulong timestamp, + struct func_info *func) +{ + struct flame_node *node = state->node; + + if (entry) { + struct flame_node *child, *chd; + + /* see if we have this as a child node already */ + child = NULL; + list_for_each_entry(chd, &node->child_head, sibling_node) { + if (chd->func == func) { + child = chd; + break; + } + } + if (!child) { + /* create a new node */ + child = create_node("child"); + if (!child) + return -1; + list_add_tail(&child->sibling_node, &node->child_head); + child->func = func; + child->parent = node; + state->nodes++; + } + debug("entry %s: move from %s to %s\n", func->name, + node->func ? node->func->name : "(root)", + child->func->name); + child->count++; + node = child; + } else if (node->parent) { + debug("exit %s: move from %s to %s\n", func->name, + node->func->name, node->parent->func ? + node->parent->func->name : "(root)"); + node = node->parent; + } + + state->node = node; + + return 0; +} + +/** + * make_flame_tree() - Create a tree of stack traces + * + * Set up a tree, with the root node having the top-level functions as children + * and the leaf nodes being leaf functions. Each node has a count of how many + * times this function appears in the trace + * + * @treep: Returns the resulting flamegraph tree + * Returns: 0 on success, -ve on error + */ +static int make_flame_tree(struct flame_node **treep) +{ + struct flame_state state; + struct flame_node *tree; + struct trace_call *call; + int missing_count = 0; + int i, depth; + + /* + * The first thing in the trace may not be the top-level function, so + * set the initial depth so that no function goes below depth 0 + */ + depth = -calc_min_depth(); + + tree = create_node("tree"); + if (!tree) + return -1; + state.node = tree; + state.nodes = 0; + + for (i = 0, call = call_list; i < call_count; i++, call++) { + bool entry = TRACE_CALL_TYPE(call) == FUNCF_ENTRY; + ulong timestamp = call->flags & FUNCF_TIMESTAMP_MASK; + struct func_info *func; + + if (entry) + depth++; + else + depth--; + + func = find_func_by_offset(call->func); + if (!func) { + warn("Cannot find function at %lx\n", + text_offset + call->func); + missing_count++; + continue; + } + + if (process_call(&state, entry, timestamp, func)) + return -1; + } + fprintf(stderr, "%d nodes\n", state.nodes); + *treep = tree; + + return 0; +} + +/** + * output_tree() - Output a flamegraph tree + * + * Writes the tree out to a file in a format suitable for flamegraph.pl + * + * This works by maintaining a string shared across all recursive calls. The + * function name for this node is added to the existing string, to make up the + * full call-stack description. For example, on entry, @str might contain: + * + * "initf_bootstage;bootstage_mark_name" + * ^ @base + * + * with @base pointing to the \0 at the end of the string. This function adds + * a ';' following by the name of the current function, e.g. "timer_get_boot_us" + * as well as the output value, to get the full line: + * + * initf_bootstage;bootstage_mark_name;timer_get_boot_us 123 + * + * @fout: Output file + * @node: Node to output (pass the whole tree at first) + * @str: String to use to build the output line (e.g. 500 charas long) + * @maxlen: Maximum length of string + * @base: Current base position in the string + * @treep: Returns the resulting flamegraph tree + * Returns 0 if OK, -1 on error + */ +static int output_tree(FILE *fout, const struct flame_node *node, + char *str, int maxlen, int base) +{ + const struct flame_node *child; + int pos; + + if (node->count) + fprintf(fout, "%s %d\n", str, node->count); + + pos = base; + if (pos) + str[pos++] = ';'; + list_for_each_entry(child, &node->child_head, sibling_node) { + int len; + + len = strlen(child->func->name); + if (pos + len + 1 >= maxlen) { + fprintf(stderr, "String too short (%d chars)\n", + maxlen); + return -1; + } + strcpy(str + pos, child->func->name); + if (output_tree(fout, child, str, maxlen, pos + len)) + return -1; + } + + return 0; +} + +/** + * make_flamegraph() - Write out a flame graph + * + * @fout: Output file + * Returns 0 if OK, -1 on error + */ +static int make_flamegraph(FILE *fout) +{ + struct flame_node *tree; + char str[500]; + + if (make_flame_tree(&tree)) + return -1; + + *str = '\0'; + if (output_tree(fout, tree, str, sizeof(str), 0)) + return -1; + + return 0; +} + /** * prof_tool() - Performs requested action * @@ -1560,6 +1819,17 @@ static int prof_tool(int argc, char *const argv[], } err = make_ftrace(fout, out_format); fclose(fout); + } else if (!strcmp(cmd, "dump-flamegraph")) { + FILE *fout; + + fout = fopen(out_fname, "w"); + if (!fout) { + fprintf(stderr, "Cannot write file '%s'\n", + out_fname); + return -1; + } + err = make_flamegraph(fout); + fclose(fout); } else { warn("Unknown command '%s'\n", cmd); } From patchwork Sun Jan 15 21:15:58 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 1726844 X-Patchwork-Delegate: trini@ti.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=2a01:238:438b:c500:173d:9f52:ddab:ee01; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: legolas.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=chromium.org header.i=@chromium.org header.a=rsa-sha256 header.s=google header.b=IZEAa7Tb; dkim-atps=neutral Received: from phobos.denx.de (phobos.denx.de [IPv6:2a01:238:438b:c500:173d:9f52:ddab:ee01]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4Nw7S44TT5z23fT for ; Mon, 16 Jan 2023 08:23:32 +1100 (AEDT) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 2BD9983620; Sun, 15 Jan 2023 22:23:30 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=chromium.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (1024-bit key; unprotected) header.d=chromium.org header.i=@chromium.org header.b="IZEAa7Tb"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id DB9BA85347; Sun, 15 Jan 2023 22:23:27 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,SPF_HELO_NONE, SPF_PASS autolearn=ham autolearn_force=no version=3.4.2 Received: from mail-io1-xd30.google.com (mail-io1-xd30.google.com [IPv6:2607:f8b0:4864:20::d30]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id BFAE18554F for ; Sun, 15 Jan 2023 22:16:40 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=chromium.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=sjg@chromium.org Received: by mail-io1-xd30.google.com with SMTP id p189so890569iod.0 for ; Sun, 15 Jan 2023 13:16:40 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=MDYnjKe7EmpVmCrjZWUVowPDy3saEvC5n/PB5n36g+A=; b=IZEAa7Tbz/S43VifdLYIUPjQHnlsb7f6wpDb7JzUEO8+U6lLOmyFPdO3Ad3DE//TiD X4eh/OZb6JYPV438bOrS35yNdTXqR5p/iSkCZkfL2P5G9KZMnHLPsDTPVbNRKu2t0Io/ rOajMimyBFi6IWIE8Dl9Z99ybiP3BVGPbwnJU= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=MDYnjKe7EmpVmCrjZWUVowPDy3saEvC5n/PB5n36g+A=; b=GyF2/kz+otl4rJs4w+gL3hB1KoZVUQ9Ei3bM7pG5Oih9jcBdeYbfL6+knvkrYAOtbD XXe1a5d339an4ORVG3ygcjkaEq4V9uKyHwQR9fRQTPIbTeg6KV03BHlwRSmxBjCCh8Y7 lL2Gc+LbMmBeQ35VVGNuzp2u+SHOMUFhbsYMa/t9KR/XL79SJibvdh9neOc1HsXjDmAO qoQ3t9ld3NDNnH/a4gTd8nfDn32qcKHGs83LGbLTR+g7zJ8tvEWl6c+PBK+DmK/0HpmH QmHE3UsHMZGLhdv4DOuXMN93KHd6Gu2iRjniLGEnVhrkWStlE/UuGvLIaQq+fmFO2OAu Shzw== X-Gm-Message-State: AFqh2krr6iDUHJ8XRNrBu5uUnAtJ+mAIQFcejmU8xNJYfCjV+KkfI3Nj Uyw9FgUoc4HQmj0mB8PqgBgbpDrv1eTE4hvlQl0= X-Google-Smtp-Source: AMrXdXu0GAMggRZ8+a3ch2vVoNp0OqRL48VQOuJJgwmobf24Odefqi4S7FIM/aXW/4VVETt2U+ZVGg== X-Received: by 2002:a5d:8b11:0:b0:6df:5a37:ed5 with SMTP id k17-20020a5d8b11000000b006df5a370ed5mr56967127ion.17.1673817399063; Sun, 15 Jan 2023 13:16:39 -0800 (PST) Received: from sjg1.roam.corp.google.com (c-73-14-173-85.hsd1.co.comcast.net. [73.14.173.85]) by smtp.gmail.com with ESMTPSA id j6-20020a6bf906000000b007046e9e138esm4329107iog.22.2023.01.15.13.16.38 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 15 Jan 2023 13:16:38 -0800 (PST) From: Simon Glass To: U-Boot Mailing List Cc: Tom Rini , Heinrich Schuchardt , Simon Glass Subject: [PATCH 21/24] trace: Provide a flamegraph that uses timing Date: Sun, 15 Jan 2023 14:15:58 -0700 Message-Id: <20230115211602.1127661-22-sjg@chromium.org> X-Mailer: git-send-email 2.39.0.314.g84b9a713c41-goog In-Reply-To: <20230115211602.1127661-1-sjg@chromium.org> References: <20230115211602.1127661-1-sjg@chromium.org> MIME-Version: 1.0 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.39 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.103.6 at phobos.denx.de X-Virus-Status: Clean Add a second variant of the flame graph that shows records in terms of the number of microseconds used by each call stack. This is a useful way of seeing where time is going within the execution of U-Boot. This requires a call stack that records the start time of each function, as well as a way of subtracting all time consumed by child functions, so that this time is not counted twice by the flamegraph. The time values in the output are just for the function itself, not for its children. Signed-off-by: Simon Glass --- tools/proftool.c | 108 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 97 insertions(+), 11 deletions(-) diff --git a/tools/proftool.c b/tools/proftool.c index 844ff3d0d06..089360428c2 100644 --- a/tools/proftool.c +++ b/tools/proftool.c @@ -67,11 +67,16 @@ enum { * @OUT_FMT_DEFAULT: Use the default for the output file * @OUT_FMT_FUNCTION: Write ftrace 'function' records * @OUT_FMT_FUNCGRAPH: Write ftrace funcgraph_entry and funcgraph_exit records + * @OUT_FMT_FLAMEGRAPH_CALLS: Write a file suitable for flamegraph.pl + * @OUT_FMT_FLAMEGRAPH_TIMING: Write a file suitable for flamegraph.pl with the + * counts set to the number of microseconds used by each function */ enum out_format_t { OUT_FMT_DEFAULT, OUT_FMT_FUNCTION, OUT_FMT_FUNCGRAPH, + OUT_FMT_FLAMEGRAPH_CALLS, + OUT_FMT_FLAMEGRAPH_TIMING, }; /* Section types for v7 format (trace-cmd format) */ @@ -127,6 +132,8 @@ enum trace_type { * @sibling: Next node in the list of children * @func: Function this node refers to (NULL for root node) * @count: Number of times this call-stack occurred + * @duration: Number of microseconds taken to run this function, excluding all + * of the functions it calls */ struct flame_node { struct flame_node *parent; @@ -134,16 +141,27 @@ struct flame_node { struct list_head sibling_node; struct func_info *func; int count; + ulong duration; }; /** * struct flame_state - state information for building the flame graph * * @node: Current node being processed (corresponds to a function call) + * @stack: Stack of call-start time for this function as well as the + * accumulated total time of all child calls (so we can subtract them from the + * function's call time. This is an 'empty' stack, meaning that @stack_ptr + * points to the next available stack position + * @stack_ptr: points to first empty position in the stack * @nodes: Number of nodes created (running count) */ struct flame_state { struct flame_node *node; + struct stack_info { + ulong timestamp; + ulong child_total; + } stack[MAX_STACK_DEPTH]; + int stack_ptr; int nodes; }; @@ -279,7 +297,11 @@ static void usage(void) "\n" "Subtypes for dump-ftrace:\n" " function - write function-call records (caller/callee)\n" - " funcgraph - write function entry/exit records (graph)\n"); + " funcgraph - write function entry/exit records (graph)\n" + "\n" + "Subtypes for dump-flamegraph\n" + " calls - create a flamegraph of stack frames\n" + " timing - create a flamegraph of microseconds for each stack frame\n"); exit(EXIT_FAILURE); } @@ -1604,6 +1626,7 @@ static int process_call(struct flame_state *state, bool entry, ulong timestamp, struct func_info *func) { struct flame_node *node = state->node; + int stack_ptr = state->stack_ptr; if (entry) { struct flame_node *child, *chd; @@ -1630,14 +1653,44 @@ static int process_call(struct flame_state *state, bool entry, ulong timestamp, node->func ? node->func->name : "(root)", child->func->name); child->count++; + if (stack_ptr < MAX_STACK_DEPTH) { + state->stack[stack_ptr].timestamp = timestamp; + state->stack[stack_ptr].child_total = 0; + } + debug("%d: %20s: entry at %ld\n", stack_ptr, func->name, + timestamp); + stack_ptr++; node = child; } else if (node->parent) { + ulong total_duration = 0, child_duration = 0; + struct stack_info *stk; + debug("exit %s: move from %s to %s\n", func->name, node->func->name, node->parent->func ? node->parent->func->name : "(root)"); + if (stack_ptr && stack_ptr <= MAX_STACK_DEPTH) { + stk = &state->stack[--stack_ptr]; + + /* + * get total duration of the function which just + * exited + */ + total_duration = timestamp - stk->timestamp; + child_duration = stk->child_total; + + if (stack_ptr) + state->stack[stack_ptr - 1].child_total += total_duration; + + debug("%d: %20s: exit at %ld, total %ld, child %ld, child_total=%ld\n", + stack_ptr, func->name, timestamp, + total_duration, child_duration, + stk->child_total); + } + node->duration += total_duration - child_duration; node = node->parent; } + state->stack_ptr = stack_ptr; state->node = node; return 0; @@ -1650,10 +1703,12 @@ static int process_call(struct flame_state *state, bool entry, ulong timestamp, * and the leaf nodes being leaf functions. Each node has a count of how many * times this function appears in the trace * + * @out_format: Output format to use * @treep: Returns the resulting flamegraph tree * Returns: 0 on success, -ve on error */ -static int make_flame_tree(struct flame_node **treep) +static int make_flame_tree(enum out_format_t out_format, + struct flame_node **treep) { struct flame_state state; struct flame_node *tree; @@ -1661,6 +1716,9 @@ static int make_flame_tree(struct flame_node **treep) int missing_count = 0; int i, depth; + /* maintain a stack of start times, etc. for 'calling' functions */ + state.stack_ptr = 0; + /* * The first thing in the trace may not be the top-level function, so * set the initial depth so that no function goes below depth 0 @@ -1719,6 +1777,7 @@ static int make_flame_tree(struct flame_node **treep) * initf_bootstage;bootstage_mark_name;timer_get_boot_us 123 * * @fout: Output file + * @out_format: Output format to use * @node: Node to output (pass the whole tree at first) * @str: String to use to build the output line (e.g. 500 charas long) * @maxlen: Maximum length of string @@ -1726,14 +1785,32 @@ static int make_flame_tree(struct flame_node **treep) * @treep: Returns the resulting flamegraph tree * Returns 0 if OK, -1 on error */ -static int output_tree(FILE *fout, const struct flame_node *node, - char *str, int maxlen, int base) +static int output_tree(FILE *fout, enum out_format_t out_format, + const struct flame_node *node, char *str, int maxlen, + int base) { const struct flame_node *child; int pos; - if (node->count) - fprintf(fout, "%s %d\n", str, node->count); + if (node->count) { + if (out_format == OUT_FMT_FLAMEGRAPH_CALLS) { + fprintf(fout, "%s %d\n", str, node->count); + } else { + /* + * Write out the number of microseconds used by this + * call stack. Since the time taken by child calls is + * subtracted from this total, it can reach 0, meaning + * that this function took no time beyond what its + * children used. For this case, write 1 rather than 0, + * so that this call stack appears in the flamegraph. + * This has the effect of inflating the timing slightly, + * but only by at most 1 microsecond per function, + * assuming that is the timestamp resolution + */ + fprintf(fout, "%s %ld\n", str, + node->duration ? node->duration : 1); + } + } pos = base; if (pos) @@ -1748,7 +1825,8 @@ static int output_tree(FILE *fout, const struct flame_node *node, return -1; } strcpy(str + pos, child->func->name); - if (output_tree(fout, child, str, maxlen, pos + len)) + if (output_tree(fout, out_format, child, str, maxlen, + pos + len)) return -1; } @@ -1759,18 +1837,19 @@ static int output_tree(FILE *fout, const struct flame_node *node, * make_flamegraph() - Write out a flame graph * * @fout: Output file + * @out_format: Output format to use, e.g. function counts or timing * Returns 0 if OK, -1 on error */ -static int make_flamegraph(FILE *fout) +static int make_flamegraph(FILE *fout, enum out_format_t out_format) { struct flame_node *tree; char str[500]; - if (make_flame_tree(&tree)) + if (make_flame_tree(out_format, &tree)) return -1; *str = '\0'; - if (output_tree(fout, tree, str, sizeof(str), 0)) + if (output_tree(fout, out_format, tree, str, sizeof(str), 0)) return -1; return 0; @@ -1822,13 +1901,16 @@ static int prof_tool(int argc, char *const argv[], } else if (!strcmp(cmd, "dump-flamegraph")) { FILE *fout; + if (out_format != OUT_FMT_FLAMEGRAPH_CALLS && + out_format != OUT_FMT_FLAMEGRAPH_TIMING) + out_format = OUT_FMT_FLAMEGRAPH_CALLS; fout = fopen(out_fname, "w"); if (!fout) { fprintf(stderr, "Cannot write file '%s'\n", out_fname); return -1; } - err = make_flamegraph(fout); + err = make_flamegraph(fout, out_format); fclose(fout); } else { warn("Unknown command '%s'\n", cmd); @@ -1858,6 +1940,10 @@ int main(int argc, char *argv[]) out_format = OUT_FMT_FUNCTION; } else if (!strcmp("funcgraph", optarg)) { out_format = OUT_FMT_FUNCGRAPH; + } else if (!strcmp("calls", optarg)) { + out_format = OUT_FMT_FLAMEGRAPH_CALLS; + } else if (!strcmp("timing", optarg)) { + out_format = OUT_FMT_FLAMEGRAPH_TIMING; } else { fprintf(stderr, "Invalid format: use function, funcgraph, calls, timing\n"); From patchwork Sun Jan 15 21:15:59 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 1726841 X-Patchwork-Delegate: trini@ti.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=2a01:238:438b:c500:173d:9f52:ddab:ee01; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: legolas.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=chromium.org header.i=@chromium.org header.a=rsa-sha256 header.s=google header.b=cca7zj0w; dkim-atps=neutral Received: from phobos.denx.de (phobos.denx.de [IPv6:2a01:238:438b:c500:173d:9f52:ddab:ee01]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4Nw7NW0D5Nz23fT for ; Mon, 16 Jan 2023 08:20:27 +1100 (AEDT) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 9C88685626; Sun, 15 Jan 2023 22:17:21 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=chromium.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (1024-bit key; unprotected) header.d=chromium.org header.i=@chromium.org header.b="cca7zj0w"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id DAF64855D3; Sun, 15 Jan 2023 22:16:50 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,SPF_HELO_NONE, SPF_PASS autolearn=ham autolearn_force=no version=3.4.2 Received: from mail-io1-xd33.google.com (mail-io1-xd33.google.com [IPv6:2607:f8b0:4864:20::d33]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id 6B1DD8555D for ; Sun, 15 Jan 2023 22:16:40 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=chromium.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=sjg@chromium.org Received: by mail-io1-xd33.google.com with SMTP id v65so8555606ioe.4 for ; Sun, 15 Jan 2023 13:16:40 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=RE4Rh+ljdIcfS94TeO/UznpKpwVWo3yFbRWADp7arL8=; b=cca7zj0wAiRo2uZFVHIdLgHYKzElkhZOq8C+PRbC2bjiHyvs0+9vko4F+nTSZe0IyV 9gM1JCGKQRaRSwXmOBNZGyefIw/2orsXP6N++FwiTnMiaA6CCQqreZsiY0G5BNypHFxm VBnIiFHEIf7Xqu4kqyccOVUXxDQzl/e7MhV8Q= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=RE4Rh+ljdIcfS94TeO/UznpKpwVWo3yFbRWADp7arL8=; b=NCzBLIxKAQFO9ZBYAZ00gZDKqMyNU7NK9VGz6dKNYU4O41VWnaJUiC8+X3O5isGcg0 JrOAoMJatBCJRsjjUjpg86PmeEneZ3y1+ae70AtCCFYjlrNuphQIghTDWR9RIPUabGPB VzOgS1VU0XLDspBbgMTGpPUCtlkLF7kQ/ByWYo9latkOcU9TK7++wZsH8dgmnDSIilm1 A7dCSlH3FAxkdzucPTkbqyZI2WoQRsf7zCWQB17OzVGd4+fBQWOUt9iKwfIjQTJFfZmJ FsftVU6YdWMKw0ueBoDj+0Uklom4xPZKq5nnns36+DfT1DFk+G+N6r7rQIdakIXp4Ca/ ezWQ== X-Gm-Message-State: AFqh2krYNDdrWOVrQdVMbl/vbFlv6rKv2BuFzg8YHePzJsa1eMNYKa6v zeW8mrm4JWCd7aEdl/unLHjKPH1cLzCo6M05VCY= X-Google-Smtp-Source: AMrXdXtQ1xh49AqQGKRMt0wqnA11g26QvnklTxRsrNjLiHu6+RLQrtVErJeMiI4Q9OL9907xQNkpeg== X-Received: by 2002:a05:6602:4191:b0:704:884e:fda2 with SMTP id bx17-20020a056602419100b00704884efda2mr6695756iob.12.1673817399900; Sun, 15 Jan 2023 13:16:39 -0800 (PST) Received: from sjg1.roam.corp.google.com (c-73-14-173-85.hsd1.co.comcast.net. [73.14.173.85]) by smtp.gmail.com with ESMTPSA id j6-20020a6bf906000000b007046e9e138esm4329107iog.22.2023.01.15.13.16.39 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 15 Jan 2023 13:16:39 -0800 (PST) From: Simon Glass To: U-Boot Mailing List Cc: Tom Rini , Heinrich Schuchardt , Simon Glass , AKASHI Takahiro , Huang Jianan , Rick Chen Subject: [PATCH 22/24] Docker: Support trace-cmd Date: Sun, 15 Jan 2023 14:15:59 -0700 Message-Id: <20230115211602.1127661-23-sjg@chromium.org> X-Mailer: git-send-email 2.39.0.314.g84b9a713c41-goog In-Reply-To: <20230115211602.1127661-1-sjg@chromium.org> References: <20230115211602.1127661-1-sjg@chromium.org> MIME-Version: 1.0 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.39 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.103.6 at phobos.denx.de X-Virus-Status: Clean Build trace-cmd as part of the docker image, so that trace tests can be used. Unfortunately the version provided by distributions is a little old and has bugs. It also does not support specifying the time base for the trace, which is required to convert microseconds to nanaseconds. Signed-off-by: Simon Glass --- tools/docker/Dockerfile | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tools/docker/Dockerfile b/tools/docker/Dockerfile index 202a8145af7..6e0cdd48dd5 100644 --- a/tools/docker/Dockerfile +++ b/tools/docker/Dockerfile @@ -213,6 +213,22 @@ RUN git clone https://github.com/stefanberger/swtpm /tmp/swtpm && \ make install && \ rm -rf /tmp/swtpm +# Build trace-cmd +RUN mkdir /tmp/trace && \ + git clone https://git.kernel.org/pub/scm/libs/libtrace/libtraceevent.git /tmp/trace/libtraceevent && \ + cd /tmp/trace/libtraceevent && \ + make -j$(nproc) && \ + sudo make install && \ + git clone https://git.kernel.org/pub/scm/libs/libtrace/libtracefs.git /tmp/trace/libtracefs && \ + cd /tmp/trace/libtracefs && \ + make -j$(nproc) && \ + sudo make install && \ + git clone https://github.com/rostedt/trace-cmd.git /tmp/trace/trace-cmd && \ + cd /tmp/trace/trace-cmd && \ + make -j$(nproc) && \ + sudo make install && \ + rm -rf /tmp/trace + # Create our user/group RUN echo uboot ALL=NOPASSWD: ALL > /etc/sudoers.d/uboot RUN useradd -m -U uboot From patchwork Sun Jan 15 21:16:00 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 1726842 X-Patchwork-Delegate: trini@ti.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=2a01:238:438b:c500:173d:9f52:ddab:ee01; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: legolas.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=chromium.org header.i=@chromium.org header.a=rsa-sha256 header.s=google header.b=g06xKxKG; dkim-atps=neutral Received: from phobos.denx.de (phobos.denx.de [IPv6:2a01:238:438b:c500:173d:9f52:ddab:ee01]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4Nw7Pr4x05z23fT for ; Mon, 16 Jan 2023 08:21:36 +1100 (AEDT) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 2A66485685; Sun, 15 Jan 2023 22:17:23 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=chromium.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (1024-bit key; unprotected) header.d=chromium.org header.i=@chromium.org header.b="g06xKxKG"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id D8BCC855D6; Sun, 15 Jan 2023 22:16:51 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,SPF_HELO_NONE, SPF_PASS autolearn=ham autolearn_force=no version=3.4.2 Received: from mail-io1-xd33.google.com (mail-io1-xd33.google.com [IPv6:2607:f8b0:4864:20::d33]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id 727058556A for ; Sun, 15 Jan 2023 22:16:41 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=chromium.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=sjg@chromium.org Received: by mail-io1-xd33.google.com with SMTP id v65so8555623ioe.4 for ; Sun, 15 Jan 2023 13:16:41 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=cA67DWCybIRS+mdPV2E1SVq+MsRFf1WdwLA0hNREvkw=; b=g06xKxKGXSoeCH554kJRERXYuM3MnUy9uwIxEFdRQVSTo5GExDcHVFOdMzda78jtU4 Hre/+GVGEN0QmfF5awIkOYB2i7VfS2WVvaKhB8xuMiu0Pz7n5R6Uld2aXjY0N9bbLUEl t3JK9Mb2T3GKBmT7q88oy5p3lu6ONUlb197vM= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=cA67DWCybIRS+mdPV2E1SVq+MsRFf1WdwLA0hNREvkw=; b=vx7w1XqqSPFBLGr6BsUiMBFGR955gRpUtxfRma7Ivzdd127TUmx2PIE3uM9A/jqwAX eUNO4Do5w1J8JPGSh9gdt/PgtDGJAcpG4gDvk8ZRyiSdFISKhmNRSudv6C16DDx3c3Gz F1ptG9M175Hl9jqmj2VdabDgLuRKKowERbPby0jzqoSjCu30hTq0m6UQDf6G8HXVLqhh 0X0Um02ZedNNxGI4kyxFEaPczo5oYcnkkfHQeR/RzPGOyxL9YIGkZEJCnM/q7DLTo9wX Q2WewNQX+JoIXGzEcNEWmP3P+XeaGGxmqrWEbLt15kNg44MFynahyORMLkTZHHFvoB/r LnaQ== X-Gm-Message-State: AFqh2krih115rhtdtpxT27MXEGdjLJnllG+ftSxOLlQQNTIjMuFDUWvx 5cQOSk3M87Jp529VIYQOR3XJ9Q4pTYqjRk3y+Ls= X-Google-Smtp-Source: AMrXdXuIBQh9LDcf0VlITsdbmztof1ytHgqhgTwZ/Nc+yloNy4AavFPqiAD7Gq/BT7J1b+3rPbzzfA== X-Received: by 2002:a05:6602:24ce:b0:6e0:7dd:5976 with SMTP id h14-20020a05660224ce00b006e007dd5976mr11739404ioe.12.1673817400748; Sun, 15 Jan 2023 13:16:40 -0800 (PST) Received: from sjg1.roam.corp.google.com (c-73-14-173-85.hsd1.co.comcast.net. [73.14.173.85]) by smtp.gmail.com with ESMTPSA id j6-20020a6bf906000000b007046e9e138esm4329107iog.22.2023.01.15.13.16.40 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 15 Jan 2023 13:16:40 -0800 (PST) From: Simon Glass To: U-Boot Mailing List Cc: Tom Rini , Heinrich Schuchardt , Simon Glass , AKASHI Takahiro , Joel Stanley , Rick Chen Subject: [PATCH 23/24] trace: Add a test Date: Sun, 15 Jan 2023 14:16:00 -0700 Message-Id: <20230115211602.1127661-24-sjg@chromium.org> X-Mailer: git-send-email 2.39.0.314.g84b9a713c41-goog In-Reply-To: <20230115211602.1127661-1-sjg@chromium.org> References: <20230115211602.1127661-1-sjg@chromium.org> MIME-Version: 1.0 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.39 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.103.6 at phobos.denx.de X-Virus-Status: Clean Add a test which runs sandbox, collects a trace and makes sure it can be processed by trace-cmd. This should ensure that this feature continues to work as U-Boot and trace-cmd evolve. Signed-off-by: Simon Glass --- .azure-pipelines.yml | 8 + .gitlab-ci.yml | 12 ++ test/py/tests/test_trace.py | 304 ++++++++++++++++++++++++++++++++++++ 3 files changed, 324 insertions(+) create mode 100644 test/py/tests/test_trace.py diff --git a/.azure-pipelines.yml b/.azure-pipelines.yml index 49fc34fbf23..8f5c8e05dc5 100644 --- a/.azure-pipelines.yml +++ b/.azure-pipelines.yml @@ -239,6 +239,11 @@ stages: TEST_PY_TEST_SPEC: "test_ofplatdata or test_handoff or test_spl" sandbox_flattree: TEST_PY_BD: "sandbox_flattree" + sandbox_trace: + TEST_PY_BD: "sandbox" + BUILD_ENV: "FTRACE=1 NO_LTO=1" + TEST_PY_TEST_SPEC: "trace" + OVERRIDE: "-a CONFIG_TRACE=y -a CONFIG_TRACE_EARLY=y -a CONFIG_TRACE_EARLY_SIZE=0x01000000" coreboot: TEST_PY_BD: "coreboot" TEST_PY_ID: "--id qemu" @@ -361,6 +366,9 @@ stages: # the below corresponds to .gitlab-ci.yml "script" cd ${WORK_DIR} export UBOOT_TRAVIS_BUILD_DIR=/tmp/${TEST_PY_BD}; + if [ -n "${BUILD_ENV}" ]; then + export ${BUILD_ENV}; + fi tools/buildman/buildman -o ${UBOOT_TRAVIS_BUILD_DIR} -w -E -W -e --board ${TEST_PY_BD} ${OVERRIDE} cp ~/grub_x86.efi ${UBOOT_TRAVIS_BUILD_DIR}/ cp ~/grub_x64.efi ${UBOOT_TRAVIS_BUILD_DIR}/ diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 398fa2b45e2..87288a666df 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -35,6 +35,9 @@ stages: # If we've been asked to use clang only do one configuration. - export UBOOT_TRAVIS_BUILD_DIR=/tmp/${TEST_PY_BD} - echo BUILD_ENV ${BUILD_ENV} + - if [ -n "${BUILD_ENV}" ]; then + export ${BUILD_ENV}; + fi - tools/buildman/buildman -o ${UBOOT_TRAVIS_BUILD_DIR} -w -E -W -e --board ${TEST_PY_BD} ${OVERRIDE} - cp ~/grub_x86.efi $UBOOT_TRAVIS_BUILD_DIR/ @@ -267,6 +270,15 @@ sandbox_vpl test.py: TEST_PY_TEST_SPEC: "test_vpl_help or test_spl" <<: *buildman_and_testpy_dfn +# Enable tracing and disable LTO, to ensure functions are not elided +sandbox trace_test.py: + variables: + TEST_PY_BD: "sandbox" + BUILD_ENV: "FTRACE=1 NO_LTO=1" + TEST_PY_TEST_SPEC: "trace" + OVERRIDE: "-a CONFIG_TRACE=y -a CONFIG_TRACE_EARLY=y -a CONFIG_TRACE_EARLY_SIZE=0x01000000" + <<: *buildman_and_testpy_dfn + evb-ast2500 test.py: variables: TEST_PY_BD: "evb-ast2500" diff --git a/test/py/tests/test_trace.py b/test/py/tests/test_trace.py new file mode 100644 index 00000000000..14584d11a23 --- /dev/null +++ b/test/py/tests/test_trace.py @@ -0,0 +1,304 @@ +# SPDX-License-Identifier: GPL-2.0 +# Copyright 2022 Google LLC +# Written by Simon Glass + +import os +import pytest +import re + +import u_boot_utils as util + +# This is needed for Azure, since the default '..' directory is not writeable +TMPDIR = '/tmp/test_trace' + +# Decode a function-graph line +RE_LINE = re.compile(r'.*\[000\]\s*([0-9.]*): func.*[|](\s*)(\S.*)?([{};])$') + + +def collect_trace(cons): + """Build U-Boot and run it to collect a trace + + Args: + cons (ConsoleBase): U-Boot console + + Returns: + tuple: + str: Filename of the output trace file + int: Microseconds taken for initf_dm according to bootstage + """ + cons.run_command('trace pause') + out = cons.run_command('trace stats') + + # The output is something like this: + # 251,003 function sites + # 1,160,283 function calls + # 0 untracked function calls + # 1,230,758 traced function calls (341538 dropped due to overflow) + # 33 maximum observed call depth + # 15 call depth limit + # 748,268 calls not traced due to depth + # 1,230,758 max function calls + + # Get a dict of values from the output + lines = [line.split(maxsplit=1) for line in out.splitlines() if line] + vals = {key: val.replace(',', '') for val, key in lines} + + assert int(vals['function sites']) > 100000 + assert int(vals['function calls']) > 200000 + assert int(vals['untracked function calls']) == 0 + assert int(vals['maximum observed call depth']) > 30 + assert (vals['call depth limit'] == + cons.config.buildconfig.get('config_trace_call_depth_limit')) + assert int(vals['calls not traced due to depth']) > 100000 + + out = cons.run_command('bootstage report') + # Accumulated time: + # 19,104 dm_r + # 23,078 of_live + # 46,280 dm_f + dm_f_time = [line.split()[0] for line in out.replace(',', '').splitlines() + if 'dm_f' in line] + + # Read out the trace data + addr = 0x02000000 + size = 0x01000000 + out = cons.run_command(f'trace calls {addr:x} {size:x}') + print(out) + fname = os.path.join(TMPDIR, 'trace') + out = cons.run_command( + 'host save hostfs - %x %s ${profoffset}' % (addr, fname)) + return fname, int(dm_f_time[0]) + + +def check_function(cons, fname, proftool, map_fname, trace_dat): + """Check that the 'function' output works + + Args: + cons (ConsoleBase): U-Boot console + fname (str): Filename of trace file + proftool (str): Filename of proftool + map_fname (str): Filename of System.map + trace_dat (str): Filename of output file + """ + out = util.run_and_log( + cons, [proftool, '-t', fname, '-o', trace_dat, '-m', map_fname, + 'dump-ftrace']) + + # Check that trace-cmd can read it + out = util.run_and_log(cons, ['trace-cmd', 'dump', trace_dat]) + + # Tracing meta data in file /tmp/test_trace/trace.dat: + # [Initial format] + # 6 [Version] + # 0 [Little endian] + # 4 [Bytes in a long] + # 4096 [Page size, bytes] + # [Header page, 205 bytes] + # [Header event, 205 bytes] + # [Ftrace format, 3 events] + # [Events format, 0 systems] + # [Kallsyms, 342244 bytes] + # [Trace printk, 0 bytes] + # [Saved command lines, 9 bytes] + # 1 [CPUs with tracing data] + # [6 options] + # [Flyrecord tracing data] + # [Tracing clock] + # [local] global counter uptime perf mono mono_raw boot x86-tsc + assert '[Flyrecord tracing data]' in out + assert '4096 [Page size, bytes]' in out + kallsyms = [line.split() for line in out.splitlines() if 'Kallsyms' in line] + # [['[Kallsyms,', '342244', 'bytes]']] + val = int(kallsyms[0][1]) + assert val > 50000 # Should be at least 50KB of symbols + + # Check that the trace has something useful + cmd = f"trace-cmd report {trace_dat} |grep -E '(initf_|initr_)'" + out = util.run_and_log(cons, ['sh', '-c', cmd]) + + # Format: + # unknown option 14 + # u-boot-1 [000] 60.805596: function: initf_malloc + # u-boot-1 [000] 60.805597: function: initf_malloc + # u-boot-1 [000] 60.805601: function: initf_bootstage + # u-boot-1 [000] 60.805607: function: initf_bootstage + lines = [line.replace(':', '').split() for line in out.splitlines()] + vals = {items[4]: float(items[2]) for items in lines if len(items) == 5} + base = None + max_delta = 0 + for timestamp in vals.values(): + if base: + max_delta = max(max_delta, timestamp - base) + else: + base = timestamp + + # Check for some expected functions + assert 'initf_malloc' in vals.keys() + assert 'initr_watchdog' in vals.keys() + assert 'initr_dm' in vals.keys() + + # All the functions should be executed within five seconds at most + assert max_delta < 5 + + +def check_funcgraph(cons, fname, proftool, map_fname, trace_dat): + """Check that the 'funcgraph' output works + + Args: + cons (ConsoleBase): U-Boot console + fname (str): Filename of trace file + proftool (str): Filename of proftool + map_fname (str): Filename of System.map + trace_dat (str): Filename of output file + + Returns: + int: Time taken by the first part of the initf_dm() function, in us + """ + + # Generate the funcgraph format + out = util.run_and_log( + cons, [proftool, '-t', fname, '-o', trace_dat, '-m', map_fname, + 'dump-ftrace', '-f', 'funcgraph']) + + # Check that the trace has what we expect + cmd = f'trace-cmd report {trace_dat} |head -n 70' + out = util.run_and_log(cons, ['sh', '-c', cmd]) + + # First look for this: + # u-boot-1 [000] 282.101360: funcgraph_entry: 0.004 us | initf_malloc(); + # ... + # u-boot-1 [000] 282.101369: funcgraph_entry: | initf_bootstage() { + # u-boot-1 [000] 282.101369: funcgraph_entry: | bootstage_init() { + # u-boot-1 [000] 282.101369: funcgraph_entry: | dlmalloc() { + # ... + # u-boot-1 [000] 282.101375: funcgraph_exit: 0.001 us | } + # Then look for this: + # u-boot-1 [000] 282.101375: funcgraph_exit: 0.006 us | } + # Then check for this: + # u-boot-1 [000] 282.101375: funcgraph_entry: 0.000 us | event_init(); + + expected_indent = None + found_start = False + found_end = False + upto = None + + # Look for initf_bootstage() entry and make sure we see the exit + # Collect the time for initf_dm() + for line in out.splitlines(): + m = RE_LINE.match(line) + if m: + timestamp, indent, func, brace = m.groups() + if found_end: + upto = func + break + elif func == 'initf_bootstage() ': + found_start = True + expected_indent = indent + ' ' + elif found_start and indent == expected_indent and brace == '}': + found_end = True + + # The next function after initf_bootstage() exits should be event_init() + assert upto == 'event_init()' + + # Now look for initf_dm() and dm_timer_init() so we can check the bootstage + # time + cmd = f"trace-cmd report {trace_dat} |grep -E '(initf_dm|dm_timer_init)'" + out = util.run_and_log(cons, ['sh', '-c', cmd]) + + start_timestamp = None + end_timestamp = None + for line in out.splitlines(): + m = RE_LINE.match(line) + if m: + timestamp, indent, func, brace = m.groups() + if func == 'initf_dm() ': + start_timestamp = timestamp + elif func == 'dm_timer_init() ': + end_timestamp = timestamp + break + assert start_timestamp and end_timestamp + + # Convert the time to microseconds + return int((float(end_timestamp) - float(start_timestamp)) * 1000000) + + +def check_flamegraph(cons, fname, proftool, map_fname, trace_fg): + """Check that the 'flamegraph' output works + + This spot checks a few call counts and estimates the time taken by the + initf_dm() function + + Args: + cons (ConsoleBase): U-Boot console + fname (str): Filename of trace file + proftool (str): Filename of proftool + map_fname (str): Filename of System.map + trace_fg (str): Filename of output file + + Returns: + int: Approximate number of microseconds used by the initf_dm() function + """ + + # Generate the flamegraph format + out = util.run_and_log( + cons, [proftool, '-t', fname, '-o', trace_fg, '-m', map_fname, + 'dump-flamegraph']) + + # We expect dm_timer_init() to be called twice: once before relocation and + # once after + look1 = 'initf_dm;dm_timer_init 1' + look2 = 'board_init_r;initr_dm_devices;dm_timer_init 1' + found = 0 + with open(trace_fg, 'r') as fd: + for line in fd: + line = line.strip() + if line == look1 or line == look2: + found += 1 + assert found == 2 + + # Generate the timing graph + out = util.run_and_log( + cons, [proftool, '-t', fname, '-o', trace_fg, '-m', map_fname, + 'dump-flamegraph', '-f', 'timing']) + + # Add up all the time spend in initf_dm() and its children + total = 0 + with open(trace_fg, 'r') as fd: + for line in fd: + line = line.strip() + if line.startswith('initf_dm'): + func, val = line.split() + count = int(val) + total += count + return total + + +@pytest.mark.slow +@pytest.mark.boardspec('sandbox') +@pytest.mark.buildconfigspec('trace') +def test_trace(u_boot_console): + """Test we can build sandbox with trace, collect and process a trace""" + cons = u_boot_console + + if not os.path.exists(TMPDIR): + os.mkdir(TMPDIR) + proftool = os.path.join(cons.config.build_dir, 'tools', 'proftool') + map_fname = os.path.join(cons.config.build_dir, 'System.map') + trace_dat = os.path.join(TMPDIR, 'trace.dat') + trace_fg = os.path.join(TMPDIR, 'trace.fg') + + fname, dm_f_time = collect_trace(cons) + + check_function(cons, fname, proftool, map_fname, trace_dat) + trace_time = check_funcgraph(cons, fname, proftool, map_fname, trace_dat) + + # Check that bootstage and funcgraph agree to within 10 microseconds + diff = abs(trace_time - dm_f_time) + print(f'trace_time {trace_time}, dm_f_time {dm_f_time}') + assert diff / dm_f_time < 0.01 + + fg_time = check_flamegraph(cons, fname, proftool, map_fname, trace_fg) + + # Check that bootstage and flamegraph agree to within 10% + diff = abs(fg_time - dm_f_time) + assert diff / dm_f_time < 0.1 From patchwork Sun Jan 15 21:16:01 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 1726843 X-Patchwork-Delegate: trini@ti.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=2a01:238:438b:c500:173d:9f52:ddab:ee01; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: legolas.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=chromium.org header.i=@chromium.org header.a=rsa-sha256 header.s=google header.b=L2AXIXgZ; dkim-atps=neutral Received: from phobos.denx.de (phobos.denx.de [IPv6:2a01:238:438b:c500:173d:9f52:ddab:ee01]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4Nw7QT3RGZz23fT for ; Mon, 16 Jan 2023 08:22:09 +1100 (AEDT) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 0B4CC854E0; Sun, 15 Jan 2023 22:22:07 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=chromium.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (1024-bit key; unprotected) header.d=chromium.org header.i=@chromium.org header.b="L2AXIXgZ"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id 30628854E0; Sun, 15 Jan 2023 22:17:09 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-0.4 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,LOTS_OF_MONEY, NORMAL_HTTP_TO_IP,NUMERIC_HTTP_ADDR,PDS_BTC_ID,SPF_HELO_NONE,SPF_PASS autolearn=no autolearn_force=no version=3.4.2 Received: from mail-io1-xd36.google.com (mail-io1-xd36.google.com [IPv6:2607:f8b0:4864:20::d36]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id 5F5928559B for ; Sun, 15 Jan 2023 22:16:45 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=chromium.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=sjg@chromium.org Received: by mail-io1-xd36.google.com with SMTP id d22so4046093iof.5 for ; Sun, 15 Jan 2023 13:16:45 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=R0pC5/o2RI7pKA69it/zRyLMqFTCW4hFLKUHcpnZ/uM=; b=L2AXIXgZAR+8zXWsK9l4RhD9plcAJjSkG0445PkvR4Je94i3xtv/QeOxfvEeVgyoc2 k1bgUL/Xf/MLWH77qT5OOs/jDfxb+eQVGKm7L5yFyloEI47miHeXVRW0s0qll5YQlova AnQd6UkiK7dbwliU1YtNCsQ2kATLm/phhpEj0= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=R0pC5/o2RI7pKA69it/zRyLMqFTCW4hFLKUHcpnZ/uM=; b=jZ42G8esNTjiDLPDEmg5XAWcdQcpfsg8WxKRudJjIyt8YoMc/KqwuIrbYQkQ7sMCIs 1ULYtKY8bZeN8I+7x3cKCEWWrXKmwjjyVatRzLxeRnmXztWVTuMWwF9oIT339W3VcsIG M9BdXY5VIJc/B5rMbBtx7NxCKdtu02Ai6tty/tuJ+ORVw8lYVDBkDuHst4jjfBDjwDwK xkyqkbrnlsR2hssc7VigkB8Lh4G+YLrsWl+8z/gkq3BizKty7l3bBtpRhi9NM7m9IT0U c1wBDIqnjsKGAN+vgkyjK0q8H1oo+90Fz0LswXXkifPdiqL5FdtR/73xdO0Yo5PRROEo PCuQ== X-Gm-Message-State: AFqh2kpP1l5W1nTSMr2t6GI1tV/SCggjuCIoNatkg6JP/SRZIC+P5PuJ VH9dhm0/F8q8dR5aZxTw1mlOMAW9AkHsUxQU9MA= X-Google-Smtp-Source: AMrXdXvE4fyGilQNoG8SLTLC4fKHKkpd8XdLqzI6Iv5DaKJWvjpiLSsvpSoEDNj+OYagEyvBWx//bw== X-Received: by 2002:a5e:8347:0:b0:704:8b14:b6ca with SMTP id y7-20020a5e8347000000b007048b14b6camr7008951iom.13.1673817402332; Sun, 15 Jan 2023 13:16:42 -0800 (PST) Received: from sjg1.roam.corp.google.com (c-73-14-173-85.hsd1.co.comcast.net. [73.14.173.85]) by smtp.gmail.com with ESMTPSA id j6-20020a6bf906000000b007046e9e138esm4329107iog.22.2023.01.15.13.16.41 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 15 Jan 2023 13:16:41 -0800 (PST) From: Simon Glass To: U-Boot Mailing List Cc: Tom Rini , Heinrich Schuchardt , Simon Glass , Bin Meng , Ilias Apalodimas , Roger Knecht , Sughosh Ganu Subject: [PATCH 24/24] trace: Update documentation Date: Sun, 15 Jan 2023 14:16:01 -0700 Message-Id: <20230115211602.1127661-25-sjg@chromium.org> X-Mailer: git-send-email 2.39.0.314.g84b9a713c41-goog In-Reply-To: <20230115211602.1127661-1-sjg@chromium.org> References: <20230115211602.1127661-1-sjg@chromium.org> MIME-Version: 1.0 X-Mailman-Approved-At: Sun, 15 Jan 2023 22:22:05 +0100 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.39 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.103.6 at phobos.denx.de X-Virus-Status: Clean Revamp the documentation for the new features, including a description of the new features and documentation for the trace command. Signed-off-by: Simon Glass --- .gitattributes | 1 + doc/develop/pics/flamegraph.png | Bin 0 -> 48224 bytes doc/develop/pics/flamegraph_timing.png | Bin 0 -> 31305 bytes doc/develop/pics/flamegraph_zoom.png | Bin 0 -> 25465 bytes doc/develop/pics/kernelshark.png | Bin 0 -> 29617 bytes doc/develop/pics/kernelshark_fg.png | Bin 0 -> 28899 bytes doc/develop/trace.rst | 281 +++++++++++++++++++------ doc/usage/cmd/trace.rst | 163 ++++++++++++++ doc/usage/index.rst | 1 + 9 files changed, 382 insertions(+), 64 deletions(-) create mode 100644 doc/develop/pics/flamegraph.png create mode 100644 doc/develop/pics/flamegraph_timing.png create mode 100644 doc/develop/pics/flamegraph_zoom.png create mode 100644 doc/develop/pics/kernelshark.png create mode 100644 doc/develop/pics/kernelshark_fg.png create mode 100644 doc/usage/cmd/trace.rst diff --git a/.gitattributes b/.gitattributes index 1879a2dfb3c..d5931f03e7c 100644 --- a/.gitattributes +++ b/.gitattributes @@ -4,3 +4,4 @@ *.bmp binary *.ttf binary *.gz binary +*.png binary diff --git a/doc/develop/pics/flamegraph.png b/doc/develop/pics/flamegraph.png new file mode 100644 index 0000000000000000000000000000000000000000..dbdd27e6d872668dcf6f27174382371a75751e9e GIT binary patch literal 48224 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

>){k0gUGQs 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 literal 0 HcmV?d00001 diff --git a/doc/develop/pics/flamegraph_timing.png b/doc/develop/pics/flamegraph_timing.png new file mode 100644 index 0000000000000000000000000000000000000000..b388b8b9881f26a3fc8eab4676caccd22779149c GIT binary patch literal 31305 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 B>39GD literal 0 HcmV?d00001 diff --git a/doc/develop/pics/flamegraph_zoom.png b/doc/develop/pics/flamegraph_zoom.png new file mode 100644 index 0000000000000000000000000000000000000000..38b68444b7ba5cfaa34d9efe6773d697efa5ff13 GIT binary patch literal 25465 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 literal 0 HcmV?d00001 diff --git a/doc/develop/pics/kernelshark.png b/doc/develop/pics/kernelshark.png new file mode 100644 index 0000000000000000000000000000000000000000..3450c6b5fd37c849f5b3f5b1d6793b1883d94bc4 GIT binary patch literal 29617 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%0D)elj${nci zgEqLleK;qi%~9#54n%vxUB-aZ<9r~CLVIY5*kPXkdFU%4SN~G$Osr2fvG4DxxhEH> zNOj?6Ld$NS9w8%!%v|4e&>kPTDj8-o-r1hlpamX`!G6&7ts6F$uqWTagmtfVCx93h9IvSVupH|6K)Wfdxp; zgdThp`UqfEkl!h=R?TcTGzsDlmI3a?<@W#Z`-1`?XM8;WIHeC6Li+Mo`wtMP>Ho<; z|F2Zf-%E7G?gn3LecS4NJUO9`jqec4EDEISksgaUym?aTr$$Qz^QDLo8Zy6WUNMWe zTTg;olxX;siyS9q;ymMG4GS|?;V==FhNF+1za`gk%R}_MR}ES&_qzCbgB-zFbop*3+jg@RW^G`_k#EOcznNb`4e&AFAs_cGObm^hgW5 zoVoC8d3v~mabDlmKA$97?R8D?n3033l8r4RWFw(I&6FH#bq}v-ignBD`LugBJXyYEL%opp)R3+tA0Y1nugfnNC`hUf)gU-*!*nuf0K^uiO*23 zp(_X7Ex&4Fro{Dhjrd#Xz~pqfINKYavFTxTBJa^Ukxu4}Ay-0NTr{HKUUZpOZ;+E& zHvPUWqRVuV(nJ4T*1!$+mWbDkRvK@h(Q1j|IMHPMn43(|&ke)=r*SK}UTv4ImhWOG z=>XyX)hzA|QQ?5f0XFhqq~jvfiR<+}VDsQ-FwLLhzGS!-3OfBjqQKN%>V9_PZ_-UFG*e+GeVv+DE#B-|4+%T8?9#8 zB$Bt~V)CswCP&3~l5{GugN80Z;0q8Zy<3}XyfGT^4Bok;n(d>rIhJbc?X2g5A1fZc zL5?>`w6D)ndDmildN(AmiH}w#=;6B!WvW1DOtYVCI>W_{cNU%<(!aX5+SHHNRz@`Z z$yd}VTCMT$`ov-xKOUG#+2g=3#UG)WHe2lhr(I4d_n{d*HQ zj0;8+&ndqX2k+zr=&90!y9Ve2E|KW|T;d5*{L?8W%2d(%7bYNDr#lD;iSpY@G!2}< zlw0|%uUZa@t-pV5a(QlMmGs$?g}uiD*7dfuQkg9Mt9aIpeD;ZFA0OT=u(%oax_Fu* z;8sRHnvD?PgP52s8;xWJ#3HQn1<7b4BTrrDyeKV<};mq$6Ef@axb-5)Ae>H(hoLy#M{mK1O!kj|AHjnY-2;^s)wvxe5LJymg4Mrw%gr8=4 z!Ahd&Vg|b!iB@;Yl3IvX+U`5dRt{XBk$ndn6}Gfch1o}~$>LdN+!#@Y<`uihB{dM) z%V%a@u%QPrblB;dmjCrVRM7E!-x)$+-6CYd24X-Q+7J@=m z$;RHx`EmX93Jez*00-ah#_AMV_5u-Gyy)HLTY&)rzcniRDX)~Yjys6hWT(!NMSy58 zzUyI@xS$6{7d*Srm~*qllC8)DYd5Vm#@k;nV5?u{S$on&Ol*!KZ6pNv`kitu*!htd@qmlAW^h@4a*W!iFQKK3 zhD*Yx=bUe&2rhms`-eD-T@|tLze!AU(H;yUVxEr9n+WL@%EC~lIQg5qG~cKn`9urR zgL37G&nMC^+uHv3(odSV z3_ACs%9IlCutB^ihC80}K{gOAOe0>?gA~EU>_Ca=HJyFyn5oE0i^Ukt(ZH&c zvbmUrZPs7o!EGt|7&Td|5w}%z0TCA`glMy7)K^w1s#vbHJ36hc2_?3r3f(81VJ9y6 z{3I=3h}S6~=Xp+293qc=l)e03pUV<)ehYjV*uOKg6*CpKN<|lBfWgnLA?MHsTE%Ku zo!hVyG@dT(U2Co-HmO$b%QF@$7A}BCZM)8m3irwodqFBq zd@ymA!jFi8Yg>B4?V60nqr>8;@JygT- zEI(C*8nJ}EfXn())aF`+*26?qJ9Rs8WTAJx!lUWsN8>^g9Fi%(Gl!%Ybpu+TF+(`P zHi#3ps@G)42!UgmTZ~c>u*ynDJmkl%Lnow3GP~1CXhsjkN*t>=buG(TZ4e4CkCTFvs?vD)t+N$1J%@pFLG%I)= zX1^vT{;g819jS+-ADRBsc~%dqzRGvqacDd`?NS+fjH4+Z%6b=%A+L%Gt@FXoxp;~( zn3k3oVNwtMIT2EV9CvsuLLzRmJQJj-VwduM@ac?|%8VG3|{SA3VC{XxW^wNkz#DEG-4#dd5bf&T#)=u2 ztrtumBg#9bP?gAJ)3G_Djd+Y(l)ac4{p)?<@X);vHhKDd+;bd|jRJ+R4X${@?OIE| z!l?fAcFKpb+*Hx}?Xh7Q%%2gVNx95FM_VP1`?W@6x(AO~i@Op!W*8w(dpeB{$-lhi zQx)=?U|#4bLW@it*SRLE&4wfGt!bjjw@&Ib)gnFL3fB@zKV16 zlzA6OkW7`89IHi^Iid@cYYDb3%2Bj&u7IttTQNb>zIDIok4fNy@CGk)A3Kffn1;1% z+(BrzxB5=3w9FHlbv!uPk1IJ;eTYHS100k(}{*1a>|z9-&-?QsviC#H6Wu; zEO}ef+$>SMMg)Z}@DUfr@M(OuXf#;l(ci&!Y+=*r8c%4%wEUO}Fl^jt-SKl5K`Iq= z#S;eSLs`aC+Xr|gMly6?T36B!+jt4Te{NR4&K7#lpP=qk+wp`GJX-f73i+_s`2#KI ze%Sk>q~mbSDY!TRJtC}LN9onEs*t)5y`L3(K(|3|XY-@Yr5okB#U?aj!_OaK>Pz*p zpHhx@jh*}CRE(O5=2IUmP1i|_*JPF2r?{D^$op7thBbKWq%S>_Y^ME|KT4_;vGpM$ z<=bcWAG|+_GDEH#!Uaq`lQfD%YSTaaKFjt1%J)Wl_`yxn2o|E?_AnvwMluj z=^32MgFewTt{*x%h} zwQHu)c|1;fZ3IgAsA{E45O0}HH5?IJ*M@odoawtY;21Sd}a*%W>kpy1{1rDhxsd~ zYFgvU+4}nrweGS(_$8+u*dY5i?4Exb+fNS*)Msb!`RZx*;wfBZhz#IBT^^X$0 zY!JVKLUS$6C|`&~}GTxutuD&AX#hkHi9yiBQG(SshV z>OtjqHWE@RB#DMha34N39eqGUBtu~3SCUqTk-}?GaJEmie+p5ZJ8T;CfiW z)mu60)4u-m*s(`Z5`C^ZI74M=3^kE@oUvzf*H`0hmO1O^l^pGdERb@^q@nQV*GnIn zzP-T&@4ejzSrR2h#3&{qq9&VE4~wRJG$;f#tn%NHCOr1nZ&x1POCe(4xp6}La56qE zdnZfKSZf1U>A=o~FBYXxh^*>z(Q0Vn>dfDIECZ}QO`Y257CDIHhaarD z61jjsiwW{&Hn|;qFk@JuJnP>84|Grd9j0+$&4w`h)2(m4UzYxL-fQPw>0YZ9?_TTq zl257?IYksa>ylW|P~q|WLL~))3Iu|<7a*bjrh_}Q#dPx_UOeX$j{aO*{7655pW3Ar%_n(~JRaI`Mp!9H zXt?<%gmzfIE37ebIdnqAdF|#|nG1|msEDM_r0~V?EpMsrM)}r>kTRNy*Z1l9-Yt!f z;q}b86)7#SxIc!fCQYse^@pz;&?$b#vi9O>eejaGs~8&1OqedbH4r{Qr%FFXj(9*@ zj(P63X^C{msgAt%rt&U(eYEQFK|s)$l&$@)HgYlrJ{$H~%K^IrEC6k6Tp%HZA<$7%gEC&YcB zG1Du9xym(`xUOK}A%hkj)&XX0Ya*^Hab`wGhKRbi?iqTsANiLsy52EmXhelkV>LgA z6JInz6;Eg>ostG4Dz?!(oVPIjNoupLyA(=6f|(`_zu|qK$}rW2J=^MHS}*5}Akoil zmtJvhKd<&3Sn`csj>nY+EQlFFrOlhxmJ<>w@D0zZ($r{xTpSH+eT3x&*BX~$nbpa}R+#Vs z2lnGqX^?X3YO-8Z1v$_yP0RwrPfsrHjx$2$ypcz1!kDyYAIP<&qv|gky5;r5Vfrbd zKLeuFjD^CMM>xil?w8Co+ATD?97kupDRj|!K~>}#FUp7Jt2b{4gOgGZo>oY?>*Hq) z`@gd=a*j25f2BA$V(FRYC#Rg6`0yR?fYf3%az(()oZVUT6WqV9zG$omPELQb()H;hf2J|#p*f1@il;ot-VqF{@=OGrV+fR@Wxen zzDK(FtmRV4@PQD3h#%id zI6N9jJrBIYU{=Uwr=?jWK?ycndVhO@)k%*)mR{6a7HqtGsg+ zkcUIuzq$W_;bGlt7Ihv&h247)dFVk_{XEV1L?kM(Nf}bU{6J|)Vx_O(*SQGyH;JWD zi*PY6h@Uk?ou{f|X#76?m+x^GALt4`A3U&=u4hGjrLEHcNIknE;w7cpWcu8RadVAvpBjbOr=o(p*NV-JhAg3LR9@fGVV(`jP_s01UaNO&A19cz`nI}q zg_lNAyED%7>Sc=)%sbw9`SaCYXx6TC<1k`^OoG&@0!tuARlb)9bWOU0xBzKd7gf~CaK+T`sg%#{cP)zHvm-Sx#_Tsv7O zZxz`Z7uUKf!=-QD0cZSRf^ewg9p};4>O;kV-410*pOO0}5W8l&>3F!Pw-{Vh>yZ@*AH7+Aw zT34q6E4IJLS3?d22wV8Bg>F51+Wa7a1h!){Jougco+I{Js0+1cSMHgp6bcQ<3WXEW zdKlY%?aHOa#XMMP304H@W4|7(MEn+!-~qUYH?1cLMFnd=hWQ_D zdmb@EChuyW39O{v6FBTjdx*gGv>Yb-ts}#76cXwzzuBK_O61nPVX*7+NaD99M4?*? z-#;p3{Mg?9s6g#`{rT@Quu~ca``9~*)A15HMMwgBWGVIm{MRZN7F-YA>bddnsu9Ww z>8J<>Xm31TV3|hT|3ll~EA}7iOTeMTNK&^v%ur=ABL3yPP6Jh`WSOAQt)0Raeqh%* z2eC|dZ4UF|5hFzVOZN1%H)gO(Mx^)sMf#}&(>VpTXM)H?oXk=8MVrL(onKpx{Wvho zlswim;wr;XmrHfeThbt0j5ssHgOv_lnDLTsD?i;m5Bwv{@z06ejG^adFYkBI z(c@yW30s;rpNnxk)uLZ}ba5zz(~ArZsR_ij@z9R@j&VkWVs*@Y47`b}a4|ym;rjI_ z6Hp&&Pk(`xx%wP#u_BwMk86+o&Ww6QIPy2wy~!olz&T@K-c4r2F=|xFtucF!!-GM> zNgoaOepn7~_U8JJ1-UH8?w}59gkilX^fxJeJ^5YAH}`zJXBXch$DieJBw2)RrIV~Q zhE~~jb>+^!kvS^77?>f>_Z&am$st~Hb#Thbec#SIVSfJyCXkjmTCKrDbh1uHgn_|| z>Ty?9;XnGB4JvfLlavnIKaAFdicLwSJkmzsaWl`0RdB?}2m^D5CWUc^ViIcngjT-h zQB_0{5VlCtc)DVS_9--Dfg#1F!e^v3vOLx$Q!P07g4gl0h}v46-Q}Tq?M1Jjhq_dT zJKbV5U#0r^N5`)h<Z3mbXyAw{mz#q zu-+28(Ry%O^!gu5MZ1dGNClbD`~1UjOFcCmhXZkZysNJN6?8rU$@9};B4EeH1R~s( zzv%w^0wZuJ2i1H_{OcwVvV8vHLPQxMx`++0^ShoRo_WHZCaP}N2wQqGT5N|m#~u9P z2S<=bQKy9120lM4&A?_yJa6votm{|-uU_+>G8u1K0b>YZi$*53r?^)a=IKRy0x$6_ zi}fZPD}Xumxzg?M9vX4cc2mN|d>aZ+Aqd@Sj;nJ7Ovquj)~2cE-oo<`Mo1Z*@XA~f zsX0;0Nq%rSl-jdZWaY*4hIaI+zcQsokYZqH*WtL4|JqUoho6N@jg3v&7G^YMuS~AlrNC8L z;$NIE#qrxd<-u+JEGb#voRW_va}BCt1J+7p{d6~!Fx2G;7eidp=p986$B+con{??# zv?6t&!u8Pm4b?RWkNO4gd3XF{T&X<#!5?J`hEvc#kYOkf%my$P-9NM1J*T2lE&LGq z(bC^?pdj;}2R~l)`%b&5ZJ(uM=h$Y6pDE1Uq$HR*Hh)22SzATzWrJSb!Nq(bYQY#g zyVhL_bJq1MS-EjT(71=a1=dQbd@3(7QUZT)9g-3k@$~NC`I;@j$XZ{7)VAEBJjtOD^=&#m}1SqtF zPZYe)Q_~82p;FOU^_S26;S@jQ(gH6J)dP^C)c@Z|#(yKVI+Uw+yIFw`7ZaG>@{N`C zM}fE}$A?`1wh~8NjIQj#19#Ctt`n{oelNG{KF?WA6G1!xL;QXh)?6dg^hFoZPY<<+ zNSHpniHlj#FcVzK)-ljQ?W1H~%tNN&pmPzHAr zS;>}@u1v|cfL8KQQ3G{eb-OCm#buaxZ+vn0=B^FwmCTW4=vMqQR(NFgtS)So!Dc)` zF}OLX`Zp{kQC3m1}Y0F{q(2!HrKcnlb z<3qIHXEr7#3Ek?##oVjl(Yu(CA@kl$Kr2*XG?IhhHHVrcziJeOUF+pvZ9JaLFJcuj zdJ#$)f86}D)eO>3?YS=D)hxs?j2U<5v>Xmhk@4XVHd+G^YXsS&Zb1Q>K+F91@(`h0DQJ=FbeM}xL?VoW2=wmo-1%UUT zCkyy8QyE>y-jH{dDfFUBZP5RG{3m6Y1#irZSoDBJuSP27=}iW#yLIT6l$M!Go%@+I zkZ;`ubhe`SqF!q4VYMiQpag7Di>LM^5aLAa|Kyq57)H3?rTW@GK}n)P=7=b&;u|-i z?JFRK3J%6%L*5kBDI0j>H@9$w>i-j3zA)R*TVI3xE6vJyb<$|_&zk`55VqieG#~c^ z=u`h+f#_e)d;sI26u#9XhlGD4%oQbJ3tr~8T>p~$ri%0FMi`@e+wEO<2Y#DWBj)5* zoJFY1#h*5qf3#72eB#rX4N?+ig`C0n9EK}8Lu8J=bz`z*n%YIv!(ur;930;PTi{|& zxv4#K=5tMH9Lw@fU&1KVJf7X_nYtTF8SF}i=iA?iY}&|F))~aR9;a%;xEE;EPa~x&(H#!p&IYV8fr4SZY(2DeSgJSA<4lKd-6}5wKOi zZMx?o(OgS=mG;Pov*p{P-#xdkm_i<`Ks23)o$oqw!$u0*-f4c_$5zBqXPmc}Xey{A zcDLIc=|Pc4u1bz3N^Y+LMU=KZrhV@MIP%rvWA51oE~c>NP#%h^x$i~i;rNp{ZRe=+ z^GaU>71$Y28!Yvpr?PNj(j0R>@Smorb+~(`ju-K4%3a%ZtV(?6$kx0sRG}Ve*Y8pf z-Eglrt*_%=`^U`qKUn#yBTNN;!Gm&r6Z7UvdE44{1zN%M1#N3J`fWc9AhF-F4eDQS z=^$)5Fa#nAfGWaY4HVL_WF?Mr0`YU{Ox%}qCeV5tk*gXCn!f0yw}x;NDDMm!2NpfO zIVnyH4O$<}{7X$>*X-4acNjep(9V;G)D#XMxO>EPvX%jw7Y^*wL!*U`~;?7h35 z3kA=PuKlxE171kM`z!0mU40A%zHayvy{%VKeay2*>>%3zuzLhl5unVMsXzm}=D)U+ z{uSx}QRDs2uHvKMKVG&|0vVzg{b$n{+Ea~ox}e*Ca;fRuvsZ!5`QgiP-?w>1nIRF^ z4-J4+Md^`0bBR^c=yNsv54mT|hSZ+Y)qLJ{T+>?w!MJWxIMklA{3}6FAW2g5MMxwonc+F9 zkiD*dxS&_k*mfEQ6fAQ%{^A`(E%pV@$w;2FW}w?@nWKeMcRXJ+55CA+vQ7&z#*1A4 z`}a`zv%=@~Ye4GjhqtkLEWA=Eol@Ym7j}jMFsVz!jDKaTKj4AI)@ZS}4pi?$Y9QOW z$e`!}Wfxw;MC9*g8|8g2OQ#otSeElF4NZ$Y-J9Y;W_G1}~t$2fM7lgd|cB|g@pBa?wQM5gH;Q28A$rsAsu-|^O3A;BVsmmyNO@K842U$&D1>&U4x z(^$~#4I2&n;r>^|4KlLW;?i<}@sx6@PD?#NvDul96l=pmiYwmS;ze9|uY9d*qJaYS zpm(mzVlgwYOKKGYSh&ORMRmuwjdx_zRSV;xsqmH|1+=Bwc3Z*DE8vq<;ja1lQ23Gc zaA1&kKW~$0FxT&ZIiG_>g0R;_|0+|rMqeSn-TPJenIrDzj1IkFAs>94sQfAjSxJ4Ej?i?Bbzr-Y1TNQ`h^> z=w}vtOPj-&kGRQ~NaxIRVkQ}uHge|8;gcUx4AK@WvJ3&cas{01r#4h%nZKMZVP9s? zo^BG17#{XF+=rc9p6;gvUS7_299&%tut@XLe@H}1fYFmbP>L}YdwWOS#*4HS z-CfafZ9%5^$Gt#d+)1s)*BV3q++ye8qTm<_v84ae-_+Dp6%aR>4GKO4x?b)%vJ$OHbR{_Rb-eA={+?ad47SHOI$;S`2-mijGf@fzL(O zUlx~0?;C3INgJ;>e#hi7pb^-9kw*W{_8{(`+tD#{t&>{14QI!V!#QLW^VuDjRu^A$ z=Ck!bL?f#|V_$cyhU*!Oc~g^(!K}nF{d->y@v6LU ziW^M|(@oeP?*Wv|evdpfyQA~7!_MJpO~jRiDj(qf*#Byk?@x;<~yFiFn9Ff=bE z6-1o0#{`kSIyg)SzJM?7R0Urg5ai@ycMpydj*g_~I@_*%7TRMwr90a@N30JQ80P2Z zv(YNY?A@i~Yrr=Q!6zq|Bpww~yPcP8sKtxb{xh)fG#?Loak9x`dmdfgYXse|JX>(w zxwvTc-3=VB3Tm(ZGTjqNhTuc@(>jL-|N)}Z79jqR6Z~rFyLPc+`ig0t~@$*P|qwf z-FN)P>lZBWrOj1ccl-g*JaU^^Z6YMGj28Qe>fEZ_<^>!jLBEWK`V8~>`Hm3Kko!$u zyp5f{6mSTqK;%fuk@?;CT3cJd+R7HbJ@Y{(l0Ox;nj`Z-93#wUd%i>2=KcoxTXrz#tEjBPC5Q8 zYW3518ToU;O&!{8U0OD^{*R4=wkVw`5{5|%Nq!?ANB|$iwI2A_5FT^(yvxBgrTHA1 ztPs^3elXIU`JCXufCufzmAig^wh}d$k*7q4WxWbio9P9 zr`#Tcr%QL}3{n)RqZEpG7bM_>^Owh&KwWm!-p*Why=B36%;<Oh1V+Uhr!4$4?$V zI_+R5Cks6!28mnwi?zVAE$lf1OY-#mqo%UgDNjs)YHGhc^jLX)vYi*)ogqQ9YyxrZ z0+_C-Aj~qBTTA^OpvJp~$DTyqP0-^Y%2Sa^_Y>+ys87TSl^GM{?B=JX0y~&sZ%;<4 z84K*kOqam>hV`CF4wJ5Z6azPQH>={b&3B-n6XFGwMBUK0Z%zGKA$&kfmL?}?4THxB zXYg6@crrAL#G)e|YZcqv#uL}9jtb{Sy%8mIaQz%jU=3k5WBO_hvy6N^E=u{_<^6t- z+Ky)pZC=C6s>_tJm-K5V4Pr}HE}!M0LHx!i_NeAv@V*R?u%qY96Gfw?i09>x_BS^- z^~VQ9rdKWw)(=i5`K&{{<~xh2N?aDB@Y{a{95bM2hqlpApyufC=+y~ks=YwB2D?Y6 zixq1kz+T0-8SJZ%7DKzeANi`JrGiF>j&?~dkD98agM<8oEOm!mrGo;`mZkqsabF$} zW&i%GjmnlRLzYs~X2zC%DP>7QrLqk|h%60*B1?&ENoC6tDV1d3#t1$3jAevujTl+7 z%uu4za;|&O)AK#Q^IN{J*E#2}DfjYOukC%kug@Kz8gMxv;34;c)PSdB>?0FfM{-l$ zoQLREy&FeCt+u5eApKg{mGb3RlO+9D`4t6J94Dso#n10wx7TC+dEE}EM}`e`r7IXg z{^5tuSp2F0|0_I2o^ntJ=jn2!{;S6Di-6R(pFVyfjp(%>WgR%L^bUOBHfmDiaf9y? z%~@Ji&8gwHa^2`ulPgzVROWfz6~!1%oM1mcXJwUY)vLgbd!RD%A>w=RuX(YB zTgfJsZNViH5e}j%HoFpSF;@3G`BNhgPo9`1dLMkam7Eb=)%cSnY4%(x|4J&W?^DhB zNk#f^2j>9&=LUZsh6nELPUm!xQ6(qt zDuIc837R}j{Wz`VeqIueG-;Y?B5g|LUUJa0YS*cXON}!FH$ImS@+-M~{|P|P6)z@c zU6`wQf=&#*-aWy63%CGb%$|hE9h=$35h_4fx7!)9-OXVk{zj5FQr%~@>U7mi%G=J; z{mb}@z4$_}-Az$ZXk*E8>pS(DMoEZ{z5)(JMml&CJH@ZF?Rv=t!Hix3QS?;~wYFF1 zqw-GUO3!#5B>f*|8dkoI{o!AlT+I4{5q2LBhDRhEIX}v}0g8yN<&ieV&RE>UmhaFt zX6NqH)SCEfB1!&pb#6^{eM~HmwAykr8PB)KBts~>4dZy^SJ=F;r6~K<%XPD!8y4gg zmec=7G8JSZ*LZ9{hT_iKhOytfSUT}i-LY#!z7h6)eX(Hc6aCvL1@V>!ZkBvrox9Pq zYYF$)P^;V0QmTYs4B#}Vukq{rTG(|aq&CMt{iW=jL1^6YT0;C~&8I?_7oC;g#>)mar#n2{x?Nq903%5Ao-HWM_41t5lTD_5hPpLbey!o?R-N ztmnWAy+`*`WjL0c51Ycx6`Oh*SK%^s&EGttoEAF3zFtMUyF{hS(Zv27UONi>?~|s2 zcb;ydri))EMAyy0;X&yo)>&O*IkqM3KIzY@3D24|fVB`TH*#6T@6cSQ?z0kfA0b27 z#Osm!>rVY9gRWEFj!9?pd?Ybqu?@!AT{<~?af6>N$5BwA3Hko)hRPYp_ZNF^NDTMy zdVCr>y%O*jDQ%FXovD75G1`~ZnT_}eF~9=AJ{3$nUa*ko?;gcAUNWa+_bxhuCqCp% zjV-m>zpY+v_BMgMwK8#1gRAo-wsWl;5>W-e`J@<=|FAJZ5m)+jXMNjcB<0Wd{&{a) zSV_{imUxC65P7q>S)cdQoF$nRbrgGEcw(bx^ht~m7}N{ici-*)S2$sJQsAR~DzPE# zN!#PiV?t9?Zxd!J<>>Wy_m$74-aCwrKlVe+MLR;zFK^^^*N3B|U@Mf3UutB^?x|b; z*BCJyE5$_pMi=(X(3-A^jo(JQ!|Jp+$np=yKaQugo_->3^S~XMwFk*k99`gJEp=;r z`)Q5-b;KDsvZwe-?1S{1w>3`q9rTmH!xFER+aM@M6~C1R#{G>}49_0koAMjqk34`Z zKbItN_*YPh&?c0+#9kKJ5}RD}{la=85qf)%T330i>Z|=_HYC=3t!}1*AXfBR&dET3 zpTe(*E>$(06WDNE^eJ8y!%q2lo4M;3Ziyr%hDIbxLB;?&B_-&47}p+b2+*RMheTg! zbm#7-^}D0AGKUk)cX%J!bnc{XC)Xo)Iih=ZUB*t+U6PzP>w-D=6l6JmE;d#;Aj?ua zvgKx;Qku$};@LnTBN?2jIAh4;eBF9zbu=M4qb;UjQu&M?y?A81`sIdQTT8Henazz; z<=j6wZ^tB=VImMzu*=2|P2e6?xFK2JG_Mhhi-@m(*(oTtz%S{$A!15vBB9Qj>2nB8@+)&ooxja_$NJu^h63&Tb$rjKjK-QksD73G`-O)@xBz{t?Pkv+n zn}o9!^T*f~C(m%Cj#D3Ps2Q0N)@=%j%;5{0Yto|?%uX5Bt;@#Mxqy#aZf*s*9 z4cLN%6x{aVr`f$)2h#Ld4ebs*&8SP{CbW$(t&jt7^oq4K1^Zb3=^HAmAWHxKBP@b- z8zyi$K^FwoiVQFc(s22B>M5!(cOd)!7%06#BU==eSt5W#4gIr37rKaKsAUKM|0N^0 z^W=)!`k?fu-V{mxIz5m1y06Uu0I|wh2`I zRA#rh(Lwd3Y@yE{yndS2v=5Ma`s|vn_cgy4}z4e z!QER32b9&6jVQ2>qd$owT;^NUmt=C$aL(a7pPY_o^d%hK+_a-_bIEbX=62l6y*KJc z!k+~A3E&H*QItf^;SoqF%)62;oGAQL$;%;Aw^xPu>eUqG)tY-w=?N!Q-rcr!bbekFI2zf zpQN62BI$*aETgdDmL)LTPc#>rn}dLI8h4ssTogJ_vGUT($c-b=@0+Do55>x=3?UpA8>{SFP_ zkFm!L2jvbNVlwAMMsFS+!5oDogP|?CVj{0%Hf{HV+lPQi}{>}@;>7CZvV@^P!D^fMXda6evjQcIMe8Ze3D@rNP4O)I z?_}EzX3CkceLu}55X8H&y%2^aOtz(LpPi#eJxTtt1)rtFzNfo}Gf-n8 zs*zI^W6a0O<{V1m2;hTF?qk4X1z9WC2xiK&-L_FOEpJQ{7RkWRSh&fK>m8C90|313 zLscT@@;y)eqvRR)9EZG|Z$mi2S>f$Gq$9@WtXgi|&?wakay@@bwL4zExPa`LK%*S;BOU(!EWa;twU-FPI*aq(L)3%ZByZ%K<@8zLa6U zc4;_I9}s5lR<+sCR*SF^=_$aUHMgdhhqcCQl-`&9;w1iOU(6k>X@}Q9dR#%LR;zsf zyYKVACfSIKN~6Xe2*2Sz(qOcpOJa6`)WVP#Bs<(!F!=3kL_dd_mwym)OxH3~qLy5L zaN{E&T`s+Zaqc?iAPaOOw!e7_ff@>M>fZUX9=2O?j3SOd@7?z0Y)k{SVO_2=Jzf7L1%TX2X0M43pb4$){RpEXi{g{ zt*GvYgIu-uBu!Bp0K{AD16Ht$C^}*(;{ttn?D$iIXz? zb~ccv9pq|jDeyGP(-hqa!>CD1g38KPVXN=~CvwZ~ug3$Fv zbWNH{^PLdR@yBA0{c)oMb$9~;!YD#$Sqr%5{CGF-NAuQX;f~<17Qe0%V;_dU_v6!p zg=X-<)Y(=Ngx57n>1-nWNRYO$3xiQK{g>5*9;q;|fYr{-zzzGo>@QJE@!WsKw}KAS zZsr=#I*}>4kbzqT#1n6#16}X386nZ*X1jNOOH?^KOR0qweqBo9r2uVnH|S&E7aw6n zcF{1$7j4KD9fMw0O&!%;$roN+ig59ID@JRs!JoiBHvc7%no%-)sz|;PA-0rSvNBUV z1Rc85`ZEba$7aG)YMj2zY}3G=$v;=N&9LXR!CA5}@ZB!Dkt^ENK+HbV`p5EyLFtXm6`sW_<-}T!uww$)h=nNv~6%x@2E&R@ZQh2 zq&DNl3_0hjTaar$9~&`65Ks4Ld*gwBjGitVJr|Ry$vY6AIf`|dt9TVvKA~;EijJL@ zZ!EJtoO1D17q?ILw%iM&g3`q-lGSwA%avTw zt=2!)ns*Ff;B!^NKdBjmcpEt9A7(`C=`>?9Lj}Y&%UY zcrbD(v+k922@BmE^H-$W7u&O1*z}e$gt_JqyCut0SO8D=Y>R_+_>n+*OMg>9z}hlK zXUXre$Dsk+tg-!rq;dg^LOoXG<54cqE2V#I9^kqx5FJQL%0|OZx8-N!#;ZN=`Lud! zzw4hOJfT+S@XdBhW=3c_EpuPq_K3V#Uqh@ii+RLP77mXf&gI_B?S{Rc{r7CU8>H?* z2xBr`$jkhcjRpMN3Wx7ImR%Q1sc6&6t-F8l#DY)M^j~#;n2fjOvpeLiR#Y!Flbu+j zzhFR-Hg^rLv|ULsz0_8=d*dl^x%PyC)@!fg&o_8mm#AS8+4!a_-`_4iY`^~gui|x7 z8#&e5I#cC*_qO?R7pd8SRsW7+?!@>a&f>cA{*(iy3D?gJF~dAty%%Gq_-@zBskCaT z@b>=v)cBDLKi+V<00o1$$Qx5kAmp(aCw}!c0>A0@U4A@0Orp#T`_|X{z?2{HjVe9} z63#g_KTSX63pXo%XM!6-znf4CBGGiv(}{%ZNww958s0tbxFOc}B;dEwWCihUVwXgt zzCGKy|G2u}Sz_69C)$g0)7%ub;(J_OE)JM0-*p>xW@#m27^Cv3%dnqz-M)AkKnM)K zM|Ilb95bb3tz>PxRleWt$Rtwp#K_0HN$`S>=*J29N~d(bOgNtG=ITg6-Y~4GU>mP? z3-(l6oHl-{L7c&RfgTugzu2S`P*;%>qWuo-()7Ilsp3bPyo_AA7O%ymHINRAu=Z00 zV=xCPBf(B(=RU??Q3rM3=1f-8pE)G-Bi6AJouwI_Ija5PuW}Xkn9?+5*XDtcANJ~z z-lfIT@n2`#rPbMqmw5-N)mDRi!03hlJ=tIx`mjm{EiqCOZBiETZH9)q=X=U!>QdkF z$@839{z7!u3sjkaoTynxGUb&|pXEsfaF7Pld=m$Q6~AR=5_mjwBxuS91}GLh{3`c# z=*;MNl?7Ufck%i1mJG=t*LjK4BFFOw{ikLN2;gcougp|SC~LVN+QiT3sUF=mpLC&J zdZfSWIPNk(-4%3nh{gOCOLn3F)?MaKdu~A;LN6-RSlIs;D{juXkXmhT!H04fplEe= zW`9|=Pq%(liamFYm#Rn|l%{KxTE|y}0AV&{Tu*La=`R>)?MkcYFp}Nd%ie{`&#~0Z zJ2SJ?=%bq=zV9BOti)(s%#>XtT(14W%aoSYK&yFw;zhYAgDB~o@#zaQ1$BuBHWHHX zM>%{*u1#B9Jwp@uAG0j;tjQMVhbK?NUdmEJZ3h2Rt3(k0E)YmY#Tkq1P{XR#er{*- z;jZ1olL#5}pLfYu%nk$A@{85HIoX7cqrGUFHtV>t$=#8Vt@1!fVpl2N>0XwL_h7ie3jj>_CA(D6Ne;)js1;q#bAzm%KL zjwjunq5AiZtjbBr&)T2azl|?tIN>I5oJLQ{gG@NScefR7TkhoZl!%8_iJzH%HJfmu zT&`4v!`i8h9a;_Eo-LWu-gKxdRY|o8yk2F?W^~LU$N2r@jWPNMU&mGybgX$h)hc$C zM|N~wLpiDVYs{lwcdp8}c2<;n*eJ3hgQu>$3_KQyJWepxI8 zkpmO0zGD6$~;2eO<$*$?=hwvU(8 zqJLtFZ|#929IS13?#$)*4hK@b(LEP#zA4`GY`9+Ru42`-!;0Vb!Hxw9k5r>lTOcSg zt@r`1xehy#ea~&!l;0MyGG)dQ6XEf3v^l2k)}B@6+btUxv2!XzEDDtN+}HIysFG0P z1rHvbfOR;5t1Kv&kg6&c6og2EC{MqXyR(l`!Pl~oNPxje`$0X~rA|{LO<+WgjqUO_ zE*YsDd=cT1B`wi#QH1;AZ^PBgCRBp{cjTC&ayAz!bx1vOX!FNKtf2B5X37?@I;)r| z<{-e!m(2}}#JJni#qg^cSNr$y!Q|E(wYQXvh4Wjo5xdp~{EX{GUxZ`6@wenTm?eQH+B8_#5sk>XWNy9GI3%9aQSV3AXIzZ$*@T)7tcZe; zQ%&PmrIhUZ;+@x*N;0N5tI*MRIC>_(03nMT_>y+Kfh%O3r5X=q=P*+Jr&kb1-XBC; z(VSvC{IPrzAvczu_Y+#;44$u_t9s7I{A0N@=GA7Uq0V$ZN>7@(;S7;$-(oGK*&s^(w^y+{&3w`Q!V_BX z+9h(X3b3_4=Ytu89VTXCF|Ie^|pfW@^JS7FK3Lx zyHz6){4?IAH^c%&U!C`IIDxY77VNbn?|U}IpD#B6(Ctm-+rCU+B(O(>v$dxK|III} zK&o3F%z>ZnVQkTwd1bJJ#ge676PD|j_^}nT^ZQeN&N{{hmz6-&v=GIP`yiah2!a;f zOAi~@;Fg$4@{8*`@b4?TOcO4!o+bZa>fwsFxuAeVGV>#E3@EHnP~q2;){n2h|L7rK zC*0)$cdZ8%Y*?wg! zgjbJ8vh#NcbEd}@9{?`F4C`9(+1+pP0N*MXDZJw?h>48&LSSHxAmh zo2`UrtR~I;$&;$Y9QEaTiH$+D4S8ik)}R>d)_#biBCm zJ)C)7yLkGH4yZwUpZeh@4KJl7pB0$-FY|X|dLLWfMg_UbstrHq97a5$rRpeKJ#4iL zI~U_ApL-uBv|-g5B~}gjaJ*8lmk$WJe8*i{caXvULq8wcffEY@1gI!d`leDBLYUgbTE$Gs_r_$V*}nJGD-l2dL!Z!Niu_mvwr(0yIv!gvV?9v_U} z)zxqDmnSm?pdGMdKrV*q|1DGNgIwPUs7n1`l_(oBWvy7>V+B~8&t~kYMwpOPPyn-! z0a;(|jL`wm$KXiGXH!uG#K{&vTL?w_jQoZ*S#1@V)WlR$$&+LRGc8U$d-%&L0JXRT zm??p_b#1|FCrevWM?jO$5+NFaxd0z4N)6Xb8>6SYRVNf(?n=R8bH;}%0dF?z+E*Bp$@D=D)3~Mp2=9dvfVMTga3P z5d9M0M)9To)^f=^sGDCIHFji-L*?p}=`+=6ULIx&#EYO1d11gib^A*`FAbOtqqN*< zipN3hYEOsSX}4chtza4Jzy$t(kTA%J)!gpOg{*;xC{V<$Kp;R$qClw&M|JuG0GG_l z;GaXUZ_vD8lcD;zu3;o97$Fo2wr#DQiaZ-JB85r?Zf9Fr^zSVW;)(GJkATpBDTZS# z78;(>M*|2`zDBkb|2h7fUTB71o-QR&WdYD9JdOomJHHZ_zN*c5(0QZZUhp` z-i2&^8W@h&{BvZAA+~<$6%5rfEusfHrPdD79vhaYfCjf&+;uSwM2bMTSGJ}tfCGK< z$&p*HNj2Q2Ou8)C{h>}m$LuPjEvSwR=Wv8VO5iit5(Q|nT zylz6b1~PqlK|+0&?OLhF3IO^4DEG4rF-}<%@}z&)vi|Lx`8vf{ghIj49oqid7)7QxgrimxlpHZB!k!}u;vL8b3zR+yM8>Wl4>R1&zi3@f^|;f}@v zG%5m@pt72MZZPZK-+n+HWQXAzOi1>A+5J_CtiQE2;1Ui?@Seq|RTQr;jCyRwL^kBx zk}Zx+GoZf~^U7lm&AFqH$Xm8vutN1cOU;>ert_}oJ3pa)5M;ZQdO?&i>KWuoACCQp zQIVf2=$-*6@pfeED`u;f-)apB#}M=lw1A-JVgTjch;-7nWn)y+InqUSXTNlD_Ea4s z-NW&pOG!vb>?Tww31<-3ipa^m2geR#w_zHTOrh4^I6T5_(u(P2uf~5^`jsZr9)3bX z-jxFgfJ+A;NZmUhTQbFsasddqyiq}|bR2BO16erB>wohQW)72&y7cbC^ra=;VNpR& zEr6=z6RzBOrlfzk-lES!l{<3e04sKhVub;hrLyiT-5`H`EBJxJw_!aMby)DhpU?Nu zxRBzo@9hW9&=P<94XqkDKnrz?+V?eqCf$Sr`X^uF=VfU^j4QR2$oasQC0%id?(6P%821$T7SIFLi6}M7P2bzTT{i&pfekp^!uPwBcOh zz1(F0r@&Wu?3RD` zAxC*%7+2>aYQg8ymVb?#!&#Y_ght=}%NG+@{u^l6_KR~c;(>YIUI%OV<6gX$3I4FV zoi*Ok&2`%;M;AM$Q=WF)q@}hUwRYVmBPAodO-fN&N={iuW}CjzDUywd3p}+GdFq@s z-cH#TdDM;xxe+ZTjh2=>B_*xAUtU>OexH<-vXs=Fg<|+3<{uBZxSeyfzx;oGVE7q( xB0L~~v|!|BkN38Aw_|c}b#t*pdq87$t{&&z@booR>Tna2u9ksj&Y`o{{ujdx!0P}2 literal 0 HcmV?d00001 diff --git a/doc/develop/pics/kernelshark_fg.png b/doc/develop/pics/kernelshark_fg.png new file mode 100644 index 0000000000000000000000000000000000000000..a54efd1c4cf8d6d6f2f3dc5085fba167d01ebefe GIT binary patch literal 28899 zcmbrlcR*9!wl5k*K~O+JK*4}gr3gyLP^3wZ(mRNB>5vdQDkvZVN^b$_ReF)oyA)}m z2pD<~BmtziyYSol?eFe$_kHi2=N~w;)>vbXIp!$8G1gom&!GzBWb|Yp5Qtn!QBDH{ zx`Y6Mh#*&pfGc~dA4`D$E?G;fNrOP85m%4RE(5>snk#Ckfk0mDAkgbT5akK;igI_G4Rx;Sv-__?Z<{Mp$VFuZZ&1~W6WfPjFNl~qDQg0{9c0)dc| zlLPMJa5xMGQ(Idb92}gVpWoZti^H7(cLW5^5VZ*A1ZGe$NFYHVxHmYVH{nL`4Y>rl z{N8*F4ij7(+>7f?NH}9=2BtXE&eyKR)XL?{VK8S1#943e*^L`#!NF(R+Go9(-rCx; z{QNU3t23*7t9(p8b1<`2t(A6yHZy`5qz$@(xFJw0AXh8LT+7Uy&s>YEwd%DJ$QMBL zBD8C@ac8(-OmG4w0ds}{Awa=rHxkaY6VBv<&jj*o^O*&hK{r5h+HzJ1s~gNWw5_xe z!H9(XgxcQP)&251VDT4V8cDZ5(qK*u^5D5tMg$UNxQMv`QcX+o zubpZwg4_arT+5yk#jreaBLTgbx9m$rOI(4GfF8E+PyU=`8~}rwZmm!dRFdm-@&wC; z3(8sXOu_=cZasAomW;!%RqrHIX7l;o%th5g zEUbzIww$3s1HZ*iO~&7}PA#OZKID^ts}Mh~z6Q&=|BaAY{_--^EHD4&hgFG*#52R{ z0dUhSDvGB4ZFtz{C}piuOH^wj#O;J96!)-FCSaM2XB64YG|328FYx~Yd9ngE3NENC z>W=MsHWaH$n)u;_o7b=2xJRj5O3pQOf`ikNNRhGI-zijQJ^7~Ep4&vMWzU*X?}SP| z&2Y43J6r+ZLK6noryE9eyyl#I(8DN;Dcxum>iix)PK4T4&m-fq4BDyWy7xd;ty|}q zyJ5FV1!ESrCdW9rp~)Zfs#X@AnQJjZMNW4jK%JGpklylJc@5esrHmQ8r={JRr1TE| z@q!~fi1Zl;WB?gKffp>jiY!p-du*hI4YjXe&DcnLo}S+2eMD$Y(2!di$iD9e_Ic$; zTN^B}3e{?({B9wo5_Fd`y7pq@6GW4AaC2gOMA?=61{|xZqe->fQ1;Ev72g(AG>hcn zfMZ?m!sB#*D-3tGu8W8bPe(-iK9uh5DAGrpzv;%8)XNm#gY;;?Pv< zS+U1@@8TOAMvMB6ARWC8Z>i0&1_-OmADt9NZ?KSrA8hlSxEW|MUz3bC(qMFE zB`QW;|0%_$S)q!hC3I_G#!=^{#0=wD=8r6$QiqI!%O#u^U%2$;kn6zxnW|LOhisg4 z*KI?fF^6J{&&Cg2gqT)H(Pc4jbd~62c{~1o=FXDb zWvomy&3MJaoAeqtnlF%ky89gL%Z?sCGA_9MMp`5DwWDF)CB zJ{33zMGyZ+>wr)VS_{oswMtRqfakWgY~(+-eCaYTfSez?p){$XdZP!EcEWVE?Usq8 zw{w@W?phs@9G_GMJP)vcb@ow_2cnw76S3duaE4f+0G%d`fxAC_{e(bKyVpKIgZ<>F zBHioIpF_Coav(~RTf%DS!1bp4uM$VSE@2ZlpBqLB3mq8|yG-iPgxH!7Ue1FE zbtT4k-lbe)XO0mylc9RdsJXTZ{e%v@N-4z<0YzCozXFMeP4ihEDuUdLY1V@U zi3IY@H#)(BkUY#G5<17hg7%hLUm&1;>#w+lU0l}_1l55QIwW)QF}$rL)sj(U+`_CZ zmF<~8xIqpi0T*-|(>2(Cv55{a7fM6-%4IdpMkjoxs#H3=ZTokp$ljIkYuaJlInroB zZ8h7+d60US#muhuZ>|P|fx>2vQbBigDWcfZw(M_&>WDjnFMyyg!*Bx+X`a<7i6(0Q z8bh)w{w$g+b-xo#GUo(W2;xHNY4@EDg)IL%6!ZF$l2Ja8p<}Q3Q+Ts&%AI28j&V5q zX1V;mP%w~VoP65gX~MTJfs#r7OMsEPSstgJ$Dg3|aC{R-c5mh%K=^#<1# z`04J3irTQZY>HP#4NV^880ll%b-Hwn@ls~yKi!hpyvM3;cvGAHlOk^VIv2%NrSDR~ zx(8xoNU75(DX`=II(j+Pf79~7I@SO5fb#S>X#Hr}2dkTUmT-KaAhmzo-?(e62NDmw zjEV}1X1|wUGuDfR-a-d1s4DVL1isMt;9_NYE2AX`mIJKCjH_@VY3KgYuR%;>Y{ zmpmsgZN9|h(dPA=9`AD)AQmo|`kco3@3!_!a{K>25SczE2$}6T~T|@hsGj>vV4VtQObPf7)t#vhxHX zd2}4KH5n23%ja-T9^prbvpjIyxs4)fg2t{vmFD;X=X{yi3g@_*$iBqKNI6&aRWB*m zw&fGIrfi-(V(2-UEF+vt-6dg`;r@+!K6hu%#h?#5k>aX~(4M5H1+ZnO(?bra(})wT z<4&fth2pd9y%Q;N*fNQKQG*iZU=IBpv5?Aiyj+GL2F%4!KNnI+DaRRiJ6k{l5&u2f zEdNkHdaq?)>ScNJO1OQ?&A?0bOVBo+JTqppa9WhKlkQBP`2F=|_l6my}8rl%vu@Dzj%!?6ZdeFUNd`RZdMA611) z_rQynh49XKVV;sWYf>?#0Qfw_zx}Z`%i_Uptk;S5L3!f=!yuK{s`ZJM@6q7$^zkwG z!JD%qH!)m*A1#PiU%a99NWJ)krwC%k{miH)?NaYA zHOSEE=|r3^aQHvIGkt(gJ?{Fw-{((Do~Y47K5v*NDs_0gJjc)xbHVvL8HRKFuC1#? zQ6ZdzJTd!*Y@bp(+*-6K`DywCEmm@e{qpVD)$3^HsxWwp%xHXf{J=n9nV-(kDzqRq zWBXJWrRe^COv*oHheL|@Y+vdaejp-sP%yh)Se65MTP*2&I!@`opV9vq!`ZmsY%O)X zzTFsY+HicVFzt8f??XomqBIM`MY}v<-noNW36CG;@SF3uM^S$-Ws=nXwBT?L#&Kg( zFDhI0;O7l&=sUT72A-g8;?}#SkMW+-s1#h?Rw~anvD6NHxuEg5d0A@z-N6A#>e)fR z?>XxW*z*59PY12_b(I0he1@^f^!9&B=KseG|DP}N3?O5L@n1H&jzq&_-!-1pHX>T4 zPaO1xmtXE(Oy~;AA{?XSynbz#Ec|-!iLqTa85yt2!Oe>r(4Ou#9&hPF_ZR&SCRIFA ze=N0X==mAnlc4a_b9HR3!}T`iMWvu3=56%%YfVqL&fqP4{s)M-+@GN)Rj4aoA-_cz z%(`mGw^0J7{6F&kn*MC07`$1~*eKWTP8Y=H>E+{fXA78_c%?7?GHN@?-y;?$cy;=@ zyCz0yb(pVOwU6jE?qk9j68~XZQUy`wtiK{M0zS<)JdzDGWM97UO9Qc=^ae~arhx5} zx(`3VC|XXf_7#7a-XBGdU0M~jI6f(;Zv;o7G%p8U`s}Gz!GtMoAVsm|9o*TBd(she zOtssXYtYx7(5T~j4c1B7xdKgyEN5Ems=6jr|&s?i%(|} zrmnXS*RZC?a|l&L!_k`E6w#5y@Uj4%29!{)T; z4prOxN;a*N5K`TEaeJFKSAnbaTqzB17*1Q~`d#RqM`@2L}j+qJuA=_HZ}_Q11pCFcHI{AYIyz)Urd_%^-F_V z8|z6nWE`6X<2%ewg1Qlvv6#By@SVE$ z@8JiBPGILLB)-Sl|MC)yAL>z-ZV$tH08^J(C9`4iyUp$1$%l|pphkti!UO6 z?X00#63rYK@)cHTF|+gC34U|!onCGCVXf7f17N(pSBiGORKIH)M8E#fGgcFGaJrW& z>AUyfXlwE5cqSkv=4n*H_)#pI{U&FzQ!E_Y7}rAZG(BKj74o2J};-&IWv+)~p{AXY3lucA#o(PPiLbI_>$7tm9{GDa^T#8446m+nr4}vlB z2^`rLo?(3&)1@TnT&l9@LSA)v>DpVIak(e|mF_s4mN>%-(fi{x>Re^7yf9U&Z|7mQ`*BZb)Vd3B60qwK0YYtlUK==KdMA`UWf z-x~$L)KDojD0F2CboZQEIlI7I!d3K+Z57jK*qul&n|$s?{AxDTBCS6c!?!g5EiQ(K zZ$(lP&OugrXBW`^e4VhGQ0-Q`7SW1qv`#; zK4aoqQN$fNoy#0#9$z4Jr&Y%kw|cyIRI11(bi$S2+NG;}*C@-E`*FUXrsbO}v2$Nj zwMooAb?4TvKp8GwNVUk^4OY7UIL1rhn|PV1_Cd%+#x*EIU?83CUBits3+fh9VdVAX zH=JoMU29Y$bOoF?ob=C~v!t&2CzM)A6c~ZOhwnO~nbaIu-D|7@`{19+Bfbx(nx^ zYaC;xXmw@xer--sv)&>7EP83NsCB;I`Ri}T2O*l+MM(@P|EUu_ca3erMRHh>zY_N3 z-Q`i|@0KDIUg?5-2r#4nd%G-zol>#^A7T}%vM{Q=O2H?6f^ae&E-}7uPg}ZBc_0Fwrhl})Dglo*4f|ejnEy}@vwlD`#*Y&gZ`y~ z9$yr7e1!C^EKiMVaE{qX^b-Ws3eXpJ`>hK8e_vo6?)lJ`)K|vo+28P>tzBp=j*qA0 zy)197%K&wjXAPFHFJQ!7Z>Tai>{a7rlo0%AUT|X-ngT!5$!z(yb?~32*WBiWkUQ-J z8X#C*XixYDyVP_5Y2w)#WX)Ntg3;4EWSWL3Xv!?EftI-s6xe zdMB>w)4H^hCi?dW>lKpyy6!9C_`i06ZPfY#s1Nk_E>Hhbs@JuKlRe3^j3E52fCvzb zq%Mt5@vQZG^zlaO`ftiJe8W5?FBy!)=>3~-E~mDnHZ_>*D-`?J74LaD)JXpl2Rg4! zG~C)NM4=2YlGlc2Om5|szr09J&`W4A(Vw1^?f~*F2qbyE70ZO*Ao{;{WB=uf|8ITU z|4hj<3O-MGGC+?DwD+HL*ngV9`%634AJhxn_P+mN>DXgshUllW#hBudNp5>>2MGHxxg3LsNr5TD-mL!iGt+ zHaYnH3vImqyZE!d;YIHBXM0+tgy%(>kRJ(S25z`jUiZVX?}fl4gHG93>#`&Ucn=l7 z4I%AuRijJgW={}x@>UL{-v*J=Nw(6pxgQF;4t3)!sqhVVnv}i`fg^j@2R^;x{iw3q z=X}ik;hE$~9`O3+Ln2G^8dRHi2q_Itzd?#Bk-y%C*G=t zze7#W5pc^HAXDt{gCB}0R>D1BfRG)|!R!)g5rxU}1E*U&yn6{#L${4WQ(+Rr0$yKL z>cJ@;J9V7$i*@VS|#;+|Yj)XpjM(1WCP_3by?1l0A(3s0d)NPhGT<>+iHJgz=L{U?X z_jjvmN5Q$R%*u{#^F`gIh2M|Xe(GbTm0qnKCxKCCkRw8p=$3!WD*VtlwbPUU^e*Lx zgPj?L)xLkIQnsNkaZn!?bVwj6G;VECN(wy7h2^lLY8eC7sO0!i)bbUiN~6P>v9k-u zQ1*QOt0`LAiMo9Z;%eQ4akUMuuObJt9}L}{{rp1LP{yuBi#>Rj2JfP69BJGjgs9>PbH%oB7=WMV9z03g*vktzE_AA6o_71`L zXNTa+REEbQ$5;9+rKJi;6@TTw|LTYtH4@){@Gjr*Cf-`e7%ehtHf;3VU>Exwp)q39 z=XQ`q)!9?<#cIqQCdZevYP`49edEV%_mdJQwj&RInYCnhVk?t)Osn9J3`Ajd%LIY!itajR&K98_3r}a5=Z2Rj9nG zlO+FqNZ}^)E3#snIU?O?jlG&Shw!mSfaFBQp^wJ$?{aVFUZOJ}+~ygj3f4CxqaU=l z9FZRlGuY^bX9$HQLlG7UT^3K$QSRVf*C98p*kQ!yFm{mPaCKSokB zPO5Yu4PU?-xuaU~c%hK0_CD7`yN5$y$*NvA=Iio(IHE$O)}8TmNODEwfzCo%c(nN5 z+6)`vo-%@ps%HtB15tYpv_bXh;vJ%>WG%o$LQuz>7(Pj=FYr$L7Y|lHtx{?}(LuLN z?7@lO^Z10Pd}5y^HmDoPBdB`09s;M0wmJ^NA{9NI1 zv;lUZw$6(X-nrPB(@1QNG1GtUhEekT>?R+wzY^war2jiO3rFzN>#@GumX_f4P@sXD z6v^dv!ZX?*3um4U7=1Gc-nplr4e>Pj%&*Enb(*(!x2d8{rSv)C=hxsh1)XCj8J?5E z6kNP?TH$m*m0I#`%q&E=u&dFYcP^Dc%PlxN|RvD0Vg)Df^ z$VuTFoa%1*Pe*-|jvBxFOfR6bS$YIkXJ?tG``V- zO21;Ihgr?qE^|>wEZ82JAoS!5Kk#scXEW%AC%vbwq1P2gMFHh&$u5P1KDW&mh)~uz zZuI9OJclga`FW&>nlUNTQiObpEL}B>c@WeDz4V2FbLht9;?{)I|c zm`XLx{eA2N0CQoNds`>eKd5qQA#*3O0eExtLd0+k9pEr#fEV-9Ay^QC7M>#X>c*GY zS?8p^o*|TD-#hOKwqRGo?+c!)*@oDZJWu(l6V8`&k54X-gBsQ9rY7!TJsmaH)cJ8t ziLktER)p1|B@D#3Exd`Z0mR(=nXE!ajxPJq;uvt}?OF@K zmOYJ>5PcQd+xGj*<2YxZEZ({WP^ofyz@OfwY7sG!%B7yk8X>;F@} z$HRjzf?jjSuJw&(y&oAR0>5{DK}d?&g-xhz6%K>AWiP+M0XcK~d^`Y-YnDaaA^evy zGOJl+_08u1oVbus(+4l>LjIll1f0d}TcVYGHz>Yt!GafV{cdn860JkG^~^XSQJA^2 zj)T@icDUnd;}>rvuI;$Jxho&7MA`qCl~wseAVGIR@Yu52$4)6WaHLyT>4Qkn=s|6C z*Iu_4*2H#%(r>?q3Nzak>X|>JQ)j8=LyA7QMIhRq?P;be?`erPTpV?)|08QmYehhXH-%mbKqaJlG_B=AK z`{uy!0axw1NXhL|mRM2#nL19jEA#0}_&2{LQYmlW7*{s1HAk^B9E{iz%Fotj#?+dIUg2$7a#<`>R@BZqK%I+4v$Dol zjJpri2l`KJm4~utn@3sAOxrd}@0CTCaaTC>yxn@L+GFYsrPlFpk9)siOfqOeSc@06 z*;nxx?}`*VSy_etLW4&&^*(WZg{)PO+D^t|)&&d%(r9l`%8rC*T=wVo%(`5M5M1p3 zp8ohTFZtvy;|4J@@qYRm&7hXWCI3N!ed~>10pR}fS2{@+YNtVb!D_JZ%sdr)~CI-OdGd&S#^aY6jIjyGpbc z*9(!j5*3@lHyDKbgq+~dwxrkNQp|JY`1*HTaJD0Z-Ei8le&tNb-i}U8aVkw#nZ;s3 zxID@ZR>Rmrfl)dr+3H@t_Mli9i6h+mS@`P<1UL*q=2u#Zt%#A38ac{c`xL(k-W7Yn z!5bqJBKe_kfHj581T3qh7w5x};0vj}0h($b&j*yDfw=fN{rS`6M!5K=&o&9f9qMN` zj~X;xeQgtZKZe)l;BLM_NqmP@mv>X*nyoP7;tiU+hx!#X7(p@G@ zx`z0z9m@8>x@$#rh2q^IKrgVYY-+lRAY-qdB zR7P#6oW8PcI^*9XKd>GrznKX2r(PyEKS-I36{K!XGT%>)PrZ)}NfS-nE5CFca2)wL zA#Q7zayTc(Y4(S#@m-!dn$Uu&PuI5-r)F&fJ__}Bbhev$QmVd+FKe)p3lpK1x-_w? zp99fOkjM71uW8Xl0u^Z?8p%&q#?G=jbiD#cu;avGq3klW-mL4IRAqLe9}_bz!>%ZI zqN2)-Tk>Xh9x2IEM}|<#&-yI9M^O*4hbUIDYI}Y+&9qH7_#8dTMuWbP50z>o=FO76 zP9CB2{^D(>#oJ7s0c!5Lan$hxV6KjsdE}db&;dtBJnMR5pYAA;r@rnZf0>CfBp1!I z3c8?&Sr9fRhR<>4txS8bPTHO)$R&&)G4 z(rRGYV>IUQJj62TBYu(iTS@hd59-eA=UvbdUV{P$<_yPkA=78h)YFZoIyHeO_wL*} zUdoU_?na7p3pI5=#T?A;CGFpXEoh98)MMrseDIUpcfQC1{y^vusIyd>#L?X#qh0NZsUdI zPo>4jEi<>v>SPgqr$PQF%l;>=B3O71YmIx?_^nwUXr#|f^9Zr+Epo}5X3s@jCZ~bf zzky>R7}E0QLE~#xw5{3VvjyzbHOxXr%h2@L^`urrsVZV>L+CTzyn%U@9+^K27RFJO zQw3XPaXD&m?oqBOil^K)QqShtaTwieunfW-_e=Tgoah3_KMjf@FDnrb?YJJ%&CV>Y z@t+E91qk0+cgH!Tnfb)yZnE?YRkoKrdPZ;Tpt}~XY*hYB4=z~(_EuYH|2F!&y6)zw z&gg32+ut!34K`sJ8xXrmK{$hK|M~#Z|3G)Q|Libs2SvSU<%?P{zV5_wr{VsX$_Rt- z+k?LP2WHz)gxpu9qoOY^S|l3FdbRrdL5Y;U{YQE24lPf}*-3JA?_P0cC+fKz% zrFs>mWj&007?jl3sZNz!V8EnJ!rG&0_}%3u^=E09;Y)mb(Ofa_x5?A)b*XG5GktK= zbe~i8GRcK>$pJf}=HC;IgUNSwb1N?QJ{mI`N#lY?@szh`7Js%Jgao%qPZ8{S=Rf5_ zmK70!F<*bZbmynI+wrQnrkvwD1?Hgj?D(_*e!ImXSG#s4ZXAnT$XdG$ z&+k#)_~oFK{xS>qDL1dC_7>ZtT8+f1pnS4<<(m4#VephH-R25&8<&Sh>DqW(*h7iM zYzv{Unp3Zyjni_nB!93C^UcB~-b!Za;ffIfWK)yU(J-|)Y}x;8lIheT3O8K%7>`B{y%gQm z*x7&Ve2>Oz*-_<*E|#J|+$FaqJbfzY>Rx$8XT@DL?*{!AA+7p*ven+hvl0Lt@2Jo4 zAj;4}ZBx1S7GGujvj5P=?gQ=tO+%p;YTo_ilZNMyP~o@<(JV-Y0eYIh0Mg_2*{~zV zyNjPRb=|rY_8$JZ;G(h|o6iXNvspUzxR{YUsff3~5$0fd10{>7LKr0WRUq1kxW~zK zAxRJPO?XDYv3jNNf?5k4zu-%y5#{wIxZHx^#*&XBIJNAn<6q=(S`-v`7>5=U3J{G` z+2LN&HGT#7B6CAYsAjT~i7*nEOCoiAWrw#)1SPA0l8viI(AIU>XW-&39t?mDep(5-|PJjY|w!-P$l@!-_7GPNfL-z(eNDJ3hk{>dy2}CTFF?r6+k}?Y_sKaTU+k; zTSg(`E82+YTP3nPm*J{Xp~lO26Fa??efvS=%K+dFrdY1Od%uj26UL!`Up5GUW6$-LKv07k|`406V`aY zkYV}};uOj}JjK5GRJw2;!gnw9+MFk36!~~P_3oqaW1##kD>)N>c(vXjW9wy?+ix@V zKIlW|EJ(JYU>+p>k}Lmx5#x)on@C5G{86&#A5~Mly*e1Pv*TmRvqPt|!=STrtDV|m ztobIz)+GACxx-BmTD#`)?Ld|^UM0;_aA$t zSf-buZoyto`Nm74R_PI168(|W=v*GnN1x-Q5|rCOZmR9rMekxdP4A>O1X+5-npD3R z>A1y!9-{m1D;p~E2}qb%FM1U!^2SF7;Z^x`QNG$zYu|WuWti1PwtT!x5b(tO^k|NB zmDs7FEGGj1!pN!(U*(>!TJycHbmpnU;#ACjC#rf@;g0Uo*%qAY2mLsw@z(O-(Q@D3oVFtUlj7s@fZXjq%Yh5d>Bk5;je(Vq;J~BvcgQ_AI!Ii ztPGbB7kOYey>(WgUrpyNA}xV@;Vn?qyCtZdFqn(nA(=b|qqPKz3$Km}=NGpzV)Q9T z-QST zJjb2|O?ZpbBhBnx$&-2-j3b40S`wa(A&*Chn@Ti+E=8hq8bl{|-E;&JP;=$HtdcT9 zj6To#FhaLQ1h@9K5~tZuMqOh>&A+zJBGyZj1rD-Z1u}nHfUe?$QRG+tpxwSKsJGHT zv4qD;IMKh4fvji0$G5kD<;{sA_Ihb6cKi6&K8nwBmT0H+!lAv1QU91P%(%v+u+qfR}cNU2#cjCe-}-T_4pY7)b*zXde|?_iR5#g8zx>C%U+8 zcy*~?%_K>C5N>}9z8pAY@>-SrVe{CDs3{`lVCW~z{-^KJ-SG?_eMUv>~e#4ol#VrnoXZMG|Obs~sX?RWrzw%6i@@f|Uf1>+ypsdSmeW&Z&AMkl&(6)$2PFQdw@7hZ+mK0X0VvttaS zZL&_Z9rNtsIi5UP?c)mHhVOl*w9N&w$%xA zZe*-pQHI&Nel<0lS@dE9PDOwB39=!f$Rl-GUtPR1OU0C$V(D39GGoE70-rro z46R_<(j}~cXn>1)-w0arJPl|)gGX&Rz_fBv??vGNu7 z(alodk$6iI9i9VY4>Z}1S%<)aIC5FB`QLO+5vBAJ-KPGDSNuRe7+vBj^WvkGbHv7{ zq8>4TloPRSu|RK1{)9A87nO@`tzmhqwk73nHd6kja*@FItb9lAIJUI)wgkZ)bwp(C zO1N;2NEiL&h)4!JpWJr1ukKRY)S+w~x46^6_t)bZ9cf!+%Q=yf_JyjhxAirVC85=&V3k<|FxpyH!@4Y>8YjMWWDZzY*g%DgNWmKeGdW0*n`I>|zR zeXU@(eL2JI73NZnGf5h0Tplh!jO#n+kHo21E;XCh_7F<-ww7iQN~**j@9Hjx$FDl2 zv=L=5FvHG`4Y;tf$#uUn5=zrOSsx6;Ca!ECS?;D<(W$W2JTL)Ad0b&>*xa|&5k)E5 z&)hz3%{~tmVvI*{SYkXhBpZ5jh5yD`#nR1@l|;p2)C>Dm+(0GvwEhsK`KajEHNP_A zzxcK%M4r-Qo7iQ9U!fxLERAqLnMYR2A(T0JenlH7zCRcMwhS2?-=u7oUIccz(u700cAR_kO3T>E71KSx)+ggNdyJTPVuBj1Gaj&_@%6O_8^}+Y zqX&?s`zfYgPxRiklHHAQBi}zpK95u4d1=?i#ptq1WT>EM9$sQ~Uynd%U3xL=?Ws?}Bw-AWq+Hl0I4&b#_10>(BovxzX z;)}gyWT<&z%j9_*4_?IBzcok^kG|*m%j@@pCkS5n1kpio1CGR^*Z4KJu z0jlcM$|1e)1;w?5>DlFX#kCJy2=K--9FN#W*tIFd5vn+f64=U@mTXddKA2goqje5W zbjyD1_UNPCPZ5^R>+HPOMTQt|*8vqoY0cp^!1l6m*Y{DaW4<4dsQHd^jD;Sb2`#0k zE!%S)(!6N+@j2TAa)aIxYXT5*y17{ia3CJs^qz!3#V6I?@7(tOj&-rrTu1PGOpi>J z#uxO@jEqUJRNTZVom18#|H(GBH0W3nfwLeqAbdCsax#Fa_5I%j-aZ#oG9;gth|8jU!;M9z|W8L<2B0=IL9^A_tD$p(e!|>NR`4tCFr^f%li^td2ZKiBmOA z8*q0v-)f#O0}~#)iNvIARDQLBV#8NWFkLgg5sj|aMGdzAy*MNfr+LJZp7SzvA&A>G zTGw`!P$UKU+*z}Jo8XlKX9?Jo*p7j??X&|MQT&tGEbp(0$EEx`-&xo8J#76c+Yn>e z237j9g#Yz@28@+4CiZWHrxD;xGni$;DKr!6b2H=|H|?R3+D&68&kIvF3cf}Bb?w<0 z7)Z?_Bjvs{dyhPV&Mk2kRZhH*!gqXSIIg@l^*^+;RGgL_Q{Mprj-RvbOA2K55i#|= z1OTC}H@=v->)3?#%_Gi@yyOt-j{+GVOzN&UbxC5n#uA5*02|vBTwcU}Tob{TclWN(ks4To>R>16e==fep|%x_`Re|U z>jTKwj>E_(UkqHlc3YT*p-UQwS%9rk>*co?6pv~Zi58>Ko&h(a>@e+*a33$D{qBpr zj5vcfOe_tD7T1R4i1E?PcZW_u*v^fw;dboGea@k80)J+b*)Sm)6yUg1|M@-6u+)#H z3LF0LfH2l?u#TN-MZP~XQ>m$5KObq28B zHeiPRgU)~I4EXZmkrPv$`%|k3OP`#iq300>iwhYMcxU0Aa_H`#z5Aiq;n&R`5Oh8P z^2PZC+nQ~zUfG8Oo{ihf`eAhmiBEs*OQd?FXxsnMS*=In_NV}s6$oRd2s+q&cSjx4 zGC&n|@FJL|8PPsIdYY-Ja0b(g7=D&`C?v#OQkFiJ<4!~$fqzyQt8Enxe;J10`qhR}&mO>(N z^vh|2H@RI^DxZy^G9fP_aF^7|U2jL4nj*HTeJ~_VW0)Cf1nuMc2&JtMCazb5V4)kO zV3C_tGX1IIB`S!~)IK1V9ssPX+M35O=wqZj6mOT?fr?rQ6}p3QMDV$czoo=%0vOis z?YW9K?i4|ikW+AzGJ86fYo)zS%+Fds5lgqHn*_ZwYF?q>t~O%-ZbWY0x-_{;Q4HZ$ zpsG7WC8hpRHl!2V_cRBg_DM5QD7`K-<_RPJqa0NoWvT&w8p}L5$2mSas^$Fr*=215 zmXpUBH4k5009HN;)FT9VwQC*D9_A&oiG5YiBdPPmrEeOqyER#3U(1F0yvTmKT6e8r z5FP~$qXu{NEw3zgo6!RiPkwCbO|ka{Q^eK3CMUO3OVs_Pi0S&kv)FK3!&PpO`~2yt zrV+cvy3r#pf>~iH;l{Htx@04k7prMHO zGwKewhS zztQfoS3r;zk!l_TH{jg+(8w4l-Z$DN0>-iQfu$pPCy*y9o;P(;ooqWP3?Hbk;Y6>y z`>%aS&Vg_P`@p+M8Y7gJKliEH(hJq9%o&+*Yw1D1{HZv%lDwKAbiT{RW7e_1{N<=i zzpf4y07U*FVRy)UH}HII;Z26&73tA2usgR-XwbxS-WPL=w4pa|yL2h2<<_qD(U$Q3 z*2sBRd~~&%z>xgmu(qH~gQ#cGuo!0Gzu|)K{#*7vq^` zgGtz(ep7sO*%#9Z^h&dOHeE}cr!%wXVyVih{UlcUo(Aj*T8O36P+XfLQV1*1{@23^ zgt+{yn?-0Ku>$y+#}=9Pp(EYKAkF5;JZ^NFlZg$pHX?=6D9gwiH#nFg{kV zVID4qrM3nzS4{B{@Fms`fBr9q>5zr{XhZQoQbs~@x_aHr34XlZ9Wm8w;UcDc`~x(_ zh3t%Z02ly1ClBq2sio4fI9XvWk4q%Mj5`vhxO6o|i1Ev1oy#ygsh*@_@8PI`AxZwr zrh5g4sJ&NV-Jw9;E=@|Q$r6uz0faO6TXk4SyJWzgeHD!d2m-Tyk=$?{@O4h5#B4Jc zr}<2Z)>R;f`T^Y!ldtNYgARjYj>_M9=#h!6jy6x1CSn+2)=ACYH%2OMc%dd|Bz}p` zm4*Va=cr@#Dqv8IE1X=~f?_d54Y;@+IQ~^w-_>&Yoh9KdcM@BNO^Fr*sFvd@Q!bXx zf;M0;VhuYL+GYT$KPr_)&_hcc)f0g7X?r$o`!V1MK+9;(%k>YDI$QbGE?i%q-{^$W zD1cJEnb>tdp0ncSxXwFz9;yAIIftl8 z>Z=&f9LUCmU#_X?UP|-Pt8)!Gnj&bgYs>z$idZ};R5(I4mW`S&xv!&<9+o0K0LSSW z-#lD20ghP0_9M93`mD*#kI~?hTm12AQ%DZ zvdEU^z3kjqDU46Pol^ngJw?o%w|gM?xJ2H`R~XOy;@TL|%zj70`VewwVs>N<<8$BY zA1$)-FFgif4J-Gp=DB`1`(VDl@L5LU3R5`&s`{gc8+8<>d-Fb+b_fOYsyt&>dZp#H zsm?sl#k>Zb4nZ9FL{kuZwX2}md(Ujb6UYIb2dMMLk=6q@#d>nv*<)lUpp)0Q7se~M z6##4mG>zu@Q2__t14!!dhEA{F0BhgOj>Hzb6^fm$@E}diD;SqsK;T_|Xo_IUE6pa5 zp){!?@sx`bf9%Z}qfg|6sn(P@y8W2sZ&ljm1{`oCRN5QB>^AtnO1!_D-`~f(D^RLP z=f%g7cKfJp&*~ey)TDJ=$X67WVB8nkhAFVMOMYGtHlK5wGpavXd z6DY^>TVo6T#kvmq2c=$z9>s%EEIJtqSSwNE)-mIF#|aj|0gxVBaFG!+_$Vboz<+tO zfVpFR0Ic3}K#bYMVR>U|{t$Tspkj>>xl>Jm`yX=+JObKCk=dEtS%>ruI1NPhSO(B0 zbZ@|AKUQ7sivhlxf)sSbFf5wXyafagH8lSQJ>O(AAU?q3hmhPyD5zkbbEj})}cN|?PK*o+^YlPUdp*BbrvTNd@xLSKs`aYD*#~t&IssQELKLgo<}Q) zDZ&_RQho}c&Rf&^8IapuHdR9tC%}S$s?AIkEbfEBFJh;(gVaZ-TgHGh89EaE`So9; zey(Co$TDL|zV|bub2{g9ey`u>bN=Zip8a{h@B6y1>$=}h zIENbG7Gw(jOAENa_`zmhC8D9JzNr&b>Cb3Ek009i!~gs_(t12niqb3vu~a_&ZIqW8 zeZp%3$<4t)MxD8OdR`eQlu0G)jv7c~YK*}Mq}KFLJFZ`_cAq+z?yd?XdS{nE_YnQ3K);9y4nMd{hC$Dw9?9ZsArhNCsal#MSo*9mRwD^nQ>(+Ywtf0gmc zsSKWo5tgl6`JI1;FgzX!wo#S)Q2)X6(+WcuaA=@RIu#xoJ|f8fVE>8i&p{YfcNq&T$*$R}-jM+s%IM01rd^vxm~2n-UY_N&7jO8s&A@AT@g(j!MCZ`%v(nVe~4!Z$pOB zGSBYETNcHw!OO8GbH9-2BJ{es84_J?*AA+`1O%DLt0SKrN{F-1HQ2@52c$_6Y34T@ zuNE}Li(FQR7yB-1`(+83a3B!4@CoQ*SR)uA@X*^ysN~bp%i?r$_;5|>}-BVA9AMqtO4&9A?Y}AA*V#rRM zXCqe?Bed!jjNRX`1lMhzoA9KR4LzeL|t^BmJ^WY5e6EFo9&57sw2{i_jFcCyz2@RvnLzNcDg6#r#Y-W9|G{3t8839M8;~@XOKp zt(0+iip0hpZZ9N|T6SGgn`#*_^kpb^Dx2v`onj%cNwhJE+`E z3Vf{rBo2O5=%aU1dJ{*~3PKN31Rs}1ZWR)za>DXuQf@FL{5n--0fj-sO#=^H-6*xX zYJ!0njs+<(3mrI3lG?hnXFp-BDT|n}E2hIp0txU!OPMnNx4o zF27!frz({)Y$$ho?0XLofbSvlYH3z{$&-(o5s>bt1B|pTsNMRlR`A4)$!GP{vEDGi zRjmp^-W#=WR2wWo3l=2f(d!|~;_QRElHhWIq$%8d7@#{#h9}sb&kky5<*u0}vGdQfA3c~X&N-#LFx33S>v$-I z07WCEW5R3t3cnVN?FaE9Pq}Fs#%z@k1~S)!KM-hP3I~Cn8||3dGh>V;816_&JXm58 z<3X;PsG5m{|a#y>S|-R zPqtF#Sx2f=%m#>0#L~wu!vjx3FN4u5fK)#)dKuCRtgF+tQj3u+F^97k0Z==8>J%bvO4QE%ggx4yjQ$#rq?sS~H{c6k*{h@yP!?YNlaCqX&L93} zc^?Y8Y{C*UIN|UsvTwP8FJ)HDdbvXA(`iy=mG27CQbx6c?*_;p1KX!aLIr@nwNu8g z&>Q-J3hmXp8ZtTf)8E^L31}=kx$fM$OAJx+7``ThPbSPq@xx1vIv_pHPLV_#fpfOS zeZrC4<*KldUBn z6+@^Xh@p<9qRHd4KsJ8E0Jj@2VNY z6z;yjG|@xl3*Y1V&~RmeAw?omq?YN_MkH*a;nYH-c(NEpTI9q&Y#kXT&oFy1X!v4E zd7Mt~L@mP-e1~uOQVb4_2i)*%imDXekap-hu9S$bCS(=>DSnxTC^2gA2>?A zKNdh#pJ$ZFUmu`$CAlQAc|W4D3sSPL;UCKTmvxbj!ILfb>5sUA5d09hRzM8lk!M^& zN(ny_GPRs8UUbd>2}w}Pt9+LrhKwI@atb=u8vZLG+Z7n>3WIidkq<}8Lbh&Y(OiJ9 zsmtLVns|q+YS(J?a`>uZsD$4cQF#A%oEeKMD4Ao05T^b~yT##dWIA4eTq^qcdmK?E zV?+fHhl{W!jXM+VhZ=TQWu<8tB*2AV{nind?z`>!hB@OYrG{^j(S_%MZZT(dor(0i zS0?mBvQ`)jOKAZ|MYHI>-6V?ogR#Q(1mHYyuXBk-IrD3{Y5+&*-GAV2v@e=)>HPCm z_U}I&rsz6nqHi5dd}Dq7;u9_0j)CdwK)(7YWxN81Bvmh6g+vmwpRB z+0{_8^>jzx%bm`T#*)jj8P7NP-sYzY-M`q+)QVZnyC>DMrQJAnxl_UJuRVb=;o6rD zOJX^+k}>vEj6!p9lO<^f}I7q~rK!kQfeDa!}^b*+fZmaQ*h<5MxMRs}VuUb~2vz^RbOBd^jyUqU$ ztfEFITD}zYtV{EaTY%kjh((27 zGo+LZVYDe$T&)##M>lA-VCQp13DWBPJuS4HXx_~6&t}C5!PmOuI}=u3*0y;9C((C~ zIpp16y)N15zaSKmJ_}4&yBJ%g^?}cRP0XT9yOF92&>QgmghKE(_raBzFS!(WU ze6yTo$NFA#%JI~s&q2u@7vdAYr6(|O(;Z>PFld_p;M%T4`t zpmk-O-{Nvh@~y}2Z;W!*LyD0mg@$ps6FMWA@12n9^it0GvkAl<(OB7>k_1bs#aQ+h zAIhwngDthwyZG$7a(MP;QpWUesE9KOqFx)#`xn=Bm^N(b9w$^_Zs4CMzV}K(4+}Rj zw;frc@_jJML0-HX-e&5_s{4Nl>swi0r^pKy zoi|I98vLF4u{B~hKj!FeG>c%3mlvQ9&aBDFWBRy07z{%$6Lgj~W$G+sL&z{E`JdGd z-i;3X5dU3k+b$6qqTQtdq66iR!pOq-Of5D|%3V@!#=sGm2$v2<{nL09%@9Z@nQ#Zkf`6qv`h#b^h|PpZoYpDy_)gf4`^L z&?tf2(59Sit488+`;4kyGMYB)1@B~xl{+fAcqlR+muL*uFW(VMU)Q;cmy>$?T0pGI zDNclYshc8|jo6>4)l{~(9?Hauc=w^3>*_`w*QcVl3DvLZ^T_Pzj=Q|!wI;=Lpd1zj zqkVf%{YryMI9A;J21f|!x+N2R)$Cr*IxU&HnPy!(>xM7~=3|YRbIdnSe%&UdP6I9` zcG&(a9#g>uG_j%%B=^03-{WQhd7WLSC;+R%3M`64HK35dAGBafFVM%nf<1wM4!(gYs{irb;jjL(nQvebr9WS8y2if2@F;pF^asu!N6aeiJ+F}p;boxI2sJ=V|cDV+! zMg`egPq1kCOU1e;9<|-R55UyPq#~wHlT+4@+q;?h@)OFXjI6OU5-~&{VPvp%84=7} z9}tVeKUkP}6f=(H*!K*XaL_Qvc*XtwH!mDQ&VT=joF6guxY2-ALjODIiU9L?*BM!a z_@L)2c_iNa3!iod;X3NXd4|`sHR!vlIDQx_-8C8~u3JM5A~=+b!2PVQ>Tci7Tp3lF z;+aqWu~(X*+dW2cTFflE^zBl~gqKC{_M`B)`nk_H5XT z{XOcVVHarHD5p*vDTDB^aCgW2BCO!DxIa4xA=%KRc2x`$tDthA&O8(7 zlv*%)3MeSkmZW*3Qb`XE#_2m*f$^nFdGf|$5YKJRb+IOnxSA+UYh{BJKGIp}dpKVP z5>AopoGK6VFLavu!@GW$58f`W3vqo$bBXn;ykd_fv`)!*ucW10=m*PrtBW2YQE43k zuF2@nhDGqNii-vW>QNB%KuKlh9vuu3&d-u!61jn|P65*76-uA|X-pDyw#4^@1 zqp9eT{|nUm2LNS>M(q%^j?6ihXq!!(o!UeC)lISBOBdN%tUk;*bG-eoCgs#U&;8L_ zbpoB>yHkP~^S9e(zY359K=}0e=2wclh@lYs|1p~Dgkq3XF%#mhqsW=(WM@R01n0m1eO9c@vNQvHNrJm z{AJZ$&9u{N9&b0dp;$FN^W;UO-Ga zw~kiwlPdYXNJi1k3`wrLCo(uw4@cQkPuAS@aJeX{av@_}o=HLr`ui0yG8dOJx&@Fa z{exim?=1?w5H}juSlcMkfZjUT_-&`wH_2;TfCal3AoO8USUKd?tO`)g%h#xX(OeI+ zw?n^Zxt%7@Yo%|A5DN_^>W%s;17C%M1Zuoy$k57&@%<>4U=Ud^FFeZ!#970WH_6_a z@bWHCc=1>H5BrXSJE&CoIjTq-V2JtAiS$PlIX$X#ik>R=HNL*viT|z(u!$(WOnMQXu zfV2TC>+_?Z0nIntY%=>vkhzRIj4bz>mT4YgW)~;ok*LZqcQ)bH7D|xlrA%L_MN-n) z+3P#`xsL7em13NH0m7F!H(%_2AD=43%h`~;>be>eK>^^rp3Bd6Y>G#?y2sb1Jv25z zBUH4O_yi1|a17C~)H4yRe!$dI=ZsryPd-BvCh-z016K>ccDWV@A+fPj$bJbT1`Aeb z%O=TLm*1)!t=tm^=-*dV6IQ5|GBT=)evtsBZ(_ozr1IH9ffH;WeeRLziF?7VQQ2sT z^npmYgp;qvGb`>8y>km*K-!KQq$PRs{&#xJIxl&! z=g$#IIeZ~=hsI@1^|$OmH~0VnP$%5+cu89002SHphh^-)7hQsZoZY-!x4^L(L^8sC zUN==4A4=c@Cf%^>sCftEN<9ym8qG#81J`et^}MB{Sx7x01>XQr8NjPRh6r~nm3?{* z%s?A_C|x5jVO-xEH4AHrC$Dz*t5Jh$#J-i0ren=7N^h=mW1efqZHK5bS>E)0WdIqE`Doxe*;RQv7ia{)uq&mpfN+rO?e+w>Amm@vA%f+aWy!inCM<5r|AG|b^A@=^$=0k%%}oTRSDh{5^N%i&#B zhmbHU*|IY@2^|GuvU7Uw6bny&rwl|Pb(R#O@|OQe(Tb0A!4fOCGRMw5B+lwrwnL(G z_!e1mbHXH3vMNdw)D_BjYd?SAe!{^(uQqW>jaia;i4rh{0384H+Y7gUY|OwMiUh7O ze~(H3`}=2}p<9P(v<4O4DC@z76)5DISlC{0AmsW|7EJZ5P#GaT4~u&NQdoj?3iPk# z4bwLGgQRkFDD2HAk3xpWI6i#F4Pf%CAeeUi`cCw$3fT|#ZGH3&C3fF{@{D{nyuC`j zOs=g(;83iZLVBZ{KLI5EJE3-Ub_Os&j1Z<7(t{KzpFd{<*{^st$qrjY1p#s(czAb} zWYDyR!AX|swq$iFeO{Bd#OtfD?3rP_aJvs>siqE?5->g#Z_%hccc$j3l0Y~3Bhs#; z0Y8l2qi0wBB@cMp9l-qDUQ<$3rQPmwQ7njrI_4{*yFs;q!!-U}*f*gLZB)p%%6EHz ztMZ{ar>~paZnJ#30Src-$hoKX0^8UvyojTMD|Yg_AOP-P05h0B_`S)t#$aWntUnPV z*Kad=_CK@0HG2b%&YLhluiNO8PkJKc>&L}iJ5k(bnumD!i02wp|OFYbKBa6kIo$74HXf5r0lD8vHpYA@+e(;`*Vn7r))=A-dFu zGI`vE>c-YdJHE&6#+pN3TTYo?mqC25lqEoz5L9$yj^kH zV1!dkeET%1{Y{F!16|k6pO6MT=w*DdTkE`ET3jz}nV|$M?T8vwBK&#iwb-vBV>#Oq<)2B&g*S^MA z+#-65OW_MLr=bgqvR=eaw!-Bv?OqwudO8kupW?$!{!~b+$tA&S>O*fMi1~2UaOG>9 z7dR-Wba}}@>q~C&!KNCv1TDjNyCXr;&tF2>@m&6c(9u+;STV+XhWA)`nsD>(L7jqp*Wp|HXv~>KhC~;44UKb&p>m$ z;C#I6D=$vq=l!L62Loq+PgBQ5!2FTRCPZzAMi0LBc#-c{p#X|FLK=gB9r6!F0s0$H z%`*CbRs?-1NJW6gAC5Uk96isb(>EM@0+u#*FTHbgbAJ5;7EzLcuiF99E{1BR4@v^O8=?5_fuFZ$Z#FtqUb z*(z+FTkW8mZEHlWIKtM5FH$VR9gaQcO|yT-#w!#a!>855Bmi^i`iTs5hIICUNy)tN zIm=2;B`|O_Qr`i-oMVv-ihSdGi_R4E=Y#Dn1!KQs*=E*`@9G$R+`8yTHPFcp5LE60 z+g+sj+eeH~IqBYe^!-^4M+h&1^3th;PkkxVUN1Dx+3o|>>IU6~^A*PJq^FAfla{P0 zQuqoMGzQk5x^(YMd{@*kjVGmk6=}lKc@#Q5xDO2I;guJD!4ec;V)E;ME+m+r*12~2 z0tQL;@)j^%Pb3@@X>$#Z-8<%aKX3TS(SvxyD8aP5*dP?CCH7omso|M8BKj~gqe~Fd zS{Af;?{1)cVaUiWqkkmFr&~4luT3vFep0sW>^i%v!DIAUKBnORES#s^|5G^seLtaN z8Tc^&7yN%9@Did;h1q{{+vm+Yf@1!EOfH~c%Y@c*%qK3J5qq1gPf}L&ZOdOf69GvZ z{-)v3`}L4T_O3BcsYJ!+@5sIZcM3tiDdCW-e+cF+WNQ;HX;fUj>-S5ow6L#ug(!t` zFwZ#W6$c?!<{Y;rJ#Li3LZUZs+m=wHecO+u*w|N289we5$~{EznI^@_aW0_GhoZBI ztD564QO7-9^#Om=qhD+O_GBZ;iS&+KVgaA>@&OMFhYAMSw|MoVclMTVz4!i6FKqjT zlsoGg1wln(uKAJ<3t(KKFQF6)8x!7Fo2kO; zhze37up(u-$W?~ba#$-OGHLywpod^nyiCtgLQ~_CXdaTg)%YAG|mB10d9M&RTyO)r4eHF6ar@8D0Wbsd-|9U~N6>`YuY20@p z|BiE3@Ab#$z*Q`Iu!3&$Fmc(UQCJam(M92$hyeJGN4JKJ6#ty;qAR?}_9}|;vJ>!` z3aQiTmV>aes>Z30aPr-EwU_+ui*P^wTVB&Qzl2>7o?rXEffs%$jnlEf9dNTfjXUq+ zywUW$lkFl?yzNFM#f^HWoi{2gDywW%+^w#tq`pgaqk)NO`m-DGm7YbC$X+(5aklDb zkzH*UAsfmmD#5;`?r<_&XZLe1IOftaE!b$0u8!fsto^61{U6i~X4U`z literal 0 HcmV?d00001 diff --git a/doc/develop/trace.rst b/doc/develop/trace.rst index 5c7802da51a..8425d843e9c 100644 --- a/doc/develop/trace.rst +++ b/doc/develop/trace.rst @@ -15,12 +15,16 @@ Overview The trace feature uses GCC's instrument-functions feature to trace all function entry/exit points. These are then recorded in a memory buffer. The memory buffer can be saved to the host over a network link using -tftpput or by writing to an attached memory device such as MMC. +tftpput or by writing to an attached storage device such as MMC. On the host, the file is first converted with a tool called 'proftool', which extracts useful information from it. The resulting trace output resembles that emitted by Linux's ftrace feature, so can be visually -displayed by pytimechart. +displayed by kernelshark (see kernelshark_) and used with +'trace-cmd report' (see trace_cmd_). + +It is also possible to produce a flame graph for use with flamegraph.pl +(see flamegraph_pl_). Quick-start using Sandbox @@ -30,7 +34,7 @@ Sandbox is a build of U-Boot that can run under Linux so it is a convenient way of trying out tracing before you use it on your actual board. To do this, follow these steps: -Add the following to config/sandbox_defconfig +Add the following to `config/sandbox_defconfig`: .. code-block:: c @@ -75,7 +79,7 @@ a trace: 16 maximum observed call depth 15 call depth limit 1,275,767 calls not traced due to depth - =>trace calls 0 e00000 + =>trace calls 1000000 e00000 Call list dumped to 00000000, size 0xae0a40 =>print baudrate=115200 @@ -87,7 +91,7 @@ a trace: stdout=serial Environment size: 117/8188 bytes - =>host save host 0 trace 0 ${profoffset} + =>host save hostfs - 1000000 trace ${profoffset} 11405888 bytes written in 10 ms (1.1 GiB/s) =>reset @@ -96,18 +100,107 @@ Then run proftool to convert the trace information to ftrace format .. code-block:: console - $ ./sandbox/tools/proftool -m sandbox/System.map -p trace dump-ftrace >trace.txt + $ ./sandbox/tools/proftool -m sandbox/System.map -t trace dump-ftrace >trace.dat -Finally run pytimechart to display it +Finally run kernelshark to display it (note it only works with `.dat` files!): .. code-block:: console - $ pytimechart trace.txt + $ kernelshark trace.dat -Using this tool you can zoom and pan across the trace, with the function -calls on the left and little marks representing the start and end of each +Using this tool you can view the trace records and see the timestamp for each function. +.. image:: pics/kernelshark.png + :width: 800 + :alt: Kernelshark showing function-trace records + + +To see the records on the console, use trace-cmd: + +.. code-block:: console + + $ trace-cmd report trace.dat | less + cpus=1 + u-boot-1 [000] 3.116364: function: initf_malloc + u-boot-1 [000] 3.116375: function: initf_malloc + u-boot-1 [000] 3.116386: function: initf_bootstage + u-boot-1 [000] 3.116396: function: bootstage_init + u-boot-1 [000] 3.116408: function: malloc + u-boot-1 [000] 3.116418: function: malloc_simple + u-boot-1 [000] 3.116429: function: alloc_simple + u-boot-1 [000] 3.116441: function: alloc_simple + u-boot-1 [000] 3.116449: function: malloc_simple + u-boot-1 [000] 3.116457: function: malloc + +Note that `pytimechart` is obsolete so cannot be used anymore. + +There is a -f option available to select a function graph: + +.. code-block:: console + + $ ./sandbox/tools/proftool -m sandbox/System.map -t trace -f funcgraph dump-ftrace >trace.dat + +Again, you can use kernelshark or trace-cmd to look at the output. In this case +you will see the time taken by each function shown against its exit record. + +.. image:: pics/kernelshark_fg.png + :width: 800 + :alt: Kernelshark showing function-graph records + +.. code-block:: console + + $ trace-cmd report trace.dat | less + cpus=1 + u-boot-1 [000] 3.116364: funcgraph_entry: 0.011 us | initf_malloc(); + u-boot-1 [000] 3.116386: funcgraph_entry: | initf_bootstage() { + u-boot-1 [000] 3.116396: funcgraph_entry: | bootstage_init() { + u-boot-1 [000] 3.116408: funcgraph_entry: | malloc() { + u-boot-1 [000] 3.116418: funcgraph_entry: | malloc_simple() { + u-boot-1 [000] 3.116429: funcgraph_entry: 0.012 us | alloc_simple(); + u-boot-1 [000] 3.116449: funcgraph_exit: 0.031 us | } + u-boot-1 [000] 3.116457: funcgraph_exit: 0.049 us | } + u-boot-1 [000] 3.116466: funcgraph_entry: 0.063 us | memset(); + u-boot-1 [000] 3.116539: funcgraph_exit: 0.143 us | } + +Flame graph +----------- + +Some simple flame graph options are available as well, using the dump-flamegraph +command: + +.. code-block:: console + + $ ./sandbox/tools/proftool -m sandbox/System.map -t trace dump-flamegraph >trace.fg + $ flamegraph.pl trace.fg >trace.svg + +You can load the .svg file into a viewer. If you use Chrome (and some other +programs) you can click around and zoom in and out. + +.. image:: pics/flamegraph.png + :width: 800 + :alt: Chrome showing the flamegraph.pl output + +.. image:: pics/flamegraph_zoom.png + :width: 800 + :alt: Chrome showing zooming into the flamegraph.pl output + + +A timing variant is also available, which gives an idea of how much time is +spend in each call stack: + +.. code-block:: console + + $ ./sandbox/tools/proftool -m sandbox/System.map -t trace dump-flamegraph -f timing >trace.fg + $ flamegraph.pl trace.fg >trace.svg + +Note that trace collection does slow down execution so the timings will be +inflated. They should be used to guide optimisation. For accurate boot timings, +use bootstage. + +.. image:: pics/flamegraph_timing.png + :width: 800 + :alt: Chrome showing flamegraph.pl output with timing CONFIG Options -------------- @@ -138,6 +231,11 @@ CONFIG_TRACE_EARLY_SIZE CONFIG_TRACE_EARLY_ADDR Address of early trace buffer +CONFIG_TRACE_CALL_DEPTH_LIMIT + Sets the limit on trace call-depth. For a broad view, 10 is typically + sufficient. Setting this too large creates enormous traces and distorts + the overall timing considerable. + Building U-Boot with Tracing Enabled ------------------------------------ @@ -148,6 +246,26 @@ instrumenting from the command line instead of having to change board config files. +Board requirements +------------------ + +Trace data collection relies on a microsecond timer, accessed through +`timer_get_us()`. So the first thing you should do is make sure that +this produces sensible results for your board. Suitable sources for +this timer include high resolution timers, PWMs or profile timers if +available. Most modern SOCs have a suitable timer for this. + +See `add_ftrace()` for where `timer_get_us()` is called. The `notrace` +attribute must be used on each function called by `timer_get_us()` since +recursive calls to `add_ftrace()` will cause a fault:: + + trace: recursion detected, disabling + +You cannot use driver model to obtain the microsecond timer, since tracing +may be enabled before driver model is set up. Instead, provide a low-level +function which accesses the timer, setting it up if needed. + + Collecting Trace Data --------------------- @@ -155,21 +273,22 @@ When you run U-Boot on your board it will collect trace data up to the limit of the trace buffer size you have specified. Once that is exhausted no more data will be collected. -Collecting trace data has an affect on execution time/performance. You +Collecting trace data affects execution time and performance. You will notice this particularly with trivial functions - the overhead of recording their execution may even exceed their normal execution time. In practice this doesn't matter much so long as you are aware of the effect. Once you have done your optimizations, turn off tracing before -doing end-to-end timing. +doing end-to-end timing using bootstage. The best time to start tracing is right at the beginning of U-Boot. The best time to stop tracing is right at the end. In practice it is hard to achieve these ideals. -This implementation enables tracing early in board_init_f(). This means +This implementation enables tracing early in `board_init_r()`, or +`board_init_f()` when `TRACE_EARLY` is enabled. This means that it captures most of the board init process, missing only the early architecture-specific init. However, it also misses the entire -SPL stage if there is one. +SPL stage if there is one. At present tracing is not supported in SPL. U-Boot typically ends with a 'bootm' command which loads and runs an OS. There is useful trace data in the execution of that bootm @@ -179,39 +298,11 @@ the OS. In practical terms, U-Boot runs the 'fakegocmd' environment variable at this point. This variable should have a short script which collects the trace data and writes it somewhere. -Trace data collection relies on a microsecond timer, accessed through -timer_get_us(). So the first think you should do is make sure that -this produces sensible results for your board. Suitable sources for -this timer include high resolution timers, PWMs or profile timers if -available. Most modern SOCs have a suitable timer for this. Make sure -that you mark this timer (and anything it calls) with -notrace so that the trace library can -use it without causing an infinite loop. - - -Commands --------- - -The trace command has variable sub-commands: - -stats - Display tracing statistics - -pause - Pause tracing - -resume - Resume tracing - -funclist [ ] - Dump a list of functions into the buffer - -calls [ ] - Dump function call trace into buffer +Controlling the trace +--------------------- -If the address and size are not given, these are obtained from environment -variables (see below). In any case the environment variables are updated -after the command runs. +U-Boot provides a command-line interface to the trace system for controlling +tracing and accessing the trace data. See :doc:`../usage/cmd/trace`. Environment Variables @@ -264,39 +355,94 @@ a trace log to address 10000000 and sends it to a host machine using TFTP. After this, U-Boot will boot the OS normally, albeit a little later. +For a filesystem you may do something like:: + + trace calls 10000000 1000000; + save mmc 1:1 10000000 /trace ${profoffset} + +The trace buffer format is internal to the trace system. It consists of a +header, a call count for each function site, followed by a list of trace +records, once for each function call. + -Converting Trace Output Data ----------------------------- +Converting Trace Output Data (proftool) +--------------------------------------- The trace output data is kept in a binary format which is not documented -here. To convert it into something useful, you can use proftool. +here. See the `trace.h` header file if you are interested. To convert it into +something useful, you can use proftool. This tool must be given the U-Boot map file and the trace data received -from running that U-Boot. It produces a text output file. +from running that U-Boot. It produces a binary output file. + +It is also possible to provide a configuration file to indicate which functions +should be included or dropped during conversion. This file consists of lines +like:: + + include-func + exclude-func -Options +where is a regular expression matched against function names. It +allows some functions to be dropped from the trace when producing ftrace +records. + +Options: + +-c + Specify the optional configuration file, to control which functions are + included in the output. + +-f + Specifies the format to use (see below) -m - Specify U-Boot map file + Specify U-Boot map file (`System.map`) + +-o + Specify the output filename --p - Specify profile/trace file +-t + Specify trace file, the data saved from U-Boot + +-v <0-4> + Specify the verbosity, where 0 is the minimum and 4 is for debugging. Commands: -dump-ftrace - Write a text dump of the file in Linux ftrace format to stdout +dump-ftrace: + Write a binary dump of the file in Linux ftrace format. Two options are + available: + + function + write function-call records (caller/callee) + + funcgraph + write function entry/exit records (graph) + + This format can be used with kernelshark_ and trace_cmd_. + +dump-flamegraph + Write a list of stack records useful for producing a flame graph. Two + options are available: + calls + create a flamegraph of stack frames + + timing + create a flamegraph of microseconds for each stack frame + + This format can be used with flamegraph_pl_. Viewing the Trace Data ---------------------- -You can use pytimechart for this (sudo apt-get pytimechart might work on -your Debian-style machine, and use your favourite search engine to obtain -documentation). It expects the file to have a .txt extension. The program -has terse user interface but is very convenient for viewing U-Boot -profile information. +You can use kernelshark_ for a GUI, but note that version 2.0.x was broken. If +you have that version you could try building it from source. +The file must have a .dat extension or it is ignored. The program has terse +user interface but is very convenient for viewing U-Boot profile information. + +Also available is trace_cmd_ which provides a command-line interface. Workflow Suggestions -------------------- @@ -329,7 +475,9 @@ There are a few parameters in the code that you may want to consider. There is a function call depth limit (set to 15 by default). When the stack depth goes above this then no tracing information is recorded. The maximum depth reached is recorded and displayed by the 'trace stats' -command. +command. While it might be tempting to set the depth limit quite high, this +can dramatically increase the size of the trace output as well as the execution +time. Future Work @@ -346,5 +494,10 @@ Some other features that might be useful: - Compression of trace information -Simon Glass -April 2013 +.. sectionauthor:: Simon Glass +.. April 2013 +.. Updated January 2023 + +.. _kernelshark: https://kernelshark.org/ +.. _trace_cmd: https://www.trace-cmd.org/ +.. _flamegraph_pl: https://github.com/brendangregg/FlameGraph/blob/master/flamegraph.pl diff --git a/doc/usage/cmd/trace.rst b/doc/usage/cmd/trace.rst new file mode 100644 index 00000000000..3bdf4f0a860 --- /dev/null +++ b/doc/usage/cmd/trace.rst @@ -0,0 +1,163 @@ +.. SPDX-License-Identifier: GPL-2.0+: + +trace command +============= + +Synopis +------- + +:: + + trace stats + trace pause + trace resume + trace funclist [ ] + trace calls [ ] + +Description +----------- + +The *trace* command is used to control the U-Boot tracing system. It allows +tracing to be paused and resumed, shows statistics for traces and provides a +way to dump out the trace information. + + +trace stats +~~~~~~~~~~~ + +This display tracing statistics, as follows: + +function sites + Functions are binned as a way of reducing the amount of space needed to + hold all the function information. This is controlled by FUNC_SITE_SIZE in + the trace.h header file. The usual value is 4, which provides the finest + granularity (assuming a minimum instruction size of 4 bytes) which means + that every function can be resolved individually. + +function calls + Total number of function calls, including those which were not traced due + to buffer space. This count does not include functions which exceeded the + depth limit. + +untracked function calls + Total number of function calls which did not appear in the U-Boot image. + This can happen if a function is called outside the normal code area. + +traced function calls + Total number of function calls which were actually traced, i.e. are included + in the recorded trace data. + +dropped due to overflow + If the trace buffer was exhausted then this shows the number of records that + were dropped. Try reducing the depth limit or expanding the buffer size. + +maximum observed call depth + Maximum observed call depth while tracing. + +calls not traced due to depth + Counts the number of function calls that were not recorded because they + exceeded the maximum call depth. + +max function calls + Maximum number of function calls which can be recorded in the trace buffer, + given its size. Once `function calls` hits this value, recording stops. + +trace buffer + Address of trace buffer + +call records + Address of first trace record. This is near the start of the trace buffer, + after the function-call counts. + + +trace pause +~~~~~~~~~~~ + +Pauses tracing, so that no more data is added to the trace buffer. + + +trace resume +~~~~~~~~~~~~ + +Resumes tracing, so that new function calls are added to the trace buffer if +there is sufficient space. + + +trace funclist [ ] +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Dumps a list of functions into the provided buffer. The file uses a format +specific to U-Boot: a header, following by the function offset and call count. + +If the address and size are not given, these are obtained from +:ref:`develop/trace:environment variables`. In any case the environment +variables are updated after the command runs. + +The resulting data should be written out to the host, e.g. using Ethernet or +a filesystem. There are no tools provided to read this sdata. + + +trace calls [ ] +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Dumps a list of function calls into the provided buffer. The file uses a format +specific to U-Boot: a header, following by the list of calls. The proftool +tool can be used to convert this information ready for further analysis. + + +Example +------- + +:: + + => trace stats + 269,252 function sites + 38,025,059 function calls + 3 untracked function calls + 7,382,690 traced function calls + 17 maximum observed call depth + 15 call depth limit + 68,667,432 calls not traced due to depth + 22,190,112 max function calls + + trace buffer 6c000000 call records 6c20de78 + => trace resume + => trace pause + +This shows that resuming the trace causes the buffer to overflow:: + + => trace stats + 269,252 function sites + 49,573,694 function calls + 3 untracked function calls + 22,190,112 traced function calls (8289848 dropped due to overflow) + 17 maximum observed call depth + 15 call depth limit + 68,667,432 calls not traced due to depth + 22,190,112 max function calls + + trace buffer 6c000000 call records 6c20de78 + => trace funcs 30000000 0x100000 + Function trace dumped to 30000000, size 0x1e70 + +This shows collecting and writing out the result trace data: + +:: + => trace calls 20000000 0x10000000 + Call list dumped to 20000000, size 0xfdf21a0 + => save mmc 1:1 20000000 /trace ${profoffset} + File System is consistent + file found, deleting + update journal finished + File System is consistent + update journal finished + 266281376 bytes written in 18584 ms (13.7 MiB/s) + +From here you can use proftool to convert it: + +.. code-block:: bash + + tools/proftool -m System.map -t trace -o asc.fg dump-ftrace + + +.. _`ACPI specification`: https://uefi.org/sites/default/files/resources/ACPI_6_3_final_Jan30.pdf diff --git a/doc/usage/index.rst b/doc/usage/index.rst index bbd40a6e189..d6d53151489 100644 --- a/doc/usage/index.rst +++ b/doc/usage/index.rst @@ -76,6 +76,7 @@ Shell commands cmd/sound cmd/temperature cmd/tftpput + cmd/trace cmd/true cmd/ums cmd/ut