public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
From: Maxim Kuvyrkov <maxim.kuvyrkov@linaro.org>
To: gcc-patches@gcc.gnu.org
Cc: Maxim Kuvyrkov <maxim.kuvyrkov@linaro.org>,
	Bernd Schmidt <bernds_cb1@t-online.de>,
	Vladimir Makarov <vmakarov@redhat.com>,
	Jeff Law <jeffreyalaw@gmail.com>,
	Alexander Monakov <amonakov@ispras.ru>,
	Richard Guenther <richard.guenther@gmail.com>
Subject: [PATCH v3 8/8] Improve logging of scheduler dependency analysis context
Date: Wed, 22 Nov 2023 11:14:15 +0000	[thread overview]
Message-ID: <20231122111415.815147-9-maxim.kuvyrkov@linaro.org> (raw)
In-Reply-To: <20231120120649.672893-1-maxim.kuvyrkov@linaro.org>

Scheduler dependency analysis uses two main data structures:
1. reg_pending_* data contains effects of INSN on the register file,
   which is then incorporated into ...
2. deps_desc object, which contains commulative information about all
   instructions processed from deps_desc object's initialization.

This patch adds debug dumping of (2).

Dependency analysis contexts (aka deps_desc objects) are huge, but
each instruction affects only a small amount of data in these objects.
Therefore, it is most useful to dump differential information
compared to the dependency state after previous instruction.

gcc/ChangeLog:

	* sched-deps.cc (reset_deps, dump_rtx_insn_list)
	(rtx_insn_list_same_p):	New helper functions.
	(dump_deps_desc_diff): New function to dump dependency information.
	(sched_analysis_prev_deps): New static variable.
	(sched_analyze_insn): Dump dependency information.
	(init_deps_global, finish_deps_global): Handle sched_analysis_prev_deps.
	* sched-int.h (struct deps_reg): Update comments.
	* sched-rgn.cc (concat_insn_list, concat_expr_list): Update comments.
---
 gcc/sched-deps.cc | 197 ++++++++++++++++++++++++++++++++++++++++++++++
 gcc/sched-int.h   |   9 ++-
 gcc/sched-rgn.cc  |   5 ++
 3 files changed, 210 insertions(+), 1 deletion(-)

diff --git a/gcc/sched-deps.cc b/gcc/sched-deps.cc
index f9290c82fd2..edca9927e23 100644
--- a/gcc/sched-deps.cc
+++ b/gcc/sched-deps.cc
@@ -1677,6 +1677,15 @@ delete_all_dependences (rtx_insn *insn)
     sd_delete_dep (sd_it);
 }
 
+/* Re-initialize existing dependency context DEPS to be a copy of FROM.  */
+static void
+reset_deps (class deps_desc *deps, class deps_desc *from)
+{
+  free_deps (deps);
+  init_deps (deps, false);
+  deps_join (deps, from);
+}
+
 /* All insns in a scheduling group except the first should only have
    dependencies on the previous insn in the group.  So we find the
    first instruction in the scheduling group by walking the dependence
@@ -2960,6 +2969,177 @@ dump_reg_pending_data (FILE *file, rtx_insn *insn)
     }
 }
 
+/* Dump rtx_insn_list LIST.
+   Consider moving to lists.cc if there are users outside of sched-deps.cc.  */
+static void
+dump_rtx_insn_list (FILE *file, rtx_insn_list *list)
+{
+  for (; list; list = list->next ())
+    fprintf (file, " %d", INSN_UID (list->insn ()));
+}
+
+/* Return TRUE if lists A and B have same elements in the same order.  */
+static bool
+rtx_insn_list_same_p (rtx_insn_list *a, rtx_insn_list *b)
+{
+  for (; a && b; a = a->next (), b = b->next ())
+    if (a->insn () != b->insn ())
+      return false;
+
+  if (a || b)
+    return false;
+
+  return true;
+}
+
+/* Dump parts of DEPS that are different from PREV.
+   Dumping all information from dependency context produces huge
+   hard-to-analize logs; differential dumping is way more managable.  */
+static void
+dump_deps_desc_diff (FILE *file, class deps_desc *deps, class deps_desc *prev)
+{
+  /* Each "paragraph" is a single line of output.  */
+
+  /* Note on param_max_pending_list_length:
+     During normal dependency analysis various lists should not exceed this
+     limit.  Searching for "!!!" in scheduler logs can point to potential bugs
+     or poorly-handled corner-cases.  */
+
+  if (!rtx_insn_list_same_p (deps->pending_read_insns,
+			     prev->pending_read_insns))
+    {
+      fprintf (file, ";; deps pending mem reads length(%d):",
+	       deps->pending_read_list_length);
+      if ((deps->pending_read_list_length + deps->pending_write_list_length)
+	  >= param_max_pending_list_length)
+	fprintf (file, "%d insns!!!", deps->pending_read_list_length);
+      else
+	dump_rtx_insn_list (file, deps->pending_read_insns);
+      fprintf (file, "\n");
+    }
+
+  if (!rtx_insn_list_same_p (deps->pending_write_insns,
+			     prev->pending_write_insns))
+    {
+      fprintf (file, ";; deps pending mem writes length(%d):",
+	       deps->pending_write_list_length);
+      if ((deps->pending_read_list_length + deps->pending_write_list_length)
+	  >= param_max_pending_list_length)
+	fprintf (file, "%d insns!!!", deps->pending_write_list_length);
+      else
+	dump_rtx_insn_list (file, deps->pending_write_insns);
+      fprintf (file, "\n");
+    }
+
+  if (!rtx_insn_list_same_p (deps->pending_jump_insns,
+			     prev->pending_jump_insns))
+    {
+      fprintf (file, ";; deps pending jump length(%d):",
+	       deps->pending_flush_length);
+      if (deps->pending_flush_length >= param_max_pending_list_length)
+	fprintf (file, "%d insns!!!", deps->pending_flush_length);
+      else
+	dump_rtx_insn_list (file, deps->pending_jump_insns);
+      fprintf (file, "\n");
+    }
+
+  fprintf (file, ";; last");
+  if (!rtx_insn_list_same_p (deps->last_pending_memory_flush,
+			     prev->last_pending_memory_flush))
+    {
+      fprintf (file, " memory_flush(");
+      dump_rtx_insn_list (file, deps->last_pending_memory_flush);
+      fprintf (file, ")");
+    }
+  if (!rtx_insn_list_same_p (deps->last_function_call,
+			     prev->last_function_call))
+    {
+      fprintf (file, " call(");
+      dump_rtx_insn_list (file, deps->last_function_call);
+      fprintf (file, ")");
+    }
+  if (!rtx_insn_list_same_p (deps->last_function_call_may_noreturn,
+			     prev->last_function_call_may_noreturn))
+    {
+      fprintf (file, " noreturn(");
+      dump_rtx_insn_list (file, deps->last_function_call_may_noreturn);
+      fprintf (file, ")");
+    }
+  fprintf (file, "\n");
+
+  fprintf (file, ";; sched_before_next");
+  if (!rtx_insn_list_same_p (deps->sched_before_next_call,
+			     prev->sched_before_next_call))
+    {
+      fprintf (file, " call(");
+      dump_rtx_insn_list (file, deps->sched_before_next_call);
+      fprintf (file, ")");
+    }
+  if (!rtx_insn_list_same_p (deps->sched_before_next_jump,
+			     prev->sched_before_next_jump))
+    {
+      fprintf (file, " jump(");
+      dump_rtx_insn_list (file, deps->sched_before_next_jump);
+      fprintf (file, ")");
+    }
+  fprintf (file, " in_post_call_group_p(%d)\n", deps->in_post_call_group_p);
+
+  fprintf (file, ";; last_debug_insn(%d) last_args_size(%d) last_prologue(",
+	   deps->last_debug_insn ? INSN_UID (deps->last_debug_insn) : -1,
+	   deps->last_args_size ? INSN_UID (deps->last_args_size) : -1);
+  dump_rtx_insn_list (file, deps->last_prologue);
+  fprintf (file, ") last_epilogue(");
+  dump_rtx_insn_list (file, deps->last_epilogue);
+  fprintf (file, ") last_logue_was_epilogue(%d)\n",
+	   deps->last_logue_was_epilogue);
+
+  int i;
+
+  gcc_assert (deps->max_reg == prev->max_reg);
+  for (i = 0; i < deps->max_reg; ++i)
+    {
+      struct deps_reg *reg_last = &deps->reg_last[i];
+      struct deps_reg *reg_prev = &prev->reg_last[i];
+
+      if (rtx_insn_list_same_p (reg_last->uses, reg_prev->uses)
+	  && rtx_insn_list_same_p (reg_last->sets, reg_prev->sets)
+	  && rtx_insn_list_same_p (reg_last->implicit_sets,
+				   reg_prev->implicit_sets)
+	  && rtx_insn_list_same_p (reg_last->control_uses,
+				   reg_prev->control_uses)
+	  && rtx_insn_list_same_p (reg_last->clobbers,
+				   reg_prev->clobbers))
+	continue;
+
+      fprintf (file, ";; reg %u: uses(", i);
+      if (reg_last->uses_length >= param_max_pending_list_length)
+	fprintf (file, "%d insns!!!", reg_last->uses_length);
+      else
+	dump_rtx_insn_list (file, reg_last->uses);
+      if (reg_last->clobbers_length >= param_max_pending_list_length)
+	{
+	  fprintf (file, ") clobbers(");
+	  fprintf (file, "%d insns!!!", reg_last->clobbers_length);
+	}
+      else
+	{
+	  fprintf (file, ") sets(");
+	  dump_rtx_insn_list (file, reg_last->sets);
+	  fprintf (file, ") implicit_sets(");
+	  dump_rtx_insn_list (file, reg_last->implicit_sets);
+	  fprintf (file, ") control_uses(");
+	  dump_rtx_insn_list (file, reg_last->control_uses);
+	  fprintf (file, ") clobbers(");
+	  dump_rtx_insn_list (file, reg_last->clobbers);
+	}
+      fprintf (file, ")\n");
+    }
+}
+
+/* Dependency analysis state before current insn.
+   Used by dump_deps_desc_diff().  */
+static class deps_desc *sched_analysis_prev_deps;
+
 /* Analyze an INSN with pattern X to find all dependencies.
    This analysis uses two main data structures:
    1. reg_pending_* data contains effects of INSN on the register file,
@@ -3627,6 +3807,16 @@ sched_analyze_insn (class deps_desc *deps, rtx x, rtx_insn *insn)
 	  deps->last_logue_was_epilogue = true;
 	}
     }
+
+    if (sched_verbose >= 8)
+      {
+	dump_deps_desc_diff (sched_dump, deps, sched_analysis_prev_deps);
+	reset_deps (sched_analysis_prev_deps, deps);
+	fprintf (sched_dump, ";; ");
+	dump_lists (sched_dump, insn, SD_LIST_BACK,
+		    DUMP_LISTS_ALL | DUMP_DEP_PRO);
+	fprintf (sched_dump, "\n");
+      }
 }
 
 /* Return TRUE if INSN might not always return normally (e.g. call exit,
@@ -4305,6 +4495,9 @@ init_deps_global (void)
       sched_deps_info->note_mem_dep = haifa_note_mem_dep;
       sched_deps_info->note_dep = haifa_note_dep;
    }
+
+  sched_analysis_prev_deps = XNEW (class deps_desc);
+  init_deps (sched_analysis_prev_deps, false);
 }
 
 /* Free everything used by the dependency analysis code.  */
@@ -4316,6 +4509,10 @@ finish_deps_global (void)
   FREE_REG_SET (reg_pending_clobbers);
   FREE_REG_SET (reg_pending_uses);
   FREE_REG_SET (reg_pending_control_uses);
+
+  free_deps (sched_analysis_prev_deps);
+  free (sched_analysis_prev_deps);
+  sched_analysis_prev_deps = NULL;
 }
 
 /* Estimate the weakness of dependence between MEM1 and MEM2.  */
diff --git a/gcc/sched-int.h b/gcc/sched-int.h
index 64a2f0bcff9..8a3109ce86e 100644
--- a/gcc/sched-int.h
+++ b/gcc/sched-int.h
@@ -455,7 +455,9 @@ struct deps_reg
   int clobbers_length;
 };
 
-/* Describe state of dependencies used during sched_analyze phase.  */
+/* Describe state of dependencies used during sched_analyze phase.
+   Please consider updating sched-deps.cc:dump_deps_desc_diff() when adding
+   new fields.  */
 class deps_desc
 {
 public:
@@ -499,6 +501,11 @@ public:
      large lists.  */
   int pending_flush_length;
 
+  /* Below are lists (and not just a single instructions) to allow inter-block
+     dependency analysis.  Each block
+     may add a single insn to below lists, but when merging dependency
+     analysis context from multiple predecessor blocks, we may get a list.  */
+
   /* The last insn upon which all memory references must depend.
      This is an insn which flushed the pending lists, creating a dependency
      between it and all previously pending memory references.  This creates
diff --git a/gcc/sched-rgn.cc b/gcc/sched-rgn.cc
index da3ec0458ff..72f0a2de66e 100644
--- a/gcc/sched-rgn.cc
+++ b/gcc/sched-rgn.cc
@@ -2590,6 +2590,10 @@ static rtx_insn_list *
 concat_insn_list (rtx_insn_list *copy, rtx_insn_list *old)
 {
   if (!old)
+    /* concat_*_LIST() will return a reversed copy of COPY.  Working with
+       reversed copies would complicate dependency dumping in
+       dump_deps_desc_diff(), which internally uses reset_deps() and
+       deps_join().  Therefore, use copy_INSN_LIST() when OLD is NULL.  */
     return copy_INSN_LIST (copy);
   return concat_INSN_LIST (copy, old);
 }
@@ -2599,6 +2603,7 @@ static rtx_expr_list *
 concat_expr_list (rtx_expr_list *copy, rtx_expr_list *old)
 {
   if (!old)
+    /* See comment in concat_insn_list() above.  */
     return copy_EXPR_LIST (copy);
   return concat_EXPR_LIST (copy, old);
 }
-- 
2.34.1


  parent reply	other threads:[~2023-11-22 11:15 UTC|newest]

Thread overview: 37+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-11-20 12:06 [PATCH 0/1] Avoid exponential behavior in scheduler and better logging Maxim Kuvyrkov
2023-11-20 12:06 ` [PATCH 1/1] sched-deps.cc (find_modifiable_mems): Avoid exponential behavior Maxim Kuvyrkov
2023-11-20 13:09   ` Richard Biener
2023-11-20 13:42     ` Maxim Kuvyrkov
2023-11-20 13:45       ` Richard Biener
2023-11-20 14:48         ` [PATCH v2] " Maxim Kuvyrkov
2023-11-20 18:59         ` [PATCH 1/1] " Maxim Kuvyrkov
2023-11-20 13:52   ` Alexander Monakov
2023-11-20 14:39     ` Maxim Kuvyrkov
2023-11-20 16:30       ` Alexander Monakov
2023-11-21 10:32         ` Maxim Kuvyrkov
2023-11-21 11:05           ` Alexander Monakov
2023-11-22 11:14 ` [PATCH v3 0/8] Avoid exponential behavior in scheduler and better logging Maxim Kuvyrkov
2023-11-22 11:14 ` [PATCH v3 1/8] sched-deps.cc (find_modifiable_mems): Avoid exponential behavior Maxim Kuvyrkov
2024-01-15 12:56   ` Maxim Kuvyrkov
2024-01-15 18:26     ` Vladimir Makarov
2024-01-16 14:52     ` Jeff Law
2024-01-17  6:51       ` Richard Biener
2024-01-17  7:39         ` Maxim Kuvyrkov
2024-01-17 15:02           ` Richard Biener
2024-01-17 15:05             ` Maxim Kuvyrkov
2024-01-17 15:44               ` Maxim Kuvyrkov
2024-01-17 18:54             ` H.J. Lu
2023-11-22 11:14 ` [PATCH v3 2/8] Unify implementations of print_hard_reg_set() Maxim Kuvyrkov
2023-11-22 15:04   ` Vladimir Makarov
2023-11-22 11:14 ` [PATCH v3 3/8] Simplify handling of INSN_ and EXPR_LISTs in sched-rgn.cc Maxim Kuvyrkov
2024-01-15 12:59   ` Maxim Kuvyrkov
2023-11-22 11:14 ` [PATCH v3 4/8] Improve and fix sched-deps.cc: dump_dep() and dump_lists() Maxim Kuvyrkov
2024-01-15 13:01   ` Maxim Kuvyrkov
2023-11-22 11:14 ` [PATCH v3 5/8] Add a bit more logging scheduler's dependency analysis Maxim Kuvyrkov
2024-01-15 13:04   ` Maxim Kuvyrkov
2023-11-22 11:14 ` [PATCH v3 6/8] sched_deps.cc: Simplify initialization of dependency contexts Maxim Kuvyrkov
2024-01-15 13:05   ` Maxim Kuvyrkov
2023-11-22 11:14 ` [PATCH v3 7/8] Improve logging of register data in scheduler dependency analysis Maxim Kuvyrkov
2024-01-15 13:06   ` Maxim Kuvyrkov
2023-11-22 11:14 ` Maxim Kuvyrkov [this message]
2024-01-15 13:08   ` [PATCH v3 8/8] Improve logging of scheduler dependency analysis context Maxim Kuvyrkov

Reply instructions:

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

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

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

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

  git send-email \
    --in-reply-to=20231122111415.815147-9-maxim.kuvyrkov@linaro.org \
    --to=maxim.kuvyrkov@linaro.org \
    --cc=amonakov@ispras.ru \
    --cc=bernds_cb1@t-online.de \
    --cc=gcc-patches@gcc.gnu.org \
    --cc=jeffreyalaw@gmail.com \
    --cc=richard.guenther@gmail.com \
    --cc=vmakarov@redhat.com \
    /path/to/YOUR_REPLY

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

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