test_resource_monitor.py (5348B)
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 5 import multiprocessing 6 import time 7 import unittest 8 9 import mozunit 10 11 try: 12 import psutil 13 except ImportError: 14 psutil = None 15 16 from mozsystemmonitor.resourcemonitor import SystemResourceMonitor, SystemResourceUsage 17 18 19 @unittest.skipIf(psutil is None, "Resource monitor requires psutil.") 20 class TestResourceMonitor(unittest.TestCase): 21 def test_basic(self): 22 monitor = SystemResourceMonitor(poll_interval=0.5) 23 24 monitor.start() 25 time.sleep(3) 26 27 monitor.stop() 28 29 data = list(monitor.range_usage()) 30 self.assertGreater(len(data), 3) 31 32 self.assertIsInstance(data[0], SystemResourceUsage) 33 34 def test_empty(self): 35 monitor = SystemResourceMonitor(poll_interval=2.0) 36 monitor.start() 37 monitor.stop() 38 39 data = list(monitor.range_usage()) 40 self.assertEqual(len(data), 0) 41 42 def test_phases(self): 43 monitor = SystemResourceMonitor(poll_interval=0.25) 44 45 monitor.start() 46 time.sleep(1) 47 48 with monitor.phase("phase1"): 49 time.sleep(1) 50 51 with monitor.phase("phase2"): 52 time.sleep(1) 53 54 monitor.stop() 55 56 self.assertEqual(len(monitor.phases), 2) 57 self.assertEqual(["phase2", "phase1"], list(monitor.phases.keys())) 58 59 all = list(monitor.range_usage()) 60 data1 = list(monitor.phase_usage("phase1")) 61 data2 = list(monitor.phase_usage("phase2")) 62 63 self.assertGreater(len(all), len(data1)) 64 self.assertGreater(len(data1), len(data2)) 65 66 # This could fail if time.monotonic() takes more than 0.1s. It really 67 # shouldn't. 68 self.assertAlmostEqual(data1[-1].end, data2[-1].end, delta=0.25) 69 70 def test_no_data(self): 71 monitor = SystemResourceMonitor() 72 73 data = list(monitor.range_usage()) 74 self.assertEqual(len(data), 0) 75 76 def test_events(self): 77 monitor = SystemResourceMonitor(poll_interval=0.25) 78 79 monitor.start() 80 time.sleep(0.5) 81 82 t0 = time.monotonic() 83 monitor.record_event("t0") 84 time.sleep(2) 85 86 monitor.record_event("t1") 87 time.sleep(0.5) 88 monitor.stop() 89 90 events = monitor.events 91 self.assertEqual(len(events), 2) 92 93 event = events[0] 94 95 self.assertEqual(event[1], "t0") 96 self.assertAlmostEqual(event[0], t0, delta=0.25) 97 98 data = list(monitor.between_events_usage("t0", "t1")) 99 self.assertGreater(len(data), 0) 100 101 def test_aggregate_cpu(self): 102 monitor = SystemResourceMonitor(poll_interval=0.25) 103 104 monitor.start() 105 time.sleep(1) 106 monitor.stop() 107 108 values = monitor.aggregate_cpu_percent() 109 self.assertIsInstance(values, list) 110 self.assertEqual(len(values), multiprocessing.cpu_count()) 111 for v in values: 112 self.assertIsInstance(v, float) 113 114 value = monitor.aggregate_cpu_percent(per_cpu=False) 115 self.assertIsInstance(value, float) 116 117 values = monitor.aggregate_cpu_times() 118 self.assertIsInstance(values, list) 119 self.assertGreater(len(values), 0) 120 self.assertTrue(hasattr(values[0], "user")) 121 122 t = type(values[0]) 123 124 value = monitor.aggregate_cpu_times(per_cpu=False) 125 self.assertIsInstance(value, t) 126 127 def test_aggregate_io(self): 128 monitor = SystemResourceMonitor(poll_interval=0.25) 129 130 # There's really no easy way to ensure I/O occurs. For all we know 131 # reads and writes will all be serviced by the page cache. 132 monitor.start() 133 time.sleep(1.0) 134 monitor.stop() 135 136 values = monitor.aggregate_io() 137 self.assertTrue(hasattr(values, "read_count")) 138 139 def test_memory(self): 140 monitor = SystemResourceMonitor(poll_interval=0.25) 141 142 monitor.start() 143 time.sleep(1.0) 144 monitor.stop() 145 146 v = monitor.min_memory_available() 147 self.assertIsInstance(v, int) 148 149 v = monitor.max_memory_percent() 150 self.assertIsInstance(v, float) 151 152 def test_as_profile(self): 153 monitor = SystemResourceMonitor(poll_interval=0.25) 154 155 monitor.start() 156 time.sleep(0.1) 157 monitor.begin_phase("phase1") 158 monitor.record_event("foo") 159 time.sleep(0.1) 160 monitor.begin_phase("phase2") 161 monitor.record_event("bar") 162 time.sleep(0.2) 163 monitor.finish_phase("phase1") 164 time.sleep(0.2) 165 monitor.finish_phase("phase2") 166 time.sleep(0.4) 167 monitor.stop() 168 169 d = monitor.as_profile() 170 171 self.assertEqual(len(d["threads"]), 1) 172 self.assertIn("markers", d["threads"][0]) 173 self.assertIn("data", d["threads"][0]["markers"]) 174 markers = d["threads"][0]["markers"]["data"] 175 self.assertTrue( 176 any(m["type"] == "Phase" and m["phase"] == "phase1" for m in markers) 177 ) 178 self.assertTrue( 179 any(m["type"] == "Phase" and m["phase"] == "phase2" for m in markers) 180 ) 181 self.assertIn({"type": "Text", "text": "foo"}, markers) 182 self.assertIn({"type": "Text", "text": "bar"}, markers) 183 184 185 if __name__ == "__main__": 186 mozunit.main()