From patchwork Fri Aug 2 12:44:11 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bruce Richardson X-Patchwork-Id: 142865 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 84A894571A; Fri, 2 Aug 2024 14:45:13 +0200 (CEST) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 8F18142E92; Fri, 2 Aug 2024 14:44:40 +0200 (CEST) Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.17]) by mails.dpdk.org (Postfix) with ESMTP id AD6B542E82 for ; Fri, 2 Aug 2024 14:44:37 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1722602678; x=1754138678; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=gl3z9Fzvc5I+sYRgr0EKcQuneVyhwGwmLwU+aNAcjss=; b=UaX4t2aS21SVOYyPuWUUCw9HfiyyhwEcvHeuxsbkEF505S0WaHovYhqD WE2OfahmBpEnKzCW/57HYeF4NCXAsbjSqagVWrZXuXiQViy2ub5Hzs6y9 3fSBoEQU0sWOmdQGv7p65PRiyMk85sZ3Jwm0PEDC64CRaRUQ8341/3SuH hirO+dTu7JYLIr7zR6e5pQAFMZoTRunKgvsgpKxs7Vdj4yyJJe0Xt6yo2 8NLYVqC7WHIy5Rf3vV0cbQrqu6P0FXPnCArwBBrvwhry1u5MvUpQfsQ1g IyLGSLo10i36oEz72a5ISfcZZVouf1D6vHdH69kHVYkrgF8qJTTnvBsz/ Q==; X-CSE-ConnectionGUID: fLjGDiRqQ8O1kgDm08iGYA== X-CSE-MsgGUID: 1Qo4dTIXRdWDHxc/m2YjjQ== X-IronPort-AV: E=McAfee;i="6700,10204,11152"; a="20499795" X-IronPort-AV: E=Sophos;i="6.09,257,1716274800"; d="scan'208";a="20499795" Received: from orviesa008.jf.intel.com ([10.64.159.148]) by fmvoesa111.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 02 Aug 2024 05:44:37 -0700 X-CSE-ConnectionGUID: /4zAmVBNSKmZ8uVYEzSXjA== X-CSE-MsgGUID: qA25iHptR0iWf99TKmN6Gg== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.09,257,1716274800"; d="scan'208";a="56149919" Received: from silpixa00401385.ir.intel.com ([10.237.214.25]) by orviesa008.jf.intel.com with ESMTP; 02 Aug 2024 05:44:36 -0700 From: Bruce Richardson To: dev@dpdk.org Cc: ferruh.yigit@amd.com, konstantin.ananyev@huawei.com, anatoly.burakov@intel.com, Bruce Richardson Subject: [PATCH v2 7/7] devtools: add script to generate DPDK dependency graphs Date: Fri, 2 Aug 2024 13:44:11 +0100 Message-ID: <20240802124411.485430-8-bruce.richardson@intel.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240802124411.485430-1-bruce.richardson@intel.com> References: <20240730145508.551075-1-bruce.richardson@intel.com> <20240802124411.485430-1-bruce.richardson@intel.com> MIME-Version: 1.0 X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Rather than the single monolithic graph that would be output from the deps.dot file in a build directory, we can post-process that to generate simpler graphs for different tasks. This new "draw_dependency_graphs" script takes the "deps.dot" as input and generates an output file that has the nodes categorized, filtering them based off the requested node or category. For example, use "--component net_ice" to show the dependency tree from that driver, or "--category lib" to show just the library dependency tree. Signed-off-by: Bruce Richardson --- devtools/draw-dependency-graphs.py | 136 +++++++++++++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100755 devtools/draw-dependency-graphs.py diff --git a/devtools/draw-dependency-graphs.py b/devtools/draw-dependency-graphs.py new file mode 100755 index 0000000000..826d89d5ce --- /dev/null +++ b/devtools/draw-dependency-graphs.py @@ -0,0 +1,136 @@ +#! /usr/bin/env python3 +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2024 Intel Corporation + +import argparse +import ast + + +driver_classes = [ + "baseband", + "bus", + "common", + "compress", + "crypto", + "dma", + "event", + "gpu", + "mempool", + "ml", + "net", + "raw", + "regex", + "vdpa", +] + + +def component_type(name: str): + if name.startswith("dpdk-"): + return "app" + + nameparts = name.split("_", 1) + if len(nameparts) > 1 and nameparts[0] in driver_classes: + return f"drivers/{nameparts[0]}" + + return "lib" + + +def read_deps_list(lines: list[str]): + deps_data = {} + for ln in lines: + if ln.startswith("digraph") or ln == "}": + continue + + if "->" in ln: + component, deps = [s.strip() for s in ln.split("->")] + deps = ast.literal_eval(deps) + else: + component, deps = ln, {} + + component = component.strip('"') + comp_class = component_type(component) + + if comp_class not in deps_data.keys(): + deps_data[comp_class] = {} + deps_data[comp_class][component] = deps + return deps_data + + +def create_classified_graph(deps_data: dict[dict[list[str]]]): + yield ("digraph dpdk_dependencies {\n overlap=false\n model=subset\n") + for n, category in enumerate(deps_data.keys()): + yield (f' subgraph cluster_{n} {{\n label = "{category}"\n') + for component in deps_data[category].keys(): + yield ( + f' "{component}" -> {deps_data[category][component]}\n'.replace( + "'", '"' + ) + ) + yield (" }\n") + yield ("}\n") + + +def get_deps_for_component( + dep_data: dict[dict[list[str]]], component: str, comp_deps: set +): + categories = dep_data.keys() + comp_deps.add(component) + for cat in categories: + if component in dep_data[cat].keys(): + for dep in dep_data[cat][component]: + get_deps_for_component(dep_data, dep, comp_deps) + + +def filter_deps( + dep_data: dict[dict[list[str]]], component: list[str] +) -> dict[dict[list[str]]]: + components = set() + for comp in component: + get_deps_for_component(dep_data, comp, components) + + retval = {} + for category in dep_data.keys(): + for comp in dep_data[category].keys(): + if comp in components: + if category not in retval: + retval[category] = {} + retval[category][comp] = dep_data[category][comp] + return retval + + +def main(): + parser = argparse.ArgumentParser( + description="Utility to generate dependency tree graphs for DPDK" + ) + parser.add_argument( + "--component", + type=str, + help="Only output hierarchy from specified component down.", + ) + parser.add_argument( + "--category", + type=str, + help="Output hierarchy for all components in given category, e.g. lib, app, drivers/net, etc.", + ) + parser.add_argument( + "input_file", + type=argparse.FileType("r"), + help="Path to the deps.dot file from a DPDK build directory", + ) + parser.add_argument( + "output_file", + type=argparse.FileType("w"), + help="Path to the desired output dot file", + ) + args = parser.parse_args() + + deps = read_deps_list([ln.strip() for ln in args.input_file.readlines()]) + if args.component: + deps = filter_deps(deps, [args.component]) + elif args.category: + deps = filter_deps(deps, deps[args.category].keys()) + args.output_file.writelines(create_classified_graph(deps)) + + +if __name__ == "__main__": + main()