blob: 70d4607c296ae29979ff6a7ea0a08883814e8b91 [file] [log] [blame]
Patrick Williams169d7bc2024-01-05 11:33:25 -06001From 0136ca731cba8b056b3f2ff0e7df3953b94f1e87 Mon Sep 17 00:00:00 2001
2From: Tim Orling <tim.orling@konsulko.com>
3Date: Sun, 24 Dec 2023 09:41:57 -0800
4Subject: [PATCH 1/2] test_functionality: convert line endings to Unix
Andrew Geissler69721092021-07-23 12:57:00 -04005
Patrick Williams169d7bc2024-01-05 11:33:25 -06006Convert the Windows line endings with dos2unix to be like the
7other files in tests/*
8
9Upstream-Status: Submitted [https://github.com/sumerc/yappi/pull/164]
10
11Signed-off-by: Tim Orling <tim.orling@konsulko.com>
Andrew Geissler69721092021-07-23 12:57:00 -040012---
Patrick Williams169d7bc2024-01-05 11:33:25 -060013 tests/test_functionality.py | 3822 +++++++++++++++++------------------
14 1 file changed, 1911 insertions(+), 1911 deletions(-)
Patrick Williams520786c2023-06-25 16:20:36 -050015
Patrick Williams169d7bc2024-01-05 11:33:25 -060016diff --git a/tests/test_functionality.py b/tests/test_functionality.py
17index 0e99c47..38bbe67 100644
Andrew Geissler69721092021-07-23 12:57:00 -040018--- a/tests/test_functionality.py
19+++ b/tests/test_functionality.py
Patrick Williams169d7bc2024-01-05 11:33:25 -060020@@ -1,1911 +1,1911 @@
Andrew Geissler69721092021-07-23 12:57:00 -040021-import os
22-import sys
23-import time
24-import threading
25-import unittest
26-import yappi
27-import _yappi
28-import utils
Patrick Williams169d7bc2024-01-05 11:33:25 -060029-import multiprocessing
Andrew Geissler69721092021-07-23 12:57:00 -040030-import subprocess
31-
32-_counter = 0
33-
34-
35-class BasicUsage(utils.YappiUnitTestCase):
36-
37- def test_callback_function_int_return_overflow(self):
38- # this test is just here to check if any errors are generated, as the err
39- # is printed in C side, I did not include it here. THere are ways to test
40- # this deterministically, I did not bother
41- import ctypes
42-
43- def _unsigned_overflow_margin():
44- return 2**(ctypes.sizeof(ctypes.c_void_p) * 8) - 1
45-
46- def foo():
47- pass
48-
49- #with utils.captured_output() as (out, err):
50- yappi.set_context_id_callback(_unsigned_overflow_margin)
51- yappi.set_tag_callback(_unsigned_overflow_margin)
52- yappi.start()
53- foo()
54-
55- def test_issue60(self):
56-
57- def foo():
58- buf = bytearray()
59- buf += b't' * 200
60- view = memoryview(buf)[10:]
61- view = view.tobytes()
62- del buf[:10] # this throws exception
63- return view
64-
65- yappi.start(builtins=True)
66- foo()
67- self.assertTrue(
68- len(
69- yappi.get_func_stats(
70- filter_callback=lambda x: yappi.
71- func_matches(x, [memoryview.tobytes])
72- )
73- ) > 0
74- )
75- yappi.stop()
76-
77- def test_issue54(self):
78-
79- def _tag_cbk():
80- global _counter
81- _counter += 1
82- return _counter
83-
84- def a():
85- pass
86-
87- def b():
88- pass
89-
90- yappi.set_tag_callback(_tag_cbk)
91- yappi.start()
92- a()
93- a()
94- a()
95- yappi.stop()
96- stats = yappi.get_func_stats()
97- self.assertEqual(stats.pop().ncall, 3) # aggregated if no tag is given
98- stats = yappi.get_func_stats(tag=1)
99-
100- for i in range(1, 3):
101- stats = yappi.get_func_stats(tag=i)
102- stats = yappi.get_func_stats(
103- tag=i, filter_callback=lambda x: yappi.func_matches(x, [a])
104- )
105-
106- stat = stats.pop()
107- self.assertEqual(stat.ncall, 1)
108-
109- yappi.set_tag_callback(None)
110- yappi.clear_stats()
111- yappi.start()
112- b()
113- b()
114- stats = yappi.get_func_stats()
115- self.assertEqual(len(stats), 1)
116- stat = stats.pop()
117- self.assertEqual(stat.ncall, 2)
118-
119- def test_filter(self):
120-
121- def a():
122- pass
123-
124- def b():
125- a()
126-
127- def c():
128- b()
129-
130- _TCOUNT = 5
131-
132- ts = []
133- yappi.start()
134- for i in range(_TCOUNT):
135- t = threading.Thread(target=c)
136- t.start()
137- ts.append(t)
138-
139- for t in ts:
140- t.join()
141-
142- yappi.stop()
143-
144- ctx_ids = []
145- for tstat in yappi.get_thread_stats():
146- if tstat.name == '_MainThread':
147- main_ctx_id = tstat.id
148- else:
149- ctx_ids.append(tstat.id)
150-
151- fstats = yappi.get_func_stats(filter={"ctx_id": 9})
152- self.assertTrue(fstats.empty())
153- fstats = yappi.get_func_stats(
154- filter={
155- "ctx_id": main_ctx_id,
156- "name": "c"
157- }
158- ) # main thread
159- self.assertTrue(fstats.empty())
160-
161- for i in ctx_ids:
162- fstats = yappi.get_func_stats(
163- filter={
164- "ctx_id": i,
165- "name": "a",
166- "ncall": 1
167- }
168- )
169- self.assertEqual(fstats.pop().ncall, 1)
170- fstats = yappi.get_func_stats(filter={"ctx_id": i, "name": "b"})
171- self.assertEqual(fstats.pop().ncall, 1)
172- fstats = yappi.get_func_stats(filter={"ctx_id": i, "name": "c"})
173- self.assertEqual(fstats.pop().ncall, 1)
174-
175- yappi.clear_stats()
176- yappi.start(builtins=True)
177- time.sleep(0.1)
178- yappi.stop()
179- fstats = yappi.get_func_stats(filter={"module": "time"})
180- self.assertEqual(len(fstats), 1)
181-
182- # invalid filters`
183- self.assertRaises(
184- Exception, yappi.get_func_stats, filter={'tag': "sss"}
185- )
186- self.assertRaises(
187- Exception, yappi.get_func_stats, filter={'ctx_id': "None"}
188- )
189-
190- def test_filter_callback(self):
191-
192- def a():
193- time.sleep(0.1)
194-
195- def b():
196- a()
197-
198- def c():
199- pass
200-
201- def d():
202- pass
203-
204- yappi.set_clock_type("wall")
205- yappi.start(builtins=True)
206- a()
207- b()
208- c()
209- d()
210- stats = yappi.get_func_stats(
211- filter_callback=lambda x: yappi.func_matches(x, [a, b])
212- )
213- #stats.print_all()
214- r1 = '''
215- tests/test_functionality.py:98 a 2 0.000000 0.200350 0.100175
216- tests/test_functionality.py:101 b 1 0.000000 0.120000 0.100197
217- '''
218- self.assert_traces_almost_equal(r1, stats)
219- self.assertEqual(len(stats), 2)
220- stats = yappi.get_func_stats(
221- filter_callback=lambda x: yappi.
222- module_matches(x, [sys.modules[__name__]])
223- )
224- r1 = '''
225- tests/test_functionality.py:98 a 2 0.000000 0.230130 0.115065
226- tests/test_functionality.py:101 b 1 0.000000 0.120000 0.109011
227- tests/test_functionality.py:104 c 1 0.000000 0.000002 0.000002
228- tests/test_functionality.py:107 d 1 0.000000 0.000001 0.000001
229- '''
230- self.assert_traces_almost_equal(r1, stats)
231- self.assertEqual(len(stats), 4)
232-
233- stats = yappi.get_func_stats(
234- filter_callback=lambda x: yappi.func_matches(x, [time.sleep])
235- )
236- self.assertEqual(len(stats), 1)
237- r1 = '''
238- time.sleep 2 0.206804 0.220000 0.103402
239- '''
240- self.assert_traces_almost_equal(r1, stats)
241-
242- def test_print_formatting(self):
243-
244- def a():
245- pass
246-
247- def b():
248- a()
249-
250- func_cols = {
251- 1: ("name", 48),
252- 0: ("ncall", 5),
253- 2: ("tsub", 8),
254- }
255- thread_cols = {
256- 1: ("name", 48),
257- 0: ("ttot", 8),
258- }
259-
260- yappi.start()
261- a()
262- b()
263- yappi.stop()
264- fs = yappi.get_func_stats()
265- cs = fs[1].children
266- ts = yappi.get_thread_stats()
267- #fs.print_all(out=sys.stderr, columns={1:("name", 70), })
268- #cs.print_all(out=sys.stderr, columns=func_cols)
269- #ts.print_all(out=sys.stderr, columns=thread_cols)
270- #cs.print_all(out=sys.stderr, columns={})
271-
272- self.assertRaises(
273- yappi.YappiError, fs.print_all, columns={1: ("namee", 9)}
274- )
275- self.assertRaises(
276- yappi.YappiError, cs.print_all, columns={1: ("dd", 0)}
277- )
278- self.assertRaises(
279- yappi.YappiError, ts.print_all, columns={1: ("tidd", 0)}
280- )
281-
282- def test_get_clock(self):
283- yappi.set_clock_type('cpu')
284- self.assertEqual('cpu', yappi.get_clock_type())
285- clock_info = yappi.get_clock_info()
286- self.assertTrue('api' in clock_info)
287- self.assertTrue('resolution' in clock_info)
288-
289- yappi.set_clock_type('wall')
290- self.assertEqual('wall', yappi.get_clock_type())
291-
292- t0 = yappi.get_clock_time()
293- time.sleep(0.1)
294- duration = yappi.get_clock_time() - t0
295- self.assertTrue(0.05 < duration < 0.3)
296-
297- def test_profile_decorator(self):
298-
299- def aggregate(func, stats):
Patrick Williams169d7bc2024-01-05 11:33:25 -0600300- fname = f"tests/{func.__name__}.profile"
Andrew Geissler69721092021-07-23 12:57:00 -0400301- try:
302- stats.add(fname)
Patrick Williams169d7bc2024-01-05 11:33:25 -0600303- except OSError:
Andrew Geissler69721092021-07-23 12:57:00 -0400304- pass
305- stats.save(fname)
306- raise Exception("messing around")
307-
308- @yappi.profile(return_callback=aggregate)
309- def a(x, y):
310- if x + y == 25:
311- raise Exception("")
312- return x + y
313-
314- def b():
315- pass
316-
317- try:
318- os.remove(
319- "tests/a.profile"
320- ) # remove the one from prev test, if available
321- except:
322- pass
323-
324- # global profile is on to mess things up
325- yappi.start()
326- b()
327-
328- # assert functionality and call function at same time
329- try:
330- self.assertEqual(a(1, 2), 3)
331- except:
332- pass
333- try:
334- self.assertEqual(a(2, 5), 7)
335- except:
336- pass
337- try:
338- a(4, 21)
339- except:
340- pass
341- stats = yappi.get_func_stats().add("tests/a.profile")
342- fsa = utils.find_stat_by_name(stats, 'a')
343- self.assertEqual(fsa.ncall, 3)
344- self.assertEqual(len(stats), 1) # b() should be cleared out.
345-
346- @yappi.profile(return_callback=aggregate)
347- def count_down_rec(n):
348- if n == 0:
349- return
350- count_down_rec(n - 1)
351-
352- try:
353- os.remove(
354- "tests/count_down_rec.profile"
355- ) # remove the one from prev test, if available
356- except:
357- pass
358-
359- try:
360- count_down_rec(4)
361- except:
362- pass
363- try:
364- count_down_rec(3)
365- except:
366- pass
367-
368- stats = yappi.YFuncStats("tests/count_down_rec.profile")
369- fsrec = utils.find_stat_by_name(stats, 'count_down_rec')
370- self.assertEqual(fsrec.ncall, 9)
371- self.assertEqual(fsrec.nactualcall, 2)
372-
373- def test_strip_dirs(self):
374-
375- def a():
376- pass
377-
378- stats = utils.run_and_get_func_stats(a, )
379- stats.strip_dirs()
380- fsa = utils.find_stat_by_name(stats, "a")
381- self.assertEqual(fsa.module, os.path.basename(fsa.module))
382-
383- @unittest.skipIf(os.name == "nt", "do not run on Windows")
384- def test_run_as_script(self):
385- import re
386- p = subprocess.Popen(
387- ['yappi', os.path.join('./tests', 'run_as_script.py')],
388- stdout=subprocess.PIPE
389- )
390- out, err = p.communicate()
391- self.assertEqual(p.returncode, 0)
392- func_stats, thread_stats = re.split(
393- b'name\\s+id\\s+tid\\s+ttot\\s+scnt\\s*\n', out
394- )
395- self.assertTrue(b'FancyThread' in thread_stats)
396-
397- def test_yappi_overhead(self):
398- LOOP_COUNT = 100000
399-
400- def a():
401- pass
402-
403- def b():
404- for i in range(LOOP_COUNT):
405- a()
406-
407- t0 = time.time()
408- yappi.start()
409- b()
410- yappi.stop()
411- time_with_yappi = time.time() - t0
412- t0 = time.time()
413- b()
414- time_without_yappi = time.time() - t0
415- if time_without_yappi == 0:
416- time_without_yappi = 0.000001
417-
418- # in latest v0.82, I calculated this as close to "7.0" in my machine.
419- # however, %83 of this overhead is coming from tickcount(). The other %17
420- # seems to have been evenly distributed to the internal bookkeeping
421- # structures/algorithms which seems acceptable. Note that our test only
422- # tests one function being profiled at-a-time in a short interval.
423- # profiling high number of functions in a small time
424- # is a different beast, (which is pretty unlikely in most applications)
425- # So as a conclusion: I cannot see any optimization window for Yappi that
426- # is worth implementing as we will only optimize %17 of the time.
427- sys.stderr.write("\r\nYappi puts %0.1f times overhead to the profiled application in average.\r\n" % \
428- (time_with_yappi / time_without_yappi))
429-
430- def test_clear_stats_while_running(self):
431-
432- def a():
433- pass
434-
435- yappi.start()
436- a()
437- yappi.clear_stats()
438- a()
439- stats = yappi.get_func_stats()
440- fsa = utils.find_stat_by_name(stats, 'a')
441- self.assertEqual(fsa.ncall, 1)
442-
443- def test_generator(self):
444-
445- def _gen(n):
446- while (n > 0):
447- yield n
448- n -= 1
449-
450- yappi.start()
451- for x in _gen(5):
452- pass
453- self.assertTrue(
454- yappi.convert2pstats(yappi.get_func_stats()) is not None
455- )
456-
457- def test_slice_child_stats_and_strip_dirs(self):
458-
459- def b():
460- for i in range(10000000):
461- pass
462-
463- def a():
464- b()
465-
466- yappi.start(builtins=True)
467- a()
468- stats = yappi.get_func_stats()
469- fsa = utils.find_stat_by_name(stats, 'a')
470- fsb = utils.find_stat_by_name(stats, 'b')
471- self.assertTrue(fsa.children[0:1] is not None)
472- prev_afullname = fsa.full_name
473- prev_bchildfullname = fsa.children[fsb].full_name
474- stats.strip_dirs()
475- self.assertTrue(len(prev_afullname) > len(fsa.full_name))
476- self.assertTrue(
477- len(prev_bchildfullname) > len(fsa.children[fsb].full_name)
478- )
479-
480- def test_children_stat_functions(self):
481- _timings = {"a_1": 5, "b_1": 3, "c_1": 1}
482- _yappi._set_test_timings(_timings)
483-
484- def b():
485- pass
486-
487- def c():
488- pass
489-
490- def a():
491- b()
492- c()
493-
494- yappi.start()
495- a()
496- b() # non-child call
497- c() # non-child call
498- stats = yappi.get_func_stats()
499- fsa = utils.find_stat_by_name(stats, 'a')
500- childs_of_a = fsa.children.get().sort("tavg", "desc")
501- prev_item = None
502- for item in childs_of_a:
503- if prev_item:
504- self.assertTrue(prev_item.tavg > item.tavg)
505- prev_item = item
506- childs_of_a.sort("name", "desc")
507- prev_item = None
508- for item in childs_of_a:
509- if prev_item:
510- self.assertTrue(prev_item.name > item.name)
511- prev_item = item
512- childs_of_a.clear()
513- self.assertTrue(childs_of_a.empty())
514-
515- def test_no_stats_different_clock_type_load(self):
516-
517- def a():
518- pass
519-
520- yappi.start()
521- a()
522- yappi.stop()
523- yappi.get_func_stats().save("tests/ystats1.ys")
524- yappi.clear_stats()
525- yappi.set_clock_type("WALL")
526- yappi.start()
527- yappi.stop()
528- stats = yappi.get_func_stats().add("tests/ystats1.ys")
529- fsa = utils.find_stat_by_name(stats, 'a')
530- self.assertTrue(fsa is not None)
531-
532- def test_subsequent_profile(self):
533- _timings = {"a_1": 1, "b_1": 1}
534- _yappi._set_test_timings(_timings)
535-
536- def a():
537- pass
538-
539- def b():
540- pass
541-
542- yappi.start()
543- a()
544- yappi.stop()
545- yappi.start()
546- b()
547- yappi.stop()
548- stats = yappi.get_func_stats()
549- fsa = utils.find_stat_by_name(stats, 'a')
550- fsb = utils.find_stat_by_name(stats, 'b')
551- self.assertTrue(fsa is not None)
552- self.assertTrue(fsb is not None)
553- self.assertEqual(fsa.ttot, 1)
554- self.assertEqual(fsb.ttot, 1)
555-
556- def test_lambda(self):
557- f = lambda: time.sleep(0.3)
558- yappi.set_clock_type("wall")
559- yappi.start()
560- f()
561- stats = yappi.get_func_stats()
562- fsa = utils.find_stat_by_name(stats, '<lambda>')
563- self.assertTrue(fsa.ttot > 0.1)
564-
565- def test_module_stress(self):
566- self.assertEqual(yappi.is_running(), False)
567-
568- yappi.start()
569- yappi.clear_stats()
570- self.assertRaises(_yappi.error, yappi.set_clock_type, "wall")
571-
572- yappi.stop()
573- yappi.clear_stats()
574- yappi.set_clock_type("cpu")
575- self.assertRaises(yappi.YappiError, yappi.set_clock_type, "dummy")
576- self.assertEqual(yappi.is_running(), False)
577- yappi.clear_stats()
578- yappi.clear_stats()
579-
580- def test_stat_sorting(self):
581- _timings = {"a_1": 13, "b_1": 10, "a_2": 6, "b_2": 1}
582- _yappi._set_test_timings(_timings)
583-
584- self._ncall = 1
585-
586- def a():
587- b()
588-
589- def b():
590- if self._ncall == 2:
591- return
592- self._ncall += 1
593- a()
594-
595- stats = utils.run_and_get_func_stats(a)
596- stats = stats.sort("totaltime", "desc")
597- prev_stat = None
598- for stat in stats:
599- if prev_stat:
600- self.assertTrue(prev_stat.ttot >= stat.ttot)
601- prev_stat = stat
602- stats = stats.sort("totaltime", "asc")
603- prev_stat = None
604- for stat in stats:
605- if prev_stat:
606- self.assertTrue(prev_stat.ttot <= stat.ttot)
607- prev_stat = stat
608- stats = stats.sort("avgtime", "asc")
609- prev_stat = None
610- for stat in stats:
611- if prev_stat:
612- self.assertTrue(prev_stat.tavg <= stat.tavg)
613- prev_stat = stat
614- stats = stats.sort("name", "asc")
615- prev_stat = None
616- for stat in stats:
617- if prev_stat:
618- self.assertTrue(prev_stat.name <= stat.name)
619- prev_stat = stat
620- stats = stats.sort("subtime", "asc")
621- prev_stat = None
622- for stat in stats:
623- if prev_stat:
624- self.assertTrue(prev_stat.tsub <= stat.tsub)
625- prev_stat = stat
626-
627- self.assertRaises(
628- yappi.YappiError, stats.sort, "invalid_func_sorttype_arg"
629- )
630- self.assertRaises(
631- yappi.YappiError, stats.sort, "totaltime",
632- "invalid_func_sortorder_arg"
633- )
634-
635- def test_start_flags(self):
636- self.assertEqual(_yappi._get_start_flags(), None)
637- yappi.start()
638-
639- def a():
640- pass
641-
642- a()
643- self.assertEqual(_yappi._get_start_flags()["profile_builtins"], 0)
644- self.assertEqual(_yappi._get_start_flags()["profile_multicontext"], 1)
645- self.assertEqual(len(yappi.get_thread_stats()), 1)
646-
647- def test_builtin_profiling(self):
648-
649- def a():
650- time.sleep(0.4) # is a builtin function
651-
652- yappi.set_clock_type('wall')
653-
654- yappi.start(builtins=True)
655- a()
656- stats = yappi.get_func_stats()
657- fsa = utils.find_stat_by_name(stats, 'sleep')
658- self.assertTrue(fsa is not None)
659- self.assertTrue(fsa.ttot > 0.3)
660- yappi.stop()
661- yappi.clear_stats()
662-
663- def a():
664- pass
665-
666- yappi.start()
667- t = threading.Thread(target=a)
668- t.start()
669- t.join()
670- stats = yappi.get_func_stats()
671-
672- def test_singlethread_profiling(self):
673- yappi.set_clock_type('wall')
674-
675- def a():
676- time.sleep(0.2)
677-
678- class Worker1(threading.Thread):
679-
680- def a(self):
681- time.sleep(0.3)
682-
683- def run(self):
684- self.a()
685-
686- yappi.start(profile_threads=False)
687-
688- c = Worker1()
689- c.start()
690- c.join()
691- a()
692- stats = yappi.get_func_stats()
693- fsa1 = utils.find_stat_by_name(stats, 'Worker1.a')
694- fsa2 = utils.find_stat_by_name(stats, 'a')
695- self.assertTrue(fsa1 is None)
696- self.assertTrue(fsa2 is not None)
697- self.assertTrue(fsa2.ttot > 0.1)
698-
699- def test_run(self):
700-
701- def profiled():
702- pass
703-
704- yappi.clear_stats()
705- try:
706- with yappi.run():
707- profiled()
708- stats = yappi.get_func_stats()
709- finally:
710- yappi.clear_stats()
711-
712- self.assertIsNotNone(utils.find_stat_by_name(stats, 'profiled'))
713-
714- def test_run_recursive(self):
715-
716- def profiled():
717- pass
718-
719- def not_profiled():
720- pass
721-
722- yappi.clear_stats()
723- try:
724- with yappi.run():
725- with yappi.run():
726- profiled()
727- # Profiling stopped here
728- not_profiled()
729- stats = yappi.get_func_stats()
730- finally:
731- yappi.clear_stats()
732-
733- self.assertIsNotNone(utils.find_stat_by_name(stats, 'profiled'))
734- self.assertIsNone(utils.find_stat_by_name(stats, 'not_profiled'))
735-
736-
737-class StatSaveScenarios(utils.YappiUnitTestCase):
738-
739- def test_pstats_conversion(self):
740-
741- def pstat_id(fs):
742- return (fs.module, fs.lineno, fs.name)
743-
744- def a():
745- d()
746-
747- def b():
748- d()
749-
750- def c():
751- pass
752-
753- def d():
754- pass
755-
756- _timings = {"a_1": 12, "b_1": 7, "c_1": 5, "d_1": 2}
757- _yappi._set_test_timings(_timings)
758- stats = utils.run_and_get_func_stats(a, )
759- stats.strip_dirs()
760- stats.save("tests/a1.pstats", type="pstat")
761- fsa_pid = pstat_id(utils.find_stat_by_name(stats, "a"))
762- fsd_pid = pstat_id(utils.find_stat_by_name(stats, "d"))
763- yappi.clear_stats()
764- _yappi._set_test_timings(_timings)
765- stats = utils.run_and_get_func_stats(a, )
766- stats.strip_dirs()
767- stats.save("tests/a2.pstats", type="pstat")
768- yappi.clear_stats()
769- _yappi._set_test_timings(_timings)
770- stats = utils.run_and_get_func_stats(b, )
771- stats.strip_dirs()
772- stats.save("tests/b1.pstats", type="pstat")
773- fsb_pid = pstat_id(utils.find_stat_by_name(stats, "b"))
774- yappi.clear_stats()
775- _yappi._set_test_timings(_timings)
776- stats = utils.run_and_get_func_stats(c, )
777- stats.strip_dirs()
778- stats.save("tests/c1.pstats", type="pstat")
779- fsc_pid = pstat_id(utils.find_stat_by_name(stats, "c"))
780-
781- # merge saved stats and check pstats values are correct
782- import pstats
783- p = pstats.Stats(
784- 'tests/a1.pstats', 'tests/a2.pstats', 'tests/b1.pstats',
785- 'tests/c1.pstats'
786- )
787- p.strip_dirs()
788- # ct = ttot, tt = tsub
789- (cc, nc, tt, ct, callers) = p.stats[fsa_pid]
790- self.assertEqual(cc, nc, 2)
791- self.assertEqual(tt, 20)
792- self.assertEqual(ct, 24)
793- (cc, nc, tt, ct, callers) = p.stats[fsd_pid]
794- self.assertEqual(cc, nc, 3)
795- self.assertEqual(tt, 6)
796- self.assertEqual(ct, 6)
797- self.assertEqual(len(callers), 2)
798- (cc, nc, tt, ct) = callers[fsa_pid]
799- self.assertEqual(cc, nc, 2)
800- self.assertEqual(tt, 4)
801- self.assertEqual(ct, 4)
802- (cc, nc, tt, ct) = callers[fsb_pid]
803- self.assertEqual(cc, nc, 1)
804- self.assertEqual(tt, 2)
805- self.assertEqual(ct, 2)
806-
807- def test_merge_stats(self):
808- _timings = {
809- "a_1": 15,
810- "b_1": 14,
811- "c_1": 12,
812- "d_1": 10,
813- "e_1": 9,
814- "f_1": 7,
815- "g_1": 6,
816- "h_1": 5,
817- "i_1": 1
818- }
819- _yappi._set_test_timings(_timings)
820-
821- def a():
822- b()
823-
824- def b():
825- c()
826-
827- def c():
828- d()
829-
830- def d():
831- e()
832-
833- def e():
834- f()
835-
836- def f():
837- g()
838-
839- def g():
840- h()
841-
842- def h():
843- i()
844-
845- def i():
846- pass
847-
848- yappi.start()
849- a()
850- a()
851- yappi.stop()
852- stats = yappi.get_func_stats()
853- self.assertRaises(
854- NotImplementedError, stats.save, "", "INVALID_SAVE_TYPE"
855- )
856- stats.save("tests/ystats2.ys")
857- yappi.clear_stats()
858- _yappi._set_test_timings(_timings)
859- yappi.start()
860- a()
861- stats = yappi.get_func_stats().add("tests/ystats2.ys")
862- fsa = utils.find_stat_by_name(stats, "a")
863- fsb = utils.find_stat_by_name(stats, "b")
864- fsc = utils.find_stat_by_name(stats, "c")
865- fsd = utils.find_stat_by_name(stats, "d")
866- fse = utils.find_stat_by_name(stats, "e")
867- fsf = utils.find_stat_by_name(stats, "f")
868- fsg = utils.find_stat_by_name(stats, "g")
869- fsh = utils.find_stat_by_name(stats, "h")
870- fsi = utils.find_stat_by_name(stats, "i")
871- self.assertEqual(fsa.ttot, 45)
872- self.assertEqual(fsa.ncall, 3)
873- self.assertEqual(fsa.nactualcall, 3)
874- self.assertEqual(fsa.tsub, 3)
875- self.assertEqual(fsa.children[fsb].ttot, fsb.ttot)
876- self.assertEqual(fsa.children[fsb].tsub, fsb.tsub)
877- self.assertEqual(fsb.children[fsc].ttot, fsc.ttot)
878- self.assertEqual(fsb.children[fsc].tsub, fsc.tsub)
879- self.assertEqual(fsc.tsub, 6)
880- self.assertEqual(fsc.children[fsd].ttot, fsd.ttot)
881- self.assertEqual(fsc.children[fsd].tsub, fsd.tsub)
882- self.assertEqual(fsd.children[fse].ttot, fse.ttot)
883- self.assertEqual(fsd.children[fse].tsub, fse.tsub)
884- self.assertEqual(fse.children[fsf].ttot, fsf.ttot)
885- self.assertEqual(fse.children[fsf].tsub, fsf.tsub)
886- self.assertEqual(fsf.children[fsg].ttot, fsg.ttot)
887- self.assertEqual(fsf.children[fsg].tsub, fsg.tsub)
888- self.assertEqual(fsg.ttot, 18)
889- self.assertEqual(fsg.tsub, 3)
890- self.assertEqual(fsg.children[fsh].ttot, fsh.ttot)
891- self.assertEqual(fsg.children[fsh].tsub, fsh.tsub)
892- self.assertEqual(fsh.ttot, 15)
893- self.assertEqual(fsh.tsub, 12)
894- self.assertEqual(fsh.tavg, 5)
895- self.assertEqual(fsh.children[fsi].ttot, fsi.ttot)
896- self.assertEqual(fsh.children[fsi].tsub, fsi.tsub)
897- #stats.debug_print()
898-
899- def test_merge_multithreaded_stats(self):
900- import _yappi
901- timings = {"a_1": 2, "b_1": 1}
902- _yappi._set_test_timings(timings)
903-
904- def a():
905- pass
906-
907- def b():
908- pass
909-
910- yappi.start()
911- t = threading.Thread(target=a)
912- t.start()
913- t.join()
914- t = threading.Thread(target=b)
915- t.start()
916- t.join()
917- yappi.get_func_stats().save("tests/ystats1.ys")
918- yappi.clear_stats()
919- _yappi._set_test_timings(timings)
920- self.assertEqual(len(yappi.get_func_stats()), 0)
921- self.assertEqual(len(yappi.get_thread_stats()), 1)
922- t = threading.Thread(target=a)
923- t.start()
924- t.join()
925-
926- self.assertEqual(_yappi._get_start_flags()["profile_builtins"], 0)
927- self.assertEqual(_yappi._get_start_flags()["profile_multicontext"], 1)
928- yappi.get_func_stats().save("tests/ystats2.ys")
929-
930- stats = yappi.YFuncStats([
931- "tests/ystats1.ys",
932- "tests/ystats2.ys",
933- ])
934- fsa = utils.find_stat_by_name(stats, "a")
935- fsb = utils.find_stat_by_name(stats, "b")
936- self.assertEqual(fsa.ncall, 2)
937- self.assertEqual(fsb.ncall, 1)
938- self.assertEqual(fsa.tsub, fsa.ttot, 4)
939- self.assertEqual(fsb.tsub, fsb.ttot, 1)
940-
941- def test_merge_load_different_clock_types(self):
942- yappi.start(builtins=True)
943-
944- def a():
945- b()
946-
947- def b():
948- c()
949-
950- def c():
951- pass
952-
953- t = threading.Thread(target=a)
954- t.start()
955- t.join()
956- yappi.get_func_stats().sort("name", "asc").save("tests/ystats1.ys")
957- yappi.stop()
958- yappi.clear_stats()
959- yappi.start(builtins=False)
960- t = threading.Thread(target=a)
961- t.start()
962- t.join()
963- yappi.get_func_stats().save("tests/ystats2.ys")
964- yappi.stop()
965- self.assertRaises(_yappi.error, yappi.set_clock_type, "wall")
966- yappi.clear_stats()
967- yappi.set_clock_type("wall")
968- yappi.start()
969- t = threading.Thread(target=a)
970- t.start()
971- t.join()
972- yappi.get_func_stats().save("tests/ystats3.ys")
973- self.assertRaises(
974- yappi.YappiError,
975- yappi.YFuncStats().add("tests/ystats1.ys").add, "tests/ystats3.ys"
976- )
977- stats = yappi.YFuncStats(["tests/ystats1.ys",
978- "tests/ystats2.ys"]).sort("name")
979- fsa = utils.find_stat_by_name(stats, "a")
980- fsb = utils.find_stat_by_name(stats, "b")
981- fsc = utils.find_stat_by_name(stats, "c")
982- self.assertEqual(fsa.ncall, 2)
983- self.assertEqual(fsa.ncall, fsb.ncall, fsc.ncall)
984-
985- def test_merge_aabab_aabbc(self):
986- _timings = {
987- "a_1": 15,
988- "a_2": 14,
989- "b_1": 12,
990- "a_3": 10,
991- "b_2": 9,
992- "c_1": 4
993- }
994- _yappi._set_test_timings(_timings)
995-
996- def a():
997- if self._ncall == 1:
998- self._ncall += 1
999- a()
1000- elif self._ncall == 5:
1001- self._ncall += 1
1002- a()
1003- else:
1004- b()
1005-
1006- def b():
1007- if self._ncall == 2:
1008- self._ncall += 1
1009- a()
1010- elif self._ncall == 6:
1011- self._ncall += 1
1012- b()
1013- elif self._ncall == 7:
1014- c()
1015- else:
1016- return
1017-
1018- def c():
1019- pass
1020-
1021- self._ncall = 1
1022- stats = utils.run_and_get_func_stats(a, )
1023- stats.save("tests/ystats1.ys")
1024- yappi.clear_stats()
1025- _yappi._set_test_timings(_timings)
1026- #stats.print_all()
1027-
1028- self._ncall = 5
1029- stats = utils.run_and_get_func_stats(a, )
1030- stats.save("tests/ystats2.ys")
1031-
1032- #stats.print_all()
1033-
1034- def a(): # same name but another function(code object)
1035- pass
1036-
1037- yappi.start()
1038- a()
1039- stats = yappi.get_func_stats().add(
1040- ["tests/ystats1.ys", "tests/ystats2.ys"]
1041- )
1042- #stats.print_all()
1043- self.assertEqual(len(stats), 4)
1044-
1045- fsa = None
1046- for stat in stats:
1047- if stat.name == "a" and stat.ttot == 45:
1048- fsa = stat
1049- break
1050- self.assertTrue(fsa is not None)
1051-
1052- self.assertEqual(fsa.ncall, 7)
1053- self.assertEqual(fsa.nactualcall, 3)
1054- self.assertEqual(fsa.ttot, 45)
1055- self.assertEqual(fsa.tsub, 10)
1056- fsb = utils.find_stat_by_name(stats, "b")
1057- fsc = utils.find_stat_by_name(stats, "c")
1058- self.assertEqual(fsb.ncall, 6)
1059- self.assertEqual(fsb.nactualcall, 3)
1060- self.assertEqual(fsb.ttot, 36)
1061- self.assertEqual(fsb.tsub, 27)
1062- self.assertEqual(fsb.tavg, 6)
1063- self.assertEqual(fsc.ttot, 8)
1064- self.assertEqual(fsc.tsub, 8)
1065- self.assertEqual(fsc.tavg, 4)
1066- self.assertEqual(fsc.nactualcall, fsc.ncall, 2)
1067-
1068-
1069-class MultithreadedScenarios(utils.YappiUnitTestCase):
1070-
1071- def test_issue_32(self):
1072- '''
1073- Start yappi from different thread and we get Internal Error(15) as
1074- the current_ctx_id() called while enumerating the threads in start()
1075- and as it does not swap to the enumerated ThreadState* the THreadState_GetDict()
1076- returns wrong object and thus sets an invalid id for the _ctx structure.
1077-
1078- When this issue happens multiple Threads have same tid as the internal ts_ptr
1079- will be same for different contexts. So, let's see if that happens
1080- '''
1081-
1082- def foo():
1083- time.sleep(0.2)
1084-
1085- def bar():
1086- time.sleep(0.1)
1087-
1088- def thread_func():
1089- yappi.set_clock_type("wall")
1090- yappi.start()
1091-
1092- bar()
1093-
1094- t = threading.Thread(target=thread_func)
1095- t.start()
1096- t.join()
1097-
1098- foo()
1099-
1100- yappi.stop()
1101-
1102- thread_ids = set()
1103- for tstat in yappi.get_thread_stats():
1104- self.assertTrue(tstat.tid not in thread_ids)
1105- thread_ids.add(tstat.tid)
1106-
1107- def test_subsequent_profile(self):
1108- WORKER_COUNT = 5
1109-
1110- def a():
1111- pass
1112-
1113- def b():
1114- pass
1115-
1116- def c():
1117- pass
1118-
1119- _timings = {
1120- "a_1": 3,
1121- "b_1": 2,
1122- "c_1": 1,
1123- }
1124-
1125- yappi.start()
1126-
1127- def g():
1128- pass
1129-
1130- g()
1131- yappi.stop()
1132- yappi.clear_stats()
1133- _yappi._set_test_timings(_timings)
1134- yappi.start()
1135-
1136- _dummy = []
1137- for i in range(WORKER_COUNT):
1138- t = threading.Thread(target=a)
1139- t.start()
1140- t.join()
1141- for i in range(WORKER_COUNT):
1142- t = threading.Thread(target=b)
1143- t.start()
1144- _dummy.append(t)
1145- t.join()
1146- for i in range(WORKER_COUNT):
1147- t = threading.Thread(target=a)
1148- t.start()
1149- t.join()
1150- for i in range(WORKER_COUNT):
1151- t = threading.Thread(target=c)
1152- t.start()
1153- t.join()
1154- yappi.stop()
1155- yappi.start()
1156-
1157- def f():
1158- pass
1159-
1160- f()
1161- stats = yappi.get_func_stats()
1162- fsa = utils.find_stat_by_name(stats, 'a')
1163- fsb = utils.find_stat_by_name(stats, 'b')
1164- fsc = utils.find_stat_by_name(stats, 'c')
1165- self.assertEqual(fsa.ncall, 10)
1166- self.assertEqual(fsb.ncall, 5)
1167- self.assertEqual(fsc.ncall, 5)
1168- self.assertEqual(fsa.ttot, fsa.tsub, 30)
1169- self.assertEqual(fsb.ttot, fsb.tsub, 10)
1170- self.assertEqual(fsc.ttot, fsc.tsub, 5)
1171-
1172- # MACOSx optimizes by only creating one worker thread
1173- self.assertTrue(len(yappi.get_thread_stats()) >= 2)
1174-
1175- def test_basic(self):
1176- yappi.set_clock_type('wall')
1177-
1178- def dummy():
1179- pass
1180-
1181- def a():
1182- time.sleep(0.2)
1183-
1184- class Worker1(threading.Thread):
1185-
1186- def a(self):
1187- time.sleep(0.3)
1188-
1189- def run(self):
1190- self.a()
1191-
1192- yappi.start(builtins=False, profile_threads=True)
1193-
1194- c = Worker1()
1195- c.start()
1196- c.join()
1197- a()
1198- stats = yappi.get_func_stats()
1199- fsa1 = utils.find_stat_by_name(stats, 'Worker1.a')
1200- fsa2 = utils.find_stat_by_name(stats, 'a')
1201- self.assertTrue(fsa1 is not None)
1202- self.assertTrue(fsa2 is not None)
1203- self.assertTrue(fsa1.ttot > 0.2)
1204- self.assertTrue(fsa2.ttot > 0.1)
1205- tstats = yappi.get_thread_stats()
1206- self.assertEqual(len(tstats), 2)
1207- tsa = utils.find_stat_by_name(tstats, 'Worker1')
1208- tsm = utils.find_stat_by_name(tstats, '_MainThread')
1209- dummy() # call dummy to force ctx name to be retrieved again.
1210- self.assertTrue(tsa is not None)
1211- # TODO: I put dummy() to fix below, remove the comments after a while.
1212- self.assertTrue( # FIX: I see this fails sometimes?
1213- tsm is not None,
Patrick Williams169d7bc2024-01-05 11:33:25 -06001214- f"Could not find \"_MainThread\". Found: {', '.join(utils.get_stat_names(tstats))}")
Andrew Geissler69721092021-07-23 12:57:00 -04001215-
1216- def test_ctx_stats(self):
1217- from threading import Thread
1218- DUMMY_WORKER_COUNT = 5
1219- yappi.start()
1220-
1221- class DummyThread(Thread):
1222- pass
1223-
1224- def dummy():
1225- pass
1226-
1227- def dummy_worker():
1228- pass
1229-
1230- for i in range(DUMMY_WORKER_COUNT):
1231- t = DummyThread(target=dummy_worker)
1232- t.start()
1233- t.join()
1234- yappi.stop()
1235- stats = yappi.get_thread_stats()
1236- tsa = utils.find_stat_by_name(stats, "DummyThread")
1237- self.assertTrue(tsa is not None)
1238- yappi.clear_stats()
1239- time.sleep(1.0)
1240- _timings = {
1241- "a_1": 6,
1242- "b_1": 5,
1243- "c_1": 3,
1244- "d_1": 1,
1245- "a_2": 4,
1246- "b_2": 3,
1247- "c_2": 2,
1248- "d_2": 1
1249- }
1250- _yappi._set_test_timings(_timings)
1251-
1252- class Thread1(Thread):
1253- pass
1254-
1255- class Thread2(Thread):
1256- pass
1257-
1258- def a():
1259- b()
1260-
1261- def b():
1262- c()
1263-
1264- def c():
1265- d()
1266-
1267- def d():
1268- time.sleep(0.6)
1269-
1270- yappi.set_clock_type("wall")
1271- yappi.start()
1272- t1 = Thread1(target=a)
1273- t1.start()
1274- t2 = Thread2(target=a)
1275- t2.start()
1276- t1.join()
1277- t2.join()
1278- stats = yappi.get_thread_stats()
1279-
1280- # the fist clear_stats clears the context table?
1281- tsa = utils.find_stat_by_name(stats, "DummyThread")
1282- self.assertTrue(tsa is None)
1283-
1284- tst1 = utils.find_stat_by_name(stats, "Thread1")
1285- tst2 = utils.find_stat_by_name(stats, "Thread2")
1286- tsmain = utils.find_stat_by_name(stats, "_MainThread")
1287- dummy() # call dummy to force ctx name to be retrieved again.
1288- self.assertTrue(len(stats) == 3)
1289- self.assertTrue(tst1 is not None)
1290- self.assertTrue(tst2 is not None)
1291- # TODO: I put dummy() to fix below, remove the comments after a while.
1292- self.assertTrue( # FIX: I see this fails sometimes
1293- tsmain is not None,
Patrick Williams169d7bc2024-01-05 11:33:25 -06001294- f"Could not find \"_MainThread\". Found: {', '.join(utils.get_stat_names(stats))}")
Andrew Geissler69721092021-07-23 12:57:00 -04001295- self.assertTrue(1.0 > tst2.ttot >= 0.5)
1296- self.assertTrue(1.0 > tst1.ttot >= 0.5)
1297-
1298- # test sorting of the ctx stats
1299- stats = stats.sort("totaltime", "desc")
1300- prev_stat = None
1301- for stat in stats:
1302- if prev_stat:
1303- self.assertTrue(prev_stat.ttot >= stat.ttot)
1304- prev_stat = stat
1305- stats = stats.sort("totaltime", "asc")
1306- prev_stat = None
1307- for stat in stats:
1308- if prev_stat:
1309- self.assertTrue(prev_stat.ttot <= stat.ttot)
1310- prev_stat = stat
1311- stats = stats.sort("schedcount", "desc")
1312- prev_stat = None
1313- for stat in stats:
1314- if prev_stat:
1315- self.assertTrue(prev_stat.sched_count >= stat.sched_count)
1316- prev_stat = stat
1317- stats = stats.sort("name", "desc")
1318- prev_stat = None
1319- for stat in stats:
1320- if prev_stat:
1321- self.assertTrue(prev_stat.name.lower() >= stat.name.lower())
1322- prev_stat = stat
1323- self.assertRaises(
1324- yappi.YappiError, stats.sort, "invalid_thread_sorttype_arg"
1325- )
1326- self.assertRaises(
1327- yappi.YappiError, stats.sort, "invalid_thread_sortorder_arg"
1328- )
1329-
1330- def test_ctx_stats_cpu(self):
1331-
1332- def get_thread_name():
1333- try:
1334- return threading.current_thread().name
1335- except AttributeError:
1336- return "Anonymous"
1337-
1338- def burn_cpu(sec):
1339- t0 = yappi.get_clock_time()
1340- elapsed = 0
1341- while (elapsed < sec):
1342- for _ in range(1000):
1343- pass
1344- elapsed = yappi.get_clock_time() - t0
1345-
1346- def test():
1347-
1348- ts = []
1349- for i in (0.01, 0.05, 0.1):
1350- t = threading.Thread(target=burn_cpu, args=(i, ))
Patrick Williams169d7bc2024-01-05 11:33:25 -06001351- t.name = f"burn_cpu-{str(i)}"
Andrew Geissler69721092021-07-23 12:57:00 -04001352- t.start()
1353- ts.append(t)
1354- for t in ts:
1355- t.join()
1356-
1357- yappi.set_clock_type("cpu")
1358- yappi.set_context_name_callback(get_thread_name)
1359-
1360- yappi.start()
1361-
1362- test()
1363-
1364- yappi.stop()
1365-
1366- tstats = yappi.get_thread_stats()
1367- r1 = '''
1368- burn_cpu-0.1 3 123145356058624 0.100105 8
1369- burn_cpu-0.05 2 123145361313792 0.050149 8
1370- burn_cpu-0.01 1 123145356058624 0.010127 2
1371- MainThread 0 4321620864 0.001632 6
1372- '''
1373- self.assert_ctx_stats_almost_equal(r1, tstats)
1374-
1375- def test_producer_consumer_with_queues(self):
1376- # we currently just stress yappi, no functionality test is done here.
1377- yappi.start()
Patrick Williams169d7bc2024-01-05 11:33:25 -06001378- from queue import Queue
Andrew Geissler69721092021-07-23 12:57:00 -04001379- from threading import Thread
1380- WORKER_THREAD_COUNT = 50
1381- WORK_ITEM_COUNT = 2000
1382-
1383- def worker():
1384- while True:
1385- item = q.get()
1386- # do the work with item
1387- q.task_done()
1388-
1389- q = Queue()
1390- for i in range(WORKER_THREAD_COUNT):
1391- t = Thread(target=worker)
1392- t.daemon = True
1393- t.start()
1394-
1395- for item in range(WORK_ITEM_COUNT):
1396- q.put(item)
1397- q.join() # block until all tasks are done
1398- #yappi.get_func_stats().sort("callcount").print_all()
1399- yappi.stop()
1400-
1401- def test_temporary_lock_waiting(self):
1402- yappi.start()
1403- _lock = threading.Lock()
1404-
1405- def worker():
1406- _lock.acquire()
1407- try:
1408- time.sleep(1.0)
1409- finally:
1410- _lock.release()
1411-
1412- t1 = threading.Thread(target=worker)
1413- t2 = threading.Thread(target=worker)
1414- t1.start()
1415- t2.start()
1416- t1.join()
1417- t2.join()
1418- #yappi.get_func_stats().sort("callcount").print_all()
1419- yappi.stop()
1420-
1421- @unittest.skipIf(os.name != "posix", "requires Posix compliant OS")
1422- def test_signals_with_blocking_calls(self):
1423- import signal, os, time
1424-
1425- # just to verify if signal is handled correctly and stats/yappi are not corrupted.
1426- def handler(signum, frame):
1427- raise Exception("Signal handler executed!")
1428-
1429- yappi.start()
1430- signal.signal(signal.SIGALRM, handler)
1431- signal.alarm(1)
1432- self.assertRaises(Exception, time.sleep, 2)
1433- stats = yappi.get_func_stats()
1434- fsh = utils.find_stat_by_name(stats, "handler")
1435- self.assertTrue(fsh is not None)
1436-
Andrew Geissler69721092021-07-23 12:57:00 -04001437- def test_concurrent_futures(self):
1438- yappi.start()
1439- from concurrent.futures import ThreadPoolExecutor
1440- with ThreadPoolExecutor(max_workers=5) as executor:
1441- f = executor.submit(pow, 5, 2)
1442- self.assertEqual(f.result(), 25)
1443- time.sleep(1.0)
1444- yappi.stop()
1445-
Andrew Geissler69721092021-07-23 12:57:00 -04001446- def test_barrier(self):
1447- yappi.start()
1448- b = threading.Barrier(2, timeout=1)
1449-
1450- def worker():
1451- try:
1452- b.wait()
1453- except threading.BrokenBarrierError:
1454- pass
1455- except Exception:
1456- raise Exception("BrokenBarrierError not raised")
1457-
1458- t1 = threading.Thread(target=worker)
1459- t1.start()
1460- #b.wait()
1461- t1.join()
1462- yappi.stop()
1463-
1464-
1465-class NonRecursiveFunctions(utils.YappiUnitTestCase):
1466-
1467- def test_abcd(self):
1468- _timings = {"a_1": 6, "b_1": 5, "c_1": 3, "d_1": 1}
1469- _yappi._set_test_timings(_timings)
1470-
1471- def a():
1472- b()
1473-
1474- def b():
1475- c()
1476-
1477- def c():
1478- d()
1479-
1480- def d():
1481- pass
1482-
1483- stats = utils.run_and_get_func_stats(a)
1484- fsa = utils.find_stat_by_name(stats, 'a')
1485- fsb = utils.find_stat_by_name(stats, 'b')
1486- fsc = utils.find_stat_by_name(stats, 'c')
1487- fsd = utils.find_stat_by_name(stats, 'd')
1488- cfsab = fsa.children[fsb]
1489- cfsbc = fsb.children[fsc]
1490- cfscd = fsc.children[fsd]
1491-
1492- self.assertEqual(fsa.ttot, 6)
1493- self.assertEqual(fsa.tsub, 1)
1494- self.assertEqual(fsb.ttot, 5)
1495- self.assertEqual(fsb.tsub, 2)
1496- self.assertEqual(fsc.ttot, 3)
1497- self.assertEqual(fsc.tsub, 2)
1498- self.assertEqual(fsd.ttot, 1)
1499- self.assertEqual(fsd.tsub, 1)
1500- self.assertEqual(cfsab.ttot, 5)
1501- self.assertEqual(cfsab.tsub, 2)
1502- self.assertEqual(cfsbc.ttot, 3)
1503- self.assertEqual(cfsbc.tsub, 2)
1504- self.assertEqual(cfscd.ttot, 1)
1505- self.assertEqual(cfscd.tsub, 1)
1506-
1507- def test_stop_in_middle(self):
1508- _timings = {"a_1": 6, "b_1": 4}
1509- _yappi._set_test_timings(_timings)
1510-
1511- def a():
1512- b()
1513- yappi.stop()
1514-
1515- def b():
1516- time.sleep(0.2)
1517-
1518- yappi.start()
1519- a()
1520- stats = yappi.get_func_stats()
1521- fsa = utils.find_stat_by_name(stats, 'a')
1522- fsb = utils.find_stat_by_name(stats, 'b')
1523-
1524- self.assertEqual(fsa.ncall, 1)
1525- self.assertEqual(fsa.nactualcall, 0)
1526- self.assertEqual(fsa.ttot, 0) # no call_leave called
1527- self.assertEqual(fsa.tsub, 0) # no call_leave called
1528- self.assertEqual(fsb.ttot, 4)
1529-
1530-
1531-class RecursiveFunctions(utils.YappiUnitTestCase):
1532-
1533- def test_fibonacci(self):
1534-
1535- def fib(n):
1536- if n > 1:
1537- return fib(n - 1) + fib(n - 2)
1538- else:
1539- return n
1540-
1541- stats = utils.run_and_get_func_stats(fib, 22)
1542- fs = utils.find_stat_by_name(stats, 'fib')
1543- self.assertEqual(fs.ncall, 57313)
1544- self.assertEqual(fs.ttot, fs.tsub)
1545-
1546- def test_abcadc(self):
1547- _timings = {
1548- "a_1": 20,
1549- "b_1": 19,
1550- "c_1": 17,
1551- "a_2": 13,
1552- "d_1": 12,
1553- "c_2": 10,
1554- "a_3": 5
1555- }
1556- _yappi._set_test_timings(_timings)
1557-
1558- def a(n):
1559- if n == 3:
1560- return
1561- if n == 1 + 1:
1562- d(n)
1563- else:
1564- b(n)
1565-
1566- def b(n):
1567- c(n)
1568-
1569- def c(n):
1570- a(n + 1)
1571-
1572- def d(n):
1573- c(n)
1574-
1575- stats = utils.run_and_get_func_stats(a, 1)
1576- fsa = utils.find_stat_by_name(stats, 'a')
1577- fsb = utils.find_stat_by_name(stats, 'b')
1578- fsc = utils.find_stat_by_name(stats, 'c')
1579- fsd = utils.find_stat_by_name(stats, 'd')
1580- self.assertEqual(fsa.ncall, 3)
1581- self.assertEqual(fsa.nactualcall, 1)
1582- self.assertEqual(fsa.ttot, 20)
1583- self.assertEqual(fsa.tsub, 7)
1584- self.assertEqual(fsb.ttot, 19)
1585- self.assertEqual(fsb.tsub, 2)
1586- self.assertEqual(fsc.ttot, 17)
1587- self.assertEqual(fsc.tsub, 9)
1588- self.assertEqual(fsd.ttot, 12)
1589- self.assertEqual(fsd.tsub, 2)
1590- cfsca = fsc.children[fsa]
1591- self.assertEqual(cfsca.nactualcall, 0)
1592- self.assertEqual(cfsca.ncall, 2)
1593- self.assertEqual(cfsca.ttot, 13)
1594- self.assertEqual(cfsca.tsub, 6)
1595-
1596- def test_aaaa(self):
1597- _timings = {"d_1": 9, "d_2": 7, "d_3": 3, "d_4": 2}
1598- _yappi._set_test_timings(_timings)
1599-
1600- def d(n):
1601- if n == 3:
1602- return
1603- d(n + 1)
1604-
1605- stats = utils.run_and_get_func_stats(d, 0)
1606- fsd = utils.find_stat_by_name(stats, 'd')
1607- self.assertEqual(fsd.ncall, 4)
1608- self.assertEqual(fsd.nactualcall, 1)
1609- self.assertEqual(fsd.ttot, 9)
1610- self.assertEqual(fsd.tsub, 9)
1611- cfsdd = fsd.children[fsd]
1612- self.assertEqual(cfsdd.ttot, 7)
1613- self.assertEqual(cfsdd.tsub, 7)
1614- self.assertEqual(cfsdd.ncall, 3)
1615- self.assertEqual(cfsdd.nactualcall, 0)
1616-
1617- def test_abcabc(self):
1618- _timings = {
1619- "a_1": 20,
1620- "b_1": 19,
1621- "c_1": 17,
1622- "a_2": 13,
1623- "b_2": 11,
1624- "c_2": 9,
1625- "a_3": 6
1626- }
1627- _yappi._set_test_timings(_timings)
1628-
1629- def a(n):
1630- if n == 3:
1631- return
1632- else:
1633- b(n)
1634-
1635- def b(n):
1636- c(n)
1637-
1638- def c(n):
1639- a(n + 1)
1640-
1641- stats = utils.run_and_get_func_stats(a, 1)
1642- fsa = utils.find_stat_by_name(stats, 'a')
1643- fsb = utils.find_stat_by_name(stats, 'b')
1644- fsc = utils.find_stat_by_name(stats, 'c')
1645- self.assertEqual(fsa.ncall, 3)
1646- self.assertEqual(fsa.nactualcall, 1)
1647- self.assertEqual(fsa.ttot, 20)
1648- self.assertEqual(fsa.tsub, 9)
1649- self.assertEqual(fsb.ttot, 19)
1650- self.assertEqual(fsb.tsub, 4)
1651- self.assertEqual(fsc.ttot, 17)
1652- self.assertEqual(fsc.tsub, 7)
1653- cfsab = fsa.children[fsb]
1654- cfsbc = fsb.children[fsc]
1655- cfsca = fsc.children[fsa]
1656- self.assertEqual(cfsab.ttot, 19)
1657- self.assertEqual(cfsab.tsub, 4)
1658- self.assertEqual(cfsbc.ttot, 17)
1659- self.assertEqual(cfsbc.tsub, 7)
1660- self.assertEqual(cfsca.ttot, 13)
1661- self.assertEqual(cfsca.tsub, 8)
1662-
1663- def test_abcbca(self):
1664- _timings = {"a_1": 10, "b_1": 9, "c_1": 7, "b_2": 4, "c_2": 2, "a_2": 1}
1665- _yappi._set_test_timings(_timings)
1666- self._ncall = 1
1667-
1668- def a():
1669- if self._ncall == 1:
1670- b()
1671- else:
1672- return
1673-
1674- def b():
1675- c()
1676-
1677- def c():
1678- if self._ncall == 1:
1679- self._ncall += 1
1680- b()
1681- else:
1682- a()
1683-
1684- stats = utils.run_and_get_func_stats(a)
1685- fsa = utils.find_stat_by_name(stats, 'a')
1686- fsb = utils.find_stat_by_name(stats, 'b')
1687- fsc = utils.find_stat_by_name(stats, 'c')
1688- cfsab = fsa.children[fsb]
1689- cfsbc = fsb.children[fsc]
1690- cfsca = fsc.children[fsa]
1691- self.assertEqual(fsa.ttot, 10)
1692- self.assertEqual(fsa.tsub, 2)
1693- self.assertEqual(fsb.ttot, 9)
1694- self.assertEqual(fsb.tsub, 4)
1695- self.assertEqual(fsc.ttot, 7)
1696- self.assertEqual(fsc.tsub, 4)
1697- self.assertEqual(cfsab.ttot, 9)
1698- self.assertEqual(cfsab.tsub, 2)
1699- self.assertEqual(cfsbc.ttot, 7)
1700- self.assertEqual(cfsbc.tsub, 4)
1701- self.assertEqual(cfsca.ttot, 1)
1702- self.assertEqual(cfsca.tsub, 1)
1703- self.assertEqual(cfsca.ncall, 1)
1704- self.assertEqual(cfsca.nactualcall, 0)
1705-
1706- def test_aabccb(self):
1707- _timings = {
1708- "a_1": 13,
1709- "a_2": 11,
1710- "b_1": 9,
1711- "c_1": 5,
1712- "c_2": 3,
1713- "b_2": 1
1714- }
1715- _yappi._set_test_timings(_timings)
1716- self._ncall = 1
1717-
1718- def a():
1719- if self._ncall == 1:
1720- self._ncall += 1
1721- a()
1722- else:
1723- b()
1724-
1725- def b():
1726- if self._ncall == 3:
1727- return
1728- else:
1729- c()
1730-
1731- def c():
1732- if self._ncall == 2:
1733- self._ncall += 1
1734- c()
1735- else:
1736- b()
1737-
1738- stats = utils.run_and_get_func_stats(a)
1739- fsa = utils.find_stat_by_name(stats, 'a')
1740- fsb = utils.find_stat_by_name(stats, 'b')
1741- fsc = utils.find_stat_by_name(stats, 'c')
1742- cfsaa = fsa.children[fsa.index]
1743- cfsab = fsa.children[fsb]
1744- cfsbc = fsb.children[fsc.full_name]
1745- cfscc = fsc.children[fsc]
1746- cfscb = fsc.children[fsb]
1747- self.assertEqual(fsb.ttot, 9)
1748- self.assertEqual(fsb.tsub, 5)
1749- self.assertEqual(cfsbc.ttot, 5)
1750- self.assertEqual(cfsbc.tsub, 2)
1751- self.assertEqual(fsa.ttot, 13)
1752- self.assertEqual(fsa.tsub, 4)
1753- self.assertEqual(cfsab.ttot, 9)
1754- self.assertEqual(cfsab.tsub, 4)
1755- self.assertEqual(cfsaa.ttot, 11)
1756- self.assertEqual(cfsaa.tsub, 2)
1757- self.assertEqual(fsc.ttot, 5)
1758- self.assertEqual(fsc.tsub, 4)
1759-
1760- def test_abaa(self):
1761- _timings = {"a_1": 13, "b_1": 10, "a_2": 9, "a_3": 5}
1762- _yappi._set_test_timings(_timings)
1763-
1764- self._ncall = 1
1765-
1766- def a():
1767- if self._ncall == 1:
1768- b()
1769- elif self._ncall == 2:
1770- self._ncall += 1
1771- a()
1772- else:
1773- return
1774-
1775- def b():
1776- self._ncall += 1
1777- a()
1778-
1779- stats = utils.run_and_get_func_stats(a)
1780- fsa = utils.find_stat_by_name(stats, 'a')
1781- fsb = utils.find_stat_by_name(stats, 'b')
1782- cfsaa = fsa.children[fsa]
1783- cfsba = fsb.children[fsa]
1784- self.assertEqual(fsb.ttot, 10)
1785- self.assertEqual(fsb.tsub, 1)
1786- self.assertEqual(fsa.ttot, 13)
1787- self.assertEqual(fsa.tsub, 12)
1788- self.assertEqual(cfsaa.ttot, 5)
1789- self.assertEqual(cfsaa.tsub, 5)
1790- self.assertEqual(cfsba.ttot, 9)
1791- self.assertEqual(cfsba.tsub, 4)
1792-
1793- def test_aabb(self):
1794- _timings = {"a_1": 13, "a_2": 10, "b_1": 9, "b_2": 5}
1795- _yappi._set_test_timings(_timings)
1796-
1797- self._ncall = 1
1798-
1799- def a():
1800- if self._ncall == 1:
1801- self._ncall += 1
1802- a()
1803- elif self._ncall == 2:
1804- b()
1805- else:
1806- return
1807-
1808- def b():
1809- if self._ncall == 2:
1810- self._ncall += 1
1811- b()
1812- else:
1813- return
1814-
1815- stats = utils.run_and_get_func_stats(a)
1816- fsa = utils.find_stat_by_name(stats, 'a')
1817- fsb = utils.find_stat_by_name(stats, 'b')
1818- cfsaa = fsa.children[fsa]
1819- cfsab = fsa.children[fsb]
1820- cfsbb = fsb.children[fsb]
1821- self.assertEqual(fsa.ttot, 13)
1822- self.assertEqual(fsa.tsub, 4)
1823- self.assertEqual(fsb.ttot, 9)
1824- self.assertEqual(fsb.tsub, 9)
1825- self.assertEqual(cfsaa.ttot, 10)
1826- self.assertEqual(cfsaa.tsub, 1)
1827- self.assertEqual(cfsab.ttot, 9)
1828- self.assertEqual(cfsab.tsub, 4)
1829- self.assertEqual(cfsbb.ttot, 5)
1830- self.assertEqual(cfsbb.tsub, 5)
1831-
1832- def test_abbb(self):
1833- _timings = {"a_1": 13, "b_1": 10, "b_2": 6, "b_3": 1}
1834- _yappi._set_test_timings(_timings)
1835-
1836- self._ncall = 1
1837-
1838- def a():
1839- if self._ncall == 1:
1840- b()
1841-
1842- def b():
1843- if self._ncall == 3:
1844- return
1845- self._ncall += 1
1846- b()
1847-
1848- stats = utils.run_and_get_func_stats(a)
1849- fsa = utils.find_stat_by_name(stats, 'a')
1850- fsb = utils.find_stat_by_name(stats, 'b')
1851- cfsab = fsa.children[fsb]
1852- cfsbb = fsb.children[fsb]
1853- self.assertEqual(fsa.ttot, 13)
1854- self.assertEqual(fsa.tsub, 3)
1855- self.assertEqual(fsb.ttot, 10)
1856- self.assertEqual(fsb.tsub, 10)
1857- self.assertEqual(fsb.ncall, 3)
1858- self.assertEqual(fsb.nactualcall, 1)
1859- self.assertEqual(cfsab.ttot, 10)
1860- self.assertEqual(cfsab.tsub, 4)
1861- self.assertEqual(cfsbb.ttot, 6)
1862- self.assertEqual(cfsbb.tsub, 6)
1863- self.assertEqual(cfsbb.nactualcall, 0)
1864- self.assertEqual(cfsbb.ncall, 2)
1865-
1866- def test_aaab(self):
1867- _timings = {"a_1": 13, "a_2": 10, "a_3": 6, "b_1": 1}
1868- _yappi._set_test_timings(_timings)
1869-
1870- self._ncall = 1
1871-
1872- def a():
1873- if self._ncall == 3:
1874- b()
1875- return
1876- self._ncall += 1
1877- a()
1878-
1879- def b():
1880- return
1881-
1882- stats = utils.run_and_get_func_stats(a)
1883- fsa = utils.find_stat_by_name(stats, 'a')
1884- fsb = utils.find_stat_by_name(stats, 'b')
1885- cfsaa = fsa.children[fsa]
1886- cfsab = fsa.children[fsb]
1887- self.assertEqual(fsa.ttot, 13)
1888- self.assertEqual(fsa.tsub, 12)
1889- self.assertEqual(fsb.ttot, 1)
1890- self.assertEqual(fsb.tsub, 1)
1891- self.assertEqual(cfsaa.ttot, 10)
1892- self.assertEqual(cfsaa.tsub, 9)
1893- self.assertEqual(cfsab.ttot, 1)
1894- self.assertEqual(cfsab.tsub, 1)
1895-
1896- def test_abab(self):
1897- _timings = {"a_1": 13, "b_1": 10, "a_2": 6, "b_2": 1}
1898- _yappi._set_test_timings(_timings)
1899-
1900- self._ncall = 1
1901-
1902- def a():
1903- b()
1904-
1905- def b():
1906- if self._ncall == 2:
1907- return
1908- self._ncall += 1
1909- a()
1910-
1911- stats = utils.run_and_get_func_stats(a)
1912- fsa = utils.find_stat_by_name(stats, 'a')
1913- fsb = utils.find_stat_by_name(stats, 'b')
1914- cfsab = fsa.children[fsb]
1915- cfsba = fsb.children[fsa]
1916- self.assertEqual(fsa.ttot, 13)
1917- self.assertEqual(fsa.tsub, 8)
1918- self.assertEqual(fsb.ttot, 10)
1919- self.assertEqual(fsb.tsub, 5)
1920- self.assertEqual(cfsab.ttot, 10)
1921- self.assertEqual(cfsab.tsub, 5)
1922- self.assertEqual(cfsab.ncall, 2)
1923- self.assertEqual(cfsab.nactualcall, 1)
1924- self.assertEqual(cfsba.ttot, 6)
1925- self.assertEqual(cfsba.tsub, 5)
1926-
1927-
1928-if __name__ == '__main__':
1929- # import sys;sys.argv = ['', 'BasicUsage.test_run_as_script']
1930- # import sys;sys.argv = ['', 'MultithreadedScenarios.test_subsequent_profile']
1931- unittest.main()
1932+import os
1933+import sys
1934+import time
1935+import threading
1936+import unittest
1937+import yappi
1938+import _yappi
Patrick Williams169d7bc2024-01-05 11:33:25 -06001939+import utils
1940+import multiprocessing
Andrew Geissler69721092021-07-23 12:57:00 -04001941+import subprocess
1942+
1943+_counter = 0
1944+
1945+
1946+class BasicUsage(utils.YappiUnitTestCase):
1947+
1948+ def test_callback_function_int_return_overflow(self):
1949+ # this test is just here to check if any errors are generated, as the err
1950+ # is printed in C side, I did not include it here. THere are ways to test
1951+ # this deterministically, I did not bother
1952+ import ctypes
1953+
1954+ def _unsigned_overflow_margin():
1955+ return 2**(ctypes.sizeof(ctypes.c_void_p) * 8) - 1
1956+
1957+ def foo():
1958+ pass
1959+
1960+ #with utils.captured_output() as (out, err):
1961+ yappi.set_context_id_callback(_unsigned_overflow_margin)
1962+ yappi.set_tag_callback(_unsigned_overflow_margin)
1963+ yappi.start()
1964+ foo()
1965+
1966+ def test_issue60(self):
1967+
1968+ def foo():
1969+ buf = bytearray()
1970+ buf += b't' * 200
1971+ view = memoryview(buf)[10:]
1972+ view = view.tobytes()
1973+ del buf[:10] # this throws exception
1974+ return view
1975+
1976+ yappi.start(builtins=True)
1977+ foo()
1978+ self.assertTrue(
1979+ len(
1980+ yappi.get_func_stats(
1981+ filter_callback=lambda x: yappi.
1982+ func_matches(x, [memoryview.tobytes])
1983+ )
1984+ ) > 0
1985+ )
1986+ yappi.stop()
1987+
1988+ def test_issue54(self):
1989+
1990+ def _tag_cbk():
1991+ global _counter
1992+ _counter += 1
1993+ return _counter
1994+
1995+ def a():
1996+ pass
1997+
1998+ def b():
1999+ pass
2000+
2001+ yappi.set_tag_callback(_tag_cbk)
2002+ yappi.start()
2003+ a()
2004+ a()
2005+ a()
2006+ yappi.stop()
2007+ stats = yappi.get_func_stats()
2008+ self.assertEqual(stats.pop().ncall, 3) # aggregated if no tag is given
2009+ stats = yappi.get_func_stats(tag=1)
2010+
2011+ for i in range(1, 3):
2012+ stats = yappi.get_func_stats(tag=i)
2013+ stats = yappi.get_func_stats(
2014+ tag=i, filter_callback=lambda x: yappi.func_matches(x, [a])
2015+ )
2016+
2017+ stat = stats.pop()
2018+ self.assertEqual(stat.ncall, 1)
2019+
2020+ yappi.set_tag_callback(None)
2021+ yappi.clear_stats()
2022+ yappi.start()
2023+ b()
2024+ b()
2025+ stats = yappi.get_func_stats()
2026+ self.assertEqual(len(stats), 1)
2027+ stat = stats.pop()
2028+ self.assertEqual(stat.ncall, 2)
2029+
2030+ def test_filter(self):
2031+
2032+ def a():
2033+ pass
2034+
2035+ def b():
2036+ a()
2037+
2038+ def c():
2039+ b()
2040+
2041+ _TCOUNT = 5
2042+
2043+ ts = []
2044+ yappi.start()
2045+ for i in range(_TCOUNT):
2046+ t = threading.Thread(target=c)
2047+ t.start()
2048+ ts.append(t)
2049+
2050+ for t in ts:
2051+ t.join()
2052+
2053+ yappi.stop()
2054+
2055+ ctx_ids = []
2056+ for tstat in yappi.get_thread_stats():
2057+ if tstat.name == '_MainThread':
2058+ main_ctx_id = tstat.id
2059+ else:
2060+ ctx_ids.append(tstat.id)
2061+
2062+ fstats = yappi.get_func_stats(filter={"ctx_id": 9})
2063+ self.assertTrue(fstats.empty())
2064+ fstats = yappi.get_func_stats(
2065+ filter={
2066+ "ctx_id": main_ctx_id,
2067+ "name": "c"
2068+ }
2069+ ) # main thread
2070+ self.assertTrue(fstats.empty())
2071+
2072+ for i in ctx_ids:
2073+ fstats = yappi.get_func_stats(
2074+ filter={
2075+ "ctx_id": i,
2076+ "name": "a",
2077+ "ncall": 1
2078+ }
2079+ )
2080+ self.assertEqual(fstats.pop().ncall, 1)
2081+ fstats = yappi.get_func_stats(filter={"ctx_id": i, "name": "b"})
2082+ self.assertEqual(fstats.pop().ncall, 1)
2083+ fstats = yappi.get_func_stats(filter={"ctx_id": i, "name": "c"})
2084+ self.assertEqual(fstats.pop().ncall, 1)
2085+
2086+ yappi.clear_stats()
2087+ yappi.start(builtins=True)
2088+ time.sleep(0.1)
2089+ yappi.stop()
2090+ fstats = yappi.get_func_stats(filter={"module": "time"})
2091+ self.assertEqual(len(fstats), 1)
2092+
2093+ # invalid filters`
2094+ self.assertRaises(
2095+ Exception, yappi.get_func_stats, filter={'tag': "sss"}
2096+ )
2097+ self.assertRaises(
2098+ Exception, yappi.get_func_stats, filter={'ctx_id': "None"}
2099+ )
2100+
2101+ def test_filter_callback(self):
2102+
2103+ def a():
2104+ time.sleep(0.1)
2105+
2106+ def b():
2107+ a()
2108+
2109+ def c():
2110+ pass
2111+
2112+ def d():
2113+ pass
2114+
2115+ yappi.set_clock_type("wall")
2116+ yappi.start(builtins=True)
2117+ a()
2118+ b()
2119+ c()
2120+ d()
2121+ stats = yappi.get_func_stats(
2122+ filter_callback=lambda x: yappi.func_matches(x, [a, b])
2123+ )
2124+ #stats.print_all()
2125+ r1 = '''
2126+ tests/test_functionality.py:98 a 2 0.000000 0.200350 0.100175
2127+ tests/test_functionality.py:101 b 1 0.000000 0.120000 0.100197
2128+ '''
2129+ self.assert_traces_almost_equal(r1, stats)
2130+ self.assertEqual(len(stats), 2)
2131+ stats = yappi.get_func_stats(
2132+ filter_callback=lambda x: yappi.
2133+ module_matches(x, [sys.modules[__name__]])
2134+ )
2135+ r1 = '''
2136+ tests/test_functionality.py:98 a 2 0.000000 0.230130 0.115065
2137+ tests/test_functionality.py:101 b 1 0.000000 0.120000 0.109011
2138+ tests/test_functionality.py:104 c 1 0.000000 0.000002 0.000002
2139+ tests/test_functionality.py:107 d 1 0.000000 0.000001 0.000001
2140+ '''
2141+ self.assert_traces_almost_equal(r1, stats)
2142+ self.assertEqual(len(stats), 4)
2143+
2144+ stats = yappi.get_func_stats(
2145+ filter_callback=lambda x: yappi.func_matches(x, [time.sleep])
2146+ )
2147+ self.assertEqual(len(stats), 1)
2148+ r1 = '''
2149+ time.sleep 2 0.206804 0.220000 0.103402
2150+ '''
2151+ self.assert_traces_almost_equal(r1, stats)
2152+
2153+ def test_print_formatting(self):
2154+
2155+ def a():
2156+ pass
2157+
2158+ def b():
2159+ a()
2160+
2161+ func_cols = {
2162+ 1: ("name", 48),
2163+ 0: ("ncall", 5),
2164+ 2: ("tsub", 8),
2165+ }
2166+ thread_cols = {
2167+ 1: ("name", 48),
2168+ 0: ("ttot", 8),
2169+ }
2170+
2171+ yappi.start()
2172+ a()
2173+ b()
2174+ yappi.stop()
2175+ fs = yappi.get_func_stats()
2176+ cs = fs[1].children
2177+ ts = yappi.get_thread_stats()
2178+ #fs.print_all(out=sys.stderr, columns={1:("name", 70), })
2179+ #cs.print_all(out=sys.stderr, columns=func_cols)
2180+ #ts.print_all(out=sys.stderr, columns=thread_cols)
2181+ #cs.print_all(out=sys.stderr, columns={})
2182+
2183+ self.assertRaises(
2184+ yappi.YappiError, fs.print_all, columns={1: ("namee", 9)}
2185+ )
2186+ self.assertRaises(
2187+ yappi.YappiError, cs.print_all, columns={1: ("dd", 0)}
2188+ )
2189+ self.assertRaises(
2190+ yappi.YappiError, ts.print_all, columns={1: ("tidd", 0)}
2191+ )
2192+
2193+ def test_get_clock(self):
2194+ yappi.set_clock_type('cpu')
2195+ self.assertEqual('cpu', yappi.get_clock_type())
2196+ clock_info = yappi.get_clock_info()
2197+ self.assertTrue('api' in clock_info)
2198+ self.assertTrue('resolution' in clock_info)
2199+
2200+ yappi.set_clock_type('wall')
2201+ self.assertEqual('wall', yappi.get_clock_type())
2202+
2203+ t0 = yappi.get_clock_time()
2204+ time.sleep(0.1)
2205+ duration = yappi.get_clock_time() - t0
2206+ self.assertTrue(0.05 < duration < 0.3)
2207+
2208+ def test_profile_decorator(self):
2209+
2210+ def aggregate(func, stats):
Patrick Williams169d7bc2024-01-05 11:33:25 -06002211+ fname = f"tests/{func.__name__}.profile"
Andrew Geissler69721092021-07-23 12:57:00 -04002212+ try:
2213+ stats.add(fname)
Patrick Williams169d7bc2024-01-05 11:33:25 -06002214+ except OSError:
Andrew Geissler69721092021-07-23 12:57:00 -04002215+ pass
2216+ stats.save(fname)
2217+ raise Exception("messing around")
2218+
2219+ @yappi.profile(return_callback=aggregate)
2220+ def a(x, y):
2221+ if x + y == 25:
2222+ raise Exception("")
2223+ return x + y
2224+
2225+ def b():
2226+ pass
2227+
2228+ try:
2229+ os.remove(
2230+ "tests/a.profile"
2231+ ) # remove the one from prev test, if available
2232+ except:
2233+ pass
2234+
2235+ # global profile is on to mess things up
2236+ yappi.start()
2237+ b()
2238+
2239+ # assert functionality and call function at same time
2240+ try:
2241+ self.assertEqual(a(1, 2), 3)
2242+ except:
2243+ pass
2244+ try:
2245+ self.assertEqual(a(2, 5), 7)
2246+ except:
2247+ pass
2248+ try:
2249+ a(4, 21)
2250+ except:
2251+ pass
2252+ stats = yappi.get_func_stats().add("tests/a.profile")
2253+ fsa = utils.find_stat_by_name(stats, 'a')
2254+ self.assertEqual(fsa.ncall, 3)
2255+ self.assertEqual(len(stats), 1) # b() should be cleared out.
2256+
2257+ @yappi.profile(return_callback=aggregate)
2258+ def count_down_rec(n):
2259+ if n == 0:
2260+ return
2261+ count_down_rec(n - 1)
2262+
2263+ try:
2264+ os.remove(
2265+ "tests/count_down_rec.profile"
2266+ ) # remove the one from prev test, if available
2267+ except:
2268+ pass
2269+
2270+ try:
2271+ count_down_rec(4)
2272+ except:
2273+ pass
2274+ try:
2275+ count_down_rec(3)
2276+ except:
2277+ pass
2278+
2279+ stats = yappi.YFuncStats("tests/count_down_rec.profile")
2280+ fsrec = utils.find_stat_by_name(stats, 'count_down_rec')
2281+ self.assertEqual(fsrec.ncall, 9)
2282+ self.assertEqual(fsrec.nactualcall, 2)
2283+
2284+ def test_strip_dirs(self):
2285+
2286+ def a():
2287+ pass
2288+
2289+ stats = utils.run_and_get_func_stats(a, )
2290+ stats.strip_dirs()
2291+ fsa = utils.find_stat_by_name(stats, "a")
2292+ self.assertEqual(fsa.module, os.path.basename(fsa.module))
2293+
2294+ @unittest.skipIf(os.name == "nt", "do not run on Windows")
2295+ def test_run_as_script(self):
2296+ import re
2297+ p = subprocess.Popen(
2298+ ['yappi', os.path.join('./tests', 'run_as_script.py')],
2299+ stdout=subprocess.PIPE
2300+ )
2301+ out, err = p.communicate()
2302+ self.assertEqual(p.returncode, 0)
2303+ func_stats, thread_stats = re.split(
2304+ b'name\\s+id\\s+tid\\s+ttot\\s+scnt\\s*\n', out
2305+ )
2306+ self.assertTrue(b'FancyThread' in thread_stats)
2307+
2308+ def test_yappi_overhead(self):
2309+ LOOP_COUNT = 100000
2310+
2311+ def a():
2312+ pass
2313+
2314+ def b():
2315+ for i in range(LOOP_COUNT):
2316+ a()
2317+
2318+ t0 = time.time()
2319+ yappi.start()
2320+ b()
2321+ yappi.stop()
2322+ time_with_yappi = time.time() - t0
2323+ t0 = time.time()
2324+ b()
2325+ time_without_yappi = time.time() - t0
2326+ if time_without_yappi == 0:
2327+ time_without_yappi = 0.000001
2328+
2329+ # in latest v0.82, I calculated this as close to "7.0" in my machine.
2330+ # however, %83 of this overhead is coming from tickcount(). The other %17
2331+ # seems to have been evenly distributed to the internal bookkeeping
2332+ # structures/algorithms which seems acceptable. Note that our test only
2333+ # tests one function being profiled at-a-time in a short interval.
2334+ # profiling high number of functions in a small time
2335+ # is a different beast, (which is pretty unlikely in most applications)
2336+ # So as a conclusion: I cannot see any optimization window for Yappi that
2337+ # is worth implementing as we will only optimize %17 of the time.
2338+ sys.stderr.write("\r\nYappi puts %0.1f times overhead to the profiled application in average.\r\n" % \
2339+ (time_with_yappi / time_without_yappi))
2340+
2341+ def test_clear_stats_while_running(self):
2342+
2343+ def a():
2344+ pass
2345+
2346+ yappi.start()
2347+ a()
2348+ yappi.clear_stats()
2349+ a()
2350+ stats = yappi.get_func_stats()
2351+ fsa = utils.find_stat_by_name(stats, 'a')
2352+ self.assertEqual(fsa.ncall, 1)
2353+
2354+ def test_generator(self):
2355+
2356+ def _gen(n):
2357+ while (n > 0):
2358+ yield n
2359+ n -= 1
2360+
2361+ yappi.start()
2362+ for x in _gen(5):
2363+ pass
2364+ self.assertTrue(
2365+ yappi.convert2pstats(yappi.get_func_stats()) is not None
2366+ )
2367+
2368+ def test_slice_child_stats_and_strip_dirs(self):
2369+
2370+ def b():
2371+ for i in range(10000000):
2372+ pass
2373+
2374+ def a():
2375+ b()
2376+
2377+ yappi.start(builtins=True)
2378+ a()
2379+ stats = yappi.get_func_stats()
2380+ fsa = utils.find_stat_by_name(stats, 'a')
2381+ fsb = utils.find_stat_by_name(stats, 'b')
2382+ self.assertTrue(fsa.children[0:1] is not None)
2383+ prev_afullname = fsa.full_name
2384+ prev_bchildfullname = fsa.children[fsb].full_name
2385+ stats.strip_dirs()
2386+ self.assertTrue(len(prev_afullname) > len(fsa.full_name))
2387+ self.assertTrue(
2388+ len(prev_bchildfullname) > len(fsa.children[fsb].full_name)
2389+ )
2390+
2391+ def test_children_stat_functions(self):
2392+ _timings = {"a_1": 5, "b_1": 3, "c_1": 1}
2393+ _yappi._set_test_timings(_timings)
2394+
2395+ def b():
2396+ pass
2397+
2398+ def c():
2399+ pass
2400+
2401+ def a():
2402+ b()
2403+ c()
2404+
2405+ yappi.start()
2406+ a()
2407+ b() # non-child call
2408+ c() # non-child call
2409+ stats = yappi.get_func_stats()
2410+ fsa = utils.find_stat_by_name(stats, 'a')
2411+ childs_of_a = fsa.children.get().sort("tavg", "desc")
2412+ prev_item = None
2413+ for item in childs_of_a:
2414+ if prev_item:
2415+ self.assertTrue(prev_item.tavg > item.tavg)
2416+ prev_item = item
2417+ childs_of_a.sort("name", "desc")
2418+ prev_item = None
2419+ for item in childs_of_a:
2420+ if prev_item:
2421+ self.assertTrue(prev_item.name > item.name)
2422+ prev_item = item
2423+ childs_of_a.clear()
2424+ self.assertTrue(childs_of_a.empty())
2425+
2426+ def test_no_stats_different_clock_type_load(self):
2427+
2428+ def a():
2429+ pass
2430+
2431+ yappi.start()
2432+ a()
2433+ yappi.stop()
2434+ yappi.get_func_stats().save("tests/ystats1.ys")
2435+ yappi.clear_stats()
2436+ yappi.set_clock_type("WALL")
2437+ yappi.start()
2438+ yappi.stop()
2439+ stats = yappi.get_func_stats().add("tests/ystats1.ys")
2440+ fsa = utils.find_stat_by_name(stats, 'a')
2441+ self.assertTrue(fsa is not None)
2442+
2443+ def test_subsequent_profile(self):
2444+ _timings = {"a_1": 1, "b_1": 1}
2445+ _yappi._set_test_timings(_timings)
2446+
2447+ def a():
2448+ pass
2449+
2450+ def b():
2451+ pass
2452+
2453+ yappi.start()
2454+ a()
2455+ yappi.stop()
2456+ yappi.start()
2457+ b()
2458+ yappi.stop()
2459+ stats = yappi.get_func_stats()
2460+ fsa = utils.find_stat_by_name(stats, 'a')
2461+ fsb = utils.find_stat_by_name(stats, 'b')
2462+ self.assertTrue(fsa is not None)
2463+ self.assertTrue(fsb is not None)
2464+ self.assertEqual(fsa.ttot, 1)
2465+ self.assertEqual(fsb.ttot, 1)
2466+
2467+ def test_lambda(self):
2468+ f = lambda: time.sleep(0.3)
2469+ yappi.set_clock_type("wall")
2470+ yappi.start()
2471+ f()
2472+ stats = yappi.get_func_stats()
2473+ fsa = utils.find_stat_by_name(stats, '<lambda>')
2474+ self.assertTrue(fsa.ttot > 0.1)
2475+
2476+ def test_module_stress(self):
2477+ self.assertEqual(yappi.is_running(), False)
2478+
2479+ yappi.start()
2480+ yappi.clear_stats()
2481+ self.assertRaises(_yappi.error, yappi.set_clock_type, "wall")
2482+
2483+ yappi.stop()
2484+ yappi.clear_stats()
2485+ yappi.set_clock_type("cpu")
2486+ self.assertRaises(yappi.YappiError, yappi.set_clock_type, "dummy")
2487+ self.assertEqual(yappi.is_running(), False)
2488+ yappi.clear_stats()
2489+ yappi.clear_stats()
2490+
2491+ def test_stat_sorting(self):
2492+ _timings = {"a_1": 13, "b_1": 10, "a_2": 6, "b_2": 1}
2493+ _yappi._set_test_timings(_timings)
2494+
2495+ self._ncall = 1
2496+
2497+ def a():
2498+ b()
2499+
2500+ def b():
2501+ if self._ncall == 2:
2502+ return
2503+ self._ncall += 1
2504+ a()
2505+
2506+ stats = utils.run_and_get_func_stats(a)
2507+ stats = stats.sort("totaltime", "desc")
2508+ prev_stat = None
2509+ for stat in stats:
2510+ if prev_stat:
2511+ self.assertTrue(prev_stat.ttot >= stat.ttot)
2512+ prev_stat = stat
2513+ stats = stats.sort("totaltime", "asc")
2514+ prev_stat = None
2515+ for stat in stats:
2516+ if prev_stat:
2517+ self.assertTrue(prev_stat.ttot <= stat.ttot)
2518+ prev_stat = stat
2519+ stats = stats.sort("avgtime", "asc")
2520+ prev_stat = None
2521+ for stat in stats:
2522+ if prev_stat:
2523+ self.assertTrue(prev_stat.tavg <= stat.tavg)
2524+ prev_stat = stat
2525+ stats = stats.sort("name", "asc")
2526+ prev_stat = None
2527+ for stat in stats:
2528+ if prev_stat:
2529+ self.assertTrue(prev_stat.name <= stat.name)
2530+ prev_stat = stat
2531+ stats = stats.sort("subtime", "asc")
2532+ prev_stat = None
2533+ for stat in stats:
2534+ if prev_stat:
2535+ self.assertTrue(prev_stat.tsub <= stat.tsub)
2536+ prev_stat = stat
2537+
2538+ self.assertRaises(
2539+ yappi.YappiError, stats.sort, "invalid_func_sorttype_arg"
2540+ )
2541+ self.assertRaises(
2542+ yappi.YappiError, stats.sort, "totaltime",
2543+ "invalid_func_sortorder_arg"
2544+ )
2545+
2546+ def test_start_flags(self):
2547+ self.assertEqual(_yappi._get_start_flags(), None)
2548+ yappi.start()
2549+
2550+ def a():
2551+ pass
2552+
2553+ a()
2554+ self.assertEqual(_yappi._get_start_flags()["profile_builtins"], 0)
2555+ self.assertEqual(_yappi._get_start_flags()["profile_multicontext"], 1)
2556+ self.assertEqual(len(yappi.get_thread_stats()), 1)
2557+
2558+ def test_builtin_profiling(self):
2559+
2560+ def a():
2561+ time.sleep(0.4) # is a builtin function
2562+
2563+ yappi.set_clock_type('wall')
2564+
2565+ yappi.start(builtins=True)
2566+ a()
2567+ stats = yappi.get_func_stats()
2568+ fsa = utils.find_stat_by_name(stats, 'sleep')
2569+ self.assertTrue(fsa is not None)
2570+ self.assertTrue(fsa.ttot > 0.3)
2571+ yappi.stop()
2572+ yappi.clear_stats()
2573+
2574+ def a():
2575+ pass
2576+
2577+ yappi.start()
2578+ t = threading.Thread(target=a)
2579+ t.start()
2580+ t.join()
2581+ stats = yappi.get_func_stats()
2582+
2583+ def test_singlethread_profiling(self):
2584+ yappi.set_clock_type('wall')
2585+
2586+ def a():
2587+ time.sleep(0.2)
2588+
2589+ class Worker1(threading.Thread):
2590+
2591+ def a(self):
2592+ time.sleep(0.3)
2593+
2594+ def run(self):
2595+ self.a()
2596+
2597+ yappi.start(profile_threads=False)
2598+
2599+ c = Worker1()
2600+ c.start()
2601+ c.join()
2602+ a()
2603+ stats = yappi.get_func_stats()
2604+ fsa1 = utils.find_stat_by_name(stats, 'Worker1.a')
2605+ fsa2 = utils.find_stat_by_name(stats, 'a')
2606+ self.assertTrue(fsa1 is None)
2607+ self.assertTrue(fsa2 is not None)
2608+ self.assertTrue(fsa2.ttot > 0.1)
2609+
2610+ def test_run(self):
2611+
2612+ def profiled():
2613+ pass
2614+
2615+ yappi.clear_stats()
2616+ try:
2617+ with yappi.run():
2618+ profiled()
2619+ stats = yappi.get_func_stats()
2620+ finally:
2621+ yappi.clear_stats()
2622+
2623+ self.assertIsNotNone(utils.find_stat_by_name(stats, 'profiled'))
2624+
2625+ def test_run_recursive(self):
2626+
2627+ def profiled():
2628+ pass
2629+
2630+ def not_profiled():
2631+ pass
2632+
2633+ yappi.clear_stats()
2634+ try:
2635+ with yappi.run():
2636+ with yappi.run():
2637+ profiled()
2638+ # Profiling stopped here
2639+ not_profiled()
2640+ stats = yappi.get_func_stats()
2641+ finally:
2642+ yappi.clear_stats()
2643+
2644+ self.assertIsNotNone(utils.find_stat_by_name(stats, 'profiled'))
2645+ self.assertIsNone(utils.find_stat_by_name(stats, 'not_profiled'))
2646+
2647+
2648+class StatSaveScenarios(utils.YappiUnitTestCase):
2649+
2650+ def test_pstats_conversion(self):
2651+
2652+ def pstat_id(fs):
2653+ return (fs.module, fs.lineno, fs.name)
2654+
2655+ def a():
2656+ d()
2657+
2658+ def b():
2659+ d()
2660+
2661+ def c():
2662+ pass
2663+
2664+ def d():
2665+ pass
2666+
2667+ _timings = {"a_1": 12, "b_1": 7, "c_1": 5, "d_1": 2}
2668+ _yappi._set_test_timings(_timings)
2669+ stats = utils.run_and_get_func_stats(a, )
2670+ stats.strip_dirs()
2671+ stats.save("tests/a1.pstats", type="pstat")
2672+ fsa_pid = pstat_id(utils.find_stat_by_name(stats, "a"))
2673+ fsd_pid = pstat_id(utils.find_stat_by_name(stats, "d"))
2674+ yappi.clear_stats()
2675+ _yappi._set_test_timings(_timings)
2676+ stats = utils.run_and_get_func_stats(a, )
2677+ stats.strip_dirs()
2678+ stats.save("tests/a2.pstats", type="pstat")
2679+ yappi.clear_stats()
2680+ _yappi._set_test_timings(_timings)
2681+ stats = utils.run_and_get_func_stats(b, )
2682+ stats.strip_dirs()
2683+ stats.save("tests/b1.pstats", type="pstat")
2684+ fsb_pid = pstat_id(utils.find_stat_by_name(stats, "b"))
2685+ yappi.clear_stats()
2686+ _yappi._set_test_timings(_timings)
2687+ stats = utils.run_and_get_func_stats(c, )
2688+ stats.strip_dirs()
2689+ stats.save("tests/c1.pstats", type="pstat")
2690+ fsc_pid = pstat_id(utils.find_stat_by_name(stats, "c"))
2691+
2692+ # merge saved stats and check pstats values are correct
2693+ import pstats
2694+ p = pstats.Stats(
2695+ 'tests/a1.pstats', 'tests/a2.pstats', 'tests/b1.pstats',
2696+ 'tests/c1.pstats'
2697+ )
2698+ p.strip_dirs()
2699+ # ct = ttot, tt = tsub
2700+ (cc, nc, tt, ct, callers) = p.stats[fsa_pid]
2701+ self.assertEqual(cc, nc, 2)
2702+ self.assertEqual(tt, 20)
2703+ self.assertEqual(ct, 24)
2704+ (cc, nc, tt, ct, callers) = p.stats[fsd_pid]
2705+ self.assertEqual(cc, nc, 3)
2706+ self.assertEqual(tt, 6)
2707+ self.assertEqual(ct, 6)
2708+ self.assertEqual(len(callers), 2)
2709+ (cc, nc, tt, ct) = callers[fsa_pid]
2710+ self.assertEqual(cc, nc, 2)
2711+ self.assertEqual(tt, 4)
2712+ self.assertEqual(ct, 4)
2713+ (cc, nc, tt, ct) = callers[fsb_pid]
2714+ self.assertEqual(cc, nc, 1)
2715+ self.assertEqual(tt, 2)
2716+ self.assertEqual(ct, 2)
2717+
2718+ def test_merge_stats(self):
2719+ _timings = {
2720+ "a_1": 15,
2721+ "b_1": 14,
2722+ "c_1": 12,
2723+ "d_1": 10,
2724+ "e_1": 9,
2725+ "f_1": 7,
2726+ "g_1": 6,
2727+ "h_1": 5,
2728+ "i_1": 1
2729+ }
2730+ _yappi._set_test_timings(_timings)
2731+
2732+ def a():
2733+ b()
2734+
2735+ def b():
2736+ c()
2737+
2738+ def c():
2739+ d()
2740+
2741+ def d():
2742+ e()
2743+
2744+ def e():
2745+ f()
2746+
2747+ def f():
2748+ g()
2749+
2750+ def g():
2751+ h()
2752+
2753+ def h():
2754+ i()
2755+
2756+ def i():
2757+ pass
2758+
2759+ yappi.start()
2760+ a()
2761+ a()
2762+ yappi.stop()
2763+ stats = yappi.get_func_stats()
2764+ self.assertRaises(
2765+ NotImplementedError, stats.save, "", "INVALID_SAVE_TYPE"
2766+ )
2767+ stats.save("tests/ystats2.ys")
2768+ yappi.clear_stats()
2769+ _yappi._set_test_timings(_timings)
2770+ yappi.start()
2771+ a()
2772+ stats = yappi.get_func_stats().add("tests/ystats2.ys")
2773+ fsa = utils.find_stat_by_name(stats, "a")
2774+ fsb = utils.find_stat_by_name(stats, "b")
2775+ fsc = utils.find_stat_by_name(stats, "c")
2776+ fsd = utils.find_stat_by_name(stats, "d")
2777+ fse = utils.find_stat_by_name(stats, "e")
2778+ fsf = utils.find_stat_by_name(stats, "f")
2779+ fsg = utils.find_stat_by_name(stats, "g")
2780+ fsh = utils.find_stat_by_name(stats, "h")
2781+ fsi = utils.find_stat_by_name(stats, "i")
2782+ self.assertEqual(fsa.ttot, 45)
2783+ self.assertEqual(fsa.ncall, 3)
2784+ self.assertEqual(fsa.nactualcall, 3)
2785+ self.assertEqual(fsa.tsub, 3)
2786+ self.assertEqual(fsa.children[fsb].ttot, fsb.ttot)
2787+ self.assertEqual(fsa.children[fsb].tsub, fsb.tsub)
2788+ self.assertEqual(fsb.children[fsc].ttot, fsc.ttot)
2789+ self.assertEqual(fsb.children[fsc].tsub, fsc.tsub)
2790+ self.assertEqual(fsc.tsub, 6)
2791+ self.assertEqual(fsc.children[fsd].ttot, fsd.ttot)
2792+ self.assertEqual(fsc.children[fsd].tsub, fsd.tsub)
2793+ self.assertEqual(fsd.children[fse].ttot, fse.ttot)
2794+ self.assertEqual(fsd.children[fse].tsub, fse.tsub)
2795+ self.assertEqual(fse.children[fsf].ttot, fsf.ttot)
2796+ self.assertEqual(fse.children[fsf].tsub, fsf.tsub)
2797+ self.assertEqual(fsf.children[fsg].ttot, fsg.ttot)
2798+ self.assertEqual(fsf.children[fsg].tsub, fsg.tsub)
2799+ self.assertEqual(fsg.ttot, 18)
2800+ self.assertEqual(fsg.tsub, 3)
2801+ self.assertEqual(fsg.children[fsh].ttot, fsh.ttot)
2802+ self.assertEqual(fsg.children[fsh].tsub, fsh.tsub)
2803+ self.assertEqual(fsh.ttot, 15)
2804+ self.assertEqual(fsh.tsub, 12)
2805+ self.assertEqual(fsh.tavg, 5)
2806+ self.assertEqual(fsh.children[fsi].ttot, fsi.ttot)
2807+ self.assertEqual(fsh.children[fsi].tsub, fsi.tsub)
2808+ #stats.debug_print()
2809+
2810+ def test_merge_multithreaded_stats(self):
2811+ import _yappi
2812+ timings = {"a_1": 2, "b_1": 1}
2813+ _yappi._set_test_timings(timings)
2814+
2815+ def a():
2816+ pass
2817+
2818+ def b():
2819+ pass
2820+
2821+ yappi.start()
2822+ t = threading.Thread(target=a)
2823+ t.start()
2824+ t.join()
2825+ t = threading.Thread(target=b)
2826+ t.start()
2827+ t.join()
2828+ yappi.get_func_stats().save("tests/ystats1.ys")
2829+ yappi.clear_stats()
2830+ _yappi._set_test_timings(timings)
2831+ self.assertEqual(len(yappi.get_func_stats()), 0)
2832+ self.assertEqual(len(yappi.get_thread_stats()), 1)
2833+ t = threading.Thread(target=a)
2834+ t.start()
2835+ t.join()
2836+
2837+ self.assertEqual(_yappi._get_start_flags()["profile_builtins"], 0)
2838+ self.assertEqual(_yappi._get_start_flags()["profile_multicontext"], 1)
2839+ yappi.get_func_stats().save("tests/ystats2.ys")
2840+
2841+ stats = yappi.YFuncStats([
2842+ "tests/ystats1.ys",
2843+ "tests/ystats2.ys",
2844+ ])
2845+ fsa = utils.find_stat_by_name(stats, "a")
2846+ fsb = utils.find_stat_by_name(stats, "b")
2847+ self.assertEqual(fsa.ncall, 2)
2848+ self.assertEqual(fsb.ncall, 1)
2849+ self.assertEqual(fsa.tsub, fsa.ttot, 4)
2850+ self.assertEqual(fsb.tsub, fsb.ttot, 1)
2851+
2852+ def test_merge_load_different_clock_types(self):
2853+ yappi.start(builtins=True)
2854+
2855+ def a():
2856+ b()
2857+
2858+ def b():
2859+ c()
2860+
2861+ def c():
2862+ pass
2863+
2864+ t = threading.Thread(target=a)
2865+ t.start()
2866+ t.join()
2867+ yappi.get_func_stats().sort("name", "asc").save("tests/ystats1.ys")
2868+ yappi.stop()
2869+ yappi.clear_stats()
2870+ yappi.start(builtins=False)
2871+ t = threading.Thread(target=a)
2872+ t.start()
2873+ t.join()
2874+ yappi.get_func_stats().save("tests/ystats2.ys")
2875+ yappi.stop()
2876+ self.assertRaises(_yappi.error, yappi.set_clock_type, "wall")
2877+ yappi.clear_stats()
2878+ yappi.set_clock_type("wall")
2879+ yappi.start()
2880+ t = threading.Thread(target=a)
2881+ t.start()
2882+ t.join()
2883+ yappi.get_func_stats().save("tests/ystats3.ys")
2884+ self.assertRaises(
2885+ yappi.YappiError,
2886+ yappi.YFuncStats().add("tests/ystats1.ys").add, "tests/ystats3.ys"
2887+ )
2888+ stats = yappi.YFuncStats(["tests/ystats1.ys",
2889+ "tests/ystats2.ys"]).sort("name")
2890+ fsa = utils.find_stat_by_name(stats, "a")
2891+ fsb = utils.find_stat_by_name(stats, "b")
2892+ fsc = utils.find_stat_by_name(stats, "c")
2893+ self.assertEqual(fsa.ncall, 2)
2894+ self.assertEqual(fsa.ncall, fsb.ncall, fsc.ncall)
2895+
2896+ def test_merge_aabab_aabbc(self):
2897+ _timings = {
2898+ "a_1": 15,
2899+ "a_2": 14,
2900+ "b_1": 12,
2901+ "a_3": 10,
2902+ "b_2": 9,
2903+ "c_1": 4
2904+ }
2905+ _yappi._set_test_timings(_timings)
2906+
2907+ def a():
2908+ if self._ncall == 1:
2909+ self._ncall += 1
2910+ a()
2911+ elif self._ncall == 5:
2912+ self._ncall += 1
2913+ a()
2914+ else:
2915+ b()
2916+
2917+ def b():
2918+ if self._ncall == 2:
2919+ self._ncall += 1
2920+ a()
2921+ elif self._ncall == 6:
2922+ self._ncall += 1
2923+ b()
2924+ elif self._ncall == 7:
2925+ c()
2926+ else:
2927+ return
2928+
2929+ def c():
2930+ pass
2931+
2932+ self._ncall = 1
2933+ stats = utils.run_and_get_func_stats(a, )
2934+ stats.save("tests/ystats1.ys")
2935+ yappi.clear_stats()
2936+ _yappi._set_test_timings(_timings)
2937+ #stats.print_all()
2938+
2939+ self._ncall = 5
2940+ stats = utils.run_and_get_func_stats(a, )
2941+ stats.save("tests/ystats2.ys")
2942+
2943+ #stats.print_all()
2944+
2945+ def a(): # same name but another function(code object)
2946+ pass
2947+
2948+ yappi.start()
2949+ a()
2950+ stats = yappi.get_func_stats().add(
2951+ ["tests/ystats1.ys", "tests/ystats2.ys"]
2952+ )
2953+ #stats.print_all()
2954+ self.assertEqual(len(stats), 4)
2955+
2956+ fsa = None
2957+ for stat in stats:
2958+ if stat.name == "a" and stat.ttot == 45:
2959+ fsa = stat
2960+ break
2961+ self.assertTrue(fsa is not None)
2962+
2963+ self.assertEqual(fsa.ncall, 7)
2964+ self.assertEqual(fsa.nactualcall, 3)
2965+ self.assertEqual(fsa.ttot, 45)
2966+ self.assertEqual(fsa.tsub, 10)
2967+ fsb = utils.find_stat_by_name(stats, "b")
2968+ fsc = utils.find_stat_by_name(stats, "c")
2969+ self.assertEqual(fsb.ncall, 6)
2970+ self.assertEqual(fsb.nactualcall, 3)
2971+ self.assertEqual(fsb.ttot, 36)
2972+ self.assertEqual(fsb.tsub, 27)
2973+ self.assertEqual(fsb.tavg, 6)
2974+ self.assertEqual(fsc.ttot, 8)
2975+ self.assertEqual(fsc.tsub, 8)
2976+ self.assertEqual(fsc.tavg, 4)
2977+ self.assertEqual(fsc.nactualcall, fsc.ncall, 2)
2978+
2979+
2980+class MultithreadedScenarios(utils.YappiUnitTestCase):
2981+
2982+ def test_issue_32(self):
2983+ '''
Patrick Williams169d7bc2024-01-05 11:33:25 -06002984+ Start yappi from different thread and we get Internal Error(15) as
2985+ the current_ctx_id() called while enumerating the threads in start()
Andrew Geissler69721092021-07-23 12:57:00 -04002986+ and as it does not swap to the enumerated ThreadState* the THreadState_GetDict()
2987+ returns wrong object and thus sets an invalid id for the _ctx structure.
2988+
2989+ When this issue happens multiple Threads have same tid as the internal ts_ptr
2990+ will be same for different contexts. So, let's see if that happens
2991+ '''
2992+
2993+ def foo():
2994+ time.sleep(0.2)
2995+
2996+ def bar():
2997+ time.sleep(0.1)
2998+
2999+ def thread_func():
3000+ yappi.set_clock_type("wall")
3001+ yappi.start()
3002+
3003+ bar()
3004+
3005+ t = threading.Thread(target=thread_func)
3006+ t.start()
3007+ t.join()
3008+
3009+ foo()
3010+
3011+ yappi.stop()
3012+
3013+ thread_ids = set()
3014+ for tstat in yappi.get_thread_stats():
3015+ self.assertTrue(tstat.tid not in thread_ids)
3016+ thread_ids.add(tstat.tid)
3017+
3018+ def test_subsequent_profile(self):
3019+ WORKER_COUNT = 5
3020+
3021+ def a():
3022+ pass
3023+
3024+ def b():
3025+ pass
3026+
3027+ def c():
3028+ pass
3029+
3030+ _timings = {
3031+ "a_1": 3,
3032+ "b_1": 2,
3033+ "c_1": 1,
3034+ }
3035+
3036+ yappi.start()
3037+
3038+ def g():
3039+ pass
3040+
3041+ g()
3042+ yappi.stop()
3043+ yappi.clear_stats()
3044+ _yappi._set_test_timings(_timings)
3045+ yappi.start()
3046+
3047+ _dummy = []
3048+ for i in range(WORKER_COUNT):
3049+ t = threading.Thread(target=a)
3050+ t.start()
3051+ t.join()
3052+ for i in range(WORKER_COUNT):
3053+ t = threading.Thread(target=b)
3054+ t.start()
3055+ _dummy.append(t)
3056+ t.join()
3057+ for i in range(WORKER_COUNT):
3058+ t = threading.Thread(target=a)
3059+ t.start()
3060+ t.join()
3061+ for i in range(WORKER_COUNT):
3062+ t = threading.Thread(target=c)
3063+ t.start()
3064+ t.join()
3065+ yappi.stop()
3066+ yappi.start()
3067+
3068+ def f():
3069+ pass
3070+
3071+ f()
3072+ stats = yappi.get_func_stats()
3073+ fsa = utils.find_stat_by_name(stats, 'a')
3074+ fsb = utils.find_stat_by_name(stats, 'b')
3075+ fsc = utils.find_stat_by_name(stats, 'c')
3076+ self.assertEqual(fsa.ncall, 10)
3077+ self.assertEqual(fsb.ncall, 5)
3078+ self.assertEqual(fsc.ncall, 5)
3079+ self.assertEqual(fsa.ttot, fsa.tsub, 30)
3080+ self.assertEqual(fsb.ttot, fsb.tsub, 10)
3081+ self.assertEqual(fsc.ttot, fsc.tsub, 5)
3082+
3083+ # MACOSx optimizes by only creating one worker thread
3084+ self.assertTrue(len(yappi.get_thread_stats()) >= 2)
3085+
3086+ def test_basic(self):
3087+ yappi.set_clock_type('wall')
3088+
3089+ def dummy():
3090+ pass
3091+
3092+ def a():
3093+ time.sleep(0.2)
3094+
3095+ class Worker1(threading.Thread):
3096+
3097+ def a(self):
3098+ time.sleep(0.3)
3099+
3100+ def run(self):
3101+ self.a()
3102+
3103+ yappi.start(builtins=False, profile_threads=True)
3104+
3105+ c = Worker1()
3106+ c.start()
3107+ c.join()
3108+ a()
3109+ stats = yappi.get_func_stats()
3110+ fsa1 = utils.find_stat_by_name(stats, 'Worker1.a')
3111+ fsa2 = utils.find_stat_by_name(stats, 'a')
3112+ self.assertTrue(fsa1 is not None)
3113+ self.assertTrue(fsa2 is not None)
3114+ self.assertTrue(fsa1.ttot > 0.2)
3115+ self.assertTrue(fsa2.ttot > 0.1)
3116+ tstats = yappi.get_thread_stats()
3117+ self.assertEqual(len(tstats), 2)
3118+ tsa = utils.find_stat_by_name(tstats, 'Worker1')
3119+ tsm = utils.find_stat_by_name(tstats, '_MainThread')
3120+ dummy() # call dummy to force ctx name to be retrieved again.
3121+ self.assertTrue(tsa is not None)
3122+ # TODO: I put dummy() to fix below, remove the comments after a while.
3123+ self.assertTrue( # FIX: I see this fails sometimes?
3124+ tsm is not None,
Patrick Williams169d7bc2024-01-05 11:33:25 -06003125+ f"Could not find \"_MainThread\". Found: {', '.join(utils.get_stat_names(tstats))}")
Andrew Geissler69721092021-07-23 12:57:00 -04003126+
3127+ def test_ctx_stats(self):
3128+ from threading import Thread
3129+ DUMMY_WORKER_COUNT = 5
3130+ yappi.start()
3131+
3132+ class DummyThread(Thread):
3133+ pass
3134+
3135+ def dummy():
3136+ pass
3137+
3138+ def dummy_worker():
3139+ pass
3140+
3141+ for i in range(DUMMY_WORKER_COUNT):
3142+ t = DummyThread(target=dummy_worker)
3143+ t.start()
3144+ t.join()
3145+ yappi.stop()
3146+ stats = yappi.get_thread_stats()
3147+ tsa = utils.find_stat_by_name(stats, "DummyThread")
3148+ self.assertTrue(tsa is not None)
3149+ yappi.clear_stats()
3150+ time.sleep(1.0)
3151+ _timings = {
3152+ "a_1": 6,
3153+ "b_1": 5,
3154+ "c_1": 3,
3155+ "d_1": 1,
3156+ "a_2": 4,
3157+ "b_2": 3,
3158+ "c_2": 2,
3159+ "d_2": 1
3160+ }
3161+ _yappi._set_test_timings(_timings)
3162+
3163+ class Thread1(Thread):
3164+ pass
3165+
3166+ class Thread2(Thread):
3167+ pass
3168+
3169+ def a():
3170+ b()
3171+
3172+ def b():
3173+ c()
3174+
3175+ def c():
3176+ d()
3177+
3178+ def d():
3179+ time.sleep(0.6)
3180+
3181+ yappi.set_clock_type("wall")
3182+ yappi.start()
3183+ t1 = Thread1(target=a)
3184+ t1.start()
3185+ t2 = Thread2(target=a)
3186+ t2.start()
3187+ t1.join()
3188+ t2.join()
3189+ stats = yappi.get_thread_stats()
3190+
3191+ # the fist clear_stats clears the context table?
3192+ tsa = utils.find_stat_by_name(stats, "DummyThread")
3193+ self.assertTrue(tsa is None)
3194+
3195+ tst1 = utils.find_stat_by_name(stats, "Thread1")
3196+ tst2 = utils.find_stat_by_name(stats, "Thread2")
3197+ tsmain = utils.find_stat_by_name(stats, "_MainThread")
3198+ dummy() # call dummy to force ctx name to be retrieved again.
3199+ self.assertTrue(len(stats) == 3)
3200+ self.assertTrue(tst1 is not None)
3201+ self.assertTrue(tst2 is not None)
3202+ # TODO: I put dummy() to fix below, remove the comments after a while.
3203+ self.assertTrue( # FIX: I see this fails sometimes
3204+ tsmain is not None,
Patrick Williams169d7bc2024-01-05 11:33:25 -06003205+ f"Could not find \"_MainThread\". Found: {', '.join(utils.get_stat_names(stats))}")
Andrew Geissler69721092021-07-23 12:57:00 -04003206+ self.assertTrue(1.0 > tst2.ttot >= 0.5)
3207+ self.assertTrue(1.0 > tst1.ttot >= 0.5)
3208+
3209+ # test sorting of the ctx stats
3210+ stats = stats.sort("totaltime", "desc")
3211+ prev_stat = None
3212+ for stat in stats:
3213+ if prev_stat:
3214+ self.assertTrue(prev_stat.ttot >= stat.ttot)
3215+ prev_stat = stat
3216+ stats = stats.sort("totaltime", "asc")
3217+ prev_stat = None
3218+ for stat in stats:
3219+ if prev_stat:
3220+ self.assertTrue(prev_stat.ttot <= stat.ttot)
3221+ prev_stat = stat
3222+ stats = stats.sort("schedcount", "desc")
3223+ prev_stat = None
3224+ for stat in stats:
3225+ if prev_stat:
3226+ self.assertTrue(prev_stat.sched_count >= stat.sched_count)
3227+ prev_stat = stat
3228+ stats = stats.sort("name", "desc")
3229+ prev_stat = None
3230+ for stat in stats:
3231+ if prev_stat:
3232+ self.assertTrue(prev_stat.name.lower() >= stat.name.lower())
3233+ prev_stat = stat
3234+ self.assertRaises(
3235+ yappi.YappiError, stats.sort, "invalid_thread_sorttype_arg"
3236+ )
3237+ self.assertRaises(
3238+ yappi.YappiError, stats.sort, "invalid_thread_sortorder_arg"
3239+ )
3240+
3241+ def test_ctx_stats_cpu(self):
3242+
3243+ def get_thread_name():
3244+ try:
3245+ return threading.current_thread().name
3246+ except AttributeError:
3247+ return "Anonymous"
3248+
3249+ def burn_cpu(sec):
3250+ t0 = yappi.get_clock_time()
3251+ elapsed = 0
3252+ while (elapsed < sec):
3253+ for _ in range(1000):
3254+ pass
3255+ elapsed = yappi.get_clock_time() - t0
3256+
3257+ def test():
3258+
3259+ ts = []
3260+ for i in (0.01, 0.05, 0.1):
3261+ t = threading.Thread(target=burn_cpu, args=(i, ))
Patrick Williams169d7bc2024-01-05 11:33:25 -06003262+ t.name = f"burn_cpu-{str(i)}"
Andrew Geissler69721092021-07-23 12:57:00 -04003263+ t.start()
3264+ ts.append(t)
3265+ for t in ts:
3266+ t.join()
3267+
3268+ yappi.set_clock_type("cpu")
3269+ yappi.set_context_name_callback(get_thread_name)
3270+
3271+ yappi.start()
3272+
3273+ test()
3274+
3275+ yappi.stop()
3276+
3277+ tstats = yappi.get_thread_stats()
3278+ r1 = '''
3279+ burn_cpu-0.1 3 123145356058624 0.100105 8
3280+ burn_cpu-0.05 2 123145361313792 0.050149 8
3281+ burn_cpu-0.01 1 123145356058624 0.010127 2
3282+ MainThread 0 4321620864 0.001632 6
3283+ '''
3284+ self.assert_ctx_stats_almost_equal(r1, tstats)
3285+
3286+ def test_producer_consumer_with_queues(self):
3287+ # we currently just stress yappi, no functionality test is done here.
3288+ yappi.start()
Patrick Williams169d7bc2024-01-05 11:33:25 -06003289+ from queue import Queue
Andrew Geissler69721092021-07-23 12:57:00 -04003290+ from threading import Thread
3291+ WORKER_THREAD_COUNT = 50
3292+ WORK_ITEM_COUNT = 2000
3293+
3294+ def worker():
3295+ while True:
3296+ item = q.get()
3297+ # do the work with item
3298+ q.task_done()
3299+
3300+ q = Queue()
3301+ for i in range(WORKER_THREAD_COUNT):
3302+ t = Thread(target=worker)
3303+ t.daemon = True
3304+ t.start()
3305+
3306+ for item in range(WORK_ITEM_COUNT):
3307+ q.put(item)
3308+ q.join() # block until all tasks are done
3309+ #yappi.get_func_stats().sort("callcount").print_all()
3310+ yappi.stop()
3311+
3312+ def test_temporary_lock_waiting(self):
3313+ yappi.start()
3314+ _lock = threading.Lock()
3315+
3316+ def worker():
3317+ _lock.acquire()
3318+ try:
3319+ time.sleep(1.0)
3320+ finally:
3321+ _lock.release()
3322+
3323+ t1 = threading.Thread(target=worker)
3324+ t2 = threading.Thread(target=worker)
3325+ t1.start()
3326+ t2.start()
3327+ t1.join()
3328+ t2.join()
3329+ #yappi.get_func_stats().sort("callcount").print_all()
3330+ yappi.stop()
3331+
3332+ @unittest.skipIf(os.name != "posix", "requires Posix compliant OS")
3333+ def test_signals_with_blocking_calls(self):
3334+ import signal, os, time
3335+
3336+ # just to verify if signal is handled correctly and stats/yappi are not corrupted.
3337+ def handler(signum, frame):
3338+ raise Exception("Signal handler executed!")
3339+
3340+ yappi.start()
3341+ signal.signal(signal.SIGALRM, handler)
3342+ signal.alarm(1)
3343+ self.assertRaises(Exception, time.sleep, 2)
3344+ stats = yappi.get_func_stats()
3345+ fsh = utils.find_stat_by_name(stats, "handler")
3346+ self.assertTrue(fsh is not None)
3347+
Andrew Geissler69721092021-07-23 12:57:00 -04003348+ def test_concurrent_futures(self):
3349+ yappi.start()
3350+ from concurrent.futures import ThreadPoolExecutor
3351+ with ThreadPoolExecutor(max_workers=5) as executor:
3352+ f = executor.submit(pow, 5, 2)
3353+ self.assertEqual(f.result(), 25)
3354+ time.sleep(1.0)
3355+ yappi.stop()
3356+
Andrew Geissler69721092021-07-23 12:57:00 -04003357+ def test_barrier(self):
3358+ yappi.start()
3359+ b = threading.Barrier(2, timeout=1)
3360+
3361+ def worker():
3362+ try:
3363+ b.wait()
3364+ except threading.BrokenBarrierError:
3365+ pass
3366+ except Exception:
3367+ raise Exception("BrokenBarrierError not raised")
3368+
3369+ t1 = threading.Thread(target=worker)
3370+ t1.start()
3371+ #b.wait()
3372+ t1.join()
3373+ yappi.stop()
3374+
3375+
3376+class NonRecursiveFunctions(utils.YappiUnitTestCase):
3377+
3378+ def test_abcd(self):
3379+ _timings = {"a_1": 6, "b_1": 5, "c_1": 3, "d_1": 1}
3380+ _yappi._set_test_timings(_timings)
3381+
3382+ def a():
3383+ b()
3384+
3385+ def b():
3386+ c()
3387+
3388+ def c():
3389+ d()
3390+
3391+ def d():
3392+ pass
3393+
3394+ stats = utils.run_and_get_func_stats(a)
3395+ fsa = utils.find_stat_by_name(stats, 'a')
3396+ fsb = utils.find_stat_by_name(stats, 'b')
3397+ fsc = utils.find_stat_by_name(stats, 'c')
3398+ fsd = utils.find_stat_by_name(stats, 'd')
3399+ cfsab = fsa.children[fsb]
3400+ cfsbc = fsb.children[fsc]
3401+ cfscd = fsc.children[fsd]
3402+
3403+ self.assertEqual(fsa.ttot, 6)
3404+ self.assertEqual(fsa.tsub, 1)
3405+ self.assertEqual(fsb.ttot, 5)
3406+ self.assertEqual(fsb.tsub, 2)
3407+ self.assertEqual(fsc.ttot, 3)
3408+ self.assertEqual(fsc.tsub, 2)
3409+ self.assertEqual(fsd.ttot, 1)
3410+ self.assertEqual(fsd.tsub, 1)
3411+ self.assertEqual(cfsab.ttot, 5)
3412+ self.assertEqual(cfsab.tsub, 2)
3413+ self.assertEqual(cfsbc.ttot, 3)
3414+ self.assertEqual(cfsbc.tsub, 2)
3415+ self.assertEqual(cfscd.ttot, 1)
3416+ self.assertEqual(cfscd.tsub, 1)
3417+
3418+ def test_stop_in_middle(self):
3419+ _timings = {"a_1": 6, "b_1": 4}
3420+ _yappi._set_test_timings(_timings)
3421+
3422+ def a():
3423+ b()
3424+ yappi.stop()
3425+
3426+ def b():
3427+ time.sleep(0.2)
3428+
3429+ yappi.start()
3430+ a()
3431+ stats = yappi.get_func_stats()
3432+ fsa = utils.find_stat_by_name(stats, 'a')
3433+ fsb = utils.find_stat_by_name(stats, 'b')
3434+
3435+ self.assertEqual(fsa.ncall, 1)
3436+ self.assertEqual(fsa.nactualcall, 0)
3437+ self.assertEqual(fsa.ttot, 0) # no call_leave called
3438+ self.assertEqual(fsa.tsub, 0) # no call_leave called
3439+ self.assertEqual(fsb.ttot, 4)
3440+
3441+
3442+class RecursiveFunctions(utils.YappiUnitTestCase):
3443+
3444+ def test_fibonacci(self):
3445+
3446+ def fib(n):
3447+ if n > 1:
3448+ return fib(n - 1) + fib(n - 2)
3449+ else:
3450+ return n
3451+
3452+ stats = utils.run_and_get_func_stats(fib, 22)
3453+ fs = utils.find_stat_by_name(stats, 'fib')
3454+ self.assertEqual(fs.ncall, 57313)
3455+ self.assertEqual(fs.ttot, fs.tsub)
3456+
3457+ def test_abcadc(self):
3458+ _timings = {
3459+ "a_1": 20,
3460+ "b_1": 19,
3461+ "c_1": 17,
3462+ "a_2": 13,
3463+ "d_1": 12,
3464+ "c_2": 10,
3465+ "a_3": 5
3466+ }
3467+ _yappi._set_test_timings(_timings)
3468+
3469+ def a(n):
3470+ if n == 3:
3471+ return
3472+ if n == 1 + 1:
3473+ d(n)
3474+ else:
3475+ b(n)
3476+
3477+ def b(n):
3478+ c(n)
3479+
3480+ def c(n):
3481+ a(n + 1)
3482+
3483+ def d(n):
3484+ c(n)
3485+
3486+ stats = utils.run_and_get_func_stats(a, 1)
3487+ fsa = utils.find_stat_by_name(stats, 'a')
3488+ fsb = utils.find_stat_by_name(stats, 'b')
3489+ fsc = utils.find_stat_by_name(stats, 'c')
3490+ fsd = utils.find_stat_by_name(stats, 'd')
3491+ self.assertEqual(fsa.ncall, 3)
3492+ self.assertEqual(fsa.nactualcall, 1)
3493+ self.assertEqual(fsa.ttot, 20)
3494+ self.assertEqual(fsa.tsub, 7)
3495+ self.assertEqual(fsb.ttot, 19)
3496+ self.assertEqual(fsb.tsub, 2)
3497+ self.assertEqual(fsc.ttot, 17)
3498+ self.assertEqual(fsc.tsub, 9)
3499+ self.assertEqual(fsd.ttot, 12)
3500+ self.assertEqual(fsd.tsub, 2)
3501+ cfsca = fsc.children[fsa]
3502+ self.assertEqual(cfsca.nactualcall, 0)
3503+ self.assertEqual(cfsca.ncall, 2)
3504+ self.assertEqual(cfsca.ttot, 13)
3505+ self.assertEqual(cfsca.tsub, 6)
3506+
3507+ def test_aaaa(self):
3508+ _timings = {"d_1": 9, "d_2": 7, "d_3": 3, "d_4": 2}
3509+ _yappi._set_test_timings(_timings)
3510+
3511+ def d(n):
3512+ if n == 3:
3513+ return
3514+ d(n + 1)
3515+
3516+ stats = utils.run_and_get_func_stats(d, 0)
3517+ fsd = utils.find_stat_by_name(stats, 'd')
3518+ self.assertEqual(fsd.ncall, 4)
3519+ self.assertEqual(fsd.nactualcall, 1)
3520+ self.assertEqual(fsd.ttot, 9)
3521+ self.assertEqual(fsd.tsub, 9)
3522+ cfsdd = fsd.children[fsd]
3523+ self.assertEqual(cfsdd.ttot, 7)
3524+ self.assertEqual(cfsdd.tsub, 7)
3525+ self.assertEqual(cfsdd.ncall, 3)
3526+ self.assertEqual(cfsdd.nactualcall, 0)
3527+
3528+ def test_abcabc(self):
3529+ _timings = {
3530+ "a_1": 20,
3531+ "b_1": 19,
3532+ "c_1": 17,
3533+ "a_2": 13,
3534+ "b_2": 11,
3535+ "c_2": 9,
3536+ "a_3": 6
3537+ }
3538+ _yappi._set_test_timings(_timings)
3539+
3540+ def a(n):
3541+ if n == 3:
3542+ return
3543+ else:
3544+ b(n)
3545+
3546+ def b(n):
3547+ c(n)
3548+
3549+ def c(n):
3550+ a(n + 1)
3551+
3552+ stats = utils.run_and_get_func_stats(a, 1)
3553+ fsa = utils.find_stat_by_name(stats, 'a')
3554+ fsb = utils.find_stat_by_name(stats, 'b')
3555+ fsc = utils.find_stat_by_name(stats, 'c')
3556+ self.assertEqual(fsa.ncall, 3)
3557+ self.assertEqual(fsa.nactualcall, 1)
3558+ self.assertEqual(fsa.ttot, 20)
3559+ self.assertEqual(fsa.tsub, 9)
3560+ self.assertEqual(fsb.ttot, 19)
3561+ self.assertEqual(fsb.tsub, 4)
3562+ self.assertEqual(fsc.ttot, 17)
3563+ self.assertEqual(fsc.tsub, 7)
3564+ cfsab = fsa.children[fsb]
3565+ cfsbc = fsb.children[fsc]
3566+ cfsca = fsc.children[fsa]
3567+ self.assertEqual(cfsab.ttot, 19)
3568+ self.assertEqual(cfsab.tsub, 4)
3569+ self.assertEqual(cfsbc.ttot, 17)
3570+ self.assertEqual(cfsbc.tsub, 7)
3571+ self.assertEqual(cfsca.ttot, 13)
3572+ self.assertEqual(cfsca.tsub, 8)
3573+
3574+ def test_abcbca(self):
3575+ _timings = {"a_1": 10, "b_1": 9, "c_1": 7, "b_2": 4, "c_2": 2, "a_2": 1}
3576+ _yappi._set_test_timings(_timings)
3577+ self._ncall = 1
3578+
3579+ def a():
3580+ if self._ncall == 1:
3581+ b()
3582+ else:
3583+ return
3584+
3585+ def b():
3586+ c()
3587+
3588+ def c():
3589+ if self._ncall == 1:
3590+ self._ncall += 1
3591+ b()
3592+ else:
3593+ a()
3594+
3595+ stats = utils.run_and_get_func_stats(a)
3596+ fsa = utils.find_stat_by_name(stats, 'a')
3597+ fsb = utils.find_stat_by_name(stats, 'b')
3598+ fsc = utils.find_stat_by_name(stats, 'c')
3599+ cfsab = fsa.children[fsb]
3600+ cfsbc = fsb.children[fsc]
3601+ cfsca = fsc.children[fsa]
3602+ self.assertEqual(fsa.ttot, 10)
3603+ self.assertEqual(fsa.tsub, 2)
3604+ self.assertEqual(fsb.ttot, 9)
3605+ self.assertEqual(fsb.tsub, 4)
3606+ self.assertEqual(fsc.ttot, 7)
3607+ self.assertEqual(fsc.tsub, 4)
3608+ self.assertEqual(cfsab.ttot, 9)
3609+ self.assertEqual(cfsab.tsub, 2)
3610+ self.assertEqual(cfsbc.ttot, 7)
3611+ self.assertEqual(cfsbc.tsub, 4)
3612+ self.assertEqual(cfsca.ttot, 1)
3613+ self.assertEqual(cfsca.tsub, 1)
3614+ self.assertEqual(cfsca.ncall, 1)
3615+ self.assertEqual(cfsca.nactualcall, 0)
3616+
3617+ def test_aabccb(self):
3618+ _timings = {
3619+ "a_1": 13,
3620+ "a_2": 11,
3621+ "b_1": 9,
3622+ "c_1": 5,
3623+ "c_2": 3,
3624+ "b_2": 1
3625+ }
3626+ _yappi._set_test_timings(_timings)
3627+ self._ncall = 1
3628+
3629+ def a():
3630+ if self._ncall == 1:
3631+ self._ncall += 1
3632+ a()
3633+ else:
3634+ b()
3635+
3636+ def b():
3637+ if self._ncall == 3:
3638+ return
3639+ else:
3640+ c()
3641+
3642+ def c():
3643+ if self._ncall == 2:
3644+ self._ncall += 1
3645+ c()
3646+ else:
3647+ b()
3648+
3649+ stats = utils.run_and_get_func_stats(a)
3650+ fsa = utils.find_stat_by_name(stats, 'a')
3651+ fsb = utils.find_stat_by_name(stats, 'b')
3652+ fsc = utils.find_stat_by_name(stats, 'c')
3653+ cfsaa = fsa.children[fsa.index]
3654+ cfsab = fsa.children[fsb]
3655+ cfsbc = fsb.children[fsc.full_name]
3656+ cfscc = fsc.children[fsc]
3657+ cfscb = fsc.children[fsb]
3658+ self.assertEqual(fsb.ttot, 9)
3659+ self.assertEqual(fsb.tsub, 5)
3660+ self.assertEqual(cfsbc.ttot, 5)
3661+ self.assertEqual(cfsbc.tsub, 2)
3662+ self.assertEqual(fsa.ttot, 13)
3663+ self.assertEqual(fsa.tsub, 4)
3664+ self.assertEqual(cfsab.ttot, 9)
3665+ self.assertEqual(cfsab.tsub, 4)
3666+ self.assertEqual(cfsaa.ttot, 11)
3667+ self.assertEqual(cfsaa.tsub, 2)
3668+ self.assertEqual(fsc.ttot, 5)
3669+ self.assertEqual(fsc.tsub, 4)
3670+
3671+ def test_abaa(self):
3672+ _timings = {"a_1": 13, "b_1": 10, "a_2": 9, "a_3": 5}
3673+ _yappi._set_test_timings(_timings)
3674+
3675+ self._ncall = 1
3676+
3677+ def a():
3678+ if self._ncall == 1:
3679+ b()
3680+ elif self._ncall == 2:
3681+ self._ncall += 1
3682+ a()
3683+ else:
3684+ return
3685+
3686+ def b():
3687+ self._ncall += 1
3688+ a()
3689+
3690+ stats = utils.run_and_get_func_stats(a)
3691+ fsa = utils.find_stat_by_name(stats, 'a')
3692+ fsb = utils.find_stat_by_name(stats, 'b')
3693+ cfsaa = fsa.children[fsa]
3694+ cfsba = fsb.children[fsa]
3695+ self.assertEqual(fsb.ttot, 10)
3696+ self.assertEqual(fsb.tsub, 1)
3697+ self.assertEqual(fsa.ttot, 13)
3698+ self.assertEqual(fsa.tsub, 12)
3699+ self.assertEqual(cfsaa.ttot, 5)
3700+ self.assertEqual(cfsaa.tsub, 5)
3701+ self.assertEqual(cfsba.ttot, 9)
3702+ self.assertEqual(cfsba.tsub, 4)
3703+
3704+ def test_aabb(self):
3705+ _timings = {"a_1": 13, "a_2": 10, "b_1": 9, "b_2": 5}
3706+ _yappi._set_test_timings(_timings)
3707+
3708+ self._ncall = 1
3709+
3710+ def a():
3711+ if self._ncall == 1:
3712+ self._ncall += 1
3713+ a()
3714+ elif self._ncall == 2:
3715+ b()
3716+ else:
3717+ return
3718+
3719+ def b():
3720+ if self._ncall == 2:
3721+ self._ncall += 1
3722+ b()
3723+ else:
3724+ return
3725+
3726+ stats = utils.run_and_get_func_stats(a)
3727+ fsa = utils.find_stat_by_name(stats, 'a')
3728+ fsb = utils.find_stat_by_name(stats, 'b')
3729+ cfsaa = fsa.children[fsa]
3730+ cfsab = fsa.children[fsb]
3731+ cfsbb = fsb.children[fsb]
3732+ self.assertEqual(fsa.ttot, 13)
3733+ self.assertEqual(fsa.tsub, 4)
3734+ self.assertEqual(fsb.ttot, 9)
3735+ self.assertEqual(fsb.tsub, 9)
3736+ self.assertEqual(cfsaa.ttot, 10)
3737+ self.assertEqual(cfsaa.tsub, 1)
3738+ self.assertEqual(cfsab.ttot, 9)
3739+ self.assertEqual(cfsab.tsub, 4)
3740+ self.assertEqual(cfsbb.ttot, 5)
3741+ self.assertEqual(cfsbb.tsub, 5)
3742+
3743+ def test_abbb(self):
3744+ _timings = {"a_1": 13, "b_1": 10, "b_2": 6, "b_3": 1}
3745+ _yappi._set_test_timings(_timings)
3746+
3747+ self._ncall = 1
3748+
3749+ def a():
3750+ if self._ncall == 1:
3751+ b()
3752+
3753+ def b():
3754+ if self._ncall == 3:
3755+ return
3756+ self._ncall += 1
3757+ b()
3758+
3759+ stats = utils.run_and_get_func_stats(a)
3760+ fsa = utils.find_stat_by_name(stats, 'a')
3761+ fsb = utils.find_stat_by_name(stats, 'b')
3762+ cfsab = fsa.children[fsb]
3763+ cfsbb = fsb.children[fsb]
3764+ self.assertEqual(fsa.ttot, 13)
3765+ self.assertEqual(fsa.tsub, 3)
3766+ self.assertEqual(fsb.ttot, 10)
3767+ self.assertEqual(fsb.tsub, 10)
3768+ self.assertEqual(fsb.ncall, 3)
3769+ self.assertEqual(fsb.nactualcall, 1)
3770+ self.assertEqual(cfsab.ttot, 10)
3771+ self.assertEqual(cfsab.tsub, 4)
3772+ self.assertEqual(cfsbb.ttot, 6)
3773+ self.assertEqual(cfsbb.tsub, 6)
3774+ self.assertEqual(cfsbb.nactualcall, 0)
3775+ self.assertEqual(cfsbb.ncall, 2)
3776+
3777+ def test_aaab(self):
3778+ _timings = {"a_1": 13, "a_2": 10, "a_3": 6, "b_1": 1}
3779+ _yappi._set_test_timings(_timings)
3780+
3781+ self._ncall = 1
3782+
3783+ def a():
3784+ if self._ncall == 3:
3785+ b()
3786+ return
3787+ self._ncall += 1
3788+ a()
3789+
3790+ def b():
3791+ return
3792+
3793+ stats = utils.run_and_get_func_stats(a)
3794+ fsa = utils.find_stat_by_name(stats, 'a')
3795+ fsb = utils.find_stat_by_name(stats, 'b')
3796+ cfsaa = fsa.children[fsa]
3797+ cfsab = fsa.children[fsb]
3798+ self.assertEqual(fsa.ttot, 13)
3799+ self.assertEqual(fsa.tsub, 12)
3800+ self.assertEqual(fsb.ttot, 1)
3801+ self.assertEqual(fsb.tsub, 1)
3802+ self.assertEqual(cfsaa.ttot, 10)
3803+ self.assertEqual(cfsaa.tsub, 9)
3804+ self.assertEqual(cfsab.ttot, 1)
3805+ self.assertEqual(cfsab.tsub, 1)
3806+
3807+ def test_abab(self):
3808+ _timings = {"a_1": 13, "b_1": 10, "a_2": 6, "b_2": 1}
3809+ _yappi._set_test_timings(_timings)
3810+
3811+ self._ncall = 1
3812+
3813+ def a():
3814+ b()
3815+
3816+ def b():
3817+ if self._ncall == 2:
3818+ return
3819+ self._ncall += 1
3820+ a()
3821+
3822+ stats = utils.run_and_get_func_stats(a)
3823+ fsa = utils.find_stat_by_name(stats, 'a')
3824+ fsb = utils.find_stat_by_name(stats, 'b')
3825+ cfsab = fsa.children[fsb]
3826+ cfsba = fsb.children[fsa]
3827+ self.assertEqual(fsa.ttot, 13)
3828+ self.assertEqual(fsa.tsub, 8)
3829+ self.assertEqual(fsb.ttot, 10)
3830+ self.assertEqual(fsb.tsub, 5)
3831+ self.assertEqual(cfsab.ttot, 10)
3832+ self.assertEqual(cfsab.tsub, 5)
3833+ self.assertEqual(cfsab.ncall, 2)
3834+ self.assertEqual(cfsab.nactualcall, 1)
3835+ self.assertEqual(cfsba.ttot, 6)
3836+ self.assertEqual(cfsba.tsub, 5)
3837+
3838+
3839+if __name__ == '__main__':
3840+ # import sys;sys.argv = ['', 'BasicUsage.test_run_as_script']
3841+ # import sys;sys.argv = ['', 'MultithreadedScenarios.test_subsequent_profile']
3842+ unittest.main()
Patrick Williams169d7bc2024-01-05 11:33:25 -06003843--
38442.34.1
3845