On Fri, 28 Jul 2023, David Malcolm wrote: > On Fri, 2023-07-28 at 08:00 +0200, Richard Biener wrote: > > On Fri, Jul 28, 2023 at 12:23?AM David Malcolm via Gcc-patches > > <gcc-patches@gcc.gnu.org> wrote: > > > > > > On Tue, 2023-04-11 at 08:43 +0000, Richard Biener wrote: > > > > 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. > > [...snip...] > > > > > > > > > '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. > > > > > > Revisiting this; sorry about the delay. > > > > > > As I understand the status quo, we currently have: > > > * -ftime-report: enable capturing of timing information (with a > > > slight > > > speed hit), and report it to stderr > > > * -ftime-report-details: tweak how that information is captured (if > > > - > > > ftime-report is enabled), so that timevar->children is populated > > > and > > > printed > > > > > > There seem to be two things here: > > > - what timing data we capture > > > - where that timing data goes > > > > > > What I need is to some way to specify that the output should go to > > > the > > > SARIF file, rather than to stderr. > > > > > > Some ways we could do this: > > > (a) simply enforce that if SARIF diagnostics were requested with - > > > fdiagnostics-format=sarif-{file|stderr} that the time report goes > > > there > > > in JSON form, rather than to stderr > > > (b) add an option to specify where the time report goes > > > (c) add options to allow the time report to potentially go to > > > multiple > > > places (both stderr and SARIF, one or the other, neither); this > > > seems > > > overcomplex to me. > > > (d) something else? > > > > > > The patch I posted implements a form of (b), but right now I'm > > > leaning > > > towards option (a): if the user requested SARIF output, then the > > > time > > > report goes to the SARIF output, rather than stderr. > > > > I'm fine with (a), but -fdiagnostics-format= doesn't naturally apply > > to > > -ftime-report (or -fmem-report), those are not "diagnostics" in my > > opinion but they are auxiliary data for the compilation process > > rather than the input to it. But yes, -ftime-report-format= would be > > too specific, maybe -faux-format=. > > > > That said, we can go with (a) and do something else later if desired. > > I don't think preserving behavior in this area will be important so > > we > > don't have to get it right immediately. > > Thanks. > > Here's an updated version of the patch which implements (a). > > Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu. > As before, I've tested this with my analyzer integration testsuite and > was able to use the .sarif data to generate reports about which source > files get slowed down by the analyzer [1]. I've validated the generated > .sarif files against the SARIF schema. > > OK for trunk?
OK. Thanks, Richard. > Dave > [1] https://github.com/davidmalcolm/gcc-analyzer-integration-tests/issues/5 > > > 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. > > 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 <dmalc...@redhat.com> > --- > 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(-) > 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/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 <dmalc...@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 fa765d5a0dd..5ea45c6566d 100644 > --- a/gcc/doc/invoke.texi > +++ b/gcc/doc/invoke.texi > @@ -19932,8 +19932,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 <dmalc...@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; > -- Richard Biener <rguent...@suse.de> SUSE Software Solutions Germany GmbH, Frankenstrasse 146, 90461 Nuernberg, Germany; GF: Ivo Totev, Andrew McDonald, Werner Knoblich; (HRB 36809, AG Nuernberg)