Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(2022)

Delta Between Two Patch Sets: Lib/test/test_dtrace.py

Issue 13405: Add DTrace probes
Left Patch Set: Created 1 year, 6 months ago
Right Patch Set: Created 10 months, 3 weeks ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « Lib/test/dtrace_sample.py ('k') | Makefile.pre.in » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
1 import sys, unittest, subprocess, os.path, dis, types 1 import sys, unittest, subprocess, os.path, dis, types
2 from test.test_support import TESTFN, run_unittest, findfile 2 import dtrace
3 from test.support import TESTFN, run_unittest, findfile
3 4
4 sample = os.path.abspath(findfile("dtrace_sample.py")) 5 sample = os.path.abspath(findfile("dtrace_sample.py"))
5 v = sys.trace_instrumentation 6 if not dtrace.available :
6 if (v is None) or (v[0].lower() != "dtrace") : 7 raise unittest.SkipTest("dtrace support not compiled in")
7 raise unittest.SkipTest, "dtrace support not compiled in" 8
9 def normalize(data) :
10 # DTRACE keeps a per-CPU buffer, and when showing the fired probes,
11 # buffers are concatenated. So if the operating system moves our
12 # thread around, the straight result can be "non causal".
13 # So we add timestamps to the probe firing, and sort by that field.
14 try :
15 result = data if isinstance(data, str) else data.decode("ascii")
16 result = [i.split("\t") \
17 for i in result.replace("\r", "").split("\n") if len(i)]
18 result.sort(key = lambda i: int(i[0]))
19 result = "".join((i[1] for i in result))
20 result = result.replace(" ", "")
21 except :
22 # If something goes wrong, rebuild the value so we can see the
23 # real result when the assert fails.
24 result = data if isinstance(data, str) else data.decode("ascii")
25 result = result.replace("\r", "").replace("\n", "")
26 return result
8 27
9 dscript = """ 28 dscript = """
10 pid$target::PyEval_EvalCode:entry 29 pid$target::PyEval_EvalCode:entry
11 """ 30 """
12 dscript = dscript.replace("\r", "").replace("\n", "") 31 dscript = dscript.replace("\r", "").replace("\n", "")
13 result, _ = subprocess.Popen(["dtrace", "-q", "-l", "-n", dscript, 32 result, _ = subprocess.Popen(["dtrace", "-q", "-l", "-n", dscript,
14 "-c", "%s %s" %(sys.executable, sample)], stdout=subprocess.PIPE, 33 "-c", "%s %s" %(sys.executable, sample)], stdout=subprocess.PIPE,
15 stderr=subprocess.STDOUT).communicate() 34 stderr=subprocess.STDOUT).communicate()
16 if result.split("\n")[1].split()[-2:] != ["PyEval_EvalCode", "entry"] : 35 if result.decode("ascii").split("\n")[1].split()[-2:] != \
36 ["PyEval_EvalCode", "entry"] :
17 result2 = repr(result) 37 result2 = repr(result)
18 raise unittest.SkipTest("dtrace seems not to be working. " + \ 38 raise unittest.SkipTest("dtrace seems not to be working. " + \
19 "Please, check your privileges. " + 39 "Please, check your privileges. " +
20 "Result: " +result2) 40 "Result: " +result2)
21 41
22 class DTraceTestsNormal(unittest.TestCase) : 42 class DTraceTestsNormal(unittest.TestCase) :
23 def setUp(self) : 43 def setUp(self) :
24 self.optimize = False 44 self.optimize = False
25 45
26 def test_function_entry_return(self) : 46 def test_function_entry_return(self) :
27 dscript = """ 47 dscript = """
28 python$target:::function-entry 48 python$target:::function-entry
29 /(copyinstr(arg0)=="%(path)s") && 49 /(copyinstr(arg0)=="%(path)s") &&
30 (copyinstr(arg1)=="test_entry_return_and_stack")/ 50 (copyinstr(arg1)=="test_entry_return_and_stack")/
31 { 51 {
32 self->trace = 1; 52 self->trace = 1;
33 } 53 }
34 python$target:::function-entry,python$target:::function-return 54 python$target:::function-entry,python$target:::function-return
35 /(copyinstr(arg0)=="%(path)s") && (self->trace)/ 55 /(copyinstr(arg0)=="%(path)s") && (self->trace)/
36 { 56 {
37 printf("**%%s*%%s*%%s*%%d\\n", probename, copyinstr(arg0), 57 printf("%%d\t**%%s*%%s*%%s*%%d\\n", timestamp,
58 probename, copyinstr(arg0),
38 copyinstr(arg1), arg2); 59 copyinstr(arg1), arg2);
39 } 60 }
40 python$target:::function-return 61 python$target:::function-return
41 /(copyinstr(arg0)=="%(path)s") && 62 /(copyinstr(arg0)=="%(path)s") &&
42 (copyinstr(arg1)=="test_entry_return_and_stack")/ 63 (copyinstr(arg1)=="test_entry_return_and_stack")/
43 { 64 {
44 self->trace = 0; 65 self->trace = 0;
45 } 66 }
46 """ %{"path":sample} 67 """ %{"path":sample}
47 68
(...skipping 16 matching lines...) Expand all
64 """ %{"path":sample} 85 """ %{"path":sample}
65 86
66 command = "%s %s" %(sys.executable, sample) 87 command = "%s %s" %(sys.executable, sample)
67 if self.optimize : 88 if self.optimize :
68 command = "%s -OO %s" %(sys.executable, sample) 89 command = "%s -OO %s" %(sys.executable, sample)
69 actual_result, _ = subprocess.Popen(["dtrace", "-q", "-n", 90 actual_result, _ = subprocess.Popen(["dtrace", "-q", "-n",
70 dscript, 91 dscript,
71 "-c", command], 92 "-c", command],
72 stdout=subprocess.PIPE, stderr=subprocess.STDOUT).communicate() 93 stdout=subprocess.PIPE, stderr=subprocess.STDOUT).communicate()
73 94
74 actual_result = actual_result.replace("\r", "").replace("\n", 95 actual_result = normalize(actual_result)
75 "").replace(" ", "") 96 expected_result = expected_result.replace("\r", "").replace("\n",
76 expected_result = expected_result.replace("\r", "").replace("\n", 97 "").replace(" ", "")
77 "").replace(" ", "") 98 self.assertEqual(actual_result, expected_result)
78 self.assertEqual(actual_result, expected_result) 99
79 100 @unittest.skipIf(sys.platform == 'darwin',
101 "MacOS X doesn't support jstack()")
80 def test_stack(self) : 102 def test_stack(self) :
81 dscript = """ 103 dscript = """
82 python$target:::function-entry 104 python$target:::function-entry
83 /(copyinstr(arg0)=="%(path)s") && 105 /(copyinstr(arg0)=="%(path)s") &&
84 (copyinstr(arg1)=="test_entry_return_and_stack")/ 106 (copyinstr(arg1)=="test_entry_return_and_stack")/
85 { 107 {
86 self->trace = 1; 108 self->trace = 1;
87 } 109 }
88 python$target:::function-entry 110 python$target:::function-entry
89 /(copyinstr(arg0)=="%(path)s") && (self->trace)/ 111 /(copyinstr(arg0)=="%(path)s") && (self->trace)/
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
125 """ %{"path":sample} 147 """ %{"path":sample}
126 148
127 command = "%s %s" %(sys.executable, sample) 149 command = "%s %s" %(sys.executable, sample)
128 if self.optimize : 150 if self.optimize :
129 command = "%s -OO %s" %(sys.executable, sample) 151 command = "%s -OO %s" %(sys.executable, sample)
130 actual_result, _ = subprocess.Popen(["dtrace", "-q", "-n", 152 actual_result, _ = subprocess.Popen(["dtrace", "-q", "-n",
131 dscript, 153 dscript,
132 "-c", command], 154 "-c", command],
133 stdout=subprocess.PIPE, stderr=subprocess.STDOUT).communicate() 155 stdout=subprocess.PIPE, stderr=subprocess.STDOUT).communicate()
134 156
135 actual_result = [i for i in actual_result.split("\n") if (("[" in i) 157 actual_result = [i for i in actual_result.decode("ascii").split("\n") \
136 and not i.endswith(" (<module>) ]"))] 158 if (("[" in i) and not i.endswith(" (<module>) ]"))]
137 actual_result = "".join(actual_result) 159 actual_result = "".join(actual_result)
138 actual_result = actual_result.replace("\r", "").replace("\n", 160 actual_result = actual_result.replace("\r", "").replace("\n",
139 "").replace(" ", "") 161 "").replace(" ", "")
140 expected_result = expected_result.replace("\r", "").replace("\n", 162 expected_result = expected_result.replace("\r", "").replace("\n",
141 "").replace(" ", "") 163 "").replace(" ", "")
142 self.assertEqual(actual_result, expected_result) 164 self.assertEqual(actual_result, expected_result)
143 165
144 def test_garbage_collection(self) : 166 def test_garbage_collection(self) :
145 dscript = """ 167 dscript = """
146 python$target:::gc-start,python$target:::gc-done 168 python$target:::gc-start,python$target:::gc-done
147 { 169 {
148 printf("**%s(%ld)\\n", probename, arg0); 170 printf("%d\t**%s(%ld)\\n", timestamp, probename, arg0);
149 } 171 }
150 """ 172 """
151 173
152 dscript = dscript.replace("\r", "").replace("\n", "") 174 dscript = dscript.replace("\r", "").replace("\n", "")
153 command = "%s %s" %(sys.executable, sample) 175 command = "%s %s" %(sys.executable, sample)
154 if self.optimize : 176 if self.optimize :
155 command = "%s -OO %s" %(sys.executable, sample) 177 command = "%s -OO %s" %(sys.executable, sample)
156 actual_result, _ = subprocess.Popen(["dtrace", "-q", "-n", 178 actual_result, _ = subprocess.Popen(["dtrace", "-q", "-n",
157 dscript, 179 dscript,
158 "-c", command], 180 "-c", command],
159 stdout=subprocess.PIPE, stderr=subprocess.STDOUT).communicate() 181 stdout=subprocess.PIPE, stderr=subprocess.STDOUT).communicate()
160 182
161 actual_result = "".join(actual_result) 183 actual_result = normalize(actual_result)
162 actual_result = actual_result.replace("\r", "").replace("\n", 184 for i in range(10) :
163 "").replace(" ", "")
164 for i in xrange(10) :
165 actual_result = actual_result.replace(str(i), "") 185 actual_result = actual_result.replace(str(i), "")
166 expected_result = "**gc-start()**gc-done()" * \ 186 expected_result = "**gc-start()**gc-done()" * \
167 actual_result.count("**gc-start()**") 187 actual_result.count("**gc-start()**")
168 188
169 self.assertEqual(actual_result, expected_result) 189 self.assertEqual(actual_result, expected_result)
170 190
171 def test_verify_opcodes(self) : 191 def test_verify_opcodes(self) :
172 # Verify that we are checking: 192 # Verify that we are checking:
173 opcodes = set(["CALL_FUNCTION", "CALL_FUNCTION_VAR", 193 opcodes = set(["CALL_FUNCTION", "CALL_FUNCTION_VAR",
174 "CALL_FUNCTION_KW", "CALL_FUNCTION_VAR_KW"]) 194 "CALL_FUNCTION_KW", "CALL_FUNCTION_VAR_KW"])
175 obj = compile(open(sample).read(), "sample", "exec") 195 obj = compile(open(sample, encoding="utf-8").read(), "sample", "exec")
176 class dump() : 196 class dump() :
177 def __init__(self) : 197 def __init__(self) :
178 self.buf = [] 198 self.buf = []
179 def write(self, v) : 199 def write(self, v) :
180 self.buf.append(v) 200 self.buf.append(v)
181 201
182 dump = dump() 202 dump = dump()
183 stdout = sys.stdout 203 stdout = sys.stdout
184 sys.stdout = dump 204 sys.stdout = dump
185 for i in obj.co_consts : 205 for i in obj.co_consts :
186 if isinstance(i, types.CodeType) and \ 206 if isinstance(i, types.CodeType) and \
187 (i.co_name == 'test_entry_return_and_stack') : 207 (i.co_name == 'test_entry_return_and_stack') :
188 dis.dis(i) 208 dis.dis(i)
189 sys.stdout = stdout 209 sys.stdout = stdout
190 dump = "\n".join(dump.buf) 210 dump = "\n".join(dump.buf)
191 dump = dump.replace("\r", "").replace("\n", "").split() 211 dump = dump.replace("\r", "").replace("\n", "").split()
192 for i in dump : 212 for i in dump :
193 opcodes.discard(i) 213 opcodes.discard(i)
194 # Are we verifying all the relevant opcodes? 214 # Are we verifying all the relevant opcodes?
195 self.assertEqual(set(), opcodes) # Are we verifying all opcodes? 215 self.assertEqual(set(), opcodes) # Are we verifying all opcodes?
196 216
197 def test_line(self) : 217 def test_line(self) :
198 dscript = """ 218 dscript = """
199 python$target:::line 219 python$target:::line
200 /(copyinstr(arg0)=="%(path)s") && 220 /(copyinstr(arg0)=="%(path)s") &&
201 (copyinstr(arg1)=="test_line")/ 221 (copyinstr(arg1)=="test_line")/
202 { 222 {
203 printf("**%%s*%%s*%%s*%%d\\n", probename, copyinstr(arg0), 223 printf("%%d\t**%%s*%%s*%%s*%%d\\n", timestamp,
224 probename, copyinstr(arg0),
204 copyinstr(arg1), arg2); 225 copyinstr(arg1), arg2);
205 } 226 }
206 """ %{"path":sample} 227 """ %{"path":sample}
207 228
208 dscript = dscript.replace("\r", "").replace("\n", "") 229 dscript = dscript.replace("\r", "").replace("\n", "")
209 expected_result = """ 230 expected_result = """
210 **line*%(path)s*test_line*33 231 **line*%(path)s*test_line*33
211 **line*%(path)s*test_line*34 232 **line*%(path)s*test_line*34
212 **line*%(path)s*test_line*35 233 **line*%(path)s*test_line*35
213 **line*%(path)s*test_line*36 234 **line*%(path)s*test_line*36
214 **line*%(path)s*test_line*37 235 **line*%(path)s*test_line*37
215 **line*%(path)s*test_line*38 236 **line*%(path)s*test_line*38
216 **line*%(path)s*test_line*34 237 **line*%(path)s*test_line*34
217 **line*%(path)s*test_line*35 238 **line*%(path)s*test_line*35
218 **line*%(path)s*test_line*36 239 **line*%(path)s*test_line*36
219 **line*%(path)s*test_line*37 240 **line*%(path)s*test_line*37
220 **line*%(path)s*test_line*38 241 **line*%(path)s*test_line*38
221 **line*%(path)s*test_line*34 242 **line*%(path)s*test_line*34
222 **line*%(path)s*test_line*39 243 **line*%(path)s*test_line*39
223 """ %{"path":sample} 244 """ %{"path":sample}
224 245
225 command = "%s %s" %(sys.executable, sample) 246 command = "%s %s" %(sys.executable, sample)
226 if self.optimize : 247 if self.optimize :
227 command = "%s -OO %s" %(sys.executable, sample) 248 command = "%s -OO %s" %(sys.executable, sample)
228 actual_result, _ = subprocess.Popen(["dtrace", "-q", "-n", 249 actual_result, _ = subprocess.Popen(["dtrace", "-q", "-n",
229 dscript, 250 dscript,
230 "-c", command], 251 "-c", command],
231 stdout=subprocess.PIPE, stderr=subprocess.STDOUT).communicate() 252 stdout=subprocess.PIPE, stderr=subprocess.STDOUT).communicate()
232 253
233 actual_result = actual_result.replace("\r", "").replace("\n", 254 actual_result = normalize(actual_result)
234 "").replace(" ", "")
235 expected_result = expected_result.replace("\r", "").replace("\n", 255 expected_result = expected_result.replace("\r", "").replace("\n",
236 "").replace(" ", "") 256 "").replace(" ", "")
237 self.assertEqual(actual_result, expected_result) 257 self.assertEqual(actual_result, expected_result)
238 258
239 def test_instance_creation_destruction(self) : 259 def test_instance_creation_destruction(self) :
240 dscript = """ 260 dscript = """
241 python$target:::function-entry 261 python$target:::function-entry
242 /(copyinstr(arg0)=="%(path)s") && 262 /(copyinstr(arg0)=="%(path)s") &&
243 (copyinstr(arg1)=="test_instance_creation_destruction")/ 263 (copyinstr(arg1)=="test_instance_creation_destruction")/
244 { 264 {
245 self->trace = 1; 265 self->trace = 1;
246 } 266 }
247 267
248 python$target:::instance-new-start, 268 python$target:::instance-new-start,
249 python$target:::instance-new-done, 269 python$target:::instance-new-done,
250 python$target:::instance-delete-start, 270 python$target:::instance-delete-start,
251 python$target:::instance-delete-done 271 python$target:::instance-delete-done
252 /self->trace/ 272 /self->trace/
253 { 273 {
254 printf("**%%s* (%%s.%%s)\\n", probename, copyinstr(arg1), copyinstr(arg0)); 274 printf("%%d\t**%%s* (%%s.%%s)\\n", timestamp,
275 probename, copyinstr(arg1), copyinstr(arg0));
255 } 276 }
256 277
257 python$target:::function-return 278 python$target:::function-return
258 /(copyinstr(arg0)=="%(path)s") && 279 /(copyinstr(arg0)=="%(path)s") &&
259 (copyinstr(arg1)=="test_instance_creation_destruction")/ 280 (copyinstr(arg1)=="test_instance_creation_destruction")/
260 { 281 {
261 self->trace = 0; 282 self->trace = 0;
262 } 283 }
263 """ %{"path":sample} 284 """ %{"path":sample}
264 285
(...skipping 18 matching lines...) Expand all
283 """ 304 """
284 305
285 command = "%s %s" %(sys.executable, sample) 306 command = "%s %s" %(sys.executable, sample)
286 if self.optimize : 307 if self.optimize :
287 command = "%s -OO %s" %(sys.executable, sample) 308 command = "%s -OO %s" %(sys.executable, sample)
288 actual_result, _ = subprocess.Popen(["dtrace", "-q", "-n", 309 actual_result, _ = subprocess.Popen(["dtrace", "-q", "-n",
289 dscript, 310 dscript,
290 "-c", command], 311 "-c", command],
291 stdout=subprocess.PIPE, stderr=subprocess.STDOUT).communicate() 312 stdout=subprocess.PIPE, stderr=subprocess.STDOUT).communicate()
292 313
314 actual_result = normalize(actual_result)
315 expected_result = expected_result.replace("\r", "").replace("\n",
316 "").replace(" ", "")
317 self.assertEqual(actual_result, expected_result)
318
319 def test_unicode_function_entry_return(self) :
320 dscript = """
321 python$target:::function-entry
322 /(copyinstr(arg0)=="%(path)s") &&
323 (copyinstr(arg1)=="test_unicode_entry_return_and_stack")/
324 {
325 self->trace = 1;
326 }
327 python$target:::function-entry,python$target:::function-return
328 /(copyinstr(arg0)=="%(path)s") && (self->trace)/
329 {
330 printf("%%d\t**%%s*%%s*%%s*%%d\\n", timestamp,
331 probename, copyinstr(arg0),
332 copyinstr(arg1), arg2);
333 }
334 python$target:::function-return
335 /(copyinstr(arg0)=="%(path)s") &&
336 (copyinstr(arg1)=="test_unicode_entry_return_and_stack")/
337 {
338 self->trace = 0;
339 }
340 """ %{"path":sample}
341
342 dscript = dscript.replace("\r", "").replace("\n", "")
343 expected_result = """
344 **function-entry*%(path)s*test_unicode_entry_return_and_stack*41
345 **function-entry*%(path)s*únícódé*42
346 **function-return*%(path)s*únícódé*43
347 **function-return*%(path)s*test_unicode_entry_return_and_stack*44
348 """ %{"path":sample}
349
350 command = "%s %s" %(sys.executable, sample)
351 if self.optimize :
352 command = "%s -OO %s" %(sys.executable, sample)
353 actual_result, _ = subprocess.Popen(["dtrace", "-q", "-n",
354 dscript,
355 "-c", command],
356 stdout=subprocess.PIPE, stderr=subprocess.STDOUT).communicate()
357
358 actual_result = actual_result.decode("utf8")
359 actual_result = normalize(actual_result)
360 expected_result = expected_result.replace("\r", "").replace("\n",
361 "").replace(" ", "")
362 self.assertEqual(actual_result, expected_result)
363
364 @unittest.skipIf(sys.platform == 'darwin',
365 "MacOS X doesn't support jstack()")
366 def test_unicode_stack(self) :
367 dscript = """
368 python$target:::function-entry
369 /(copyinstr(arg0)=="%(path)s") &&
370 (copyinstr(arg1)=="test_unicode_entry_return_and_stack")/
371 {
372 self->trace = 1;
373 }
374 python$target:::function-entry
375 /(copyinstr(arg0)=="%(path)s") && (self->trace)/
376 {
377 printf("[x]");
378 jstack();
379 }
380 python$target:::function-return
381 /(copyinstr(arg0)=="%(path)s") &&
382 (copyinstr(arg1)=="test_unicode_entry_return_and_stack")/
383 {
384 self->trace = 0;
385 }
386 """ %{"path":sample}
387
388 dscript = dscript.replace("\r", "").replace("\n", "")
389 expected_result = """
390 [x]
391 [%(path)s:41(test_unicode_entry_return_and_stack)]
392 [x]
393 [%(path)s:42(únícódé)]
394 [%(path)s:44(test_unicode_entry_return_and_stack)]
395 """ %{"path":sample}
396
397 command = "%s %s" %(sys.executable, sample)
398 if self.optimize :
399 command = "%s -OO %s" %(sys.executable, sample)
400 actual_result, _ = subprocess.Popen(["dtrace", "-q", "-n",
401 dscript,
402 "-c", command],
403 stdout=subprocess.PIPE, stderr=subprocess.STDOUT).communicate()
404
405 actual_result = [i for i in actual_result.decode("utf8").split("\n") \
406 if (("[" in i) and not i.endswith(" (<module>) ]"))]
407 actual_result = "".join(actual_result)
293 actual_result = actual_result.replace("\r", "").replace("\n", 408 actual_result = actual_result.replace("\r", "").replace("\n",
294 "").replace(" ", "") 409 "").replace(" ", "")
295 expected_result = expected_result.replace("\r", "").replace("\n", 410 expected_result = expected_result.replace("\r", "").replace("\n",
296 "").replace(" ", "") 411 "").replace(" ", "")
297 self.assertEqual(actual_result, expected_result) 412 self.assertEqual(actual_result, expected_result)
298 413
299 414
300 415
301 # This class try to verify that dtrace probes 416 # This class try to verify that dtrace probes
302 # are still working with optimizations enabled in the bytecode. 417 # are still working with optimizations enabled in the bytecode.
303 # 418 #
304 # Some tests will not actually verify it. For instance, 419 # Some tests will not actually verify it. For instance,
305 # source code compilation follows optimization status of 420 # source code compilation follows optimization status of
306 # current working Python. So, you should run the test 421 # current working Python. So, you should run the test
307 # both with an optimizing and a non optimizing Python. 422 # both with an optimizing and a non optimizing Python.
308 class DTraceTestsOptimize(DTraceTestsNormal) : 423 class DTraceTestsOptimize(DTraceTestsNormal) :
309 def setUp(self) : 424 def setUp(self) :
310 self.optimize = True 425 self.optimize = True
311 426
312 427
313 def test_main(): 428 def test_main():
314 run_unittest(DTraceTestsNormal) 429 run_unittest(DTraceTestsNormal)
315 run_unittest(DTraceTestsOptimize) 430 run_unittest(DTraceTestsOptimize)
316 431
317 if __name__ == '__main__': 432 if __name__ == '__main__':
318 test_main() 433 test_main()
319 434
LEFTRIGHT

RSS Feeds Recent Issues | This issue
This is Rietveld cbc36f91f3f7