1# Copyright 2015 The Chromium Authors. All rights reserved. 2# Use of this source code is governed by a BSD-style license that can be 3# found in the LICENSE file. 4 5import unittest 6 7from telemetry.testing import test_page_test_results 8from telemetry.timeline import slice as slice_module 9from telemetry.timeline import model as model_module 10from telemetry.web_perf import timeline_interaction_record as tir_module 11 12from telemetry.web_perf.metrics import v8_execution 13 14RENDERER_PROCESS = 'Renderer' 15OTHER_PROCESS = 'Other' 16INTERACTION_RECORDS = [tir_module.TimelineInteractionRecord("test-record", 17 0, 18 float('inf'))] 19 20STATS = ('v8_execution_time_total', 'v8_execution_time_self', 21 'v8_parse_lazy_total', 'v8_compile_fullcode_total', 22 'v8_recompile_total', 'v8_recompile_synchronous_total', 23 'v8_recompile_concurrent_total', 'v8_optimize_code_total', 24 'v8_deoptimize_code_total',) 25 26 27class SliceContext(object): 28 """ 29 Context object for easily adding subslices/subevents. 30 """ 31 def __init__(self, test, record): 32 self.test = test 33 self.record = record 34 35 def __enter__(self): 36 self.test.parent_slice = self.record 37 38 def __exit__(self, exc_type, exc_value, exc_traceback): 39 self.test.parent_slice = self.record.parent_slice 40 41 42class V8ExecutionTests(unittest.TestCase): 43 44 def setUp(self): 45 self.model = model_module.TimelineModel() 46 self.renderer_process = self.model.GetOrCreateProcess(1) 47 self.renderer_process.name = RENDERER_PROCESS 48 self.renderer_thread = self.renderer_process.GetOrCreateThread(tid=11) 49 self.other_process = self.model.GetOrCreateProcess(2) 50 self.other_process.name = OTHER_PROCESS 51 self.other_thread = self.other_process.GetOrCreateThread(tid=12) 52 self.metric = v8_execution.V8ExecutionMetric() 53 self.results = None 54 self.parent_slice = None 55 56 def GetThreadForProcessName(self, process_name): 57 if process_name is RENDERER_PROCESS: 58 return self.renderer_thread 59 elif process_name is OTHER_PROCESS: 60 return self.other_thread 61 else: 62 raise 63 64 def AddResults(self): 65 self.results = test_page_test_results.TestPageTestResults(self) 66 self.metric.AddResults(self.model, self.renderer_thread, 67 INTERACTION_RECORDS, self.results) 68 69 def AddEvent(self, process_name, event_category, event_name, 70 start, duration, thread_start=None, thread_duration=None): 71 thread = self.GetThreadForProcessName(process_name) 72 record = slice_module.Slice(thread, event_category, event_name, 73 start, duration, 74 start if thread_start is None else thread_start, 75 duration if thread_duration is None else thread_duration) 76 thread.PushSlice(record) 77 if self.parent_slice is not None: 78 record.parent_slice = self.parent_slice 79 self.parent_slice.AddSubSlice(record) 80 return SliceContext(self, record) 81 82 def AssertResultValues(self, name, value, count, average): 83 self.results.AssertHasPageSpecificScalarValue('%s' % name, 'ms', value) 84 self.results.AssertHasPageSpecificScalarValue('%s_count' % name, 'count', 85 count) 86 self.results.AssertHasPageSpecificScalarValue('%s_average' % name, 'ms', 87 average) 88 89 def testWithNoTraceEvents(self): 90 self.AddResults() 91 for name in STATS: 92 self.AssertResultValues(name, value=0, count=0, average=0) 93 94 def testExecutionTime(self): 95 self.AddEvent(RENDERER_PROCESS, '', 'V8.Execute', 0, 10) 96 with self.AddEvent(RENDERER_PROCESS, '', 'V8.Execute', 10, 20): 97 self.AddEvent(RENDERER_PROCESS, '', 'other', 10, 12) 98 self.AddResults() 99 self.AssertResultValues('v8_execution_time_total', value=30, count=2, 100 average=15) 101 self.AssertResultValues('v8_execution_time_self', value=18, count=2, 102 average=9) 103 104 def testOptimizeParseLazy(self): 105 self.AddEvent(RENDERER_PROCESS, '', 'V8.ParseLazy', 0, 10) 106 self.AddResults() 107 self.AssertResultValues('v8_parse_lazy_total', value=10, count=1, 108 average=10) 109 self.AssertResultValues('v8_optimize_code_total', value=0, count=0, 110 average=0) 111 self.AssertResultValues('v8_optimize_parse_lazy_total', value=0, count=0, 112 average=0) 113 114 with self.AddEvent(RENDERER_PROCESS, '', 'V8.OptimizeCode', 10, 20): 115 self.AddEvent(RENDERER_PROCESS, '', 'V8.ParseLazy', 20, 8) 116 self.AddResults() 117 self.AssertResultValues('v8_parse_lazy_total', value=18, count=2, average=9) 118 self.AssertResultValues('v8_optimize_code_total', value=20, count=1, 119 average=20) 120 self.AssertResultValues('v8_optimize_parse_lazy_total', value=8, count=1, 121 average=8) 122 123 def testRecompile(self): 124 self.AddEvent(RENDERER_PROCESS, '', 'V8.RecompileSynchronous', 0, 10) 125 self.AddResults() 126 self.AssertResultValues('v8_recompile_synchronous_total', value=10, count=1, 127 average=10) 128 self.AssertResultValues('v8_recompile_concurrent_total', value=0, count=0, 129 average=0) 130 self.AssertResultValues('v8_recompile_total', value=10, count=1, average=10) 131 132 self.AddEvent(RENDERER_PROCESS, '', 'V8.RecompileConcurrent', 10, 8) 133 self.AddResults() 134 self.AssertResultValues('v8_recompile_synchronous_total', value=10, count=1, 135 average=10) 136 self.AssertResultValues('v8_recompile_concurrent_total', value=8, count=1, 137 average=8) 138 self.AssertResultValues('v8_recompile_total', value=18, count=2, average=9) 139