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

Side by Side Diff: Lib/test/test_dtrace.py

Issue 13405: Add DTrace probes
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:
View unified diff | Download patch
« no previous file with comments | « Lib/test/dtrace_sample.py ('k') | Makefile.pre.in » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 import sys, unittest, subprocess, os.path, dis, types
2 import dtrace
3 from test.support import TESTFN, run_unittest, findfile
4
5 sample = os.path.abspath(findfile("dtrace_sample.py"))
6 if not dtrace.available :
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
27
28 dscript = """
29 pid$target::PyEval_EvalCode:entry
30 """
31 dscript = dscript.replace("\r", "").replace("\n", "")
32 result, _ = subprocess.Popen(["dtrace", "-q", "-l", "-n", dscript,
33 "-c", "%s %s" %(sys.executable, sample)], stdout=subprocess.PIPE,
34 stderr=subprocess.STDOUT).communicate()
35 if result.decode("ascii").split("\n")[1].split()[-2:] != \
36 ["PyEval_EvalCode", "entry"] :
37 result2 = repr(result)
38 raise unittest.SkipTest("dtrace seems not to be working. " + \
39 "Please, check your privileges. " +
40 "Result: " +result2)
41
42 class DTraceTestsNormal(unittest.TestCase) :
43 def setUp(self) :
44 self.optimize = False
45
46 def test_function_entry_return(self) :
47 dscript = """
48 python$target:::function-entry
49 /(copyinstr(arg0)=="%(path)s") &&
50 (copyinstr(arg1)=="test_entry_return_and_stack")/
51 {
52 self->trace = 1;
53 }
54 python$target:::function-entry,python$target:::function-return
55 /(copyinstr(arg0)=="%(path)s") && (self->trace)/
56 {
57 printf("%%d\t**%%s*%%s*%%s*%%d\\n", timestamp,
58 probename, copyinstr(arg0),
59 copyinstr(arg1), arg2);
60 }
61 python$target:::function-return
62 /(copyinstr(arg0)=="%(path)s") &&
63 (copyinstr(arg1)=="test_entry_return_and_stack")/
64 {
65 self->trace = 0;
66 }
67 """ %{"path":sample}
68
69 dscript = dscript.replace("\r", "").replace("\n", "")
70 expected_result = """
71 **function-entry*%(path)s*test_entry_return_and_stack*25
72 **function-entry*%(path)s*function_1*6
73 **function-return*%(path)s*function_1*7
74 **function-entry*%(path)s*function_2*10
75 **function-entry*%(path)s*function_1*6
76 **function-return*%(path)s*function_1*7
77 **function-return*%(path)s*function_2*11
78 **function-entry*%(path)s*function_3*14
79 **function-return*%(path)s*function_3*15
80 **function-entry*%(path)s*function_4*18
81 **function-return*%(path)s*function_4*19
82 **function-entry*%(path)s*function_5*22
83 **function-return*%(path)s*function_5*23
84 **function-return*%(path)s*test_entry_return_and_stack*30
85 """ %{"path":sample}
86
87 command = "%s %s" %(sys.executable, sample)
88 if self.optimize :
89 command = "%s -OO %s" %(sys.executable, sample)
90 actual_result, _ = subprocess.Popen(["dtrace", "-q", "-n",
91 dscript,
92 "-c", command],
93 stdout=subprocess.PIPE, stderr=subprocess.STDOUT).communicate()
94
95 actual_result = normalize(actual_result)
96 expected_result = expected_result.replace("\r", "").replace("\n",
97 "").replace(" ", "")
98 self.assertEqual(actual_result, expected_result)
99
100 @unittest.skipIf(sys.platform == 'darwin',
101 "MacOS X doesn't support jstack()")
102 def test_stack(self) :
103 dscript = """
104 python$target:::function-entry
105 /(copyinstr(arg0)=="%(path)s") &&
106 (copyinstr(arg1)=="test_entry_return_and_stack")/
107 {
108 self->trace = 1;
109 }
110 python$target:::function-entry
111 /(copyinstr(arg0)=="%(path)s") && (self->trace)/
112 {
113 printf("[x]");
114 jstack();
115 }
116 python$target:::function-return
117 /(copyinstr(arg0)=="%(path)s") &&
118 (copyinstr(arg1)=="test_entry_return_and_stack")/
119 {
120 self->trace = 0;
121 }
122 """ %{"path":sample}
123
124 dscript = dscript.replace("\r", "").replace("\n", "")
125 expected_result = """
126 [x]
127 [%(path)s:25(test_entry_return_and_stack)]
128 [x]
129 [%(path)s:6(function_1)]
130 [%(path)s:26(test_entry_return_and_stack)]
131 [x]
132 [%(path)s:10(function_2)]
133 [%(path)s:27(test_entry_return_and_stack)]
134 [x]
135 [%(path)s:6(function_1)]
136 [%(path)s:11(function_2)]
137 [%(path)s:27(test_entry_return_and_stack)]
138 [x]
139 [%(path)s:14(function_3)]
140 [%(path)s:28(test_entry_return_and_stack)]
141 [x]
142 [%(path)s:18(function_4)]
143 [%(path)s:29(test_entry_return_and_stack)]
144 [x]
145 [%(path)s:22(function_5)]
146 [%(path)s:30(test_entry_return_and_stack)]
147 """ %{"path":sample}
148
149 command = "%s %s" %(sys.executable, sample)
150 if self.optimize :
151 command = "%s -OO %s" %(sys.executable, sample)
152 actual_result, _ = subprocess.Popen(["dtrace", "-q", "-n",
153 dscript,
154 "-c", command],
155 stdout=subprocess.PIPE, stderr=subprocess.STDOUT).communicate()
156
157 actual_result = [i for i in actual_result.decode("ascii").split("\n") \
158 if (("[" in i) and not i.endswith(" (<module>) ]"))]
159 actual_result = "".join(actual_result)
160 actual_result = actual_result.replace("\r", "").replace("\n",
161 "").replace(" ", "")
162 expected_result = expected_result.replace("\r", "").replace("\n",
163 "").replace(" ", "")
164 self.assertEqual(actual_result, expected_result)
165
166 def test_garbage_collection(self) :
167 dscript = """
168 python$target:::gc-start,python$target:::gc-done
169 {
170 printf("%d\t**%s(%ld)\\n", timestamp, probename, arg0);
171 }
172 """
173
174 dscript = dscript.replace("\r", "").replace("\n", "")
175 command = "%s %s" %(sys.executable, sample)
176 if self.optimize :
177 command = "%s -OO %s" %(sys.executable, sample)
178 actual_result, _ = subprocess.Popen(["dtrace", "-q", "-n",
179 dscript,
180 "-c", command],
181 stdout=subprocess.PIPE, stderr=subprocess.STDOUT).communicate()
182
183 actual_result = normalize(actual_result)
184 for i in range(10) :
185 actual_result = actual_result.replace(str(i), "")
186 expected_result = "**gc-start()**gc-done()" * \
187 actual_result.count("**gc-start()**")
188
189 self.assertEqual(actual_result, expected_result)
190
191 def test_verify_opcodes(self) :
192 # Verify that we are checking:
193 opcodes = set(["CALL_FUNCTION", "CALL_FUNCTION_VAR",
194 "CALL_FUNCTION_KW", "CALL_FUNCTION_VAR_KW"])
195 obj = compile(open(sample, encoding="utf-8").read(), "sample", "exec")
196 class dump() :
197 def __init__(self) :
198 self.buf = []
199 def write(self, v) :
200 self.buf.append(v)
201
202 dump = dump()
203 stdout = sys.stdout
204 sys.stdout = dump
205 for i in obj.co_consts :
206 if isinstance(i, types.CodeType) and \
207 (i.co_name == 'test_entry_return_and_stack') :
208 dis.dis(i)
209 sys.stdout = stdout
210 dump = "\n".join(dump.buf)
211 dump = dump.replace("\r", "").replace("\n", "").split()
212 for i in dump :
213 opcodes.discard(i)
214 # Are we verifying all the relevant opcodes?
215 self.assertEqual(set(), opcodes) # Are we verifying all opcodes?
216
217 def test_line(self) :
218 dscript = """
219 python$target:::line
220 /(copyinstr(arg0)=="%(path)s") &&
221 (copyinstr(arg1)=="test_line")/
222 {
223 printf("%%d\t**%%s*%%s*%%s*%%d\\n", timestamp,
224 probename, copyinstr(arg0),
225 copyinstr(arg1), arg2);
226 }
227 """ %{"path":sample}
228
229 dscript = dscript.replace("\r", "").replace("\n", "")
230 expected_result = """
231 **line*%(path)s*test_line*33
232 **line*%(path)s*test_line*34
233 **line*%(path)s*test_line*35
234 **line*%(path)s*test_line*36
235 **line*%(path)s*test_line*37
236 **line*%(path)s*test_line*38
237 **line*%(path)s*test_line*34
238 **line*%(path)s*test_line*35
239 **line*%(path)s*test_line*36
240 **line*%(path)s*test_line*37
241 **line*%(path)s*test_line*38
242 **line*%(path)s*test_line*34
243 **line*%(path)s*test_line*39
244 """ %{"path":sample}
245
246 command = "%s %s" %(sys.executable, sample)
247 if self.optimize :
248 command = "%s -OO %s" %(sys.executable, sample)
249 actual_result, _ = subprocess.Popen(["dtrace", "-q", "-n",
250 dscript,
251 "-c", command],
252 stdout=subprocess.PIPE, stderr=subprocess.STDOUT).communicate()
253
254 actual_result = normalize(actual_result)
255 expected_result = expected_result.replace("\r", "").replace("\n",
256 "").replace(" ", "")
257 self.assertEqual(actual_result, expected_result)
258
259 def test_instance_creation_destruction(self) :
260 dscript = """
261 python$target:::function-entry
262 /(copyinstr(arg0)=="%(path)s") &&
263 (copyinstr(arg1)=="test_instance_creation_destruction")/
264 {
265 self->trace = 1;
266 }
267
268 python$target:::instance-new-start,
269 python$target:::instance-new-done,
270 python$target:::instance-delete-start,
271 python$target:::instance-delete-done
272 /self->trace/
273 {
274 printf("%%d\t**%%s* (%%s.%%s)\\n", timestamp,
275 probename, copyinstr(arg1), copyinstr(arg0));
276 }
277
278 python$target:::function-return
279 /(copyinstr(arg0)=="%(path)s") &&
280 (copyinstr(arg1)=="test_instance_creation_destruction")/
281 {
282 self->trace = 0;
283 }
284 """ %{"path":sample}
285
286 dscript = dscript.replace("\r", "").replace("\n", "")
287 expected_result = """
288 **instance-new-start*(__main__.old_style_class)
289 **instance-new-done*(__main__.old_style_class)
290 **instance-delete-start*(__main__.old_style_class)
291 **instance-delete-done*(__main__.old_style_class)
292 **instance-new-start*(__main__.new_style_class)
293 **instance-new-done*(__main__.new_style_class)
294 **instance-delete-start*(__main__.new_style_class)
295 **instance-delete-done*(__main__.new_style_class)
296 **instance-new-start*(__main__.old_style_class)
297 **instance-new-done*(__main__.old_style_class)
298 **instance-new-start*(__main__.new_style_class)
299 **instance-new-done*(__main__.new_style_class)
300 **instance-delete-start*(__main__.old_style_class)
301 **instance-delete-done*(__main__.old_style_class)
302 **instance-delete-start*(__main__.new_style_class)
303 **instance-delete-done*(__main__.new_style_class)
304 """
305
306 command = "%s %s" %(sys.executable, sample)
307 if self.optimize :
308 command = "%s -OO %s" %(sys.executable, sample)
309 actual_result, _ = subprocess.Popen(["dtrace", "-q", "-n",
310 dscript,
311 "-c", command],
312 stdout=subprocess.PIPE, stderr=subprocess.STDOUT).communicate()
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)
408 actual_result = actual_result.replace("\r", "").replace("\n",
409 "").replace(" ", "")
410 expected_result = expected_result.replace("\r", "").replace("\n",
411 "").replace(" ", "")
412 self.assertEqual(actual_result, expected_result)
413
414
415
416 # This class try to verify that dtrace probes
417 # are still working with optimizations enabled in the bytecode.
418 #
419 # Some tests will not actually verify it. For instance,
420 # source code compilation follows optimization status of
421 # current working Python. So, you should run the test
422 # both with an optimizing and a non optimizing Python.
423 class DTraceTestsOptimize(DTraceTestsNormal) :
424 def setUp(self) :
425 self.optimize = True
426
427
428 def test_main():
429 run_unittest(DTraceTestsNormal)
430 run_unittest(DTraceTestsOptimize)
431
432 if __name__ == '__main__':
433 test_main()
434
OLDNEW
« no previous file with comments | « Lib/test/dtrace_sample.py ('k') | Makefile.pre.in » ('j') | no next file with comments »

RSS Feeds Recent Issues | This issue
This is Rietveld cbc36f91f3f7