Bug 1464501 - Part 3: Use rust-size to get section sizes. r=froydnj
authorEric Rahm <erahm@mozilla.com>
Thu, 07 Jun 2018 17:25:18 -0700
changeset 422639 c6d82575895c86a073d95cb2157e1e9a17d5c834
parent 422638 05c128083f25afdc0be8bc2d344e43f1dc5acc19
child 422640 7336f8d839014d88c2fe1feb7a54fbfd2d8b51db
push id34140
push useraciure@mozilla.com
push dateFri, 15 Jun 2018 09:49:23 +0000
treeherdermozilla-central@0b5495dc100d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfroydnj
bugs1464501
milestone62.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1464501 - Part 3: Use rust-size to get section sizes. r=froydnj
testing/mozharness/mozharness/mozilla/building/buildbase.py
--- a/testing/mozharness/mozharness/mozilla/building/buildbase.py
+++ b/testing/mozharness/mozharness/mozilla/building/buildbase.py
@@ -1601,77 +1601,93 @@ or run without that action (ie: --no-{ac
             })
 
     def _get_sections(self, file, filter=None):
         """
         Returns a dictionary of sections and their sizes.
         """
         from StringIO import StringIO
 
-        # Check for binutils' `size` program
-        size_names = ('size', 'gsize')
-        size_prog = None
-        for name in size_names:
-            size_prog = self.which(name)
-            if size_prog:
-                break
+        # Check for `rust_size`, our cross platform version of size. It should
+        # be installed by tooltool in $abs_src_dir/rust-size/rust-size
+        rust_size = os.path.join(self.query_abs_dirs()['abs_src_dir'],
+                                 'rust-size', 'rust-size')
+        size_prog = self.which(rust_size)
+        if not size_prog:
+            self.info("Couldn't find `rust-size` program")
+            return {}
 
-        if not size_prog:
-            self.info("Couldn't find `size` program")
+        self.info("Using %s" % size_prog)
+        cmd = [size_prog, file]
+        output = self.get_output_from_command(cmd)
+        if not output:
+            self.info("`rust-size` failed")
             return {}
 
-        # Call `size` and output with SysV format in decimal radix
-        cmd = [size_prog, '-A', '-d', file]
-        output = self.get_output_from_command(cmd)
-        if not output:
+        # Format is JSON:
+        # {
+        #   "section_type": {
+        #     "section_name": size, ....
+        #   },
+        #   ...
+        # }
+        try:
+            parsed = json.loads(output)
+        except ValueError:
+            self.info("`rust-size` failed: %s" % output)
             return {}
 
-        # Format is:
-        # <section-name> <size> <address>, ie:
-        # .data                  302160   101053344
-        size_section_re = re.compile(r"([\w\.]+)\s+(\d+)\s+(\d+)")
         sections = {}
-        for line in output.splitlines():
-            m = size_section_re.match(line)
-            if m:
-                name = m.group(1)
+        for sec_type in parsed.itervalues():
+            for name, size in sec_type.iteritems():
                 if not filter or name in filter:
-                    sections[name] = int(m.group(2))
+                    sections[name] = size
 
         return sections
 
     def _get_binary_metrics(self):
         """
         Provides metrics on interesting compenents of the built binaries.
         Currently just the sizes of interesting sections.
         """
         lib_interests = {
             'XUL': ('libxul.so', 'xul.dll', 'XUL'),
             'NSS': ('libnss3.so', 'nss3.dll', 'libnss3.dylib'),
             'NSPR': ('libnspr4.so', 'nspr4.dll', 'libnspr4.dylib'),
             'avcodec': ('libmozavcodec.so', 'mozavcodec.dll', 'libmozavcodec.dylib'),
             'avutil': ('libmozavutil.so', 'mozavutil.dll', 'libmozavutil.dylib')
         }
-        # TODO(erahm): update for windows and osx. As-is we only have support
-        # for `size` on debian which gives us linux and android.
-        section_interests = ('.text', '.data', '.rodata', '.data.rel.ro', '.bss')
+        section_interests = ('.text', '.data', '.rodata', '.rdata',
+                             '.cstring', '.data.rel.ro', '.bss')
         lib_details = []
 
         dirs = self.query_abs_dirs()
         dist_dir = os.path.join(dirs['abs_obj_dir'], 'dist')
         bin_dir = os.path.join(dist_dir, 'bin')
 
         for lib_type, lib_names in lib_interests.iteritems():
             for lib_name in lib_names:
                 lib = os.path.join(bin_dir, lib_name)
                 if os.path.exists(lib):
                     lib_size = 0
                     section_details = self._get_sections(lib, section_interests)
                     section_measurements = []
                     # Build up the subtests
+
+                    # Lump rodata sections together
+                    # - Mach-O separates out read-only string data as .cstring
+                    # - PE really uses .rdata, but XUL at least has a .rodata as well
+                    for ro_alias in ('.cstring', '.rdata'):
+                        if ro_alias in section_details:
+                            if '.rodata' in section_details:
+                                section_details['.rodata'] += section_details[ro_alias]
+                            else:
+                                section_details['.rodata'] = section_details[ro_alias]
+                            del section_details[ro_alias]
+
                     for k, v in section_details.iteritems():
                         section_measurements.append({'name': k, 'value': v})
                         lib_size += v
                     lib_details.append({
                         'name': lib_type,
                         'size': lib_size,
                         'sections': section_measurements
                     })