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