From patchwork Tue Apr 4 17:08:57 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Malcolm X-Patchwork-Id: 79256 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:b0ea:0:b0:3b6:4342:cba0 with SMTP id b10csp36155vqo; Tue, 4 Apr 2023 10:12:09 -0700 (PDT) X-Google-Smtp-Source: AKy350ZWro75Bj2kIBYyvtUk+Chq/PiSyTc2ssxrY8kbbyVAh++s2VXUU7DPy35vUaO6KiLfn+Gn X-Received: by 2002:a17:906:8c8:b0:93e:fa12:aa1a with SMTP id o8-20020a17090608c800b0093efa12aa1amr332518eje.1.1680628329239; Tue, 04 Apr 2023 10:12:09 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1680628329; cv=none; d=google.com; s=arc-20160816; b=vu0ZcPJShGU+ZObym1upAF86WggxCnwAP2K/3T+z0ZEsHIUlrWmyGaWG7e8Enp0nXf a3GdhTfJOF9KzD2E4wSOBD8vNyNvSTOc1Zkc0JihzMWHIzoRfZIT2CXpnnhtYZ4quyAW euSRg5DPU8VW6zHeXA7mmmCFiqARWj/SwYPR/PdLJS/qh7jRyn3k7zEOJrqUrONS+MSY azKaPgeUUO8fzinRhGaJ5sAtGeYJtsqPndmWpQ/sGviD5PUoBHMhZhouCTYF0PHfY+oE kDT0RfQrRIaohFrxaWbM0dAmYs9fN4vaqFfqKT9mwoRkhVr4vEWppmn6yneFtpEh/fQg iROw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:reply-to:from:list-subscribe:list-help:list-post :list-archive:list-unsubscribe:list-id:precedence :content-transfer-encoding:mime-version:message-id:date:subject:cc :to:dmarc-filter:delivered-to:dkim-signature:dkim-filter; bh=8FAH+BmQUWEYNDipBRN2UBydRxyI0yhlTo1AQxU+X3w=; b=WGHebJwbyqT+UPRqhlntFpu1WDMzhQk9aJJdgX/3SpmB0nhBk2MyWif4IbJSffVkNY iXgw8k72oe57GiSp55BxyDOp/1nOMm4i1mFj9evY1vRbbcO8eOuvYnJW2NmdqgdxTNVj Z8QdFPXJlhJGzYHg/o3rKYatSQgEjQfxo2hGsZ+Y/mtM97xM3vI1LNMjeN/UGCRikyIL jeNq4M4i0aiG5XsB8UrLK1VWnnRb6QqkVHQBLkOFUpJNB8bbYAVFxzGqAqVh+aHBeApH Tcyr+t/Ukxdfb0swAU82lp9inTB4W7j7z25n6H7Os0PUsM77yfkUICkd23dd5JiN0Y8t BTmQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gcc.gnu.org header.s=default header.b="dnt/yPWa"; spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=gnu.org Received: from sourceware.org (server2.sourceware.org. [2620:52:3:1:0:246e:9693:128c]) by mx.google.com with ESMTPS id sd22-20020a1709076e1600b00947c422a55dsi2028873ejc.866.2023.04.04.10.12.08 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 04 Apr 2023 10:12:09 -0700 (PDT) Received-SPF: pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) client-ip=2620:52:3:1:0:246e:9693:128c; Authentication-Results: mx.google.com; dkim=pass header.i=@gcc.gnu.org header.s=default header.b="dnt/yPWa"; spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=gnu.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id BCFDC3851402 for ; Tue, 4 Apr 2023 17:11:06 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org BCFDC3851402 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1680628266; bh=8FAH+BmQUWEYNDipBRN2UBydRxyI0yhlTo1AQxU+X3w=; h=To:Cc:Subject:Date:List-Id:List-Unsubscribe:List-Archive: List-Post:List-Help:List-Subscribe:From:Reply-To:From; b=dnt/yPWaB+BXJk61STD7JDiKNNKrMi9CHnmNQQQRrzNSvVq7iVjnEs14ujQA812Eu BKLG+ZAI/NZYAFx3i1/5pXRzfnB2VIjmpyTemqJkBxF01AdHBU6ogUiaHJN8Unjayb z7DBJw2+81k99nqlSXDKPbAgbV4OjMB8n3iwaKIE= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.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 0342B385480D for ; Tue, 4 Apr 2023 17:09:22 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 0342B385480D Received: from mimecast-mx02.redhat.com (mx3-rdu2.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-397-4lSq31KLNzmsly5r5zoo5g-1; Tue, 04 Apr 2023 13:09:19 -0400 X-MC-Unique: 4lSq31KLNzmsly5r5zoo5g-1 Received: from smtp.corp.redhat.com (int-mx10.intmail.prod.int.rdu2.redhat.com [10.11.54.10]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id E96F61C09509; Tue, 4 Apr 2023 17:09:18 +0000 (UTC) Received: from t14s.localdomain.com (unknown [10.2.17.70]) by smtp.corp.redhat.com (Postfix) with ESMTP id 9E754483EC1; Tue, 4 Apr 2023 17:09:18 +0000 (UTC) To: gcc-patches@gcc.gnu.org, Richard Biener , Jakub Jelinek Cc: David Malcolm Subject: [PATCH] Add -fsarif-time-report [PR109361] Date: Tue, 4 Apr 2023 13:08:57 -0400 Message-Id: <20230404170857.608270-1-dmalcolm@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.1 on 10.11.54.10 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-11.8 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2, SPF_HELO_NONE, SPF_NONE, TXREP, T_FILL_THIS_FORM_SHORT 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: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: David Malcolm via Gcc-patches From: David Malcolm Reply-To: David Malcolm Errors-To: gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org Sender: "Gcc-patches" X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1762266531075988055?= X-GMAIL-MSGID: =?utf-8?q?1762266531075988055?= Richi, Jakub: I can probably self-approve this, but it's technically a new feature. OK if I push this to trunk in stage 4? I believe it's low risk, and is very useful for benchmarking -fanalyzer. This patch adds support for embeddding profiling information about the compiler itself into the SARIF output. In an earlier version of this patch I extended -ftime-report so that as well as writing to stderr, it would embed the information in any SARIF output. This turned out to be awkward to use, in that I found myself needing to get the data in JSON form without also having it emitted on stderr (which was affecting the output of the build). Hence this version of the patch adds a new -fsarif-time-report, similar to the existing -ftime-report for requesting GCC profile itself using the timevar machinery. Specifically, if -fsarif-time-report is specified, the timing information will be captured (as if -ftime-report were specified), and will be embedded in JSON form within any SARIF as a "gcc/timeReport" property within a property bag of the "invocation" object. Here's an example of the output: "invocations": [ { "executionSuccessful": true, "toolExecutionNotifications": [], "properties": { "gcc/timeReport": { "timevars": [ { "name": "phase setup", "elapsed": { "user": 0.04, "sys": 0, "wall": 0.04, "ggc_mem": 1863472 } }, [...snip...] { "name": "analyzer: processing worklist", "elapsed": { "user": 0.06, "sys": 0, "wall": 0.06, "ggc_mem": 48 } }, { "name": "analyzer: emitting diagnostics", "elapsed": { "user": 0.01, "sys": 0, "wall": 0.01, "ggc_mem": 0 } }, { "name": "TOTAL", "elapsed": { "user": 0.21, "sys": 0.03, "wall": 0.24, "ggc_mem": 3368736 } } ], "CHECKING_P": true, "flag_checking": true } } } ] I have successfully used this in my analyzer integration tests to get timing information about which source files get slowed down by the analyzer. I've validated the generated .sarif files against the SARIF schema. The documentation notes that the precise output format is subject to change. Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu. gcc/ChangeLog: PR analyzer/109361 * common.opt (fsarif-time-report): New option. * diagnostic-client-data-hooks.h (class sarif_object): New forward decl. (diagnostic_client_data_hooks::add_sarif_invocation_properties): New vfunc. * diagnostic-format-sarif.cc: Include "diagnostic-format-sarif.h". (class sarif_invocation): Inherit from sarif_object rather than json::object. (class sarif_result): Likewise. (class sarif_ice_notification): Likewise. (sarif_object::get_or_create_properties): New. (sarif_invocation::prepare_to_flush): Add "context" param. Use it to call the context's add_sarif_invocation_properties hook. (sarif_builder::flush_to_file): Pass m_context to sarif_invocation::prepare_to_flush. * diagnostic-format-sarif.h: New header. * doc/invoke.texi (Developer Options): Add -fsarif-time-report. * timevar.cc: Include "json.h". (timer::named_items::m_hash_map): Split out type into... (timer::named_items::hash_map_t): ...this new typedef. (timer::named_items::make_json): New function. (timevar_diff): New function. (make_json_for_timevar_time_def): New function. (timer::timevar_def::make_json): New function. (timer::make_json): New function. * timevar.h (class json::value): New forward decl. (timer::make_json): New decl. (timer::timevar_def::make_json): New decl. * toplev.cc (toplev::~toplev): Guard the call to timer::print so that it doesn't happen on just -fsarif-time-report. (toplev::start_timevars): Add sarif_time_report to the flags that can lead to timevar_init being called. * tree-diagnostic-client-data-hooks.cc: Include "diagnostic-format-sarif.h" and "timevar.h". (compiler_data_hooks::add_sarif_invocation_properties): New vfunc implementation. gcc/testsuite/ChangeLog: PR analyzer/109361 * c-c++-common/diagnostic-format-sarif-file-timevars-1.c: New test. * c-c++-common/diagnostic-format-sarif-file-timevars-2.c: New test. Signed-off-by: David Malcolm --- gcc/common.opt | 4 + gcc/diagnostic-client-data-hooks.h | 6 + gcc/diagnostic-format-sarif.cc | 45 +++-- gcc/diagnostic-format-sarif.h | 45 +++++ gcc/doc/invoke.texi | 11 +- .../diagnostic-format-sarif-file-timevars-1.c | 18 ++ .../diagnostic-format-sarif-file-timevars-2.c | 21 +++ gcc/timevar.cc | 164 +++++++++++++++++- gcc/timevar.h | 5 + gcc/toplev.cc | 10 +- gcc/tree-diagnostic-client-data-hooks.cc | 18 +- 11 files changed, 330 insertions(+), 17 deletions(-) create mode 100644 gcc/diagnostic-format-sarif.h create mode 100644 gcc/testsuite/c-c++-common/diagnostic-format-sarif-file-timevars-1.c create mode 100644 gcc/testsuite/c-c++-common/diagnostic-format-sarif-file-timevars-2.c diff --git a/gcc/common.opt b/gcc/common.opt index e558385c7f4..cf1f696cac2 100644 --- a/gcc/common.opt +++ b/gcc/common.opt @@ -2519,6 +2519,10 @@ frename-registers Common Var(flag_rename_registers) Optimization EnabledBy(funroll-loops) Perform a register renaming optimization pass. +fsarif-time-report +Common Var(sarif_time_report) +Report the time taken by each compiler pass in any SARIF output. + fschedule-fusion Common Var(flag_schedule_fusion) Init(2) Optimization Perform a target dependent instruction fusion optimization pass. diff --git a/gcc/diagnostic-client-data-hooks.h b/gcc/diagnostic-client-data-hooks.h index 5f8b9a25294..e3f2d056207 100644 --- a/gcc/diagnostic-client-data-hooks.h +++ b/gcc/diagnostic-client-data-hooks.h @@ -21,6 +21,7 @@ along with GCC; see the file COPYING3. If not see #ifndef GCC_DIAGNOSTIC_CLIENT_DATA_HOOKS_H #define GCC_DIAGNOSTIC_CLIENT_DATA_HOOKS_H +class sarif_object; class client_version_info; /* A bundle of additional metadata, owned by the diagnostic_context, @@ -41,6 +42,11 @@ class diagnostic_client_data_hooks See SARIF v2.1.0 Appendix J for suggested values. */ virtual const char * maybe_get_sarif_source_language (const char *filename) const = 0; + + /* Hook to allow client to populate a SARIF "invocation" object with + a custom property bag (see SARIF v2.1.0 section 3.8). */ + virtual void + add_sarif_invocation_properties (sarif_object &invocation_obj) const = 0; }; /* Factory function for making an instance of diagnostic_client_data_hooks diff --git a/gcc/diagnostic-format-sarif.cc b/gcc/diagnostic-format-sarif.cc index fd29ac2ca3b..f88f429be58 100644 --- a/gcc/diagnostic-format-sarif.cc +++ b/gcc/diagnostic-format-sarif.cc @@ -29,13 +29,14 @@ along with GCC; see the file COPYING3. If not see #include "cpplib.h" #include "logical-location.h" #include "diagnostic-client-data-hooks.h" +#include "diagnostic-format-sarif.h" class sarif_builder; /* Subclass of json::object for SARIF invocation objects (SARIF v2.1.0 section 3.20). */ -class sarif_invocation : public json::object +class sarif_invocation : public sarif_object { public: sarif_invocation () @@ -46,17 +47,17 @@ public: void add_notification_for_ice (diagnostic_context *context, diagnostic_info *diagnostic, sarif_builder *builder); - void prepare_to_flush (); + void prepare_to_flush (diagnostic_context *context); private: json::array *m_notifications_arr; bool m_success; }; -/* Subclass of json::object for SARIF result objects +/* Subclass of sarif_object for SARIF result objects (SARIF v2.1.0 section 3.27). */ -class sarif_result : public json::object +class sarif_result : public sarif_object { public: sarif_result () : m_related_locations_arr (NULL) {} @@ -71,13 +72,13 @@ private: json::array *m_related_locations_arr; }; -/* Subclass of json::object for SARIF notification objects +/* Subclass of sarif_object for SARIF notification objects (SARIF v2.1.0 section 3.58). This subclass is specifically for notifying when an internal compiler error occurs. */ -class sarif_ice_notification : public json::object +class sarif_ice_notification : public sarif_object { public: sarif_ice_notification (diagnostic_context *context, @@ -220,7 +221,24 @@ private: static sarif_builder *the_builder; -/* class sarif_invocation : public json::object. */ +/* class sarif_object : public json::object. */ + +sarif_property_bag & +sarif_object::get_or_create_properties () +{ + json::value *properties_val = get ("properties"); + if (properties_val) + { + if (properties_val->get_kind () == json::JSON_OBJECT) + return *static_cast (properties_val); + } + + sarif_property_bag *bag = new sarif_property_bag (); + set ("properties", bag); + return *bag; +} + +/* class sarif_invocation : public sarif_object. */ /* Handle an internal compiler error DIAGNOSTIC occurring on CONTEXT. Add an object representing the ICE to the notifications array. */ @@ -238,16 +256,21 @@ sarif_invocation::add_notification_for_ice (diagnostic_context *context, } void -sarif_invocation::prepare_to_flush () +sarif_invocation::prepare_to_flush (diagnostic_context *context) { /* "executionSuccessful" property (SARIF v2.1.0 section 3.20.14). */ set ("executionSuccessful", new json::literal (m_success)); /* "toolExecutionNotifications" property (SARIF v2.1.0 section 3.20.21). */ set ("toolExecutionNotifications", m_notifications_arr); + + /* Call client hook, allowing it to create a custom property bag for + this object (SARIF v2.1.0 section 3.8) e.g. for recording time vars. */ + if (context->m_client_data_hooks) + context->m_client_data_hooks->add_sarif_invocation_properties (*this); } -/* class sarif_result : public json::object. */ +/* class sarif_result : public sarif_object. */ /* Handle secondary diagnostics that occur within a diagnostic group. The closest SARIF seems to have to nested diagnostics is the @@ -280,7 +303,7 @@ sarif_result::on_nested_diagnostic (diagnostic_context *context, m_related_locations_arr->append (location_obj); } -/* class sarif_ice_notification : public json::object. */ +/* class sarif_ice_notification : public sarif_object. */ /* sarif_ice_notification's ctor. DIAGNOSTIC is an internal compiler error. */ @@ -364,7 +387,7 @@ sarif_builder::end_group () void sarif_builder::flush_to_file (FILE *outf) { - m_invocation_obj->prepare_to_flush (); + m_invocation_obj->prepare_to_flush (m_context); json::object *top = make_top_level_object (m_invocation_obj, m_results_array); top->dump (outf); m_invocation_obj = NULL; diff --git a/gcc/diagnostic-format-sarif.h b/gcc/diagnostic-format-sarif.h new file mode 100644 index 00000000000..82ed9b9ee44 --- /dev/null +++ b/gcc/diagnostic-format-sarif.h @@ -0,0 +1,45 @@ +/* SARIF output for diagnostics. + Copyright (C) 2023 Free Software Foundation, Inc. + Contributed by David Malcolm . + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#ifndef GCC_DIAGNOSTIC_FORMAT_SARIF_H +#define GCC_DIAGNOSTIC_FORMAT_SARIF_H + +#include "json.h" + +/* Concrete subclass of json::object for SARIF property bags + (SARIF v2.1.0 section 3.8). */ + +class sarif_property_bag : public json::object +{ +}; + +/* Concrete subclass of json::object for SARIF objects that can + contain property bags (as per SARIF v2.1.0 section 3.8.1, which has: + "In addition to those properties that are explicitly documented, every + object defined in this document MAY contain a property named properties + whose value is a property bag.") */ + +class sarif_object : public json::object +{ +public: + sarif_property_bag &get_or_create_properties (); +}; + +#endif /* ! GCC_DIAGNOSTIC_FORMAT_SARIF_H */ diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index def2df4584b..f43ba4f9dd5 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -745,7 +745,7 @@ Objective-C and Objective-C++ Dialects}. -fmem-report -fpre-ipa-mem-report -fpost-ipa-mem-report -fopt-info -fopt-info-@var{options}@r{[}=@var{file}@r{]} -fmultiflags -fprofile-report --frandom-seed=@var{string} -fsched-verbose=@var{n} +-frandom-seed=@var{string} -fsarif-time-report -fsched-verbose=@var{n} -fsel-sched-verbose -fsel-sched-dump-cfg -fsel-sched-pipelining-verbose -fstats -fstack-usage -ftime-report -ftime-report-details -fvar-tracking-assignments-toggle -gtoggle @@ -19631,6 +19631,15 @@ computing CRC32). The @var{string} should be different for every file you compile. +@opindex fsarif-time-report +@item -fsarif-time-report +Equivalent to @option{-ftime-report}, except the information is emitted +in JSON form as part of SARIF output (such as from +@option{-fdiagnostics-format=sarif-file}). The precise format of the +JSON data is subject to change, and the values may not exactly match those +emitted by @option{-ftime-report} due to being written out at a slightly +different place within the compiler. + @opindex save-temps @item -save-temps Store the usual ``temporary'' intermediate files permanently; name them diff --git a/gcc/testsuite/c-c++-common/diagnostic-format-sarif-file-timevars-1.c b/gcc/testsuite/c-c++-common/diagnostic-format-sarif-file-timevars-1.c new file mode 100644 index 00000000000..2b87aed8147 --- /dev/null +++ b/gcc/testsuite/c-c++-common/diagnostic-format-sarif-file-timevars-1.c @@ -0,0 +1,18 @@ +/* { dg-do compile } */ +/* { dg-options "-fdiagnostics-format=sarif-file -fsarif-time-report" } */ + +#warning message + +/* Verify that some JSON was written to a file with the expected name. */ +/* { dg-final { verify-sarif-file } } */ + +/* We expect various properties. + The indentation here reflects the expected hierarchy, though these tests + don't check for that, merely the string fragments we expect. + + { dg-final { scan-sarif-file {"invocations": } } } + { dg-final { scan-sarif-file {"properties": } } } + { dg-final { scan-sarif-file {"gcc/timeReport": } } } + { dg-final { scan-sarif-file {"timevars": } } } + { dg-final { scan-sarif-file {"name": "TOTAL",} } } +*/ diff --git a/gcc/testsuite/c-c++-common/diagnostic-format-sarif-file-timevars-2.c b/gcc/testsuite/c-c++-common/diagnostic-format-sarif-file-timevars-2.c new file mode 100644 index 00000000000..fa48171aacd --- /dev/null +++ b/gcc/testsuite/c-c++-common/diagnostic-format-sarif-file-timevars-2.c @@ -0,0 +1,21 @@ +/* As per diagnostic-format-sarif-file-timevars-1.c, but + adding -ftime-report-details. */ + +/* { dg-do compile } */ +/* { dg-options "-fdiagnostics-format=sarif-file -fsarif-time-report -ftime-report-details" } */ + +#warning message + +/* Verify that some JSON was written to a file with the expected name. */ +/* { dg-final { verify-sarif-file } } */ + +/* We expect various properties. + The indentation here reflects the expected hierarchy, though these tests + don't check for that, merely the string fragments we expect. + + { dg-final { scan-sarif-file {"invocations": } } } + { dg-final { scan-sarif-file {"properties": } } } + { dg-final { scan-sarif-file {"gcc/timeReport": } } } + { dg-final { scan-sarif-file {"timevars": } } } + { dg-final { scan-sarif-file {"name": "TOTAL",} } } +*/ diff --git a/gcc/timevar.cc b/gcc/timevar.cc index d695297aae7..5368ff06ac9 100644 --- a/gcc/timevar.cc +++ b/gcc/timevar.cc @@ -23,6 +23,7 @@ along with GCC; see the file COPYING3. If not see #include "coretypes.h" #include "timevar.h" #include "options.h" +#include "json.h" #ifndef HAVE_CLOCK_T typedef int clock_t; @@ -135,6 +136,8 @@ class timer::named_items void pop (); void print (FILE *fp, const timevar_time_def *total); + json::value *make_json () const; + private: /* Which timer instance does this relate to? */ timer *m_timer; @@ -143,7 +146,8 @@ class timer::named_items Note that currently we merely store/compare the raw string pointers provided by client code; we don't take a copy, or use strcmp. */ - hash_map m_hash_map; + typedef hash_map hash_map_t; + hash_map_t m_hash_map; /* The order in which items were originally inserted. */ auto_vec m_names; @@ -207,6 +211,23 @@ timer::named_items::print (FILE *fp, const timevar_time_def *total) } } +/* Create a json value representing this object, suitable for use + in SARIF output. */ + +json::value * +timer::named_items::make_json () const +{ + json::array *arr = new json::array (); + for (const char *item_name : m_names) + { + hash_map_t &mut_map = const_cast (m_hash_map); + timer::timevar_def *def = mut_map.get (item_name); + gcc_assert (def); + arr->append (def->make_json ()); + } + return arr; +} + /* Fill the current times into TIME. The definition of this function also defines any or all of the HAVE_USER_TIME, HAVE_SYS_TIME, and HAVE_WALL_TIME macros. */ @@ -251,6 +272,19 @@ timevar_accumulate (struct timevar_time_def *timer, timer->ggc_mem += stop_time->ggc_mem - start_time->ggc_mem; } +/* Get the difference between STOP_TIME and START_TIME. */ + +static void +timevar_diff (struct timevar_time_def *out, + const timevar_time_def &start_time, + const timevar_time_def &stop_time) +{ + out->user = stop_time.user - start_time.user; + out->sys = stop_time.sys - start_time.sys; + out->wall = stop_time.wall - start_time.wall; + out->ggc_mem = stop_time.ggc_mem - start_time.ggc_mem; +} + /* Class timer's constructor. */ timer::timer () : @@ -791,6 +825,134 @@ timer::print (FILE *fp) validate_phases (fp); } +/* Create a json value representing this object, suitable for use + in SARIF output. */ + +json::object * +make_json_for_timevar_time_def (const timevar_time_def &ttd) +{ + json::object *obj = new json::object (); + obj->set ("user", new json::float_number (ttd.user)); + obj->set ("sys", new json::float_number (ttd.sys)); + obj->set ("wall", new json::float_number (ttd.wall)); + obj->set ("ggc_mem", new json::integer_number (ttd.ggc_mem)); + return obj; +} + +/* Create a json value representing this object, suitable for use + in SARIF output. */ + +json::value * +timer::timevar_def::make_json () const +{ + json::object *timevar_obj = new json::object (); + timevar_obj->set ("name", new json::string (name)); + timevar_obj->set ("elapsed", make_json_for_timevar_time_def (elapsed)); + + if (children) + { + bool any_children_with_time = false; + for (auto i : *children) + if (!all_zero (i.second)) + { + any_children_with_time = true; + break; + } + if (any_children_with_time) + { + json::array *children_arr = new json::array (); + timevar_obj->set ("children", children_arr); + for (auto i : *children) + { + /* Don't emit timing variables if we're going to get a row of + zeroes. */ + if (all_zero (i.second)) + continue; + json::object *child_obj = new json::object; + children_arr->append (child_obj); + child_obj->set ("name", new json::string (i.first->name)); + child_obj->set ("elapsed", + make_json_for_timevar_time_def (i.second)); + } + } + } + + return timevar_obj; +} + +/* Create a json value representing this object, suitable for use + in SARIF output. */ + +json::value * +timer::make_json () const +{ + /* Only generate stuff if we have some sort of time information. */ +#if defined (HAVE_USER_TIME) || defined (HAVE_SYS_TIME) || defined (HAVE_WALL_TIME) + json::object *report_obj = new json::object (); + json::array *json_arr = new json::array (); + report_obj->set ("timevars", json_arr); + + for (unsigned id = 0; id < (unsigned int) TIMEVAR_LAST; ++id) + { + const timevar_def *tv = &m_timevars[(timevar_id_t) id]; + + /* Don't print the total execution time here; this isn't initialized + by the time the sarif output runs. */ + if ((timevar_id_t) id == TV_TOTAL) + continue; + + /* Don't emit timing variables that were never used. */ + if (!tv->used) + continue; + + bool any_children_with_time = false; + if (tv->children) + for (child_map_t::iterator i = tv->children->begin (); + i != tv->children->end (); ++i) + if (! all_zero ((*i).second)) + { + any_children_with_time = true; + break; + } + + /* Don't emit timing variables if we're going to get a row of + zeroes. Unless there are children with non-zero time. */ + if (! any_children_with_time + && all_zero (tv->elapsed)) + continue; + + json_arr->append (tv->make_json ()); + } + + /* Special-case for total. */ + { + /* Get our own total up till now, without affecting TV_TOTAL. */ + struct timevar_time_def total_now; + struct timevar_time_def total_elapsed; + get_time (&total_now); + timevar_diff (&total_elapsed, m_timevars[TV_TOTAL].start_time, total_now); + + json::object *total_obj = new json::object(); + json_arr->append (total_obj); + total_obj->set ("name", new json::string ("TOTAL")); + total_obj->set ("elapsed", make_json_for_timevar_time_def (total_elapsed)); + } + + if (m_jit_client_items) + report_obj->set ("client_items", m_jit_client_items->make_json ()); + + report_obj->set ("CHECKING_P", new json::literal ((bool)CHECKING_P)); + report_obj->set ("flag_checking", new json::literal ((bool)flag_checking)); + + return report_obj; + +#else /* defined (HAVE_USER_TIME) || defined (HAVE_SYS_TIME) + || defined (HAVE_WALL_TIME) */ + return NULL; +#endif /* defined (HAVE_USER_TIME) || defined (HAVE_SYS_TIME) + || defined (HAVE_WALL_TIME) */ +} + /* Get the name of the topmost item. For use by jit for validating inputs to gcc_jit_timer_pop. */ const char * diff --git a/gcc/timevar.h b/gcc/timevar.h index ad465731609..e359e9fa1fa 100644 --- a/gcc/timevar.h +++ b/gcc/timevar.h @@ -21,6 +21,8 @@ #ifndef GCC_TIMEVAR_H #define GCC_TIMEVAR_H +namespace json { class value; } + /* Timing variables are used to measure elapsed time in various portions of the compiler. Each measures elapsed user, system, and wall-clock time, as appropriate to and supported by the host @@ -119,6 +121,7 @@ class timer void pop_client_item (); void print (FILE *fp); + json::value *make_json () const; const char *get_topmost_item_name () const; @@ -140,6 +143,8 @@ class timer /* Private type: a timing variable. */ struct timevar_def { + json::value *make_json () const; + /* Elapsed time for this variable. */ struct timevar_time_def elapsed; diff --git a/gcc/toplev.cc b/gcc/toplev.cc index 109c9d58cbd..5847efec346 100644 --- a/gcc/toplev.cc +++ b/gcc/toplev.cc @@ -2151,7 +2151,10 @@ toplev::~toplev () if (g_timer && m_use_TV_TOTAL) { g_timer->stop (TV_TOTAL); - g_timer->print (stderr); + /* -fsarif-time-report doesn't lead to the output being printed + to stderr; the other flags do. */ + if (time_report || !quiet_flag || flag_detailed_statistics) + g_timer->print (stderr); delete g_timer; g_timer = NULL; } @@ -2163,7 +2166,10 @@ toplev::~toplev () void toplev::start_timevars () { - if (time_report || !quiet_flag || flag_detailed_statistics) + if (time_report + || sarif_time_report + || !quiet_flag + || flag_detailed_statistics) timevar_init (); timevar_start (TV_TOTAL); diff --git a/gcc/tree-diagnostic-client-data-hooks.cc b/gcc/tree-diagnostic-client-data-hooks.cc index 1a35f4cb122..63e8500435a 100644 --- a/gcc/tree-diagnostic-client-data-hooks.cc +++ b/gcc/tree-diagnostic-client-data-hooks.cc @@ -1,5 +1,5 @@ /* Implementation of diagnostic_client_data_hooks for the compilers - (e.g. with knowledge of "tree" and lang_hooks). + (e.g. with knowledge of "tree", lang_hooks, and timevars). Copyright (C) 2022-2023 Free Software Foundation, Inc. Contributed by David Malcolm . @@ -27,8 +27,10 @@ along with GCC; see the file COPYING3. If not see #include "diagnostic.h" #include "tree-logical-location.h" #include "diagnostic-client-data-hooks.h" +#include "diagnostic-format-sarif.h" #include "langhooks.h" #include "plugin.h" +#include "timevar.h" /* Concrete class for supplying a diagnostic_context with information about a specific plugin within the client, when the client is the @@ -111,7 +113,7 @@ private: }; /* Subclass of diagnostic_client_data_hooks for use by compilers proper - i.e. with knowledge of "tree", access to langhooks, etc. */ + i.e. with knowledge of "tree", access to langhooks, timevars etc. */ class compiler_data_hooks : public diagnostic_client_data_hooks { @@ -135,6 +137,18 @@ public: return lang_hooks.get_sarif_source_language (filename); } + void + add_sarif_invocation_properties (sarif_object &invocation_obj) + const final override + { + if (g_timer && sarif_time_report) + if (json::value *timereport_val = g_timer->make_json ()) + { + sarif_property_bag &bag_obj = invocation_obj.get_or_create_properties (); + bag_obj.set ("gcc/timeReport", timereport_val); + } + } + private: compiler_version_info m_version_info; current_fndecl_logical_location m_current_fndecl_logical_loc;