Map ".text.hot" and ".text.unlikely" input section prefixes to separate output sections.

Sriraman Tallam tmsriram@google.com
Wed Nov 21 03:08:00 GMT 2012


Hi Ian,

On Tue, Nov 20, 2012 at 10:00 AM, Ian Lance Taylor <iant@google.com> wrote:
> On Tue, Nov 20, 2012 at 9:50 AM, Sriraman Tallam <tmsriram@google.com> wrote:
>> On Mon, Nov 19, 2012 at 4:52 PM, Ian Lance Taylor <iant@google.com> wrote:
>>> On Mon, Nov 19, 2012 at 2:52 PM, Alan Modra <amodra@gmail.com> wrote:
>>>> On Fri, Nov 16, 2012 at 05:19:01PM -0800, Ian Lance Taylor wrote:
>>>>> On Wed, Nov 14, 2012 at 5:06 PM, Sriraman Tallam <tmsriram@google.com> wrote:
>>>>> >> Ideally gold should group all input sections with the same name
>>>>
>>>> I strongly disagree.  Grouping sections with the same name is a bad
>>>> idea, unless the name gives you some infomation from the compiler (as
>>>> it does with .text.hot* et al).  The problem with grouping sections
>>>> with the same name is that with -ffunction-sections objects, you'll
>>>> potentially move functions away from their callers, losing cache
>>>> locality.  The canonical example is a number of object files with
>>>> static "setup" functions.  These will all have code in .text.setup,
>>>> but there is no good reason to group these sections.
>>>
>>> That is a good point.
>>>
>>> Unfortunately it leaves us adding more special cases for section
>>> names, which I really dislike.  Is there any happy medium?
>>
>> gold now has multiple ways to reorder functions. There is the
>> --section-ordering-file option, there is the plugin interface, and
>> also the reordering via linker scripts.  So, instead of adding another
>> way to sort text sections, I was wondering instead if we could just
>> use the --section-ordering-file  mechanism.  I can initialize the data
>> structures to do this ordering by default.  Is this a reasonable idea?
>
> Sure, if it works, and if using the --section-ordering-file option
> doesn't discard the defaults unnecessarily.

I have attached the new patch. This is slightly different from the old
patch in that:

* It does not create a new sort method. The existing method for
section_ordering is modified.
* It sorts text sections only when it finds atleast one section with
the special prefix.

Thanks,
-Sri.

>
> Ian
-------------- next part --------------
	* layout.cc (Layout::is_section_name_prefix_grouped): New function.
	* layout.h (Layout::is_section_name_prefix_grouped): New function.
	* output.cc (Output_section::add_input_section): Check if section
	name contains special prefix.  Keep input sections to sort such
	sections.
	(Output_section::Input_section_sort_section_order_index_compare
	 ::operator()): Group sections according to prefixes.
	* (Output_section::sort_attached_input_sections): Add condition
	to Input_section_entry constructor call.
	* testsuite/Makefile.am (text_section_grouping): New test.
	* testsuite/Makefile.in: Regenerate.
	* testsuite/text_section_grouping.cc: New file.
	* testsuite/text_section_grouping.sh: New file.

Index: layout.cc
===================================================================
RCS file: /cvs/src/src/gold/layout.cc,v
retrieving revision 1.239
diff -u -u -p -r1.239 layout.cc
--- layout.cc	16 Oct 2012 16:50:32 -0000	1.239
+++ layout.cc	21 Nov 2012 02:58:49 -0000
@@ -2409,6 +2409,20 @@ Layout::relaxation_loop_body(
   return off;
 }
 
+// By default, gold groups input sections with certain prefixes.  This 
+// function returns true if this section name NAME contains such a prefix.
+
+bool
+Layout::is_section_name_prefix_grouped(const char *name)
+{
+  if (is_prefix_of(".text.unlikely", name)
+      || is_prefix_of(".text.startup", name)
+      || is_prefix_of(".text.hot", name))
+    return true;
+
+  return false;
+}
+
 // Search the list of patterns and find the postion of the given section
 // name in the output section.  If the section name matches a glob
 // pattern and a non-glob name, then the non-glob position takes
Index: layout.h
===================================================================
RCS file: /cvs/src/src/gold/layout.h,v
retrieving revision 1.105
diff -u -u -p -r1.105 layout.h
--- layout.h	24 Aug 2012 18:35:34 -0000	1.105
+++ layout.h	21 Nov 2012 02:58:49 -0000
@@ -552,6 +552,11 @@ class Layout
   // Maps section SECN to SEGMENT s.
   void
   insert_section_segment_map(Const_section_id secn, Unique_segment_info *s);
+
+  // By default, gold groups input sections with certain prefixes.  This 
+  // function returns true if this section name NAME contains such a prefix.
+  bool
+  is_section_name_prefix_grouped(const char *name);
   
   bool
   is_section_ordering_specified()
Index: output.cc
===================================================================
RCS file: /cvs/src/src/gold/output.cc,v
retrieving revision 1.176
diff -u -u -p -r1.176 output.cc
--- output.cc	1 Nov 2012 22:35:06 -0000	1.176
+++ output.cc	21 Nov 2012 02:58:49 -0000
@@ -2476,6 +2476,19 @@ Output_section::add_input_section(Layout
         }
     }
 
+  // The GNU linker groups input sections whose names match .text.unlikely.*.
+  // This is used to get better code layout.  We are compatible.
+  // Additionally, it could also be beneficial to group .text.hot.*,
+  // .text.startup.* prefixed input sections.  Function
+  // "is_section_name_prefix_grouped" in layout.cc determines the input
+  // section prefixes that must be grouped.
+  if (!have_sections_script
+      && !parameters->options().relocatable()
+      && !this->input_section_order_specified()
+      && !this->must_sort_attached_input_sections()
+      && layout->is_section_name_prefix_grouped(secname))
+    this->set_input_section_order_specified();
+
   // We need to keep track of this section if we are already keeping
   // track of sections, or if we are relaxing.  Also, if this is a
   // section which requires sorting, or which may require sorting in
@@ -2489,7 +2502,8 @@ Output_section::add_input_section(Layout
       || this->must_sort_attached_input_sections()
       || parameters->options().user_set_Map()
       || parameters->target().may_relax()
-      || layout->is_section_ordering_specified())
+      || layout->is_section_ordering_specified()
+      || this->input_section_order_specified())
     {
       Input_section isecn(object, shndx, input_section_size, addralign);
       /* If section ordering is requested by specifying a ordering file,*/
@@ -3482,7 +3496,9 @@ Output_section::Input_section_sort_init_
 
 // Return true if S1 should come before S2.  Sections that do not match
 // any pattern in the section ordering file are placed ahead of the sections
-// that match some pattern.
+// that match some pattern.  This function is also used to group text according
+// to their prefix.  The following prefixes are recognized: ".text.startup",
+// ".text.hot", and ".text.unlikely".
 
 bool
 Output_section::Input_section_sort_section_order_index_compare::operator()(
@@ -3492,11 +3508,57 @@ Output_section::Input_section_sort_secti
   unsigned int s1_secn_index = s1.input_section().section_order_index();
   unsigned int s2_secn_index = s2.input_section().section_order_index();
 
-  // Keep input order if section ordering cannot determine order.
-  if (s1_secn_index == s2_secn_index)
-    return s1.index() < s2.index();
+  // If section ordering is specified, it takes precedence.
+  if (s1_secn_index != s2_secn_index)
+    return s1_secn_index < s2_secn_index;
+
+  // Sort all the sections with no names to the end.
+  if (!s1.section_has_name() || !s2.section_has_name())
+    {
+      if (s1.section_has_name())
+	return true;
+      if (s2.section_has_name())
+	return false;
+      return s1.index() < s2.index();
+    }
+
+  // If it is a text section use the following order:
+  // .text.unlikely, .text.startup, .text.hot.
+  const char* section_prefix [] = 
+  {
+    ".text.unlikely",
+    ".text.startup",
+    ".text.hot"
+  };
+
+  const unsigned int num_prefixes
+    = sizeof(section_prefix) / sizeof(const char*);
+
+  unsigned int s1_group_index = num_prefixes;
+  unsigned int s2_group_index = num_prefixes;
+
+  unsigned int flag_done = 0;
+  for (unsigned int i = 0; i < num_prefixes && flag_done < 2; i++)
+    {
+      if (s1_group_index == num_prefixes
+	  && is_prefix_of(section_prefix[i], s1.section_name().c_str()))
+	{
+          s1_group_index = i;
+	  flag_done++;
+	}
 
-  return s1_secn_index < s2_secn_index;
+      if (s2_group_index == num_prefixes
+	  && is_prefix_of(section_prefix[i], s2.section_name().c_str()))
+	{
+          s2_group_index = i;
+	  flag_done++;
+	}
+    }
+
+  if (s1_group_index == s2_group_index)
+    return s1.index() < s2.index();
+  else
+    return s1_group_index < s2_group_index;
 }
 
 // This updates the section order index of input sections according to the
@@ -3557,7 +3619,8 @@ Output_section::sort_attached_input_sect
        p != this->input_sections_.end();
        ++p, ++i)
       sort_list.push_back(Input_section_sort_entry(*p, i,
-                            this->must_sort_attached_input_sections()));
+                            (this->must_sort_attached_input_sections()
+			     || this->input_section_order_specified())));
 
   // Sort the input sections.
   if (this->must_sort_attached_input_sections())
Index: testsuite/Makefile.am
===================================================================
RCS file: /cvs/src/src/gold/testsuite/Makefile.am,v
retrieving revision 1.200
diff -u -u -p -r1.200 Makefile.am
--- testsuite/Makefile.am	26 Oct 2012 00:50:05 -0000	1.200
+++ testsuite/Makefile.am	21 Nov 2012 02:58:49 -0000
@@ -250,6 +250,16 @@ final_layout: final_layout.o final_layou
 final_layout.stdout: final_layout
 	$(TEST_NM) -n --synthetic final_layout > final_layout.stdout
 
+check_SCRIPTS += text_section_grouping.sh
+check_DATA += text_section_grouping.stdout
+MOSTLYCLEANFILES += text_section_grouping
+text_section_grouping.o: text_section_grouping.cc
+	$(CXXCOMPILE) -O0 -c -ffunction-sections -g -o $@ $<
+text_section_grouping: text_section_grouping.o gcctestdir/ld
+	$(CXXLINK)  -Bgcctestdir/ text_section_grouping.o
+text_section_grouping.stdout: text_section_grouping
+	$(TEST_NM) -n --synthetic text_section_grouping > text_section_grouping.stdout 
+
 check_PROGRAMS += icf_virtual_function_folding_test
 MOSTLYCLEANFILES += icf_virtual_function_folding_test
 icf_virtual_function_folding_test.o: icf_virtual_function_folding_test.cc
Index: testsuite/text_section_grouping.cc
===================================================================
RCS file: testsuite/text_section_grouping.cc
diff -N testsuite/text_section_grouping.cc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/text_section_grouping.cc	21 Nov 2012 02:58:50 -0000
@@ -0,0 +1,72 @@
+// text_section_grouping.cc -- a test case for gold
+
+// Copyright 2012 Free Software Foundation, Inc.
+// Written by Sriraman Tallam <tmsriram@google.com>.
+
+// This file is part of gold.
+
+// This program 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 of the License, or
+// (at your option) any later version.
+
+// This program 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 this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+// MA 02110-1301, USA.
+
+// The goal of this program is to verify if .text sections are grouped
+// according to prefix.  .text.unlikely, .text.startup and .text.hot should
+// be grouped and placed together.
+
+extern "C"
+__attribute__ ((section(".text.hot.foo")))
+int hot_foo()
+{
+  return 1;
+}
+
+extern "C"
+__attribute__ ((section(".text.startup.foo")))
+int startup_foo()
+{
+  return 1;
+}
+
+extern "C"
+__attribute__ ((section(".text.unlikely.foo")))
+int unlikely_foo()
+{
+  return 1;
+}
+
+extern "C"
+__attribute__ ((section(".text.hot.bar")))
+int hot_bar()
+{
+  return 1;
+}
+
+extern "C"
+__attribute__ ((section(".text.startup.bar")))
+int startup_bar()
+{
+  return 1;
+}
+
+extern "C"
+__attribute__ ((section(".text.unlikely.bar")))
+int unlikely_bar()
+{
+  return 1;
+}
+
+int main()
+{
+  return 1;
+}
Index: testsuite/text_section_grouping.sh
===================================================================
RCS file: testsuite/text_section_grouping.sh
diff -N testsuite/text_section_grouping.sh
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/text_section_grouping.sh	21 Nov 2012 02:58:50 -0000
@@ -0,0 +1,65 @@
+#!/bin/sh
+
+# text_section_grouping.sh -- test
+
+# Copyright 2012 Free Software Foundation, Inc.
+# Written by Sriraman Tallam <tmsriram@google.com>.
+
+# This file is part of gold.
+
+# This program 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 of the License, or
+# (at your option) any later version.
+
+# This program 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 this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+# MA 02110-1301, USA.
+
+# The goal of this program is to verify if .text sections are grouped
+# according to prefix.  .text.unlikely, .text.startup and .text.hot should
+# be grouped and placed together.
+
+set -e
+
+check()
+{
+    awk "
+BEGIN { saw1 = 0; saw2 = 0; err = 0; }
+/.*$2\$/ { saw1 = 1; }
+/.*$3\$/ {
+     saw2 = 1;
+     if (!saw1)
+       {
+	  printf \"layout of $2 and $3 is not right\\n\";
+	  err = 1;
+	  exit 1;
+       }
+    }
+END {
+      if (!saw1 && !err)
+        {
+	  printf \"did not see $2\\n\";
+	  exit 1;
+	}
+      if (!saw2 && !err)
+	{
+	  printf \"did not see $3\\n\";
+	  exit 1;
+	}
+    }" $1
+}
+
+# addr (unlikely_*) < addr (startup_*) < addr (hot_*)
+check text_section_grouping.stdout "unlikely_foo" "startup_foo"
+check text_section_grouping.stdout "startup_foo" "hot_foo"
+check text_section_grouping.stdout "unlikely_bar" "startup_bar"
+check text_section_grouping.stdout "startup_bar" "hot_bar"
+check text_section_grouping.stdout "unlikely_foo" "startup_bar"
+check text_section_grouping.stdout "startup_foo" "hot_bar"


More information about the Binutils mailing list