blob: 881f9ba147ce052c4e15bcffd583c47b37299d29 [file] [log] [blame]
Joel Fernandesa19ff252017-05-15 03:02:31 -07001# Copyright 2015-2017 ARM Limited, Google and contributors
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14#
15
16import os
Brendan Jackman878b9ac2017-06-02 14:05:04 +010017import shutil
Joel Fernandesa19ff252017-05-15 03:02:31 -070018import sys
19import unittest
20import utils_tests
21import trappy
22from trappy.ftrace import GenericFTrace
23
24class TestCaching(utils_tests.SetupDirectory):
25 def __init__(self, *args, **kwargs):
26 super(TestCaching, self).__init__(
27 [("trace_sched.txt", "trace.txt"),
28 ("trace_sched.txt", "trace.raw.txt")],
29 *args,
30 **kwargs)
31
32 def test_cache_created(self):
33 """Test cache creation when enabled"""
34 GenericFTrace.disable_cache = False
35 trace = trappy.FTrace()
36
37 trace_path = os.path.abspath(trace.trace_path)
38 trace_dir = os.path.dirname(trace_path)
39 trace_file = os.path.basename(trace_path)
40 cache_dir = '.' + trace_file + '.cache'
41
42 self.assertTrue(cache_dir in os.listdir(trace_dir))
43
44 def test_cache_not_created(self):
45 """Test that cache should not be created when disabled """
46 GenericFTrace.disable_cache = True
47 trace = trappy.FTrace()
48
49 trace_path = os.path.abspath(trace.trace_path)
50 trace_dir = os.path.dirname(trace_path)
51 trace_file = os.path.basename(trace_path)
52 cache_dir = '.' + trace_file + '.cache'
53
54 self.assertFalse(cache_dir in os.listdir(trace_dir))
55
56 def test_compare_cached_vs_uncached(self):
57 """ Test that the cached and uncached traces are same """
58 # Build the cache, but the actual trace will be parsed
59 # fresh since this is a first time parse
60 GenericFTrace.disable_cache = False
61 uncached_trace = trappy.FTrace()
62 uncached_dfr = uncached_trace.sched_wakeup.data_frame
63
64 # Now read from previously parsed cache by reusing the path
65 cached_trace = trappy.FTrace(uncached_trace.trace_path)
66 cached_dfr = cached_trace.sched_wakeup.data_frame
67
68 # Test whether timestamps are the same:
69 # The cached/uncached versions of the timestamps are slightly
70 # different due to floating point precision errors due to converting
71 # back and forth CSV and DataFrame. For all purposes this is not relevant
72 # since such rounding doesn't effect the end result.
73 # Here's an example of the error, the actual normalized time when
74 # calculated by hand is 0.081489, however following is what's stored
75 # in the CSV for sched_wakeup events in this trace.
76 # When converting the index to strings (and also what's in the CSV)
77 # cached: ['0.0814890000001', '1.981491']
78 # uncached: ['0.0814890000001', '1.981491']
79 #
80 # Keeping index as numpy.float64
81 # cached: [0.081489000000100009, 1.9814909999999999]
82 # uncached: [0.081489000000146916, 1.9814909999995507]
83 #
84 # To make it possible to test, lets just convert the timestamps to strings
85 # and compare them below.
86
87 cached_times = [str(r[0]) for r in cached_dfr.iterrows()]
88 uncached_times = [str(r[0]) for r in uncached_dfr.iterrows()]
89
90 self.assertTrue(cached_times == uncached_times)
91
92 # compare other columns as well
93 self.assertTrue([r[1].pid for r in cached_dfr.iterrows()] ==
94 [r[1].pid for r in uncached_dfr.iterrows()])
95
96 self.assertTrue([r[1].comm for r in cached_dfr.iterrows()] ==
97 [r[1].comm for r in uncached_dfr.iterrows()])
98
99 self.assertTrue([r[1].prio for r in cached_dfr.iterrows()] ==
100 [r[1].prio for r in uncached_dfr.iterrows()])
Brendan Jackman878b9ac2017-06-02 14:05:04 +0100101
102 def test_invalid_cache_overwritten(self):
103 """Test a cache with a bad checksum is overwritten"""
104 # This is a directory so we can't use the files_to_copy arg of
105 # SetUpDirectory, just do it ourselves.
106 cache_path = ".trace.txt.cache"
107 src = os.path.join(utils_tests.TESTS_DIRECTORY, "trace_sched.txt.cache")
108 shutil.copytree(src, cache_path)
109
110 md5_path = os.path.join(cache_path, "md5sum")
111 def read_md5sum():
112 with open(md5_path) as f:
113 return f.read()
114
115 # Change 1 character of the stored checksum
116 md5sum = read_md5sum()
117 # Sorry, I guess modifying strings in Python is kind of awkward?
118 md5sum_inc = "".join(list(md5sum[:-1]) + [chr(ord(md5sum[-1]) + 1)])
119 with open(md5_path, "w") as f:
120 f.write(md5sum_inc)
121
122 # Parse a trace, this should delete and overwrite the invalidated cache
123 GenericFTrace.disable_cache = False
124 trace = trappy.FTrace()
125
126 # Check that the modified md5sum was overwritten
127 self.assertNotEqual(read_md5sum(), md5sum_inc,
128 "The invalid ftrace cache wasn't overwritten")
129
130 def test_cache_dynamic_events(self):
131 """Test that caching works if new event parsers have been registered"""
132
133 # Parse the trace to create a cache
134 GenericFTrace.disable_cache = False
135 trace1 = trappy.FTrace()
136
137 # Check we're actually testing what we think we are
138 if hasattr(trace1, 'dynamic_event'):
139 raise RuntimeError('Test bug: found unexpected event in trace')
140
141 # Now register a new event type, call the constructor again, and check
142 # that the newly added event (which is not present in the cache) is
143 # parsed.
144
145 parse_class = trappy.register_dynamic_ftrace("DynamicEvent", "dynamic_test_key")
146
147 trace2 = trappy.FTrace()
148 self.assertTrue(len(trace2.dynamic_event.data_frame) == 1)
149
150 trappy.unregister_dynamic_ftrace(parse_class)
151
152 def test_cache_normalize_time(self):
153 """Test that caching doesn't break normalize_time"""
154 GenericFTrace.disable_cache = False
155
156 # Times in trace_sched.txt
157 start_time = 6550.018511
158 first_freq_event_time = 6550.056870
159
160 # Parse without normalizing time
161 trace1 = trappy.FTrace(events=['cpu_frequency', 'sched_wakeup'],
162 normalize_time=False)
163
164 self.assertEqual(trace1.cpu_frequency.data_frame.index[0],
165 first_freq_event_time)
166
167 # Parse with normalized time
168 trace2 = trappy.FTrace(events=['cpu_frequency', 'sched_wakeup'],
169 normalize_time=True)
170
171 self.assertEqual(trace2.cpu_frequency.data_frame.index[0],
172 first_freq_event_time - start_time)
173
174 def test_cache_window(self):
175 """Test that caching doesn't break the 'window' parameter"""
176 GenericFTrace.disable_cache = False
177
178 trace1 = trappy.FTrace(
179 events=['sched_wakeup'],
180 window=(0, 1))
181
182 # Check that we're testing what we think we're testing The trace
183 # contains 2 sched_wakeup events; this window should get rid of one of
184 # them.
185 if len(trace1.sched_wakeup.data_frame) != 1:
186 raise RuntimeError('Test bug: bad sched_wakeup event count')
187
188 # Parse again without the window
189 trace1 = trappy.FTrace(
190 events=['sched_wakeup'],
191 window=(0, None))
192
193 self.assertEqual(len(trace1.sched_wakeup.data_frame), 2)
Joel Fernandes96f11482017-07-08 19:22:22 -0700194
195 def test_cache_delete_single(self):
196 GenericFTrace.disable_cache = False
197 trace = trappy.FTrace()
198
199 trace_path = os.path.abspath(trace.trace_path)
200 trace_dir = os.path.dirname(trace_path)
201 trace_file = os.path.basename(trace_path)
202 cache_dir = '.' + trace_file + '.cache'
Kevin DuBoisa74ef6f2017-10-23 11:07:15 -0700203 number_of_trace_categories = 29
Kevin DuBoisb5108a12017-10-04 14:28:52 -0700204 self.assertEquals(len(os.listdir(cache_dir)), number_of_trace_categories)
Joel Fernandes96f11482017-07-08 19:22:22 -0700205
206 os.remove(os.path.join(cache_dir, 'SchedWakeup.csv'))
Kevin DuBoisb5108a12017-10-04 14:28:52 -0700207 self.assertEquals(len(os.listdir(cache_dir)), number_of_trace_categories - 1)
Joel Fernandes96f11482017-07-08 19:22:22 -0700208
209 # Generate trace again, should regenerate only the missing item
210 trace = trappy.FTrace()
Kevin DuBoisb5108a12017-10-04 14:28:52 -0700211 self.assertEquals(len(os.listdir(cache_dir)), number_of_trace_categories)
Joel Fernandes96f11482017-07-08 19:22:22 -0700212 for c in trace.trace_classes:
213 if isinstance(c, trace.class_definitions['sched_wakeup']):
214 self.assertEquals(c.cached, False)
215 continue
216 self.assertEquals(c.cached, True)