public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
From: Richard Biener <rguenther@suse.de>
To: David Malcolm <dmalcolm@redhat.com>
Cc: gcc-patches@gcc.gnu.org, Jakub Jelinek <jakub@redhat.com>
Subject: Re: [PATCH] Add -fsarif-time-report [PR109361]
Date: Tue, 11 Apr 2023 08:43:40 +0000 (UTC)	[thread overview]
Message-ID: <nycvar.YFH.7.77.849.2304110838230.4466@jbgna.fhfr.qr> (raw)
In-Reply-To: <20230404170857.608270-1-dmalcolm@redhat.com>

On Tue, 4 Apr 2023, David Malcolm wrote:

> 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.

Please wait for stage1 at this point.  One comment on the patch
below ...

> 
> 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.

'sarif' is currently used only with -fdiagnostics-format= it seems.
We already have

ftime-report
Common Var(time_report)
Report the time taken by each compiler pass.

ftime-report-details
Common Var(time_report_details)
Record times taken by sub-phases separately. 

so -fsarif-time-report is not a) -ftime-report-sarif and b) it's
unclear if it applies to -ftime-report or to both -ftime-report
and -ftime-report-details?  (note -ftime-report-details needs
-ftime-report to be effective)

I'd rather have a -ftime-report-format= (or -freport-format in
case we want to cover -fmem-report, -fmem-report-wpa,
-fpre-ipa-mem-report and -fpost-ipa-mem-report as well?)

ISTR there's a summer of code project in this are as well.

Thanks,
Richard.

> 	* 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 <dmalcolm@redhat.com>
> ---
>  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 <sarif_property_bag *> (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 <dmalcolm@redhat.com>.
> +
> +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
> +<http://www.gnu.org/licenses/>.  */
> +
> +#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 <const char *, timer::timevar_def> m_hash_map;
> +  typedef hash_map <const char *, timer::timevar_def> hash_map_t;
> +  hash_map_t m_hash_map;
>  
>    /* The order in which items were originally inserted.  */
>    auto_vec <const char *> 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 <hash_map_t &> (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 <dmalcolm@redhat.com>.
>  
> @@ -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;
> 

-- 
Richard Biener <rguenther@suse.de>
SUSE Software Solutions Germany GmbH, Frankenstrasse 146, 90461 Nuernberg,
Germany; GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman;
HRB 36809 (AG Nuernberg)

  reply	other threads:[~2023-04-11  8:43 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-04-04 17:08 David Malcolm
2023-04-11  8:43 ` Richard Biener [this message]
2023-07-27 22:22   ` David Malcolm
2023-07-28  6:00     ` Richard Biener
2023-07-28 20:19       ` [PATCH v2] SARIF and -ftime-report's output [PR109361] David Malcolm
2023-07-31  7:06         ` Richard Biener

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=nycvar.YFH.7.77.849.2304110838230.4466@jbgna.fhfr.qr \
    --to=rguenther@suse.de \
    --cc=dmalcolm@redhat.com \
    --cc=gcc-patches@gcc.gnu.org \
    --cc=jakub@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).