1# This Source Code Form is subject to the terms of the Mozilla Public
2# License, v. 2.0. If a copy of the MPL was not distributed with this
3# file, You can obtain one at http://mozilla.org/MPL/2.0/.
4
5from __future__ import absolute_import
6
7import os
8import sys
9
10AWSY_PATH = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
11if AWSY_PATH not in sys.path:
12    sys.path.append(AWSY_PATH)
13
14from awsy.awsy_test_case import AwsyTestCase
15
16# A description of each checkpoint and the root path to it.
17CHECKPOINTS = [
18    {
19        'name': "After tabs open [+30s, forced GC]",
20        'path': "memory-report-TabsOpenForceGC-4.json.gz",
21        'name_filter': 'Web Content',  # We only want the content process
22        'median': True,  # We want the median from all content processes
23    },
24]
25
26# A description of each perfherder suite and the path to its values.
27PERF_SUITES = [
28    {'name': "Base Content Resident Unique Memory", 'node': "resident-unique"},
29    {'name': "Base Content Heap Unclassified", 'node': "explicit/heap-unclassified"},
30    {'name': "Base Content JS", 'node': "js-main-runtime/", 'alertThreshold': 0.25},
31    {'name': "Base Content Explicit", 'node': "explicit/"},
32]
33
34
35class TestMemoryUsage(AwsyTestCase):
36    """
37    Provides a base case test that just loads about:memory and reports the
38    memory usage of a single content process.
39    """
40
41    def urls(self):
42        return self._urls
43
44    def perf_suites(self):
45        return PERF_SUITES
46
47    def perf_checkpoints(self):
48        return CHECKPOINTS
49
50    def setUp(self):
51        AwsyTestCase.setUp(self)
52        self.logger.info("setting up!")
53
54        # Override AwsyTestCase value, this is always going to be 1 iteration.
55        self._iterations = 1
56
57        # Override "entities" from our configuration.
58        #
59        # We aim to load a number of about:blank pages exactly matching the
60        # number of content processes we can have. After this we should no
61        # longer have a preallocated content process (although to be sure we
62        # explicitly drop it at the end of the test).
63        process_count = self.marionette.get_pref('dom.ipc.processCount')
64        self._pages_to_load = process_count
65        self._urls = ['about:blank'] * process_count
66
67        self.logger.info("areweslimyet run by %d pages, "
68                         "%d iterations, %d perTabPause, %d settleWaitTime, "
69                         "%d content processes"
70                         % (self._pages_to_load, self._iterations,
71                            self._perTabPause, self._settleWaitTime,
72                            process_count))
73        self.logger.info("done setting up!")
74
75    def tearDown(self):
76        self.logger.info("tearing down!")
77        AwsyTestCase.tearDown(self)
78        self.logger.info("done tearing down!")
79
80    def set_preallocated_process_enabled_state(self, enabled):
81        """Sets the pref that controls whether we have a preallocated content
82        process to the given value.
83
84        This will cause the preallocated process to be destroyed or created
85        as appropriate.
86        """
87        if enabled:
88            self.logger.info('re-enabling preallocated process')
89        else:
90            self.logger.info('disabling preallocated process')
91        self.marionette.set_pref('dom.ipc.processPrelaunch.enabled', enabled)
92
93    def test_open_tabs(self):
94        """Marionette test entry that returns an array of checkoint arrays.
95
96        This will generate a set of checkpoints for each iteration requested.
97        Upon succesful completion the results will be stored in
98        |self.testvars["results"]| and accessible to the test runner via the
99        |testvars| object it passed in.
100        """
101        # setup the results array
102        results = [[] for _ in range(self.iterations())]
103
104        def create_checkpoint(name, iteration):
105            checkpoint = self.do_memory_report(name, iteration)
106            self.assertIsNotNone(checkpoint, "Checkpoint was recorded")
107            results[iteration].append(checkpoint)
108
109        # As long as we force the number of iterations to 1 in setUp() above,
110        # we don't need to loop over this work.
111        assert self._iterations == 1
112        self.open_pages()
113        self.set_preallocated_process_enabled_state(False)
114        self.settle()
115        self.settle()
116        self.assertTrue(self.do_full_gc())
117        self.settle()
118        create_checkpoint("TabsOpenForceGC", 0)
119        self.set_preallocated_process_enabled_state(True)
120        # (If we wanted to do something after the preallocated process has been
121        # recreated, we should call self.settle() again to wait for it.)
122
123        # TODO(ER): Temporary hack until bug 1121139 lands
124        self.logger.info("setting results")
125        self.testvars["results"] = results
126