subtree updates

meta-raspberrypi: fde68b24f0..4c033eb074:
  Harunobu Kurokawa (1):
        rpi-cmdline, rpi-u-boot-src: Support USB boot

meta-arm: 0b61cc659a..4d22f982bc:
  Debbie Martin (2):
        arm-systemready: Add parted dependency and inherit testimage
        ci: Add Arm SystemReady firmware and IR ACS builds

  Harsimran Singh Tungal (3):
        arm-bsp/documentation: corstone1000: fix the steps in the user guide and instructions
        corstone1000:arm-bsp/optee: Update optee to v4.0
        corstone1000:arm-bsp/tftf: Fix tftf tests on mps3

  Jon Mason (5):
        arm/trusted-firmware-a: move patch file to bbappend
        arm/trusted-firmware-a: update to 2.10
        arm/hafnium: update to v2.10
        CI: rename meta-secure-core directory
        arm/edk2: update to 202311

  Ross Burton (1):
        CI: switch back to master

poky: 028b6f6226..4675bbb757:
  Adrian Freihofer (4):
        cmake-qemu.bbclass: make it more usable
        oe-selftest: add a cpp-example recipe
        oeqa/core/decorator: add skip if not qemu-usermode
        oe-selftest: add tests for C and C++ build tools

  Alassane Yattara (22):
        bitbake: toaster/test: bug-fix on tests/browser/test_all_builds_page
        bitbake: toaster/test: from test_no_builds_message.py wait for the empty state div to appear
        bitbake: toaster/test: delay driver action until elements to appear
        bitbake: toaster/tests: Ensure to kill toaster process create for tests functional
        bitbake: toaster/tests: Added functional/utils, contains useful methods using by functional tests
        bitbake: toaster/tests: Refactorize tests/functional
        bitbake: toaster/tests: Bug fixes, functional tests dependent on each other
        bitbake: toaster/tests: Fixes warnings in autobuilder
        bitbake: toaster/tests: bug-fix tests writing files into /tmp on the autobuilders
        bitbake: toaster/test: fix Copyright
        bitbake: toaster/tests: logging warning in console, trying to kill unavailable Runbuilds process
        bitbake: toaster/tests: Removed all time.sleep occurrence
        bitbake: toaster/tests: Bug-Fix testcase functional/test_project_page_tab_config.py
        bitbake: toaster/tests: bug-fix element click intercepted in browser/test_layerdetails_page.py
        bitbake: toaster/tests: Update tests/functional/functional_helpers test_functional_basic
        bitbake: toaster/tests: Fixes functional tests warning on autobuilder
        bitbake: toaster/tests: Bug-fix test_functional_basic, delay driver actions
        bitbake: toaster/tests: bug-fix An element matching "#projectstable" should be visible
        bitbake: toaster/tests: bug-fix An element matching "#lastest_builds" should be on the page
        bitbake: toaster/tests: Skip to show more then 100 item in ToasterTable
        bitbake: toaster/tests: Bug-fix "#project-created-notification" should be visible
        bitbake: toaster/toastergui: Bug-fix verify given layer path only if import/add local layer

  Alex Bennée (1):
        qemurunner: more cleanups for output blocking

  Alex Kiernan (17):
        cargo: Rename MANIFEST_PATH -> CARGO_MANIFEST_PATH
        cargo: Move CARGO_MANIFEST_PATH/CARGO_SRC_DIR to cargo_common
        rust: cargo: Convert single-valued variables to weak defaults
        cargo: Add CARGO_LOCK_PATH for path to Cargo.lock
        rust: Upgrade 1.70.0 -> 1.71.0
        rust: Upgrade 1.71.0 -> 1.71.1
        sstate-cache-management: Rewrite in python
        devtool: selftest: Fix test_devtool_modify_git_crates_subpath inequality
        devtool: selftest: Fix test_devtool_modify_git_crates_subpath bbappend check
        meta-selftest: hello-rs: Simple rust test recipe
        devtool: selftest: Swap to hello-rs for crates testing
        zvariant: Drop recipe
        rust: Upgrade 1.71.1 -> 1.72.0
        rust: Upgrade 1.72.0 -> 1.72.1
        rust: Upgrade 1.72.1 -> 1.73.0
        rust: Upgrade 1.73.0 -> 1.74.0
        rust: Upgrade 1.74.0 -> 1.74.1

  Alexander Kanavin (21):
        selftest/sstatetest: print output from bitbake with actual newlines, not \n
        selftest/sstatetests: do not delete custom $TMPDIRs under build-st when testing printdiff
        sstatesig/find_siginfo: special-case gcc-source when looking in sstate caches
        oeqa/selftest/sstatetests: re-work CDN tests, add local cache tests
        gobject-introspection: depend on setuptools to obtain distutils module
        libcap-ng-python: depend on setuptools to obtain distutils copy
        dnf: remove obsolete python3-gpg dependency (provided by gpgme)
        gpgme: disable python support (until upstream fixes 3.12 compatibility)
        python3-setuptools-rust: remove distutils dependency
        python3-babel: replace distutils with setuptools, as supported by upstream
        python3-pip: remove distutils depedency
        glib-2.0: replace distutils dependency with setuptools
        python3-pytest-runner: remove distutils dependency
        python3-numpy: distutils is no longer required
        bitbake: bitbake/codeparser.py: address ast module deprecations in py 3.12
        glibc-y2038-tests: do not run tests using 32 bit time APIs
        bitbake: bitbake/runqueue: add debugging for find_siginfo() calls
        bitbake: bitbake-diffsigs/runqueue: adapt to reworked find_siginfo()
        bitbake: bitbake/runqueue: prioritize local stamps over sstate signatures in printdiff
        sstatesig/find_siginfo: unify a disjointed API
        lib/sstatesig/find_siginfo: raise an error instead of returning None when obtaining mtime

  Alexander Lussier-Cullen (6):
        bitbake: toaster: fix pytest build test execution and test discovery
        bitbake: toaster: Add verbose printout for missing chrome(driver) dependencies
        bitbake: bitbake: toaster: add functional testing toaster error details
        bitbake: toaster/tests: Exit tests on chromedriver creation failure
        bitbake: toaster/tests: fix functional tests setup and teardown
        bitbake: toaster/tests: fix chrome argument syntax and wait for driver exit

  Alexandre Belloni (1):
        oeqa/selftest/recipetool: stop looking for md5sum

  Anuj Mittal (9):
        sqlite3: upgrade 3.44.0 -> 3.44.2
        base-passwd: upgrade 3.6.2 -> 3.6.3
        bluez5: upgrade 5.70 -> 5.71
        glib-2.0: upgrade 2.78.1 -> 2.78.3
        glib-networking: upgrade 2.76.1 -> 2.78.0
        puzzles: upgrade to latest revision
        stress-ng: upgrade 0.17.01 -> 0.17.03
        libusb1: fix upstream version check
        enchant2: upgrade 2.6.2 -> 2.6.4

  Archana Polampalli (1):
        bluez5: fix CVE-2023-45866

  Bruce Ashfield (31):
        linux-yocto/6.5: cfg: split runtime and symbol debug
        linux-yocto/6.5: update to v6.5.11
        linux-yocto/6.1: update to v6.1.62
        linux-yocto-dev: bump to v6.7
        linux-yocto/6.5: update to v6.5.12
        linux-yocto/6.5: update to v6.5.13
        linux-yocto/6.1: update to v6.1.65
        linux-yocto/6.1: drop removed IMA option
        linux-yocto/6.5: drop removed IMA option
        linux-yocto-rt/6.1: update to -rt18
        linux-yocto/6.1: update to v6.1.66
        linux-yocto/6.1: update to v6.1.67
        linux-yocto/6.5: fix AB-INT: QEMU kernel panic: No irq handler for vector
        linux-yocto/6.1: update to v6.1.68
        oeqa/runtime/parselogs: add qemux86 ACPI ignore for kernel v6.6+
        linux-libc-headers: update to v6.6-lts
        linux-yocto: introduce 6.6 reference kernel
        linux-yocto/6.6: fix AB-INT: QEMU kernel panic: No irq handler for vector
        linux-yocto-rt/6.6: fix CVE exclusion include
        linux-yocto/6.6: update CVE exclusions
        linux-yocto/6.6: update to v6.6.8
        linux-yocto/6.1: update to v6.1.69
        linux-yocto/6.5: drop 6.5 recipes
        linux-yocto-rt/6.6: correct meta data branch
        linux-yocto/6.6: update to v6.6.9
        linux-yocto/6.6: update CVE exclusions
        linux-yocto/6.1: update to v6.1.70
        linux-yocto/6.1: update CVE exclusions
        linux-yocto/6.6: ARM fix configuration audit warning
        linux-yocto/6.6: arm: jitter entropy backport
        poky/poky-tiny: make 6.6 the default kernel

  Changqing Li (1):
        man-pages: remove conflict pages

  Chen Qi (1):
        devtool: use straight print in check-upgrade-status output

  Clay Chang (1):
        devtool: deploy: provide max_process to strip_execs

  Daniel Ammann (1):
        base: Unpack .7z files with p7zip

  Deepthi Hemraj (1):
        autoconf: Add missing perl modules to RDEPENDS

  Dhairya Nagodra (2):
        cve-update-nvd2-native: faster requests with API keys
        cve-update-nvd2-native: increase the delay between subsequent request failures

  Eilís 'pidge' Ní Fhlannagáin (3):
        useradd: Fix issues with useradd dependencies
        useradd: Add testcase for bugzilla issue (currently disabled)
        usergrouptests.py: Add test for switching between static-ids

  Enrico Scholz (1):
        tcp-wrappers: drop libnsl2 build dependency

  Etienne Cordonnier (2):
        gdb/systemd: enable minidebuginfo support conditionally
        manuals: document minidebuginfo

  Fabio Estevam (3):
        libdrm: Upgrade to 2.4.119
        kmscube: Upgrade to latest revision
        bmap-tools: Upgrade to 3.7

  Hongxu Jia (2):
        socat: 1.7.4.4 -> 1.8.0.0
        man-db: 2.11.2 -> 2.12.0

  Jason Andryuk (3):
        linux-firmware: Package iwlwifi .pnvm files
        linux-firmware: Change bnx2 packaging
        linux-firmware: Create bnx2x subpackage

  Jeremy A. Puhlman (1):
        create-spdx-2.2: combine spdx can try to write before dir creation

  Jermain Horsman (2):
        lib/bblayers/makesetup.py: Remove unused imports
        lib/bblayers/buildconf.py: Remove unused imports/variables

  Jose Quaresma (2):
        go: update 1.20.10 -> 1.20.11
        go: update 1.20.11 -> 1.20.12

  Joshua Watt (11):
        bitbake: bitbake-hashserv: Add description of permissions
        bitbake.conf: Add runtimedir
        rpcbind: Specify state directory under /run
        libinput: Add packageconfig for tests
        ipk: Switch to using zstd compression
        lib/oe/path.py: Add relsymlink()
        lib/packagedata.py: Fix broken symlinks for providers with a '/'
        bitbake: contrib/vim: Syntax improvements
        classes-global/sstate: Fix variable typo
        lib/packagedata.py: Add API to iterate over rprovides
        classes-global/insane: Look up all runtime providers for file-rdeps

  Julien Stephan (19):
        recipetool: create_buildsys_python.py: initialize metadata
        recipetool: create: add trailing newlines
        recipetool: create: add new optional process_url callback for plugins
        recipetool: create_buildsys_python: add pypi support
        oeqa/selftest/recipetool: remove spaces on empty lines
        oeqa/selftest/recipetool/devtool: add test for pypi class
        recipetool: appendsrcfile(s): add dry-run mode
        recipeutils: bbappend_recipe: fix undefined variable
        recipeutils: bbappend_recipe: fix docstring
        recipeutils: bbappend_recipe: add a way to specify the name of the file to add
        recipeutils: bbappend_recipe: remove old srcuri entry if parameters are different
        recipetool: appendsrcfile(s): use params instead of extraline
        recipeutils: bbappend_recipe: allow to patch the recipe itself
        recipetool: appendsrcfile(s): add a mode to update the recipe itself
        oeqa/selftest/recipetool: appendsrfile: add test for machine
        oeqa/selftest/recipetool: appendsrc: add test for update mode
        oeqa/selftest/recipetool: add back checksum checks on pypi tests
        oeqa/selftest/recipetool: remove left over from development
        oeqa/selftest/recipetool: fix metadata corruption on meta layer

  Kevin Hao (2):
        beaglebone-yocto: Remove the redundant kernel-devicetree
        beaglebone-yocto: Remove the obsolete variables for uImage

  Khem Raj (13):
        tiff: Backport fixes for CVE-2023-6277
        kmod: Fix build with latest musl
        elfutils: Use own basename API implementation
        util-linux: Fix build with latest musl
        sysvinit: Include libgen.h for basename API
        attr: Fix build with latest musl
        opkg: Use own version of portable basename function
        util-linux: Delete md-raid tests
        gdb: Update to gdb 14.1 release
        systemd: Fix build with latest musl
        qemu: Fix build with latest musl
        qemu: Add packageconfig knob to enable pipewire support
        weston: Include libgen.h for basename

  Lee Chee Yang (5):
        migration-guides: reword fix in release-notes-4.3.1
        migration-guides: add release notes for 4.0.15
        perlcross: update to 1.5.2
        perl: 5.38.0 -> 5.38.2
        curl: update to 8.5.0

  Lucas Stach (1):
        mesa: upgrade 23.2.1 -> 23.3.1

  Ludovic Jozeau (1):
        image-live.bbclass: LIVE_ROOTFS_TYPE support compression

  Lukas Funke (1):
        selftest: wic: add test for zerorize option of empty plugin

  Malte Schmidt (1):
        wic: extend empty plugin with options to write zeros to partiton

  Markus Volk (3):
        gtk4: upgrade 4.12.3 -> 4.12.4
        libadwaita: update 1.4.0 -> 1.4.2
        appstream: Upgrade 0.16.3 -> 1.0.0

  Marlon Rodriguez Garcia (5):
        bitbake: toaster/tests: Update build test
        bitbake: toaster: Added new feature to import eventlogs from command line into toaster using replay functionality
        bitbake: toaster: remove test and update setup to avoid rebuilding image
        bitbake: toaster: Commandline build import table improvements
        bitbake: toaster: Added validation to stop import if there is a build in progress

  Marta Rybczynska (1):
        bitbake: toastergui: verify that an existing layer path is given

  Massimiliano Minella (1):
        zstd: fix LICENSE statement

  Michael Opdenacker (8):
        test-manual: text and formatting fixes
        test-manual: resource updates
        test-manual: use working example
        test-manual: add links to python unittest
        test-manual: explicit or fix file paths
        test-manual: add or improve hyperlinks
        dev-manual: runtime-testing: fix test module name
        poky.conf: update SANITY_TESTED_DISTROS to match autobuilder

  Mikko Rapeli (1):
        runqemu: match .rootfs. in addition to -image- for rootfs

  Ming Liu (1):
        grub: fs/fat: Don't error when mtime is 0

  Mingli Yu (2):
        python3-license-expression: Fix the ptest failure
        ptest-packagelists.inc: Add python3-license-expression

  Pavel Zhukov (2):
        bitbake: utils: Do not create directories with ${ in the name
        oeqa/selftest/bbtests: Add test for unexpanded variables in the dirname

  Peter Kjellerstedt (11):
        oeqa/selftest/devtool: Correct git clone of local repository
        oeqa/selftest/devtool: Avoid global Git hooks when amending a patch
        oeqa/selftest/devtool: Make test_devtool_load_plugin more resilient
        oeqa/selftest/recipetool: Make test_recipetool_load_plugin more resilient
        lib/oe/recipeutils: Avoid wrapping any SRC_URI[sha*sum] variables
        recipetool: create: Improve identification of licenses
        recipetool: create: Only include the expected SRC_URI checksums
        devtool: upgrade: Update all existing checksums for the SRC_URI
        devtool: modify: Make --no-extract work again
        devtool: modify: Handle recipes with a menuconfig task correctly
        dev-manual: Discourage the use of SRC_URI[md5sum]

  Peter Marko (1):
        dtc: preserve version also from shallow git clones

  Philip Balister (1):
        sanity.bbclass: Check for additional native perl modules.

  Renat Khalikov (1):
        python3-maturin: Add missing space appending to CFLAGS

  Richard Purdie (41):
        bitbake: runqueue: Improve inter setscene task dependency handling
        bitbake: bb/toaster: Fix assertEquals deprecation warnings
        bitbake: toaster: Fix assertRegexpMatches deprecation warnings
        bitbake: toastermain/settings: Avoid python filehandle closure warnings
        bitbake: toastergui: Fix regex markup issues
        bitbake: bitbake: Move to version 2.6.1 to mark runqueue changes
        bitbake: toaster-eventreplay: Remove ordering assumptions
        sanity.conf: Require bitbake 2.6.1 for recent runqueue change
        sstate: Remove unneeded code from setscene_depvalid() related to useradd
        oeqa/runtime/systemd: Ensure test runs only on systemd images
        bitbake: toaster: Update to use qemux86-64 machine by default
        bitbake: toaster/tests/builds: Add BB_HASHSERVE passthrough
        pseudo: Update to pull in syncfs probe fix
        useradd: Fix useradd do_populate_sysroot dependency bug
        sstate: Fix dir ownership issues in SSTATE_DIR
        oeqa/sstatetests: Disable gcc source printdiff test for now
        build-appliance-image: Update to master head revision
        bitbake: utils: Fix mkdir with PosixPath
        bitbake: runqueue: Remove tie between rqexe and starts_worker
        build-appliance-image: Update to master head revision
        testimage: Exclude wtmp from target-dumper commands
        qemurunner: Improve stdout logging handling
        qemurunner: Improve handling of serial port output blocking
        oeqa/selftest/overlayfs: Don't overwrite DISTRO_FEATURES
        testimage: Drop target_dumper and most of monitor_dumper
        oeqa/selftest/overlayfs: Fix whitespace
        qemu: Clean up DEPENDS
        qemu: Ensure pip and the python venv aren't used for meson
        curl: Disable two intermittently failing tests
        linux/cve-exclusion6.1: Update to latest kernel point release
        lib/prservice: Improve lock handling robustness
        oeqa/selftest/prservice: Improve test robustness
        scripts: Drop shell sstate-cache-management
        oeqa/selftest/sstatetests: Update sstate management script tests to python script
        curl: Disable test 1091 due to intermittent failures
        bitbake: lib/bb: Add workaround for libgcc issues with python 3.8 and 3.9
        bitbake: bitbake: Post release version bump to 2.7.0
        bitbake: siggen: Ensure version of siggen is verified
        bitbake: bitbake: Version bump for find_siginfo chanages
        sstatesig: Add version information for find_sigingfo
        sanity: Require bitbake 2.7.1

  Robert Berger (1):
        uninative-tarball.xz - reproducibility fix

  Robert Yang (5):
        gettext: Upgrade 0.22.3 -> 0.22.4
        nfs-utils: Upgrade 2.6.3 -> 2.6.4
        archiver.bbclass: Improve work-shared checking
        nfs-utils: Update Upstream-Status
        archiver.bbclass: Drop tarfile module to improve performance

  Ross Burton (23):
        avahi: update URL for new project location
        oeqa/runtime/parselogs: load ignores from disk
        oeqa/runtime/parselogs: migrate ignores
        meta-yocto-bsp/oeqa/parselogs: add BSP-specific ignores
        linux-yocto: update CVE exclusions
        genericx86: remove redundant assignments
        images: remove redundant IMAGE_BASENAME assignments
        insane: ensure more paths have the workdir removed
        tcl: skip timing-dependent tests in run-ptest
        qemurunner: remove unused import
        go: set vendor in CVE_PRODUCT
        runqemu: add qmp socket support
        linux-yocto: update CVE exclusions
        tcl: skip async and event tests in run-ptest
        images: add core-image-initramfs-boot
        machine/arch-armv9: remove crc and sve tunes, they are mandatory
        python3: re-enable profile guided optimisation
        openssl: mark assembler sections as call targets for PAC/BTI support on aarch64
        nativesdk: ensure features don't get backfilled
        nativesdk: don't unset MACHINE_FEATURES, let machine-sdk/ set it
        conf/machine-sdk: declare qemu-usermode SDK_MACHINE_FEATURE
        libseccomp: remove redundant PV assignment
        oeqa/parselogs-ignores-qemuarmv5: add comments and organise

  Saul Wold (1):
        package.py: OEHasPackage: Add MLPREFIX to packagename

  Shubham Kulkarni (1):
        tzdata: Upgrade to 2023d

  Simone Weiß (2):
        manuals: brief-yoctoprojectqs: align variable order with default local.conf
        patchtest: Add test for deprecated CVE_CHECK_IGNORE

  Soumya Sambu (1):
        ncurses: Fix - tty is hung after reset

  Sundeep KOKKONDA (1):
        rust: rustdoc reproducibility issue fix - disable PGO

  Tim Orling (12):
        python3-bcrypt: upgrade 4.0.1 -> 4.1.1
        python3-pygments: upgrade 2.16.1 -> 2.17.2
        recipetool: pypi: do not clobber SRC_URI checksums
        python3-setuptools-rust: BBCLASSEXTEND + nativesdk
        python3-maturin: add v1.4.0
        python3-maturin: bzip2-sys reproduciblility
        classes-recipe: add python_maturin.bbclass
        recipetool: add python_maturin support
        oe-selfest: add maturn runtime (testimage) test
        oeqa: add simple 'maturin' SDK (testsdk) test case
        oeqa: add "maturin develop" SDK test case
        oeqa: add runtime 'maturin develop' test case

  Tom Rini (1):
        inetutils: Update to the 2.5 release

  Trevor Gamblin (1):
        scripts/runqemu: fix regex escape sequences

  Victor Kamensky (5):
        systemtap: upgrade 4.9 -> 5.0
        systemtap: do not install uprobes and uprobes sources
        systemtap-uprobes: removed as obsolete
        systemtap: explicit handling debuginfod library dependency
        systemtap: fix libdebuginfod auto detection logic

  Vijay Anusuri (1):
        avahi: backport CVE-2023-1981 & CVE's follow-up patches

  Viswanath Kraleti (2):
        image-uefi.conf: Add EFI_UKI_PATH variable
        systemd-boot: Add recipe to compile native

  Wang Mingyu (38):
        kbd: upgrade 2.6.3 -> 2.6.4
        libatomic-ops: upgrade 7.8.0 -> 7.8.2
        libnl: upgrade 3.8.0 -> 3.9.0
        libseccomp: upgrade 2.5.4 -> 2.5.5
        libva-utils: upgrade 2.20.0 -> 2.20.1
        dnf: upgrade 4.18.1 -> 4.18.2
        gpgme: upgrade 1.23.1 -> 1.23.2
        kea: upgrade 2.4.0 -> 2.4.1
        opkg-utils: upgrade 0.6.2 -> 0.6.3
        repo: upgrade 2.39 -> 2.40
        sysstat: upgrade 12.7.4 -> 12.7.5
        p11-kit: upgrade 0.25.2 -> 0.25.3
        python3-babel: upgrade 2.13.1 -> 2.14.0
        python3-dbusmock: upgrade 0.29.1 -> 0.30.0
        python3-hatchling: upgrade 1.18.0 -> 1.20.0
        python3-hypothesis: upgrade 6.90.0 -> 6.92.1
        python3-importlib-metadata: upgrade 6.8.0 -> 7.0.0
        python3-license-expression: upgrade 30.1.1 -> 30.2.0
        python3-pathspec: upgrade 0.11.2 -> 0.12.1
        python3-pip: upgrade 23.3.1 -> 23.3.2
        python3-psutil: upgrade 5.9.6 -> 5.9.7
        python3-pytest-runner: upgrade 6.0.0 -> 6.0.1
        python3-trove-classifiers: upgrade 2023.11.22 -> 2023.11.29
        python3-typing-extensions: upgrade 4.8.0 -> 4.9.0
        python3-wcwidth: upgrade 0.2.11 -> 0.2.12
        ttyrun: upgrade 2.29.0 -> 2.30.0
        xwayland: upgrade 23.2.2 -> 23.2.3
        diffoscope: upgrade 252 -> 253
        iputils: upgrade 20221126 -> 20231222
        gstreamer1.0: upgrade 1.22.7 -> 1.22.8
        dhcpcd: upgrade 10.0.5 -> 10.0.6
        fontconfig: upgrade 2.14.2 -> 2.15.0
        python3-setuptools: upgrade 69.0.2 -> 69.0.3
        python3-dbusmock: upgrade 0.30.0 -> 0.30.1
        python3-hatchling: upgrade 1.20.0 -> 1.21.0
        python3-importlib-metadata: upgrade 7.0.0 -> 7.0.1
        python3-lxml: upgrade 4.9.3 -> 4.9.4
        aspell: upgrade 0.60.8 -> 0.60.8.1

  Yash Shinde (1):
        rust: Disable rust oe-selftest

  Yi Zhao (3):
        json-glib: upgrade 1.6.6 -> 1.8.0
        psplash: upgrade to latest revision
        debianutils: upgrade 5.14 -> 5.15

  Yoann Congal (2):
        lib/oe/patch: handle creating patches for CRLF sources
        strace: Disable bluetooth support by default

  Zang Ruochen (2):
        ell: upgrade 0.60 -> 0.61
        musl: add typedefs for Elf64_Relr and Elf32_Relr

  Zoltan Boszormenyi (1):
        update_gtk_icon_cache: Fix for GTK4-only builds

  venkata pyla (1):
        wic: use E2FSPROGS_FAKE_TIME and hash_seed to generate reproducible ext4 images

meta-openembedded: 5ad7203f68..7d8115d550:
  Alex Kiernan (7):
        mdns: Fix HOMEPAGE URL
        mbedtls: Upgrade 3.5.0 -> 3.5.1
        c-ares: Upgrade 1.22.1 -> 1.24.0
        mdns: Upgrade 2200.40.37.0.1 -> 2200.60.25.0.4
        c-ares: Move to tarballs, add ptest and static support
        thin-provisioning-tools: Upgrade 1.0.4 -> 1.0.9
        bearssl: Upgrade to latest

  Alexander Kanavin (29):
        python3-pyinotify: remove as unmaintained
        python3-supervisor: do not rely on smtpd module
        python3-meld3: do not rely on smtpd module
        python3-m2crypto: do not rely on smtpd module
        python3-uinput: remove as unmaintained
        python3-mcrypto: rely on setuptools for distutils copy
        python3-joblib: do not rely in distutils
        python3-web3: remove distutils dependency
        python3-cppy: remove unused distutils dependency
        python3-pyroute2: remove unused distutils dependency
        python3-eventlet: backport a patch to remove distutils dependency
        python3-unoconv: rely on setuptools to obtain distutils copy
        python3-astroid: remove unneeded distutils dependency
        python3-django: remove unneeded distutils dependency
        python3-pillow: remove unneeded distutils dependency
        python3-grpcio: update 1.56.2 -> 1.59.3
        gstd: correctly delete files in do_install
        libplist: fix python 3.12 compatibility
        libcamera: skip until upstream resolves python 3.12 compatibility
        nodejs: backport (partially) python 3.12 support
        nodejs: backport (partially) python 3.12 support
        polkit: remove long obsolete 0.119 version
        mozjs-115: split the way-too-long PYTHONPATH line
        polkit: update mozjs dependency 102 -> 115
        mozjs-115: backport py 3.12 compatibility
        mozjs-102: remove the recipe
        gthumb: update 3.12.2 -> 3.12.4
        flatpak: do not rely on executables from the host
        bolt: package systemd units

  Archana Polampalli (1):
        cjson: upgrade 1.7.16 -> 1.7.17

  Bruce Ashfield (1):
        zfs: update to 2.2.2

  Changqing Li (2):
        postgresql: upgrade 15.4 -> 15.5
        redis: upgrade 6.2.13 -> 6.2.14

  Derek Straka (70):
        python3-greenlet: update to version 3.0.2
        python3-ujson: update to version 5.9.0
        python3-termcolor: update to version 2.4.0
        python3-cmake: update to version 3.28.0
        python3-pint: upgrade to 0.23
        python3-gnupg: update to 0.5.2
        python3-pyzmq: update to 25.1.2
        python3-tox: update to version 4.11.4
        python3-olefile: update to version 0.47
        python3-distlib: update to version 0.3.8
        python3-colorlog: update to version 6.8.0
        python3-pymongo: update version to 4.6.1
        python3-bandit: update to version 1.7.6
        python3-gmqtt: update to version 0.6.13
        python3-portion: update to version 2.4.2
        python3-prompt-toolkit: update to version 3.0.43
        python3-asyncinotify: update to version 4.0.4
        python3-bitstring: update to version 4.1.4
        python3-ipython: update to version 8.18.1
        nginx: update versions for both the stable branch and mainline
        python3-portalocker: update to version 2.8.2
        python3-astroid: update to version 3.0.2
        python3-alembic: update to version 1.13.1
        python3-pymisp: update to verion 2.4.182
        python3-ninja: update to version 1.11.1.1
        python3-coverage: update to version 7.3.4
        python3-pdm: update to version 2.11.1
        python3-paramiko: update to version 3.4.0
        python3-zeroconf: update to version 0.131.0
        python3-wtforms: update to version 3.1.1
        python3-isort: update to version 5.13.2
        python3-protobuf: update to version 4.25.1
        python3-lazy-object-proxy: update to version 1.10.0
        python3-cantools: update to version 39.4.0
        python3-sentry-sdk: update to version 1.39.1
        python3-xmlschema: update to version 2.5.1
        python3-apiflask: update to version 2.1.0
        python3-rapidjson: update to version 1.14
        python3-bitarray: update to version 2.9.0
        python3-pyfanotify: update to version 0.2.2
        python3-eventlet: update to version 0.34.1
        python3-flask-wtf: update to version 1.2.1
        python3-grpcio: update to version 1.60.0
        python3-grpcio-tools: update to version 1.60.0
        python3-cmake: update to version 3.28.1
        python3-flask-sqlalchemy: fix upstream uri check
        python3-wtforms: fix upstream uri and version check
        gyp: update to the latest commit
        python3-ipython-genutils: fix upstream uri and version check
        python3-flask: fix upstream uri and version check
        python3-wpa-supplicant: fix upstream uri and version check
        python3-uswid: update to version 0.4.7
        python3-flask-wtf: fix upstream uri and version check
        python3-gspread: update to version 5.12.3
        python3-pytest-html: update to version 4.1.1
        python3-setuptools-scm-git-archive: remove obsolete package
        python3-pyroute2: update to version 0.7.10
        python3-constantly: update to version 23.10.4
        python3-mypy: update to version 1.8.0
        python3-flask-jwt-extended: update to version 4.6.0
        python3-greenlet: update to version 3.0.3
        python3-web3: update to version 6.13.0
        python3-parse: update to version 1.20.0
        python3-kmod: add comment about update to version 0.9.2
        python3-engineio: update to version 4.8.1
        python3-sqlalchemy: update to version 2.0.24
        python3-pdm-backend: update to version 2.1.8
        python3-cantools: update to version 39.4.1
        python3-argh: update to version 0.30.5
        python3-dominate: update to version 2.9.1

  Dmitry Baryshkov (2):
        android-tools: remove two Debianisms
        networkmanager: drop libnewt dependency

  Frederic Martinsons (3):
        crash: factorize recipe with inc file to prepare cross-canadian version
        crash: add cross canadian version
        crash: update to 8.0.4

  Jan Vermaete (1):
        netdata: added Python as rdepends

  Jean-Marc BOUCHE (1):
        terminus-font: build compressed archives with -n

  Jose Quaresma (1):
        ostree: Upgrade 2023.7 -> 2023.8

  Joshua Watt (1):
        redis: Create state directory in systemd service

  Jörg Sommer (1):
        i2cdev: New recipe with i2c tools

  Kai Kang (1):
        lvm2: 2.03.16 -> 2.03.22

  Khem Raj (3):
        Revert "nodejs: backport (partially) python 3.12 support"
        Revert "libcamera: skip until upstream resolves python 3.12 compatibility"
        libcamera: Fix build with python 3.12

  Leon Anavi (11):
        sip: Upgrade 6.7.12 -> 6.8.0
        python3-expandvars: add recipe
        python3-frozenlist: upgrade 1.4.0 -> 1.4.1
        python3-yarl: upgrade 1.9.2 -> 1.9.4
        python3-coverage: upgrade 7.3.2 -> 7.3.3
        python3-cycler: upgrade 0.11.0 -> 0.12.1
        python3-aiohue: upgrade 4.6.2 -> 4.7.0
        python3-sdbus: upgrade 0.11.0 -> 0.11.1
        python3-zeroconf: upgrade 0.128.4 -> 0.130.0
        python3-dominate: upgrade 2.8.0 -> 2.9.0
        python3-rlp: upgrade 3.0.0 -> 4.0.0

  Marek Vasut (1):
        faad2: Upgrade 2.10.0 -> 2.11.1

  Markus Volk (3):
        wireplumber: update 0.4.15 -> 0.4.17
        tracker: dont inherit gsettings
        gnome-software: update 45.1 -> 45.2

  Martin Jansa (4):
        monocypher: pass LIBDIR to fix installed-vs-shipped QA issue with multilib
        rygel: fix build with gtk+3 PACKAGECONFIG disabled
        rygel: add x11 to DISTRO_FEATURES
        driverctl: fix installed-vs-shipped

  Meenali Gupta (1):
        nginx: upgrade 1.25.2 -> 1.25.3

  Mingli Yu (2):
        mariadb: Upgrade to 10.11.6
        tk: Remove buildpath issue

  Nathan BRIENT (1):
        cyaml: new recipe

  Niko Mauno (1):
        pkcs11-provider: Add recipe

  Ny Antra Ranaivoarison (1):
        python3-click-spinner: backport patch that fixes deprecated methods

  Patrick Wicki (1):
        poco: upgrade 1.12.4 -> 1.12.5p2

  Petr Chernikov (1):
        abseil-cpp: remove -Dcmake_cxx_standard=14 flag from extra_oecmake

  Robert Yang (1):
        minifi-cpp: Fix do_configure error builder aarch64

  Ross Burton (13):
        Remove unused SRC_DISTRIBUTE_LICENSES
        gspell: inherit gtk-doc
        gspell: update DEPENDS, switch iso-codes for icu
        librest: remove spurious build dependencies
        librest: inherit gtk-doc
        keybinder: use autotools-brokensep instead of setting B
        keybinder: disable gtk-doc documentation
        gtksourceview3: remove obsolete DEPENDS
        libgsf: remove obsolete DEPENDS
        evolution-data-server: remove obsolete intltool DEPENDS
        php: remove lemon-native build dependency
        lemon: upgrade to 3.44.2
        renderdoc: no need to depend on vim-native

  Samuli Piippo (1):
        jasper: enable opengl only wih x11

  Theodore A. Roth (1):
        python3-flask-sqlalchemy: upgrade 2.5.1 -> 3.1.1

  Thomas Perrot (2):
        networkmanager: add missing modemmanager rdepends
        networkmanager: fix some missing pkgconfig

  Tim Orling (8):
        python3-pydantic-core: add v2.14.5
        python3-annotated-types: add v0.6.0
        python3-pydantic: fix RDEPENDS
        python3-dirty-equals: add v0.7.1
        python3-pydantic-core: enable ptest
        python3-cloudpickle: add v3.0.0
        python3-pydantic: enable ptest
        python3-yappi: upgrade 1.4.0 -> 1.6.0; fix ptests

  Wang Mingyu (61):
        python3-alembic: upgrade 1.12.1 -> 1.13.0
        python3-ansi2html: upgrade 1.8.0 -> 1.9.1
        python3-argcomplete: upgrade 3.1.6 -> 3.2.1
        python3-dbus-fast: upgrade 2.15.0 -> 2.21.0
        python3-django: upgrade 4.2.7 -> 5.0
        python3-flask-restx: upgrade 1.2.0 -> 1.3.0
        python3-google-api-core: upgrade 2.14.0 -> 2.15.0
        python3-google-api-python-client: upgrade 2.108.0 -> 2.111.0
        python3-googleapis-common-protos: upgrade 1.61.0 -> 1.62.0
        python3-google-auth: upgrade 2.23.4 -> 2.25.2
        python3-imageio: upgrade 2.33.0 -> 2.33.1
        python3-isort: upgrade 5.12.0 -> 5.13.1
        python3-path: upgrade 16.7.1 -> 16.9.0
        python3-platformdirs: upgrade 4.0.0 -> 4.1.0
        python3-pytest-asyncio: upgrade 0.22.0 -> 0.23.2
        python3-sentry-sdk: upgrade 1.37.1 -> 1.39.0
        python3-bitarray: upgrade 2.8.3 -> 2.8.5
        python3-eth-keyfile: upgrade 0.6.1 -> 0.7.0
        python3-eth-rlp: upgrade 0.3.0 -> 1.0.0
        python3-fastnumbers: upgrade 5.0.1 -> 5.1.0
        python3-pylint: upgrade 3.0.2 -> 3.0.3
        python3-tornado: upgrade 6.3.3 -> 6.4
        python3-traitlets: upgrade 5.13.0 -> 5.14.0
        python3-types-setuptools: upgrade 68.2.0.2 -> 69.0.0.0
        python3-virtualenv: upgrade 20.24.7 -> 20.25.0
        python3-web3: upgrade 6.11.3 -> 6.12.0
        python3-websocket-client: upgrade 1.6.4 -> 1.7.0
        python3-zeroconf: upgrade 0.127.0 -> 0.128.4
        ctags: upgrade 6.0.20231126.0 -> 6.0.20231210.0
        gensio: upgrade 2.8.0 -> 2.8.2
        hwdata: upgrade 0.376 -> 0.377
        lvgl: upgrade 8.3.10 -> 8.3.11
        gjs: upgrade 1.78.0 -> 1.78.1
        ifenslave: upgrade 2.13 -> 2.14
        libei: upgrade 1.1.0 -> 1.2.0
        pkcs11-helper: upgrade 1.29.0 -> 1.30.0
        strongswan: upgrade 5.9.12 -> 5.9.13
        webkitgtk3: upgrade 2.42.2 -> 2.42.3
        sip: upgrade 6.8.0 -> 6.8.1
        paho-mqtt-cpp: upgrade 1.3.1 -> 1.3.2
        dbus-cxx: upgrade 2.4.0 -> 2.5.0
        exiftool: upgrade 12.70 -> 12.71
        uftp: upgrade 5.0.2 -> 5.0.3
        ctags: upgrade 6.0.20231210.0 -> 6.0.20231224.0
        jasper: Fix install conflict when enable multilib.
        jq: upgrade 1.7 -> 1.7.1
        libmbim: upgrade 1.31.1 -> 1.31.2
        libqmi: upgrade 1.34.0 -> 1.35.1
        opencl-headers: upgrade 2023.04.17 -> 2023.12.14
        valijson: upgrade 1.0.1 -> 1.0.2
        python3-apispec: upgrade 6.3.0 -> 6.3.1
        python3-asyncinotify: upgrade 4.0.4 -> 4.0.5
        python3-bitarray: upgrade 2.9.0 -> 2.9.1
        python3-cassandra-driver: upgrade 3.28.0 -> 3.29.0
        python3-ipython: upgrade 8.18.1 -> 8.19.0
        python3-pydantic: upgrade 2.5.2 -> 2.5.3
        python3-regex: upgrade 2023.10.3 -> 2023.12.25
        opencl-icd-loader: upgrade 2023.04.17 -> 2023.12.14
        python3-distro: upgrade 1.8.0 -> 1.9.0
        zchunk: upgrade 1.3.2 -> 1.4.0
        python3-eventlet: upgrade 0.34.1 -> 0.34.2

  William Lyu (1):
        networkmanager: Improved SUMMARY and added DESCRIPTION

  Xiangyu Chen (1):
        layer.conf: add libbpf to NON_MULTILIB_RECIPES

  Yi Zhao (2):
        open-vm-tools: upgrade 12.1.5 -> 12.3.5
        samba: upgrade 4.18.8 -> 4.18.9

  Zoltán Böszörményi (2):
        mutter: Make gnome-desktop and libcanberra dependencies optional
        zenity: Upgrade to 4.0.0

  alperak (29):
        jasper: upgrade 2.0.33 -> 4.1.1
        xcursorgen: upgrade 1.0.7 -> 1.0.8
        xstdcmap: upgrade 1.0.4 -> 1.0.5
        xlsclients: upgrade 1.1.4 -> 1.1.5
        xlsatoms: upgrade 1.1.3 -> 1.1.4
        xkbevd: upgrade 1.1.4 -> 1.1.5
        xgamma: upgrade 1.0.6 -> 1.0.7
        sessreg: upgrade 1.1.2 -> 1.1.3
        xbitmaps: upgrade 1.1.2 -> 1.1.3
        xcursor-themes: add recipe
        xorg-docs: add recipe
        xorg-sgml-doctools: update summary depends and inc file
        xf86-video-ati: upgrade 19.1.0 -> 22.0.0
        xf86-input-void: upgrade 1.4.1 -> 1.4.2
        libxaw: upgrade 1.0.14 -> 1.0.15
        xf86-video-mga: upgrade 2.0.0 -> 2.0.1
        snappy: upgrade 1.1.9 -> 1.1.10
        xsetroot: upgrade 1.1.2 -> 1.1.3
        libbytesize: Removed unnecessary setting of B
        libmxml: use autotools-brokensep instead of setting B
        libsombok3: use autotools-brokensep instead of setting B
        pgpool2: use autotools-brokensep instead of setting B
        qpdf: upgrade 11.6.3 -> 11.6.4
        cpprest: upgrade 2.10.18 -> 2.10.19
        avro-c: upgrade 1.11.2 -> 1.11.3
        dool: upgrade 1.1.0 -> 1.3.1
        driverctl: upgrade 0.111 -> 0.115
        hstr: upgrade 2.5.0 -> 3.1.0
        libharu: upgrade 2.3.0 -> 2.4.4

meta-security: 070a1e82cc..b2e1511338:
  Armin Kuster (6):
        libgssglue: update to 0.8
        python3-privacyidea: Update to 3.9.1
        lynis: Update SRC_URI to improve updater
        layers: Move READMEs to markdown format
        arpwatch: adjust CONFIGURE params to allow to build again.
        python3-pyinotify: fail2ban needs this module

  Dawid Dabrowski (1):
        libhoth recipe update

  Erik Schilling (2):
        dm-verity-img.bbclass: use bc-native
        dm-verity-img.bbclass: remove IMAGE_NAME_SUFFIX

  Mikko Rapeli (2):
        tpm2-tss: support native builds
        dm-verity-img.bbclass: add DM_VERITY_DEPLOY_DIR

Change-Id: I94d7f1ee5ff2da4555c05fbf63a1293ec8f249c2
Signed-off-by: Patrick Williams <patrick@stwcx.xyz>
diff --git a/meta-openembedded/meta-python/recipes-devtools/python/python3-yappi/0001-test_functionality-convert-line-endings-to-Unix.patch b/meta-openembedded/meta-python/recipes-devtools/python/python3-yappi/0001-test_functionality-convert-line-endings-to-Unix.patch
new file mode 100644
index 0000000..70d4607
--- /dev/null
+++ b/meta-openembedded/meta-python/recipes-devtools/python/python3-yappi/0001-test_functionality-convert-line-endings-to-Unix.patch
@@ -0,0 +1,3845 @@
+From 0136ca731cba8b056b3f2ff0e7df3953b94f1e87 Mon Sep 17 00:00:00 2001
+From: Tim Orling <tim.orling@konsulko.com>
+Date: Sun, 24 Dec 2023 09:41:57 -0800
+Subject: [PATCH 1/2] test_functionality: convert line endings to Unix
+
+Convert the Windows line endings with dos2unix to be like the
+other files in tests/*
+
+Upstream-Status: Submitted [https://github.com/sumerc/yappi/pull/164]
+
+Signed-off-by: Tim Orling <tim.orling@konsulko.com>
+---
+ tests/test_functionality.py | 3822 +++++++++++++++++------------------
+ 1 file changed, 1911 insertions(+), 1911 deletions(-)
+
+diff --git a/tests/test_functionality.py b/tests/test_functionality.py
+index 0e99c47..38bbe67 100644
+--- a/tests/test_functionality.py
++++ b/tests/test_functionality.py
+@@ -1,1911 +1,1911 @@
+-import os

+-import sys

+-import time

+-import threading

+-import unittest

+-import yappi

+-import _yappi

+-import utils

+-import multiprocessing

+-import subprocess

+-

+-_counter = 0

+-

+-

+-class BasicUsage(utils.YappiUnitTestCase):

+-

+-    def test_callback_function_int_return_overflow(self):

+-        # this test is just here to check if any errors are generated, as the err

+-        # is printed in C side, I did not include it here. THere are ways to test

+-        # this deterministically, I did not bother

+-        import ctypes

+-

+-        def _unsigned_overflow_margin():

+-            return 2**(ctypes.sizeof(ctypes.c_void_p) * 8) - 1

+-

+-        def foo():

+-            pass

+-

+-        #with utils.captured_output() as (out, err):

+-        yappi.set_context_id_callback(_unsigned_overflow_margin)

+-        yappi.set_tag_callback(_unsigned_overflow_margin)

+-        yappi.start()

+-        foo()

+-

+-    def test_issue60(self):

+-

+-        def foo():

+-            buf = bytearray()

+-            buf += b't' * 200

+-            view = memoryview(buf)[10:]

+-            view = view.tobytes()

+-            del buf[:10]  # this throws exception

+-            return view

+-

+-        yappi.start(builtins=True)

+-        foo()

+-        self.assertTrue(

+-            len(

+-                yappi.get_func_stats(

+-                    filter_callback=lambda x: yappi.

+-                    func_matches(x, [memoryview.tobytes])

+-                )

+-            ) > 0

+-        )

+-        yappi.stop()

+-

+-    def test_issue54(self):

+-

+-        def _tag_cbk():

+-            global _counter

+-            _counter += 1

+-            return _counter

+-

+-        def a():

+-            pass

+-

+-        def b():

+-            pass

+-

+-        yappi.set_tag_callback(_tag_cbk)

+-        yappi.start()

+-        a()

+-        a()

+-        a()

+-        yappi.stop()

+-        stats = yappi.get_func_stats()

+-        self.assertEqual(stats.pop().ncall, 3)  # aggregated if no tag is given

+-        stats = yappi.get_func_stats(tag=1)

+-

+-        for i in range(1, 3):

+-            stats = yappi.get_func_stats(tag=i)

+-            stats = yappi.get_func_stats(

+-                tag=i, filter_callback=lambda x: yappi.func_matches(x, [a])

+-            )

+-

+-            stat = stats.pop()

+-            self.assertEqual(stat.ncall, 1)

+-

+-        yappi.set_tag_callback(None)

+-        yappi.clear_stats()

+-        yappi.start()

+-        b()

+-        b()

+-        stats = yappi.get_func_stats()

+-        self.assertEqual(len(stats), 1)

+-        stat = stats.pop()

+-        self.assertEqual(stat.ncall, 2)

+-

+-    def test_filter(self):

+-

+-        def a():

+-            pass

+-

+-        def b():

+-            a()

+-

+-        def c():

+-            b()

+-

+-        _TCOUNT = 5

+-

+-        ts = []

+-        yappi.start()

+-        for i in range(_TCOUNT):

+-            t = threading.Thread(target=c)

+-            t.start()

+-            ts.append(t)

+-

+-        for t in ts:

+-            t.join()

+-

+-        yappi.stop()

+-

+-        ctx_ids = []

+-        for tstat in yappi.get_thread_stats():

+-            if tstat.name == '_MainThread':

+-                main_ctx_id = tstat.id

+-            else:

+-                ctx_ids.append(tstat.id)

+-

+-        fstats = yappi.get_func_stats(filter={"ctx_id": 9})

+-        self.assertTrue(fstats.empty())

+-        fstats = yappi.get_func_stats(

+-            filter={

+-                "ctx_id": main_ctx_id,

+-                "name": "c"

+-            }

+-        )  # main thread

+-        self.assertTrue(fstats.empty())

+-

+-        for i in ctx_ids:

+-            fstats = yappi.get_func_stats(

+-                filter={

+-                    "ctx_id": i,

+-                    "name": "a",

+-                    "ncall": 1

+-                }

+-            )

+-            self.assertEqual(fstats.pop().ncall, 1)

+-            fstats = yappi.get_func_stats(filter={"ctx_id": i, "name": "b"})

+-            self.assertEqual(fstats.pop().ncall, 1)

+-            fstats = yappi.get_func_stats(filter={"ctx_id": i, "name": "c"})

+-            self.assertEqual(fstats.pop().ncall, 1)

+-

+-        yappi.clear_stats()

+-        yappi.start(builtins=True)

+-        time.sleep(0.1)

+-        yappi.stop()

+-        fstats = yappi.get_func_stats(filter={"module": "time"})

+-        self.assertEqual(len(fstats), 1)

+-

+-        # invalid filters`

+-        self.assertRaises(

+-            Exception, yappi.get_func_stats, filter={'tag': "sss"}

+-        )

+-        self.assertRaises(

+-            Exception, yappi.get_func_stats, filter={'ctx_id': "None"}

+-        )

+-

+-    def test_filter_callback(self):

+-

+-        def a():

+-            time.sleep(0.1)

+-

+-        def b():

+-            a()

+-

+-        def c():

+-            pass

+-

+-        def d():

+-            pass

+-

+-        yappi.set_clock_type("wall")

+-        yappi.start(builtins=True)

+-        a()

+-        b()

+-        c()

+-        d()

+-        stats = yappi.get_func_stats(

+-            filter_callback=lambda x: yappi.func_matches(x, [a, b])

+-        )

+-        #stats.print_all()

+-        r1 = '''

+-        tests/test_functionality.py:98 a      2      0.000000  0.200350  0.100175

+-        tests/test_functionality.py:101 b     1      0.000000  0.120000  0.100197

+-        '''

+-        self.assert_traces_almost_equal(r1, stats)

+-        self.assertEqual(len(stats), 2)

+-        stats = yappi.get_func_stats(

+-            filter_callback=lambda x: yappi.

+-            module_matches(x, [sys.modules[__name__]])

+-        )

+-        r1 = '''

+-        tests/test_functionality.py:98 a      2      0.000000  0.230130  0.115065

+-        tests/test_functionality.py:101 b     1      0.000000  0.120000  0.109011

+-        tests/test_functionality.py:104 c     1      0.000000  0.000002  0.000002

+-        tests/test_functionality.py:107 d     1      0.000000  0.000001  0.000001

+-        '''

+-        self.assert_traces_almost_equal(r1, stats)

+-        self.assertEqual(len(stats), 4)

+-

+-        stats = yappi.get_func_stats(

+-            filter_callback=lambda x: yappi.func_matches(x, [time.sleep])

+-        )

+-        self.assertEqual(len(stats), 1)

+-        r1 = '''

+-        time.sleep                            2      0.206804  0.220000  0.103402

+-        '''

+-        self.assert_traces_almost_equal(r1, stats)

+-

+-    def test_print_formatting(self):

+-

+-        def a():

+-            pass

+-

+-        def b():

+-            a()

+-

+-        func_cols = {

+-            1: ("name", 48),

+-            0: ("ncall", 5),

+-            2: ("tsub", 8),

+-        }

+-        thread_cols = {

+-            1: ("name", 48),

+-            0: ("ttot", 8),

+-        }

+-

+-        yappi.start()

+-        a()

+-        b()

+-        yappi.stop()

+-        fs = yappi.get_func_stats()

+-        cs = fs[1].children

+-        ts = yappi.get_thread_stats()

+-        #fs.print_all(out=sys.stderr, columns={1:("name", 70), })

+-        #cs.print_all(out=sys.stderr, columns=func_cols)

+-        #ts.print_all(out=sys.stderr, columns=thread_cols)

+-        #cs.print_all(out=sys.stderr, columns={})

+-

+-        self.assertRaises(

+-            yappi.YappiError, fs.print_all, columns={1: ("namee", 9)}

+-        )

+-        self.assertRaises(

+-            yappi.YappiError, cs.print_all, columns={1: ("dd", 0)}

+-        )

+-        self.assertRaises(

+-            yappi.YappiError, ts.print_all, columns={1: ("tidd", 0)}

+-        )

+-

+-    def test_get_clock(self):

+-        yappi.set_clock_type('cpu')

+-        self.assertEqual('cpu', yappi.get_clock_type())

+-        clock_info = yappi.get_clock_info()

+-        self.assertTrue('api' in clock_info)

+-        self.assertTrue('resolution' in clock_info)

+-

+-        yappi.set_clock_type('wall')

+-        self.assertEqual('wall', yappi.get_clock_type())

+-

+-        t0 = yappi.get_clock_time()

+-        time.sleep(0.1)

+-        duration = yappi.get_clock_time() - t0

+-        self.assertTrue(0.05 < duration < 0.3)

+-

+-    def test_profile_decorator(self):

+-

+-        def aggregate(func, stats):

+-            fname = f"tests/{func.__name__}.profile"

+-            try:

+-                stats.add(fname)

+-            except OSError:

+-                pass

+-            stats.save(fname)

+-            raise Exception("messing around")

+-

+-        @yappi.profile(return_callback=aggregate)

+-        def a(x, y):

+-            if x + y == 25:

+-                raise Exception("")

+-            return x + y

+-

+-        def b():

+-            pass

+-

+-        try:

+-            os.remove(

+-                "tests/a.profile"

+-            )  # remove the one from prev test, if available

+-        except:

+-            pass

+-

+-        # global profile is on to mess things up

+-        yappi.start()

+-        b()

+-

+-        # assert functionality and call function at same time

+-        try:

+-            self.assertEqual(a(1, 2), 3)

+-        except:

+-            pass

+-        try:

+-            self.assertEqual(a(2, 5), 7)

+-        except:

+-            pass

+-        try:

+-            a(4, 21)

+-        except:

+-            pass

+-        stats = yappi.get_func_stats().add("tests/a.profile")

+-        fsa = utils.find_stat_by_name(stats, 'a')

+-        self.assertEqual(fsa.ncall, 3)

+-        self.assertEqual(len(stats), 1)  # b() should be cleared out.

+-

+-        @yappi.profile(return_callback=aggregate)

+-        def count_down_rec(n):

+-            if n == 0:

+-                return

+-            count_down_rec(n - 1)

+-

+-        try:

+-            os.remove(

+-                "tests/count_down_rec.profile"

+-            )  # remove the one from prev test, if available

+-        except:

+-            pass

+-

+-        try:

+-            count_down_rec(4)

+-        except:

+-            pass

+-        try:

+-            count_down_rec(3)

+-        except:

+-            pass

+-

+-        stats = yappi.YFuncStats("tests/count_down_rec.profile")

+-        fsrec = utils.find_stat_by_name(stats, 'count_down_rec')

+-        self.assertEqual(fsrec.ncall, 9)

+-        self.assertEqual(fsrec.nactualcall, 2)

+-

+-    def test_strip_dirs(self):

+-

+-        def a():

+-            pass

+-

+-        stats = utils.run_and_get_func_stats(a, )

+-        stats.strip_dirs()

+-        fsa = utils.find_stat_by_name(stats, "a")

+-        self.assertEqual(fsa.module, os.path.basename(fsa.module))

+-

+-    @unittest.skipIf(os.name == "nt", "do not run on Windows")

+-    def test_run_as_script(self):

+-        import re

+-        p = subprocess.Popen(

+-            ['yappi', os.path.join('./tests', 'run_as_script.py')],

+-            stdout=subprocess.PIPE

+-        )

+-        out, err = p.communicate()

+-        self.assertEqual(p.returncode, 0)

+-        func_stats, thread_stats = re.split(

+-            b'name\\s+id\\s+tid\\s+ttot\\s+scnt\\s*\n', out

+-        )

+-        self.assertTrue(b'FancyThread' in thread_stats)

+-

+-    def test_yappi_overhead(self):

+-        LOOP_COUNT = 100000

+-

+-        def a():

+-            pass

+-

+-        def b():

+-            for i in range(LOOP_COUNT):

+-                a()

+-

+-        t0 = time.time()

+-        yappi.start()

+-        b()

+-        yappi.stop()

+-        time_with_yappi = time.time() - t0

+-        t0 = time.time()

+-        b()

+-        time_without_yappi = time.time() - t0

+-        if time_without_yappi == 0:

+-            time_without_yappi = 0.000001

+-

+-        # in latest v0.82, I calculated this as close to "7.0" in my machine.

+-        # however, %83 of this overhead is coming from tickcount(). The other %17

+-        # seems to have been evenly distributed to the internal bookkeeping

+-        # structures/algorithms which seems acceptable. Note that our test only

+-        # tests one function being profiled at-a-time in a short interval.

+-        # profiling high number of functions in a small time

+-        # is a different beast, (which is pretty unlikely in most applications)

+-        # So as a conclusion: I cannot see any optimization window for Yappi that

+-        # is worth implementing as we will only optimize %17 of the time.

+-        sys.stderr.write("\r\nYappi puts %0.1f times overhead to the profiled application in average.\r\n" % \

+-            (time_with_yappi / time_without_yappi))

+-

+-    def test_clear_stats_while_running(self):

+-

+-        def a():

+-            pass

+-

+-        yappi.start()

+-        a()

+-        yappi.clear_stats()

+-        a()

+-        stats = yappi.get_func_stats()

+-        fsa = utils.find_stat_by_name(stats, 'a')

+-        self.assertEqual(fsa.ncall, 1)

+-

+-    def test_generator(self):

+-

+-        def _gen(n):

+-            while (n > 0):

+-                yield n

+-                n -= 1

+-

+-        yappi.start()

+-        for x in _gen(5):

+-            pass

+-        self.assertTrue(

+-            yappi.convert2pstats(yappi.get_func_stats()) is not None

+-        )

+-

+-    def test_slice_child_stats_and_strip_dirs(self):

+-

+-        def b():

+-            for i in range(10000000):

+-                pass

+-

+-        def a():

+-            b()

+-

+-        yappi.start(builtins=True)

+-        a()

+-        stats = yappi.get_func_stats()

+-        fsa = utils.find_stat_by_name(stats, 'a')

+-        fsb = utils.find_stat_by_name(stats, 'b')

+-        self.assertTrue(fsa.children[0:1] is not None)

+-        prev_afullname = fsa.full_name

+-        prev_bchildfullname = fsa.children[fsb].full_name

+-        stats.strip_dirs()

+-        self.assertTrue(len(prev_afullname) > len(fsa.full_name))

+-        self.assertTrue(

+-            len(prev_bchildfullname) > len(fsa.children[fsb].full_name)

+-        )

+-

+-    def test_children_stat_functions(self):

+-        _timings = {"a_1": 5, "b_1": 3, "c_1": 1}

+-        _yappi._set_test_timings(_timings)

+-

+-        def b():

+-            pass

+-

+-        def c():

+-            pass

+-

+-        def a():

+-            b()

+-            c()

+-

+-        yappi.start()

+-        a()

+-        b()  # non-child call

+-        c()  # non-child call

+-        stats = yappi.get_func_stats()

+-        fsa = utils.find_stat_by_name(stats, 'a')

+-        childs_of_a = fsa.children.get().sort("tavg", "desc")

+-        prev_item = None

+-        for item in childs_of_a:

+-            if prev_item:

+-                self.assertTrue(prev_item.tavg > item.tavg)

+-            prev_item = item

+-        childs_of_a.sort("name", "desc")

+-        prev_item = None

+-        for item in childs_of_a:

+-            if prev_item:

+-                self.assertTrue(prev_item.name > item.name)

+-            prev_item = item

+-        childs_of_a.clear()

+-        self.assertTrue(childs_of_a.empty())

+-

+-    def test_no_stats_different_clock_type_load(self):

+-

+-        def a():

+-            pass

+-

+-        yappi.start()

+-        a()

+-        yappi.stop()

+-        yappi.get_func_stats().save("tests/ystats1.ys")

+-        yappi.clear_stats()

+-        yappi.set_clock_type("WALL")

+-        yappi.start()

+-        yappi.stop()

+-        stats = yappi.get_func_stats().add("tests/ystats1.ys")

+-        fsa = utils.find_stat_by_name(stats, 'a')

+-        self.assertTrue(fsa is not None)

+-

+-    def test_subsequent_profile(self):

+-        _timings = {"a_1": 1, "b_1": 1}

+-        _yappi._set_test_timings(_timings)

+-

+-        def a():

+-            pass

+-

+-        def b():

+-            pass

+-

+-        yappi.start()

+-        a()

+-        yappi.stop()

+-        yappi.start()

+-        b()

+-        yappi.stop()

+-        stats = yappi.get_func_stats()

+-        fsa = utils.find_stat_by_name(stats, 'a')

+-        fsb = utils.find_stat_by_name(stats, 'b')

+-        self.assertTrue(fsa is not None)

+-        self.assertTrue(fsb is not None)

+-        self.assertEqual(fsa.ttot, 1)

+-        self.assertEqual(fsb.ttot, 1)

+-

+-    def test_lambda(self):

+-        f = lambda: time.sleep(0.3)

+-        yappi.set_clock_type("wall")

+-        yappi.start()

+-        f()

+-        stats = yappi.get_func_stats()

+-        fsa = utils.find_stat_by_name(stats, '<lambda>')

+-        self.assertTrue(fsa.ttot > 0.1)

+-

+-    def test_module_stress(self):

+-        self.assertEqual(yappi.is_running(), False)

+-

+-        yappi.start()

+-        yappi.clear_stats()

+-        self.assertRaises(_yappi.error, yappi.set_clock_type, "wall")

+-

+-        yappi.stop()

+-        yappi.clear_stats()

+-        yappi.set_clock_type("cpu")

+-        self.assertRaises(yappi.YappiError, yappi.set_clock_type, "dummy")

+-        self.assertEqual(yappi.is_running(), False)

+-        yappi.clear_stats()

+-        yappi.clear_stats()

+-

+-    def test_stat_sorting(self):

+-        _timings = {"a_1": 13, "b_1": 10, "a_2": 6, "b_2": 1}

+-        _yappi._set_test_timings(_timings)

+-

+-        self._ncall = 1

+-

+-        def a():

+-            b()

+-

+-        def b():

+-            if self._ncall == 2:

+-                return

+-            self._ncall += 1

+-            a()

+-

+-        stats = utils.run_and_get_func_stats(a)

+-        stats = stats.sort("totaltime", "desc")

+-        prev_stat = None

+-        for stat in stats:

+-            if prev_stat:

+-                self.assertTrue(prev_stat.ttot >= stat.ttot)

+-            prev_stat = stat

+-        stats = stats.sort("totaltime", "asc")

+-        prev_stat = None

+-        for stat in stats:

+-            if prev_stat:

+-                self.assertTrue(prev_stat.ttot <= stat.ttot)

+-            prev_stat = stat

+-        stats = stats.sort("avgtime", "asc")

+-        prev_stat = None

+-        for stat in stats:

+-            if prev_stat:

+-                self.assertTrue(prev_stat.tavg <= stat.tavg)

+-            prev_stat = stat

+-        stats = stats.sort("name", "asc")

+-        prev_stat = None

+-        for stat in stats:

+-            if prev_stat:

+-                self.assertTrue(prev_stat.name <= stat.name)

+-            prev_stat = stat

+-        stats = stats.sort("subtime", "asc")

+-        prev_stat = None

+-        for stat in stats:

+-            if prev_stat:

+-                self.assertTrue(prev_stat.tsub <= stat.tsub)

+-            prev_stat = stat

+-

+-        self.assertRaises(

+-            yappi.YappiError, stats.sort, "invalid_func_sorttype_arg"

+-        )

+-        self.assertRaises(

+-            yappi.YappiError, stats.sort, "totaltime",

+-            "invalid_func_sortorder_arg"

+-        )

+-

+-    def test_start_flags(self):

+-        self.assertEqual(_yappi._get_start_flags(), None)

+-        yappi.start()

+-

+-        def a():

+-            pass

+-

+-        a()

+-        self.assertEqual(_yappi._get_start_flags()["profile_builtins"], 0)

+-        self.assertEqual(_yappi._get_start_flags()["profile_multicontext"], 1)

+-        self.assertEqual(len(yappi.get_thread_stats()), 1)

+-

+-    def test_builtin_profiling(self):

+-

+-        def a():

+-            time.sleep(0.4)  # is a builtin function

+-

+-        yappi.set_clock_type('wall')

+-

+-        yappi.start(builtins=True)

+-        a()

+-        stats = yappi.get_func_stats()

+-        fsa = utils.find_stat_by_name(stats, 'sleep')

+-        self.assertTrue(fsa is not None)

+-        self.assertTrue(fsa.ttot > 0.3)

+-        yappi.stop()

+-        yappi.clear_stats()

+-

+-        def a():

+-            pass

+-

+-        yappi.start()

+-        t = threading.Thread(target=a)

+-        t.start()

+-        t.join()

+-        stats = yappi.get_func_stats()

+-

+-    def test_singlethread_profiling(self):

+-        yappi.set_clock_type('wall')

+-

+-        def a():

+-            time.sleep(0.2)

+-

+-        class Worker1(threading.Thread):

+-

+-            def a(self):

+-                time.sleep(0.3)

+-

+-            def run(self):

+-                self.a()

+-

+-        yappi.start(profile_threads=False)

+-

+-        c = Worker1()

+-        c.start()

+-        c.join()

+-        a()

+-        stats = yappi.get_func_stats()

+-        fsa1 = utils.find_stat_by_name(stats, 'Worker1.a')

+-        fsa2 = utils.find_stat_by_name(stats, 'a')

+-        self.assertTrue(fsa1 is None)

+-        self.assertTrue(fsa2 is not None)

+-        self.assertTrue(fsa2.ttot > 0.1)

+-

+-    def test_run(self):

+-

+-        def profiled():

+-            pass

+-

+-        yappi.clear_stats()

+-        try:

+-            with yappi.run():

+-                profiled()

+-            stats = yappi.get_func_stats()

+-        finally:

+-            yappi.clear_stats()

+-

+-        self.assertIsNotNone(utils.find_stat_by_name(stats, 'profiled'))

+-

+-    def test_run_recursive(self):

+-

+-        def profiled():

+-            pass

+-

+-        def not_profiled():

+-            pass

+-

+-        yappi.clear_stats()

+-        try:

+-            with yappi.run():

+-                with yappi.run():

+-                    profiled()

+-                # Profiling stopped here

+-                not_profiled()

+-            stats = yappi.get_func_stats()

+-        finally:

+-            yappi.clear_stats()

+-

+-        self.assertIsNotNone(utils.find_stat_by_name(stats, 'profiled'))

+-        self.assertIsNone(utils.find_stat_by_name(stats, 'not_profiled'))

+-

+-

+-class StatSaveScenarios(utils.YappiUnitTestCase):

+-

+-    def test_pstats_conversion(self):

+-

+-        def pstat_id(fs):

+-            return (fs.module, fs.lineno, fs.name)

+-

+-        def a():

+-            d()

+-

+-        def b():

+-            d()

+-

+-        def c():

+-            pass

+-

+-        def d():

+-            pass

+-

+-        _timings = {"a_1": 12, "b_1": 7, "c_1": 5, "d_1": 2}

+-        _yappi._set_test_timings(_timings)

+-        stats = utils.run_and_get_func_stats(a, )

+-        stats.strip_dirs()

+-        stats.save("tests/a1.pstats", type="pstat")

+-        fsa_pid = pstat_id(utils.find_stat_by_name(stats, "a"))

+-        fsd_pid = pstat_id(utils.find_stat_by_name(stats, "d"))

+-        yappi.clear_stats()

+-        _yappi._set_test_timings(_timings)

+-        stats = utils.run_and_get_func_stats(a, )

+-        stats.strip_dirs()

+-        stats.save("tests/a2.pstats", type="pstat")

+-        yappi.clear_stats()

+-        _yappi._set_test_timings(_timings)

+-        stats = utils.run_and_get_func_stats(b, )

+-        stats.strip_dirs()

+-        stats.save("tests/b1.pstats", type="pstat")

+-        fsb_pid = pstat_id(utils.find_stat_by_name(stats, "b"))

+-        yappi.clear_stats()

+-        _yappi._set_test_timings(_timings)

+-        stats = utils.run_and_get_func_stats(c, )

+-        stats.strip_dirs()

+-        stats.save("tests/c1.pstats", type="pstat")

+-        fsc_pid = pstat_id(utils.find_stat_by_name(stats, "c"))

+-

+-        # merge saved stats and check pstats values are correct

+-        import pstats

+-        p = pstats.Stats(

+-            'tests/a1.pstats', 'tests/a2.pstats', 'tests/b1.pstats',

+-            'tests/c1.pstats'

+-        )

+-        p.strip_dirs()

+-        # ct = ttot, tt = tsub

+-        (cc, nc, tt, ct, callers) = p.stats[fsa_pid]

+-        self.assertEqual(cc, nc, 2)

+-        self.assertEqual(tt, 20)

+-        self.assertEqual(ct, 24)

+-        (cc, nc, tt, ct, callers) = p.stats[fsd_pid]

+-        self.assertEqual(cc, nc, 3)

+-        self.assertEqual(tt, 6)

+-        self.assertEqual(ct, 6)

+-        self.assertEqual(len(callers), 2)

+-        (cc, nc, tt, ct) = callers[fsa_pid]

+-        self.assertEqual(cc, nc, 2)

+-        self.assertEqual(tt, 4)

+-        self.assertEqual(ct, 4)

+-        (cc, nc, tt, ct) = callers[fsb_pid]

+-        self.assertEqual(cc, nc, 1)

+-        self.assertEqual(tt, 2)

+-        self.assertEqual(ct, 2)

+-

+-    def test_merge_stats(self):

+-        _timings = {

+-            "a_1": 15,

+-            "b_1": 14,

+-            "c_1": 12,

+-            "d_1": 10,

+-            "e_1": 9,

+-            "f_1": 7,

+-            "g_1": 6,

+-            "h_1": 5,

+-            "i_1": 1

+-        }

+-        _yappi._set_test_timings(_timings)

+-

+-        def a():

+-            b()

+-

+-        def b():

+-            c()

+-

+-        def c():

+-            d()

+-

+-        def d():

+-            e()

+-

+-        def e():

+-            f()

+-

+-        def f():

+-            g()

+-

+-        def g():

+-            h()

+-

+-        def h():

+-            i()

+-

+-        def i():

+-            pass

+-

+-        yappi.start()

+-        a()

+-        a()

+-        yappi.stop()

+-        stats = yappi.get_func_stats()

+-        self.assertRaises(

+-            NotImplementedError, stats.save, "", "INVALID_SAVE_TYPE"

+-        )

+-        stats.save("tests/ystats2.ys")

+-        yappi.clear_stats()

+-        _yappi._set_test_timings(_timings)

+-        yappi.start()

+-        a()

+-        stats = yappi.get_func_stats().add("tests/ystats2.ys")

+-        fsa = utils.find_stat_by_name(stats, "a")

+-        fsb = utils.find_stat_by_name(stats, "b")

+-        fsc = utils.find_stat_by_name(stats, "c")

+-        fsd = utils.find_stat_by_name(stats, "d")

+-        fse = utils.find_stat_by_name(stats, "e")

+-        fsf = utils.find_stat_by_name(stats, "f")

+-        fsg = utils.find_stat_by_name(stats, "g")

+-        fsh = utils.find_stat_by_name(stats, "h")

+-        fsi = utils.find_stat_by_name(stats, "i")

+-        self.assertEqual(fsa.ttot, 45)

+-        self.assertEqual(fsa.ncall, 3)

+-        self.assertEqual(fsa.nactualcall, 3)

+-        self.assertEqual(fsa.tsub, 3)

+-        self.assertEqual(fsa.children[fsb].ttot, fsb.ttot)

+-        self.assertEqual(fsa.children[fsb].tsub, fsb.tsub)

+-        self.assertEqual(fsb.children[fsc].ttot, fsc.ttot)

+-        self.assertEqual(fsb.children[fsc].tsub, fsc.tsub)

+-        self.assertEqual(fsc.tsub, 6)

+-        self.assertEqual(fsc.children[fsd].ttot, fsd.ttot)

+-        self.assertEqual(fsc.children[fsd].tsub, fsd.tsub)

+-        self.assertEqual(fsd.children[fse].ttot, fse.ttot)

+-        self.assertEqual(fsd.children[fse].tsub, fse.tsub)

+-        self.assertEqual(fse.children[fsf].ttot, fsf.ttot)

+-        self.assertEqual(fse.children[fsf].tsub, fsf.tsub)

+-        self.assertEqual(fsf.children[fsg].ttot, fsg.ttot)

+-        self.assertEqual(fsf.children[fsg].tsub, fsg.tsub)

+-        self.assertEqual(fsg.ttot, 18)

+-        self.assertEqual(fsg.tsub, 3)

+-        self.assertEqual(fsg.children[fsh].ttot, fsh.ttot)

+-        self.assertEqual(fsg.children[fsh].tsub, fsh.tsub)

+-        self.assertEqual(fsh.ttot, 15)

+-        self.assertEqual(fsh.tsub, 12)

+-        self.assertEqual(fsh.tavg, 5)

+-        self.assertEqual(fsh.children[fsi].ttot, fsi.ttot)

+-        self.assertEqual(fsh.children[fsi].tsub, fsi.tsub)

+-        #stats.debug_print()

+-

+-    def test_merge_multithreaded_stats(self):

+-        import _yappi

+-        timings = {"a_1": 2, "b_1": 1}

+-        _yappi._set_test_timings(timings)

+-

+-        def a():

+-            pass

+-

+-        def b():

+-            pass

+-

+-        yappi.start()

+-        t = threading.Thread(target=a)

+-        t.start()

+-        t.join()

+-        t = threading.Thread(target=b)

+-        t.start()

+-        t.join()

+-        yappi.get_func_stats().save("tests/ystats1.ys")

+-        yappi.clear_stats()

+-        _yappi._set_test_timings(timings)

+-        self.assertEqual(len(yappi.get_func_stats()), 0)

+-        self.assertEqual(len(yappi.get_thread_stats()), 1)

+-        t = threading.Thread(target=a)

+-        t.start()

+-        t.join()

+-

+-        self.assertEqual(_yappi._get_start_flags()["profile_builtins"], 0)

+-        self.assertEqual(_yappi._get_start_flags()["profile_multicontext"], 1)

+-        yappi.get_func_stats().save("tests/ystats2.ys")

+-

+-        stats = yappi.YFuncStats([

+-            "tests/ystats1.ys",

+-            "tests/ystats2.ys",

+-        ])

+-        fsa = utils.find_stat_by_name(stats, "a")

+-        fsb = utils.find_stat_by_name(stats, "b")

+-        self.assertEqual(fsa.ncall, 2)

+-        self.assertEqual(fsb.ncall, 1)

+-        self.assertEqual(fsa.tsub, fsa.ttot, 4)

+-        self.assertEqual(fsb.tsub, fsb.ttot, 1)

+-

+-    def test_merge_load_different_clock_types(self):

+-        yappi.start(builtins=True)

+-

+-        def a():

+-            b()

+-

+-        def b():

+-            c()

+-

+-        def c():

+-            pass

+-

+-        t = threading.Thread(target=a)

+-        t.start()

+-        t.join()

+-        yappi.get_func_stats().sort("name", "asc").save("tests/ystats1.ys")

+-        yappi.stop()

+-        yappi.clear_stats()

+-        yappi.start(builtins=False)

+-        t = threading.Thread(target=a)

+-        t.start()

+-        t.join()

+-        yappi.get_func_stats().save("tests/ystats2.ys")

+-        yappi.stop()

+-        self.assertRaises(_yappi.error, yappi.set_clock_type, "wall")

+-        yappi.clear_stats()

+-        yappi.set_clock_type("wall")

+-        yappi.start()

+-        t = threading.Thread(target=a)

+-        t.start()

+-        t.join()

+-        yappi.get_func_stats().save("tests/ystats3.ys")

+-        self.assertRaises(

+-            yappi.YappiError,

+-            yappi.YFuncStats().add("tests/ystats1.ys").add, "tests/ystats3.ys"

+-        )

+-        stats = yappi.YFuncStats(["tests/ystats1.ys",

+-                                  "tests/ystats2.ys"]).sort("name")

+-        fsa = utils.find_stat_by_name(stats, "a")

+-        fsb = utils.find_stat_by_name(stats, "b")

+-        fsc = utils.find_stat_by_name(stats, "c")

+-        self.assertEqual(fsa.ncall, 2)

+-        self.assertEqual(fsa.ncall, fsb.ncall, fsc.ncall)

+-

+-    def test_merge_aabab_aabbc(self):

+-        _timings = {

+-            "a_1": 15,

+-            "a_2": 14,

+-            "b_1": 12,

+-            "a_3": 10,

+-            "b_2": 9,

+-            "c_1": 4

+-        }

+-        _yappi._set_test_timings(_timings)

+-

+-        def a():

+-            if self._ncall == 1:

+-                self._ncall += 1

+-                a()

+-            elif self._ncall == 5:

+-                self._ncall += 1

+-                a()

+-            else:

+-                b()

+-

+-        def b():

+-            if self._ncall == 2:

+-                self._ncall += 1

+-                a()

+-            elif self._ncall == 6:

+-                self._ncall += 1

+-                b()

+-            elif self._ncall == 7:

+-                c()

+-            else:

+-                return

+-

+-        def c():

+-            pass

+-

+-        self._ncall = 1

+-        stats = utils.run_and_get_func_stats(a, )

+-        stats.save("tests/ystats1.ys")

+-        yappi.clear_stats()

+-        _yappi._set_test_timings(_timings)

+-        #stats.print_all()

+-

+-        self._ncall = 5

+-        stats = utils.run_and_get_func_stats(a, )

+-        stats.save("tests/ystats2.ys")

+-

+-        #stats.print_all()

+-

+-        def a():  # same name but another function(code object)

+-            pass

+-

+-        yappi.start()

+-        a()

+-        stats = yappi.get_func_stats().add(

+-            ["tests/ystats1.ys", "tests/ystats2.ys"]

+-        )

+-        #stats.print_all()

+-        self.assertEqual(len(stats), 4)

+-

+-        fsa = None

+-        for stat in stats:

+-            if stat.name == "a" and stat.ttot == 45:

+-                fsa = stat

+-                break

+-        self.assertTrue(fsa is not None)

+-

+-        self.assertEqual(fsa.ncall, 7)

+-        self.assertEqual(fsa.nactualcall, 3)

+-        self.assertEqual(fsa.ttot, 45)

+-        self.assertEqual(fsa.tsub, 10)

+-        fsb = utils.find_stat_by_name(stats, "b")

+-        fsc = utils.find_stat_by_name(stats, "c")

+-        self.assertEqual(fsb.ncall, 6)

+-        self.assertEqual(fsb.nactualcall, 3)

+-        self.assertEqual(fsb.ttot, 36)

+-        self.assertEqual(fsb.tsub, 27)

+-        self.assertEqual(fsb.tavg, 6)

+-        self.assertEqual(fsc.ttot, 8)

+-        self.assertEqual(fsc.tsub, 8)

+-        self.assertEqual(fsc.tavg, 4)

+-        self.assertEqual(fsc.nactualcall, fsc.ncall, 2)

+-

+-

+-class MultithreadedScenarios(utils.YappiUnitTestCase):

+-

+-    def test_issue_32(self):

+-        '''

+-        Start yappi from different thread and we get Internal Error(15) as 

+-        the current_ctx_id() called while enumerating the threads in start() 

+-        and as it does not swap to the enumerated ThreadState* the THreadState_GetDict()

+-        returns wrong object and thus sets an invalid id for the _ctx structure.

+-

+-        When this issue happens multiple Threads have same tid as the internal ts_ptr

+-        will be same for different contexts. So, let's see if that happens

+-        '''

+-

+-        def foo():

+-            time.sleep(0.2)

+-

+-        def bar():

+-            time.sleep(0.1)

+-

+-        def thread_func():

+-            yappi.set_clock_type("wall")

+-            yappi.start()

+-

+-            bar()

+-

+-        t = threading.Thread(target=thread_func)

+-        t.start()

+-        t.join()

+-

+-        foo()

+-

+-        yappi.stop()

+-

+-        thread_ids = set()

+-        for tstat in yappi.get_thread_stats():

+-            self.assertTrue(tstat.tid not in thread_ids)

+-            thread_ids.add(tstat.tid)

+-

+-    def test_subsequent_profile(self):

+-        WORKER_COUNT = 5

+-

+-        def a():

+-            pass

+-

+-        def b():

+-            pass

+-

+-        def c():

+-            pass

+-

+-        _timings = {

+-            "a_1": 3,

+-            "b_1": 2,

+-            "c_1": 1,

+-        }

+-

+-        yappi.start()

+-

+-        def g():

+-            pass

+-

+-        g()

+-        yappi.stop()

+-        yappi.clear_stats()

+-        _yappi._set_test_timings(_timings)

+-        yappi.start()

+-

+-        _dummy = []

+-        for i in range(WORKER_COUNT):

+-            t = threading.Thread(target=a)

+-            t.start()

+-            t.join()

+-        for i in range(WORKER_COUNT):

+-            t = threading.Thread(target=b)

+-            t.start()

+-            _dummy.append(t)

+-            t.join()

+-        for i in range(WORKER_COUNT):

+-            t = threading.Thread(target=a)

+-            t.start()

+-            t.join()

+-        for i in range(WORKER_COUNT):

+-            t = threading.Thread(target=c)

+-            t.start()

+-            t.join()

+-        yappi.stop()

+-        yappi.start()

+-

+-        def f():

+-            pass

+-

+-        f()

+-        stats = yappi.get_func_stats()

+-        fsa = utils.find_stat_by_name(stats, 'a')

+-        fsb = utils.find_stat_by_name(stats, 'b')

+-        fsc = utils.find_stat_by_name(stats, 'c')

+-        self.assertEqual(fsa.ncall, 10)

+-        self.assertEqual(fsb.ncall, 5)

+-        self.assertEqual(fsc.ncall, 5)

+-        self.assertEqual(fsa.ttot, fsa.tsub, 30)

+-        self.assertEqual(fsb.ttot, fsb.tsub, 10)

+-        self.assertEqual(fsc.ttot, fsc.tsub, 5)

+-

+-        # MACOSx optimizes by only creating one worker thread

+-        self.assertTrue(len(yappi.get_thread_stats()) >= 2)

+-

+-    def test_basic(self):

+-        yappi.set_clock_type('wall')

+-

+-        def dummy():

+-            pass

+-

+-        def a():

+-            time.sleep(0.2)

+-

+-        class Worker1(threading.Thread):

+-

+-            def a(self):

+-                time.sleep(0.3)

+-

+-            def run(self):

+-                self.a()

+-

+-        yappi.start(builtins=False, profile_threads=True)

+-

+-        c = Worker1()

+-        c.start()

+-        c.join()

+-        a()

+-        stats = yappi.get_func_stats()

+-        fsa1 = utils.find_stat_by_name(stats, 'Worker1.a')

+-        fsa2 = utils.find_stat_by_name(stats, 'a')

+-        self.assertTrue(fsa1 is not None)

+-        self.assertTrue(fsa2 is not None)

+-        self.assertTrue(fsa1.ttot > 0.2)

+-        self.assertTrue(fsa2.ttot > 0.1)

+-        tstats = yappi.get_thread_stats()

+-        self.assertEqual(len(tstats), 2)

+-        tsa = utils.find_stat_by_name(tstats, 'Worker1')

+-        tsm = utils.find_stat_by_name(tstats, '_MainThread')

+-        dummy()  # call dummy to force ctx name to be retrieved again.

+-        self.assertTrue(tsa is not None)

+-        # TODO: I put dummy() to fix below, remove the comments after a while.

+-        self.assertTrue( # FIX: I see this fails sometimes?

+-            tsm is not None,

+-            f"Could not find \"_MainThread\". Found: {', '.join(utils.get_stat_names(tstats))}")

+-

+-    def test_ctx_stats(self):

+-        from threading import Thread

+-        DUMMY_WORKER_COUNT = 5

+-        yappi.start()

+-

+-        class DummyThread(Thread):

+-            pass

+-

+-        def dummy():

+-            pass

+-

+-        def dummy_worker():

+-            pass

+-

+-        for i in range(DUMMY_WORKER_COUNT):

+-            t = DummyThread(target=dummy_worker)

+-            t.start()

+-            t.join()

+-        yappi.stop()

+-        stats = yappi.get_thread_stats()

+-        tsa = utils.find_stat_by_name(stats, "DummyThread")

+-        self.assertTrue(tsa is not None)

+-        yappi.clear_stats()

+-        time.sleep(1.0)

+-        _timings = {

+-            "a_1": 6,

+-            "b_1": 5,

+-            "c_1": 3,

+-            "d_1": 1,

+-            "a_2": 4,

+-            "b_2": 3,

+-            "c_2": 2,

+-            "d_2": 1

+-        }

+-        _yappi._set_test_timings(_timings)

+-

+-        class Thread1(Thread):

+-            pass

+-

+-        class Thread2(Thread):

+-            pass

+-

+-        def a():

+-            b()

+-

+-        def b():

+-            c()

+-

+-        def c():

+-            d()

+-

+-        def d():

+-            time.sleep(0.6)

+-

+-        yappi.set_clock_type("wall")

+-        yappi.start()

+-        t1 = Thread1(target=a)

+-        t1.start()

+-        t2 = Thread2(target=a)

+-        t2.start()

+-        t1.join()

+-        t2.join()

+-        stats = yappi.get_thread_stats()

+-

+-        # the fist clear_stats clears the context table?

+-        tsa = utils.find_stat_by_name(stats, "DummyThread")

+-        self.assertTrue(tsa is None)

+-

+-        tst1 = utils.find_stat_by_name(stats, "Thread1")

+-        tst2 = utils.find_stat_by_name(stats, "Thread2")

+-        tsmain = utils.find_stat_by_name(stats, "_MainThread")

+-        dummy()  # call dummy to force ctx name to be retrieved again.

+-        self.assertTrue(len(stats) == 3)

+-        self.assertTrue(tst1 is not None)

+-        self.assertTrue(tst2 is not None)

+-        # TODO: I put dummy() to fix below, remove the comments after a while.

+-        self.assertTrue( # FIX: I see this fails sometimes

+-            tsmain is not None,

+-            f"Could not find \"_MainThread\". Found: {', '.join(utils.get_stat_names(stats))}")

+-        self.assertTrue(1.0 > tst2.ttot >= 0.5)

+-        self.assertTrue(1.0 > tst1.ttot >= 0.5)

+-

+-        # test sorting of the ctx stats

+-        stats = stats.sort("totaltime", "desc")

+-        prev_stat = None

+-        for stat in stats:

+-            if prev_stat:

+-                self.assertTrue(prev_stat.ttot >= stat.ttot)

+-            prev_stat = stat

+-        stats = stats.sort("totaltime", "asc")

+-        prev_stat = None

+-        for stat in stats:

+-            if prev_stat:

+-                self.assertTrue(prev_stat.ttot <= stat.ttot)

+-            prev_stat = stat

+-        stats = stats.sort("schedcount", "desc")

+-        prev_stat = None

+-        for stat in stats:

+-            if prev_stat:

+-                self.assertTrue(prev_stat.sched_count >= stat.sched_count)

+-            prev_stat = stat

+-        stats = stats.sort("name", "desc")

+-        prev_stat = None

+-        for stat in stats:

+-            if prev_stat:

+-                self.assertTrue(prev_stat.name.lower() >= stat.name.lower())

+-            prev_stat = stat

+-        self.assertRaises(

+-            yappi.YappiError, stats.sort, "invalid_thread_sorttype_arg"

+-        )

+-        self.assertRaises(

+-            yappi.YappiError, stats.sort, "invalid_thread_sortorder_arg"

+-        )

+-

+-    def test_ctx_stats_cpu(self):

+-

+-        def get_thread_name():

+-            try:

+-                return threading.current_thread().name

+-            except AttributeError:

+-                return "Anonymous"

+-

+-        def burn_cpu(sec):

+-            t0 = yappi.get_clock_time()

+-            elapsed = 0

+-            while (elapsed < sec):

+-                for _ in range(1000):

+-                    pass

+-                elapsed = yappi.get_clock_time() - t0

+-

+-        def test():

+-

+-            ts = []

+-            for i in (0.01, 0.05, 0.1):

+-                t = threading.Thread(target=burn_cpu, args=(i, ))

+-                t.name = f"burn_cpu-{str(i)}"

+-                t.start()

+-                ts.append(t)

+-            for t in ts:

+-                t.join()

+-

+-        yappi.set_clock_type("cpu")

+-        yappi.set_context_name_callback(get_thread_name)

+-

+-        yappi.start()

+-

+-        test()

+-

+-        yappi.stop()

+-

+-        tstats = yappi.get_thread_stats()

+-        r1 = '''

+-        burn_cpu-0.1      3      123145356058624  0.100105  8

+-        burn_cpu-0.05     2      123145361313792  0.050149  8

+-        burn_cpu-0.01     1      123145356058624  0.010127  2

+-        MainThread        0      4321620864       0.001632  6

+-        '''

+-        self.assert_ctx_stats_almost_equal(r1, tstats)

+-

+-    def test_producer_consumer_with_queues(self):

+-        # we currently just stress yappi, no functionality test is done here.

+-        yappi.start()

+-        from queue import Queue

+-        from threading import Thread

+-        WORKER_THREAD_COUNT = 50

+-        WORK_ITEM_COUNT = 2000

+-

+-        def worker():

+-            while True:

+-                item = q.get()

+-                # do the work with item

+-                q.task_done()

+-

+-        q = Queue()

+-        for i in range(WORKER_THREAD_COUNT):

+-            t = Thread(target=worker)

+-            t.daemon = True

+-            t.start()

+-

+-        for item in range(WORK_ITEM_COUNT):

+-            q.put(item)

+-        q.join()  # block until all tasks are done

+-        #yappi.get_func_stats().sort("callcount").print_all()

+-        yappi.stop()

+-

+-    def test_temporary_lock_waiting(self):

+-        yappi.start()

+-        _lock = threading.Lock()

+-

+-        def worker():

+-            _lock.acquire()

+-            try:

+-                time.sleep(1.0)

+-            finally:

+-                _lock.release()

+-

+-        t1 = threading.Thread(target=worker)

+-        t2 = threading.Thread(target=worker)

+-        t1.start()

+-        t2.start()

+-        t1.join()

+-        t2.join()

+-        #yappi.get_func_stats().sort("callcount").print_all()

+-        yappi.stop()

+-

+-    @unittest.skipIf(os.name != "posix", "requires Posix compliant OS")

+-    def test_signals_with_blocking_calls(self):

+-        import signal, os, time

+-

+-        # just to verify if signal is handled correctly and stats/yappi are not corrupted.

+-        def handler(signum, frame):

+-            raise Exception("Signal handler executed!")

+-

+-        yappi.start()

+-        signal.signal(signal.SIGALRM, handler)

+-        signal.alarm(1)

+-        self.assertRaises(Exception, time.sleep, 2)

+-        stats = yappi.get_func_stats()

+-        fsh = utils.find_stat_by_name(stats, "handler")

+-        self.assertTrue(fsh is not None)

+-

+-    def test_concurrent_futures(self):

+-        yappi.start()

+-        from concurrent.futures import ThreadPoolExecutor

+-        with ThreadPoolExecutor(max_workers=5) as executor:

+-            f = executor.submit(pow, 5, 2)

+-            self.assertEqual(f.result(), 25)

+-        time.sleep(1.0)

+-        yappi.stop()

+-

+-    def test_barrier(self):

+-        yappi.start()

+-        b = threading.Barrier(2, timeout=1)

+-

+-        def worker():

+-            try:

+-                b.wait()

+-            except threading.BrokenBarrierError:

+-                pass

+-            except Exception:

+-                raise Exception("BrokenBarrierError not raised")

+-

+-        t1 = threading.Thread(target=worker)

+-        t1.start()

+-        #b.wait()

+-        t1.join()

+-        yappi.stop()

+-

+-

+-class NonRecursiveFunctions(utils.YappiUnitTestCase):

+-

+-    def test_abcd(self):

+-        _timings = {"a_1": 6, "b_1": 5, "c_1": 3, "d_1": 1}

+-        _yappi._set_test_timings(_timings)

+-

+-        def a():

+-            b()

+-

+-        def b():

+-            c()

+-

+-        def c():

+-            d()

+-

+-        def d():

+-            pass

+-

+-        stats = utils.run_and_get_func_stats(a)

+-        fsa = utils.find_stat_by_name(stats, 'a')

+-        fsb = utils.find_stat_by_name(stats, 'b')

+-        fsc = utils.find_stat_by_name(stats, 'c')

+-        fsd = utils.find_stat_by_name(stats, 'd')

+-        cfsab = fsa.children[fsb]

+-        cfsbc = fsb.children[fsc]

+-        cfscd = fsc.children[fsd]

+-

+-        self.assertEqual(fsa.ttot, 6)

+-        self.assertEqual(fsa.tsub, 1)

+-        self.assertEqual(fsb.ttot, 5)

+-        self.assertEqual(fsb.tsub, 2)

+-        self.assertEqual(fsc.ttot, 3)

+-        self.assertEqual(fsc.tsub, 2)

+-        self.assertEqual(fsd.ttot, 1)

+-        self.assertEqual(fsd.tsub, 1)

+-        self.assertEqual(cfsab.ttot, 5)

+-        self.assertEqual(cfsab.tsub, 2)

+-        self.assertEqual(cfsbc.ttot, 3)

+-        self.assertEqual(cfsbc.tsub, 2)

+-        self.assertEqual(cfscd.ttot, 1)

+-        self.assertEqual(cfscd.tsub, 1)

+-

+-    def test_stop_in_middle(self):

+-        _timings = {"a_1": 6, "b_1": 4}

+-        _yappi._set_test_timings(_timings)

+-

+-        def a():

+-            b()

+-            yappi.stop()

+-

+-        def b():

+-            time.sleep(0.2)

+-

+-        yappi.start()

+-        a()

+-        stats = yappi.get_func_stats()

+-        fsa = utils.find_stat_by_name(stats, 'a')

+-        fsb = utils.find_stat_by_name(stats, 'b')

+-

+-        self.assertEqual(fsa.ncall, 1)

+-        self.assertEqual(fsa.nactualcall, 0)

+-        self.assertEqual(fsa.ttot, 0)  # no call_leave called

+-        self.assertEqual(fsa.tsub, 0)  # no call_leave called

+-        self.assertEqual(fsb.ttot, 4)

+-

+-

+-class RecursiveFunctions(utils.YappiUnitTestCase):

+-

+-    def test_fibonacci(self):

+-

+-        def fib(n):

+-            if n > 1:

+-                return fib(n - 1) + fib(n - 2)

+-            else:

+-                return n

+-

+-        stats = utils.run_and_get_func_stats(fib, 22)

+-        fs = utils.find_stat_by_name(stats, 'fib')

+-        self.assertEqual(fs.ncall, 57313)

+-        self.assertEqual(fs.ttot, fs.tsub)

+-

+-    def test_abcadc(self):

+-        _timings = {

+-            "a_1": 20,

+-            "b_1": 19,

+-            "c_1": 17,

+-            "a_2": 13,

+-            "d_1": 12,

+-            "c_2": 10,

+-            "a_3": 5

+-        }

+-        _yappi._set_test_timings(_timings)

+-

+-        def a(n):

+-            if n == 3:

+-                return

+-            if n == 1 + 1:

+-                d(n)

+-            else:

+-                b(n)

+-

+-        def b(n):

+-            c(n)

+-

+-        def c(n):

+-            a(n + 1)

+-

+-        def d(n):

+-            c(n)

+-

+-        stats = utils.run_and_get_func_stats(a, 1)

+-        fsa = utils.find_stat_by_name(stats, 'a')

+-        fsb = utils.find_stat_by_name(stats, 'b')

+-        fsc = utils.find_stat_by_name(stats, 'c')

+-        fsd = utils.find_stat_by_name(stats, 'd')

+-        self.assertEqual(fsa.ncall, 3)

+-        self.assertEqual(fsa.nactualcall, 1)

+-        self.assertEqual(fsa.ttot, 20)

+-        self.assertEqual(fsa.tsub, 7)

+-        self.assertEqual(fsb.ttot, 19)

+-        self.assertEqual(fsb.tsub, 2)

+-        self.assertEqual(fsc.ttot, 17)

+-        self.assertEqual(fsc.tsub, 9)

+-        self.assertEqual(fsd.ttot, 12)

+-        self.assertEqual(fsd.tsub, 2)

+-        cfsca = fsc.children[fsa]

+-        self.assertEqual(cfsca.nactualcall, 0)

+-        self.assertEqual(cfsca.ncall, 2)

+-        self.assertEqual(cfsca.ttot, 13)

+-        self.assertEqual(cfsca.tsub, 6)

+-

+-    def test_aaaa(self):

+-        _timings = {"d_1": 9, "d_2": 7, "d_3": 3, "d_4": 2}

+-        _yappi._set_test_timings(_timings)

+-

+-        def d(n):

+-            if n == 3:

+-                return

+-            d(n + 1)

+-

+-        stats = utils.run_and_get_func_stats(d, 0)

+-        fsd = utils.find_stat_by_name(stats, 'd')

+-        self.assertEqual(fsd.ncall, 4)

+-        self.assertEqual(fsd.nactualcall, 1)

+-        self.assertEqual(fsd.ttot, 9)

+-        self.assertEqual(fsd.tsub, 9)

+-        cfsdd = fsd.children[fsd]

+-        self.assertEqual(cfsdd.ttot, 7)

+-        self.assertEqual(cfsdd.tsub, 7)

+-        self.assertEqual(cfsdd.ncall, 3)

+-        self.assertEqual(cfsdd.nactualcall, 0)

+-

+-    def test_abcabc(self):

+-        _timings = {

+-            "a_1": 20,

+-            "b_1": 19,

+-            "c_1": 17,

+-            "a_2": 13,

+-            "b_2": 11,

+-            "c_2": 9,

+-            "a_3": 6

+-        }

+-        _yappi._set_test_timings(_timings)

+-

+-        def a(n):

+-            if n == 3:

+-                return

+-            else:

+-                b(n)

+-

+-        def b(n):

+-            c(n)

+-

+-        def c(n):

+-            a(n + 1)

+-

+-        stats = utils.run_and_get_func_stats(a, 1)

+-        fsa = utils.find_stat_by_name(stats, 'a')

+-        fsb = utils.find_stat_by_name(stats, 'b')

+-        fsc = utils.find_stat_by_name(stats, 'c')

+-        self.assertEqual(fsa.ncall, 3)

+-        self.assertEqual(fsa.nactualcall, 1)

+-        self.assertEqual(fsa.ttot, 20)

+-        self.assertEqual(fsa.tsub, 9)

+-        self.assertEqual(fsb.ttot, 19)

+-        self.assertEqual(fsb.tsub, 4)

+-        self.assertEqual(fsc.ttot, 17)

+-        self.assertEqual(fsc.tsub, 7)

+-        cfsab = fsa.children[fsb]

+-        cfsbc = fsb.children[fsc]

+-        cfsca = fsc.children[fsa]

+-        self.assertEqual(cfsab.ttot, 19)

+-        self.assertEqual(cfsab.tsub, 4)

+-        self.assertEqual(cfsbc.ttot, 17)

+-        self.assertEqual(cfsbc.tsub, 7)

+-        self.assertEqual(cfsca.ttot, 13)

+-        self.assertEqual(cfsca.tsub, 8)

+-

+-    def test_abcbca(self):

+-        _timings = {"a_1": 10, "b_1": 9, "c_1": 7, "b_2": 4, "c_2": 2, "a_2": 1}

+-        _yappi._set_test_timings(_timings)

+-        self._ncall = 1

+-

+-        def a():

+-            if self._ncall == 1:

+-                b()

+-            else:

+-                return

+-

+-        def b():

+-            c()

+-

+-        def c():

+-            if self._ncall == 1:

+-                self._ncall += 1

+-                b()

+-            else:

+-                a()

+-

+-        stats = utils.run_and_get_func_stats(a)

+-        fsa = utils.find_stat_by_name(stats, 'a')

+-        fsb = utils.find_stat_by_name(stats, 'b')

+-        fsc = utils.find_stat_by_name(stats, 'c')

+-        cfsab = fsa.children[fsb]

+-        cfsbc = fsb.children[fsc]

+-        cfsca = fsc.children[fsa]

+-        self.assertEqual(fsa.ttot, 10)

+-        self.assertEqual(fsa.tsub, 2)

+-        self.assertEqual(fsb.ttot, 9)

+-        self.assertEqual(fsb.tsub, 4)

+-        self.assertEqual(fsc.ttot, 7)

+-        self.assertEqual(fsc.tsub, 4)

+-        self.assertEqual(cfsab.ttot, 9)

+-        self.assertEqual(cfsab.tsub, 2)

+-        self.assertEqual(cfsbc.ttot, 7)

+-        self.assertEqual(cfsbc.tsub, 4)

+-        self.assertEqual(cfsca.ttot, 1)

+-        self.assertEqual(cfsca.tsub, 1)

+-        self.assertEqual(cfsca.ncall, 1)

+-        self.assertEqual(cfsca.nactualcall, 0)

+-

+-    def test_aabccb(self):

+-        _timings = {

+-            "a_1": 13,

+-            "a_2": 11,

+-            "b_1": 9,

+-            "c_1": 5,

+-            "c_2": 3,

+-            "b_2": 1

+-        }

+-        _yappi._set_test_timings(_timings)

+-        self._ncall = 1

+-

+-        def a():

+-            if self._ncall == 1:

+-                self._ncall += 1

+-                a()

+-            else:

+-                b()

+-

+-        def b():

+-            if self._ncall == 3:

+-                return

+-            else:

+-                c()

+-

+-        def c():

+-            if self._ncall == 2:

+-                self._ncall += 1

+-                c()

+-            else:

+-                b()

+-

+-        stats = utils.run_and_get_func_stats(a)

+-        fsa = utils.find_stat_by_name(stats, 'a')

+-        fsb = utils.find_stat_by_name(stats, 'b')

+-        fsc = utils.find_stat_by_name(stats, 'c')

+-        cfsaa = fsa.children[fsa.index]

+-        cfsab = fsa.children[fsb]

+-        cfsbc = fsb.children[fsc.full_name]

+-        cfscc = fsc.children[fsc]

+-        cfscb = fsc.children[fsb]

+-        self.assertEqual(fsb.ttot, 9)

+-        self.assertEqual(fsb.tsub, 5)

+-        self.assertEqual(cfsbc.ttot, 5)

+-        self.assertEqual(cfsbc.tsub, 2)

+-        self.assertEqual(fsa.ttot, 13)

+-        self.assertEqual(fsa.tsub, 4)

+-        self.assertEqual(cfsab.ttot, 9)

+-        self.assertEqual(cfsab.tsub, 4)

+-        self.assertEqual(cfsaa.ttot, 11)

+-        self.assertEqual(cfsaa.tsub, 2)

+-        self.assertEqual(fsc.ttot, 5)

+-        self.assertEqual(fsc.tsub, 4)

+-

+-    def test_abaa(self):

+-        _timings = {"a_1": 13, "b_1": 10, "a_2": 9, "a_3": 5}

+-        _yappi._set_test_timings(_timings)

+-

+-        self._ncall = 1

+-

+-        def a():

+-            if self._ncall == 1:

+-                b()

+-            elif self._ncall == 2:

+-                self._ncall += 1

+-                a()

+-            else:

+-                return

+-

+-        def b():

+-            self._ncall += 1

+-            a()

+-

+-        stats = utils.run_and_get_func_stats(a)

+-        fsa = utils.find_stat_by_name(stats, 'a')

+-        fsb = utils.find_stat_by_name(stats, 'b')

+-        cfsaa = fsa.children[fsa]

+-        cfsba = fsb.children[fsa]

+-        self.assertEqual(fsb.ttot, 10)

+-        self.assertEqual(fsb.tsub, 1)

+-        self.assertEqual(fsa.ttot, 13)

+-        self.assertEqual(fsa.tsub, 12)

+-        self.assertEqual(cfsaa.ttot, 5)

+-        self.assertEqual(cfsaa.tsub, 5)

+-        self.assertEqual(cfsba.ttot, 9)

+-        self.assertEqual(cfsba.tsub, 4)

+-

+-    def test_aabb(self):

+-        _timings = {"a_1": 13, "a_2": 10, "b_1": 9, "b_2": 5}

+-        _yappi._set_test_timings(_timings)

+-

+-        self._ncall = 1

+-

+-        def a():

+-            if self._ncall == 1:

+-                self._ncall += 1

+-                a()

+-            elif self._ncall == 2:

+-                b()

+-            else:

+-                return

+-

+-        def b():

+-            if self._ncall == 2:

+-                self._ncall += 1

+-                b()

+-            else:

+-                return

+-

+-        stats = utils.run_and_get_func_stats(a)

+-        fsa = utils.find_stat_by_name(stats, 'a')

+-        fsb = utils.find_stat_by_name(stats, 'b')

+-        cfsaa = fsa.children[fsa]

+-        cfsab = fsa.children[fsb]

+-        cfsbb = fsb.children[fsb]

+-        self.assertEqual(fsa.ttot, 13)

+-        self.assertEqual(fsa.tsub, 4)

+-        self.assertEqual(fsb.ttot, 9)

+-        self.assertEqual(fsb.tsub, 9)

+-        self.assertEqual(cfsaa.ttot, 10)

+-        self.assertEqual(cfsaa.tsub, 1)

+-        self.assertEqual(cfsab.ttot, 9)

+-        self.assertEqual(cfsab.tsub, 4)

+-        self.assertEqual(cfsbb.ttot, 5)

+-        self.assertEqual(cfsbb.tsub, 5)

+-

+-    def test_abbb(self):

+-        _timings = {"a_1": 13, "b_1": 10, "b_2": 6, "b_3": 1}

+-        _yappi._set_test_timings(_timings)

+-

+-        self._ncall = 1

+-

+-        def a():

+-            if self._ncall == 1:

+-                b()

+-

+-        def b():

+-            if self._ncall == 3:

+-                return

+-            self._ncall += 1

+-            b()

+-

+-        stats = utils.run_and_get_func_stats(a)

+-        fsa = utils.find_stat_by_name(stats, 'a')

+-        fsb = utils.find_stat_by_name(stats, 'b')

+-        cfsab = fsa.children[fsb]

+-        cfsbb = fsb.children[fsb]

+-        self.assertEqual(fsa.ttot, 13)

+-        self.assertEqual(fsa.tsub, 3)

+-        self.assertEqual(fsb.ttot, 10)

+-        self.assertEqual(fsb.tsub, 10)

+-        self.assertEqual(fsb.ncall, 3)

+-        self.assertEqual(fsb.nactualcall, 1)

+-        self.assertEqual(cfsab.ttot, 10)

+-        self.assertEqual(cfsab.tsub, 4)

+-        self.assertEqual(cfsbb.ttot, 6)

+-        self.assertEqual(cfsbb.tsub, 6)

+-        self.assertEqual(cfsbb.nactualcall, 0)

+-        self.assertEqual(cfsbb.ncall, 2)

+-

+-    def test_aaab(self):

+-        _timings = {"a_1": 13, "a_2": 10, "a_3": 6, "b_1": 1}

+-        _yappi._set_test_timings(_timings)

+-

+-        self._ncall = 1

+-

+-        def a():

+-            if self._ncall == 3:

+-                b()

+-                return

+-            self._ncall += 1

+-            a()

+-

+-        def b():

+-            return

+-

+-        stats = utils.run_and_get_func_stats(a)

+-        fsa = utils.find_stat_by_name(stats, 'a')

+-        fsb = utils.find_stat_by_name(stats, 'b')

+-        cfsaa = fsa.children[fsa]

+-        cfsab = fsa.children[fsb]

+-        self.assertEqual(fsa.ttot, 13)

+-        self.assertEqual(fsa.tsub, 12)

+-        self.assertEqual(fsb.ttot, 1)

+-        self.assertEqual(fsb.tsub, 1)

+-        self.assertEqual(cfsaa.ttot, 10)

+-        self.assertEqual(cfsaa.tsub, 9)

+-        self.assertEqual(cfsab.ttot, 1)

+-        self.assertEqual(cfsab.tsub, 1)

+-

+-    def test_abab(self):

+-        _timings = {"a_1": 13, "b_1": 10, "a_2": 6, "b_2": 1}

+-        _yappi._set_test_timings(_timings)

+-

+-        self._ncall = 1

+-

+-        def a():

+-            b()

+-

+-        def b():

+-            if self._ncall == 2:

+-                return

+-            self._ncall += 1

+-            a()

+-

+-        stats = utils.run_and_get_func_stats(a)

+-        fsa = utils.find_stat_by_name(stats, 'a')

+-        fsb = utils.find_stat_by_name(stats, 'b')

+-        cfsab = fsa.children[fsb]

+-        cfsba = fsb.children[fsa]

+-        self.assertEqual(fsa.ttot, 13)

+-        self.assertEqual(fsa.tsub, 8)

+-        self.assertEqual(fsb.ttot, 10)

+-        self.assertEqual(fsb.tsub, 5)

+-        self.assertEqual(cfsab.ttot, 10)

+-        self.assertEqual(cfsab.tsub, 5)

+-        self.assertEqual(cfsab.ncall, 2)

+-        self.assertEqual(cfsab.nactualcall, 1)

+-        self.assertEqual(cfsba.ttot, 6)

+-        self.assertEqual(cfsba.tsub, 5)

+-

+-

+-if __name__ == '__main__':

+-    #     import sys;sys.argv = ['', 'BasicUsage.test_run_as_script']

+-    #     import sys;sys.argv = ['', 'MultithreadedScenarios.test_subsequent_profile']

+-    unittest.main()

++import os
++import sys
++import time
++import threading
++import unittest
++import yappi
++import _yappi
++import utils
++import multiprocessing
++import subprocess
++
++_counter = 0
++
++
++class BasicUsage(utils.YappiUnitTestCase):
++
++    def test_callback_function_int_return_overflow(self):
++        # this test is just here to check if any errors are generated, as the err
++        # is printed in C side, I did not include it here. THere are ways to test
++        # this deterministically, I did not bother
++        import ctypes
++
++        def _unsigned_overflow_margin():
++            return 2**(ctypes.sizeof(ctypes.c_void_p) * 8) - 1
++
++        def foo():
++            pass
++
++        #with utils.captured_output() as (out, err):
++        yappi.set_context_id_callback(_unsigned_overflow_margin)
++        yappi.set_tag_callback(_unsigned_overflow_margin)
++        yappi.start()
++        foo()
++
++    def test_issue60(self):
++
++        def foo():
++            buf = bytearray()
++            buf += b't' * 200
++            view = memoryview(buf)[10:]
++            view = view.tobytes()
++            del buf[:10]  # this throws exception
++            return view
++
++        yappi.start(builtins=True)
++        foo()
++        self.assertTrue(
++            len(
++                yappi.get_func_stats(
++                    filter_callback=lambda x: yappi.
++                    func_matches(x, [memoryview.tobytes])
++                )
++            ) > 0
++        )
++        yappi.stop()
++
++    def test_issue54(self):
++
++        def _tag_cbk():
++            global _counter
++            _counter += 1
++            return _counter
++
++        def a():
++            pass
++
++        def b():
++            pass
++
++        yappi.set_tag_callback(_tag_cbk)
++        yappi.start()
++        a()
++        a()
++        a()
++        yappi.stop()
++        stats = yappi.get_func_stats()
++        self.assertEqual(stats.pop().ncall, 3)  # aggregated if no tag is given
++        stats = yappi.get_func_stats(tag=1)
++
++        for i in range(1, 3):
++            stats = yappi.get_func_stats(tag=i)
++            stats = yappi.get_func_stats(
++                tag=i, filter_callback=lambda x: yappi.func_matches(x, [a])
++            )
++
++            stat = stats.pop()
++            self.assertEqual(stat.ncall, 1)
++
++        yappi.set_tag_callback(None)
++        yappi.clear_stats()
++        yappi.start()
++        b()
++        b()
++        stats = yappi.get_func_stats()
++        self.assertEqual(len(stats), 1)
++        stat = stats.pop()
++        self.assertEqual(stat.ncall, 2)
++
++    def test_filter(self):
++
++        def a():
++            pass
++
++        def b():
++            a()
++
++        def c():
++            b()
++
++        _TCOUNT = 5
++
++        ts = []
++        yappi.start()
++        for i in range(_TCOUNT):
++            t = threading.Thread(target=c)
++            t.start()
++            ts.append(t)
++
++        for t in ts:
++            t.join()
++
++        yappi.stop()
++
++        ctx_ids = []
++        for tstat in yappi.get_thread_stats():
++            if tstat.name == '_MainThread':
++                main_ctx_id = tstat.id
++            else:
++                ctx_ids.append(tstat.id)
++
++        fstats = yappi.get_func_stats(filter={"ctx_id": 9})
++        self.assertTrue(fstats.empty())
++        fstats = yappi.get_func_stats(
++            filter={
++                "ctx_id": main_ctx_id,
++                "name": "c"
++            }
++        )  # main thread
++        self.assertTrue(fstats.empty())
++
++        for i in ctx_ids:
++            fstats = yappi.get_func_stats(
++                filter={
++                    "ctx_id": i,
++                    "name": "a",
++                    "ncall": 1
++                }
++            )
++            self.assertEqual(fstats.pop().ncall, 1)
++            fstats = yappi.get_func_stats(filter={"ctx_id": i, "name": "b"})
++            self.assertEqual(fstats.pop().ncall, 1)
++            fstats = yappi.get_func_stats(filter={"ctx_id": i, "name": "c"})
++            self.assertEqual(fstats.pop().ncall, 1)
++
++        yappi.clear_stats()
++        yappi.start(builtins=True)
++        time.sleep(0.1)
++        yappi.stop()
++        fstats = yappi.get_func_stats(filter={"module": "time"})
++        self.assertEqual(len(fstats), 1)
++
++        # invalid filters`
++        self.assertRaises(
++            Exception, yappi.get_func_stats, filter={'tag': "sss"}
++        )
++        self.assertRaises(
++            Exception, yappi.get_func_stats, filter={'ctx_id': "None"}
++        )
++
++    def test_filter_callback(self):
++
++        def a():
++            time.sleep(0.1)
++
++        def b():
++            a()
++
++        def c():
++            pass
++
++        def d():
++            pass
++
++        yappi.set_clock_type("wall")
++        yappi.start(builtins=True)
++        a()
++        b()
++        c()
++        d()
++        stats = yappi.get_func_stats(
++            filter_callback=lambda x: yappi.func_matches(x, [a, b])
++        )
++        #stats.print_all()
++        r1 = '''
++        tests/test_functionality.py:98 a      2      0.000000  0.200350  0.100175
++        tests/test_functionality.py:101 b     1      0.000000  0.120000  0.100197
++        '''
++        self.assert_traces_almost_equal(r1, stats)
++        self.assertEqual(len(stats), 2)
++        stats = yappi.get_func_stats(
++            filter_callback=lambda x: yappi.
++            module_matches(x, [sys.modules[__name__]])
++        )
++        r1 = '''
++        tests/test_functionality.py:98 a      2      0.000000  0.230130  0.115065
++        tests/test_functionality.py:101 b     1      0.000000  0.120000  0.109011
++        tests/test_functionality.py:104 c     1      0.000000  0.000002  0.000002
++        tests/test_functionality.py:107 d     1      0.000000  0.000001  0.000001
++        '''
++        self.assert_traces_almost_equal(r1, stats)
++        self.assertEqual(len(stats), 4)
++
++        stats = yappi.get_func_stats(
++            filter_callback=lambda x: yappi.func_matches(x, [time.sleep])
++        )
++        self.assertEqual(len(stats), 1)
++        r1 = '''
++        time.sleep                            2      0.206804  0.220000  0.103402
++        '''
++        self.assert_traces_almost_equal(r1, stats)
++
++    def test_print_formatting(self):
++
++        def a():
++            pass
++
++        def b():
++            a()
++
++        func_cols = {
++            1: ("name", 48),
++            0: ("ncall", 5),
++            2: ("tsub", 8),
++        }
++        thread_cols = {
++            1: ("name", 48),
++            0: ("ttot", 8),
++        }
++
++        yappi.start()
++        a()
++        b()
++        yappi.stop()
++        fs = yappi.get_func_stats()
++        cs = fs[1].children
++        ts = yappi.get_thread_stats()
++        #fs.print_all(out=sys.stderr, columns={1:("name", 70), })
++        #cs.print_all(out=sys.stderr, columns=func_cols)
++        #ts.print_all(out=sys.stderr, columns=thread_cols)
++        #cs.print_all(out=sys.stderr, columns={})
++
++        self.assertRaises(
++            yappi.YappiError, fs.print_all, columns={1: ("namee", 9)}
++        )
++        self.assertRaises(
++            yappi.YappiError, cs.print_all, columns={1: ("dd", 0)}
++        )
++        self.assertRaises(
++            yappi.YappiError, ts.print_all, columns={1: ("tidd", 0)}
++        )
++
++    def test_get_clock(self):
++        yappi.set_clock_type('cpu')
++        self.assertEqual('cpu', yappi.get_clock_type())
++        clock_info = yappi.get_clock_info()
++        self.assertTrue('api' in clock_info)
++        self.assertTrue('resolution' in clock_info)
++
++        yappi.set_clock_type('wall')
++        self.assertEqual('wall', yappi.get_clock_type())
++
++        t0 = yappi.get_clock_time()
++        time.sleep(0.1)
++        duration = yappi.get_clock_time() - t0
++        self.assertTrue(0.05 < duration < 0.3)
++
++    def test_profile_decorator(self):
++
++        def aggregate(func, stats):
++            fname = f"tests/{func.__name__}.profile"
++            try:
++                stats.add(fname)
++            except OSError:
++                pass
++            stats.save(fname)
++            raise Exception("messing around")
++
++        @yappi.profile(return_callback=aggregate)
++        def a(x, y):
++            if x + y == 25:
++                raise Exception("")
++            return x + y
++
++        def b():
++            pass
++
++        try:
++            os.remove(
++                "tests/a.profile"
++            )  # remove the one from prev test, if available
++        except:
++            pass
++
++        # global profile is on to mess things up
++        yappi.start()
++        b()
++
++        # assert functionality and call function at same time
++        try:
++            self.assertEqual(a(1, 2), 3)
++        except:
++            pass
++        try:
++            self.assertEqual(a(2, 5), 7)
++        except:
++            pass
++        try:
++            a(4, 21)
++        except:
++            pass
++        stats = yappi.get_func_stats().add("tests/a.profile")
++        fsa = utils.find_stat_by_name(stats, 'a')
++        self.assertEqual(fsa.ncall, 3)
++        self.assertEqual(len(stats), 1)  # b() should be cleared out.
++
++        @yappi.profile(return_callback=aggregate)
++        def count_down_rec(n):
++            if n == 0:
++                return
++            count_down_rec(n - 1)
++
++        try:
++            os.remove(
++                "tests/count_down_rec.profile"
++            )  # remove the one from prev test, if available
++        except:
++            pass
++
++        try:
++            count_down_rec(4)
++        except:
++            pass
++        try:
++            count_down_rec(3)
++        except:
++            pass
++
++        stats = yappi.YFuncStats("tests/count_down_rec.profile")
++        fsrec = utils.find_stat_by_name(stats, 'count_down_rec')
++        self.assertEqual(fsrec.ncall, 9)
++        self.assertEqual(fsrec.nactualcall, 2)
++
++    def test_strip_dirs(self):
++
++        def a():
++            pass
++
++        stats = utils.run_and_get_func_stats(a, )
++        stats.strip_dirs()
++        fsa = utils.find_stat_by_name(stats, "a")
++        self.assertEqual(fsa.module, os.path.basename(fsa.module))
++
++    @unittest.skipIf(os.name == "nt", "do not run on Windows")
++    def test_run_as_script(self):
++        import re
++        p = subprocess.Popen(
++            ['yappi', os.path.join('./tests', 'run_as_script.py')],
++            stdout=subprocess.PIPE
++        )
++        out, err = p.communicate()
++        self.assertEqual(p.returncode, 0)
++        func_stats, thread_stats = re.split(
++            b'name\\s+id\\s+tid\\s+ttot\\s+scnt\\s*\n', out
++        )
++        self.assertTrue(b'FancyThread' in thread_stats)
++
++    def test_yappi_overhead(self):
++        LOOP_COUNT = 100000
++
++        def a():
++            pass
++
++        def b():
++            for i in range(LOOP_COUNT):
++                a()
++
++        t0 = time.time()
++        yappi.start()
++        b()
++        yappi.stop()
++        time_with_yappi = time.time() - t0
++        t0 = time.time()
++        b()
++        time_without_yappi = time.time() - t0
++        if time_without_yappi == 0:
++            time_without_yappi = 0.000001
++
++        # in latest v0.82, I calculated this as close to "7.0" in my machine.
++        # however, %83 of this overhead is coming from tickcount(). The other %17
++        # seems to have been evenly distributed to the internal bookkeeping
++        # structures/algorithms which seems acceptable. Note that our test only
++        # tests one function being profiled at-a-time in a short interval.
++        # profiling high number of functions in a small time
++        # is a different beast, (which is pretty unlikely in most applications)
++        # So as a conclusion: I cannot see any optimization window for Yappi that
++        # is worth implementing as we will only optimize %17 of the time.
++        sys.stderr.write("\r\nYappi puts %0.1f times overhead to the profiled application in average.\r\n" % \
++            (time_with_yappi / time_without_yappi))
++
++    def test_clear_stats_while_running(self):
++
++        def a():
++            pass
++
++        yappi.start()
++        a()
++        yappi.clear_stats()
++        a()
++        stats = yappi.get_func_stats()
++        fsa = utils.find_stat_by_name(stats, 'a')
++        self.assertEqual(fsa.ncall, 1)
++
++    def test_generator(self):
++
++        def _gen(n):
++            while (n > 0):
++                yield n
++                n -= 1
++
++        yappi.start()
++        for x in _gen(5):
++            pass
++        self.assertTrue(
++            yappi.convert2pstats(yappi.get_func_stats()) is not None
++        )
++
++    def test_slice_child_stats_and_strip_dirs(self):
++
++        def b():
++            for i in range(10000000):
++                pass
++
++        def a():
++            b()
++
++        yappi.start(builtins=True)
++        a()
++        stats = yappi.get_func_stats()
++        fsa = utils.find_stat_by_name(stats, 'a')
++        fsb = utils.find_stat_by_name(stats, 'b')
++        self.assertTrue(fsa.children[0:1] is not None)
++        prev_afullname = fsa.full_name
++        prev_bchildfullname = fsa.children[fsb].full_name
++        stats.strip_dirs()
++        self.assertTrue(len(prev_afullname) > len(fsa.full_name))
++        self.assertTrue(
++            len(prev_bchildfullname) > len(fsa.children[fsb].full_name)
++        )
++
++    def test_children_stat_functions(self):
++        _timings = {"a_1": 5, "b_1": 3, "c_1": 1}
++        _yappi._set_test_timings(_timings)
++
++        def b():
++            pass
++
++        def c():
++            pass
++
++        def a():
++            b()
++            c()
++
++        yappi.start()
++        a()
++        b()  # non-child call
++        c()  # non-child call
++        stats = yappi.get_func_stats()
++        fsa = utils.find_stat_by_name(stats, 'a')
++        childs_of_a = fsa.children.get().sort("tavg", "desc")
++        prev_item = None
++        for item in childs_of_a:
++            if prev_item:
++                self.assertTrue(prev_item.tavg > item.tavg)
++            prev_item = item
++        childs_of_a.sort("name", "desc")
++        prev_item = None
++        for item in childs_of_a:
++            if prev_item:
++                self.assertTrue(prev_item.name > item.name)
++            prev_item = item
++        childs_of_a.clear()
++        self.assertTrue(childs_of_a.empty())
++
++    def test_no_stats_different_clock_type_load(self):
++
++        def a():
++            pass
++
++        yappi.start()
++        a()
++        yappi.stop()
++        yappi.get_func_stats().save("tests/ystats1.ys")
++        yappi.clear_stats()
++        yappi.set_clock_type("WALL")
++        yappi.start()
++        yappi.stop()
++        stats = yappi.get_func_stats().add("tests/ystats1.ys")
++        fsa = utils.find_stat_by_name(stats, 'a')
++        self.assertTrue(fsa is not None)
++
++    def test_subsequent_profile(self):
++        _timings = {"a_1": 1, "b_1": 1}
++        _yappi._set_test_timings(_timings)
++
++        def a():
++            pass
++
++        def b():
++            pass
++
++        yappi.start()
++        a()
++        yappi.stop()
++        yappi.start()
++        b()
++        yappi.stop()
++        stats = yappi.get_func_stats()
++        fsa = utils.find_stat_by_name(stats, 'a')
++        fsb = utils.find_stat_by_name(stats, 'b')
++        self.assertTrue(fsa is not None)
++        self.assertTrue(fsb is not None)
++        self.assertEqual(fsa.ttot, 1)
++        self.assertEqual(fsb.ttot, 1)
++
++    def test_lambda(self):
++        f = lambda: time.sleep(0.3)
++        yappi.set_clock_type("wall")
++        yappi.start()
++        f()
++        stats = yappi.get_func_stats()
++        fsa = utils.find_stat_by_name(stats, '<lambda>')
++        self.assertTrue(fsa.ttot > 0.1)
++
++    def test_module_stress(self):
++        self.assertEqual(yappi.is_running(), False)
++
++        yappi.start()
++        yappi.clear_stats()
++        self.assertRaises(_yappi.error, yappi.set_clock_type, "wall")
++
++        yappi.stop()
++        yappi.clear_stats()
++        yappi.set_clock_type("cpu")
++        self.assertRaises(yappi.YappiError, yappi.set_clock_type, "dummy")
++        self.assertEqual(yappi.is_running(), False)
++        yappi.clear_stats()
++        yappi.clear_stats()
++
++    def test_stat_sorting(self):
++        _timings = {"a_1": 13, "b_1": 10, "a_2": 6, "b_2": 1}
++        _yappi._set_test_timings(_timings)
++
++        self._ncall = 1
++
++        def a():
++            b()
++
++        def b():
++            if self._ncall == 2:
++                return
++            self._ncall += 1
++            a()
++
++        stats = utils.run_and_get_func_stats(a)
++        stats = stats.sort("totaltime", "desc")
++        prev_stat = None
++        for stat in stats:
++            if prev_stat:
++                self.assertTrue(prev_stat.ttot >= stat.ttot)
++            prev_stat = stat
++        stats = stats.sort("totaltime", "asc")
++        prev_stat = None
++        for stat in stats:
++            if prev_stat:
++                self.assertTrue(prev_stat.ttot <= stat.ttot)
++            prev_stat = stat
++        stats = stats.sort("avgtime", "asc")
++        prev_stat = None
++        for stat in stats:
++            if prev_stat:
++                self.assertTrue(prev_stat.tavg <= stat.tavg)
++            prev_stat = stat
++        stats = stats.sort("name", "asc")
++        prev_stat = None
++        for stat in stats:
++            if prev_stat:
++                self.assertTrue(prev_stat.name <= stat.name)
++            prev_stat = stat
++        stats = stats.sort("subtime", "asc")
++        prev_stat = None
++        for stat in stats:
++            if prev_stat:
++                self.assertTrue(prev_stat.tsub <= stat.tsub)
++            prev_stat = stat
++
++        self.assertRaises(
++            yappi.YappiError, stats.sort, "invalid_func_sorttype_arg"
++        )
++        self.assertRaises(
++            yappi.YappiError, stats.sort, "totaltime",
++            "invalid_func_sortorder_arg"
++        )
++
++    def test_start_flags(self):
++        self.assertEqual(_yappi._get_start_flags(), None)
++        yappi.start()
++
++        def a():
++            pass
++
++        a()
++        self.assertEqual(_yappi._get_start_flags()["profile_builtins"], 0)
++        self.assertEqual(_yappi._get_start_flags()["profile_multicontext"], 1)
++        self.assertEqual(len(yappi.get_thread_stats()), 1)
++
++    def test_builtin_profiling(self):
++
++        def a():
++            time.sleep(0.4)  # is a builtin function
++
++        yappi.set_clock_type('wall')
++
++        yappi.start(builtins=True)
++        a()
++        stats = yappi.get_func_stats()
++        fsa = utils.find_stat_by_name(stats, 'sleep')
++        self.assertTrue(fsa is not None)
++        self.assertTrue(fsa.ttot > 0.3)
++        yappi.stop()
++        yappi.clear_stats()
++
++        def a():
++            pass
++
++        yappi.start()
++        t = threading.Thread(target=a)
++        t.start()
++        t.join()
++        stats = yappi.get_func_stats()
++
++    def test_singlethread_profiling(self):
++        yappi.set_clock_type('wall')
++
++        def a():
++            time.sleep(0.2)
++
++        class Worker1(threading.Thread):
++
++            def a(self):
++                time.sleep(0.3)
++
++            def run(self):
++                self.a()
++
++        yappi.start(profile_threads=False)
++
++        c = Worker1()
++        c.start()
++        c.join()
++        a()
++        stats = yappi.get_func_stats()
++        fsa1 = utils.find_stat_by_name(stats, 'Worker1.a')
++        fsa2 = utils.find_stat_by_name(stats, 'a')
++        self.assertTrue(fsa1 is None)
++        self.assertTrue(fsa2 is not None)
++        self.assertTrue(fsa2.ttot > 0.1)
++
++    def test_run(self):
++
++        def profiled():
++            pass
++
++        yappi.clear_stats()
++        try:
++            with yappi.run():
++                profiled()
++            stats = yappi.get_func_stats()
++        finally:
++            yappi.clear_stats()
++
++        self.assertIsNotNone(utils.find_stat_by_name(stats, 'profiled'))
++
++    def test_run_recursive(self):
++
++        def profiled():
++            pass
++
++        def not_profiled():
++            pass
++
++        yappi.clear_stats()
++        try:
++            with yappi.run():
++                with yappi.run():
++                    profiled()
++                # Profiling stopped here
++                not_profiled()
++            stats = yappi.get_func_stats()
++        finally:
++            yappi.clear_stats()
++
++        self.assertIsNotNone(utils.find_stat_by_name(stats, 'profiled'))
++        self.assertIsNone(utils.find_stat_by_name(stats, 'not_profiled'))
++
++
++class StatSaveScenarios(utils.YappiUnitTestCase):
++
++    def test_pstats_conversion(self):
++
++        def pstat_id(fs):
++            return (fs.module, fs.lineno, fs.name)
++
++        def a():
++            d()
++
++        def b():
++            d()
++
++        def c():
++            pass
++
++        def d():
++            pass
++
++        _timings = {"a_1": 12, "b_1": 7, "c_1": 5, "d_1": 2}
++        _yappi._set_test_timings(_timings)
++        stats = utils.run_and_get_func_stats(a, )
++        stats.strip_dirs()
++        stats.save("tests/a1.pstats", type="pstat")
++        fsa_pid = pstat_id(utils.find_stat_by_name(stats, "a"))
++        fsd_pid = pstat_id(utils.find_stat_by_name(stats, "d"))
++        yappi.clear_stats()
++        _yappi._set_test_timings(_timings)
++        stats = utils.run_and_get_func_stats(a, )
++        stats.strip_dirs()
++        stats.save("tests/a2.pstats", type="pstat")
++        yappi.clear_stats()
++        _yappi._set_test_timings(_timings)
++        stats = utils.run_and_get_func_stats(b, )
++        stats.strip_dirs()
++        stats.save("tests/b1.pstats", type="pstat")
++        fsb_pid = pstat_id(utils.find_stat_by_name(stats, "b"))
++        yappi.clear_stats()
++        _yappi._set_test_timings(_timings)
++        stats = utils.run_and_get_func_stats(c, )
++        stats.strip_dirs()
++        stats.save("tests/c1.pstats", type="pstat")
++        fsc_pid = pstat_id(utils.find_stat_by_name(stats, "c"))
++
++        # merge saved stats and check pstats values are correct
++        import pstats
++        p = pstats.Stats(
++            'tests/a1.pstats', 'tests/a2.pstats', 'tests/b1.pstats',
++            'tests/c1.pstats'
++        )
++        p.strip_dirs()
++        # ct = ttot, tt = tsub
++        (cc, nc, tt, ct, callers) = p.stats[fsa_pid]
++        self.assertEqual(cc, nc, 2)
++        self.assertEqual(tt, 20)
++        self.assertEqual(ct, 24)
++        (cc, nc, tt, ct, callers) = p.stats[fsd_pid]
++        self.assertEqual(cc, nc, 3)
++        self.assertEqual(tt, 6)
++        self.assertEqual(ct, 6)
++        self.assertEqual(len(callers), 2)
++        (cc, nc, tt, ct) = callers[fsa_pid]
++        self.assertEqual(cc, nc, 2)
++        self.assertEqual(tt, 4)
++        self.assertEqual(ct, 4)
++        (cc, nc, tt, ct) = callers[fsb_pid]
++        self.assertEqual(cc, nc, 1)
++        self.assertEqual(tt, 2)
++        self.assertEqual(ct, 2)
++
++    def test_merge_stats(self):
++        _timings = {
++            "a_1": 15,
++            "b_1": 14,
++            "c_1": 12,
++            "d_1": 10,
++            "e_1": 9,
++            "f_1": 7,
++            "g_1": 6,
++            "h_1": 5,
++            "i_1": 1
++        }
++        _yappi._set_test_timings(_timings)
++
++        def a():
++            b()
++
++        def b():
++            c()
++
++        def c():
++            d()
++
++        def d():
++            e()
++
++        def e():
++            f()
++
++        def f():
++            g()
++
++        def g():
++            h()
++
++        def h():
++            i()
++
++        def i():
++            pass
++
++        yappi.start()
++        a()
++        a()
++        yappi.stop()
++        stats = yappi.get_func_stats()
++        self.assertRaises(
++            NotImplementedError, stats.save, "", "INVALID_SAVE_TYPE"
++        )
++        stats.save("tests/ystats2.ys")
++        yappi.clear_stats()
++        _yappi._set_test_timings(_timings)
++        yappi.start()
++        a()
++        stats = yappi.get_func_stats().add("tests/ystats2.ys")
++        fsa = utils.find_stat_by_name(stats, "a")
++        fsb = utils.find_stat_by_name(stats, "b")
++        fsc = utils.find_stat_by_name(stats, "c")
++        fsd = utils.find_stat_by_name(stats, "d")
++        fse = utils.find_stat_by_name(stats, "e")
++        fsf = utils.find_stat_by_name(stats, "f")
++        fsg = utils.find_stat_by_name(stats, "g")
++        fsh = utils.find_stat_by_name(stats, "h")
++        fsi = utils.find_stat_by_name(stats, "i")
++        self.assertEqual(fsa.ttot, 45)
++        self.assertEqual(fsa.ncall, 3)
++        self.assertEqual(fsa.nactualcall, 3)
++        self.assertEqual(fsa.tsub, 3)
++        self.assertEqual(fsa.children[fsb].ttot, fsb.ttot)
++        self.assertEqual(fsa.children[fsb].tsub, fsb.tsub)
++        self.assertEqual(fsb.children[fsc].ttot, fsc.ttot)
++        self.assertEqual(fsb.children[fsc].tsub, fsc.tsub)
++        self.assertEqual(fsc.tsub, 6)
++        self.assertEqual(fsc.children[fsd].ttot, fsd.ttot)
++        self.assertEqual(fsc.children[fsd].tsub, fsd.tsub)
++        self.assertEqual(fsd.children[fse].ttot, fse.ttot)
++        self.assertEqual(fsd.children[fse].tsub, fse.tsub)
++        self.assertEqual(fse.children[fsf].ttot, fsf.ttot)
++        self.assertEqual(fse.children[fsf].tsub, fsf.tsub)
++        self.assertEqual(fsf.children[fsg].ttot, fsg.ttot)
++        self.assertEqual(fsf.children[fsg].tsub, fsg.tsub)
++        self.assertEqual(fsg.ttot, 18)
++        self.assertEqual(fsg.tsub, 3)
++        self.assertEqual(fsg.children[fsh].ttot, fsh.ttot)
++        self.assertEqual(fsg.children[fsh].tsub, fsh.tsub)
++        self.assertEqual(fsh.ttot, 15)
++        self.assertEqual(fsh.tsub, 12)
++        self.assertEqual(fsh.tavg, 5)
++        self.assertEqual(fsh.children[fsi].ttot, fsi.ttot)
++        self.assertEqual(fsh.children[fsi].tsub, fsi.tsub)
++        #stats.debug_print()
++
++    def test_merge_multithreaded_stats(self):
++        import _yappi
++        timings = {"a_1": 2, "b_1": 1}
++        _yappi._set_test_timings(timings)
++
++        def a():
++            pass
++
++        def b():
++            pass
++
++        yappi.start()
++        t = threading.Thread(target=a)
++        t.start()
++        t.join()
++        t = threading.Thread(target=b)
++        t.start()
++        t.join()
++        yappi.get_func_stats().save("tests/ystats1.ys")
++        yappi.clear_stats()
++        _yappi._set_test_timings(timings)
++        self.assertEqual(len(yappi.get_func_stats()), 0)
++        self.assertEqual(len(yappi.get_thread_stats()), 1)
++        t = threading.Thread(target=a)
++        t.start()
++        t.join()
++
++        self.assertEqual(_yappi._get_start_flags()["profile_builtins"], 0)
++        self.assertEqual(_yappi._get_start_flags()["profile_multicontext"], 1)
++        yappi.get_func_stats().save("tests/ystats2.ys")
++
++        stats = yappi.YFuncStats([
++            "tests/ystats1.ys",
++            "tests/ystats2.ys",
++        ])
++        fsa = utils.find_stat_by_name(stats, "a")
++        fsb = utils.find_stat_by_name(stats, "b")
++        self.assertEqual(fsa.ncall, 2)
++        self.assertEqual(fsb.ncall, 1)
++        self.assertEqual(fsa.tsub, fsa.ttot, 4)
++        self.assertEqual(fsb.tsub, fsb.ttot, 1)
++
++    def test_merge_load_different_clock_types(self):
++        yappi.start(builtins=True)
++
++        def a():
++            b()
++
++        def b():
++            c()
++
++        def c():
++            pass
++
++        t = threading.Thread(target=a)
++        t.start()
++        t.join()
++        yappi.get_func_stats().sort("name", "asc").save("tests/ystats1.ys")
++        yappi.stop()
++        yappi.clear_stats()
++        yappi.start(builtins=False)
++        t = threading.Thread(target=a)
++        t.start()
++        t.join()
++        yappi.get_func_stats().save("tests/ystats2.ys")
++        yappi.stop()
++        self.assertRaises(_yappi.error, yappi.set_clock_type, "wall")
++        yappi.clear_stats()
++        yappi.set_clock_type("wall")
++        yappi.start()
++        t = threading.Thread(target=a)
++        t.start()
++        t.join()
++        yappi.get_func_stats().save("tests/ystats3.ys")
++        self.assertRaises(
++            yappi.YappiError,
++            yappi.YFuncStats().add("tests/ystats1.ys").add, "tests/ystats3.ys"
++        )
++        stats = yappi.YFuncStats(["tests/ystats1.ys",
++                                  "tests/ystats2.ys"]).sort("name")
++        fsa = utils.find_stat_by_name(stats, "a")
++        fsb = utils.find_stat_by_name(stats, "b")
++        fsc = utils.find_stat_by_name(stats, "c")
++        self.assertEqual(fsa.ncall, 2)
++        self.assertEqual(fsa.ncall, fsb.ncall, fsc.ncall)
++
++    def test_merge_aabab_aabbc(self):
++        _timings = {
++            "a_1": 15,
++            "a_2": 14,
++            "b_1": 12,
++            "a_3": 10,
++            "b_2": 9,
++            "c_1": 4
++        }
++        _yappi._set_test_timings(_timings)
++
++        def a():
++            if self._ncall == 1:
++                self._ncall += 1
++                a()
++            elif self._ncall == 5:
++                self._ncall += 1
++                a()
++            else:
++                b()
++
++        def b():
++            if self._ncall == 2:
++                self._ncall += 1
++                a()
++            elif self._ncall == 6:
++                self._ncall += 1
++                b()
++            elif self._ncall == 7:
++                c()
++            else:
++                return
++
++        def c():
++            pass
++
++        self._ncall = 1
++        stats = utils.run_and_get_func_stats(a, )
++        stats.save("tests/ystats1.ys")
++        yappi.clear_stats()
++        _yappi._set_test_timings(_timings)
++        #stats.print_all()
++
++        self._ncall = 5
++        stats = utils.run_and_get_func_stats(a, )
++        stats.save("tests/ystats2.ys")
++
++        #stats.print_all()
++
++        def a():  # same name but another function(code object)
++            pass
++
++        yappi.start()
++        a()
++        stats = yappi.get_func_stats().add(
++            ["tests/ystats1.ys", "tests/ystats2.ys"]
++        )
++        #stats.print_all()
++        self.assertEqual(len(stats), 4)
++
++        fsa = None
++        for stat in stats:
++            if stat.name == "a" and stat.ttot == 45:
++                fsa = stat
++                break
++        self.assertTrue(fsa is not None)
++
++        self.assertEqual(fsa.ncall, 7)
++        self.assertEqual(fsa.nactualcall, 3)
++        self.assertEqual(fsa.ttot, 45)
++        self.assertEqual(fsa.tsub, 10)
++        fsb = utils.find_stat_by_name(stats, "b")
++        fsc = utils.find_stat_by_name(stats, "c")
++        self.assertEqual(fsb.ncall, 6)
++        self.assertEqual(fsb.nactualcall, 3)
++        self.assertEqual(fsb.ttot, 36)
++        self.assertEqual(fsb.tsub, 27)
++        self.assertEqual(fsb.tavg, 6)
++        self.assertEqual(fsc.ttot, 8)
++        self.assertEqual(fsc.tsub, 8)
++        self.assertEqual(fsc.tavg, 4)
++        self.assertEqual(fsc.nactualcall, fsc.ncall, 2)
++
++
++class MultithreadedScenarios(utils.YappiUnitTestCase):
++
++    def test_issue_32(self):
++        '''
++        Start yappi from different thread and we get Internal Error(15) as 
++        the current_ctx_id() called while enumerating the threads in start() 
++        and as it does not swap to the enumerated ThreadState* the THreadState_GetDict()
++        returns wrong object and thus sets an invalid id for the _ctx structure.
++
++        When this issue happens multiple Threads have same tid as the internal ts_ptr
++        will be same for different contexts. So, let's see if that happens
++        '''
++
++        def foo():
++            time.sleep(0.2)
++
++        def bar():
++            time.sleep(0.1)
++
++        def thread_func():
++            yappi.set_clock_type("wall")
++            yappi.start()
++
++            bar()
++
++        t = threading.Thread(target=thread_func)
++        t.start()
++        t.join()
++
++        foo()
++
++        yappi.stop()
++
++        thread_ids = set()
++        for tstat in yappi.get_thread_stats():
++            self.assertTrue(tstat.tid not in thread_ids)
++            thread_ids.add(tstat.tid)
++
++    def test_subsequent_profile(self):
++        WORKER_COUNT = 5
++
++        def a():
++            pass
++
++        def b():
++            pass
++
++        def c():
++            pass
++
++        _timings = {
++            "a_1": 3,
++            "b_1": 2,
++            "c_1": 1,
++        }
++
++        yappi.start()
++
++        def g():
++            pass
++
++        g()
++        yappi.stop()
++        yappi.clear_stats()
++        _yappi._set_test_timings(_timings)
++        yappi.start()
++
++        _dummy = []
++        for i in range(WORKER_COUNT):
++            t = threading.Thread(target=a)
++            t.start()
++            t.join()
++        for i in range(WORKER_COUNT):
++            t = threading.Thread(target=b)
++            t.start()
++            _dummy.append(t)
++            t.join()
++        for i in range(WORKER_COUNT):
++            t = threading.Thread(target=a)
++            t.start()
++            t.join()
++        for i in range(WORKER_COUNT):
++            t = threading.Thread(target=c)
++            t.start()
++            t.join()
++        yappi.stop()
++        yappi.start()
++
++        def f():
++            pass
++
++        f()
++        stats = yappi.get_func_stats()
++        fsa = utils.find_stat_by_name(stats, 'a')
++        fsb = utils.find_stat_by_name(stats, 'b')
++        fsc = utils.find_stat_by_name(stats, 'c')
++        self.assertEqual(fsa.ncall, 10)
++        self.assertEqual(fsb.ncall, 5)
++        self.assertEqual(fsc.ncall, 5)
++        self.assertEqual(fsa.ttot, fsa.tsub, 30)
++        self.assertEqual(fsb.ttot, fsb.tsub, 10)
++        self.assertEqual(fsc.ttot, fsc.tsub, 5)
++
++        # MACOSx optimizes by only creating one worker thread
++        self.assertTrue(len(yappi.get_thread_stats()) >= 2)
++
++    def test_basic(self):
++        yappi.set_clock_type('wall')
++
++        def dummy():
++            pass
++
++        def a():
++            time.sleep(0.2)
++
++        class Worker1(threading.Thread):
++
++            def a(self):
++                time.sleep(0.3)
++
++            def run(self):
++                self.a()
++
++        yappi.start(builtins=False, profile_threads=True)
++
++        c = Worker1()
++        c.start()
++        c.join()
++        a()
++        stats = yappi.get_func_stats()
++        fsa1 = utils.find_stat_by_name(stats, 'Worker1.a')
++        fsa2 = utils.find_stat_by_name(stats, 'a')
++        self.assertTrue(fsa1 is not None)
++        self.assertTrue(fsa2 is not None)
++        self.assertTrue(fsa1.ttot > 0.2)
++        self.assertTrue(fsa2.ttot > 0.1)
++        tstats = yappi.get_thread_stats()
++        self.assertEqual(len(tstats), 2)
++        tsa = utils.find_stat_by_name(tstats, 'Worker1')
++        tsm = utils.find_stat_by_name(tstats, '_MainThread')
++        dummy()  # call dummy to force ctx name to be retrieved again.
++        self.assertTrue(tsa is not None)
++        # TODO: I put dummy() to fix below, remove the comments after a while.
++        self.assertTrue( # FIX: I see this fails sometimes?
++            tsm is not None,
++            f"Could not find \"_MainThread\". Found: {', '.join(utils.get_stat_names(tstats))}")
++
++    def test_ctx_stats(self):
++        from threading import Thread
++        DUMMY_WORKER_COUNT = 5
++        yappi.start()
++
++        class DummyThread(Thread):
++            pass
++
++        def dummy():
++            pass
++
++        def dummy_worker():
++            pass
++
++        for i in range(DUMMY_WORKER_COUNT):
++            t = DummyThread(target=dummy_worker)
++            t.start()
++            t.join()
++        yappi.stop()
++        stats = yappi.get_thread_stats()
++        tsa = utils.find_stat_by_name(stats, "DummyThread")
++        self.assertTrue(tsa is not None)
++        yappi.clear_stats()
++        time.sleep(1.0)
++        _timings = {
++            "a_1": 6,
++            "b_1": 5,
++            "c_1": 3,
++            "d_1": 1,
++            "a_2": 4,
++            "b_2": 3,
++            "c_2": 2,
++            "d_2": 1
++        }
++        _yappi._set_test_timings(_timings)
++
++        class Thread1(Thread):
++            pass
++
++        class Thread2(Thread):
++            pass
++
++        def a():
++            b()
++
++        def b():
++            c()
++
++        def c():
++            d()
++
++        def d():
++            time.sleep(0.6)
++
++        yappi.set_clock_type("wall")
++        yappi.start()
++        t1 = Thread1(target=a)
++        t1.start()
++        t2 = Thread2(target=a)
++        t2.start()
++        t1.join()
++        t2.join()
++        stats = yappi.get_thread_stats()
++
++        # the fist clear_stats clears the context table?
++        tsa = utils.find_stat_by_name(stats, "DummyThread")
++        self.assertTrue(tsa is None)
++
++        tst1 = utils.find_stat_by_name(stats, "Thread1")
++        tst2 = utils.find_stat_by_name(stats, "Thread2")
++        tsmain = utils.find_stat_by_name(stats, "_MainThread")
++        dummy()  # call dummy to force ctx name to be retrieved again.
++        self.assertTrue(len(stats) == 3)
++        self.assertTrue(tst1 is not None)
++        self.assertTrue(tst2 is not None)
++        # TODO: I put dummy() to fix below, remove the comments after a while.
++        self.assertTrue( # FIX: I see this fails sometimes
++            tsmain is not None,
++            f"Could not find \"_MainThread\". Found: {', '.join(utils.get_stat_names(stats))}")
++        self.assertTrue(1.0 > tst2.ttot >= 0.5)
++        self.assertTrue(1.0 > tst1.ttot >= 0.5)
++
++        # test sorting of the ctx stats
++        stats = stats.sort("totaltime", "desc")
++        prev_stat = None
++        for stat in stats:
++            if prev_stat:
++                self.assertTrue(prev_stat.ttot >= stat.ttot)
++            prev_stat = stat
++        stats = stats.sort("totaltime", "asc")
++        prev_stat = None
++        for stat in stats:
++            if prev_stat:
++                self.assertTrue(prev_stat.ttot <= stat.ttot)
++            prev_stat = stat
++        stats = stats.sort("schedcount", "desc")
++        prev_stat = None
++        for stat in stats:
++            if prev_stat:
++                self.assertTrue(prev_stat.sched_count >= stat.sched_count)
++            prev_stat = stat
++        stats = stats.sort("name", "desc")
++        prev_stat = None
++        for stat in stats:
++            if prev_stat:
++                self.assertTrue(prev_stat.name.lower() >= stat.name.lower())
++            prev_stat = stat
++        self.assertRaises(
++            yappi.YappiError, stats.sort, "invalid_thread_sorttype_arg"
++        )
++        self.assertRaises(
++            yappi.YappiError, stats.sort, "invalid_thread_sortorder_arg"
++        )
++
++    def test_ctx_stats_cpu(self):
++
++        def get_thread_name():
++            try:
++                return threading.current_thread().name
++            except AttributeError:
++                return "Anonymous"
++
++        def burn_cpu(sec):
++            t0 = yappi.get_clock_time()
++            elapsed = 0
++            while (elapsed < sec):
++                for _ in range(1000):
++                    pass
++                elapsed = yappi.get_clock_time() - t0
++
++        def test():
++
++            ts = []
++            for i in (0.01, 0.05, 0.1):
++                t = threading.Thread(target=burn_cpu, args=(i, ))
++                t.name = f"burn_cpu-{str(i)}"
++                t.start()
++                ts.append(t)
++            for t in ts:
++                t.join()
++
++        yappi.set_clock_type("cpu")
++        yappi.set_context_name_callback(get_thread_name)
++
++        yappi.start()
++
++        test()
++
++        yappi.stop()
++
++        tstats = yappi.get_thread_stats()
++        r1 = '''
++        burn_cpu-0.1      3      123145356058624  0.100105  8
++        burn_cpu-0.05     2      123145361313792  0.050149  8
++        burn_cpu-0.01     1      123145356058624  0.010127  2
++        MainThread        0      4321620864       0.001632  6
++        '''
++        self.assert_ctx_stats_almost_equal(r1, tstats)
++
++    def test_producer_consumer_with_queues(self):
++        # we currently just stress yappi, no functionality test is done here.
++        yappi.start()
++        from queue import Queue
++        from threading import Thread
++        WORKER_THREAD_COUNT = 50
++        WORK_ITEM_COUNT = 2000
++
++        def worker():
++            while True:
++                item = q.get()
++                # do the work with item
++                q.task_done()
++
++        q = Queue()
++        for i in range(WORKER_THREAD_COUNT):
++            t = Thread(target=worker)
++            t.daemon = True
++            t.start()
++
++        for item in range(WORK_ITEM_COUNT):
++            q.put(item)
++        q.join()  # block until all tasks are done
++        #yappi.get_func_stats().sort("callcount").print_all()
++        yappi.stop()
++
++    def test_temporary_lock_waiting(self):
++        yappi.start()
++        _lock = threading.Lock()
++
++        def worker():
++            _lock.acquire()
++            try:
++                time.sleep(1.0)
++            finally:
++                _lock.release()
++
++        t1 = threading.Thread(target=worker)
++        t2 = threading.Thread(target=worker)
++        t1.start()
++        t2.start()
++        t1.join()
++        t2.join()
++        #yappi.get_func_stats().sort("callcount").print_all()
++        yappi.stop()
++
++    @unittest.skipIf(os.name != "posix", "requires Posix compliant OS")
++    def test_signals_with_blocking_calls(self):
++        import signal, os, time
++
++        # just to verify if signal is handled correctly and stats/yappi are not corrupted.
++        def handler(signum, frame):
++            raise Exception("Signal handler executed!")
++
++        yappi.start()
++        signal.signal(signal.SIGALRM, handler)
++        signal.alarm(1)
++        self.assertRaises(Exception, time.sleep, 2)
++        stats = yappi.get_func_stats()
++        fsh = utils.find_stat_by_name(stats, "handler")
++        self.assertTrue(fsh is not None)
++
++    def test_concurrent_futures(self):
++        yappi.start()
++        from concurrent.futures import ThreadPoolExecutor
++        with ThreadPoolExecutor(max_workers=5) as executor:
++            f = executor.submit(pow, 5, 2)
++            self.assertEqual(f.result(), 25)
++        time.sleep(1.0)
++        yappi.stop()
++
++    def test_barrier(self):
++        yappi.start()
++        b = threading.Barrier(2, timeout=1)
++
++        def worker():
++            try:
++                b.wait()
++            except threading.BrokenBarrierError:
++                pass
++            except Exception:
++                raise Exception("BrokenBarrierError not raised")
++
++        t1 = threading.Thread(target=worker)
++        t1.start()
++        #b.wait()
++        t1.join()
++        yappi.stop()
++
++
++class NonRecursiveFunctions(utils.YappiUnitTestCase):
++
++    def test_abcd(self):
++        _timings = {"a_1": 6, "b_1": 5, "c_1": 3, "d_1": 1}
++        _yappi._set_test_timings(_timings)
++
++        def a():
++            b()
++
++        def b():
++            c()
++
++        def c():
++            d()
++
++        def d():
++            pass
++
++        stats = utils.run_and_get_func_stats(a)
++        fsa = utils.find_stat_by_name(stats, 'a')
++        fsb = utils.find_stat_by_name(stats, 'b')
++        fsc = utils.find_stat_by_name(stats, 'c')
++        fsd = utils.find_stat_by_name(stats, 'd')
++        cfsab = fsa.children[fsb]
++        cfsbc = fsb.children[fsc]
++        cfscd = fsc.children[fsd]
++
++        self.assertEqual(fsa.ttot, 6)
++        self.assertEqual(fsa.tsub, 1)
++        self.assertEqual(fsb.ttot, 5)
++        self.assertEqual(fsb.tsub, 2)
++        self.assertEqual(fsc.ttot, 3)
++        self.assertEqual(fsc.tsub, 2)
++        self.assertEqual(fsd.ttot, 1)
++        self.assertEqual(fsd.tsub, 1)
++        self.assertEqual(cfsab.ttot, 5)
++        self.assertEqual(cfsab.tsub, 2)
++        self.assertEqual(cfsbc.ttot, 3)
++        self.assertEqual(cfsbc.tsub, 2)
++        self.assertEqual(cfscd.ttot, 1)
++        self.assertEqual(cfscd.tsub, 1)
++
++    def test_stop_in_middle(self):
++        _timings = {"a_1": 6, "b_1": 4}
++        _yappi._set_test_timings(_timings)
++
++        def a():
++            b()
++            yappi.stop()
++
++        def b():
++            time.sleep(0.2)
++
++        yappi.start()
++        a()
++        stats = yappi.get_func_stats()
++        fsa = utils.find_stat_by_name(stats, 'a')
++        fsb = utils.find_stat_by_name(stats, 'b')
++
++        self.assertEqual(fsa.ncall, 1)
++        self.assertEqual(fsa.nactualcall, 0)
++        self.assertEqual(fsa.ttot, 0)  # no call_leave called
++        self.assertEqual(fsa.tsub, 0)  # no call_leave called
++        self.assertEqual(fsb.ttot, 4)
++
++
++class RecursiveFunctions(utils.YappiUnitTestCase):
++
++    def test_fibonacci(self):
++
++        def fib(n):
++            if n > 1:
++                return fib(n - 1) + fib(n - 2)
++            else:
++                return n
++
++        stats = utils.run_and_get_func_stats(fib, 22)
++        fs = utils.find_stat_by_name(stats, 'fib')
++        self.assertEqual(fs.ncall, 57313)
++        self.assertEqual(fs.ttot, fs.tsub)
++
++    def test_abcadc(self):
++        _timings = {
++            "a_1": 20,
++            "b_1": 19,
++            "c_1": 17,
++            "a_2": 13,
++            "d_1": 12,
++            "c_2": 10,
++            "a_3": 5
++        }
++        _yappi._set_test_timings(_timings)
++
++        def a(n):
++            if n == 3:
++                return
++            if n == 1 + 1:
++                d(n)
++            else:
++                b(n)
++
++        def b(n):
++            c(n)
++
++        def c(n):
++            a(n + 1)
++
++        def d(n):
++            c(n)
++
++        stats = utils.run_and_get_func_stats(a, 1)
++        fsa = utils.find_stat_by_name(stats, 'a')
++        fsb = utils.find_stat_by_name(stats, 'b')
++        fsc = utils.find_stat_by_name(stats, 'c')
++        fsd = utils.find_stat_by_name(stats, 'd')
++        self.assertEqual(fsa.ncall, 3)
++        self.assertEqual(fsa.nactualcall, 1)
++        self.assertEqual(fsa.ttot, 20)
++        self.assertEqual(fsa.tsub, 7)
++        self.assertEqual(fsb.ttot, 19)
++        self.assertEqual(fsb.tsub, 2)
++        self.assertEqual(fsc.ttot, 17)
++        self.assertEqual(fsc.tsub, 9)
++        self.assertEqual(fsd.ttot, 12)
++        self.assertEqual(fsd.tsub, 2)
++        cfsca = fsc.children[fsa]
++        self.assertEqual(cfsca.nactualcall, 0)
++        self.assertEqual(cfsca.ncall, 2)
++        self.assertEqual(cfsca.ttot, 13)
++        self.assertEqual(cfsca.tsub, 6)
++
++    def test_aaaa(self):
++        _timings = {"d_1": 9, "d_2": 7, "d_3": 3, "d_4": 2}
++        _yappi._set_test_timings(_timings)
++
++        def d(n):
++            if n == 3:
++                return
++            d(n + 1)
++
++        stats = utils.run_and_get_func_stats(d, 0)
++        fsd = utils.find_stat_by_name(stats, 'd')
++        self.assertEqual(fsd.ncall, 4)
++        self.assertEqual(fsd.nactualcall, 1)
++        self.assertEqual(fsd.ttot, 9)
++        self.assertEqual(fsd.tsub, 9)
++        cfsdd = fsd.children[fsd]
++        self.assertEqual(cfsdd.ttot, 7)
++        self.assertEqual(cfsdd.tsub, 7)
++        self.assertEqual(cfsdd.ncall, 3)
++        self.assertEqual(cfsdd.nactualcall, 0)
++
++    def test_abcabc(self):
++        _timings = {
++            "a_1": 20,
++            "b_1": 19,
++            "c_1": 17,
++            "a_2": 13,
++            "b_2": 11,
++            "c_2": 9,
++            "a_3": 6
++        }
++        _yappi._set_test_timings(_timings)
++
++        def a(n):
++            if n == 3:
++                return
++            else:
++                b(n)
++
++        def b(n):
++            c(n)
++
++        def c(n):
++            a(n + 1)
++
++        stats = utils.run_and_get_func_stats(a, 1)
++        fsa = utils.find_stat_by_name(stats, 'a')
++        fsb = utils.find_stat_by_name(stats, 'b')
++        fsc = utils.find_stat_by_name(stats, 'c')
++        self.assertEqual(fsa.ncall, 3)
++        self.assertEqual(fsa.nactualcall, 1)
++        self.assertEqual(fsa.ttot, 20)
++        self.assertEqual(fsa.tsub, 9)
++        self.assertEqual(fsb.ttot, 19)
++        self.assertEqual(fsb.tsub, 4)
++        self.assertEqual(fsc.ttot, 17)
++        self.assertEqual(fsc.tsub, 7)
++        cfsab = fsa.children[fsb]
++        cfsbc = fsb.children[fsc]
++        cfsca = fsc.children[fsa]
++        self.assertEqual(cfsab.ttot, 19)
++        self.assertEqual(cfsab.tsub, 4)
++        self.assertEqual(cfsbc.ttot, 17)
++        self.assertEqual(cfsbc.tsub, 7)
++        self.assertEqual(cfsca.ttot, 13)
++        self.assertEqual(cfsca.tsub, 8)
++
++    def test_abcbca(self):
++        _timings = {"a_1": 10, "b_1": 9, "c_1": 7, "b_2": 4, "c_2": 2, "a_2": 1}
++        _yappi._set_test_timings(_timings)
++        self._ncall = 1
++
++        def a():
++            if self._ncall == 1:
++                b()
++            else:
++                return
++
++        def b():
++            c()
++
++        def c():
++            if self._ncall == 1:
++                self._ncall += 1
++                b()
++            else:
++                a()
++
++        stats = utils.run_and_get_func_stats(a)
++        fsa = utils.find_stat_by_name(stats, 'a')
++        fsb = utils.find_stat_by_name(stats, 'b')
++        fsc = utils.find_stat_by_name(stats, 'c')
++        cfsab = fsa.children[fsb]
++        cfsbc = fsb.children[fsc]
++        cfsca = fsc.children[fsa]
++        self.assertEqual(fsa.ttot, 10)
++        self.assertEqual(fsa.tsub, 2)
++        self.assertEqual(fsb.ttot, 9)
++        self.assertEqual(fsb.tsub, 4)
++        self.assertEqual(fsc.ttot, 7)
++        self.assertEqual(fsc.tsub, 4)
++        self.assertEqual(cfsab.ttot, 9)
++        self.assertEqual(cfsab.tsub, 2)
++        self.assertEqual(cfsbc.ttot, 7)
++        self.assertEqual(cfsbc.tsub, 4)
++        self.assertEqual(cfsca.ttot, 1)
++        self.assertEqual(cfsca.tsub, 1)
++        self.assertEqual(cfsca.ncall, 1)
++        self.assertEqual(cfsca.nactualcall, 0)
++
++    def test_aabccb(self):
++        _timings = {
++            "a_1": 13,
++            "a_2": 11,
++            "b_1": 9,
++            "c_1": 5,
++            "c_2": 3,
++            "b_2": 1
++        }
++        _yappi._set_test_timings(_timings)
++        self._ncall = 1
++
++        def a():
++            if self._ncall == 1:
++                self._ncall += 1
++                a()
++            else:
++                b()
++
++        def b():
++            if self._ncall == 3:
++                return
++            else:
++                c()
++
++        def c():
++            if self._ncall == 2:
++                self._ncall += 1
++                c()
++            else:
++                b()
++
++        stats = utils.run_and_get_func_stats(a)
++        fsa = utils.find_stat_by_name(stats, 'a')
++        fsb = utils.find_stat_by_name(stats, 'b')
++        fsc = utils.find_stat_by_name(stats, 'c')
++        cfsaa = fsa.children[fsa.index]
++        cfsab = fsa.children[fsb]
++        cfsbc = fsb.children[fsc.full_name]
++        cfscc = fsc.children[fsc]
++        cfscb = fsc.children[fsb]
++        self.assertEqual(fsb.ttot, 9)
++        self.assertEqual(fsb.tsub, 5)
++        self.assertEqual(cfsbc.ttot, 5)
++        self.assertEqual(cfsbc.tsub, 2)
++        self.assertEqual(fsa.ttot, 13)
++        self.assertEqual(fsa.tsub, 4)
++        self.assertEqual(cfsab.ttot, 9)
++        self.assertEqual(cfsab.tsub, 4)
++        self.assertEqual(cfsaa.ttot, 11)
++        self.assertEqual(cfsaa.tsub, 2)
++        self.assertEqual(fsc.ttot, 5)
++        self.assertEqual(fsc.tsub, 4)
++
++    def test_abaa(self):
++        _timings = {"a_1": 13, "b_1": 10, "a_2": 9, "a_3": 5}
++        _yappi._set_test_timings(_timings)
++
++        self._ncall = 1
++
++        def a():
++            if self._ncall == 1:
++                b()
++            elif self._ncall == 2:
++                self._ncall += 1
++                a()
++            else:
++                return
++
++        def b():
++            self._ncall += 1
++            a()
++
++        stats = utils.run_and_get_func_stats(a)
++        fsa = utils.find_stat_by_name(stats, 'a')
++        fsb = utils.find_stat_by_name(stats, 'b')
++        cfsaa = fsa.children[fsa]
++        cfsba = fsb.children[fsa]
++        self.assertEqual(fsb.ttot, 10)
++        self.assertEqual(fsb.tsub, 1)
++        self.assertEqual(fsa.ttot, 13)
++        self.assertEqual(fsa.tsub, 12)
++        self.assertEqual(cfsaa.ttot, 5)
++        self.assertEqual(cfsaa.tsub, 5)
++        self.assertEqual(cfsba.ttot, 9)
++        self.assertEqual(cfsba.tsub, 4)
++
++    def test_aabb(self):
++        _timings = {"a_1": 13, "a_2": 10, "b_1": 9, "b_2": 5}
++        _yappi._set_test_timings(_timings)
++
++        self._ncall = 1
++
++        def a():
++            if self._ncall == 1:
++                self._ncall += 1
++                a()
++            elif self._ncall == 2:
++                b()
++            else:
++                return
++
++        def b():
++            if self._ncall == 2:
++                self._ncall += 1
++                b()
++            else:
++                return
++
++        stats = utils.run_and_get_func_stats(a)
++        fsa = utils.find_stat_by_name(stats, 'a')
++        fsb = utils.find_stat_by_name(stats, 'b')
++        cfsaa = fsa.children[fsa]
++        cfsab = fsa.children[fsb]
++        cfsbb = fsb.children[fsb]
++        self.assertEqual(fsa.ttot, 13)
++        self.assertEqual(fsa.tsub, 4)
++        self.assertEqual(fsb.ttot, 9)
++        self.assertEqual(fsb.tsub, 9)
++        self.assertEqual(cfsaa.ttot, 10)
++        self.assertEqual(cfsaa.tsub, 1)
++        self.assertEqual(cfsab.ttot, 9)
++        self.assertEqual(cfsab.tsub, 4)
++        self.assertEqual(cfsbb.ttot, 5)
++        self.assertEqual(cfsbb.tsub, 5)
++
++    def test_abbb(self):
++        _timings = {"a_1": 13, "b_1": 10, "b_2": 6, "b_3": 1}
++        _yappi._set_test_timings(_timings)
++
++        self._ncall = 1
++
++        def a():
++            if self._ncall == 1:
++                b()
++
++        def b():
++            if self._ncall == 3:
++                return
++            self._ncall += 1
++            b()
++
++        stats = utils.run_and_get_func_stats(a)
++        fsa = utils.find_stat_by_name(stats, 'a')
++        fsb = utils.find_stat_by_name(stats, 'b')
++        cfsab = fsa.children[fsb]
++        cfsbb = fsb.children[fsb]
++        self.assertEqual(fsa.ttot, 13)
++        self.assertEqual(fsa.tsub, 3)
++        self.assertEqual(fsb.ttot, 10)
++        self.assertEqual(fsb.tsub, 10)
++        self.assertEqual(fsb.ncall, 3)
++        self.assertEqual(fsb.nactualcall, 1)
++        self.assertEqual(cfsab.ttot, 10)
++        self.assertEqual(cfsab.tsub, 4)
++        self.assertEqual(cfsbb.ttot, 6)
++        self.assertEqual(cfsbb.tsub, 6)
++        self.assertEqual(cfsbb.nactualcall, 0)
++        self.assertEqual(cfsbb.ncall, 2)
++
++    def test_aaab(self):
++        _timings = {"a_1": 13, "a_2": 10, "a_3": 6, "b_1": 1}
++        _yappi._set_test_timings(_timings)
++
++        self._ncall = 1
++
++        def a():
++            if self._ncall == 3:
++                b()
++                return
++            self._ncall += 1
++            a()
++
++        def b():
++            return
++
++        stats = utils.run_and_get_func_stats(a)
++        fsa = utils.find_stat_by_name(stats, 'a')
++        fsb = utils.find_stat_by_name(stats, 'b')
++        cfsaa = fsa.children[fsa]
++        cfsab = fsa.children[fsb]
++        self.assertEqual(fsa.ttot, 13)
++        self.assertEqual(fsa.tsub, 12)
++        self.assertEqual(fsb.ttot, 1)
++        self.assertEqual(fsb.tsub, 1)
++        self.assertEqual(cfsaa.ttot, 10)
++        self.assertEqual(cfsaa.tsub, 9)
++        self.assertEqual(cfsab.ttot, 1)
++        self.assertEqual(cfsab.tsub, 1)
++
++    def test_abab(self):
++        _timings = {"a_1": 13, "b_1": 10, "a_2": 6, "b_2": 1}
++        _yappi._set_test_timings(_timings)
++
++        self._ncall = 1
++
++        def a():
++            b()
++
++        def b():
++            if self._ncall == 2:
++                return
++            self._ncall += 1
++            a()
++
++        stats = utils.run_and_get_func_stats(a)
++        fsa = utils.find_stat_by_name(stats, 'a')
++        fsb = utils.find_stat_by_name(stats, 'b')
++        cfsab = fsa.children[fsb]
++        cfsba = fsb.children[fsa]
++        self.assertEqual(fsa.ttot, 13)
++        self.assertEqual(fsa.tsub, 8)
++        self.assertEqual(fsb.ttot, 10)
++        self.assertEqual(fsb.tsub, 5)
++        self.assertEqual(cfsab.ttot, 10)
++        self.assertEqual(cfsab.tsub, 5)
++        self.assertEqual(cfsab.ncall, 2)
++        self.assertEqual(cfsab.nactualcall, 1)
++        self.assertEqual(cfsba.ttot, 6)
++        self.assertEqual(cfsba.tsub, 5)
++
++
++if __name__ == '__main__':
++    #     import sys;sys.argv = ['', 'BasicUsage.test_run_as_script']
++    #     import sys;sys.argv = ['', 'MultithreadedScenarios.test_subsequent_profile']
++    unittest.main()
+-- 
+2.34.1
+