From patchwork Fri Jun 21 12:06:04 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dodji Seketeli X-Patchwork-Id: 92640 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id AC78738983A8 for ; Fri, 21 Jun 2024 12:06:15 +0000 (GMT) X-Original-To: libabigail@sourceware.org Delivered-To: libabigail@sourceware.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTPS id 70CA93896C3A for ; Fri, 21 Jun 2024 12:06:09 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 70CA93896C3A Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 70CA93896C3A Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1718971571; cv=none; b=kfYeeZa+mUBqPilX8CckTIRDwUrWNO9zIdMCG9E95paiZ7klD6x4jPLXw+ZktvXwo8P1nK7FqUud1O/6v82aFdaE3NIDjD4hovc3j+SCXqeb0JT2Lxv6RjKq57/KPu1mXl0c1RxmfNE2SwWM9NMsb1Mgm2XbBZf65ZqHPPrlges= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1718971571; c=relaxed/simple; bh=nuoL2UswS1KpQXtiwhasoCcN8JHGrtJj5VvNOLb9gYQ=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=Ps18ysB6WO3ID8PSJvS2xeDUQjZZMWYshdvR5NZSt6z4N4sXWDNZaLUWR86CVH84mQx85VMMdkVSRigQhgF0UCnHM/6uHh50KabIa/Q/ZGjJ47NHBiApLq3s5+74+uz1C0eJk9QvA2A/70zEt3xwjrVD9Y8ubHWSc1zcRZa4pJY= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1718971569; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type; bh=CdXnMZMxDN5+n4axujtgjkDKMeMhvYMuZsFqi97O87w=; b=O/WjcDMRrALlOF8mE7fOeQavy0iUdsm82mSM71ZgZDj7Vp82DT8NFolC6tDsuAHOKlP59O rePFJX5XqegdwJqeh5rHmI+k9kia3SI+iLeNvdGHzUiYDIvWXYSbZcyH8CHBKbgey53poU vJ7Ww66biBIROV4UYwnC3en5CWp5a7w= Received: from mail-qk1-f197.google.com (mail-qk1-f197.google.com [209.85.222.197]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-680-afkhrl0BP3-6kVAwZB7ZwQ-1; Fri, 21 Jun 2024 08:06:07 -0400 X-MC-Unique: afkhrl0BP3-6kVAwZB7ZwQ-1 Received: by mail-qk1-f197.google.com with SMTP id af79cd13be357-79bbc561cadso277915285a.1 for ; Fri, 21 Jun 2024 05:06:07 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1718971567; x=1719576367; h=mime-version:user-agent:message-id:date:cc:organization:subject:to :from:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=CdXnMZMxDN5+n4axujtgjkDKMeMhvYMuZsFqi97O87w=; b=FVyHGBfZB+2fMPeQWiEQfXzJwYWAhGdLPYchSF553ULRoOR2M/xpjGltBRMPzJlPsb uGKDlNId6K3reOq5TqWWuJpluKLQFfSOSRvrMLOTRlB1vzR4EyJ6mRAE9xF9T0g6uHqH rgbtdC7Un0JUCjxU+b+52eY5rNomlyakPb0CHRGB7yHvHalsbZBefY1u6iN19YYVzJUd kwFniX4xlZI3aHbWtErvDgj48+58PfteE97+NT+ZFom6LvdHleW+5LxJ159wTSng4Svq 6Y134Og5cmgLLqrLIRav4+IS0NrBiL+JmvUofRAJHKHqhPuQ5RGXyqSVTIBznKFIC4Ze WkeA== X-Gm-Message-State: AOJu0Yzb0M37kN7S/wgYkczPs/wDaUPFrteyR5ldYPw7ub1dIZmLjJa2 F8jWcsipXOgDEHH0GOto+JbZ8JCt8Ohm43wNyI1fL3CA3NoTxMViFf8C16LVHKnndpoODEB2o8/ lPTqi1aDtB06aEBTo9HJx0Rps84XIGdrs6OzIlZ/U9mJV4EaKWY426lpOs1zWppdIJA== X-Received: by 2002:a05:6214:91:b0:6b0:8fb7:cd0 with SMTP id 6a1803df08f44-6b51be6b80amr28330616d6.43.1718971567154; Fri, 21 Jun 2024 05:06:07 -0700 (PDT) X-Google-Smtp-Source: AGHT+IGLsLBX4GXxXJDj9SYaz1YFovBUpzmPEGqgqarE13VyxQGkDN+YHUahMSf06hP695dzhZQlcA== X-Received: by 2002:a05:6214:91:b0:6b0:8fb7:cd0 with SMTP id 6a1803df08f44-6b51be6b80amr28330376d6.43.1718971566799; Fri, 21 Jun 2024 05:06:06 -0700 (PDT) Received: from localhost (88-120-130-27.subs.proxad.net. [88.120.130.27]) by smtp.gmail.com with ESMTPSA id 6a1803df08f44-6b51ecfec84sm8207926d6.19.2024.06.21.05.06.06 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 21 Jun 2024 05:06:06 -0700 (PDT) Received: by localhost (Postfix, from userid 1000) id 49EEFC1B7841; Fri, 21 Jun 2024 14:06:04 +0200 (CEST) From: Dodji Seketeli To: claudiu.zissulescu-ianculescu@oracle.com Subject: [PATCH 1/2] ctf-reader: Fix re-initialization of the CTF reader Organization: Red Hat / France cc: libabigail@sourceware.org X-Operating-System: AlmaLinux 9.4 X-URL: http://www.redhat.com Date: Fri, 21 Jun 2024 14:06:04 +0200 Message-ID: <87r0cqxzyr.fsf@redhat.com> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/27.2 (gnu/linux) MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-12.1 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H4, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: libabigail@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Mailing list of the Libabigail project List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libabigail-bounces+patchwork=sourceware.org@sourceware.org Hello, When analyzing a Linux Kernel tree made of vmlinux and loadable module binaries, the same (CTF) binary reader is re-used to load every single binaries in a loop. That can be seen, for instance, by reading the code of load_vmlinux_corpus in abg-tools-utils.cc. As part of that process, abigail::ctf::reader::initialize is invoked prior to using the reader to read type information from each binary. But then, looking at things a bit closer, I realized that ctf::reader::initialize is failing to reset the reader::ctfa data member. That leads to a memory leak that was making things grow out of proportion. Also, the resetting code fails to actually clear out the map of types that are to be sorted and canonicalized. That leads to unnecessarily sorting huge amount of types. The patch address the two points above. Apart from the obvious gain in code integrity, this patch significantly reduces the time taken to analyze a Linux Kernel tree. The patch has been successfully tested in the CI on sourceware. OK to apply to the mainline? * src/abg-ctf-reader.cc (reader::reader): Initialize ctfa, ctf_sect, symtab_sect and strtab_sect data members. (reader::initialize): In the overload taking no argument, make sure to free the ctfa data member before setting it to nullptr. In the overload that takes argument, make sure to invoke reader::initialize() to really free the data used. Also, improve the comments. Signed-off-by: Dodji Seketeli --- src/abg-ctf-reader.cc | 48 ++++++++++++++++++++++++------------------- 1 file changed, 27 insertions(+), 21 deletions(-) diff --git a/src/abg-ctf-reader.cc b/src/abg-ctf-reader.cc index f4fb91ed..8810e138 100644 --- a/src/abg-ctf-reader.cc +++ b/src/abg-ctf-reader.cc @@ -238,7 +238,8 @@ public: reader(const string& elf_path, const vector& debug_info_root_paths, environment& env) - : elf_based_reader(elf_path, debug_info_root_paths, env) + : elf_based_reader(elf_path, debug_info_root_paths, env), + ctfa(), ctf_sect(), symtab_sect(), strtab_sect() { initialize(); } @@ -248,17 +249,21 @@ public: /// This is useful to clear out the data used by the reader and get /// it ready to be used again. /// - /// Note that the reader eeps the same environment it has been - /// originally created with. + /// Note that the reader keeps (doesn't clear) the same environment + /// it has been originally created with. /// /// Please also note that the life time of this environment object - /// must be greater than the life time of the resulting @ref - /// reader the context uses resources that are allocated in - /// the environment. + /// must be greater than the life time of the resulting @ref reader + /// the context uses resources that are allocated in the + /// environment. void initialize() { - ctfa = nullptr; + if (ctfa) + { + ctf_close(ctfa); + ctfa = nullptr; + } types_map.clear(); cur_tu_.reset(); corpus_group().reset(); @@ -266,6 +271,16 @@ public: /// Initializer of the reader. /// + /// This first makes sure the data used by the reader is cleared. + /// And then it initlizes it with the information passed in + /// argument. + /// + /// This is useful to clear out the data used by the reader and get + /// it ready to be used again. + /// + /// Note that the reader keeps the same environment it has been + /// originally created with. + /// /// @param elf_path the new path to the new ELF file to use. /// /// @param debug_info_root_paths a vector of paths to use to look @@ -275,22 +290,13 @@ public: /// /// @param linux_kernel_mode currently not used. /// - /// This is useful to clear out the data used by the reader and get - /// it ready to be used again. - /// - /// Note that the reader eeps the same environment it has been - /// originally created with. - /// - /// Please also note that the life time of this environment object - /// must be greater than the life time of the resulting @ref - /// reader the context uses resources that are allocated in - /// the environment. void - initialize(const string& elf_path, - const vector& debug_info_root_paths, - bool load_all_types = false, - bool linux_kernel_mode = false) + initialize(const string& elf_path, + const vector& debug_info_root_paths, + bool load_all_types = false, + bool linux_kernel_mode = false) { + initialize(); load_all_types = load_all_types; linux_kernel_mode = linux_kernel_mode; elf_based_reader::initialize(elf_path, debug_info_root_paths); From patchwork Fri Jun 21 12:09:03 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dodji Seketeli X-Patchwork-Id: 92641 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 30E263896C3A for ; Fri, 21 Jun 2024 12:09:20 +0000 (GMT) X-Original-To: libabigail@sourceware.org Delivered-To: libabigail@sourceware.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by sourceware.org (Postfix) with ESMTPS id 6AA5F389244C for ; Fri, 21 Jun 2024 12:09:13 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 6AA5F389244C Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 6AA5F389244C Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1718971755; cv=none; b=LhB4RkGMoBmYod2WdEMVS4PEluVY1Mll2hOfptuY5zq4cSuSUzJT5q+9jJ3Zs6wE+Z3IkKkqYcuasEd3YrVWuYfeTCWs9bWkgJMNB02XUVocqepzR9esG79r4M/RQaRWpvcN6DzA2QW81zD7HcPvVp7JO6OOPipAzEy2tXX+ttU= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1718971755; c=relaxed/simple; bh=0ba+wgLe1f5T7/lT2SNuqi7037p3954FVkvIz26aJgg=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=Kh6y6iZXGIOyNW+OgCFrPxMwWGixfRq+38TOIdOEJx5k/I9VqO5icCQvVWE9IjiHgOSVURD8xilFodsl3GzWXHOFP5y5h8roD23Isl8e6Jui9oBMwUI9vcLvj5rHY6ttJt711QdZbpIRXjJrM2eN8esfq341zImvV2+jT9skeoQ= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1718971753; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type; bh=WTPEdNetciLdfER1cjUAu42RZVHaHmnHw9FpWJmftrk=; b=QkSADfbgUfGnWu0VN9QqI55C4I+TWAK3ag1IE1gmZ77kPa/dX28aewoj07rGYqmhA0RG+Z SlITcq2rE4eLmbdHFNNVAHErsY6suqFdxZt9f0oSTSeKlAOAHPxcU7HwlQBW1288BpY1iL UOlnHFJ6cJ+dKWvyM5ekbCrvkWbb/J4= Received: from mail-qv1-f71.google.com (mail-qv1-f71.google.com [209.85.219.71]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-307-WlOTwGgeOaCA-iYtJxDLmw-1; Fri, 21 Jun 2024 08:09:11 -0400 X-MC-Unique: WlOTwGgeOaCA-iYtJxDLmw-1 Received: by mail-qv1-f71.google.com with SMTP id 6a1803df08f44-6ae4c8c30baso19392896d6.0 for ; Fri, 21 Jun 2024 05:09:11 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1718971751; x=1719576551; h=mime-version:user-agent:message-id:date:organization:subject:cc:to :from:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=WTPEdNetciLdfER1cjUAu42RZVHaHmnHw9FpWJmftrk=; b=goPbabdVMjL2AOxbQ6ofc2M/CC7/z2pLA8FOuUJwJKNrK28wEwHoQ2q2U4OqQtE69t S1yXtU8/v8RiHEtk8RReubAE5TwYscu96BvBHe1k8trS/H1zDDddmv+AcdunbLbEj8KD kLFUispTNSdFJCENyXDyPoUAjxEuxYW9HseQGFsOAupviWF8xLuMF8BsIKI8cEsKuO/I wpCLK4lkhsPjRv//y8lmVaqpGI+NLG3BvUX0zmGIi8ULZFyv80sRBuM6SMrK4lX2GrEU w0U016+KmSquWt7hYagCeLZSJcQWo0+V6AbyM5wDpgrckC3O4KA0yZlclJEfahGKSDkP qruQ== X-Gm-Message-State: AOJu0YzH8rXQKTMcL+EfAQVr2vqvSEDJUt1tAIrHbm869zshIHQvWg3V fC3RpJ3EUF6Zpbx6RaNuvtA6FVZg40GRs4DMW/63OEiv0PBLFo9FAxKLCdXdUyovMgKGRw2xcRK sO730oIqnHSNbYjv9nFFB+uKnmwDS61ABBmPz3DSOm1GkO79TIcfkIQJhggzgZ6bClQ== X-Received: by 2002:ad4:5749:0:b0:6b0:65dd:4b7e with SMTP id 6a1803df08f44-6b501e9d4cbmr118831856d6.42.1718971750880; Fri, 21 Jun 2024 05:09:10 -0700 (PDT) X-Google-Smtp-Source: AGHT+IGIaYatp87x2g63+sa4/B2rA9HoF9Ip/4uU7PlWs6L2LTv25qOQEr1lwG0KUtdHxA3qymUwJQ== X-Received: by 2002:ad4:5749:0:b0:6b0:65dd:4b7e with SMTP id 6a1803df08f44-6b501e9d4cbmr118831616d6.42.1718971750479; Fri, 21 Jun 2024 05:09:10 -0700 (PDT) Received: from localhost (88-120-130-27.subs.proxad.net. [88.120.130.27]) by smtp.gmail.com with ESMTPSA id 6a1803df08f44-6b529ca50b0sm494706d6.41.2024.06.21.05.09.09 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 21 Jun 2024 05:09:10 -0700 (PDT) Received: by localhost (Postfix, from userid 1000) id 51FCDC1B7841; Fri, 21 Jun 2024 14:09:03 +0200 (CEST) From: Dodji Seketeli To: claudiu.zissulescu-ianculescu@oracle.com Cc: libabigail@sourceware.org Subject: [PATCH 2/2] ir: Cache the pretty representation used during pre-canonicalization type sorting Organization: Red Hat / France X-Operating-System: AlmaLinux 9.4 X-URL: http://www.redhat.com Date: Fri, 21 Jun 2024 14:09:03 +0200 Message-ID: <87msnexzts.fsf@redhat.com> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/27.2 (gnu/linux) MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-12.1 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H4, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: libabigail@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Mailing list of the Libabigail project List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libabigail-bounces+patchwork=sourceware.org@sourceware.org Hello, Profiling showed that pre-canonicalization type sorting (which uses the type_topo_comp sorting functor) we spend a lot of time computing the pretty representation of types and decls invoked from type_topo_comp::operator() and decl_topo_comp::operator(). This patch thus uses type_base::get_cached_pretty_representation and introduces a new decl_base::get_cached_pretty_representation to cache the pretty representation of types and decls and re-use that representation instead of computing it over and over. Together with the previous patch of this series, the time spent to analyze a Linux Kernel tree went from ~ 55 minutes to around 1m15s using a non-optimized build of libabigail. Note that these two patches are logically independent but I'd like to apply them in tandem as they are the result of the profiling and optimization work suggested by Claudiu Zissulescu Ianculescu. This patch has been tested on the sourceware CI and is thus ready to be applied to the mainline once the previous one gets in. * include/abg-ir.h (decl_base::get_cached_pretty_representation): Declare new member function. * src/abg-ir-priv.h ({type,decl}_topo_comp::operator()): Use {type,decl}_base::get_cached_pretty_representation instead of get_pretty_representation.: * src/abg-ir.cc (decl_base::priv::{internal_cached_repr_, cached_repr}): Define new data members. (decl_base::get_cached_pretty_representation): Define new member function. (type_base::get_cached_pretty_representation): Cache pretty representation even for non-canonicalized types. Fix comments. Signed-off-by: Dodji Seketeli --- include/abg-ir.h | 3 +++ src/abg-ir-priv.h | 38 +++++++++++++++--------------- src/abg-ir.cc | 59 +++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 76 insertions(+), 24 deletions(-) diff --git a/include/abg-ir.h b/include/abg-ir.h index e7fb0f01..348cce3c 100644 --- a/include/abg-ir.h +++ b/include/abg-ir.h @@ -1622,6 +1622,9 @@ public: decl_base(const environment&, const location&); + const interned_string& + get_cached_pretty_representation(bool internal = false) const; + virtual bool operator==(const decl_base&) const; diff --git a/src/abg-ir-priv.h b/src/abg-ir-priv.h index cea7494c..78a05e72 100644 --- a/src/abg-ir-priv.h +++ b/src/abg-ir-priv.h @@ -1327,8 +1327,8 @@ struct decl_topo_comp // of their pretty representation before we start looking at IR // nodes' locations down the road. if (is_unique_type(is_type(f)) || is_unique_type(is_type(s))) - return (get_pretty_representation(f, /*internal=*/false) - < get_pretty_representation(s, /*internal=*/false)); + return (f->get_cached_pretty_representation(/*internal=*/false) + < s->get_cached_pretty_representation(/*internal=*/false)); // If both decls come from an abixml file, keep the order they // have from that abixml file. @@ -1353,12 +1353,12 @@ struct decl_topo_comp // We reach this point if location data is useless. if (f->get_is_anonymous() && s->get_is_anonymous() - && (get_pretty_representation(f, /*internal=*/false) - == get_pretty_representation(s, /*internal=*/false))) + && (f->get_cached_pretty_representation(/*internal=*/false) + == s->get_cached_pretty_representation(/*internal=*/false))) return f->get_name() < s->get_name(); - return (get_pretty_representation(f, /*internal=*/false) - < get_pretty_representation(s, /*internal=*/false)); + return (f->get_cached_pretty_representation(/*internal=*/false) + < s->get_cached_pretty_representation(/*internal=*/false)); } /// The "Less Than" comparison operator of this functor. @@ -1454,8 +1454,8 @@ struct type_topo_comp && !has_artificial_or_natural_location(f) && !has_artificial_or_natural_location(s)) { - string s1 = get_pretty_representation(f, /*internal=*/false); - string s2 = get_pretty_representation(s, /*internal=*/false); + interned_string s1 = f->get_cached_pretty_representation(/*internal=*/false); + interned_string s2 = s->get_cached_pretty_representation(/*internal=*/false); if (s1 == s2) { if (qualified_type_def * q = is_qualified_type(f)) @@ -1497,8 +1497,8 @@ struct type_topo_comp type_base *peeled_s = peel_pointer_or_reference_type(s, true); - s1 = get_pretty_representation(peeled_f, /*internal=*/false); - s2 = get_pretty_representation(peeled_s, /*internal=*/false); + s1 = peeled_f->get_cached_pretty_representation(/*internal=*/false); + s2 = peeled_s->get_cached_pretty_representation(/*internal=*/false); if (s1 != s2) return s1 < s2; @@ -1508,25 +1508,23 @@ struct type_topo_comp peeled_f = peel_typedef_pointer_or_reference_type(peeled_f, true); peeled_s = peel_typedef_pointer_or_reference_type(peeled_s, true); - s1 = get_pretty_representation(peeled_f, false); - s2 = get_pretty_representation(peeled_s, false); + s1 = peeled_f->get_cached_pretty_representation(false); + s2 = peeled_s->get_cached_pretty_representation(false); if (s1 != s2) return s1 < s2; } } - string s1 = get_pretty_representation(f, false); - string s2 = get_pretty_representation(s, false); + interned_string s1 = f->get_cached_pretty_representation(false); + interned_string s2 = s->get_cached_pretty_representation(false); if (s1 != s2) return s1 < s2; if (is_typedef(f) && is_typedef(s)) { - s1 = get_pretty_representation(is_typedef(f)->get_underlying_type(), - false); - s2 = get_pretty_representation(is_typedef(s)->get_underlying_type(), - false); + s1 = is_typedef(f)->get_underlying_type()->get_cached_pretty_representation(false); + s2 = is_typedef(s)->get_underlying_type()->get_cached_pretty_representation(false); if (s1 != s2) return s1 < s2; } @@ -1534,8 +1532,8 @@ struct type_topo_comp type_base *peeled_f = peel_typedef_pointer_or_reference_type(f, true); type_base *peeled_s = peel_typedef_pointer_or_reference_type(s, true); - s1 = get_pretty_representation(peeled_f, false); - s2 = get_pretty_representation(peeled_s, false); + s1 = peeled_f->get_cached_pretty_representation(false); + s2 = peeled_s->get_cached_pretty_representation(false); if (s1 != s2) return s1 < s2; diff --git a/src/abg-ir.cc b/src/abg-ir.cc index 63527baf..d62addda 100644 --- a/src/abg-ir.cc +++ b/src/abg-ir.cc @@ -4358,6 +4358,8 @@ struct decl_base::priv interned_string qualified_name_; interned_string temporary_internal_qualified_name_; interned_string internal_qualified_name_; + interned_string internal_cached_repr_; + interned_string cached_repr_; // Unline qualified_name_, scoped_name_ contains the name of the // decl and the name of its scope; not the qualified name of the // scope. @@ -4855,6 +4857,48 @@ decl_base::get_pretty_representation(bool internal, return get_name(); } +/// Get the pretty representation of the current decl. +/// +/// The pretty representation is retrieved from a cache. If the cache +/// is empty, this function computes the pretty representation, put it +/// in the cache and returns it. +/// +/// Please note that if this function is called too early in the life +/// cycle of the decl (before it is fully constructed), then the +/// pretty representation that is cached is going to represent a +/// non-complete (and thus wrong) representation of the decl. Thus +/// this function must be called only once the decl is fully +/// constructed. +/// +/// @param internal if true, then the pretty representation is to be +/// used for purpuses that are internal to the libabigail library +/// itself. If you don't know what this means, then you probably +/// should set this parameter to "false". +/// +/// @return a reference to a cached @ref interned_string holding the +/// pretty representation of the current decl. +const interned_string& +decl_base::get_cached_pretty_representation(bool internal) const +{ + if (internal) + { + if (priv_->internal_cached_repr_.empty()) + { + string r = ir::get_pretty_representation(this, internal); + priv_->internal_cached_repr_ = get_environment().intern(r); + } + return priv_->internal_cached_repr_; + } + + if (priv_->cached_repr_.empty()) + { + string r = ir::get_pretty_representation(this, internal); + priv_->cached_repr_ = get_environment().intern(r); + } + + return priv_->cached_repr_; +} + /// Return the qualified name of the decl. /// /// This is the fully qualified name of the decl. It's made of the @@ -15780,19 +15824,26 @@ type_base::get_naked_canonical_type() const /// is empty, this function computes the pretty representation, put it /// in the cache and returns it. /// -/// Note that if the type is *NOT* canonicalized, the pretty -/// representation is never cached. +/// Please note that if this function is called too early in the life +/// cycle of the type (before the type is fully constructed), then the +/// pretty representation that is cached is going to represent a +/// non-complete (and thus wrong) representation of the type. Thus +/// this function must be called only once the type is fully +/// constructed. /// /// @param internal if true, then the pretty representation is to be /// used for purpuses that are internal to the libabigail library /// itself. If you don't know what this means, then you probably /// should set this parameter to "false". +/// +/// @return a reference to a cached @ref interned_string holding the +/// pretty representation of the current type. const interned_string& type_base::get_cached_pretty_representation(bool internal) const { if (internal) { - if (!get_naked_canonical_type() || priv_->internal_cached_repr_.empty()) + if (priv_->internal_cached_repr_.empty()) { string r = ir::get_pretty_representation(this, internal); priv_->internal_cached_repr_ = get_environment().intern(r); @@ -15800,7 +15851,7 @@ type_base::get_cached_pretty_representation(bool internal) const return priv_->internal_cached_repr_; } - if (!get_naked_canonical_type() || priv_->cached_repr_.empty()) + if (priv_->cached_repr_.empty()) { string r = ir::get_pretty_representation(this, internal); priv_->cached_repr_ = get_environment().intern(r);