public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc r14-4006] diagnostics: support multithreaded diagnostic paths
@ 2023-09-14 20:29 David Malcolm
0 siblings, 0 replies; only message in thread
From: David Malcolm @ 2023-09-14 20:29 UTC (permalink / raw)
To: gcc-cvs
https://gcc.gnu.org/g:3a1e9f3ed7aa49adad02190ace0614e0b37fc089
commit r14-4006-g3a1e9f3ed7aa49adad02190ace0614e0b37fc089
Author: David Malcolm <dmalcolm@redhat.com>
Date: Thu Sep 14 16:28:45 2023 -0400
diagnostics: support multithreaded diagnostic paths
This patch extends the existing diagnostic_path class so that as well
as list of events, there is a list of named threads, with each event
being associated with one of the threads.
No GCC diagnostics take advantage of this, but GCC plugins may find a
use for this; an example is provided in the testsuite.
Given that there is still a single list of events within a
diagnostic_path, the events in a diagnostic_path have a specific global
ordering even if they are in multiple threads.
Within the SARIF serialization, the patch adds the "executionOrder"
property to threadFlowLocation objects (SARIF v2.1.0 3.38.11). This is
1-based in order to match the human-readable numbering of events shown
in messages emitted by pretty-printer.cc's "%@".
With -fdiagnostics-path-format=separate-events, the threads are not
shown.
With -fdiagnostics-path-format=inline-events, the threads and the
per-thread stack activity are tracked and visalized separately. An
example can be seen in the testsuite.
gcc/analyzer/ChangeLog:
* checker-event.h (checker_event::get_thread_id): New.
* checker-path.h (class checker_path): Implement thread-related
vfuncs via a single simple_diagnostic_thread instance named
"main".
gcc/ChangeLog:
* diagnostic-event-id.h (diagnostic_thread_id_t): New typedef.
* diagnostic-format-sarif.cc (class sarif_thread_flow): New.
(sarif_thread_flow::sarif_thread_flow): New.
(sarif_builder::make_code_flow_object): Reimplement, creating
per-thread threadFlow objects, populating them with the relevant
events.
(sarif_builder::make_thread_flow_object): Delete, moving the
code into sarif_builder::make_code_flow_object.
(sarif_builder::make_thread_flow_location_object): Add
"path_event_idx" param. Use it to set "executionOrder"
property.
* diagnostic-path.h (diagnostic_event::get_thread_id): New
pure-virtual vfunc.
(class diagnostic_thread): New.
(diagnostic_path::num_threads): New pure-virtual vfunc.
(diagnostic_path::get_thread): New pure-virtual vfunc.
(diagnostic_path::multithreaded_p): New decl.
(simple_diagnostic_event::simple_diagnostic_event): Add optional
thread_id param.
(simple_diagnostic_event::get_thread_id): New accessor.
(simple_diagnostic_event::m_thread_id): New.
(class simple_diagnostic_thread): New.
(simple_diagnostic_path::simple_diagnostic_path): Move definition
to diagnostic.cc.
(simple_diagnostic_path::num_threads): New.
(simple_diagnostic_path::get_thread): New.
(simple_diagnostic_path::add_thread): New.
(simple_diagnostic_path::add_thread_event): New.
(simple_diagnostic_path::m_threads): New.
* diagnostic-show-locus.cc (layout::layout): Add pretty_printer
param for overriding the context's printer.
(diagnostic_show_locus): Likwise.
* diagnostic.cc (simple_diagnostic_path::simple_diagnostic_path):
Move here from diagnostic-path.h. Add main thread.
(simple_diagnostic_path::num_threads): New.
(simple_diagnostic_path::get_thread): New.
(simple_diagnostic_path::add_thread): New.
(simple_diagnostic_path::add_thread_event): New.
(simple_diagnostic_event::simple_diagnostic_event): Add thread_id
param and use it to initialize m_thread_id. Reformat.
* diagnostic.h: Add pretty_printer param for overriding the
context's printer.
* tree-diagnostic-path.cc: Add #define INCLUDE_VECTOR.
(can_consolidate_events): Compare thread ids.
(class per_thread_summary): New.
(event_range::event_range): Add per_thread_summary arg.
(event_range::print): Add "pp" param and use it rather than dc's
printer.
(event_range::m_thread_id): New field.
(event_range::m_per_thread_summary): New field.
(path_summary::multithreaded_p): New.
(path_summary::get_events_for_thread_id): New.
(path_summary::m_per_thread_summary): New field.
(path_summary::m_thread_id_to_events): New field.
(path_summary::get_or_create_events_for_thread_id): New.
(path_summary::path_summary): Create per_thread_summary instances
as needed and associate the event_range instances with them.
(base_indent): Move here from print_path_summary_as_text.
(per_frame_indent): Likewise.
(class thread_event_printer): New, adapted from parts of
print_path_summary_as_text.
(print_path_summary_as_text): Make static. Reimplement to
moving most of existing code to class thread_event_printer,
capturing state as per-thread as appropriate.
(default_tree_diagnostic_path_printer): Add missing 'break' on
final case.
gcc/testsuite/ChangeLog:
* gcc.dg/plugin/diagnostic-test-paths-multithreaded-inline-events.c:
New test.
* gcc.dg/plugin/diagnostic-test-paths-multithreaded-sarif.c: New
test.
* gcc.dg/plugin/diagnostic-test-paths-multithreaded-separate-events.c:
New test.
* gcc.dg/plugin/diagnostic_plugin_test_paths.c: Add support for
generating multithreaded paths.
* gcc.dg/plugin/plugin.exp: Add the new tests.
Signed-off-by: David Malcolm <dmalcolm@redhat.com>
Diff:
---
gcc/analyzer/checker-event.h | 4 +
gcc/analyzer/checker-path.h | 17 +-
gcc/diagnostic-event-id.h | 5 +
gcc/diagnostic-format-sarif.cc | 86 ++--
gcc/diagnostic-path.h | 55 ++-
gcc/diagnostic-show-locus.cc | 16 +-
gcc/diagnostic.cc | 78 +++-
gcc/diagnostic.h | 3 +-
...nostic-test-paths-multithreaded-inline-events.c | 72 ++++
.../diagnostic-test-paths-multithreaded-sarif.c | 35 ++
...stic-test-paths-multithreaded-separate-events.c | 18 +
.../gcc.dg/plugin/diagnostic_plugin_test_paths.c | 94 ++++-
gcc/testsuite/gcc.dg/plugin/plugin.exp | 3 +
gcc/tree-diagnostic-path.cc | 432 ++++++++++++++-------
14 files changed, 734 insertions(+), 184 deletions(-)
diff --git a/gcc/analyzer/checker-event.h b/gcc/analyzer/checker-event.h
index 5dd25cb0775..7ba92f19650 100644
--- a/gcc/analyzer/checker-event.h
+++ b/gcc/analyzer/checker-event.h
@@ -113,6 +113,10 @@ public:
return NULL;
}
meaning get_meaning () const override;
+ diagnostic_thread_id_t get_thread_id () const final override
+ {
+ return 0;
+ }
/* Additional functionality. */
diff --git a/gcc/analyzer/checker-path.h b/gcc/analyzer/checker-path.h
index 627f64e5320..93c807c3d24 100644
--- a/gcc/analyzer/checker-path.h
+++ b/gcc/analyzer/checker-path.h
@@ -30,7 +30,11 @@ namespace ana {
class checker_path : public diagnostic_path
{
public:
- checker_path (logger *logger) : diagnostic_path (), m_logger (logger) {}
+ checker_path (logger *logger)
+ : diagnostic_path (),
+ m_thread ("main"),
+ m_logger (logger)
+ {}
/* Implementation of diagnostic_path vfuncs. */
@@ -43,6 +47,15 @@ public:
{
return *m_events[idx];
}
+ unsigned num_threads () const final override
+ {
+ return 1;
+ }
+ const diagnostic_thread &
+ get_thread (diagnostic_thread_id_t) const final override
+ {
+ return m_thread;
+ }
checker_event *get_checker_event (int idx)
{
@@ -120,6 +133,8 @@ public:
private:
DISABLE_COPY_AND_ASSIGN(checker_path);
+ simple_diagnostic_thread m_thread;
+
/* The events that have occurred along this path. */
auto_delete_vec<checker_event> m_events;
diff --git a/gcc/diagnostic-event-id.h b/gcc/diagnostic-event-id.h
index 84f4b65611e..c5f5d60ddc1 100644
--- a/gcc/diagnostic-event-id.h
+++ b/gcc/diagnostic-event-id.h
@@ -58,4 +58,9 @@ class diagnostic_event_id_t
The %@ format code requires that known_p be true for the event ID. */
typedef diagnostic_event_id_t *diagnostic_event_id_ptr;
+/* A type for compactly referring to a particular thread within a
+ diagnostic_path. Typically there is just one thread per path,
+ with id 0. */
+typedef unsigned diagnostic_thread_id_t;
+
#endif /* ! GCC_DIAGNOSTIC_EVENT_ID_H */
diff --git a/gcc/diagnostic-format-sarif.cc b/gcc/diagnostic-format-sarif.cc
index 1eff71962d7..f56c4ce033d 100644
--- a/gcc/diagnostic-format-sarif.cc
+++ b/gcc/diagnostic-format-sarif.cc
@@ -94,6 +94,23 @@ public:
sarif_builder *builder);
};
+/* Subclass of sarif_object for SARIF threadFlow objects
+ (SARIF v2.1.0 section 3.37) for PATH. */
+
+class sarif_thread_flow : public sarif_object
+{
+public:
+ sarif_thread_flow (const diagnostic_thread &thread);
+
+ void add_location (json::object *thread_flow_loc_obj)
+ {
+ m_locations_arr->append (thread_flow_loc_obj);
+ }
+
+private:
+ json::array *m_locations_arr;
+};
+
/* A class for managing SARIF output (for -fdiagnostics-format=sarif-stderr
and -fdiagnostics-format=sarif-file).
@@ -168,9 +185,9 @@ private:
json::object *
make_logical_location_object (const logical_location &logical_loc) const;
json::object *make_code_flow_object (const diagnostic_path &path);
- json::object *make_thread_flow_object (const diagnostic_path &path);
json::object *
- make_thread_flow_location_object (const diagnostic_event &event);
+ make_thread_flow_location_object (const diagnostic_event &event,
+ int path_event_idx);
json::array *maybe_make_kinds_array (diagnostic_event::meaning m) const;
json::object *maybe_make_physical_location_object (location_t loc);
json::object *make_artifact_location_object (location_t loc);
@@ -365,6 +382,19 @@ sarif_ice_notification::sarif_ice_notification (diagnostic_context *context,
set ("level", new json::string ("error"));
}
+/* class sarif_thread_flow : public sarif_object. */
+
+sarif_thread_flow::sarif_thread_flow (const diagnostic_thread &thread)
+{
+ /* "id" property (SARIF v2.1.0 section 3.37.2). */
+ label_text name (thread.get_name (false));
+ set ("id", new json::string (name.get ()));
+
+ /* "locations" property (SARIF v2.1.0 section 3.37.6). */
+ m_locations_arr = new json::array ();
+ set ("locations", m_locations_arr);
+}
+
/* class sarif_builder. */
/* sarif_builder's ctor. */
@@ -1091,41 +1121,44 @@ sarif_builder::make_code_flow_object (const diagnostic_path &path)
{
json::object *code_flow_obj = new json::object ();
- /* "threadFlows" property (SARIF v2.1.0 section 3.36.3).
- Currently we only support one thread per result. */
+ /* "threadFlows" property (SARIF v2.1.0 section 3.36.3). */
json::array *thread_flows_arr = new json::array ();
- json::object *thread_flow_obj = make_thread_flow_object (path);
- thread_flows_arr->append (thread_flow_obj);
- code_flow_obj->set ("threadFlows", thread_flows_arr);
- return code_flow_obj;
-}
-
-/* Make a threadFlow object (SARIF v2.1.0 section 3.37) for PATH. */
-
-json::object *
-sarif_builder::make_thread_flow_object (const diagnostic_path &path)
-{
- json::object *thread_flow_obj = new json::object ();
-
- /* "locations" property (SARIF v2.1.0 section 3.37.6). */
- json::array *locations_arr = new json::array ();
+ /* Walk the events, consolidating into per-thread threadFlow objects,
+ using the index with PATH as the overall executionOrder. */
+ hash_map<int_hash<diagnostic_thread_id_t, -1, -2>,
+ sarif_thread_flow *> thread_id_map;
for (unsigned i = 0; i < path.num_events (); i++)
{
const diagnostic_event &event = path.get_event (i);
+ const diagnostic_thread_id_t thread_id = event.get_thread_id ();
+ sarif_thread_flow *thread_flow_obj;
+
+ if (sarif_thread_flow **slot = thread_id_map.get (thread_id))
+ thread_flow_obj = *slot;
+ else
+ {
+ const diagnostic_thread &thread = path.get_thread (thread_id);
+ thread_flow_obj = new sarif_thread_flow (thread);
+ thread_flows_arr->append (thread_flow_obj);
+ thread_id_map.put (thread_id, thread_flow_obj);
+ }
+
+ /* Add event to thread's threadFlow object. */
json::object *thread_flow_loc_obj
- = make_thread_flow_location_object (event);
- locations_arr->append (thread_flow_loc_obj);
+ = make_thread_flow_location_object (event, i);
+ thread_flow_obj->add_location (thread_flow_loc_obj);
}
- thread_flow_obj->set ("locations", locations_arr);
+ code_flow_obj->set ("threadFlows", thread_flows_arr);
- return thread_flow_obj;
+ return code_flow_obj;
}
/* Make a threadFlowLocation object (SARIF v2.1.0 section 3.38) for EVENT. */
json::object *
-sarif_builder::make_thread_flow_location_object (const diagnostic_event &ev)
+sarif_builder::make_thread_flow_location_object (const diagnostic_event &ev,
+ int path_event_idx)
{
json::object *thread_flow_loc_obj = new json::object ();
@@ -1142,6 +1175,11 @@ sarif_builder::make_thread_flow_location_object (const diagnostic_event &ev)
thread_flow_loc_obj->set ("nestingLevel",
new json::integer_number (ev.get_stack_depth ()));
+ /* "executionOrder" property (SARIF v2.1.0 3.38.11).
+ Offset by 1 to match the human-readable values emitted by %@. */
+ thread_flow_loc_obj->set ("executionOrder",
+ new json::integer_number (path_event_idx + 1));
+
/* It might be nice to eventually implement the following for -fanalyzer:
- the "stack" property (SARIF v2.1.0 section 3.38.5)
- the "state" property (SARIF v2.1.0 section 3.38.9)
diff --git a/gcc/diagnostic-path.h b/gcc/diagnostic-path.h
index 9d9d6296eb0..d39872abb9f 100644
--- a/gcc/diagnostic-path.h
+++ b/gcc/diagnostic-path.h
@@ -155,6 +155,20 @@ class diagnostic_event
virtual const logical_location *get_logical_location () const = 0;
virtual meaning get_meaning () const = 0;
+
+ virtual diagnostic_thread_id_t get_thread_id () const = 0;
+};
+
+/* Abstract base class representing a thread of execution within
+ a diagnostic_path.
+ Each diagnostic_event is associated with one thread.
+ Typically there is just one thread per diagnostic_path. */
+
+class diagnostic_thread
+{
+public:
+ virtual ~diagnostic_thread () {}
+ virtual label_text get_name (bool can_colorize) const = 0;
};
/* Abstract base class for getting at a sequence of events. */
@@ -165,8 +179,12 @@ class diagnostic_path
virtual ~diagnostic_path () {}
virtual unsigned num_events () const = 0;
virtual const diagnostic_event & get_event (int idx) const = 0;
+ virtual unsigned num_threads () const = 0;
+ virtual const diagnostic_thread &
+ get_thread (diagnostic_thread_id_t) const = 0;
bool interprocedural_p () const;
+ bool multithreaded_p () const;
private:
bool get_first_event_in_a_function (unsigned *out_idx) const;
@@ -180,7 +198,8 @@ class simple_diagnostic_event : public diagnostic_event
{
public:
simple_diagnostic_event (location_t loc, tree fndecl, int depth,
- const char *desc);
+ const char *desc,
+ diagnostic_thread_id_t thread_id = 0);
~simple_diagnostic_event ();
location_t get_location () const final override { return m_loc; }
@@ -198,12 +217,32 @@ class simple_diagnostic_event : public diagnostic_event
{
return meaning ();
}
+ diagnostic_thread_id_t get_thread_id () const final override
+ {
+ return m_thread_id;
+ }
private:
location_t m_loc;
tree m_fndecl;
int m_depth;
char *m_desc; // has been i18n-ed and formatted
+ diagnostic_thread_id_t m_thread_id;
+};
+
+/* A simple implementation of diagnostic_thread. */
+
+class simple_diagnostic_thread : public diagnostic_thread
+{
+public:
+ simple_diagnostic_thread (const char *name) : m_name (name) {}
+ label_text get_name (bool) const final override
+ {
+ return label_text::borrow (m_name);
+ }
+
+private:
+ const char *m_name; // has been i18n-ed and formatted
};
/* A simple implementation of diagnostic_path, as a vector of
@@ -212,17 +251,27 @@ class simple_diagnostic_event : public diagnostic_event
class simple_diagnostic_path : public diagnostic_path
{
public:
- simple_diagnostic_path (pretty_printer *event_pp)
- : m_event_pp (event_pp) {}
+ simple_diagnostic_path (pretty_printer *event_pp);
unsigned num_events () const final override;
const diagnostic_event & get_event (int idx) const final override;
+ unsigned num_threads () const final override;
+ const diagnostic_thread &
+ get_thread (diagnostic_thread_id_t) const final override;
+
+ diagnostic_thread_id_t add_thread (const char *name);
diagnostic_event_id_t add_event (location_t loc, tree fndecl, int depth,
const char *fmt, ...)
ATTRIBUTE_GCC_DIAG(5,6);
+ diagnostic_event_id_t
+ add_thread_event (diagnostic_thread_id_t thread_id,
+ location_t loc, tree fndecl, int depth,
+ const char *fmt, ...)
+ ATTRIBUTE_GCC_DIAG(6,7);
private:
+ auto_delete_vec<simple_diagnostic_thread> m_threads;
auto_delete_vec<simple_diagnostic_event> m_events;
/* (for use by add_event). */
diff --git a/gcc/diagnostic-show-locus.cc b/gcc/diagnostic-show-locus.cc
index 0514815b51f..31ef85151fd 100644
--- a/gcc/diagnostic-show-locus.cc
+++ b/gcc/diagnostic-show-locus.cc
@@ -367,7 +367,8 @@ class layout
public:
layout (diagnostic_context *context,
rich_location *richloc,
- diagnostic_t diagnostic_kind);
+ diagnostic_t diagnostic_kind,
+ pretty_printer *pp = nullptr);
bool maybe_add_location_range (const location_range *loc_range,
unsigned original_idx,
@@ -1183,9 +1184,10 @@ make_policy (const diagnostic_context &dc,
layout::layout (diagnostic_context * context,
rich_location *richloc,
- diagnostic_t diagnostic_kind)
+ diagnostic_t diagnostic_kind,
+ pretty_printer *pp)
: m_context (context),
- m_pp (context->printer),
+ m_pp (pp ? pp : context->printer),
m_policy (make_policy (*context, *richloc)),
m_primary_loc (richloc->get_range (0)->m_loc),
m_exploc (richloc->get_expanded_location (0), m_policy,
@@ -2825,12 +2827,14 @@ gcc_rich_location::add_location_if_nearby (location_t loc,
}
/* Print the physical source code corresponding to the location of
- this diagnostic, with additional annotations. */
+ this diagnostic, with additional annotations.
+ If PP is non-null, then use it rather than CONTEXT's printer. */
void
diagnostic_show_locus (diagnostic_context * context,
rich_location *richloc,
- diagnostic_t diagnostic_kind)
+ diagnostic_t diagnostic_kind,
+ pretty_printer *pp)
{
location_t loc = richloc->get_loc ();
/* Do nothing if source-printing has been disabled. */
@@ -2851,7 +2855,7 @@ diagnostic_show_locus (diagnostic_context * context,
context->last_location = loc;
- layout layout (context, richloc, diagnostic_kind);
+ layout layout (context, richloc, diagnostic_kind, pp);
for (int line_span_idx = 0; line_span_idx < layout.get_num_line_spans ();
line_span_idx++)
{
diff --git a/gcc/diagnostic.cc b/gcc/diagnostic.cc
index 65c0cfbf11a..00183b10700 100644
--- a/gcc/diagnostic.cc
+++ b/gcc/diagnostic.cc
@@ -2404,6 +2404,14 @@ diagnostics_text_art_charset_init (diagnostic_context *context,
}
}
+/* class simple_diagnostic_path : public diagnostic_path. */
+
+simple_diagnostic_path::simple_diagnostic_path (pretty_printer *event_pp)
+ : m_event_pp (event_pp)
+{
+ add_thread ("main");
+}
+
/* Implementation of diagnostic_path::num_events vfunc for
simple_diagnostic_path: simply get the number of events in the vec. */
@@ -2422,6 +2430,25 @@ simple_diagnostic_path::get_event (int idx) const
return *m_events[idx];
}
+unsigned
+simple_diagnostic_path::num_threads () const
+{
+ return m_threads.length ();
+}
+
+const diagnostic_thread &
+simple_diagnostic_path::get_thread (diagnostic_thread_id_t idx) const
+{
+ return *m_threads[idx];
+}
+
+diagnostic_thread_id_t
+simple_diagnostic_path::add_thread (const char *name)
+{
+ m_threads.safe_push (new simple_diagnostic_thread (name));
+ return m_threads.length () - 1;
+}
+
/* Add an event to this path at LOC within function FNDECL at
stack depth DEPTH.
@@ -2464,15 +2491,56 @@ simple_diagnostic_path::add_event (location_t loc, tree fndecl, int depth,
return diagnostic_event_id_t (m_events.length () - 1);
}
+diagnostic_event_id_t
+simple_diagnostic_path::add_thread_event (diagnostic_thread_id_t thread_id,
+ location_t loc,
+ tree fndecl,
+ int depth,
+ const char *fmt, ...)
+{
+ pretty_printer *pp = m_event_pp;
+ pp_clear_output_area (pp);
+
+ text_info ti;
+ rich_location rich_loc (line_table, UNKNOWN_LOCATION);
+
+ va_list ap;
+
+ va_start (ap, fmt);
+
+ ti.format_spec = _(fmt);
+ ti.args_ptr = ≈
+ ti.err_no = 0;
+ ti.x_data = NULL;
+ ti.m_richloc = &rich_loc;
+
+ pp_format (pp, &ti);
+ pp_output_formatted_text (pp);
+
+ va_end (ap);
+
+ simple_diagnostic_event *new_event
+ = new simple_diagnostic_event (loc, fndecl, depth, pp_formatted_text (pp),
+ thread_id);
+ m_events.safe_push (new_event);
+
+ pp_clear_output_area (pp);
+
+ return diagnostic_event_id_t (m_events.length () - 1);
+}
+
/* struct simple_diagnostic_event. */
/* simple_diagnostic_event's ctor. */
-simple_diagnostic_event::simple_diagnostic_event (location_t loc,
- tree fndecl,
- int depth,
- const char *desc)
-: m_loc (loc), m_fndecl (fndecl), m_depth (depth), m_desc (xstrdup (desc))
+simple_diagnostic_event::
+simple_diagnostic_event (location_t loc,
+ tree fndecl,
+ int depth,
+ const char *desc,
+ diagnostic_thread_id_t thread_id)
+: m_loc (loc), m_fndecl (fndecl), m_depth (depth), m_desc (xstrdup (desc)),
+ m_thread_id (thread_id)
{
}
diff --git a/gcc/diagnostic.h b/gcc/diagnostic.h
index 00b828f230d..4ec83a988d5 100644
--- a/gcc/diagnostic.h
+++ b/gcc/diagnostic.h
@@ -509,7 +509,8 @@ extern void diagnostic_finish (diagnostic_context *);
extern void diagnostic_report_current_module (diagnostic_context *, location_t);
extern void diagnostic_show_locus (diagnostic_context *,
rich_location *richloc,
- diagnostic_t diagnostic_kind);
+ diagnostic_t diagnostic_kind,
+ pretty_printer *pp = nullptr);
extern void diagnostic_show_any_path (diagnostic_context *, diagnostic_info *);
/* Because we read source files a second time after the frontend did it the
diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-paths-multithreaded-inline-events.c b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-paths-multithreaded-inline-events.c
new file mode 100644
index 00000000000..333ef735944
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-paths-multithreaded-inline-events.c
@@ -0,0 +1,72 @@
+/* { dg-do compile } */
+/* { dg-options "-fdiagnostics-path-format=inline-events -fdiagnostics-show-caret -fdiagnostics-show-line-numbers" } */
+/* { dg-enable-nn-line-numbers "" } */
+
+extern void acquire_lock_a(void);
+extern void acquire_lock_b(void);
+
+void foo ()
+{
+ acquire_lock_a ();
+ acquire_lock_b ();
+}
+
+void bar ()
+{
+ acquire_lock_b ();
+ acquire_lock_a (); /* { dg-warning "deadlock due to inconsistent lock acquisition order" } */
+}
+
+/* { dg-begin-multiline-output "" }
+ NN | acquire_lock_a ();
+ | ^~~~~~~~~~~~~~~~~
+Thread: 'Thread 1'
+ 'foo': event 1
+ |
+ | NN | {
+ | | ^
+ | | |
+ | | (1) entering 'foo'
+ |
+ +--> 'foo': event 2
+ |
+ | NN | acquire_lock_a ();
+ | | ^~~~~~~~~~~~~~~~~
+ | | |
+ | | (2) lock a is now held by thread 1
+ |
+
+Thread: 'Thread 2'
+ 'bar': event 3
+ |
+ | NN | {
+ | | ^
+ | | |
+ | | (3) entering 'bar'
+ |
+ +--> 'bar': event 4
+ |
+ | NN | acquire_lock_b ();
+ | | ^~~~~~~~~~~~~~~~~
+ | | |
+ | | (4) lock b is now held by thread 2
+ |
+
+Thread: 'Thread 1'
+ 'foo': event 5
+ |
+ | NN | acquire_lock_b ();
+ | | ^~~~~~~~~~~~~~~~~
+ | | |
+ | | (5) deadlocked due to waiting for lock b in thread 1...
+ |
+
+Thread: 'Thread 2'
+ 'bar': event 6
+ |
+ | NN | acquire_lock_a ();
+ | | ^~~~~~~~~~~~~~~~~
+ | | |
+ | | (6) ...whilst waiting for lock a in thread 2
+ |
+ { dg-end-multiline-output "" } */
diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-paths-multithreaded-sarif.c b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-paths-multithreaded-sarif.c
new file mode 100644
index 00000000000..727d1bb6469
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-paths-multithreaded-sarif.c
@@ -0,0 +1,35 @@
+/* { dg-do compile } */
+/* { dg-options "-fdiagnostics-format=sarif-file" } */
+
+extern void acquire_lock_a(void);
+extern void acquire_lock_b(void);
+
+void foo ()
+{
+ acquire_lock_a ();
+ acquire_lock_b ();
+}
+
+void bar ()
+{
+ acquire_lock_b ();
+ acquire_lock_a ();
+}
+
+/* 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 {"version": "2.1.0"} } }
+ { dg-final { scan-sarif-file {"text": "deadlock due to inconsistent lock acquisition order"} } }
+ { dg-final { scan-sarif-file {"id": "Thread 1"} } }
+ { dg-final { scan-sarif-file {"executionOrder": 1} } }
+ { dg-final { scan-sarif-file {"executionOrder": 2} } }
+ { dg-final { scan-sarif-file {"executionOrder": 5} } }
+ { dg-final { scan-sarif-file {"id": "Thread 2"} } }
+ { dg-final { scan-sarif-file {"executionOrder": 3} } }
+ { dg-final { scan-sarif-file {"executionOrder": 4} } }
+ { dg-final { scan-sarif-file {"executionOrder": 6} } } */
diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-paths-multithreaded-separate-events.c b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-paths-multithreaded-separate-events.c
new file mode 100644
index 00000000000..914918bb9e1
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-paths-multithreaded-separate-events.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-fdiagnostics-path-format=separate-events" } */
+
+extern void acquire_lock_a(void);
+extern void acquire_lock_b(void);
+
+void foo ()
+{ /* { dg-message "\\(1\\) entering 'foo'" } */
+ acquire_lock_a (); /* { dg-message "\\(2\\) lock a is now held by thread 1" } */
+ acquire_lock_b (); /* { dg-message "\\(5\\) deadlocked due to waiting for lock b in thread 1\.\.\." } */
+}
+
+void bar ()
+{ /* { dg-message "\\(3\\) entering 'bar'" } */
+ acquire_lock_b (); /* { dg-message "\\(4\\) lock b is now held by thread 2" } */
+ acquire_lock_a (); /* { dg-warning "deadlock due to inconsistent lock acquisition order" } */
+ /* { dg-message "\\(6\\) \.\.\.whilst waiting for lock a in thread 2" "" { target *-*-* } .-1 } */
+}
diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_paths.c b/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_paths.c
index 8d97fe8e8d9..62558bede95 100644
--- a/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_paths.c
+++ b/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_paths.c
@@ -192,7 +192,7 @@ struct event_location_t
/* If FUN's name matches FUNCNAME, write the function and its start location
into *OUT_ENTRY. */
-static void
+static bool
check_for_named_function (function *fun, const char *funcname,
event_location_t *out_entry)
{
@@ -200,9 +200,10 @@ check_for_named_function (function *fun, const char *funcname,
gcc_assert (funcname);
if (strcmp (IDENTIFIER_POINTER (DECL_NAME (fun->decl)), funcname))
- return;
+ return false;
*out_entry = event_location_t (fun, fun->function_start_locus);
+ return true;
}
@@ -215,12 +216,21 @@ class test_diagnostic_path : public simple_diagnostic_path
: simple_diagnostic_path (event_pp)
{
}
+ void add_event_2 (event_location_t evloc, int stack_depth,
+ const char *desc,
+ diagnostic_thread_id_t thread_id = 0)
+ {
+ gcc_assert (evloc.m_fun);
+ add_thread_event (thread_id, evloc.m_loc, evloc.m_fun->decl,
+ stack_depth, desc);
+ }
void add_entry (event_location_t evloc, int stack_depth,
- const char *funcname)
+ const char *funcname,
+ diagnostic_thread_id_t thread_id = 0)
{
gcc_assert (evloc.m_fun);
- add_event (evloc.m_loc, evloc.m_fun->decl, stack_depth,
- "entering %qs", funcname);
+ add_thread_event (thread_id, evloc.m_loc, evloc.m_fun->decl, stack_depth,
+ "entering %qs", funcname);
}
void add_call (event_location_t call_evloc, int caller_stack_depth,
@@ -422,12 +432,86 @@ example_3 ()
}
}
+/* Example 4: a multithreaded path. */
+
+static void
+example_4 ()
+{
+ gimple_stmt_iterator gsi;
+ basic_block bb;
+
+ event_location_t entry_to_foo;
+ event_location_t entry_to_bar;
+ event_location_t call_to_acquire_lock_a_in_foo;
+ event_location_t call_to_acquire_lock_b_in_foo;
+ event_location_t call_to_acquire_lock_a_in_bar;
+ event_location_t call_to_acquire_lock_b_in_bar;
+
+ cgraph_node *node;
+ FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
+ {
+ function *fun = node->get_fun ();
+ FOR_EACH_BB_FN (bb, fun)
+ {
+ bool in_foo = check_for_named_function (fun, "foo",
+ &entry_to_foo);
+ bool in_bar = check_for_named_function (fun, "bar",
+ &entry_to_bar);
+ for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
+ {
+ gimple *stmt = gsi_stmt (gsi);
+ event_location_t *evloc = NULL;
+ gcall *call = NULL;
+ if (call = check_for_named_call (stmt, "acquire_lock_a", 0))
+ evloc = (in_foo
+ ? &call_to_acquire_lock_a_in_foo
+ : &call_to_acquire_lock_a_in_bar);
+ else if (call
+ = check_for_named_call (stmt, "acquire_lock_b", 0))
+ evloc = (in_foo
+ ? &call_to_acquire_lock_b_in_foo
+ : &call_to_acquire_lock_b_in_bar);
+ if (evloc)
+ evloc->set (call, fun);
+ }
+ }
+ }
+
+ if (call_to_acquire_lock_a_in_foo.m_fun)
+ {
+ auto_diagnostic_group d;
+
+ gcc_rich_location richloc (call_to_acquire_lock_a_in_bar.m_loc);
+ test_diagnostic_path path (global_dc->printer);
+ diagnostic_thread_id_t thread_1 = path.add_thread ("Thread 1");
+ diagnostic_thread_id_t thread_2 = path.add_thread ("Thread 2");
+ path.add_entry (entry_to_foo, 0, "foo", thread_1);
+ path.add_event_2 (call_to_acquire_lock_a_in_foo, 1,
+ "lock a is now held by thread 1", thread_1);
+ path.add_entry (entry_to_bar, 0, "bar", thread_2);
+ path.add_event_2 (call_to_acquire_lock_b_in_bar, 1,
+ "lock b is now held by thread 2", thread_2);
+ path.add_event_2 (call_to_acquire_lock_b_in_foo, 1,
+ "deadlocked due to waiting for lock b in thread 1...",
+ thread_1);
+ path.add_event_2 (call_to_acquire_lock_a_in_bar, 1,
+ "...whilst waiting for lock a in thread 2",
+ thread_2);
+ richloc.set_path (&path);
+
+ diagnostic_metadata m;
+ warning_meta (&richloc, m, 0,
+ "deadlock due to inconsistent lock acquisition order");
+ }
+}
+
unsigned int
pass_test_show_path::execute (function *)
{
example_1 ();
example_2 ();
example_3 ();
+ example_4 ();
return 0;
}
diff --git a/gcc/testsuite/gcc.dg/plugin/plugin.exp b/gcc/testsuite/gcc.dg/plugin/plugin.exp
index ed72912309c..f098a327d31 100644
--- a/gcc/testsuite/gcc.dg/plugin/plugin.exp
+++ b/gcc/testsuite/gcc.dg/plugin/plugin.exp
@@ -108,6 +108,9 @@ set plugin_test_list [list \
diagnostic-test-paths-3.c \
diagnostic-test-paths-4.c \
diagnostic-test-paths-5.c \
+ diagnostic-test-paths-multithreaded-inline-events.c \
+ diagnostic-test-paths-multithreaded-sarif.c \
+ diagnostic-test-paths-multithreaded-separate-events.c \
diagnostic-path-format-plain.c \
diagnostic-path-format-none.c \
diagnostic-path-format-separate-events.c \
diff --git a/gcc/tree-diagnostic-path.cc b/gcc/tree-diagnostic-path.cc
index 988ed7f6726..84148da53af 100644
--- a/gcc/tree-diagnostic-path.cc
+++ b/gcc/tree-diagnostic-path.cc
@@ -19,6 +19,7 @@ along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#include "config.h"
+#define INCLUDE_VECTOR
#include "system.h"
#include "coretypes.h"
#include "tree.h"
@@ -83,6 +84,9 @@ can_consolidate_events (const diagnostic_event &e1,
const diagnostic_event &e2,
bool check_locations)
{
+ if (e1.get_thread_id () != e2.get_thread_id ())
+ return false;
+
if (e1.get_fndecl () != e2.get_fndecl ())
return false;
@@ -109,20 +113,67 @@ can_consolidate_events (const diagnostic_event &e1,
return true;
}
-/* A range of consecutive events within a diagnostic_path,
- all with the same fndecl and stack_depth, and which are suitable
+struct event_range;
+struct path_summary;
+class thread_event_printer;
+
+/* A bundle of information about all of the events in a diagnostic_path
+ relating to a specific path, for use by path_summary. */
+
+class per_thread_summary
+{
+public:
+ per_thread_summary (label_text name, unsigned swimlane_idx)
+ : m_name (std::move (name)),
+ m_swimlane_idx (swimlane_idx),
+ m_min_depth (INT_MAX),
+ m_max_depth (INT_MIN)
+ {}
+
+ void update_depth_limits (int stack_depth)
+ {
+ if (stack_depth < m_min_depth)
+ m_min_depth = stack_depth;
+ if (stack_depth > m_max_depth)
+ m_max_depth = stack_depth;
+ }
+
+ const char *get_name () const { return m_name.get (); }
+ unsigned get_swimlane_index () const { return m_swimlane_idx; }
+
+private:
+ friend struct path_summary;
+ friend class thread_event_printer;
+
+ const label_text m_name;
+
+ /* The "swimlane index" is the order in which this per_thread_summary
+ was created, for use when printing the events. */
+ const unsigned m_swimlane_idx;
+
+ // The event ranges specific to this thread:
+ auto_vec<event_range *> m_event_ranges;
+ int m_min_depth;
+ int m_max_depth;
+};
+
+/* A range of consecutive events within a diagnostic_path, all within the
+ same thread, and with the same fndecl and stack_depth, and which are suitable
to print with a single call to diagnostic_show_locus. */
struct event_range
{
event_range (const diagnostic_path *path, unsigned start_idx,
- const diagnostic_event &initial_event)
+ const diagnostic_event &initial_event,
+ const per_thread_summary &t)
: m_path (path),
m_initial_event (initial_event),
m_fndecl (initial_event.get_fndecl ()),
m_stack_depth (initial_event.get_stack_depth ()),
m_start_idx (start_idx), m_end_idx (start_idx),
m_path_label (path, start_idx),
- m_richloc (initial_event.get_location (), &m_path_label)
+ m_richloc (initial_event.get_location (), &m_path_label),
+ m_thread_id (initial_event.get_thread_id ()),
+ m_per_thread_summary (t)
{}
bool maybe_add_event (const diagnostic_event &new_ev, unsigned idx,
@@ -142,7 +193,7 @@ struct event_range
/* Print the events in this range to DC, typically as a single
call to the printer's diagnostic_show_locus. */
- void print (diagnostic_context *dc)
+ void print (diagnostic_context *dc, pretty_printer *pp)
{
location_t initial_loc = m_initial_event.get_location ();
@@ -172,7 +223,6 @@ struct event_range
const diagnostic_event &iter_event = m_path->get_event (i);
diagnostic_event_id_t event_id (i);
label_text event_text (iter_event.get_desc (true));
- pretty_printer *pp = dc->printer;
pp_printf (pp, " %@: %s", &event_id, event_text.get ());
pp_newline (pp);
}
@@ -180,7 +230,7 @@ struct event_range
}
/* Call diagnostic_show_locus to show the events using labels. */
- diagnostic_show_locus (dc, &m_richloc, DK_DIAGNOSTIC_PATH);
+ diagnostic_show_locus (dc, &m_richloc, DK_DIAGNOSTIC_PATH, pp);
/* If we have a macro expansion, show the expansion to the user. */
if (linemap_location_from_macro_expansion_p (line_table, initial_loc))
@@ -198,19 +248,49 @@ struct event_range
unsigned m_end_idx;
path_label m_path_label;
gcc_rich_location m_richloc;
+ diagnostic_thread_id_t m_thread_id;
+ const per_thread_summary &m_per_thread_summary;
};
/* A struct for grouping together the events in a diagnostic_path into
- ranges of events, partitioned by stack frame (i.e. by fndecl and
- stack depth). */
+ ranges of events, partitioned by thread and by stack frame (i.e. by fndecl
+ and stack depth). */
struct path_summary
{
path_summary (const diagnostic_path &path, bool check_rich_locations);
unsigned get_num_ranges () const { return m_ranges.length (); }
+ bool multithreaded_p () const { return m_per_thread_summary.length () > 1; }
+
+ const per_thread_summary &get_events_for_thread_id (diagnostic_thread_id_t tid)
+ {
+ per_thread_summary **slot = m_thread_id_to_events.get (tid);
+ gcc_assert (slot);
+ gcc_assert (*slot);
+ return **slot;
+ }
auto_delete_vec <event_range> m_ranges;
+ auto_delete_vec <per_thread_summary> m_per_thread_summary;
+ hash_map<int_hash<diagnostic_thread_id_t, -1, -2>,
+ per_thread_summary *> m_thread_id_to_events;
+
+private:
+ per_thread_summary &
+ get_or_create_events_for_thread_id (const diagnostic_path &path,
+ diagnostic_thread_id_t tid)
+ {
+ if (per_thread_summary **slot = m_thread_id_to_events.get (tid))
+ return **slot;
+
+ const diagnostic_thread &thread = path.get_thread (tid);
+ per_thread_summary *pts = new per_thread_summary (thread.get_name (false),
+ m_per_thread_summary.length ());
+ m_thread_id_to_events.put (tid, pts);
+ m_per_thread_summary.safe_push (pts);
+ return *pts;
+ }
};
/* path_summary's ctor. */
@@ -224,12 +304,19 @@ path_summary::path_summary (const diagnostic_path &path,
for (unsigned idx = 0; idx < num_events; idx++)
{
const diagnostic_event &event = path.get_event (idx);
+ const diagnostic_thread_id_t thread_id = event.get_thread_id ();
+ per_thread_summary &pts
+ = get_or_create_events_for_thread_id (path, thread_id);
+
+ pts.update_depth_limits (event.get_stack_depth ());
+
if (cur_event_range)
if (cur_event_range->maybe_add_event (event, idx, check_rich_locations))
continue;
- cur_event_range = new event_range (&path, idx, event);
+ cur_event_range = new event_range (&path, idx, event, pts);
m_ranges.safe_push (cur_event_range);
+ pts.m_event_ranges.safe_push (cur_event_range);
}
}
@@ -259,6 +346,184 @@ print_fndecl (pretty_printer *pp, tree fndecl, bool quoted)
pp_string (pp, n);
}
+static const int base_indent = 2;
+static const int per_frame_indent = 2;
+
+/* A bundle of state for printing event_range instances for a particular
+ thread. */
+
+class thread_event_printer
+{
+public:
+ thread_event_printer (const per_thread_summary &t, bool show_depths)
+ : m_per_thread_summary (t),
+ m_show_depths (show_depths),
+ m_cur_indent (base_indent),
+ m_vbar_column_for_depth (),
+ m_num_printed (0)
+ {
+ }
+
+ /* Get the previous event_range within this thread, if any. */
+ const event_range *get_any_prev_range () const
+ {
+ if (m_num_printed > 0)
+ return m_per_thread_summary.m_event_ranges[m_num_printed - 1];
+ else
+ return nullptr;
+ }
+
+ /* Get the next event_range within this thread, if any. */
+ const event_range *get_any_next_range () const
+ {
+ if (m_num_printed < m_per_thread_summary.m_event_ranges.length () - 1)
+ return m_per_thread_summary.m_event_ranges[m_num_printed + 1];
+ else
+ return nullptr;
+ }
+
+ void print_swimlane_for_event_range (diagnostic_context *dc,
+ pretty_printer *pp,
+ event_range *range)
+ {
+ const char *const line_color = "path";
+ const char *start_line_color
+ = colorize_start (pp_show_color (pp), line_color);
+ const char *end_line_color = colorize_stop (pp_show_color (pp));
+
+ write_indent (pp, m_cur_indent);
+ if (const event_range *prev_range = get_any_prev_range ())
+ {
+ if (range->m_stack_depth > prev_range->m_stack_depth)
+ {
+ /* Show pushed stack frame(s). */
+ const char *push_prefix = "+--> ";
+ pp_string (pp, start_line_color);
+ pp_string (pp, push_prefix);
+ pp_string (pp, end_line_color);
+ m_cur_indent += strlen (push_prefix);
+ }
+ }
+ if (range->m_fndecl)
+ {
+ print_fndecl (pp, range->m_fndecl, true);
+ pp_string (pp, ": ");
+ }
+ if (range->m_start_idx == range->m_end_idx)
+ pp_printf (pp, "event %i",
+ range->m_start_idx + 1);
+ else
+ pp_printf (pp, "events %i-%i",
+ range->m_start_idx + 1, range->m_end_idx + 1);
+ if (m_show_depths)
+ pp_printf (pp, " (depth %i)", range->m_stack_depth);
+ pp_newline (pp);
+
+ /* Print a run of events. */
+ {
+ write_indent (pp, m_cur_indent + per_frame_indent);
+ pp_string (pp, start_line_color);
+ pp_string (pp, "|");
+ pp_string (pp, end_line_color);
+ pp_newline (pp);
+
+ char *saved_prefix = pp_take_prefix (pp);
+ char *prefix;
+ {
+ pretty_printer tmp_pp;
+ write_indent (&tmp_pp, m_cur_indent + per_frame_indent);
+ pp_string (&tmp_pp, start_line_color);
+ pp_string (&tmp_pp, "|");
+ pp_string (&tmp_pp, end_line_color);
+ prefix = xstrdup (pp_formatted_text (&tmp_pp));
+ }
+ pp_set_prefix (pp, prefix);
+ pp_prefixing_rule (pp) = DIAGNOSTICS_SHOW_PREFIX_EVERY_LINE;
+ range->print (dc, pp);
+ pp_set_prefix (pp, saved_prefix);
+
+ write_indent (pp, m_cur_indent + per_frame_indent);
+ pp_string (pp, start_line_color);
+ pp_string (pp, "|");
+ pp_string (pp, end_line_color);
+ pp_newline (pp);
+ }
+
+ if (const event_range *next_range = get_any_next_range ())
+ {
+ if (range->m_stack_depth > next_range->m_stack_depth)
+ {
+ if (m_vbar_column_for_depth.get (next_range->m_stack_depth))
+ {
+ /* Show returning from stack frame(s), by printing
+ something like:
+ " |\n"
+ " <------------ +\n"
+ " |\n". */
+ int vbar_for_next_frame
+ = *m_vbar_column_for_depth.get (next_range->m_stack_depth);
+
+ int indent_for_next_frame
+ = vbar_for_next_frame - per_frame_indent;
+ write_indent (pp, vbar_for_next_frame);
+ pp_string (pp, start_line_color);
+ pp_character (pp, '<');
+ for (int i = indent_for_next_frame + per_frame_indent;
+ i < m_cur_indent + per_frame_indent - 1; i++)
+ pp_character (pp, '-');
+ pp_character (pp, '+');
+ pp_string (pp, end_line_color);
+ pp_newline (pp);
+ m_cur_indent = indent_for_next_frame;
+
+ write_indent (pp, vbar_for_next_frame);
+ pp_string (pp, start_line_color);
+ pp_character (pp, '|');
+ pp_string (pp, end_line_color);
+ pp_newline (pp);
+ }
+ else
+ {
+ /* Handle disjoint paths (e.g. a callback at some later
+ time). */
+ m_cur_indent = base_indent;
+ }
+ }
+ else if (range->m_stack_depth < next_range->m_stack_depth)
+ {
+ /* Prepare to show pushed stack frame. */
+ gcc_assert (range->m_stack_depth != EMPTY);
+ gcc_assert (range->m_stack_depth != DELETED);
+ m_vbar_column_for_depth.put (range->m_stack_depth,
+ m_cur_indent + per_frame_indent);
+ m_cur_indent += per_frame_indent;
+ }
+ }
+
+ m_num_printed++;
+ }
+
+ int get_cur_indent () const { return m_cur_indent; }
+
+private:
+ const per_thread_summary &m_per_thread_summary;
+ bool m_show_depths;
+
+ /* Print the ranges. */
+ int m_cur_indent;
+
+ /* Keep track of column numbers of existing '|' characters for
+ stack depths we've already printed. */
+ static const int EMPTY = -1;
+ static const int DELETED = -2;
+ typedef int_hash <int, EMPTY, DELETED> vbar_hash;
+ hash_map <vbar_hash, int> m_vbar_column_for_depth;
+
+ /* How many event ranges within this swimlane have we printed.
+ This is the index of the next event_range to print. */
+ unsigned m_num_printed;
+};
+
/* Print path_summary PS to DC, giving an overview of the interprocedural
calls and returns.
@@ -292,145 +557,33 @@ print_fndecl (pretty_printer *pp, tree fndecl, bool quoted)
For events with UNKNOWN_LOCATION, print a summary of each the event. */
-void
+static void
print_path_summary_as_text (const path_summary *ps, diagnostic_context *dc,
bool show_depths)
{
pretty_printer *pp = dc->printer;
- const int per_frame_indent = 2;
-
- const char *const line_color = "path";
- const char *start_line_color
- = colorize_start (pp_show_color (pp), line_color);
- const char *end_line_color = colorize_stop (pp_show_color (pp));
+ std::vector<thread_event_printer> thread_event_printers;
+ for (auto t : ps->m_per_thread_summary)
+ thread_event_printers.push_back (thread_event_printer (*t, show_depths));
- /* Keep track of column numbers of existing '|' characters for
- stack depths we've already printed. */
- const int EMPTY = -1;
- const int DELETED = -2;
- typedef int_hash <int, EMPTY, DELETED> vbar_hash;
- hash_map <vbar_hash, int> vbar_column_for_depth;
-
- /* Print the ranges. */
- const int base_indent = 2;
- int cur_indent = base_indent;
unsigned i;
event_range *range;
FOR_EACH_VEC_ELT (ps->m_ranges, i, range)
{
- write_indent (pp, cur_indent);
- if (i > 0)
- {
- const event_range *prev_range = ps->m_ranges[i - 1];
- if (range->m_stack_depth > prev_range->m_stack_depth)
- {
- /* Show pushed stack frame(s). */
- const char *push_prefix = "+--> ";
- pp_string (pp, start_line_color);
- pp_string (pp, push_prefix);
- pp_string (pp, end_line_color);
- cur_indent += strlen (push_prefix);
- }
- }
- if (range->m_fndecl)
- {
- print_fndecl (pp, range->m_fndecl, true);
- pp_string (pp, ": ");
- }
- if (range->m_start_idx == range->m_end_idx)
- pp_printf (pp, "event %i",
- range->m_start_idx + 1);
- else
- pp_printf (pp, "events %i-%i",
- range->m_start_idx + 1, range->m_end_idx + 1);
- if (show_depths)
- pp_printf (pp, " (depth %i)", range->m_stack_depth);
- pp_newline (pp);
-
- /* Print a run of events. */
- {
- write_indent (pp, cur_indent + per_frame_indent);
- pp_string (pp, start_line_color);
- pp_string (pp, "|");
- pp_string (pp, end_line_color);
- pp_newline (pp);
-
- char *saved_prefix = pp_take_prefix (pp);
- char *prefix;
- {
- pretty_printer tmp_pp;
- write_indent (&tmp_pp, cur_indent + per_frame_indent);
- pp_string (&tmp_pp, start_line_color);
- pp_string (&tmp_pp, "|");
- pp_string (&tmp_pp, end_line_color);
- prefix = xstrdup (pp_formatted_text (&tmp_pp));
- }
- pp_set_prefix (pp, prefix);
- pp_prefixing_rule (pp) = DIAGNOSTICS_SHOW_PREFIX_EVERY_LINE;
- range->print (dc);
- pp_set_prefix (pp, saved_prefix);
-
- write_indent (pp, cur_indent + per_frame_indent);
- pp_string (pp, start_line_color);
- pp_string (pp, "|");
- pp_string (pp, end_line_color);
- pp_newline (pp);
- }
-
- if (i < ps->m_ranges.length () - 1)
- {
- const event_range *next_range = ps->m_ranges[i + 1];
-
- if (range->m_stack_depth > next_range->m_stack_depth)
- {
- if (vbar_column_for_depth.get (next_range->m_stack_depth))
- {
- /* Show returning from stack frame(s), by printing
- something like:
- " |\n"
- " <------------ +\n"
- " |\n". */
- int vbar_for_next_frame
- = *vbar_column_for_depth.get (next_range->m_stack_depth);
-
- int indent_for_next_frame
- = vbar_for_next_frame - per_frame_indent;
- write_indent (pp, vbar_for_next_frame);
- pp_string (pp, start_line_color);
- pp_character (pp, '<');
- for (int i = indent_for_next_frame + per_frame_indent;
- i < cur_indent + per_frame_indent - 1; i++)
- pp_character (pp, '-');
- pp_character (pp, '+');
- pp_string (pp, end_line_color);
- pp_newline (pp);
- cur_indent = indent_for_next_frame;
-
- write_indent (pp, vbar_for_next_frame);
- pp_string (pp, start_line_color);
- pp_character (pp, '|');
- pp_string (pp, end_line_color);
- pp_newline (pp);
- }
- else
- {
- /* Handle disjoint paths (e.g. a callback at some later
- time). */
- cur_indent = base_indent;
- }
- }
- else if (range->m_stack_depth < next_range->m_stack_depth)
- {
- /* Prepare to show pushed stack frame. */
- gcc_assert (range->m_stack_depth != EMPTY);
- gcc_assert (range->m_stack_depth != DELETED);
- vbar_column_for_depth.put (range->m_stack_depth,
- cur_indent + per_frame_indent);
- cur_indent += per_frame_indent;
- }
-
- }
+ const int swimlane_idx
+ = range->m_per_thread_summary.get_swimlane_index ();
+ if (ps->multithreaded_p ())
+ if (i == 0 || ps->m_ranges[i - 1]->m_thread_id != range->m_thread_id)
+ {
+ if (i > 0)
+ pp_newline (pp);
+ pp_printf (pp, "Thread: %qs",
+ range->m_per_thread_summary.get_name ());
+ pp_newline (pp);
+ }
+ thread_event_printer &tep = thread_event_printers[swimlane_idx];
+ tep.print_swimlane_for_event_range (dc, pp, range);
}
}
@@ -497,6 +650,7 @@ default_tree_diagnostic_path_printer (diagnostic_context *context,
pp_flush (context->printer);
pp_set_prefix (context->printer, saved_prefix);
}
+ break;
}
}
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2023-09-14 20:29 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-09-14 20:29 [gcc r14-4006] diagnostics: support multithreaded diagnostic paths 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).