1From 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
5
6Convert 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>
12---
13 tests/test_functionality.py | 3822 +++++++++++++++++------------------
14 1 file changed, 1911 insertions(+), 1911 deletions(-)
15
16diff --git a/tests/test_functionality.py b/tests/test_functionality.py
17index 0e99c47..38bbe67 100644
18--- a/tests/test_functionality.py
19+++ b/tests/test_functionality.py
20@@ -1,1911 +1,1911 @@
21-import os
22-import sys
23-import time
24-import threading
25-import unittest
26-import yappi
27-import _yappi
28-import utils
29-import multiprocessing
30-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):
300-            fname = f"tests/{func.__name__}.profile"
301-            try:
302-                stats.add(fname)
303-            except OSError:
304-                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,
1214-            f"Could not find \"_MainThread\". Found: {', '.join(utils.get_stat_names(tstats))}")
1215-
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,
1294-            f"Could not find \"_MainThread\". Found: {', '.join(utils.get_stat_names(stats))}")
1295-        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, ))
1351-                t.name = f"burn_cpu-{str(i)}"
1352-                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()
1378-        from queue import Queue
1379-        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-
1437-    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-
1446-    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
1939+import utils
1940+import multiprocessing
1941+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):
2211+            fname = f"tests/{func.__name__}.profile"
2212+            try:
2213+                stats.add(fname)
2214+            except OSError:
2215+                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+        '''
2984+        Start yappi from different thread and we get Internal Error(15) as
2985+        the current_ctx_id() called while enumerating the threads in start()
2986+        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,
3125+            f"Could not find \"_MainThread\". Found: {', '.join(utils.get_stat_names(tstats))}")
3126+
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,
3205+            f"Could not find \"_MainThread\". Found: {', '.join(utils.get_stat_names(stats))}")
3206+        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, ))
3262+                t.name = f"burn_cpu-{str(i)}"
3263+                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()
3289+        from queue import Queue
3290+        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+
3348+    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+
3357+    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()
3843--
38442.34.1
3845
3846