public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc r14-2881] SARIF and -ftime-report's output [PR109361]
@ 2023-07-31 15:28 David Malcolm
  0 siblings, 0 replies; only message in thread
From: David Malcolm @ 2023-07-31 15:28 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:75d623946d4b6ea80a777b789b116d4b4a2298dc

commit r14-2881-g75d623946d4b6ea80a777b789b116d4b4a2298dc
Author: David Malcolm <dmalcolm@redhat.com>
Date:   Mon Jul 31 11:13:02 2023 -0400

    SARIF and -ftime-report's output [PR109361]
    
    This patch adds support for embeddding profiling information about the
    compiler itself into the SARIF output.
    
    Specifically, if SARIF diagnostic output is requested, via
    -fdiagnostics-format=sarif-file or -fdiagnostics-format=sarif-stderr,
    then any -ftime-report output is written in JSON form into the SARIF
    output, rather than to stderr.
    
    In earlier versions 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 fouling my build scripts).
    
    The timing information is written to the 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
                  }
              }
          }
      ]
    
    The documentation notes that the precise output format is subject
    to change.
    
    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.
    
    gcc/ChangeLog:
            PR analyzer/109361
            * 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): Clarify that -ftime-report
            writes to stderr.  Document that if SARIF diagnostic output is
            requested then any timing information is written in JSON form as
            part of the SARIF output, rather than to stderr.
            * 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.
            * 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>

Diff:
---
 gcc/diagnostic-client-data-hooks.h                 |   6 +
 gcc/diagnostic-format-sarif.cc                     |  45 ++++--
 gcc/diagnostic-format-sarif.h                      |  45 ++++++
 gcc/doc/invoke.texi                                |  12 +-
 .../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/tree-diagnostic-client-data-hooks.cc           |  26 +++-
 9 files changed, 326 insertions(+), 16 deletions(-)

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 5e483988027..1eff71962d7 100644
--- a/gcc/diagnostic-format-sarif.cc
+++ b/gcc/diagnostic-format-sarif.cc
@@ -32,13 +32,14 @@ along with GCC; see the file COPYING3.  If not see
 #include "diagnostic-client-data-hooks.h"
 #include "diagnostic-diagram.h"
 #include "text-art/canvas.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 ()
@@ -49,17 +50,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) {}
@@ -79,13 +80,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,
@@ -232,7 +233,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.  */
@@ -250,16 +268,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
@@ -319,7 +342,7 @@ sarif_result::add_related_location (json::object *location_obj)
   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.  */
@@ -415,7 +438,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 578b4c31e4c..c43260f8b35 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -19933,8 +19933,16 @@ print some statistics about each pass when it finishes.
 
 @opindex ftime-report
 @item -ftime-report
-Makes the compiler print some statistics about the time consumed by each
-pass when it finishes.
+Makes the compiler print some statistics to stderr about the time consumed
+by each pass when it finishes.
+
+If SARIF output of diagnostics was requested via
+@option{-fdiagnostics-format=sarif-file} or
+@option{-fdiagnostics-format=sarif-stderr} then the @option{-ftime-report}
+information is instead emitted in JSON form as part of SARIF output.  The
+precise format of this JSON data is subject to change, and the values may
+not exactly match those emitted to stderr due to being written out at a
+slightly different place within the compiler.
 
 @opindex ftime-report-details
 @item -ftime-report-details
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..be6b1e76bd4
--- /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 -ftime-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..e9c2b5e072e
--- /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 -ftime-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/tree-diagnostic-client-data-hooks.cc b/gcc/tree-diagnostic-client-data-hooks.cc
index 1a35f4cb122..fc972ce0e13 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,26 @@ public:
     return lang_hooks.get_sarif_source_language (filename);
   }
 
+  void
+  add_sarif_invocation_properties (sarif_object &invocation_obj)
+    const final override
+  {
+    if (g_timer)
+      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);
+
+	  /* If the user requested SARIF output, then assume they want the
+	     time report data in the SARIF output, and *not* later emitted on
+	     stderr.
+	     Implement this by cleaning up the global timer instance now.  */
+	  delete g_timer;
+	  g_timer = NULL;
+	}
+  }
+
 private:
   compiler_version_info m_version_info;
   current_fndecl_logical_location m_current_fndecl_logical_loc;

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2023-07-31 15:28 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-07-31 15:28 [gcc r14-2881] SARIF and -ftime-report's output [PR109361] David Malcolm

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