Bug 1628073 - Move gecko profiler testing files to mozgeckoprofiler; r=sparky,perftest-reviewers,gbrown
authorGreg Tatum <gtatum@mozilla.com>
Fri, 22 May 2020 13:18:44 +0000
changeset 531614 bfb980a9199bb85e8b95bc064ed1e25e488b6af9
parent 531613 3223007370b6abf6ffe9848a3496d75a3dd6b0fc
child 531615 699e0e8cd072d7cb9ff4250e17020244a410ec52
push id37441
push userapavel@mozilla.com
push dateFri, 22 May 2020 21:38:53 +0000
treeherdermozilla-central@d6abd35b54ad [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssparky, perftest-reviewers, gbrown
bugs1628073
milestone78.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 1628073 - Move gecko profiler testing files to mozgeckoprofiler; r=sparky,perftest-reviewers,gbrown I need to add symbolication support for the mochitest Gecko Profiler command line option. These profiles also need to be symbolicated. Unfortunately, there is not a common place where I could use these files. Talos and Raptor each had their own copy of the snappy symbolication server. This commit consolidates these packages into a re-usable mozbase package that can be used in mochitests, and eventually in other places like xpcshell tests. I stubbed out a test file, but it doesn't do anything quite yet. This commit makes it so that the tests still work in Raptor and Talos, but doesn't add any features. It also doesn't try too hard to make the files look like a mozbase package. Differential Revision: https://phabricator.services.mozilla.com/D74289
testing/config/mozbase_requirements.txt
testing/config/mozbase_source_requirements.txt
testing/mozbase/moz.build
testing/mozbase/mozgeckoprofiler/mozgeckoprofiler/README.txt
testing/mozbase/mozgeckoprofiler/mozgeckoprofiler/__init__.py
testing/mozbase/mozgeckoprofiler/mozgeckoprofiler/dump_syms_mac
testing/mozbase/mozgeckoprofiler/mozgeckoprofiler/profiling.py
testing/mozbase/mozgeckoprofiler/mozgeckoprofiler/symFileManager.py
testing/mozbase/mozgeckoprofiler/mozgeckoprofiler/symLogging.py
testing/mozbase/mozgeckoprofiler/mozgeckoprofiler/symbolication.py
testing/mozbase/mozgeckoprofiler/mozgeckoprofiler/symbolicationRequest.py
testing/mozbase/mozgeckoprofiler/setup.py
testing/mozbase/mozgeckoprofiler/tests/manifest.ini
testing/mozbase/mozgeckoprofiler/tests/test_view_gecko_profiler.py
testing/mozbase/packages.txt
testing/raptor/raptor/gecko_profile.py
testing/raptor/raptor/profiler/README.txt
testing/raptor/raptor/profiler/__init__.py
testing/raptor/raptor/profiler/dump_syms_mac
testing/raptor/raptor/profiler/profiling.py
testing/raptor/raptor/profiler/symFileManager.py
testing/raptor/raptor/profiler/symLogging.py
testing/raptor/raptor/profiler/symbolication.py
testing/raptor/raptor/profiler/symbolicationRequest.py
testing/talos/talos/gecko_profile.py
testing/talos/talos/profiler/README.txt
testing/talos/talos/profiler/__init__.py
testing/talos/talos/profiler/dump_syms_mac
testing/talos/talos/profiler/profiling.py
testing/talos/talos/profiler/symFileManager.py
testing/talos/talos/profiler/symLogging.py
testing/talos/talos/profiler/symbolication.py
testing/talos/talos/profiler/symbolicationRequest.py
testing/tools/mach_test_package_bootstrap.py
tools/lint/file-whitespace.yml
--- a/testing/config/mozbase_requirements.txt
+++ b/testing/config/mozbase_requirements.txt
@@ -1,15 +1,16 @@
 ../tools/mozterm
 
 ../mozbase/manifestparser
 ../mozbase/mozcrash
 ../mozbase/mozdebug
 ../mozbase/mozdevice
 ../mozbase/mozfile
+../mozbase/mozgeckoprofiler
 ../mozbase/mozhttpd
 ../mozbase/mozinfo
 ../mozbase/mozinstall
 ../mozbase/mozleak
 ../mozbase/mozlog
 ../mozbase/moznetwork
 ../mozbase/mozpower
 ../mozbase/mozprocess
--- a/testing/config/mozbase_source_requirements.txt
+++ b/testing/config/mozbase_source_requirements.txt
@@ -1,15 +1,16 @@
 --editable ../../python/mozterm
 
 --editable ../mozbase/manifestparser
 --editable ../mozbase/mozcrash
 --editable ../mozbase/mozdebug
 --editable ../mozbase/mozdevice
 --editable ../mozbase/mozfile
+--editable ../mozbase/mozgeckoprofiler
 --editable ../mozbase/mozhttpd
 --editable ../mozbase/mozinfo
 --editable ../mozbase/mozinstall
 --editable ../mozbase/mozleak
 --editable ../mozbase/mozlog
 --editable ../mozbase/moznetwork
 --editable ../mozbase/mozpower
 --editable ../mozbase/mozprocess
--- a/testing/mozbase/moz.build
+++ b/testing/mozbase/moz.build
@@ -5,16 +5,17 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 PYTHON_UNITTEST_MANIFESTS += [
     'manifestparser/tests/manifest.ini',
     'mozcrash/tests/manifest.ini',
     'mozdebug/tests/manifest.ini',
     'mozdevice/tests/manifest.ini',
     'mozfile/tests/manifest.ini',
+    'mozgeckoprofiler/tests/manifest.ini',
     'mozhttpd/tests/manifest.ini',
     'mozinfo/tests/manifest.ini',
     'mozinstall/tests/manifest.ini',
     'mozleak/tests/manifest.ini',
     'mozlog/tests/manifest.ini',
     'moznetwork/tests/manifest.ini',
     'mozpower/tests/manifest.ini',
     'mozprocess/tests/manifest.ini',
@@ -27,16 +28,17 @@ PYTHON_UNITTEST_MANIFESTS += [
 ]
 
 python_modules = [
     'manifestparser',
     'mozcrash',
     'mozdebug',
     'mozdevice',
     'mozfile',
+    'mozgeckoprofiler',
     'mozhttpd',
     'mozinfo',
     'mozinstall',
     'mozleak',
     'mozlog',
     'moznetwork',
     'mozpower',
     'mozprocess',
rename from testing/raptor/raptor/profiler/README.txt
rename to testing/mozbase/mozgeckoprofiler/mozgeckoprofiler/README.txt
rename from testing/talos/talos/profiler/__init__.py
rename to testing/mozbase/mozgeckoprofiler/mozgeckoprofiler/__init__.py
--- a/testing/talos/talos/profiler/__init__.py
+++ b/testing/mozbase/mozgeckoprofiler/mozgeckoprofiler/__init__.py
@@ -0,0 +1,16 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this file,
+# You can obtain one at http://mozilla.org/MPL/2.0/.
+
+"""
+mozgeckoprofiler has utilities to symbolicate and load gecko profiles.
+"""
+from __future__ import absolute_import
+
+from .profiling import save_gecko_profile
+from .symbolication import ProfileSymbolicator
+
+__all__ = [
+  'save_gecko_profile',
+  'ProfileSymbolicator',
+]
rename from testing/talos/talos/profiler/dump_syms_mac
rename to testing/mozbase/mozgeckoprofiler/mozgeckoprofiler/dump_syms_mac
rename from testing/talos/talos/profiler/profiling.py
rename to testing/mozbase/mozgeckoprofiler/mozgeckoprofiler/profiling.py
--- a/testing/talos/talos/profiler/profiling.py
+++ b/testing/mozbase/mozgeckoprofiler/mozgeckoprofiler/profiling.py
@@ -1,11 +1,11 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-from __future__ import absolute_import
-
-import json
-
-
-def save_profile(profile, filename):
-    with open(filename, "w") as f:
-        json.dump(profile, f)
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+from __future__ import absolute_import
+
+import json
+
+
+def save_gecko_profile(profile, filename):
+    with open(filename, "w") as f:
+        json.dump(profile, f)
old mode 100755
new mode 100644
rename from testing/talos/talos/profiler/symFileManager.py
rename to testing/mozbase/mozgeckoprofiler/mozgeckoprofiler/symFileManager.py
old mode 100755
new mode 100644
rename from testing/raptor/raptor/profiler/symLogging.py
rename to testing/mozbase/mozgeckoprofiler/mozgeckoprofiler/symLogging.py
old mode 100755
new mode 100644
rename from testing/talos/talos/profiler/symbolication.py
rename to testing/mozbase/mozgeckoprofiler/mozgeckoprofiler/symbolication.py
rename from testing/talos/talos/profiler/symbolicationRequest.py
rename to testing/mozbase/mozgeckoprofiler/mozgeckoprofiler/symbolicationRequest.py
new file mode 100644
--- /dev/null
+++ b/testing/mozbase/mozgeckoprofiler/setup.py
@@ -0,0 +1,34 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this file,
+# You can obtain one at http://mozilla.org/MPL/2.0/.
+
+from __future__ import absolute_import
+
+from setuptools import setup
+
+PACKAGE_NAME = "mozgeckoprofiler"
+PACKAGE_VERSION = "1.0.0"
+
+setup(
+    name=PACKAGE_NAME,
+    version=PACKAGE_VERSION,
+    description="Library to generate and view performance data in the Firefox Profiler",
+    long_description="see https://firefox-source-docs.mozilla.org/mozgeckoprofiler/index.html",
+    classifiers=[
+        "Programming Language :: Python :: 2",
+        "Programming Language :: Python :: 2.7",
+        "Programming Language :: Python :: 3",
+        "Programming Language :: Python :: 3.5",
+        "License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)",
+    ],
+    keywords="mozilla",
+    author="Mozilla Automation and Tools team",
+    author_email="tools@lists.mozilla.org",
+    url="https://wiki.mozilla.org/Auto-tools/Projects/Mozbase",
+    license="MPL",
+    packages=["mozgeckoprofiler"],
+    include_package_data=True,
+    zip_safe=False,
+    install_requires=[],
+    tests_require=[],
+)
new file mode 100644
--- /dev/null
+++ b/testing/mozbase/mozgeckoprofiler/tests/manifest.ini
@@ -0,0 +1,3 @@
+[DEFAULT]
+subsuite = mozbase
+[test_view_gecko_profiler.py]
new file mode 100644
--- /dev/null
+++ b/testing/mozbase/mozgeckoprofiler/tests/test_view_gecko_profiler.py
@@ -0,0 +1,18 @@
+#!/usr/bin/env python
+
+from __future__ import absolute_import, print_function
+
+import unittest
+import mozunit
+
+
+class TestGeckoProfiler(unittest.TestCase):
+    """test extracting archives"""
+
+    def test_it_works(self):
+        """test that this works"""
+        self.assertTrue(True)
+
+
+if __name__ == '__main__':
+    mozunit.main()
--- a/testing/mozbase/packages.txt
+++ b/testing/mozbase/packages.txt
@@ -1,14 +1,15 @@
 manifestparser.pth:testing/mozbase/manifestparser
 mozcrash.pth:testing/mozbase/mozcrash
 mozdebug.pth:testing/mozbase/mozdebug
 mozdevice.pth:testing/mozbase/mozdevice
 mozfile.pth:testing/mozbase/mozfile
 mozhttpd.pth:testing/mozbase/mozhttpd
+mozgeckoprofiler.pth:testing/mozbase/mozgeckoprofiler
 mozinfo.pth:testing/mozbase/mozinfo
 mozinstall.pth:testing/mozbase/mozinstall
 mozleak.pth:testing/mozbase/mozleak
 mozlog.pth:testing/mozbase/mozlog
 moznetwork.pth:testing/mozbase/moznetwork
 mozpower.pth:testing/mozbase/mozpower
 mozprocess.pth:testing/mozbase/mozprocess
 mozprofile.pth:testing/mozbase/mozprofile
--- a/testing/raptor/raptor/gecko_profile.py
+++ b/testing/raptor/raptor/gecko_profile.py
@@ -11,17 +11,17 @@ import json
 import os
 import tempfile
 import zipfile
 import fnmatch
 
 import mozfile
 
 from logger.logger import RaptorLogger
-from profiler import symbolication, profiling
+from mozgeckoprofiler import ProfileSymbolicator, save_gecko_profile
 
 here = os.path.dirname(os.path.realpath(__file__))
 LOG = RaptorLogger(component='raptor-gecko-profile')
 
 
 class GeckoProfile(object):
     """
     Handle Gecko profiling.
@@ -95,17 +95,17 @@ class GeckoProfile(object):
         LOG.info("Symbolicating profile at %s" % profile_path)
         try:
             with open(profile_path, 'r') as profile_file:
                 profile = json.load(profile_file)
             symbolicator.dump_and_integrate_missing_symbols(
                 profile,
                 missing_symbols_zip)
             symbolicator.symbolicate_profile(profile)
-            profiling.save_profile(profile, profile_path)
+            save_gecko_profile(profile, profile_path)
         except MemoryError:
             LOG.critical(
                 "Ran out of memory while trying"
                 " to symbolicate profile {0}"
                 .format(profile_path)
             )
         except Exception:
             LOG.critical("Encountered an exception during profile"
@@ -133,17 +133,17 @@ class GeckoProfile(object):
         Symbolicate Gecko profiling data for one pagecycle.
 
         """
         profiles = self.collect_profiles()
         if len(profiles) == 0:
             LOG.error("No profiles collected")
             return
 
-        symbolicator = symbolication.ProfileSymbolicator({
+        symbolicator = ProfileSymbolicator({
             # Trace-level logging (verbose)
             "enableTracing": 0,
             # Fallback server if symbol is not found locally
             "remoteSymbolServer":
                 "https://symbols.mozilla.org/symbolicate/v4",
             # Maximum number of symbol files to keep in memory
             "maxCacheEntries": 2000000,
             # Frequency of checking for recent symbols to
deleted file mode 100644
deleted file mode 100755
index cc23e4a1148bb2885076609388951b862efdfc7f..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100755
--- a/testing/raptor/raptor/profiler/profiling.py
+++ /dev/null
@@ -1,11 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-from __future__ import absolute_import
-
-import json
-
-
-def save_profile(profile, filename):
-    with open(filename, "w") as f:
-        json.dump(profile, f)
deleted file mode 100755
--- a/testing/raptor/raptor/profiler/symFileManager.py
+++ /dev/null
@@ -1,322 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-from __future__ import absolute_import
-
-import itertools
-import os
-import re
-import threading
-import time
-from bisect import bisect
-
-from .symLogging import LogTrace, LogError, LogMessage
-
-# Libraries to keep prefetched
-PREFETCHED_LIBS = ["xul.pdb", "firefox.pdb"]
-
-
-class SymbolInfo:
-
-    def __init__(self, addressMap):
-        self.sortedAddresses = sorted(addressMap.keys())
-        self.sortedSymbols = [addressMap[address]
-                              for address in self.sortedAddresses]
-        self.entryCount = len(self.sortedAddresses)
-
-    # TODO: Add checks for address < funcEnd ?
-    def Lookup(self, address):
-        nearest = bisect(self.sortedAddresses, address) - 1
-        if nearest < 0:
-            return None
-        return self.sortedSymbols[nearest]
-
-    def GetEntryCount(self):
-        return self.entryCount
-
-# Singleton for .sym / .nmsym file cache management
-
-
-class SymFileManager:
-    # Symbol cache data structures
-    sCache = {}
-    sCacheCount = 0
-    sCacheLock = threading.Lock()
-    sMruSymbols = []
-
-    sOptions = {}
-    sCallbackTimer = None
-
-    def __init__(self, options):
-        self.sOptions = options
-
-    def GetLibSymbolMap(self, libName, breakpadId, symbolSources):
-        # Empty lib name means client couldn't associate frame with any lib
-        if libName == "":
-            return None
-
-        # Check cache first
-        libSymbolMap = None
-        self.sCacheLock.acquire()
-        try:
-            if libName in self.sCache and breakpadId in self.sCache[libName]:
-                libSymbolMap = self.sCache[libName][breakpadId]
-                self.UpdateMruList(libName, breakpadId)
-        finally:
-            self.sCacheLock.release()
-
-        if libSymbolMap is None:
-            LogTrace(
-                "Need to fetch PDB file for " + libName + " " + breakpadId)
-
-            # Guess the name of the .sym or .nmsym file on disk
-            if libName[-4:] == ".pdb":
-                symFileNameWithoutExtension = re.sub(r"\.[^\.]+$", "", libName)
-            else:
-                symFileNameWithoutExtension = libName
-
-            # Look in the symbol dirs for this .sym or .nmsym file
-            for extension, source in itertools.product([".sym", ".nmsym"],
-                                                       symbolSources):
-                symFileName = symFileNameWithoutExtension + extension
-                pathSuffix = os.sep + libName + os.sep + \
-                    breakpadId + os.sep + symFileName
-                path = self.sOptions["symbolPaths"][source] + pathSuffix
-                libSymbolMap = self.FetchSymbolsFromFile(path)
-                if libSymbolMap:
-                    break
-
-            if not libSymbolMap:
-                LogTrace("No matching sym files, tried " + str(symbolSources))
-                return None
-
-            LogTrace("Storing libSymbolMap under [" + libName + "][" +
-                     breakpadId + "]")
-            self.sCacheLock.acquire()
-            try:
-                self.MaybeEvict(libSymbolMap.GetEntryCount())
-                if libName not in self.sCache:
-                    self.sCache[libName] = {}
-                self.sCache[libName][breakpadId] = libSymbolMap
-                self.sCacheCount += libSymbolMap.GetEntryCount()
-                self.UpdateMruList(libName, breakpadId)
-                LogTrace(str(self.sCacheCount) +
-                         " symbols in cache after fetching symbol file")
-            finally:
-                self.sCacheLock.release()
-
-        return libSymbolMap
-
-    def FetchSymbolsFromFile(self, path):
-        try:
-            symFile = open(path, "r")
-        except Exception as e:
-            LogTrace("Error opening file " + path + ": " + str(e))
-            return None
-
-        LogMessage("Parsing SYM file at " + path)
-
-        try:
-            symbolMap = {}
-            lineNum = 0
-            publicCount = 0
-            funcCount = 0
-            if path.endswith(".sym"):
-                for line in symFile:
-                    lineNum += 1
-                    if line[0:7] == "PUBLIC ":
-                        line = line.rstrip()
-                        fields = line.split(" ")
-                        if len(fields) < 4:
-                            LogTrace("Line " + str(lineNum) + " is messed")
-                            continue
-                        if fields[1] == "m":
-                            address = int(fields[2], 16)
-                            symbolMap[address] = " ".join(fields[4:])
-                        else:
-                            address = int(fields[1], 16)
-                            symbolMap[address] = " ".join(fields[3:])
-                        publicCount += 1
-                    elif line[0:5] == "FUNC ":
-                        line = line.rstrip()
-                        fields = line.split(" ")
-                        if len(fields) < 5:
-                            LogTrace("Line " + str(lineNum) + " is messed")
-                            continue
-                        if fields[1] == "m":
-                            address = int(fields[2], 16)
-                            symbolMap[address] = " ".join(fields[5:])
-                        else:
-                            address = int(fields[1], 16)
-                            symbolMap[address] = " ".join(fields[4:])
-                        funcCount += 1
-            elif path.endswith(".nmsym"):
-                addressLength = 0
-                for line in symFile:
-                    lineNum += 1
-                    if line.startswith(" "):
-                        continue
-                    if addressLength == 0:
-                        addressLength = line.find(" ")
-                    address = int(line[0:addressLength], 16)
-                    # Some lines have the form
-                    # "address space letter space symbol",
-                    # some have the form "address space symbol".
-                    # The letter has a meaning, but we ignore it.
-                    if line[addressLength + 2] == " ":
-                        symbol = line[addressLength + 3:].rstrip()
-                    else:
-                        symbol = line[addressLength + 1:].rstrip()
-                    symbolMap[address] = symbol
-                    publicCount += 1
-        except Exception:
-            LogError("Error parsing SYM file " + path)
-            return None
-
-        logString = "Found " + \
-            str(len(symbolMap.keys())) + " unique entries from "
-        logString += str(publicCount) + " PUBLIC lines, " + \
-            str(funcCount) + " FUNC lines"
-        LogTrace(logString)
-
-        return SymbolInfo(symbolMap)
-
-    def PrefetchRecentSymbolFiles(self):
-        global PREFETCHED_LIBS
-
-        LogMessage("Prefetching recent symbol files")
-        # Schedule next timer callback
-        interval = self.sOptions['prefetchInterval'] * 60 * 60
-        self.sCallbackTimer = threading.Timer(
-            interval, self.PrefetchRecentSymbolFiles)
-        self.sCallbackTimer.start()
-
-        thresholdTime = time.time() - \
-            self.sOptions['prefetchThreshold'] * 60 * 60
-        symDirsToInspect = {}
-        for pdbName in PREFETCHED_LIBS:
-            symDirsToInspect[pdbName] = []
-            topLibPath = self.sOptions['symbolPaths'][
-                'FIREFOX'] + os.sep + pdbName
-
-            try:
-                symbolDirs = os.listdir(topLibPath)
-                for symbolDir in symbolDirs:
-                    candidatePath = topLibPath + os.sep + symbolDir
-                    mtime = os.path.getmtime(candidatePath)
-                    if mtime > thresholdTime:
-                        symDirsToInspect[pdbName].append(
-                            (mtime, candidatePath))
-            except Exception as e:
-                LogError("Error while pre-fetching: " + str(e))
-
-            LogMessage("Found " + str(len(symDirsToInspect[pdbName])) +
-                       " new " + pdbName + " recent dirs")
-
-            # Only prefetch the most recent N entries
-            symDirsToInspect[pdbName].sort(reverse=True)
-            symDirsToInspect[pdbName] = symDirsToInspect[pdbName][
-                :self.sOptions['prefetchMaxSymbolsPerLib']]
-
-        # Don't fetch symbols already in cache.
-        # Ideally, mutex would be held from check to insert in self.sCache,
-        # but we don't want to hold the lock during I/O. This won't cause
-        # inconsistencies.
-        self.sCacheLock.acquire()
-        try:
-            for pdbName in symDirsToInspect:
-                for (mtime, symbolDirPath) in symDirsToInspect[pdbName]:
-                    pdbId = os.path.basename(symbolDirPath)
-                    if pdbName in self.sCache and \
-                            pdbId in self.sCache[pdbName]:
-                        symDirsToInspect[pdbName].remove(
-                            (mtime, symbolDirPath))
-        finally:
-            self.sCacheLock.release()
-
-        # Read all new symbol files in at once
-        fetchedSymbols = {}
-        fetchedCount = 0
-        for pdbName in symDirsToInspect:
-            # The corresponding symbol file name ends with .sym
-            symFileName = re.sub(r"\.[^\.]+$", ".sym", pdbName)
-
-            for (mtime, symbolDirPath) in symDirsToInspect[pdbName]:
-                pdbId = os.path.basename(symbolDirPath)
-                symbolFilePath = symbolDirPath + os.sep + symFileName
-                symbolInfo = self.FetchSymbolsFromFile(symbolFilePath)
-                if symbolInfo:
-                    # Stop if the prefetched items are bigger than the cache
-                    if fetchedCount + symbolInfo.GetEntryCount() > \
-                            self.sOptions["maxCacheEntries"]:
-                        break
-                    fetchedSymbols[(pdbName, pdbId)] = symbolInfo
-                    fetchedCount += symbolInfo.GetEntryCount()
-                else:
-                    LogError("Couldn't fetch .sym file symbols for " +
-                             symbolFilePath)
-                    continue
-
-        # Insert new symbols into global symbol cache
-        self.sCacheLock.acquire()
-        try:
-            # Make room for the new symbols
-            self.MaybeEvict(fetchedCount)
-
-            for (pdbName, pdbId) in fetchedSymbols:
-                if pdbName not in self.sCache:
-                    self.sCache[pdbName] = {}
-
-                if pdbId in self.sCache[pdbName]:
-                    continue
-
-                newSymbolFile = fetchedSymbols[(pdbName, pdbId)]
-                self.sCache[pdbName][pdbId] = newSymbolFile
-                self.sCacheCount += newSymbolFile.GetEntryCount()
-
-                # Move new symbols to front of MRU list to give them a chance
-                self.UpdateMruList(pdbName, pdbId)
-
-        finally:
-            self.sCacheLock.release()
-
-        LogMessage("Finished prefetching recent symbol files")
-
-    def UpdateMruList(self, pdbName, pdbId):
-        libId = (pdbName, pdbId)
-        if libId in self.sMruSymbols:
-            self.sMruSymbols.remove(libId)
-        self.sMruSymbols.insert(0, libId)
-
-    def MaybeEvict(self, freeEntriesNeeded):
-        maxCacheSize = self.sOptions["maxCacheEntries"]
-        LogTrace("Cache occupancy before MaybeEvict: " +
-                 str(self.sCacheCount) + "/" + str(maxCacheSize))
-
-        if self.sCacheCount == 0 or \
-                self.sCacheCount + freeEntriesNeeded <= maxCacheSize:
-            # No need to lock mutex here, this doesn't need to be 100%
-            return
-
-        # If adding the new entries would exceed the max cache size,
-        # evict so that cache is at 70% capacity after new entries added
-        numOldEntriesAfterEvict = max(
-            0, (0.70 * maxCacheSize) - freeEntriesNeeded)
-        numToEvict = self.sCacheCount - numOldEntriesAfterEvict
-
-        # Evict symbols until evict quota is met, starting with least recently
-        # used
-        for (pdbName, pdbId) in reversed(self.sMruSymbols):
-            if numToEvict <= 0:
-                break
-
-            evicteeCount = self.sCache[pdbName][pdbId].GetEntryCount()
-
-            del self.sCache[pdbName][pdbId]
-            self.sCacheCount -= evicteeCount
-            self.sMruSymbols.pop()
-
-            numToEvict -= evicteeCount
-
-        LogTrace("Cache occupancy after MaybeEvict: " +
-                 str(self.sCacheCount) + "/" + str(maxCacheSize))
deleted file mode 100755
--- a/testing/raptor/raptor/profiler/symbolication.py
+++ /dev/null
@@ -1,331 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-from __future__ import absolute_import
-
-import hashlib
-import os
-import platform
-import subprocess
-import zipfile
-
-from distutils import spawn
-from six.moves import cStringIO
-from six.moves.urllib.request import urlopen
-
-from .symFileManager import SymFileManager
-from .symLogging import LogMessage
-from .symbolicationRequest import SymbolicationRequest
-
-"""
-Symbolication is broken when using type 'str' in python 2.7, so we use 'basestring'.
-But for python 3.0 compatibility, 'basestring' isn't defined, but the 'str' type works.
-So we force 'basestring' to 'str'.
-"""
-try:
-    basestring
-except NameError:
-    basestring = str
-
-
-class SymbolError(Exception):
-    pass
-
-
-class OSXSymbolDumper:
-
-    def __init__(self):
-        self.dump_syms_bin = os.path.join(
-            os.path.dirname(__file__), 'dump_syms_mac')
-        if not os.path.exists(self.dump_syms_bin):
-            raise SymbolError("No dump_syms_mac binary in this directory")
-
-    def store_symbols(self, lib_path, expected_breakpad_id,
-                      output_filename_without_extension):
-        """
-        Returns the filename at which the .sym file was created, or None if no
-        symbols were dumped.
-        """
-        output_filename = output_filename_without_extension + ".sym"
-
-        def get_archs(filename):
-            """
-            Find the list of architectures present in a Mach-O file.
-            """
-            return subprocess.Popen(["lipo", "-info", filename],
-                                    stdout=subprocess.PIPE)\
-                .communicate()[0].split(':')[2].strip().split()
-
-        def process_file(arch):
-            proc = subprocess.Popen([self.dump_syms_bin, "-a", arch, lib_path],
-                                    stdout=subprocess.PIPE,
-                                    stderr=subprocess.PIPE)
-            stdout, stderr = proc.communicate()
-            if proc.returncode != 0:
-                return None
-
-            module = stdout.splitlines()[0]
-            bits = module.split(' ', 4)
-            if len(bits) != 5:
-                return None
-            _, platform, cpu_arch, actual_breakpad_id, debug_file = bits
-
-            if actual_breakpad_id != expected_breakpad_id:
-                return None
-
-            with open(output_filename, "w") as f:
-                f.write(stdout)
-            return output_filename
-
-        for arch in get_archs(lib_path):
-            result = process_file(arch)
-            if result is not None:
-                return result
-        return None
-
-
-class LinuxSymbolDumper:
-
-    def __init__(self):
-        self.nm = spawn.find_executable("nm")
-        if not self.nm:
-            raise SymbolError(
-                "Could not find nm, necessary for symbol dumping")
-
-    def store_symbols(self, lib_path, breakpad_id,
-                      output_filename_without_extension):
-        """
-        Returns the filename at which the .sym file was created, or None if no
-        symbols were dumped.
-        """
-        output_filename = output_filename_without_extension + ".nmsym"
-
-        proc = subprocess.Popen([self.nm, "--demangle", lib_path],
-                                stdout=subprocess.PIPE,
-                                stderr=subprocess.PIPE)
-        stdout, stderr = proc.communicate()
-
-        if proc.returncode != 0:
-            return
-
-        with open(output_filename, "w") as f:
-            f.write(stdout)
-
-            # Append nm -D output to the file. On Linux, most system libraries
-            # have no "normal" symbols, but they have "dynamic" symbols, which
-            # nm -D shows.
-            proc = subprocess.Popen([self.nm, "--demangle", "-D", lib_path],
-                                    stdout=subprocess.PIPE,
-                                    stderr=subprocess.PIPE)
-            stdout, stderr = proc.communicate()
-            if proc.returncode == 0:
-                f.write(stdout)
-        return output_filename
-
-
-class ProfileSymbolicator:
-
-    def __init__(self, options):
-        self.options = options
-        self.sym_file_manager = SymFileManager(self.options)
-        self.symbol_dumper = self.get_symbol_dumper()
-
-    def get_symbol_dumper(self):
-        try:
-            if platform.system() == "Darwin":
-                return OSXSymbolDumper()
-            elif platform.system() == "Linux":
-                return LinuxSymbolDumper()
-        except SymbolError:
-            return None
-
-    def integrate_symbol_zip_from_url(self, symbol_zip_url):
-        if self.have_integrated(symbol_zip_url):
-            return
-        LogMessage("Retrieving symbol zip from {symbol_zip_url}...".format(
-            symbol_zip_url=symbol_zip_url))
-        try:
-            io = urlopen(symbol_zip_url, None, 30)
-            with zipfile.ZipFile(cStringIO(io.read())) as zf:
-                self.integrate_symbol_zip(zf)
-            self._create_file_if_not_exists(self._marker_file(symbol_zip_url))
-        except IOError:
-            LogMessage("Symbol zip request failed.")
-
-    def integrate_symbol_zip_from_file(self, filename):
-        if self.have_integrated(filename):
-            return
-        with open(filename, 'rb') as f:
-            with zipfile.ZipFile(f) as zf:
-                self.integrate_symbol_zip(zf)
-        self._create_file_if_not_exists(self._marker_file(filename))
-
-    def _create_file_if_not_exists(self, filename):
-        try:
-            os.makedirs(os.path.dirname(filename))
-        except OSError:
-            pass
-        try:
-            open(filename, 'a').close()
-        except IOError:
-            pass
-
-    def integrate_symbol_zip(self, symbol_zip_file):
-        symbol_zip_file.extractall(self.options["symbolPaths"]["FIREFOX"])
-
-    def _marker_file(self, symbol_zip_url):
-        marker_dir = os.path.join(
-            self.options["symbolPaths"]["FIREFOX"], ".markers")
-        return os.path.join(marker_dir,
-                            hashlib.sha1(symbol_zip_url).hexdigest())
-
-    def have_integrated(self, symbol_zip_url):
-        return os.path.isfile(self._marker_file(symbol_zip_url))
-
-    def get_unknown_modules_in_profile(self, profile_json):
-        if "libs" not in profile_json:
-            return []
-        shared_libraries = profile_json["libs"]
-        memoryMap = []
-        for lib in shared_libraries:
-            memoryMap.append([lib["debugName"], lib["breakpadId"]])
-
-        rawRequest = {"stacks": [[]], "memoryMap": memoryMap,
-                      "version": 4, "symbolSources": ["FIREFOX", "WINDOWS"]}
-        request = SymbolicationRequest(self.sym_file_manager, rawRequest)
-        if not request.isValidRequest:
-            return []
-        request.Symbolicate(0)  # This sets request.knownModules
-
-        unknown_modules = []
-        for i, lib in enumerate(shared_libraries):
-            if not request.knownModules[i]:
-                unknown_modules.append(lib)
-        return unknown_modules
-
-    def dump_and_integrate_missing_symbols(self, profile_json,
-                                           symbol_zip_path):
-        if not self.symbol_dumper:
-            return
-
-        unknown_modules = self.get_unknown_modules_in_profile(profile_json)
-        if not unknown_modules:
-            return
-
-        # We integrate the dumped symbols by dumping them directly into our
-        # symbol directory.
-        output_dir = self.options["symbolPaths"]["FIREFOX"]
-
-        # Additionally, we add all dumped symbol files to the missingsymbols
-        # zip file.
-        with zipfile.ZipFile(symbol_zip_path, 'a', zipfile.ZIP_DEFLATED) as zf:
-            for lib in unknown_modules:
-                self.dump_and_integrate_symbols_for_lib(lib, output_dir, zf)
-
-    def dump_and_integrate_symbols_for_lib(self, lib, output_dir, zip):
-        name = lib["debugName"]
-        expected_name_without_extension = os.path.join(name, lib["breakpadId"], name)
-        for extension in [".sym", ".nmsym"]:
-            expected_name = expected_name_without_extension + extension
-            if expected_name in zip.namelist():
-                # No need to dump the symbols again if we already have it in
-                # the missingsymbols zip file from a previous run.
-                zip.extract(expected_name, output_dir)
-                return
-
-        lib_path = lib["path"]
-        if not os.path.exists(lib_path):
-            return
-
-        output_filename_without_extension = os.path.join(
-            output_dir, expected_name_without_extension)
-        store_path = os.path.dirname(output_filename_without_extension)
-        if not os.path.exists(store_path):
-            os.makedirs(store_path)
-
-        # Dump the symbols.
-        sym_file = self.symbol_dumper.store_symbols(
-            lib_path, lib["breakpadId"], output_filename_without_extension)
-        if sym_file:
-            rootlen = len(os.path.join(output_dir, '_')) - 1
-            output_filename = sym_file[rootlen:]
-            if output_filename not in zip.namelist():
-                zip.write(sym_file, output_filename)
-
-    def symbolicate_profile(self, profile_json):
-        if "libs" not in profile_json:
-            return
-
-        shared_libraries = profile_json["libs"]
-        addresses = self._find_addresses(profile_json)
-        symbols_to_resolve = self._assign_symbols_to_libraries(
-            addresses, shared_libraries)
-        symbolication_table = self._resolve_symbols(symbols_to_resolve)
-        self._substitute_symbols(profile_json, symbolication_table)
-
-        for process in profile_json["processes"]:
-            self.symbolicate_profile(process)
-
-    def _find_addresses(self, profile_json):
-        addresses = set()
-        for thread in profile_json["threads"]:
-            if isinstance(thread, basestring):
-                continue
-            for s in thread["stringTable"]:
-                if s[0:2] == "0x":
-                    addresses.add(s)
-        return addresses
-
-    def _substitute_symbols(self, profile_json, symbolication_table):
-        for thread in profile_json["threads"]:
-            if isinstance(thread, basestring):
-                continue
-            for i, s in enumerate(thread["stringTable"]):
-                thread["stringTable"][i] = symbolication_table.get(s, s)
-
-    def _get_containing_library(self, address, libs):
-        left = 0
-        right = len(libs) - 1
-        while left <= right:
-            mid = (left + right) / 2
-            if address >= libs[mid]["end"]:
-                left = mid + 1
-            elif address < libs[mid]["start"]:
-                right = mid - 1
-            else:
-                return libs[mid]
-        return None
-
-    def _assign_symbols_to_libraries(self, addresses, shared_libraries):
-        libs_with_symbols = {}
-        for address in addresses:
-            lib = self._get_containing_library(
-                int(address, 0), shared_libraries)
-            if not lib:
-                continue
-            if lib["start"] not in libs_with_symbols:
-                libs_with_symbols[lib["start"]] = {
-                    "library": lib, "symbols": set()}
-            libs_with_symbols[lib["start"]]["symbols"].add(address)
-        return libs_with_symbols.values()
-
-    def _resolve_symbols(self, symbols_to_resolve):
-        memoryMap = []
-        processedStack = []
-        all_symbols = []
-        for moduleIndex, library_with_symbols in enumerate(symbols_to_resolve):
-            lib = library_with_symbols["library"]
-            symbols = library_with_symbols["symbols"]
-            memoryMap.append([lib["debugName"], lib["breakpadId"]])
-            all_symbols += symbols
-            for symbol in symbols:
-                processedStack.append(
-                    [moduleIndex, int(symbol, 0) - lib["start"]])
-
-        rawRequest = {"stacks": [processedStack], "memoryMap": memoryMap,
-                      "version": 4, "symbolSources": ["FIREFOX", "WINDOWS"]}
-        request = SymbolicationRequest(self.sym_file_manager, rawRequest)
-        if not request.isValidRequest:
-            return {}
-        symbolicated_stack = request.Symbolicate(0)
-        return dict(zip(all_symbols, symbolicated_stack))
deleted file mode 100755
--- a/testing/raptor/raptor/profiler/symbolicationRequest.py
+++ /dev/null
@@ -1,317 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-from __future__ import absolute_import
-
-import json
-import re
-
-from six.moves.urllib.request import Request, urlopen
-
-from .symLogging import LogTrace, LogError
-
-# Precompiled regex for validating lib names
-# Empty lib name means client couldn't associate frame with any lib
-gLibNameRE = re.compile("[0-9a-zA-Z_+\-\.]*$")
-
-# Maximum number of times a request can be forwarded to a different server
-# for symbolication. Also prevents loops.
-MAX_FORWARDED_REQUESTS = 3
-
-"""
-Symbolication is broken when using type 'str' in python 2.7, so we use 'basestring'.
-But for python 3.0 compatibility, 'basestring' isn't defined, but the 'str' type works.
-So we force 'basestring' to 'str'.
-"""
-try:
-    basestring
-except NameError:
-    basestring = str
-
-
-class ModuleV3:
-
-    def __init__(self, libName, breakpadId):
-        self.libName = libName
-        self.breakpadId = breakpadId
-
-
-def getModuleV3(libName, breakpadId):
-    if not isinstance(libName, basestring) or not gLibNameRE.match(libName):
-        LogTrace("Bad library name: " + str(libName))
-        return None
-
-    if not isinstance(breakpadId, basestring):
-        LogTrace("Bad breakpad id: " + str(breakpadId))
-        return None
-
-    return ModuleV3(libName, breakpadId)
-
-
-class SymbolicationRequest:
-
-    def __init__(self, symFileManager, rawRequests):
-        self.Reset()
-        self.symFileManager = symFileManager
-        self.stacks = []
-        self.combinedMemoryMap = []
-        self.knownModules = []
-        self.symbolSources = []
-        self.ParseRequests(rawRequests)
-
-    def Reset(self):
-        self.symFileManager = None
-        self.isValidRequest = False
-        self.combinedMemoryMap = []
-        self.knownModules = []
-        self.stacks = []
-        self.forwardCount = 0
-
-    def ParseRequests(self, rawRequests):
-        self.isValidRequest = False
-
-        try:
-            if not isinstance(rawRequests, dict):
-                LogTrace("Request is not a dictionary")
-                return
-
-            if "version" not in rawRequests:
-                LogTrace("Request is missing 'version' field")
-                return
-            version = rawRequests["version"]
-            if version != 4:
-                LogTrace("Invalid version: %s" % version)
-                return
-
-            if "forwarded" in rawRequests:
-                if not isinstance(rawRequests["forwarded"], (int, int)):
-                    LogTrace("Invalid 'forwards' field: %s"
-                             % rawRequests["forwarded"])
-                    return
-                self.forwardCount = rawRequests["forwarded"]
-
-            # Client specifies which sets of symbols should be used
-            if "symbolSources" in rawRequests:
-                try:
-                    sourceList = [x.upper()
-                                  for x in rawRequests["symbolSources"]]
-                    for source in sourceList:
-                        if source in self.symFileManager\
-                                .sOptions["symbolPaths"]:
-                            self.symbolSources.append(source)
-                        else:
-                            LogTrace("Unrecognized symbol source: " + source)
-                            continue
-                except Exception:
-                    self.symbolSources = []
-                    pass
-
-            if not self.symbolSources:
-                self.symbolSources.append(
-                    self.symFileManager.sOptions["defaultApp"])
-                self.symbolSources.append(
-                    self.symFileManager.sOptions["defaultOs"])
-
-            if "memoryMap" not in rawRequests:
-                LogTrace("Request is missing 'memoryMap' field")
-                return
-            memoryMap = rawRequests["memoryMap"]
-            if not isinstance(memoryMap, list):
-                LogTrace("'memoryMap' field in request is not a list")
-
-            if "stacks" not in rawRequests:
-                LogTrace("Request is missing 'stacks' field")
-                return
-            stacks = rawRequests["stacks"]
-            if not isinstance(stacks, list):
-                LogTrace("'stacks' field in request is not a list")
-                return
-
-            # Check memory map is well-formatted
-            cleanMemoryMap = []
-            for module in memoryMap:
-                if not isinstance(module, list):
-                    LogTrace(
-                        "Entry in memory map is not a list: " + str(module))
-                    return
-
-                if len(module) != 2:
-                    LogTrace("Entry in memory map is not a 2 item list: " +
-                             str(module))
-                    return
-                module = getModuleV3(*module)
-
-                if module is None:
-                    return
-
-                cleanMemoryMap.append(module)
-
-            self.combinedMemoryMap = cleanMemoryMap
-            self.knownModules = [False] * len(self.combinedMemoryMap)
-
-            # Check stack is well-formatted
-            for stack in stacks:
-                if not isinstance(stack, list):
-                    LogTrace("stack is not a list")
-                    return
-                for entry in stack:
-                    if not isinstance(entry, list):
-                        LogTrace("stack entry is not a list")
-                        return
-                    if len(entry) != 2:
-                        LogTrace("stack entry doesn't have exactly 2 elements")
-                        return
-
-                self.stacks.append(stack)
-
-        except Exception as e:
-            LogTrace("Exception while parsing request: " + str(e))
-            return
-
-        self.isValidRequest = True
-
-    def ForwardRequest(self, indexes, stack, modules, symbolicatedStack):
-        LogTrace("Forwarding " + str(len(stack)) + " PCs for symbolication")
-
-        try:
-            url = self.symFileManager.sOptions["remoteSymbolServer"]
-            rawModules = []
-            moduleToIndex = {}
-            newIndexToOldIndex = {}
-            for moduleIndex, m in modules:
-                l = [m.libName, m.breakpadId]
-                newModuleIndex = len(rawModules)
-                rawModules.append(l)
-                moduleToIndex[m] = newModuleIndex
-                newIndexToOldIndex[newModuleIndex] = moduleIndex
-
-            rawStack = []
-            for entry in stack:
-                moduleIndex = entry[0]
-                offset = entry[1]
-                module = self.combinedMemoryMap[moduleIndex]
-                newIndex = moduleToIndex[module]
-                rawStack.append([newIndex, offset])
-
-            requestVersion = 4
-            while True:
-                requestObj = {
-                    "symbolSources": self.symbolSources,
-                    "stacks": [rawStack],
-                    "memoryMap": rawModules,
-                    "forwarded": self.forwardCount + 1,
-                    "version": requestVersion
-                }
-                requestJson = json.dumps(requestObj)
-                headers = {"Content-Type": "application/json"}
-                requestHandle = Request(url, requestJson, headers)
-                try:
-                    response = urlopen(requestHandle)
-
-                except Exception as e:
-                    if requestVersion == 4:
-                        # Try again with version 3
-                        requestVersion = 3
-                        continue
-                    raise e
-                succeededVersion = requestVersion
-                break
-
-        except Exception as e:
-            LogError("Exception while forwarding request: " + str(e))
-            return
-
-        try:
-            responseJson = json.loads(response.read())
-        except Exception as e:
-            LogError("Exception while reading server response to forwarded"
-                     " request: " + str(e))
-            return
-
-        try:
-            if succeededVersion == 4:
-                responseKnownModules = responseJson['knownModules']
-                for newIndex, known in enumerate(responseKnownModules):
-                    if known and newIndex in newIndexToOldIndex:
-                        self.knownModules[newIndexToOldIndex[newIndex]] = True
-
-                responseSymbols = responseJson['symbolicatedStacks'][0]
-            else:
-                responseSymbols = responseJson[0]
-            if len(responseSymbols) != len(stack):
-                LogError(str(len(responseSymbols)) + " symbols in response, " +
-                         str(len(stack)) + " PCs in request!")
-                return
-
-            for index in range(0, len(stack)):
-                symbol = responseSymbols[index]
-                originalIndex = indexes[index]
-                symbolicatedStack[originalIndex] = symbol
-        except Exception as e:
-            LogError("Exception while parsing server response to forwarded"
-                     " request: " + str(e))
-            return
-
-    def Symbolicate(self, stackNum):
-        # Check if we should forward requests when required sym files don't
-        # exist
-        shouldForwardRequests = False
-        if self.symFileManager.sOptions["remoteSymbolServer"] and \
-                self.forwardCount < MAX_FORWARDED_REQUESTS:
-            shouldForwardRequests = True
-
-        # Symbolicate each PC
-        pcIndex = -1
-        symbolicatedStack = []
-        missingSymFiles = []
-        unresolvedIndexes = []
-        unresolvedStack = []
-        unresolvedModules = []
-        stack = self.stacks[stackNum]
-
-        for moduleIndex, module in enumerate(self.combinedMemoryMap):
-            if not self.symFileManager.GetLibSymbolMap(module.libName,
-                                                       module.breakpadId,
-                                                       self.symbolSources):
-                missingSymFiles.append((module.libName, module.breakpadId))
-                if shouldForwardRequests:
-                    unresolvedModules.append((moduleIndex, module))
-            else:
-                self.knownModules[moduleIndex] = True
-
-        for entry in stack:
-            pcIndex += 1
-            moduleIndex = entry[0]
-            offset = entry[1]
-            if moduleIndex == -1:
-                symbolicatedStack.append(hex(offset))
-                continue
-            module = self.combinedMemoryMap[moduleIndex]
-
-            if (module.libName, module.breakpadId) in missingSymFiles:
-                if shouldForwardRequests:
-                    unresolvedIndexes.append(pcIndex)
-                    unresolvedStack.append(entry)
-                symbolicatedStack.append(
-                    hex(offset) + " (in " + module.libName + ")")
-                continue
-
-            functionName = None
-            libSymbolMap = self.symFileManager.GetLibSymbolMap(
-                module.libName,
-                module.breakpadId,
-                self.symbolSources
-            )
-            functionName = libSymbolMap.Lookup(offset)
-
-            if functionName is None:
-                functionName = hex(offset)
-            symbolicatedStack.append(
-                functionName + " (in " + module.libName + ")")
-
-        # Ask another server for help symbolicating unresolved addresses
-        if len(unresolvedStack) > 0 or len(unresolvedModules) > 0:
-            self.ForwardRequest(unresolvedIndexes, unresolvedStack,
-                                unresolvedModules, symbolicatedStack)
-
-        return symbolicatedStack
--- a/testing/talos/talos/gecko_profile.py
+++ b/testing/talos/talos/gecko_profile.py
@@ -9,17 +9,17 @@ from __future__ import absolute_import
 
 import json
 import os
 import tempfile
 import zipfile
 
 import mozfile
 from mozlog import get_proxy_logger
-from talos.profiler import symbolication, profiling
+from mozgeckoprofiler import ProfileSymbolicator, save_gecko_profile
 
 LOG = get_proxy_logger()
 
 
 class GeckoProfile(object):
     """
     Handle Gecko profiling.
 
@@ -92,17 +92,17 @@ class GeckoProfile(object):
                             profile_path):
         try:
             with open(profile_path, 'r') as profile_file:
                 profile = json.load(profile_file)
             symbolicator.dump_and_integrate_missing_symbols(
                 profile,
                 missing_symbols_zip)
             symbolicator.symbolicate_profile(profile)
-            profiling.save_profile(profile, profile_path)
+            save_gecko_profile(profile, profile_path)
         except MemoryError:
             LOG.critical(
                 "Ran out of memory while trying"
                 " to symbolicate profile {0} (cycle {1})"
                 .format(profile_path, cycle),
                 exc_info=True
             )
         except Exception:
@@ -112,17 +112,17 @@ class GeckoProfile(object):
                          exc_info=True)
 
     def symbolicate(self, cycle):
         """
         Symbolicate Gecko profiling data for one cycle.
 
         :param cycle: the number of the cycle of the test currently run.
         """
-        symbolicator = symbolication.ProfileSymbolicator({
+        symbolicator = ProfileSymbolicator({
             # Trace-level logging (verbose)
             "enableTracing": 0,
             # Fallback server if symbol is not found locally
             "remoteSymbolServer":
                 "https://symbols.mozilla.org/symbolicate/v4",
             # Maximum number of symbol files to keep in memory
             "maxCacheEntries": 2000000,
             # Frequency of checking for recent symbols to
deleted file mode 100644
--- a/testing/talos/talos/profiler/README.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-The files in this directory were imported from https://github.com/vdjeric/Snappy-Symbolication-Server/ and https://github.com/mstange/analyze-tryserver-profiles/ with the permission of their respective authors. Some of the files were then cleaned up to remove code that we don't use.
-
-The dump_syms_mac binary was copied from the objdir of a Firefox build on Mac. It's a byproduct of the regular Firefox build process and gets generated in objdir/dist/host/bin/.
deleted file mode 100755
--- a/testing/talos/talos/profiler/symLogging.py
+++ /dev/null
@@ -1,27 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-from __future__ import absolute_import, print_function
-
-import sys
-import threading
-import time
-
-gEnableTracing = False
-
-
-def LogTrace(string):
-    global gEnableTracing
-    if gEnableTracing:
-        threadName = threading.currentThread().getName().ljust(12)
-        print(time.asctime() + " " + threadName + " TRACE " + string, file=sys.stdout)
-
-
-def LogError(string):
-    threadName = threading.currentThread().getName().ljust(12)
-    print(time.asctime() + " " + threadName + " ERROR " + string, file=sys.stderr)
-
-
-def LogMessage(string):
-    threadName = threading.currentThread().getName().ljust(12)
-    print(time.asctime() + " " + threadName + "       " + string, file=sys.stdout)
--- a/testing/tools/mach_test_package_bootstrap.py
+++ b/testing/tools/mach_test_package_bootstrap.py
@@ -16,16 +16,17 @@ SEARCH_PATHS = [
     'marionette/client',
     'marionette/harness',
     'mochitest',
     'mozbase/manifestparser',
     'mozbase/mozcrash',
     'mozbase/mozdebug',
     'mozbase/mozdevice',
     'mozbase/mozfile',
+    'mozbase/mozgeckoprofile',
     'mozbase/mozhttpd',
     'mozbase/mozinfo',
     'mozbase/mozinstall',
     'mozbase/mozleak',
     'mozbase/mozlog',
     'mozbase/moznetwork',
     'mozbase/mozpower',
     'mozbase/mozprocess',
--- a/tools/lint/file-whitespace.yml
+++ b/tools/lint/file-whitespace.yml
@@ -46,17 +46,16 @@ file-whitespace:
         - python/l10n/convert_xul_to_fluent/lib/utils.py
         - python/l10n/convert_xul_to_fluent/lib/xul.py
         - testing/mochitest/bisection.py
         - testing/mozharness/configs/raptor/linux64_config_taskcluster.py
         - testing/mozharness/configs/talos/linux64_config_taskcluster.py
         - testing/mozharness/configs/web_platform_tests/test_config_windows.py
         - testing/mozharness/external_tools/virtualenv/virtualenv_embedded/distutils-init.py
         - testing/talos/talos/cmanager_base.py
-        - testing/talos/talos/profiler/profiling.py
         - testing/talos/talos/unittests/conftest.py
         - testing/talos/talos/unittests/test_test.py
         - testing/talos/talos/unittests/test_xtalos.py
         - testing/web-platform/tests/content-security-policy/embedded-enforcement/support/echo-allow-csp-from.py
         - testing/web-platform/tests/content-security-policy/embedded-enforcement/support/echo-policy-multiple.py
         - testing/web-platform/tests/css/tools/apiclient/apiclient/__init__.py
         - testing/web-platform/tests/css/tools/apiclient/apiclient/apiclient.py
         - testing/web-platform/tests/css/tools/apiclient/apiclient/uritemplate.py