[
  {
    "path": ".github/workflows/sys-update.yml",
    "content": "name: Update the tracy-client-sys crate\n\non:\n  workflow_dispatch:\n  schedule:\n    - cron: '37 0/6 * * *'\njobs:\n  update:\n    runs-on: ubuntu-latest\n    timeout-minutes: 10\n    steps:\n      - uses: actions/checkout@85e6279cec87321a52edac9c87bce653a07cf6c2\n      - run: rustup install stable --profile=minimal\n      - run: rustup default stable\n      - run: cargo install bindgen-cli\n      - run: sudo apt install -y jq curl\n      - run: bash make_sys.sh\n        id: make_sys\n      - run: git diff\n      - if: ${{ steps.make_sys.outputs.tracy-changed }}\n        uses: actions/create-github-app-token@dff4b11d10ecc84d937fdd0653d8343a88c5b9c4\n        id: generate-token\n        with:\n          app-id: ${{ secrets.APP_ID }}\n          private-key: ${{ secrets.APP_PRIVATE_KEY }}\n      - if: ${{ steps.make_sys.outputs.tracy-changed }}\n        name: Create Pull Request\n        uses: peter-evans/create-pull-request@88ed63ce144f5372efe9f999d8bb224f582d98d9\n        with:\n          token: ${{ steps.generate-token.outputs.token }}\n          title: \"Update tracy client bindings to ${{ steps.make_sys.outputs.tracy-tag }}\"\n          body: ''\n          delete-branch: true\n          branch: sys-update/${{ steps.make_sys.outputs.tracy-tag }}\n          base: main\n"
  },
  {
    "path": ".github/workflows/test.yml",
    "content": "concurrency:\n  group: ${{ github.workflow }}-${{ github.ref }}\n  cancel-in-progress: true\n\non:\n  push:\n    branches: [main]\n  pull_request:\n    types: [opened, repoened, synchronize]\n\njobs:\n  native-test-libraries:\n    runs-on: ${{ matrix.os }}\n    strategy:\n      fail-fast: false\n      matrix:\n        rust_toolchain: [nightly, stable, 1.82.0]\n        os: [ubuntu-latest, windows-latest, macOS-latest]\n    timeout-minutes: 20\n    steps:\n      - uses: actions/checkout@v3\n      - run: rustup install ${{ matrix.rust_toolchain }} --profile=minimal\n      - run: rustup default ${{ matrix.rust_toolchain }}\n      # FIXME: perhaps make this into a scrupt?\n      - run: cargo check -p tracy-client-sys\n      - run: cargo check -p tracy-client\n      - run: cargo check -p tracing-tracy\n      - run: cargo check -p tracy-client-examples\n      - run: cargo check -p tracy-client-sys --no-default-features\n      - run: cargo check -p tracy-client --no-default-features\n      - run: cargo check -p tracing-tracy --no-default-features\n      - run: cargo check -p tracy-client-sys --features=manual-lifetime\n      - run: cargo check -p tracy-client --features=manual-lifetime\n      - run: cargo check -p tracing-tracy --features=manual-lifetime\n      - run: cargo check -p tracy-client-sys --features=enable,fibers,system-tracing,context-switch-tracing,sampling,code-transfer,broadcast,only-localhost,only-ipv4,timer-fallback,ondemand,manual-lifetime,delayed-init,callstack-inlines\n      - run: cargo check -p tracy-client --features=enable,fibers,system-tracing,context-switch-tracing,sampling,code-transfer,broadcast,only-localhost,only-ipv4,timer-fallback,ondemand,manual-lifetime,delayed-init,callstack-inlines\n      - run: cargo check -p tracing-tracy --features=enable,fibers,system-tracing,context-switch-tracing,sampling,code-transfer,broadcast,only-localhost,only-ipv4,timer-fallback,ondemand,manual-lifetime,delayed-init,callstack-inlines\n      - run: cargo test ${{ matrix.flags }} -- --nocapture\n        env:\n          TRACY_NO_INVARIANT_CHECK: 1\n      - run: cargo test ${{ matrix.flags }} --release -- --nocapture\n        env:\n          TRACY_NO_INVARIANT_CHECK: 1\n      - run: cargo test ${{ matrix.flags }} --features=manual-lifetime -- --nocapture\n        env:\n          TRACY_NO_INVARIANT_CHECK: 1\n\n  doc:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v3\n      - run: sudo apt-get update\n      - run: sudo apt-get -y install libdebuginfod-dev\n      - run: rustup install nightly --profile=minimal\n      - run: rustup default nightly\n      - run: cargo rustdoc --all-features -p tracy-client-sys -Zunstable-options --config 'build.rustdocflags=[\"--cfg\", \"tracy_client_sys_docs\", \"-D\", \"rustdoc::broken_intra_doc_links\"]'\n      - run: cargo rustdoc --all-features -p tracy-client -Zunstable-options --config 'build.rustdocflags=[\"--cfg\", \"tracy_client_docs\", \"-D\", \"rustdoc::broken_intra_doc_links\"]'\n      - run: cargo rustdoc --all-features -p tracing-tracy -Zunstable-options --config 'build.rustdocflags=[\"--cfg\", \"tracing_tracy_docs\", \"-D\", \"rustdoc::broken_intra_doc_links\"]'\n"
  },
  {
    "path": ".gitignore",
    "content": "target\nCargo.lock\n"
  },
  {
    "path": "Cargo.toml",
    "content": "[workspace]\nmembers = [\n    \"tracy-client-sys\",\n    \"tracy-client\",\n    \"tracing-tracy\",\n    \"examples\",\n]\nresolver = \"2\"\n\n[workspace.package]\nedition = \"2021\"\nrepository = \"https://github.com/nagisa/rust_tracy_client\"\nhomepage = \"https://github.com/nagisa/rust_tracy_client\"\nlicense = \"MIT/Apache-2.0\"\nrust-version = \"1.70.0\"\n"
  },
  {
    "path": "FEATURES.mkd",
    "content": "* `enable` – enables the Tracy client. Corresponds to the `TRACY_ENABLE` define.\n* `flush-on-exit` – waits for Tracy to connect and read out the profiling data before the program\n  terminates. Corresponds to the `TRACY_NO_EXIT` define. Does not work in combination with the\n  `manual-lifetime` feature.\n* `manual-lifetime` – allow for manual initialization and deinitialization of the profiler data\n  structures. Corresponds to the `TRACY_MANUAL_LIFETIME` define. `tracy_client::Client`\n  transparently switches to manual lifetime management when this feature is enabled. Implies\n  `delayed-init`.\n* `system-tracing` – enable capture of system level details. Corresponds to the\n  `TRACY_NO_SYSTEM_TRACING` define.\n* `context-switch-tracing` – enable capture of the context switch data. Corresponds to the\n  `TRACY_NO_CONTEXT_SWITCH` define.\n* `sampling` – enable periodic sampling of the call stack. Corresponds to the\n  `TRACY_NO_SAMPLING` define.\n* `code-transfer` – enable transfer of the machine code to the profiler. Corresponds to the\n  `TRACY_NO_CODE_TRANSFER` define.\n* `broadcast` – announce presence of the client to the profilers on the local network.\n  Corresponds to the `TRACY_NO_BROADCAST` define.\n* `only-localhost` – listen for profilers on the localhost interface only. Corresponds to the\n  `TRACY_ONLY_LOCALHOST` define.\n* `only-ipv4` – listen for profilers on IPv4 interfaces only. Corresponds to the\n  `TRACY_ONLY_IPV4` define.\n* `timer-fallback` – allow running on devices without a high resolution timer support.\n  Corresponds to the `TRACY_TIMER_FALLBACK` define.\n* `ondemand` – start collecting traces only when a server connects to the client. Corresponds\n  to the `TRACY_ON_DEMAND` define.\n* `fibers` – enable support for instrumenting fibers, coroutines and similar such asynchrony\n  primitives. Corresponds to the `TRACY_FIBERS` define.\n* `callstack-inlines` - enables resolution of inline frames for call stacks. Disabling it will make\n  the profiler use the basic but much faster frame resolution mode. Corresponds to the\n  `TRACY_NO_CALLSTACK_INLINES` define.\n* `delayed-init` – initializes trace structures upon a first request, rather than at load time.\n  Corresponds to the `TRACY_DELAYED_INIT` define.\n* `demangle` - requires that the demangling function be defined by the user.\n  See the `register_demangler!` macro for more details.\n  Corresponds to the `TRACY_DEMANGLE` define.\n* `verify` - enables verification that instrumentation is well formed. Enabling this introduces\n  additional instrumentation overhead (~50% for 0 callstack depth spans.) When disabled\n  corresponds to the `TRACY_NO_VERIFY` define.\n* `debuginfod` - enables debuginfo for system libraries on systems supporting debuginfod.\n  Corresponds to the `TRACY_DEBUGINFOD` define.\n* `crash-handler` – activate signal handler that intercepts application crashes. Corresponds to the\n  `TRACY_NO_CRASH_HANDLER` define.\n\nRefer to this package's `Cargo.toml` for the list of the features enabled by default. Refer to\nthe `Tracy` manual for more information on the implications of each feature.\n"
  },
  {
    "path": "LICENSE-APACHE",
    "content": "                              Apache License\n                        Version 2.0, January 2004\n                     http://www.apache.org/licenses/\n\nTERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n1. Definitions.\n\n   \"License\" shall mean the terms and conditions for use, reproduction,\n   and distribution as defined by Sections 1 through 9 of this document.\n\n   \"Licensor\" shall mean the copyright owner or entity authorized by\n   the copyright owner that is granting the License.\n\n   \"Legal Entity\" shall mean the union of the acting entity and all\n   other entities that control, are controlled by, or are under common\n   control with that entity. For the purposes of this definition,\n   \"control\" means (i) the power, direct or indirect, to cause the\n   direction or management of such entity, whether by contract or\n   otherwise, or (ii) ownership of fifty percent (50%) or more of the\n   outstanding shares, or (iii) beneficial ownership of such entity.\n\n   \"You\" (or \"Your\") shall mean an individual or Legal Entity\n   exercising permissions granted by this License.\n\n   \"Source\" form shall mean the preferred form for making modifications,\n   including but not limited to software source code, documentation\n   source, and configuration files.\n\n   \"Object\" form shall mean any form resulting from mechanical\n   transformation or translation of a Source form, including but\n   not limited to compiled object code, generated documentation,\n   and conversions to other media types.\n\n   \"Work\" shall mean the work of authorship, whether in Source or\n   Object form, made available under the License, as indicated by a\n   copyright notice that is included in or attached to the work\n   (an example is provided in the Appendix below).\n\n   \"Derivative Works\" shall mean any work, whether in Source or Object\n   form, that is based on (or derived from) the Work and for which the\n   editorial revisions, annotations, elaborations, or other modifications\n   represent, as a whole, an original work of authorship. For the purposes\n   of this License, Derivative Works shall not include works that remain\n   separable from, or merely link (or bind by name) to the interfaces of,\n   the Work and Derivative Works thereof.\n\n   \"Contribution\" shall mean any work of authorship, including\n   the original version of the Work and any modifications or additions\n   to that Work or Derivative Works thereof, that is intentionally\n   submitted to Licensor for inclusion in the Work by the copyright owner\n   or by an individual or Legal Entity authorized to submit on behalf of\n   the copyright owner. For the purposes of this definition, \"submitted\"\n   means any form of electronic, verbal, or written communication sent\n   to the Licensor or its representatives, including but not limited to\n   communication on electronic mailing lists, source code control systems,\n   and issue tracking systems that are managed by, or on behalf of, the\n   Licensor for the purpose of discussing and improving the Work, but\n   excluding communication that is conspicuously marked or otherwise\n   designated in writing by the copyright owner as \"Not a Contribution.\"\n\n   \"Contributor\" shall mean Licensor and any individual or Legal Entity\n   on behalf of whom a Contribution has been received by Licensor and\n   subsequently incorporated within the Work.\n\n2. Grant of Copyright License. Subject to the terms and conditions of\n   this License, each Contributor hereby grants to You a perpetual,\n   worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n   copyright license to reproduce, prepare Derivative Works of,\n   publicly display, publicly perform, sublicense, and distribute the\n   Work and such Derivative Works in Source or Object form.\n\n3. Grant of Patent License. Subject to the terms and conditions of\n   this License, each Contributor hereby grants to You a perpetual,\n   worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n   (except as stated in this section) patent license to make, have made,\n   use, offer to sell, sell, import, and otherwise transfer the Work,\n   where such license applies only to those patent claims licensable\n   by such Contributor that are necessarily infringed by their\n   Contribution(s) alone or by combination of their Contribution(s)\n   with the Work to which such Contribution(s) was submitted. If You\n   institute patent litigation against any entity (including a\n   cross-claim or counterclaim in a lawsuit) alleging that the Work\n   or a Contribution incorporated within the Work constitutes direct\n   or contributory patent infringement, then any patent licenses\n   granted to You under this License for that Work shall terminate\n   as of the date such litigation is filed.\n\n4. Redistribution. You may reproduce and distribute copies of the\n   Work or Derivative Works thereof in any medium, with or without\n   modifications, and in Source or Object form, provided that You\n   meet the following conditions:\n\n   (a) You must give any other recipients of the Work or\n       Derivative Works a copy of this License; and\n\n   (b) You must cause any modified files to carry prominent notices\n       stating that You changed the files; and\n\n   (c) You must retain, in the Source form of any Derivative Works\n       that You distribute, all copyright, patent, trademark, and\n       attribution notices from the Source form of the Work,\n       excluding those notices that do not pertain to any part of\n       the Derivative Works; and\n\n   (d) If the Work includes a \"NOTICE\" text file as part of its\n       distribution, then any Derivative Works that You distribute must\n       include a readable copy of the attribution notices contained\n       within such NOTICE file, excluding those notices that do not\n       pertain to any part of the Derivative Works, in at least one\n       of the following places: within a NOTICE text file distributed\n       as part of the Derivative Works; within the Source form or\n       documentation, if provided along with the Derivative Works; or,\n       within a display generated by the Derivative Works, if and\n       wherever such third-party notices normally appear. The contents\n       of the NOTICE file are for informational purposes only and\n       do not modify the License. You may add Your own attribution\n       notices within Derivative Works that You distribute, alongside\n       or as an addendum to the NOTICE text from the Work, provided\n       that such additional attribution notices cannot be construed\n       as modifying the License.\n\n   You may add Your own copyright statement to Your modifications and\n   may provide additional or different license terms and conditions\n   for use, reproduction, or distribution of Your modifications, or\n   for any such Derivative Works as a whole, provided Your use,\n   reproduction, and distribution of the Work otherwise complies with\n   the conditions stated in this License.\n\n5. Submission of Contributions. Unless You explicitly state otherwise,\n   any Contribution intentionally submitted for inclusion in the Work\n   by You to the Licensor shall be under the terms and conditions of\n   this License, without any additional terms or conditions.\n   Notwithstanding the above, nothing herein shall supersede or modify\n   the terms of any separate license agreement you may have executed\n   with Licensor regarding such Contributions.\n\n6. Trademarks. This License does not grant permission to use the trade\n   names, trademarks, service marks, or product names of the Licensor,\n   except as required for reasonable and customary use in describing the\n   origin of the Work and reproducing the content of the NOTICE file.\n\n7. Disclaimer of Warranty. Unless required by applicable law or\n   agreed to in writing, Licensor provides the Work (and each\n   Contributor provides its Contributions) on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n   implied, including, without limitation, any warranties or conditions\n   of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n   PARTICULAR PURPOSE. You are solely responsible for determining the\n   appropriateness of using or redistributing the Work and assume any\n   risks associated with Your exercise of permissions under this License.\n\n8. Limitation of Liability. In no event and under no legal theory,\n   whether in tort (including negligence), contract, or otherwise,\n   unless required by applicable law (such as deliberate and grossly\n   negligent acts) or agreed to in writing, shall any Contributor be\n   liable to You for damages, including any direct, indirect, special,\n   incidental, or consequential damages of any character arising as a\n   result of this License or out of the use or inability to use the\n   Work (including but not limited to damages for loss of goodwill,\n   work stoppage, computer failure or malfunction, or any and all\n   other commercial damages or losses), even if such Contributor\n   has been advised of the possibility of such damages.\n\n9. Accepting Warranty or Additional Liability. While redistributing\n   the Work or Derivative Works thereof, You may choose to offer,\n   and charge a fee for, acceptance of support, warranty, indemnity,\n   or other liability obligations and/or rights consistent with this\n   License. However, in accepting such obligations, You may act only\n   on Your own behalf and on Your sole responsibility, not on behalf\n   of any other Contributor, and only if You agree to indemnify,\n   defend, and hold each Contributor harmless for any liability\n   incurred by, or claims asserted against, such Contributor by reason\n   of your accepting any such warranty or additional liability.\n\nEND OF TERMS AND CONDITIONS\n"
  },
  {
    "path": "LICENSE-MIT",
    "content": "Permission is hereby granted, free of charge, to any\nperson obtaining a copy of this software and associated\ndocumentation files (the \"Software\"), to deal in the\nSoftware without restriction, including without\nlimitation the rights to use, copy, modify, merge,\npublish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software\nis furnished to do so, subject to the following\nconditions:\n\nThe above copyright notice and this permission notice\nshall be included in all copies or substantial portions\nof the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF\nANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED\nTO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A\nPARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT\nSHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\nOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR\nIN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\nDEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "README.mkd",
    "content": "# Tracy profiler clients in Rust\n\nThis project contains Rust crates for producing [Tracy profiler](https://github.com/wolfpld/tracy)\ntraces. Tracy features nanosecond precision, ability to profile remotely and a full-featured\ngraphical interface for finding hot spots in profiled programs.\n\nWhile Tracy's support for Rust is not first-class, it is still a very potent tool. If you have an\napplication instrumented with the `tracing` crate, Tracy can be used with your program in minutes\nvia the `tracing-tracy` crate. It can work well as both a profiling and, to a lesser extent,\nan observability tool.\n\n## Important note\n\nDepending on the configuration Tracy may broadcast discovery packets to the local network and\nexpose the data it collects in the background to that same network. Traces collected by Tracy\nmay include source and assembly code as well.\n\nAs thus, you may want make sure to only enable the `tracing-tracy`, `tracy-client` and\n`tracy-client-sys` crates conditionally, via the `enable` feature flag provided by the crates.\n\n## Version support table\n\nThis project, unlike Tracy itself, follows semantic versioning. We will publish a breaking version\nbump for `tracy-client-sys` whenever there is a potentially breaking protocol change, even if the\n`Tracy` project itself does not. An older version of `Tracy` being unable to communicate with the\nclient of a more recent version is an example of such a breaking change.\n\n`tracy-client`, `tracing-tracy` and other crates also follow semantic versioning, but do not\nconsider protocol breaks a breaking change for their purposes. For that reason each future version\nof `tracy-client` may be able to support depending on a large number of incompatible\n`tracy-client-sys` versions. Users are expected to select the version of `Tracy` profiler they\ntarget and use precise version bounds in `Cargo.toml` or `Cargo.lock` to specify the version of\n`tracy-client-sys` that they want to use.\n\nThe following table lists the version correspondence between the libraries.\n\n| Tracy | tracy-client-sys | tracy-client | tracing-tracy |\n| ----- | ---------------- | ------------ | ------------- |\n| 0.7.1 | 0.9.0            | 0.8.0        | 0.2.0         |\n| 0.7.3 | 0.10.0           | 0.9.0        | 0.3.0         |\n| 0.7.4 | 0.11.0           | 0.10.0       | 0.4.0         |\n| 0.7.5 | 0.12.0           | 0.11.0       | 0.5.0         |\n| 0.7.6 | 0.13.0, 0.14.0   | 0.12.*       | 0.6.*         |\n| v0.7.7 | 0.15.0          | 0.12.*       | 0.6.*         |\n| v0.7.8 | 0.16.0          | 0.12.*       | 0.6.*         |\n| v0.7.8 | 0.16.0          | 0.12.*       | 0.7.*         |\n| v0.7.8 | 0.16.0          | 0.12.*       | 0.8.*         |\n| v0.8.1 | 0.17.*          | 0.13.*       | 0.9.*         |\n| v0.8.1 | 0.17.*          | 0.14.*       | 0.10.*        |\n| v0.8.2 | 0.18.0          | 0.14.*       | 0.10.*        |\n| v0.9   | 0.19.0          | 0.14.2       | 0.10.0        |\n| v0.9   | 0.19.0          | 0.15.0       | 0.10.1        |\n| v0.9.1 | 0.21.0          | 0.15.2       | 0.10.2        |\n| v0.9.1 | 0.21.0          | 0.16.0       | 0.10.3        |\n| v0.10  | 0.22.0          | 0.16.4       | 0.10.4        |\n| v0.10  | 0.22.0          | 0.17.0       | 0.11.0        |\n| v0.11.0 | 0.23.0         | 0.17.1       | 0.11.1        |\n| v0.11.1 | 0.24.0          | 0.17.3       | 0.11.2        |\n| v0.11.1 | 0.24.3          | 0.18.0       | 0.11.4        |\n| v0.12.0 | 0.25.0          | 0.18.1       | 0.11.4        |\n| v0.12.2 | 0.26.0          | 0.18.2       | 0.11.4        |\n| v0.13.0 | 0.27.0          | 0.18.3       | 0.11.4        |\n| v0.13.1 | 0.28.0          | 0.18.4       | 0.11.4        |\n<!-- AUTO-UPDATE -->\n"
  },
  {
    "path": "examples/Cargo.toml",
    "content": "[package]\r\nname = \"tracy-client-examples\"\r\npublish = false\r\nversion = \"0.17.4\" # AUTO-BUMP\r\nauthors = [\"Nathan Adams <dinnerbone@dinnerbone.com>\"]\r\nlicense.workspace = true\r\nedition.workspace = true\r\nrust-version.workspace = true\r\nreadme = \"README.mkd\"\r\nrepository.workspace = true\r\nhomepage.workspace = true\r\ndescription = \"\"\"\r\nExamples for using `tracy-client` in a wgpu application\r\n\"\"\"\r\n\r\n[dependencies]\r\ntracy-client = { path = \"../tracy-client\" }\r\nwgpu = \"23.0.1\"\r\nfutures = \"0.3.31\"\r\nrand = \"0.8.4\"\r\n"
  },
  {
    "path": "examples/README.mkd",
    "content": "# Examples for Tracy integration\n\nThese examples exist to demonstrate how to integrate the rust-Tracy API within an application.\nThey do not serve as examples of a real world application, but rather how an application would use a given API.\n\nTo use them, run `cargo run -p tracy-client-examples -- example_name` from within the repository root.\nIf you don't provide an `example_name`, it will list the available examples.\n\nBe sure to have Tracy running and awaiting a connection, before running any example!\n"
  },
  {
    "path": "examples/src/main.rs",
    "content": "mod plots;\nmod secondary_frames;\nmod threads;\nmod wgpu_frame_images;\nmod zones;\n\nstruct ExampleDesc {\n    name: &'static str,\n    description: &'static str,\n    function: fn(),\n}\n\nconst EXAMPLES: &[ExampleDesc] = &[\n    ExampleDesc {\n        name: \"wgpu_frame_images\",\n        description: \"Demonstrates capturing frame images with wgpu\",\n        function: wgpu_frame_images::main,\n    },\n    ExampleDesc {\n        name: \"secondary_frames\",\n        description: \"Demonstrates secondary frames, both continuous and discontinuous\",\n        function: secondary_frames::main,\n    },\n    ExampleDesc {\n        name: \"zones\",\n        description: \"Demonstrates the use of zones to measure work\",\n        function: zones::main,\n    },\n    ExampleDesc {\n        name: \"threads\",\n        description: \"Demonstrates the use of zones across threads\",\n        function: threads::main,\n    },\n    ExampleDesc {\n        name: \"plots\",\n        description: \"Demonstrates plotting values\",\n        function: plots::main,\n    },\n];\n\nfn main() {\n    let example_name = std::env::args().nth(1);\n    if let Some(example) = EXAMPLES\n        .iter()\n        .find(|e| Some(e.name) == example_name.as_deref())\n    {\n        (example.function)();\n    } else {\n        if let Some(name) = example_name {\n            eprintln!(\"Example {name} not found!\");\n        }\n        println!(\"Available examples:\");\n        for example in EXAMPLES {\n            println!(\"{}: {}\", example.name, example.description);\n        }\n    }\n}\n"
  },
  {
    "path": "examples/src/plots/mod.rs",
    "content": "use rand::Rng;\nuse std::thread::sleep;\nuse std::time::Duration;\nuse tracy_client::{Client, PlotConfiguration, PlotFormat, PlotLineStyle, PlotName};\n\n// Plots you know statically can be defined freely like so\nconst PLOT_PLAYER_COUNT: PlotName = tracy_client::plot_name!(\"Player Count\");\nconst PLOT_DISK_SPACE: PlotName = tracy_client::plot_name!(\"Disk Space\");\n\npub fn main() {\n    let client = Client::start();\n    let mut rng = rand::thread_rng();\n\n    // Anything at runtime needs to be created via PlotName\n    let bandwidth = PlotName::new_leak(\"Bandwidth\".to_string());\n\n    // You can configure how plots display, this only needs to be done once\n    client.plot_config(\n        PLOT_DISK_SPACE,\n        PlotConfiguration::default()\n            .format(PlotFormat::Memory)\n            .fill(false),\n    );\n    client.plot_config(\n        bandwidth,\n        PlotConfiguration::default()\n            .format(PlotFormat::Percentage)\n            .color(Some(0xFF0000))\n            .line_style(PlotLineStyle::Stepped),\n    );\n\n    for _ in 0..50 {\n        // You don't need to constantly send a value!\n        if rng.gen_bool(0.75) {\n            client.plot(PLOT_PLAYER_COUNT, rng.gen_range(0..10) as f64);\n        }\n\n        client.plot(PLOT_DISK_SPACE, rng.gen_range(0..1000000) as f64);\n        client.plot(bandwidth, rng.gen_range(0..100) as f64);\n\n        sleep(Duration::from_millis(20));\n    }\n}\n"
  },
  {
    "path": "examples/src/secondary_frames/mod.rs",
    "content": "use rand::rngs::ThreadRng;\nuse rand::Rng;\nuse std::thread::sleep;\nuse std::time::Duration;\nuse tracy_client::{non_continuous_frame, secondary_frame_mark};\n\npub fn main() {\n    tracy_client::Client::start();\n    let mut rng = rand::thread_rng();\n\n    for _ in 0..100 {\n        simulate_physics(&mut rng);\n        if rng.gen_bool(0.75) {\n            simulate_rendering(&mut rng);\n        }\n\n        // This marks the boundary between two continuous frames\n        secondary_frame_mark!(\"Update Loop\");\n    }\n}\n\nfn simulate_physics(rng: &mut ThreadRng) {\n    // This is a discontinuous frame; it has a defined start and stop\n    // In this case, the start is now - and the end is when _frame is dropped\n    let _frame = non_continuous_frame!(\"Physics\");\n\n    // simulate doing some work\n    sleep(Duration::from_millis(rng.gen_range(10..20)));\n}\n\nfn simulate_rendering(rng: &mut ThreadRng) {\n    // This is a discontinuous frame; it has a defined start and stop\n    // In this case, the start is now - and the end is when _frame is dropped\n    let _frame = non_continuous_frame!(\"Rendering\");\n\n    // simulate doing some work\n    sleep(Duration::from_millis(rng.gen_range(10..30)));\n}\n"
  },
  {
    "path": "examples/src/threads/mod.rs",
    "content": "use rand::rngs::ThreadRng;\nuse rand::{thread_rng, Rng, RngCore};\nuse std::thread::{sleep, spawn};\nuse std::time::Duration;\nuse tracy_client::{set_thread_name, span, Client};\n\npub fn main() {\n    Client::start();\n\n    let mut handles = Vec::new();\n    handles.push(Box::new(spawn(|| {\n        // We can mark this thread with a custom name\n        set_thread_name!(\"Physics\");\n        let mut rng = thread_rng();\n        for _ in 0..50 {\n            simulate_physics(&mut rng);\n            // simulate doing some work\n            sleep(Duration::from_millis(rng.gen_range(5..20)));\n        }\n    })));\n    handles.push(Box::new(spawn(|| {\n        // We can mark this thread with a custom name\n        set_thread_name!(\"Rendering\");\n        let mut rng = thread_rng();\n        for _ in 0..50 {\n            simulate_rendering(&mut rng);\n        }\n        // simulate doing some work\n        sleep(Duration::from_millis(rng.gen_range(5..20)));\n    })));\n\n    for handle in handles {\n        handle.join().unwrap();\n    }\n}\n\nfn simulate_physics(rng: &mut ThreadRng) {\n    // This zone starts immediately, and ends when zone is dropped\n    let zone = span!(\"Physics\");\n    // Zones can have custom colours!\n    zone.emit_color(0xFF0000);\n\n    for name in [\"Cow\", \"Pig\", \"Player\", \"Robot\"] {\n        // Let's imagine these names are dynamic\n        // To mark zones for them, we need to use a different method which temporarily allocates a zone location\n        let zone = Client::running().unwrap().span_alloc(\n            Some(name),\n            \"perform_physics\",\n            \"physics.rs\",\n            123,\n            0,\n        );\n\n        zone.emit_value(rng.next_u64()); // entity ID? Who knows!\n\n        // simulate doing some work\n        sleep(Duration::from_millis(rng.gen_range(5..20)));\n\n        if rng.gen_bool(0.15) {\n            let zone = span!(\"Collision\");\n            // Zones can have arbitrary text!\n            zone.emit_text(\"Collided against a wall\");\n\n            // simulate doing some work\n            sleep(Duration::from_millis(rng.gen_range(5..20)));\n        }\n    }\n\n    // simulate doing some work\n    sleep(Duration::from_millis(rng.gen_range(1..20)));\n}\n\nfn simulate_rendering(rng: &mut ThreadRng) {\n    // This zone starts immediately, and ends when zone is dropped\n    let zone = span!(\"Rendering\");\n    // Zones can have custom colours!\n    zone.emit_color(0x00FF00);\n\n    for _ in 0..rng.gen_range(1..10) {\n        if rng.gen_bool(0.50) {\n            let zone = span!(\"Mesh\");\n            zone.emit_color(rng.gen_range(0x000000..0xFFFFFF));\n            // simulate doing some work\n            sleep(Duration::from_millis(rng.gen_range(1..15)));\n        } else {\n            // Sometimes let's not mark it, just to show that zones don't have to next to eachother\n\n            // simulate doing some work\n            sleep(Duration::from_millis(rng.gen_range(1..15)));\n        }\n    }\n}\n"
  },
  {
    "path": "examples/src/wgpu_frame_images/blit.wgsl",
    "content": "@group(0) @binding(0) var frame_sampler: sampler;\r\n@group(0) @binding(1) var frame_texture: texture_2d<f32>;\r\n\r\nstruct VertexOutput {\r\n    @builtin(position) position: vec4<f32>,\r\n    @location(0) tex_coord: vec2<f32>,\r\n}\r\n\r\n\r\n// This shader copies an entire texture by basically drawing a giant triangle that happens to contain it all\r\n@vertex fn vs_main(@builtin(vertex_index) vertex_index: u32) -> VertexOutput {\r\n    var result: VertexOutput;\r\n    let x = i32(vertex_index) / 2;\r\n    let y = i32(vertex_index) & 1;\r\n    let tc = vec2<f32>(\r\n        f32(x) * 2.0,\r\n        f32(y) * 2.0\r\n    );\r\n    result.position = vec4<f32>(\r\n        tc.x * 2.0 - 1.0,\r\n        1.0 - tc.y * 2.0,\r\n        0.0, 1.0\r\n    );\r\n    result.tex_coord = tc;\r\n    return result;\r\n}\r\n\r\n@fragment fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {\r\n    return textureSample(frame_texture, frame_sampler, in.tex_coord);\r\n}"
  },
  {
    "path": "examples/src/wgpu_frame_images/mod.rs",
    "content": "use futures::executor::block_on;\nuse std::borrow::Cow;\nuse std::sync::atomic::{AtomicBool, Ordering};\nuse std::sync::Arc;\nuse std::thread::sleep;\nuse std::time::{Duration, Instant};\nuse tracy_client::frame_image;\n\npub fn main() {\n    tracy_client::Client::start();\n    let instance = wgpu::Instance::new(Default::default());\n    let adapter = block_on(instance.request_adapter(&Default::default())).unwrap();\n    let (device, queue) = block_on(adapter.request_device(\n        &wgpu::DeviceDescriptor {\n            label: None,\n            required_features: Default::default(),\n            required_limits: Default::default(),\n            memory_hints: Default::default(),\n        },\n        None,\n    ))\n    .unwrap();\n\n    // We're just going to render to a decently large texture, pretending that that's a window.\n    // For this to work in a real application, you need to render to a texture which is then\n    // drawn back to the window surface\n    let mut game = Game::new(&device, 1280, 720);\n    for _ in 1..200 {\n        game.render(&device, &queue);\n        sleep(Duration::from_millis(20));\n    }\n}\n\nenum CaptureBufferStatus {\n    /// This buffer is free to use\n    Free,\n\n    /// This buffer has been reserved and commands to capture a texture have been encoded\n    Capturing { frame_num: u64 },\n\n    /// The capture commands have been submitted and we're waiting to map the buffer (when the GPU is ready)\n    Mapping {\n        frame_num: u64,\n        ready: Arc<AtomicBool>,\n    },\n}\n\nstruct CaptureBuffer {\n    texture: wgpu::Texture,\n    view: wgpu::TextureView,\n    buffer: wgpu::Buffer,\n    status: CaptureBufferStatus,\n}\n\nimpl CaptureBuffer {\n    /// Width of a capture texture\n    /// This MUST be a multiple of 4.\n    const WIDTH: u32 = 320;\n\n    /// Height of a capture texture\n    /// This MUST be a multiple of 4.\n    const HEIGHT: u32 = 180;\n\n    /// Amount of capture buffers to use\n    /// If there's more than this much in flight, no more will be captured and we may lose frames in Tracy.\n    /// If there's too many, we're wasting memory.\n    /// Tune it to your preferences and use case, or make it dynamic!\n    const AMOUNT: usize = 3;\n\n    fn new(device: &wgpu::Device) -> Self {\n        // This will stretch the captured image if the aspect ratio doesn't match\n        // In a real application you'll want to resize these buffers to preserve the aspect ratio\n        let texture = device.create_texture(&wgpu::TextureDescriptor {\n            label: None,\n            size: wgpu::Extent3d {\n                width: Self::WIDTH,\n                height: Self::HEIGHT,\n                depth_or_array_layers: 1,\n            },\n            mip_level_count: 1,\n            sample_count: 1,\n            dimension: wgpu::TextureDimension::D2,\n            format: wgpu::TextureFormat::Rgba8Unorm,\n            usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::COPY_SRC,\n            view_formats: &[],\n        });\n        let view = texture.create_view(&wgpu::TextureViewDescriptor::default());\n        // 4 bytes per pixel (Tracy wants RGBA)\n        let bytes_per_row = Self::WIDTH * 4;\n        let padded_bytes_per_row =\n            wgpu::util::align_to(bytes_per_row, wgpu::COPY_BYTES_PER_ROW_ALIGNMENT);\n        let buffer = device.create_buffer(&wgpu::BufferDescriptor {\n            label: None,\n            size: (padded_bytes_per_row * Self::HEIGHT * 4) as wgpu::BufferAddress,\n            usage: wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::MAP_READ,\n            mapped_at_creation: false,\n        });\n        Self {\n            texture,\n            view,\n            buffer,\n            status: CaptureBufferStatus::Free,\n        }\n    }\n\n    pub fn submit_to_tracy(&self, current_frame: u64, frame_num: u64) {\n        // If we're so far behind we couldn't even fit into a u8, just drop it.\n        let Some(offset) = current_frame\n            .checked_sub(frame_num)\n            .and_then(|o| u8::try_from(o).ok())\n        else {\n            return;\n        };\n\n        // Tracy needs a raw rgba image with no padding, so we have to remove it\n        let mut unpadded = Vec::with_capacity(Self::WIDTH as usize * Self::HEIGHT as usize * 4);\n        let padded_width =\n            wgpu::util::align_to(Self::WIDTH * 4, wgpu::COPY_BYTES_PER_ROW_ALIGNMENT);\n        let buffer = self.buffer.slice(..).get_mapped_range();\n        for row in 0..Self::HEIGHT {\n            let start = row as usize * padded_width as usize;\n            let end = start + (Self::WIDTH as usize * 4);\n            unpadded.extend_from_slice(&buffer[start..end]);\n        }\n\n        // Submit it!\n        frame_image(\n            &unpadded,\n            Self::WIDTH as u16,\n            Self::HEIGHT as u16,\n            offset,\n            false,\n        );\n    }\n}\n\n/// An amazing game that renders a spinning triangle. Technology!\nstruct Game {\n    renderer: TriangleRenderer,\n    frame_buffer_view: wgpu::TextureView,\n    blit_pipeline: wgpu::RenderPipeline,\n    blit_frame_buffer_bind_group: wgpu::BindGroup,\n    frame_count: u64,\n    frame_captures: [CaptureBuffer; CaptureBuffer::AMOUNT],\n}\n\nimpl Game {\n    fn new(device: &wgpu::Device, width: u32, height: u32) -> Game {\n        let renderer = TriangleRenderer::new(device);\n\n        // A trivial blit (copy) pipeline; used both to render the game, and to take screenshots for Tracy\n        let blit_shader_module = device.create_shader_module(wgpu::ShaderModuleDescriptor {\n            label: None,\n            source: wgpu::ShaderSource::Wgsl(Cow::Borrowed(include_str!(\"blit.wgsl\"))),\n        });\n        let blit_bind_group_layout =\n            device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {\n                label: None,\n                entries: &[\n                    wgpu::BindGroupLayoutEntry {\n                        binding: 0,\n                        visibility: wgpu::ShaderStages::FRAGMENT,\n                        ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),\n                        count: None,\n                    },\n                    wgpu::BindGroupLayoutEntry {\n                        binding: 1,\n                        visibility: wgpu::ShaderStages::FRAGMENT,\n                        ty: wgpu::BindingType::Texture {\n                            sample_type: wgpu::TextureSampleType::Float { filterable: true },\n                            view_dimension: wgpu::TextureViewDimension::D2,\n                            multisampled: false,\n                        },\n                        count: None,\n                    },\n                ],\n            });\n        let blit_pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {\n            label: None,\n            bind_group_layouts: &[&blit_bind_group_layout],\n            push_constant_ranges: &[],\n        });\n        let blit_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {\n            label: None,\n            layout: Some(&blit_pipeline_layout),\n            vertex: wgpu::VertexState {\n                module: &blit_shader_module,\n                entry_point: None,\n                compilation_options: Default::default(),\n                buffers: &[],\n            },\n            primitive: Default::default(),\n            depth_stencil: None,\n            multisample: Default::default(),\n            fragment: Some(wgpu::FragmentState {\n                module: &blit_shader_module,\n                entry_point: None,\n                compilation_options: Default::default(),\n                targets: &[Some(wgpu::TextureFormat::Rgba8Unorm.into())],\n            }),\n            multiview: None,\n            cache: None,\n        });\n\n        let blit_sampler = device.create_sampler(&wgpu::SamplerDescriptor {\n            label: None,\n            address_mode_u: wgpu::AddressMode::ClampToEdge,\n            address_mode_v: wgpu::AddressMode::ClampToEdge,\n            mag_filter: wgpu::FilterMode::Linear,\n            min_filter: wgpu::FilterMode::Linear,\n            ..Default::default()\n        });\n\n        // We'll render the game to an intermediary texture (frame_buffer),\n        // this allows us to take copies of the texture at will (aka screenshots)\n        let frame_buffer = device.create_texture(&wgpu::TextureDescriptor {\n            label: None,\n            size: wgpu::Extent3d {\n                width,\n                height,\n                depth_or_array_layers: 1,\n            },\n            mip_level_count: 1,\n            sample_count: 1,\n            dimension: wgpu::TextureDimension::D2,\n            format: wgpu::TextureFormat::Rgba8Unorm,\n            usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::TEXTURE_BINDING,\n            view_formats: &[],\n        });\n        let frame_buffer_view = frame_buffer.create_view(&Default::default());\n        let blit_frame_buffer_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {\n            label: None,\n            layout: &blit_bind_group_layout,\n            entries: &[\n                wgpu::BindGroupEntry {\n                    binding: 0,\n                    resource: wgpu::BindingResource::Sampler(&blit_sampler),\n                },\n                wgpu::BindGroupEntry {\n                    binding: 1,\n                    resource: wgpu::BindingResource::TextureView(&frame_buffer_view),\n                },\n            ],\n        });\n        let tracy_frame_buffers: [CaptureBuffer; CaptureBuffer::AMOUNT] =\n            core::array::from_fn(|_| CaptureBuffer::new(device));\n\n        Self {\n            renderer,\n            frame_buffer_view,\n            blit_pipeline,\n            blit_frame_buffer_bind_group,\n            frame_count: 0,\n            frame_captures: tracy_frame_buffers,\n        }\n    }\n\n    fn render(&mut self, device: &wgpu::Device, queue: &wgpu::Queue) {\n        let mut encoder = device.create_command_encoder(&Default::default());\n        self.renderer\n            .render(queue, &mut encoder, &self.frame_buffer_view);\n\n        // Here's where we'd blit it to the surface... if we had one...\n\n        // Before we submit everything, but _after the frame buffer is finished_, let's try to capture an image\n        if let Some(capture) = self\n            .frame_captures\n            .iter_mut()\n            .find(|c| matches!(c.status, CaptureBufferStatus::Free))\n        {\n            // We've got a free capture slot! First blit our frame buffer over to the texture\n            let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {\n                label: None,\n                color_attachments: &[Some(wgpu::RenderPassColorAttachment {\n                    view: &capture.view,\n                    resolve_target: None,\n                    ops: Default::default(),\n                })],\n                depth_stencil_attachment: None,\n                timestamp_writes: None,\n                occlusion_query_set: None,\n            });\n            render_pass.set_pipeline(&self.blit_pipeline);\n            render_pass.set_bind_group(0, &self.blit_frame_buffer_bind_group, &[]);\n            render_pass.draw(0..3, 0..1);\n            drop(render_pass);\n\n            // Then copy the texture to a buffer\n            encoder.copy_texture_to_buffer(\n                wgpu::ImageCopyTexture {\n                    texture: &capture.texture,\n                    mip_level: 0,\n                    origin: wgpu::Origin3d::ZERO,\n                    aspect: wgpu::TextureAspect::All,\n                },\n                wgpu::ImageCopyBuffer {\n                    buffer: &capture.buffer,\n                    layout: wgpu::ImageDataLayout {\n                        offset: 0,\n                        bytes_per_row: Some(wgpu::util::align_to(\n                            CaptureBuffer::WIDTH * 4,\n                            wgpu::COPY_BYTES_PER_ROW_ALIGNMENT,\n                        )),\n                        rows_per_image: Some(CaptureBuffer::HEIGHT),\n                    },\n                },\n                capture.texture.size(),\n            );\n\n            // And mark it ready for mapping (that has to happen AFTER this encoder is submitted)\n            capture.status = CaptureBufferStatus::Capturing {\n                frame_num: self.frame_count,\n            };\n        }\n\n        queue.submit(Some(encoder.finish()));\n\n        // Here's where we'd present the surface\n\n        // Tell tracy that's the end of a frame - it's usually expected that this is immediately after presenting to the surface\n        tracy_client::frame_mark();\n        // We're tracking \"number of frames we've told Tracy about\" - so increment it here vs anywhere else\n        self.frame_count += 1;\n\n        // Now that we've submitted everything, let's find out if any of our captures are ready\n        for capture in &mut self.frame_captures {\n            match &capture.status {\n                // Nothing to do\n                CaptureBufferStatus::Free => continue,\n\n                // We'll need to try and map this\n                CaptureBufferStatus::Capturing { frame_num } => {\n                    let ready = Arc::new(AtomicBool::new(false));\n                    capture.status = CaptureBufferStatus::Mapping {\n                        frame_num: *frame_num,\n                        ready: ready.clone(),\n                    };\n                    capture\n                        .buffer\n                        .slice(..)\n                        .map_async(wgpu::MapMode::Read, move |_| {\n                            ready.store(true, Ordering::Relaxed);\n                        });\n                }\n\n                // If this is ready, submit it to Tracy and then free it up for a new capture\n                CaptureBufferStatus::Mapping { frame_num, ready } => {\n                    if ready.load(Ordering::Relaxed) {\n                        capture.submit_to_tracy(self.frame_count, *frame_num);\n                        capture.buffer.unmap();\n                        capture.status = CaptureBufferStatus::Free;\n                    }\n                }\n            }\n        }\n    }\n}\n\nstruct TriangleRenderer {\n    pipeline: wgpu::RenderPipeline,\n    buffer: wgpu::Buffer,\n    bind_group: wgpu::BindGroup,\n    start: Instant,\n}\n\nimpl TriangleRenderer {\n    fn new(device: &wgpu::Device) -> Self {\n        let triangle_shader_module = device.create_shader_module(wgpu::ShaderModuleDescriptor {\n            label: None,\n            source: wgpu::ShaderSource::Wgsl(Cow::Borrowed(include_str!(\"triangle.wgsl\"))),\n        });\n        let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {\n            label: None,\n            entries: &[wgpu::BindGroupLayoutEntry {\n                binding: 0,\n                visibility: wgpu::ShaderStages::VERTEX,\n                ty: wgpu::BindingType::Buffer {\n                    ty: wgpu::BufferBindingType::Uniform,\n                    has_dynamic_offset: false,\n                    min_binding_size: None,\n                },\n                count: None,\n            }],\n        });\n        let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {\n            label: None,\n            bind_group_layouts: &[&bind_group_layout],\n            push_constant_ranges: &[],\n        });\n        let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {\n            label: None,\n            layout: Some(&pipeline_layout),\n            vertex: wgpu::VertexState {\n                module: &triangle_shader_module,\n                entry_point: None,\n                compilation_options: Default::default(),\n                buffers: &[],\n            },\n            primitive: Default::default(),\n            depth_stencil: None,\n            multisample: Default::default(),\n            fragment: Some(wgpu::FragmentState {\n                module: &triangle_shader_module,\n                entry_point: None,\n                compilation_options: Default::default(),\n                targets: &[Some(wgpu::TextureFormat::Rgba8Unorm.into())],\n            }),\n            multiview: None,\n            cache: None,\n        });\n        let buffer = device.create_buffer(&wgpu::BufferDescriptor {\n            label: None,\n            size: std::mem::size_of::<f32>() as wgpu::BufferAddress,\n            usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,\n            mapped_at_creation: false,\n        });\n        let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {\n            label: None,\n            layout: &bind_group_layout,\n            entries: &[wgpu::BindGroupEntry {\n                binding: 0,\n                resource: buffer.as_entire_binding(),\n            }],\n        });\n        Self {\n            pipeline,\n            buffer,\n            bind_group,\n            start: Instant::now(),\n        }\n    }\n\n    fn render(\n        &mut self,\n        queue: &wgpu::Queue,\n        encoder: &mut wgpu::CommandEncoder,\n        target: &wgpu::TextureView,\n    ) {\n        queue.write_buffer(\n            &self.buffer,\n            0,\n            &self.start.elapsed().as_secs_f32().to_ne_bytes(),\n        );\n        let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {\n            label: None,\n            color_attachments: &[Some(wgpu::RenderPassColorAttachment {\n                view: target,\n                resolve_target: None,\n                ops: wgpu::Operations {\n                    load: wgpu::LoadOp::Clear(wgpu::Color::BLACK),\n                    store: wgpu::StoreOp::Store,\n                },\n            })],\n            depth_stencil_attachment: None,\n            timestamp_writes: None,\n            occlusion_query_set: None,\n        });\n        render_pass.set_pipeline(&self.pipeline);\n        render_pass.set_bind_group(0, &self.bind_group, &[]);\n        render_pass.draw(0..3, 0..1);\n    }\n}\n"
  },
  {
    "path": "examples/src/wgpu_frame_images/triangle.wgsl",
    "content": "@group(0) @binding(0) var<uniform> time: f32;\r\n\r\nstruct VertexOutput {\r\n    @builtin(position) position: vec4<f32>,\r\n    @location(0) color: vec4<f32>,\r\n}\r\n\r\n@vertex fn vs_main(@builtin(vertex_index) vertex_index: u32) -> VertexOutput {\r\n    let x = f32(i32(vertex_index) - 1);\r\n    let y = f32(i32(vertex_index & 1u) * 2 - 1);\r\n\r\n    // A spinning triangle is better than a static triangle\r\n    let cos_theta = cos(time / 2);\r\n    let sin_theta = sin(time / 2);\r\n    let rotation_matrix = mat2x2<f32>(\r\n        cos_theta, -sin_theta,\r\n        sin_theta, cos_theta\r\n    );\r\n    var pos = vec2<f32>(x, y);\r\n    let scale = 0.75 + sin(time / 5) * 0.25;\r\n    pos = rotation_matrix * pos * scale;\r\n\r\n    // And slowly rotate through colors to make it visually interesting\r\n    let offset = f32(vertex_index) * 0.5;\r\n    let r = 0.5 + 0.5 * sin(time + offset);\r\n    let g = 0.5 + 0.5 * sin(time * 0.8 + offset + 4.0);\r\n    let b = 0.5 + 0.5 * sin(time * 1.2 + offset + 8.0);\r\n    let color = vec4<f32>(r, g, b, 1.0);\r\n\r\n    var result: VertexOutput;\r\n    result.position = vec4<f32>(rotation_matrix * pos * scale, 0.0, 1.0);\r\n    result.color = color;\r\n    return result;\r\n}\r\n\r\n@fragment fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {\r\n    return in.color;\r\n}"
  },
  {
    "path": "examples/src/zones/mod.rs",
    "content": "use rand::rngs::ThreadRng;\nuse rand::{Rng, RngCore};\nuse std::thread::sleep;\nuse std::time::Duration;\nuse tracy_client::{frame_mark, span, Client};\n\npub fn main() {\n    Client::start();\n    let mut rng = rand::thread_rng();\n\n    for _ in 0..50 {\n        simulate_physics(&mut rng);\n        simulate_rendering(&mut rng);\n\n        // simulate doing some work\n        sleep(Duration::from_millis(rng.gen_range(1..50)));\n\n        // This marks the boundary between two continuous frames\n        frame_mark();\n    }\n}\n\nfn simulate_physics(rng: &mut ThreadRng) {\n    // This zone starts immediately, and ends when zone is dropped\n    let zone = span!(\"Physics\");\n    // Zones can have custom colours!\n    zone.emit_color(0xFF0000);\n\n    for name in [\"Cow\", \"Pig\", \"Player\", \"Robot\"] {\n        // Let's imagine these names are dynamic\n        // To mark zones for them, we need to use a different method which temporarily allocates a zone location\n        let zone = Client::running().unwrap().span_alloc(\n            Some(name),\n            \"perform_physics\",\n            \"physics.rs\",\n            123,\n            0,\n        );\n\n        zone.emit_value(rng.next_u64()); // entity ID? Who knows!\n\n        // simulate doing some work\n        sleep(Duration::from_millis(rng.gen_range(5..20)));\n\n        if rng.gen_bool(0.15) {\n            let zone = span!(\"Collision\");\n            // Zones can have arbitrary text!\n            zone.emit_text(\"Collided against a wall\");\n\n            // simulate doing some work\n            sleep(Duration::from_millis(rng.gen_range(5..20)));\n        }\n    }\n\n    // simulate doing some work\n    sleep(Duration::from_millis(rng.gen_range(1..20)));\n}\n\nfn simulate_rendering(rng: &mut ThreadRng) {\n    // This zone starts immediately, and ends when zone is dropped\n    let zone = span!(\"Rendering\");\n    // Zones can have custom colours!\n    zone.emit_color(0x00FF00);\n\n    for _ in 0..rng.gen_range(1..10) {\n        if rng.gen_bool(0.50) {\n            let zone = span!(\"Mesh\");\n            zone.emit_color(rng.gen_range(0x000000..0xFFFFFF));\n            // simulate doing some work\n            sleep(Duration::from_millis(rng.gen_range(1..15)));\n        } else {\n            // Sometimes let's not mark it, just to show that zones don't have to next to eachother\n\n            // simulate doing some work\n            sleep(Duration::from_millis(rng.gen_range(1..15)));\n        }\n    }\n}\n"
  },
  {
    "path": "make_sys.sh",
    "content": "#!/usr/bin/env bash\n\n# NOTE: this script is only intended to be run on CI.\nset -xe\n\nexport PATH=\"$HOME/.cargo/bin/\":\"$PATH\"\n\nif [ $# -eq 0 ]; then\n  LAST_RELEASE=($(curl -s \"https://api.github.com/repos/wolfpld/tracy/releases/latest\" \\\n                    | jq -r '\"\\(.tag_name)\\n\\(.tarball_url)\"'))\nelse\n  LAST_RELEASE=($(curl -s \"https://api.github.com/repos/wolfpld/tracy/releases/tags/$1\" \\\n                    | jq -r '\"\\(.tag_name)\\n\\(.tarball_url)\"'))\nfi\n\nTAG=\"${LAST_RELEASE[0]}\"\nTARBALL=\"${LAST_RELEASE[1]}\"\nDESTINATION=/tmp/tracy-$TAG # could use mktemp, but unnecessary complexity.\n\necho \"tracy-tag=$TAG\" >> \"${GITHUB_OUTPUT:-/dev/stdout}\"\nmkdir -p \"$DESTINATION\"\ncurl -sL \"$TARBALL\" -o - | tar -f - -zxC \"$DESTINATION\"\nBASEDIR=(\"$DESTINATION\"/*)\n\nrm -rf \"tracy-client-sys/tracy/\"\ncp -r \"$BASEDIR/public\" \"tracy-client-sys/tracy\"\ncp \"$BASEDIR/LICENSE\" \"tracy-client-sys/tracy/\"\n\nCOMMON_BINDGEN_PARAMS=(\n    \"tracy-client-sys/tracy/tracy/TracyC.h\"\n    \"--disable-header-comment\"\n    \"--\"\n    \"-DTRACY_ENABLE\"\n)\n\nbindgen -o \"tracy-client-sys/src/generated.rs\" \\\n  --rust-target 1.70.0 \\\n  --allowlist-function='.*[Tt][Rr][Aa][Cc][Yy].*' \\\n  --allowlist-type='.*[Tt][Rr][Aa][Cc][Yy].*' \\\n  --blocklist-type='TracyCLockCtx' \\\n  ${COMMON_BINDGEN_PARAMS[@]}\n\nbindgen -o \"tracy-client-sys/src/generated_manual_lifetime.rs\" \\\n  --rust-target 1.70.0 \\\n  --allowlist-function='___tracy_startup_profiler' \\\n  --allowlist-function='___tracy_shutdown_profiler' \\\n  ${COMMON_BINDGEN_PARAMS[@]} \\\n  -DTRACY_MANUAL_LIFETIME\n\nbindgen -o \"tracy-client-sys/src/generated_fibers.rs\" \\\n  --rust-target 1.70.0 \\\n  --allowlist-function='___tracy_fiber_enter' \\\n  --allowlist-function='___tracy_fiber_leave' \\\n  ${COMMON_BINDGEN_PARAMS[@]} \\\n  -DTRACY_FIBERS\n\n# The space after type avoids hitting members called \"type\".\nsed -i 's/pub type /type /g' 'tracy-client-sys/src/generated.rs'\n\n# Avoid running the other steps if we haven't really updated tracy (e.g. if bindgen/rustfmt version\n# changed)\nif ! git diff --quiet \"tracy-client-sys/tracy\"; then\n    echo \"tracy-changed=true\" >> \"${GITHUB_OUTPUT:-/dev/stdout}\"\nelse\n    exit 0\nfi\n\nCURRENT_SYS_VERSION=$(sed -n 's/^version = \"\\(.*\\)\" # AUTO-BUMP$/\\1/p' tracy-client-sys/Cargo.toml)\nCURRENT_CLIENT_VERSION=$(sed -n 's/^version = \"\\(.*\\)\" # AUTO-BUMP$/\\1/p' tracy-client/Cargo.toml)\nCURRENT_TRACING_VERSION=$(sed -n 's/^version = \"\\(.*\\)\"$/\\1/p' tracing-tracy/Cargo.toml)\n\nSYS_MAJOR=$(echo \"$CURRENT_SYS_VERSION\" | sed -nr 's,([0-9]+)\\.[0-9]+\\.[0-9]+,\\1,p')\nSYS_MINOR=$(echo \"$CURRENT_SYS_VERSION\" | sed -nr 's,[0-9]+\\.([0-9]+)\\.[0-9]+,\\1,p')\nNEXT_SYS_MINOR=$(echo \"$SYS_MINOR\" | awk '{print $0+1}')\nNEXTNEXT_SYS_MINOR=$(echo \"$NEXT_SYS_MINOR\" | awk '{print $0+1}')\nSYS_PATCH=$(echo \"$CURRENT_SYS_VERSION\" | sed -nr 's,[0-9]+\\.[0-9]+\\.([0-9]+),\\1,p')\nCLIENT_MAJOR=$(echo \"$CURRENT_CLIENT_VERSION\" | sed -nr 's,([0-9]+)\\.[0-9]+\\.[0-9]+,\\1,p')\nCLIENT_MINOR=$(echo \"$CURRENT_CLIENT_VERSION\" | sed -nr 's,[0-9]+\\.([0-9]+)\\.[0-9]+,\\1,p')\nCLIENT_PATCH=$(echo \"$CURRENT_CLIENT_VERSION\" | sed -nr 's,[0-9]+\\.[0-9]+\\.([0-9]+),\\1,p')\nNEXT_CLIENT_PATCH=$(echo \"$CLIENT_PATCH\" | awk '{print $0+1}')\n\nNEXT_SYS_VERSION=\"$SYS_MAJOR.$NEXT_SYS_MINOR.0\"\nNEXTNEXT_SYS_VERSION=\"$SYS_MAJOR.$NEXTNEXT_SYS_MINOR.0\"\nNEXT_CLIENT_VERSION=\"$CLIENT_MAJOR.$CLIENT_MINOR.$NEXT_CLIENT_PATCH\"\n\n# Adjust the table in the README file…\nsed -i \"/^<!-- AUTO-UPDATE -->$/i $(printf \"| %-6s | %-15s | %-12s | %-13s |\" \"$TAG\" \"$NEXT_SYS_VERSION\" \"$NEXT_CLIENT_VERSION\" \"$CURRENT_TRACING_VERSION\")\" \\\n    README.mkd\n# …the version in tracy-client-sys…\nsed -i \"s/^\\(version =\\) \\\".*\\\" \\(# AUTO-BUMP\\)$/\\1 \\\"$NEXT_SYS_VERSION\\\" \\2/\" \\\n    tracy-client-sys/Cargo.toml\n# …and the versions in tracy-client.\nsed -i \"s/^\\(version =\\) \\\".*\\\" \\(# AUTO-BUMP\\)$/\\1 \\\"$NEXT_CLIENT_VERSION\\\" \\2/\" \\\n    tracy-client/Cargo.toml\nsed -i \"s/^\\(version = \\\".*,\\) <.*\\\" \\(# AUTO-UPDATE\\)$/\\1 <$NEXTNEXT_SYS_VERSION\\\" \\2/\" \\\n    tracy-client/Cargo.toml\n\n# Make a commit that we'll PR\nNAME=tracy-client-sys-auto-update[bot]\nMAIL=\"GitHub <noreply@github.com>\"\ngit add tracy-client-sys tracy-client/Cargo.toml README.mkd\ngit -c user.name=\"$NAME\" -c user.email=\"$MAIL\" commit -m \"Update Tracy client bindings to $TAG\"\n"
  },
  {
    "path": "tracing-tracy/Cargo.toml",
    "content": "[package]\nname = \"tracing-tracy\"\nversion = \"0.11.4\"\nauthors = [\"Simonas Kazlauskas <tracing-tracy@kazlauskas.me>\"]\nlicense.workspace = true\nedition.workspace = true\nrust-version.workspace = true\nreadme = \"README.mkd\"\nrepository.workspace = true\nhomepage.workspace = true\ndocumentation = \"https://docs.rs/tracing-tracy\"\ndescription = \"\"\"\nInspect tracing-enabled Rust applications with Tracy\n\"\"\"\n\n[lib]\nharness = false\nbench = true\n\n[dependencies]\ntracing-core = { version = \"0.1\", default-features = false, features = [\"std\"] }\ntracing-subscriber = { version = \"0.3\", default-features = false, features = [\"fmt\", \"registry\"] }\nclient = { package = \"tracy-client\", path = \"../tracy-client\", version = \">=0.17.0,<0.19.0\", default-features = false }\n\n[dev-dependencies]\ntracing = { version = \"0.1\", default-features = false, features = [\"std\"] }\ntokio = { version = \"1\", features = [\"full\"] }\ntracing-attributes =  { version = \"0.1\"}\ntracing-futures = { version = \"0.2\" }\nfutures = \"0.3\"\ncriterion = \"0.5\"\n\n[features]\n# Refer to FEATURES.mkd for documentation on features.\ndefault = [ \"enable\", \"system-tracing\", \"context-switch-tracing\", \"sampling\", \"code-transfer\",\n            \"broadcast\", \"callstack-inlines\", \"crash-handler\" ]\nbroadcast = [\"client/broadcast\"]\ncode-transfer = [\"client/code-transfer\"]\ncontext-switch-tracing = [\"client/context-switch-tracing\"]\nenable = [\"client/enable\"]\nfibers = [\"client/fibers\"]\ntimer-fallback = [\"client/timer-fallback\"]\nondemand = [\"client/ondemand\"]\nonly-ipv4 = [\"client/only-ipv4\"]\nonly-localhost = [\"client/only-localhost\"]\nsampling = [\"client/sampling\"]\nsystem-tracing = [\"client/system-tracing\"]\ncallstack-inlines = [\"client/callstack-inlines\"]\nmanual-lifetime = [\"client/manual-lifetime\"]\ndelayed-init = [\"client/delayed-init\"]\nflush-on-exit = [\"client/flush-on-exit\"]\ndemangle = [\"client/demangle\"]\nverify = [\"client/verify\"]\ndebuginfod = [\"client/debuginfod\"]\ncrash-handler = [\"client/crash-handler\"]\n\n[package.metadata.docs.rs]\nall-features = true\n"
  },
  {
    "path": "tracing-tracy/src/config.rs",
    "content": "use client::Client;\nuse tracing_subscriber::fmt::format::DefaultFields;\nuse tracing_subscriber::fmt::FormatFields;\n\n/// Configuration of the [`TracyLayer`](super::TracyLayer) behaviour.\n///\n/// For most users [`DefaultConfig`] is going to be a good default choice, however advanced users\n/// can implement this trait manually to override the formatter used or to otherwise modify the\n/// behaviour of the `TracyLayer`.\n///\n/// # Examples\n///\n/// ```\n/// use tracing_subscriber::fmt::format::DefaultFields;\n///\n/// struct TracyLayerConfig {\n///     fmt: DefaultFields,\n/// }\n/// impl tracing_tracy::Config for TracyLayerConfig {\n///     type Formatter = DefaultFields;\n///     fn formatter(&self) -> &Self::Formatter {\n///         &self.fmt\n///     }\n///     // The boilerplate ends here\n///\n///     /// Collect 32 frames in stack traces.\n///     fn stack_depth(&self, _: &tracing::Metadata) -> u16 {\n///         32\n///     }\n///\n///     /// Do not format fields into zone names.\n///     fn format_fields_in_zone_name(&self) -> bool {\n///         false\n///     }\n///\n///     // etc.\n/// }\n/// ```\n///\n/// With this configuration `TracyLayer` will collect some call stacks and the formatting of the\n/// zone names is different from the `DefaultConfig`.\npub trait Config {\n    type Formatter: for<'writer> FormatFields<'writer> + 'static;\n\n    /// Use a custom field formatting implementation.\n    fn formatter(&self) -> &Self::Formatter;\n\n    /// Specify the maximum number of stack frames that will be collected.\n    ///\n    /// Note that enabling callstack collection can and will introduce a non-trivial overhead at\n    /// every instrumentation point. Specifying 0 frames will disable stack trace collection.\n    ///\n    /// Default implementation returns `0`.\n    fn stack_depth(&self, metadata: &tracing_core::Metadata<'_>) -> u16 {\n        let _ = metadata;\n        0\n    }\n\n    /// Specify whether or not to include tracing span fields in the tracy zone name, or to emit\n    /// them as zone text.\n    ///\n    /// The former enables zone analysis along unique span field invocations, while the latter\n    /// aggregates every invocation of a given span into a single zone, irrespective of field\n    /// values.\n    ///\n    /// Default implementation returns `true`.\n    fn format_fields_in_zone_name(&self) -> bool {\n        true\n    }\n\n    /// Apply handling for errors detected by the [`TracyLayer`](super::TracyLayer).\n    ///\n    /// Fundamentally the way the tracing crate and the Tracy profiler work are somewhat\n    /// incompatible in certain ways. For instance, a `tracing::Span` can be created on one\n    /// thread and moved to another, where it is cleaned up. Tracy on the other hand expects that\n    /// its eqvivalent concept of zone remains entirely within a thread.\n    ///\n    /// Another example a limitation in `Tracy` where the message length or zone name cannot exceed\n    /// a certain (low) limit of bytes.\n    ///\n    /// Although `tracing_tracy` does it best to paper over these sorts of differences, it can’t\n    /// always make them invisible. In certain cases detecting these sorts of issues is\n    /// straightforward, and it is when `tracing_tracy` will invoke this method to enable users to\n    /// report the issues in whatever way they wish to.\n    ///\n    /// By default a message coloured in red is emitted to the tracy client.\n    fn on_error(&self, client: &Client, error: &'static str) {\n        client.color_message(error, 0xFF000000, 0);\n    }\n}\n\n/// A default configuration of the [`TracyLayer`](super::TracyLayer).\n///\n/// This type does not allow for any adjustment of the configuration. In order to customize\n/// the behaviour of the layer implement the [`Config`] trait for your own type.\n#[derive(Default)]\npub struct DefaultConfig(DefaultFields);\n\nimpl Config for DefaultConfig {\n    type Formatter = DefaultFields;\n    fn formatter(&self) -> &Self::Formatter {\n        &self.0\n    }\n}\n"
  },
  {
    "path": "tracing-tracy/src/lib.rs",
    "content": "//! Collect [Tracy] profiles in tracing-enabled applications.\n//!\n//! Assuming the application is well instrumented, this should in practice be a very low effort way\n//! to gain great amounts of insight into an application performance.\n//!\n//! Note, however that Tracy is ultimately a profiling, not an observability, tool. As thus, some\n//! of tracing concepts cannot be represented well by Tracy. For instance, out-of-order span\n//! entries and exits, are not supported, and neither are spans that are entered and exited on\n//! different threads. This crate will attempt to mitigate the problems and retain trace validity\n//! at the cost of potentially invalid data. When such a mitigation occurs, trace will contain a\n//! message with a note about the problem.\n//!\n//! Some other caveats to keep in mind:\n//!\n//! * Only span entries and exits are recorded;\n//! * Events show up as messages in Tracy, however Tracy can struggle with large numbers of\n//! messages;\n//! * Some additional functionality such as plotting and memory allocation profiling is only\n//! available as part of the [tracy-client](client) crate.\n//!\n//! # Examples\n//!\n//! The most basic way to setup the tracy subscriber globally is as follows:\n//!\n//! ```rust\n//! use tracing_subscriber::layer::SubscriberExt;\n//!\n//! tracing::subscriber::set_global_default(\n//!     tracing_subscriber::registry().with(tracing_tracy::TracyLayer::default())\n//! ).expect(\"setup tracy layer\");\n//! ```\n//!\n//! # Important note\n//!\n//! Depending on the configuration Tracy may broadcast discovery packets to the local network and\n//! expose the data it collects in the background to that same network. Traces collected by Tracy\n//! may include source and assembly code as well.\n//!\n//! As thus, you may want make sure to only enable the `tracing-tracy` crate conditionally, via the\n//! `enable` feature flag provided by this crate.\n//!\n//! [Tracy]: https://github.com/wolfpld/tracy\n//!\n//! # Features\n//!\n//! The following crate features are provided to customize the functionality of the Tracy client:\n//!\n#![doc = include_str!(\"../FEATURES.mkd\")]\n\nuse client::{Client, Span};\npub use config::{Config, DefaultConfig};\nuse std::sync::atomic::{AtomicUsize, Ordering};\nuse std::{fmt::Write, mem};\nuse tracing_core::{\n    field::{Field, Visit},\n    span::{Attributes, Id, Record},\n    Event, Subscriber,\n};\nuse tracing_subscriber::fmt::format::FormatFields;\nuse tracing_subscriber::{\n    layer::{Context, Layer},\n    registry,\n};\nuse utils::{StrCache, StrCacheGuard, VecCell};\n\npub use client;\nmod config;\n\ntype TracyFields<C> = tracing_subscriber::fmt::FormattedFields<<C as Config>::Formatter>;\n\nthread_local! {\n    /// A stack of spans currently active on the current thread.\n    static TRACY_SPAN_STACK: VecCell<(Span, u64)> = const { VecCell::new() };\n}\n\n/// A tracing layer that collects data in Tracy profiling format.\n///\n/// # Examples\n///\n/// ```rust\n/// use tracing_subscriber::layer::SubscriberExt;\n/// tracing::subscriber::set_global_default(\n///     tracing_subscriber::registry().with(tracing_tracy::TracyLayer::default())\n/// ).expect(\"setup tracy layer\");\n/// ```\n#[derive(Clone)]\npub struct TracyLayer<C = DefaultConfig> {\n    config: C,\n    client: Client,\n}\n\nimpl<C> TracyLayer<C> {\n    /// Create a new `TracyLayer`.\n    ///\n    /// Defaults to collecting stack traces.\n    #[must_use]\n    pub fn new(config: C) -> Self {\n        Self {\n            config,\n            client: Client::start(),\n        }\n    }\n}\n\nimpl<C: Config> TracyLayer<C> {\n    fn truncate_span_to_length<'a>(\n        &self,\n        data: &'a str,\n        file: &str,\n        function: &str,\n        error_msg: &'static str,\n    ) -> &'a str {\n        self.truncate_to_length(\n            // From AllocSourceLocation\n            usize::from(u16::MAX) - 2 - 4 - 4 - function.len() - 1 - file.len() - 1,\n            data,\n            error_msg,\n        )\n    }\n\n    fn truncate_to_length<'a>(\n        &self,\n        mut max_len: usize,\n        data: &'a str,\n        error_msg: &'static str,\n    ) -> &'a str {\n        if data.len() >= max_len {\n            while !data.is_char_boundary(max_len) {\n                max_len -= 1;\n            }\n            self.config.on_error(&self.client, error_msg);\n            &data[..max_len]\n        } else {\n            data\n        }\n    }\n}\n\nimpl Default for TracyLayer {\n    fn default() -> Self {\n        Self::new(DefaultConfig::default())\n    }\n}\n\nstatic MAX_CACHE_SIZE: AtomicUsize = AtomicUsize::new(8192);\n\n/// Specify the maximum number of bytes used in thread local caches.\n///\n/// A value of zero disables the cache, while a value of [`usize::MAX`] denotes an unlimited\n/// cache size.\n///\n/// Note: the upper bound on the cache size is respected on a best effort basis only. We make\n/// no guarantees on the maximum memory used by tracing-tracy. Notably, changes to this value\n/// are eventually consistent, i.e. caches are not flushed upon an update.\n///\n/// Defaults to `8192` per thread.\npub fn set_max_cache_size(max_bytes_used_per_thread: usize) {\n    MAX_CACHE_SIZE.store(max_bytes_used_per_thread, Ordering::Relaxed);\n}\n\nthread_local! {\n    static CACHE: StrCache = const { StrCache::new() };\n}\n\nimpl<S, C> Layer<S> for TracyLayer<C>\nwhere\n    S: Subscriber + for<'a> registry::LookupSpan<'a>,\n    C: Config + 'static,\n{\n    fn on_new_span(&self, attrs: &Attributes<'_>, id: &Id, ctx: Context<'_, S>) {\n        let Some(span) = ctx.span(id) else { return };\n\n        let mut extensions = span.extensions_mut();\n        if extensions.get_mut::<TracyFields<C>>().is_none() {\n            let mut fields =\n                TracyFields::<C>::new(CACHE.with(|cache| cache.acquire().into_inner()));\n            if self\n                .config\n                .formatter()\n                .format_fields(fields.as_writer(), attrs)\n                .is_ok()\n            {\n                extensions.insert(fields);\n            }\n        }\n    }\n\n    fn on_record(&self, id: &Id, values: &Record<'_>, ctx: Context<'_, S>) {\n        let Some(span) = ctx.span(id) else { return };\n\n        let mut extensions = span.extensions_mut();\n        if let Some(fields) = extensions.get_mut::<TracyFields<C>>() {\n            let _ = self.config.formatter().add_fields(fields, values);\n        } else {\n            let mut fields =\n                TracyFields::<C>::new(CACHE.with(|cache| cache.acquire().into_inner()));\n            if self\n                .config\n                .formatter()\n                .format_fields(fields.as_writer(), values)\n                .is_ok()\n            {\n                extensions.insert(fields);\n            }\n        }\n    }\n\n    fn on_event(&self, event: &Event, _: Context<'_, S>) {\n        CACHE.with(|cache| {\n            let mut buf = cache.acquire();\n            let mut visitor = TracyEventFieldVisitor {\n                dest: &mut buf,\n                first: true,\n                frame_mark: false,\n            };\n\n            event.record(&mut visitor);\n            if !visitor.first {\n                self.client.message(\n                    self.truncate_to_length(\n                        (u16::MAX - 1).into(),\n                        visitor.dest,\n                        \"event message is too long and was truncated\",\n                    ),\n                    self.config.stack_depth(event.metadata()),\n                );\n            }\n            if visitor.frame_mark {\n                self.client.frame_mark();\n            }\n        });\n    }\n\n    fn on_enter(&self, id: &Id, ctx: Context<S>) {\n        let Some(span) = ctx.span(id) else { return };\n\n        let extensions = span.extensions();\n        let fields = extensions.get::<TracyFields<C>>();\n        let stack_frame = {\n            let metadata = span.metadata();\n            let file = metadata.file().unwrap_or(\"<not available>\");\n            let line = metadata.line().unwrap_or(0);\n            let span = |name: &str| {\n                (\n                    self.client.clone().span_alloc(\n                        Some(self.truncate_span_to_length(\n                            name,\n                            file,\n                            \"\",\n                            \"span information is too long and was truncated\",\n                        )),\n                        \"\",\n                        file,\n                        line,\n                        self.config.stack_depth(metadata),\n                    ),\n                    id.into_u64(),\n                )\n            };\n\n            match fields {\n                None => span(metadata.name()),\n                Some(fields) if fields.is_empty() => span(metadata.name()),\n                Some(fields) if self.config.format_fields_in_zone_name() => CACHE.with(|cache| {\n                    let mut buf = cache.acquire();\n                    let _ = write!(buf, \"{}{{{}}}\", metadata.name(), fields.fields);\n                    span(&buf)\n                }),\n                Some(fields) => {\n                    let span = span(metadata.name());\n                    span.0.emit_text(self.truncate_to_length(\n                        (u16::MAX - 1).into(),\n                        &fields.fields,\n                        \"span field values are too long and were truncated\",\n                    ));\n                    span\n                }\n            }\n        };\n\n        TRACY_SPAN_STACK.with(|s| {\n            s.push(stack_frame);\n        });\n    }\n\n    fn on_exit(&self, id: &Id, _: Context<S>) {\n        let stack_frame = TRACY_SPAN_STACK.with(VecCell::pop);\n\n        if let Some((span, span_id)) = stack_frame {\n            if id.into_u64() != span_id {\n                self.config.on_error(\n                    &self.client,\n                    \"Tracing spans exited out of order! \\\n                        Trace might not be accurate for this span stack.\",\n                );\n            }\n            drop(span);\n        } else {\n            self.config.on_error(\n                &self.client,\n                \"Exiting a tracing span, but got nothing on the tracy span stack!\",\n            );\n        }\n    }\n\n    fn on_close(&self, id: Id, ctx: Context<'_, S>) {\n        let Some(span) = ctx.span(&id) else { return };\n\n        if let Some(fields) = span.extensions_mut().get_mut::<TracyFields<C>>() {\n            let buf = mem::take(&mut fields.fields);\n            CACHE.with(|cache| drop(StrCacheGuard::new(cache, buf)));\n        };\n    }\n}\n\nstruct TracyEventFieldVisitor<'a> {\n    dest: &'a mut String,\n    frame_mark: bool,\n    first: bool,\n}\n\nimpl Visit for TracyEventFieldVisitor<'_> {\n    fn record_bool(&mut self, field: &Field, value: bool) {\n        match (value, field.name()) {\n            (_, \"tracy.frame_mark\") => self.frame_mark = value,\n            (true, _) => self.record_str(field, \"true\"),\n            (false, _) => self.record_str(field, \"false\"),\n        }\n    }\n\n    fn record_str(&mut self, field: &Field, value: &str) {\n        let name = field.name();\n        let alloc_always_size = name.len() + \" = \".len() + value.len();\n        if self.first {\n            self.dest.reserve(alloc_always_size);\n            self.first = false;\n        } else {\n            self.dest.reserve(\", \".len() + alloc_always_size);\n            self.dest.push_str(\", \");\n        }\n\n        self.dest.push_str(name);\n        self.dest.push_str(\" = \");\n        self.dest.push_str(value);\n    }\n\n    fn record_debug(&mut self, field: &Field, value: &dyn std::fmt::Debug) {\n        // FIXME: this is a very crude formatter, but we don’t have\n        // an easy way to do anything better...\n        if self.first {\n            self.first = false;\n            let _ = write!(self.dest, \"{} = {value:?}\", field.name());\n        } else {\n            let _ = write!(self.dest, \", {} = {value:?}\", field.name());\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests;\n#[cfg(test)]\nfn main() {\n    if std::env::args_os().any(|p| p == std::ffi::OsStr::new(\"--bench\")) {\n        tests::bench();\n    } else {\n        tests::test();\n    }\n}\n\nmod utils {\n    use crate::MAX_CACHE_SIZE;\n    use std::cell::{Cell, UnsafeCell};\n    use std::mem;\n    use std::mem::ManuallyDrop;\n    use std::ops::{Deref, DerefMut};\n    use std::sync::atomic::Ordering;\n\n    pub struct VecCell<T>(UnsafeCell<Vec<T>>);\n\n    impl<T> VecCell<T> {\n        pub const fn new() -> Self {\n            Self(UnsafeCell::new(Vec::new()))\n        }\n\n        pub fn push(&self, item: T) {\n            // SAFETY:\n            // The reference to the contents of the UnsafeCell remain strictly within this method.\n            // In addition, this method is not re-entrant.\n            unsafe { &mut *self.0.get() }.push(item);\n        }\n\n        pub fn pop(&self) -> Option<T> {\n            // SAFETY:\n            // The reference to the contents of the UnsafeCell remain strictly within this method.\n            // In addition, this method is not re-entrant.\n            unsafe { &mut *self.0.get() }.pop()\n        }\n    }\n\n    pub struct StrCache {\n        str_bufs: VecCell<String>,\n        total_size: Cell<usize>,\n    }\n\n    impl StrCache {\n        pub const fn new() -> Self {\n            Self {\n                str_bufs: VecCell::new(),\n                total_size: Cell::new(0),\n            }\n        }\n\n        pub fn acquire(&self) -> StrCacheGuard {\n            StrCacheGuard::new(\n                self,\n                self.str_bufs\n                    .pop()\n                    // TODO use inspect once 1.76 is stable\n                    .map(|buf| {\n                        self.total_size.set(self.total_size.get() - buf.capacity());\n                        buf\n                    })\n                    .unwrap_or_else(|| String::with_capacity(64)),\n            )\n        }\n\n        fn release(&self, mut buf: String) {\n            let new_cache_size = self.total_size.get().saturating_add(buf.capacity());\n            if new_cache_size == usize::MAX {\n                // This is never going to happen, but if we've used the entire address space,\n                // don't bother adding another cache entry as this keeps the logic simpler.\n                return;\n            };\n            let max_size = MAX_CACHE_SIZE.load(Ordering::Relaxed);\n            if buf.capacity() == 0 || max_size == 0 {\n                return;\n            }\n\n            buf.clear();\n            self.str_bufs.push(buf);\n            self.total_size.set(new_cache_size);\n\n            if new_cache_size > max_size {\n                // SAFETY:\n                // Sorting is not re-entrant and VecCell does not hold active references. Since we\n                // hold a reference for the duration of this line only, we do not alias.\n                unsafe { &mut *self.str_bufs.0.get() }.sort_unstable_by_key(String::capacity);\n                if let Some(trimmed) = self.str_bufs.pop() {\n                    self.total_size\n                        .set(self.total_size.get() - trimmed.capacity());\n                }\n            }\n        }\n    }\n\n    pub struct StrCacheGuard<'a> {\n        cache: &'a StrCache,\n        buf: String,\n    }\n\n    impl<'a> StrCacheGuard<'a> {\n        pub fn new(cache: &'a StrCache, buf: String) -> Self {\n            Self { cache, buf }\n        }\n\n        pub fn into_inner(self) -> String {\n            let mut this = ManuallyDrop::new(self);\n            mem::take(&mut this.buf)\n        }\n    }\n\n    impl Deref for StrCacheGuard<'_> {\n        type Target = String;\n\n        fn deref(&self) -> &Self::Target {\n            &self.buf\n        }\n    }\n\n    impl DerefMut for StrCacheGuard<'_> {\n        fn deref_mut(&mut self) -> &mut Self::Target {\n            &mut self.buf\n        }\n    }\n\n    impl Drop for StrCacheGuard<'_> {\n        fn drop(&mut self) {\n            self.cache.release(mem::take(&mut self.buf));\n        }\n    }\n}\n"
  },
  {
    "path": "tracing-tracy/src/tests.rs",
    "content": "use crate::{Config, DefaultConfig};\n\nuse super::TracyLayer;\nuse criterion::Criterion;\nuse futures::future::join_all;\nuse tracing::{debug, event, info, info_span, span, Level};\nuse tracing_attributes::instrument;\nuse tracing_subscriber::layer::SubscriberExt;\n\nfn it_works() {\n    let span = span!(Level::TRACE, \"a sec\");\n    let _enter = span.enter();\n    event!(Level::INFO, \"EXPLOSION!\");\n}\n\nfn it_works_2() {\n    let span = span!(Level::TRACE, \"2 secs\");\n    let _enter = span.enter();\n    event!(\n        Level::INFO,\n        message = \"DOUBLE THE EXPLOSION!\",\n        tracy.frame_mark = true\n    );\n}\n\nfn multiple_entries() {\n    let span = span!(Level::INFO, \"multiple_entries\");\n    span.in_scope(|| {});\n    span.in_scope(|| {});\n\n    let span = span!(Level::INFO, \"multiple_entries 2\");\n    span.in_scope(|| span.in_scope(|| {}));\n}\n\nfn out_of_order() {\n    let span1 = span!(Level::INFO, \"out of order exits 1\");\n    let span2 = span!(Level::INFO, \"out of order exits 2\");\n    let span3 = span!(Level::INFO, \"out of order exits 3\");\n    let entry1 = span1.enter();\n    let entry2 = span2.enter();\n    let entry3 = span3.enter();\n    drop(entry2);\n    drop(entry3);\n    drop(entry1);\n}\n\nfn exit_in_different_thread() {\n    let span = Box::new(span!(Level::INFO, \"exit in different thread\"));\n    let entry = span.enter();\n    std::thread::scope(|scope| {\n        let thread = scope.spawn(move || drop(entry));\n        thread.join().unwrap();\n    });\n}\n\nasync fn parent_task(subtasks: usize) {\n    info!(\"spawning subtasks...\");\n    let subtasks = (1..=subtasks)\n        .map(|number| {\n            debug!(message = \"creating subtask;\", number);\n            subtask(number)\n        })\n        .collect::<Vec<_>>();\n\n    let result = join_all(subtasks).await;\n\n    debug!(\"all subtasks completed\");\n    let sum: usize = result.into_iter().sum();\n    info!(sum);\n}\n\n#[instrument]\nasync fn subtask(number: usize) -> usize {\n    info!(\"sleeping in subtask {}...\", number);\n    tokio::time::sleep(std::time::Duration::from_millis(10)).await;\n    info!(\"sleeping in subtask {}...\", number);\n    tokio::time::sleep(std::time::Duration::from_millis(number as _)).await;\n    info!(\"sleeping in subtask {}...\", number);\n    tokio::time::sleep(std::time::Duration::from_millis(10)).await;\n    number\n}\n\n// Test based on the spawny_things example from the tracing repository.\nasync fn async_futures() {\n    parent_task(5).await;\n}\n\nfn message_too_long() {\n    info!(\"{}\", \"a\".repeat(u16::MAX.into()));\n}\n\nfn long_span_data() {\n    let data = \"c\".repeat(u16::MAX.into());\n    info_span!(\"some span name\", \"{}\", data).in_scope(|| {});\n}\n\nfn span_with_fields() {\n    let span = span!(\n        Level::TRACE,\n        \"wait\",\n        duration = 0,\n        reason = \"testing fields\"\n    );\n    let _enter = span.enter();\n}\n\npub(crate) fn test() {\n    tracing::subscriber::set_global_default(\n        tracing_subscriber::registry().with(TracyLayer::default()),\n    )\n    .expect(\"setup the subscriber\");\n    it_works();\n    it_works_2();\n    multiple_entries();\n    out_of_order();\n    exit_in_different_thread();\n    message_too_long();\n    long_span_data();\n    span_with_fields();\n    let runtime = tokio::runtime::Builder::new_current_thread()\n        .enable_all()\n        .build()\n        .expect(\"tokio runtime\");\n    runtime.block_on(async_futures());\n}\n\n#[derive(Default)]\nstruct CallstackConfig(DefaultConfig);\nimpl Config for CallstackConfig {\n    type Formatter = <DefaultConfig as Config>::Formatter;\n    fn formatter(&self) -> &Self::Formatter {\n        self.0.formatter()\n    }\n    fn stack_depth(&self, _: &tracing_core::Metadata<'_>) -> u16 {\n        100\n    }\n}\n\nfn benchmark_span(c: &mut Criterion) {\n    c.bench_function(\"span/callstack\", |bencher| {\n        let layer =\n            tracing_subscriber::registry().with(TracyLayer::new(CallstackConfig::default()));\n        tracing::subscriber::with_default(layer, || {\n            bencher.iter(|| {\n                let _span =\n                    tracing::error_span!(\"message\", field1 = \"first\", field2 = \"second\").entered();\n            });\n        });\n    });\n\n    c.bench_function(\"span/no_callstack\", |bencher| {\n        let layer = tracing_subscriber::registry().with(TracyLayer::default());\n        tracing::subscriber::with_default(layer, || {\n            bencher.iter(|| {\n                let _span =\n                    tracing::error_span!(\"message\", field1 = \"first\", field2 = \"second\").entered();\n            });\n        });\n    });\n}\n\nfn benchmark_message(c: &mut Criterion) {\n    c.bench_function(\"event/callstack\", |bencher| {\n        let layer =\n            tracing_subscriber::registry().with(TracyLayer::new(CallstackConfig::default()));\n        tracing::subscriber::with_default(layer, || {\n            bencher.iter(|| {\n                tracing::error!(field1 = \"first\", field2 = \"second\", \"message\");\n            });\n        });\n    });\n\n    c.bench_function(\"event/no_callstack\", |bencher| {\n        let layer = tracing_subscriber::registry().with(TracyLayer::default());\n        tracing::subscriber::with_default(layer, || {\n            bencher.iter(|| {\n                tracing::error!(field1 = \"first\", field2 = \"second\", \"message\");\n            });\n        });\n    });\n}\n\npub(crate) fn bench() {\n    criterion::criterion_group!(benches, benchmark_span, benchmark_message);\n    benches();\n    Criterion::default().configure_from_args().final_summary();\n}\n"
  },
  {
    "path": "tracy-client/Cargo.toml",
    "content": "[package]\nname = \"tracy-client\"\nversion = \"0.18.4\" # AUTO-BUMP\nauthors = [\"Simonas Kazlauskas <tracy-client@kazlauskas.me>\"]\nlicense.workspace = true\nedition.workspace = true\nrust-version.workspace = true\nreadme = \"README.mkd\"\nrepository.workspace = true\nhomepage.workspace = true\ndocumentation = \"https://docs.rs/tracy-client\"\ndescription = \"\"\"\nHigh level bindings to the client libraries for the Tracy profiler\n\"\"\"\n\n[[test]]\nname = \"tests\"\npath = \"tests/tests.rs\"\nharness = false\n\n[[test]]\nname = \"loom\"\npath = \"tests/loom.rs\"\nharness = false\n\n[[bench]]\nname = \"client\"\npath = \"benches/client.rs\"\nharness = false\n\n[dev-dependencies]\ncriterion = \"0.5\"\n\n[dependencies]\nonce_cell = \"1.19\"\nrustc-demangle = { version = \"0.1\", optional = true }\n\n[dependencies.sys]\npath = \"../tracy-client-sys\"\npackage = \"tracy-client-sys\"\nversion = \">=0.23.0, <0.29.0\" # AUTO-UPDATE\ndefault-features = false\n\n[target.'cfg(loom)'.dependencies.loom]\nversion = \"0.7\"\n\n[features]\n# Refer to FEATURES.mkd for documentation on features.\ndefault = [ \"enable\", \"system-tracing\", \"context-switch-tracing\", \"sampling\", \"code-transfer\",\n            \"broadcast\", \"callstack-inlines\", \"crash-handler\" ]\nbroadcast = [\"sys/broadcast\"]\ncode-transfer = [\"sys/code-transfer\"]\ncontext-switch-tracing = [\"sys/context-switch-tracing\"]\nenable = [\"sys/enable\"]\nfibers = [\"sys/fibers\"]\ntimer-fallback = [\"sys/timer-fallback\"]\nondemand = [\"sys/ondemand\"]\nonly-ipv4 = [\"sys/only-ipv4\"]\nonly-localhost = [\"sys/only-localhost\"]\nsampling = [\"sys/sampling\"]\nsystem-tracing = [\"sys/system-tracing\"]\ncallstack-inlines = [\"sys/callstack-inlines\"]\nmanual-lifetime = [\"sys/manual-lifetime\"]\ndelayed-init = [\"sys/delayed-init\"]\nflush-on-exit = [\"sys/flush-on-exit\"]\ndemangle = [\"sys/demangle\", \"dep:rustc-demangle\"]\nverify = [\"sys/verify\"]\ndebuginfod = [\"sys/debuginfod\"]\ncrash-handler = [\"sys/crash-handler\"]\n\n[package.metadata.docs.rs]\nall-features = true\n"
  },
  {
    "path": "tracy-client/benches/client.rs",
    "content": "use criterion::{criterion_group, criterion_main, Criterion};\nuse tracy_client::Client;\n\nfn client_start(c: &mut Criterion) {\n    let mut clients = Vec::<Client>::with_capacity(1_000_000_000);\n    c.bench_function(\"start\", |b| b.iter(|| clients.push(Client::start())));\n}\n\nfn client_clone(c: &mut Criterion) {\n    let mut clients = Vec::<Client>::with_capacity(1_000_000_000);\n    let client = Client::start();\n    c.bench_function(\"clone\", |b| b.iter(|| clients.push(client.clone())));\n}\n\nfn client_running(c: &mut Criterion) {\n    let _client = Client::start();\n    c.bench_function(\"running\", |b| b.iter(Client::running));\n}\n\nfn ops_alloc(c: &mut Criterion) {\n    let client = Client::start();\n    c.bench_function(\"span_alloc_callstack/0\", |bencher| {\n        bencher.iter(|| {\n            let _ = client\n                .clone()\n                .span_alloc(Some(\"hello\"), \"function\", \"file\", 42, 0);\n        });\n    });\n    c.bench_function(\"span_alloc_callstack/100\", |bencher| {\n        bencher.iter(|| {\n            let _ = client\n                .clone()\n                .span_alloc(Some(\"hello\"), \"function\", \"file\", 42, 100);\n        });\n    });\n}\n\nfn ops_static(c: &mut Criterion) {\n    let _client = tracy_client::Client::start();\n    c.bench_function(\"span_callstack/0\", |bencher| {\n        bencher.iter(|| {\n            let _ = tracy_client::span!(\"some_name\", 0);\n        });\n    });\n    c.bench_function(\"span_callstack/100\", |bencher| {\n        bencher.iter(|| {\n            let _ = tracy_client::span!(\"some_name\", 100);\n        });\n    });\n}\n\ncriterion_group!(\n    benches,\n    client_start,\n    client_clone,\n    client_running,\n    ops_alloc,\n    ops_static\n);\ncriterion_main!(benches);\n"
  },
  {
    "path": "tracy-client/src/demangle.rs",
    "content": "//! Custom symbol demangling support.\n//!\n//! By default, Tracy demangles symbols using the C++ ABI, which is not fully compatible with Rust\n//! symbol mangling.\n//!\n//! With the `demangle` feature enabled, clients must register a custom demangling function.\n//! This can be done by calling the [`register_demangler!`][macro] macro with either no arguments\n//! to use the [default demangler](default), or with a path to a custom demangler function. See\n//! [its documentation][macro] for how to use it.\n//!\n//! Note that only one demangler can be registered at a time. Attempting to register multiple\n//! demanglers will result in a linking failure due to multiple definitions of the underlying\n//! `extern \"C\"` function.\n//!\n//! [macro]: crate::register_demangler\n\nuse std::fmt;\n\n/// Opaque buffer used to write demangled symbols.\n///\n/// The only exposed API is currently [`fmt::Write`].\n///\n/// See [the module-level documentation](self) for more information.\npub struct Buffer(String);\n\nimpl fmt::Write for Buffer {\n    #[inline]\n    fn write_str(&mut self, s: &str) -> fmt::Result {\n        self.0.write_str(s)\n    }\n\n    #[inline]\n    fn write_char(&mut self, c: char) -> fmt::Result {\n        self.0.write_char(c)\n    }\n}\n\nimpl Buffer {\n    const fn new() -> Self {\n        Self(String::new())\n    }\n\n    fn clear_on_err<T, E>(&mut self, f: impl FnOnce(&mut Self) -> Result<T, E>) -> Result<T, E> {\n        let r = f(self);\n        if r.is_err() {\n            self.0.clear();\n        }\n        r\n    }\n}\n\n/// Demangles a Rust symbol using [`rustc_demangle`].\n///\n/// See [the module-level documentation](self) for more information.\npub fn default(s: &str, buffer: &mut impl fmt::Write) -> fmt::Result {\n    let Ok(demangled) = rustc_demangle::try_demangle(s) else {\n        return Err(fmt::Error);\n    };\n    // Use `:#` formatting to elide the hash.\n    write!(buffer, \"{demangled:#}\")\n}\n\n/// Symbol demangler that does nothing.\n///\n/// See [the module-level documentation](self) for more information.\npub fn noop(_: &str, _: &mut impl fmt::Write) -> fmt::Result {\n    Err(fmt::Error)\n}\n\npub(super) mod internal {\n    use super::Buffer;\n    use std::ffi::c_char;\n    use std::fmt::{self, Write};\n    use std::ptr::null;\n\n    /// Demangling glue.\n    pub unsafe fn implementation<F>(mangled: *const c_char, run: F) -> *const c_char\n    where\n        F: FnOnce(&str, &mut Buffer) -> fmt::Result,\n    {\n        // https://github.com/wolfpld/tracy/blob/d4a4b623968d99a7403cd93bae5247ed0735680a/public/client/TracyCallstack.cpp#L57-L67\n        // > The demangling function is responsible for managing memory for this string.\n        // > It is expected that it will be internally reused.\n        // > When a call to ___tracy_demangle is made, previous contents of the string memory\n        // > do not need to be preserved.\n        static mut BUFFER: Buffer = Buffer::new();\n\n        if mangled.is_null() {\n            return null();\n        }\n        let cstr = unsafe { std::ffi::CStr::from_ptr(mangled) };\n        let Ok(str) = cstr.to_str() else {\n            return null();\n        };\n\n        let buffer = unsafe { &mut *std::ptr::addr_of_mut!(BUFFER) };\n        buffer.0.clear();\n        let result = buffer.clear_on_err(|buffer| {\n            run(str, buffer)?;\n            match buffer.0.as_bytes().split_last() {\n                None | Some((&0, [])) => return Err(fmt::Error),\n                Some((_, v)) if v.contains(&0) => return Err(fmt::Error),\n                Some((&0, _)) => return Ok(()),\n                _ => (),\n            }\n            buffer.write_char('\\0')?;\n            Ok(())\n        });\n        match result {\n            Ok(()) => {\n                debug_assert_eq!(buffer.0.as_bytes().last().copied(), Some(0));\n                buffer.0.as_ptr().cast()\n            }\n            Err(fmt::Error) => null(),\n        }\n    }\n}\n\n/// Registers a custom demangler function.\n///\n/// A [default implementation](default) for demangling Rust symbols can be registered by passing no\n/// arguments.\n///\n/// Custom implementations can be registered by passing a function with the following signature:\n/// `fn(mangled: &str, buffer: &mut tracy_client::demangle::Buffer) -> std::fmt::Result`\n///\n/// Custom demanglers:\n/// - Must not write null bytes to the buffer.\n/// - Returning `Err` or leaving the buffer unchanged will result in the symbol being displayed as-is.\n///\n/// See [the module-level documentation](self) for more information.\n///\n/// # Examples\n///\n/// ```\n/// use tracy_client::{demangle, register_demangler};\n///\n/// // Register the default demangler.\n/// # #[cfg(any())]\n/// register_demangler!();\n///\n/// // Register a noop demangler.\n/// # #[cfg(any())]\n/// register_demangler!(demangle::noop);\n///\n/// // Register a custom demangler.\n/// # #[cfg(any())]\n/// register_demangler!(my_demangler);\n///\n/// fn my_demangler(s: &str, buffer: &mut demangle::Buffer) -> std::fmt::Result {\n///     // Custom demangling logic...\n///     use std::fmt::Write;\n///     write!(buffer, \"{s}\")?;\n///     Ok(())\n/// }\n/// ```\n#[macro_export]\nmacro_rules! register_demangler {\n    () => {\n        $crate::register_demangler!($crate::internal::demangle::default);\n    };\n\n    ($path:path) => {\n        const _: () = {\n            #[no_mangle]\n            unsafe extern \"C\" fn ___tracy_demangle(\n                mangled: *const std::ffi::c_char,\n            ) -> *const std::ffi::c_char {\n                unsafe { $crate::internal::demangle::implementation(mangled, $path) }\n            }\n        };\n    };\n}\n"
  },
  {
    "path": "tracy-client/src/frame.rs",
    "content": "use crate::Client;\n\n/// A non-continuous frame region.\n///\n/// Create with the [`Client::non_continuous_frame`] function.\npub struct Frame(Client, FrameName);\n\n/// A name for secondary and non-continuous frames.\n///\n/// Create with the [`frame_name!`](crate::frame_name) macro.\n#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]\npub struct FrameName(pub(crate) &'static str);\n\nimpl FrameName {\n    /// Construct a `FrameName` dynamically, leaking the provided String.\n    ///\n    /// You should call this function once for a given name, and store the returned `FrameName` for\n    /// continued use, to avoid rapid memory use growth. Whenever possible, prefer the\n    /// [`frame_name!`](crate::frame_name) macro, which takes a literal name and doesn't leak\n    /// memory.\n    ///\n    /// The resulting value may be used as an argument for the the [`Client::secondary_frame_mark`]\n    /// and [`Client::non_continuous_frame`] methods.\n    #[must_use]\n    pub fn new_leak(name: String) -> Self {\n        #[cfg(feature = \"enable\")]\n        {\n            // Ensure the name is null-terminated.\n            let mut name = name;\n            name.push('\\0');\n            // Drop excess capacity by converting into a boxed str, then leak.\n            let name = Box::leak(name.into_boxed_str());\n            Self(name)\n        }\n        #[cfg(not(feature = \"enable\"))]\n        {\n            drop(name);\n            Self(\"\\0\")\n        }\n    }\n}\n\n/// Instrumentation for global frame indicators.\nimpl Client {\n    /// Indicate that rendering of a continuous frame has ended.\n    ///\n    /// # Examples\n    ///\n    /// In a traditional rendering scenarios a frame mark should be inserted after a buffer swap.\n    ///\n    /// ```\n    /// use tracy_client::Client;\n    /// # fn swap_buffers() {}\n    /// # let client = tracy_client::Client::start();\n    /// // loop {\n    /// //     ...\n    ///        swap_buffers();\n    ///        Client::running().expect(\"client must be running\").frame_mark();\n    /// // }\n    /// ```\n    pub fn frame_mark(&self) {\n        #[cfg(feature = \"enable\")]\n        unsafe {\n            let () = sys::___tracy_emit_frame_mark(std::ptr::null());\n        }\n    }\n\n    /// Indicate that rendering of a secondary (named) continuous frame has ended.\n    ///\n    /// # Examples\n    ///\n    /// Much like with the primary frame mark, the secondary (named) frame mark should be inserted\n    /// after some continuously repeating operation finishes one iteration of its processing.\n    ///\n    /// ```\n    /// use tracy_client::frame_name;\n    /// # fn physics_tick() {}\n    /// # let client = tracy_client::Client::start();\n    /// // loop {\n    /// //     ...\n    ///        physics_tick();\n    ///        tracy_client::Client::running()\n    ///            .expect(\"client must be running\")\n    ///            .secondary_frame_mark(frame_name!(\"physics\"));\n    /// // }\n    /// ```\n    pub fn secondary_frame_mark(&self, name: FrameName) {\n        #[cfg(feature = \"enable\")]\n        unsafe {\n            // SAFE: We ensured that the name would be null-terminated.\n            let () = sys::___tracy_emit_frame_mark(name.0.as_ptr().cast());\n        }\n    }\n\n    /// Indicate that a processing of a non-continuous frame has begun.\n    ///\n    /// Dropping the returned [`Frame`] will terminate the non-continuous frame.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use tracy_client::frame_name;\n    /// # let client = tracy_client::Client::start();\n    /// let _guard = tracy_client::Client::running()\n    ///     .expect(\"client must be running\")\n    ///     .non_continuous_frame(frame_name!(\"a frame\"));\n    /// ```\n    #[must_use]\n    pub fn non_continuous_frame(&self, name: FrameName) -> Frame {\n        #[cfg(feature = \"enable\")]\n        unsafe {\n            // SAFE: We ensure that the name would be null-terminated.\n            let () = sys::___tracy_emit_frame_mark_start(name.0.as_ptr().cast());\n        }\n        Frame(self.clone(), name)\n    }\n\n    /// Emits an image of a frame.\n    ///\n    /// The following restrictions apply:\n    /// - The image must be in RGBA format.\n    /// - The image width and height must be divisible by four.\n    /// - The image data must be less than 256 KB, and should be as small as\n    ///   possible.\n    ///\n    /// The offset indicates how many frames in the past the image was captured.\n    /// For example, an offset of 1 would associate the image with the previous\n    /// call to [`frame_mark`](Client::frame_mark).\n    ///\n    /// The `flip` parameter indicates that the image should be flipped before\n    /// displaying, for example if the image is an OpenGL texture.\n    pub fn frame_image(&self, image: &[u8], width: u16, height: u16, offset: u8, flip: bool) {\n        #[cfg(feature = \"enable\")]\n        unsafe {\n            // SAFE: Tracy copies the data before returning.\n            let ptr = image.as_ptr();\n\n            let () = sys::___tracy_emit_frame_image(ptr.cast(), width, height, offset, flip as i32);\n        }\n    }\n}\n\n/// Construct a [`FrameName`].\n///\n/// The resulting value may be used as an argument for the the [`Client::secondary_frame_mark`] and\n/// [`Client::non_continuous_frame`] methods. The macro can be used in a `const` context.\n#[macro_export]\nmacro_rules! frame_name {\n    ($name: literal) => {{\n        unsafe { $crate::internal::create_frame_name(concat!($name, \"\\0\")) }\n    }};\n}\n\nimpl Drop for Frame {\n    fn drop(&mut self) {\n        #[cfg(feature = \"enable\")]\n        unsafe {\n            // SAFE: We ensure that thena me would be null-terminated. We also still have an owned\n            // Client handle.\n            let () = sys::___tracy_emit_frame_mark_end(self.1 .0.as_ptr().cast());\n            std::convert::identity(&self.0);\n        }\n    }\n}\n\n/// Convenience shortcut for [`Client::frame_mark`] on the current client.\n///\n/// # Panics\n///\n/// - If a `Client` isn't currently running.\npub fn frame_mark() {\n    Client::running()\n        .expect(\"frame_mark! without a running Client\")\n        .frame_mark();\n}\n\n/// Convenience shortcut for [`Client::frame_image`] on the current client.\npub fn frame_image(image: &[u8], width: u16, height: u16, offset: u8, flip: bool) {\n    Client::running()\n        .expect(\"frame_image without a running Client\")\n        .frame_image(image, width, height, offset, flip);\n}\n\n/// Convenience macro for [`Client::secondary_frame_mark`] on the current client.\n///\n/// # Panics\n///\n/// - If a `Client` isn't currently running.\n#[macro_export]\nmacro_rules! secondary_frame_mark {\n    ($name: literal) => {{\n        $crate::Client::running()\n            .expect(\"secondary_frame_mark! without a running Client\")\n            .secondary_frame_mark($crate::frame_name!($name))\n    }};\n}\n\n/// Convenience macro for [`Client::non_continuous_frame`] on the current client.\n///\n/// # Panics\n///\n/// - If a `Client` isn't currently running.\n#[macro_export]\nmacro_rules! non_continuous_frame {\n    ($name: literal) => {{\n        $crate::Client::running()\n            .expect(\"non_continuous_frame! without a running Client\")\n            .non_continuous_frame($crate::frame_name!($name))\n    }};\n}\n"
  },
  {
    "path": "tracy-client/src/gpu.rs",
    "content": "use std::{\n    convert::TryInto,\n    sync::{Arc, Mutex},\n};\n\nuse crate::{Client, SpanLocation};\n\n#[repr(u8)]\n/// The API label associated with the given gpu context. The list here only includes\n/// APIs that are currently supported by Tracy's own gpu implementations.\n//\n// Copied from `tracy-client-sys/tracy/common/TracyQueue.hpp:391`. Comment on enum states\n// that the values are stable, due to potential serialization issues, so copying this enum\n// shouldn't be a problem.\npub enum GpuContextType {\n    /// Stand in for other types of contexts.\n    Invalid = 0,\n    /// An OpenGL context\n    OpenGL = 1,\n    /// A Vulkan context\n    Vulkan = 2,\n    /// An OpenCL context\n    OpenCL = 3,\n    /// A D3D12 context.\n    Direct3D12 = 4,\n    /// A D3D11 context.\n    Direct3D11 = 5,\n}\n\n/// Context for creating gpu spans.\n///\n/// Generally corresponds to a single hardware queue.\n///\n/// The flow of creating and using gpu context generally looks like this:\n///\n/// ```rust,no_run\n/// # let client = tracy_client::Client::start();\n/// // The period of the gpu clock in nanoseconds, as provided by your GPU api.\n/// // This value corresponds to 1GHz.\n/// let period: f32 = 1_000_000_000.0;\n///\n/// // GPU API: Record writing a timestamp and resolve that to a mappable buffer.\n/// // GPU API: Submit the command buffer writing the timestamp.\n/// // GPU API: Immediately block until the submission is finished.\n/// // GPU API: Map buffer, get timestamp value.\n/// let starting_timestamp: i64 = /* whatever you get from this timestamp */ 0;\n///\n/// // Create the gpu context\n/// let gpu_context = client.new_gpu_context(\n///     Some(\"MyContext\"),\n///     tracy_client::GpuContextType::Vulkan,\n///     starting_timestamp,\n///     period\n/// ).unwrap();\n///\n/// // Now you have some work that you want to time on the gpu.\n///\n/// // GPU API: Record writing a timestamp before the work.\n/// let mut span = gpu_context.span_alloc(\"MyGpuSpan1\", \"My::Work\", \"myfile.rs\", 12).unwrap();\n///\n/// // GPU API: Record work.\n///\n/// // GPU API: Record writing a timestamp after the work.\n/// span.end_zone();\n///\n/// // Some time later, once the written timestamp values are available on the cpu.\n/// # let (starting_timestamp, ending_timestamp) = (0, 0);\n///\n/// span.upload_timestamp_start(starting_timestamp);\n/// span.upload_timestamp_end(ending_timestamp);\n/// ```\n#[derive(Clone)]\npub struct GpuContext {\n    #[cfg(feature = \"enable\")]\n    _client: Client,\n    #[cfg(feature = \"enable\")]\n    value: u8,\n    #[cfg(feature = \"enable\")]\n    span_freelist: Arc<Mutex<Vec<u16>>>,\n    _private: (),\n}\n#[cfg(feature = \"enable\")]\nstatic GPU_CONTEXT_INDEX: Mutex<u8> = Mutex::new(0);\n\n/// Errors that can occur when creating a gpu context.\n#[derive(Debug)]\npub enum GpuContextCreationError {\n    /// More than `u8::MAX` contexts have been created at any point in the program.\n    TooManyContextsCreated,\n}\n\nimpl std::fmt::Display for GpuContextCreationError {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        write!(\n            f,\n            \"More than 255 contexts have been created at any point in the execution of this program.\"\n        )\n    }\n}\n\nimpl std::error::Error for GpuContextCreationError {}\n\n#[derive(Debug, PartialEq)]\nenum GpuSpanState {\n    /// The span has been started. All gpu spans start in this state.\n    Started,\n    /// The span has been ended, either waiting for timestamp upload or with\n    /// timestamp upload completed.\n    Ended,\n}\n\n/// Span for timing gpu work.\n///\n/// See the [context level documentation](GpuContext) for more information on use.\n///\n/// If the span is dropped early, the following happens:\n/// - If the span has not been ended, the span is ended. AND\n/// - If the span has not had values uploaded, the span is uploaded with\n///   the timestamps marking the start of the current gpu context. This\n///   will put the span out of the way of other spans.\n#[must_use]\npub struct GpuSpan {\n    #[cfg(feature = \"enable\")]\n    context: GpuContext,\n    #[cfg(feature = \"enable\")]\n    start_query_id: u16,\n    #[cfg(feature = \"enable\")]\n    end_query_id: u16,\n    #[cfg(feature = \"enable\")]\n    state: GpuSpanState,\n    _private: (),\n}\n\n/// Errors that can occur when creating a gpu span.\n#[derive(Debug)]\npub enum GpuSpanCreationError {\n    /// More than `32767` spans are still waiting for gpu data.\n    TooManyPendingSpans,\n}\n\nimpl std::fmt::Display for GpuSpanCreationError {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        write!(\n            f,\n            \"Too many spans still waiting for gpu data. There may not be more than 32767 spans that are pending gpu data at once.\"\n        )\n    }\n}\n\nimpl std::error::Error for GpuSpanCreationError {}\n\nimpl Client {\n    /// Creates a new GPU context.\n    ///\n    /// - `name` is the name of the context.\n    /// - `ty` is the type (backend) of the context.\n    /// - `gpu_timestamp` is the gpu side timestamp the corresponds (as close as possible) to this call.\n    /// - `period` is the period of the gpu clock in nanoseconds (setting 1.0 means the clock is 1GHz, 1000.0 means 1MHz, etc).\n    ///\n    /// See the [type level documentation](GpuContext) for more information.\n    ///\n    /// # Errors\n    ///\n    /// - If more than 255 contexts were made during the lifetime of the application.\n    pub fn new_gpu_context(\n        self,\n        name: Option<&str>,\n        ty: GpuContextType,\n        gpu_timestamp: i64,\n        period: f32,\n    ) -> Result<GpuContext, GpuContextCreationError> {\n        #[cfg(feature = \"enable\")]\n        {\n            // We use a mutex to lock the context index to prevent races when using fetch_add.\n            //\n            // This prevents multiple contexts getting the same context id.\n            let mut context_index_guard = GPU_CONTEXT_INDEX.lock().unwrap();\n            if *context_index_guard == 255 {\n                return Err(GpuContextCreationError::TooManyContextsCreated);\n            }\n            let context = *context_index_guard;\n            *context_index_guard += 1;\n            drop(context_index_guard);\n\n            // SAFETY:\n            // - We know we aren't re-using the context id because of the above logic.\n            unsafe {\n                sys::___tracy_emit_gpu_new_context_serial(sys::___tracy_gpu_new_context_data {\n                    gpuTime: gpu_timestamp,\n                    period,\n                    context,\n                    flags: 0,\n                    type_: ty as u8,\n                });\n            };\n\n            if let Some(name) = name {\n                // SAFETY:\n                // - We've allocated a context.\n                // - The names will copied into the command stream, so the pointers do not need to last.\n                unsafe {\n                    sys::___tracy_emit_gpu_context_name_serial(\n                        sys::___tracy_gpu_context_name_data {\n                            context,\n                            name: name.as_ptr().cast(),\n                            len: name.len().try_into().unwrap_or(u16::MAX),\n                        },\n                    );\n                }\n            }\n\n            Ok(GpuContext {\n                _client: self,\n                value: context,\n                span_freelist: Arc::new(Mutex::new((0..=u16::MAX).collect())),\n                _private: (),\n            })\n        }\n        #[cfg(not(feature = \"enable\"))]\n        Ok(GpuContext { _private: () })\n    }\n}\n\nimpl GpuContext {\n    #[cfg(feature = \"enable\")]\n    fn alloc_span_ids(&self) -> Result<(u16, u16), GpuSpanCreationError> {\n        let mut freelist = self.span_freelist.lock().unwrap();\n        if freelist.len() < 2 {\n            return Err(GpuSpanCreationError::TooManyPendingSpans);\n        }\n        // These unwraps are unreachable.\n        let start = freelist.pop().unwrap();\n        let end = freelist.pop().unwrap();\n        Ok((start, end))\n    }\n\n    /// Creates a new gpu span with the given source location.\n    ///\n    /// This should be called right next to where you record the corresponding gpu timestamp. This\n    /// allows tracy to correctly associate the cpu time with the gpu timestamp.\n    ///\n    /// # Errors\n    ///\n    /// - If there are more than 32767 spans waiting for gpu data at once.\n    pub fn span(\n        &self,\n        span_location: &'static SpanLocation,\n    ) -> Result<GpuSpan, GpuSpanCreationError> {\n        #[cfg(feature = \"enable\")]\n        {\n            let (start_query_id, end_query_id) = self.alloc_span_ids()?;\n\n            // SAFETY: We know that the span location is valid forever as it is 'static. `usize` will\n            // always be smaller than u64, so no data will be lost.\n            unsafe {\n                sys::___tracy_emit_gpu_zone_begin_serial(sys::___tracy_gpu_zone_begin_data {\n                    srcloc: std::ptr::addr_of!(span_location.data) as usize as u64,\n                    queryId: start_query_id,\n                    context: self.value,\n                });\n            };\n\n            Ok(GpuSpan {\n                context: self.clone(),\n                start_query_id,\n                end_query_id,\n                state: GpuSpanState::Started,\n                _private: (),\n            })\n        }\n        #[cfg(not(feature = \"enable\"))]\n        Ok(GpuSpan { _private: () })\n    }\n\n    /// Creates a new gpu span with the given name, function, file, and line.\n    ///\n    /// This should be called right next to where you record the corresponding gpu timestamp. This\n    /// allows tracy to correctly associate the cpu time with the gpu timestamp.\n    ///\n    /// # Errors\n    ///\n    /// - If there are more than 32767 spans waiting for gpu data at once.\n    pub fn span_alloc(\n        &self,\n        name: &str,\n        function: &str,\n        file: &str,\n        line: u32,\n    ) -> Result<GpuSpan, GpuSpanCreationError> {\n        #[cfg(feature = \"enable\")]\n        {\n            let srcloc = unsafe {\n                sys::___tracy_alloc_srcloc_name(\n                    line,\n                    file.as_ptr().cast(),\n                    file.len(),\n                    function.as_ptr().cast(),\n                    function.len(),\n                    name.as_ptr().cast(),\n                    name.len(),\n                    0,\n                )\n            };\n\n            let (start_query_id, end_query_id) = self.alloc_span_ids()?;\n\n            unsafe {\n                sys::___tracy_emit_gpu_zone_begin_alloc_serial(sys::___tracy_gpu_zone_begin_data {\n                    srcloc,\n                    queryId: start_query_id,\n                    context: self.value,\n                });\n            };\n\n            Ok(GpuSpan {\n                context: self.clone(),\n                start_query_id,\n                end_query_id,\n                state: GpuSpanState::Started,\n                _private: (),\n            })\n        }\n        #[cfg(not(feature = \"enable\"))]\n        Ok(GpuSpan { _private: () })\n    }\n\n    /// Begins a new manually tracked GPU span.\n    ///\n    /// You can use this instead of [`GpuContext::span()`] if you'd like to track the GPU span\n    /// manually. `query_id` is the id of the GPU timestamp query that you had created; when the\n    /// GPU timestamp is ready, call [`GpuContext::upload_gpu_timestamp()`] to upload it to Tracy.\n    ///\n    /// This should be called right next to where you record the corresponding GPU timestamp. This\n    /// allows tracy to correctly associate the cpu time with the gpu timestamp.\n    pub fn begin_span(&self, span_location: &'static SpanLocation, query_id: u16) {\n        #[cfg(feature = \"enable\")]\n        // SAFETY: We know that the span location is valid forever as it is 'static. `usize` will\n        // always be smaller than u64, so no data will be lost.\n        unsafe {\n            sys::___tracy_emit_gpu_zone_begin_serial(sys::___tracy_gpu_zone_begin_data {\n                srcloc: std::ptr::addr_of!(span_location.data) as usize as u64,\n                queryId: query_id,\n                context: self.value,\n            });\n        };\n    }\n\n    /// Begins a new manually tracked GPU span with the given name, function, file, and line.\n    ///\n    /// You can use this instead of [`GpuContext::span()`] if you'd like to track the GPU span\n    /// manually.\n    ///\n    /// `query_id` is the id of the GPU timestamp query that you had created; when the GPU\n    /// timestamp is ready, call [`GpuContext::upload_gpu_timestamp()`] to upload it to Tracy.\n    ///\n    /// This should be called right next to where you record the corresponding GPU timestamp. This\n    /// allows tracy to correctly associate the cpu time with the gpu timestamp.\n    pub fn begin_span_alloc(\n        &self,\n        name: &str,\n        function: &str,\n        file: &str,\n        line: u32,\n        query_id: u16,\n    ) {\n        #[cfg(feature = \"enable\")]\n        {\n            let srcloc = unsafe {\n                sys::___tracy_alloc_srcloc_name(\n                    line,\n                    file.as_ptr().cast(),\n                    file.len(),\n                    function.as_ptr().cast(),\n                    function.len(),\n                    name.as_ptr().cast(),\n                    name.len(),\n                    0,\n                )\n            };\n\n            unsafe {\n                sys::___tracy_emit_gpu_zone_begin_alloc_serial(sys::___tracy_gpu_zone_begin_data {\n                    srcloc,\n                    queryId: query_id,\n                    context: self.value,\n                });\n            };\n        }\n    }\n\n    /// Ends a manually tracked GPU span.\n    ///\n    /// Call this to end a span started with [`GpuContext::begin_span()`] or\n    /// [`GpuContext::begin_span_alloc()`].\n    ///\n    /// `query_id` is the id of the GPU timestamp query that you had created; when the\n    /// GPU timestamp is ready, call [`GpuContext::upload_gpu_timestamp()`] to upload it to Tracy.\n    ///\n    /// This should be called right next to where you record the corresponding GPU timestamp. This\n    /// allows tracy to correctly associate the cpu time with the gpu timestamp.\n    pub fn end_span(&self, query_id: u16) {\n        #[cfg(feature = \"enable\")]\n        unsafe {\n            sys::___tracy_emit_gpu_zone_end_serial(sys::___tracy_gpu_zone_end_data {\n                queryId: query_id,\n                context: self.value,\n            });\n        };\n    }\n\n    /// Uploads a GPU timestamp for a manually tracked span.\n    ///\n    /// Call this to upload the ready GPU timestamp for a query corresponding to `query_id`.\n    pub fn upload_gpu_timestamp(&self, query_id: u16, gpu_timestamp: i64) {\n        #[cfg(feature = \"enable\")]\n        unsafe {\n            sys::___tracy_emit_gpu_time_serial(sys::___tracy_gpu_time_data {\n                gpuTime: gpu_timestamp,\n                queryId: query_id,\n                context: self.value,\n            });\n        };\n    }\n\n    /// Communicates the current GPU timestamp to Tracy.\n    ///\n    /// Some GPUs (like AMD) will aggressively reset their timing when going into lower power\n    /// states. If your application does not continuously utilize the GPU, this will cause Tracy's\n    /// synchronization of CPU and GPU timestamps to immediately go out of sync, resulting in\n    /// broken GPU span display.\n    ///\n    /// You can use this method to resynchronize CPU and GPU timestamps. Fetch the current GPU\n    /// timestamp, then immediately call this method. It will synchronize the given `gpu_timestamp`\n    /// to the CPU timestamp at the time of this call.\n    pub fn sync_gpu_time(&self, gpu_timestamp: i64) {\n        #[cfg(feature = \"enable\")]\n        unsafe {\n            sys::___tracy_emit_gpu_time_sync_serial(sys::___tracy_gpu_time_sync_data {\n                gpuTime: gpu_timestamp,\n                context: self.value,\n            });\n        };\n    }\n}\n\nimpl GpuSpan {\n    /// Marks the end of the given gpu span. This should be called right next to where you record\n    /// the corresponding gpu timestamp for the end of the span. This allows tracy to correctly\n    /// associate the cpu time with the gpu timestamp.\n    ///\n    /// Only the first time you call this function will it actually emit a gpu zone end event. Any\n    /// subsequent calls will be ignored.\n    pub fn end_zone(&mut self) {\n        #[cfg(feature = \"enable\")]\n        {\n            if self.state != GpuSpanState::Started {\n                return;\n            }\n            unsafe {\n                sys::___tracy_emit_gpu_zone_end_serial(sys::___tracy_gpu_zone_end_data {\n                    queryId: self.end_query_id,\n                    context: self.context.value,\n                });\n            };\n            self.state = GpuSpanState::Ended;\n        }\n    }\n\n    /// Supplies the GPU timestamp for the start of this span.\n    ///\n    /// In order to avoid confusing Tracy, you must call\n    /// [`Self::upload_timestamp_start`] and [`Self::upload_timestamp_end`] in\n    /// monotonically increasing timestamp order. For example, if you have two\n    /// nested spans *outer* and *inner*, you must supply the timestamps in\n    /// this order: (1) *outer* start; (2) *inner* start; (3) *inner* end; (4)\n    /// *outer* end.\n    pub fn upload_timestamp_start(&self, start_timestamp: i64) {\n        #[cfg(feature = \"enable\")]\n        unsafe {\n            sys::___tracy_emit_gpu_time_serial(sys::___tracy_gpu_time_data {\n                gpuTime: start_timestamp,\n                queryId: self.start_query_id,\n                context: self.context.value,\n            });\n        };\n    }\n\n    /// Supplies the GPU timestamp for the end of this span.\n    ///\n    /// In order to avoid confusing Tracy, you must call\n    /// [`Self::upload_timestamp_start`] and [`Self::upload_timestamp_end`] in\n    /// monotonically increasing timestamp order. For example, if you have two\n    /// nested spans *outer* and *inner*, you must supply the timestamps in this\n    /// order: (1) *outer* start; (2) *inner* start; (3) *inner* end; (4)\n    /// *outer* end.\n    pub fn upload_timestamp_end(&self, end_timestamp: i64) {\n        #[cfg(feature = \"enable\")]\n        unsafe {\n            sys::___tracy_emit_gpu_time_serial(sys::___tracy_gpu_time_data {\n                gpuTime: end_timestamp,\n                queryId: self.end_query_id,\n                context: self.context.value,\n            });\n        };\n    }\n}\n\nimpl Drop for GpuSpan {\n    fn drop(&mut self) {\n        #[cfg(feature = \"enable\")]\n        {\n            match self.state {\n                GpuSpanState::Started => {\n                    self.end_zone();\n                }\n                GpuSpanState::Ended => {}\n            }\n\n            // Put the ids back into the freelist.\n            let mut freelist = self.context.span_freelist.lock().unwrap();\n            freelist.push(self.start_query_id);\n            freelist.push(self.end_query_id);\n            drop(freelist);\n        }\n    }\n}\n"
  },
  {
    "path": "tracy-client/src/lib.rs",
    "content": "#![deny(unsafe_op_in_unsafe_fn, missing_docs)]\n#![cfg_attr(\n    not(feature = \"enable\"),\n    allow(unused_variables, unused_imports, unused_mut, dead_code)\n)]\n// TODO https://github.com/rust-lang/rust-clippy/issues/12017\n#![allow(clippy::let_unit_value)]\n//! This crate is a set of safe bindings to the client library of the [Tracy profiler].\n//!\n//! If you have already instrumented your application with `tracing`, consider the `tracing-tracy`\n//! crate.\n//!\n//! [Tracy profiler]: https://github.com/wolfpld/tracy\n//!\n//! # Important note\n//!\n//! Depending on the configuration Tracy may broadcast discovery packets to the local network and\n//! expose the data it collects in the background to that same network. Traces collected by Tracy\n//! may include source and assembly code as well.\n//!\n//! As thus, you may want make sure to only enable the `tracy-client` crate conditionally, via\n//! the `enable` feature flag provided by this crate.\n//!\n//! # Features\n//!\n//! The following crate features are provided to customize the functionality of the Tracy client:\n//!\n#![doc = include_str!(\"../FEATURES.mkd\")]\n\npub use crate::frame::{frame_image, frame_mark, Frame, FrameName};\npub use crate::gpu::{\n    GpuContext, GpuContextCreationError, GpuContextType, GpuSpan, GpuSpanCreationError,\n};\npub use crate::plot::{PlotConfiguration, PlotFormat, PlotLineStyle, PlotName};\npub use crate::span::{Span, SpanLocation};\nuse std::alloc;\nuse std::ffi::CString;\npub use sys;\n\nmod frame;\nmod gpu;\nmod plot;\nmod span;\nmod state;\n\n#[cfg(feature = \"demangle\")]\npub mod demangle;\n\n/// /!\\ /!\\ Please don't rely on anything in this module T_T /!\\ /!\\\n#[doc(hidden)]\npub mod internal {\n    pub use crate::{span::SpanLocation, sys};\n    pub use once_cell::sync::Lazy;\n    pub use std::any::type_name;\n    use std::ffi::CString;\n    pub use std::ptr::null;\n\n    #[cfg(feature = \"demangle\")]\n    pub mod demangle {\n        pub use crate::demangle::{default, internal::implementation};\n    }\n\n    #[inline(always)]\n    #[must_use]\n    pub fn make_span_location(\n        type_name: &'static str,\n        span_name: *const u8,\n        file: *const u8,\n        line: u32,\n    ) -> SpanLocation {\n        #[cfg(feature = \"enable\")]\n        {\n            let function_name = CString::new(&type_name[..type_name.len() - 3]).unwrap();\n            SpanLocation {\n                data: sys::___tracy_source_location_data {\n                    name: span_name.cast(),\n                    function: function_name.as_ptr(),\n                    file: file.cast(),\n                    line,\n                    color: 0,\n                },\n                _function_name: function_name,\n            }\n        }\n        #[cfg(not(feature = \"enable\"))]\n        crate::SpanLocation { _internal: () }\n    }\n\n    #[inline(always)]\n    #[must_use]\n    pub const unsafe fn create_frame_name(name: &'static str) -> crate::frame::FrameName {\n        crate::frame::FrameName(name)\n    }\n\n    #[inline(always)]\n    #[must_use]\n    pub const unsafe fn create_plot(name: &'static str) -> crate::plot::PlotName {\n        crate::plot::PlotName(name)\n    }\n\n    /// Safety: `name` must be null-terminated, and a `Client` must be enabled\n    #[inline(always)]\n    pub unsafe fn set_thread_name(name: *const u8) {\n        #[cfg(feature = \"enable\")]\n        unsafe {\n            let () = sys::___tracy_set_thread_name(name.cast());\n        }\n    }\n}\n\n/// A type representing an enabled Tracy client.\n///\n/// Obtaining a `Client` is required in order to instrument the application.\n///\n/// Multiple copies of a Client may be live at once. As long as at least one `Client` value lives,\n/// the `Tracy` client is enabled globally. In addition to collecting information through the\n/// instrumentation inserted by you, the Tracy client may automatically collect information about\n/// execution of the program while it is enabled. All this information may be stored in memory\n/// until a profiler application connects to the client to read the data.\n///\n/// Depending on the build configuration, the client may collect and make available machine\n/// and source code of the application as well as other potentially sensitive information.\n///\n/// When all of the `Client` values are dropped, the underlying Tracy client will be shut down as\n/// well. Shutting down the `Client` will discard any information gathered up to that point that\n/// still hasn't been delivered to the profiler application.\npub struct Client(());\n\n/// Instrumentation methods for outputting events occurring at a specific instant.\n///\n/// Data provided by this instrumentation can largely be considered to be equivalent to logs.\nimpl Client {\n    /// Output a message.\n    ///\n    /// Specifying a non-zero `callstack_depth` will enable collection of callstack for this\n    /// message. The number provided will limit the number of call frames collected. Note that\n    /// enabling callstack collection introduces a non-trivial amount of overhead to this call.\n    pub fn message(&self, message: &str, callstack_depth: u16) {\n        #[cfg(feature = \"enable\")]\n        unsafe {\n            let stack_depth = adjust_stack_depth(callstack_depth).into();\n            let () =\n                sys::___tracy_emit_message(message.as_ptr().cast(), message.len(), stack_depth);\n        }\n    }\n\n    /// Output a message with an associated color.\n    ///\n    /// Specifying a non-zero `callstack_depth` will enable collection of callstack for this\n    /// message. The number provided will limit the number of call frames collected. Note that\n    /// enabling callstack collection introduces a non-trivial amount of overhead to this call.\n    ///\n    /// The colour shall be provided as RGBA, where the least significant 8 bits represent the alpha\n    /// component and most significant 8 bits represent the red component.\n    pub fn color_message(&self, message: &str, rgba: u32, callstack_depth: u16) {\n        #[cfg(feature = \"enable\")]\n        unsafe {\n            let depth = adjust_stack_depth(callstack_depth).into();\n            let () = sys::___tracy_emit_messageC(\n                message.as_ptr().cast(),\n                message.len(),\n                rgba >> 8,\n                depth,\n            );\n        }\n    }\n}\n\nimpl Client {\n    /// Set the current thread name to the provided value.\n    ///\n    /// # Panics\n    ///\n    /// This function will panic if the name contains interior null characters.\n    pub fn set_thread_name(&self, name: &str) {\n        #[cfg(feature = \"enable\")]\n        unsafe {\n            let name = CString::new(name).unwrap();\n            // SAFE: `name` is a valid null-terminated string.\n            internal::set_thread_name(name.as_ptr().cast());\n        }\n    }\n}\n\n/// Convenience macro for [`Client::set_thread_name`] on the current client.\n///\n/// Note that any interior null characters terminate the name early. This is not checked for.\n///\n/// # Panics\n///\n/// - If a `Client` isn't currently running.\n#[macro_export]\nmacro_rules! set_thread_name {\n    ($name: literal) => {{\n        $crate::Client::running().expect(\"set_thread_name! without a running Client\");\n        unsafe {\n            // SAFE: `name` is a valid null-terminated string.\n            $crate::internal::set_thread_name(concat!($name, \"\\0\").as_ptr().cast())\n        }\n    }};\n}\n\n/// A profiling wrapper around another allocator.\n///\n/// See documentation for [`std::alloc`] for more information about global allocators.\n///\n/// Note that this wrapper will start up the client on the first allocation, if not enabled\n/// already.\n///\n/// # Examples\n///\n/// In your executable, add:\n///\n/// ```rust\n/// # use tracy_client::*;\n/// #[global_allocator]\n/// static GLOBAL: ProfiledAllocator<std::alloc::System> =\n///     ProfiledAllocator::new(std::alloc::System, 100);\n/// ```\npub struct ProfiledAllocator<T>(T, u16);\n\nimpl<T> ProfiledAllocator<T> {\n    /// Construct a new `ProfiledAllocator`.\n    ///\n    /// Specifying a non-zero `callstack_depth` will enable collection of callstack for this\n    /// message. The number provided will limit the number of call frames collected. Note that\n    /// enabling callstack collection introduces a non-trivial amount of overhead to each\n    /// allocation and deallocation.\n    pub const fn new(inner_allocator: T, callstack_depth: u16) -> Self {\n        Self(inner_allocator, adjust_stack_depth(callstack_depth))\n    }\n\n    fn emit_alloc(&self, ptr: *mut u8, size: usize) {\n        #[cfg(feature = \"enable\")]\n        unsafe {\n            Client::start();\n            if self.1 == 0 {\n                let () = sys::___tracy_emit_memory_alloc(ptr.cast(), size, 1);\n            } else {\n                let () =\n                    sys::___tracy_emit_memory_alloc_callstack(ptr.cast(), size, self.1.into(), 1);\n            }\n        }\n    }\n\n    fn emit_free(&self, ptr: *mut u8) {\n        #[cfg(feature = \"enable\")]\n        unsafe {\n            if self.1 == 0 {\n                let () = sys::___tracy_emit_memory_free(ptr.cast(), 1);\n            } else {\n                let () = sys::___tracy_emit_memory_free_callstack(ptr.cast(), self.1.into(), 1);\n            }\n        }\n    }\n}\n\nunsafe impl<T: alloc::GlobalAlloc> alloc::GlobalAlloc for ProfiledAllocator<T> {\n    unsafe fn alloc(&self, layout: alloc::Layout) -> *mut u8 {\n        let alloc = unsafe {\n            // SAFE: all invariants satisfied by the caller.\n            self.0.alloc(layout)\n        };\n        self.emit_alloc(alloc, layout.size());\n        alloc\n    }\n\n    unsafe fn dealloc(&self, ptr: *mut u8, layout: alloc::Layout) {\n        self.emit_free(ptr);\n        unsafe {\n            // SAFE: all invariants satisfied by the caller.\n            self.0.dealloc(ptr, layout);\n        }\n    }\n\n    unsafe fn alloc_zeroed(&self, layout: alloc::Layout) -> *mut u8 {\n        let alloc = unsafe {\n            // SAFE: all invariants satisfied by the caller.\n            self.0.alloc_zeroed(layout)\n        };\n        self.emit_alloc(alloc, layout.size());\n        alloc\n    }\n\n    unsafe fn realloc(&self, ptr: *mut u8, layout: alloc::Layout, new_size: usize) -> *mut u8 {\n        self.emit_free(ptr);\n        let alloc = unsafe {\n            // SAFE: all invariants satisfied by the caller.\n            self.0.realloc(ptr, layout, new_size)\n        };\n        self.emit_alloc(alloc, new_size);\n        alloc\n    }\n}\n\n/// Clamp the stack depth to the maximum supported by Tracy.\npub(crate) const fn adjust_stack_depth(depth: u16) -> u16 {\n    #[cfg(windows)]\n    {\n        62 ^ ((depth ^ 62) & 0u16.wrapping_sub((depth < 62) as _))\n    }\n    #[cfg(not(windows))]\n    {\n        depth\n    }\n}\n"
  },
  {
    "path": "tracy-client/src/plot.rs",
    "content": "use crate::Client;\n\n/// Name of a plot.\n///\n/// Create with the [`plot_name!`](crate::plot_name) macro.\n#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]\npub struct PlotName(pub(crate) &'static str);\n\n/// The format of a plot to be shown in the Tracy profiler UI.\n#[derive(Debug, Hash, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Default)]\n#[non_exhaustive]\npub enum PlotFormat {\n    /// Values will be displayed as plain numbers. This is the default.\n    #[default]\n    Number,\n\n    /// Values will be displayed as byte counts, showing as kilobytes, megabytes, etc.\n    Memory,\n\n    /// Values will be shown as a percentage (with 100 being equal to 100%).\n    Percentage,\n\n    /// Values will be shown as watts.\n    Watts,\n}\n\n/// The style of lines of a plot, shown in the Tracy profiler UI.\n#[derive(Debug, Hash, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Default)]\n#[non_exhaustive]\npub enum PlotLineStyle {\n    /// Lines will be stepped (ie look like a staircase).\n    Stepped,\n\n    /// Lines will be smooth (interpolating a line between two values).\n    #[default]\n    Smooth,\n}\n\n/// Configuration for how a plot appears in the Tracy profiling UI.\n///\n/// # Examples\n///\n/// ```\n/// # use tracy_client::PlotConfiguration;\n/// // Create a red plot line.\n/// let configuration = PlotConfiguration::default().fill(false).color(Some(0xFF0000));\n/// ```\n#[derive(Clone, PartialEq, Debug)]\npub struct PlotConfiguration {\n    /// The format of values on the plot.\n    format: PlotFormat,\n\n    /// The style of lines on the plot.\n    line_style: PlotLineStyle,\n\n    /// Whether the plot should be filled with a solid color below the line.\n    fill: bool,\n\n    /// A custom color of this plot. None means a default color will be generated by Tracy.\n    color: Option<u32>,\n}\n\nimpl PlotConfiguration {\n    /// Sets the format of values on the plot.\n    pub fn format(mut self, format: PlotFormat) -> Self {\n        self.format = format;\n        self\n    }\n\n    /// Sets the style of lines on the plot.\n    pub fn line_style(mut self, line_style: PlotLineStyle) -> Self {\n        self.line_style = line_style;\n        self\n    }\n\n    /// Sets whether the plot should be filled with a solid color below the line.\n    pub fn fill(mut self, fill: bool) -> Self {\n        self.fill = fill;\n        self\n    }\n\n    /// Sets a custom color of the plot. A value of `None` will cause Tracy to create its own color.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// # use tracy_client::PlotConfiguration;\n    /// // Configure the plot to be red.\n    /// let red = PlotConfiguration::default().color(Some(0xFF0000));\n    /// // Configure the plot to be green.\n    /// let green = PlotConfiguration::default().color(Some(0x00FF00));\n    /// // Configure the plot to be blue.\n    /// let blue = PlotConfiguration::default().color(Some(0x0000FF));\n    /// ```\n    pub fn color(mut self, color: Option<u32>) -> Self {\n        self.color = color;\n        self\n    }\n}\n\nimpl Default for PlotConfiguration {\n    fn default() -> Self {\n        Self {\n            format: Default::default(),\n            line_style: Default::default(),\n            fill: true,\n            color: None,\n        }\n    }\n}\n\nimpl PlotName {\n    /// Construct a `PlotName` dynamically, leaking the provided String.\n    ///\n    /// You should call this function once for a given name, and store the returned `PlotName` for\n    /// continued use, to avoid rapid memory use growth. Whenever possible, prefer the\n    /// [`plot_name!`](crate::plot_name) macro, which takes a literal name and doesn't leak memory.\n    ///\n    /// The resulting value may be used as an argument for the the [`Client::secondary_frame_mark`]\n    /// and [`Client::non_continuous_frame`] methods.\n    #[must_use]\n    pub fn new_leak(name: String) -> Self {\n        #[cfg(feature = \"enable\")]\n        {\n            // Ensure the name is null-terminated.\n            let mut name = name;\n            name.push('\\0');\n            // Drop excess capacity by converting into a boxed str, then leak.\n            let name = Box::leak(name.into_boxed_str());\n            Self(name)\n        }\n        #[cfg(not(feature = \"enable\"))]\n        {\n            drop(name);\n            Self(\"\\0\")\n        }\n    }\n}\n\n/// Instrumentation for drawing 2D plots.\nimpl Client {\n    /// Add a point with an y-axis value of `value` to the plot named `plot_name`.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// # let client = tracy_client::Client::start();\n    /// tracy_client::Client::running()\n    ///     .expect(\"client must be running\")\n    ///     .plot(tracy_client::plot_name!(\"temperature\"), 37.0);\n    /// ```\n    pub fn plot(&self, plot_name: PlotName, value: f64) {\n        #[cfg(feature = \"enable\")]\n        unsafe {\n            // SAFE: We made sure the `plot` refers to a null-terminated string.\n            let () = sys::___tracy_emit_plot(plot_name.0.as_ptr().cast(), value);\n        }\n    }\n\n    /// Sets the display configuration of the plot named `plot_name`.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use tracy_client::{PlotConfiguration, PlotFormat};\n    /// # let client = tracy_client::Client::start();\n    /// tracy_client::Client::running()\n    ///     .expect(\"client must be running\")\n    ///     .plot_config(tracy_client::plot_name!(\"memory\"), PlotConfiguration::default().format(PlotFormat::Memory));\n    /// ```\n    pub fn plot_config(&self, plot_name: PlotName, configuration: PlotConfiguration) {\n        #[cfg(feature = \"enable\")]\n        {\n            let format = match configuration.format {\n                PlotFormat::Number => sys::TracyPlotFormatEnum_TracyPlotFormatNumber,\n                PlotFormat::Memory => sys::TracyPlotFormatEnum_TracyPlotFormatMemory,\n                PlotFormat::Percentage => sys::TracyPlotFormatEnum_TracyPlotFormatPercentage,\n                PlotFormat::Watts => sys::TracyPlotFormatEnum_TracyPlotFormatWatt,\n            } as std::os::raw::c_int;\n            let stepped = configuration.line_style == PlotLineStyle::Stepped;\n            let filled = configuration.fill;\n            let color = configuration.color.unwrap_or(0);\n            unsafe {\n                // SAFE: We made sure the `plot` refers to a null-terminated string.\n                let () = sys::___tracy_emit_plot_config(\n                    plot_name.0.as_ptr().cast(),\n                    format,\n                    stepped.into(),\n                    filled.into(),\n                    color,\n                );\n            }\n        }\n    }\n}\n\n/// Construct a [`PlotName`].\n///\n/// The resulting value may be used as an argument for the [`Client::plot`] method. The macro can\n/// be used in a `const` context.\n#[macro_export]\nmacro_rules! plot_name {\n    ($name: expr) => {\n        unsafe { $crate::internal::create_plot(concat!($name, \"\\0\")) }\n    };\n}\n\n/// Convenience macro for [`Client::plot`] on the current client.\n///\n/// # Panics\n///\n/// - If a `Client` isn't currently running.\n#[macro_export]\nmacro_rules! plot {\n    ($name: expr, $value: expr) => {{\n        $crate::Client::running()\n            .expect(\"plot! without a running Client\")\n            .plot($crate::plot_name!($name), $value)\n    }};\n}\n"
  },
  {
    "path": "tracy-client/src/span.rs",
    "content": "use crate::{adjust_stack_depth, Client};\nuse std::ffi::CString;\n\n/// A handle representing a span of execution.\n///\n/// The trace span will be ended when this type is dropped.\npub struct Span {\n    #[cfg(feature = \"enable\")]\n    client: Client,\n    #[cfg(feature = \"enable\")]\n    zone: sys::___tracy_c_zone_context,\n    #[cfg(feature = \"enable\")]\n    _no_send_sync: std::marker::PhantomData<*mut sys::___tracy_c_zone_context>,\n    #[cfg(not(feature = \"enable\"))]\n    _no_send_sync: std::marker::PhantomData<*mut ()>,\n}\n\n/// A statically allocated location information for a span.\n///\n/// Construct with the [`span_location!`](crate::span_location) macro.\npub struct SpanLocation {\n    #[cfg(feature = \"enable\")]\n    pub(crate) _function_name: CString,\n    #[cfg(feature = \"enable\")]\n    pub(crate) data: sys::___tracy_source_location_data,\n    #[cfg(not(feature = \"enable\"))]\n    pub(crate) _internal: (),\n}\n\nunsafe impl Send for SpanLocation {}\nunsafe impl Sync for SpanLocation {}\n\n/// Instrumentation for timed regions, spans or zones of execution.\nimpl Client {\n    /// Start a new Tracy span/zone.\n    ///\n    /// In order to obtain a [`SpanLocation`] value to provide to this function use the\n    /// [`span_location!`](crate::span_location) macro.\n    ///\n    /// Specifying a non-zero `callstack_depth` will enable collection of callstack for this\n    /// message. The number provided will limit the number of call frames collected. Note that\n    /// enabling callstack collection introduces a non-trivial amount of overhead to this call. On\n    /// some systems this value may be clamped to a maximum value supported by the target.\n    ///\n    /// The [`span!`](crate::span!) macro is a convenience wrapper over this method.\n    ///\n    /// # Example\n    ///\n    /// In the following example the span is created with the location at which the\n    /// `span_location!` macro appears and will measure the execution of the 100ms long sleep.\n    ///\n    /// ```rust\n    /// use tracy_client::{Client, span_location};\n    /// let client = Client::start();\n    /// {\n    ///     let _span = client.span(span_location!(\"sleeping\"), 100);\n    ///     std::thread::sleep(std::time::Duration::from_millis(100));\n    /// } // _span ends\n    /// ```\n    #[inline]\n    #[must_use]\n    pub fn span(self, loc: &'static SpanLocation, callstack_depth: u16) -> Span {\n        #[cfg(feature = \"enable\")]\n        unsafe {\n            let zone = if callstack_depth == 0 {\n                sys::___tracy_emit_zone_begin(&loc.data, 1)\n            } else {\n                let stack_depth = adjust_stack_depth(callstack_depth).into();\n                sys::___tracy_emit_zone_begin_callstack(&loc.data, stack_depth, 1)\n            };\n            Span {\n                client: self,\n                zone,\n                _no_send_sync: std::marker::PhantomData,\n            }\n        }\n        #[cfg(not(feature = \"enable\"))]\n        Span {\n            _no_send_sync: std::marker::PhantomData,\n        }\n    }\n\n    /// Start a new Tracy span/zone.\n    ///\n    /// This function allocates the span information on the heap until it is read out by the\n    /// profiler. Prefer the [`Client::span`] as a allocation-free and faster alternative when\n    /// possible.\n    ///\n    /// Specifying a non-zero `callstack_depth` will enable collection of callstack for this\n    /// message. The number provided will limit the number of call frames collected. Note that\n    /// enabling callstack collection introduces a non-trivial amount of overhead to this call. On\n    /// some systems this value may be clamped to a maximum value supported by the target.\n    ///\n    /// # Example\n    ///\n    /// In the following example the span is created with custom span source data and will measure\n    /// the execution of the 100ms long sleep.\n    ///\n    /// ```rust\n    /// use tracy_client::Client;\n    /// let client = Client::start();\n    /// {\n    ///     let _span = client.span_alloc(Some(\"hello\"), \"my_function\", \"hello.rs\", 42, 100);\n    ///     std::thread::sleep(std::time::Duration::from_millis(100));\n    /// } // _span ends\n    /// ```\n    #[inline]\n    #[must_use]\n    pub fn span_alloc(\n        self,\n        name: Option<&str>,\n        function: &str,\n        file: &str,\n        line: u32,\n        callstack_depth: u16,\n    ) -> Span {\n        #[cfg(feature = \"enable\")]\n        unsafe {\n            let loc = sys::___tracy_alloc_srcloc_name(\n                line,\n                file.as_ptr().cast(),\n                file.len(),\n                function.as_ptr().cast(),\n                function.len(),\n                name.map_or(std::ptr::null(), |n| n.as_ptr().cast()),\n                name.unwrap_or(\"\").len(),\n                0,\n            );\n            let zone = if callstack_depth == 0 {\n                sys::___tracy_emit_zone_begin_alloc(loc, 1)\n            } else {\n                let stack_depth = adjust_stack_depth(callstack_depth).into();\n                sys::___tracy_emit_zone_begin_alloc_callstack(loc, stack_depth, 1)\n            };\n            Span {\n                client: self,\n                zone,\n                _no_send_sync: std::marker::PhantomData,\n            }\n        }\n        #[cfg(not(feature = \"enable\"))]\n        Span {\n            _no_send_sync: std::marker::PhantomData,\n        }\n    }\n}\n\nimpl Span {\n    /// Emit a numeric value associated with this span.\n    pub fn emit_value(&self, value: u64) {\n        #[cfg(feature = \"enable\")]\n        unsafe {\n            // SAFE: the only way to construct `Span` is by creating a valid tracy zone context.\n            let () = sys::___tracy_emit_zone_value(self.zone, value);\n        }\n    }\n\n    /// Emit some text associated with this span.\n    pub fn emit_text(&self, text: &str) {\n        #[cfg(feature = \"enable\")]\n        unsafe {\n            // SAFE: the only way to construct `Span` is by creating a valid tracy zone context.\n            let () = sys::___tracy_emit_zone_text(self.zone, text.as_ptr().cast(), text.len());\n        }\n    }\n\n    /// Emit a color associated with this span.\n    ///\n    /// The color is specified as RGB. It is most straightforward to specify them as hex literals\n    /// such as `0xFF0000` for red, `0x00FF00` for green or `0x0000FF` for blue.\n    pub fn emit_color(&self, color: u32) {\n        #[cfg(feature = \"enable\")]\n        unsafe {\n            // SAFE: the only way to construct `Span` is by creating a valid tracy zone context.\n            // TODO: verify if we need to shift by 8 or not...?\n            let () = sys::___tracy_emit_zone_color(self.zone, color);\n        }\n    }\n}\n\nimpl Drop for Span {\n    fn drop(&mut self) {\n        #[cfg(feature = \"enable\")]\n        unsafe {\n            // SAFE: The only way to construct `Span` is by creating a valid tracy zone context. We\n            // also still have an owned Client handle.\n            let () = sys::___tracy_emit_zone_end(self.zone);\n            std::convert::identity(&self.client);\n        }\n    }\n}\n\n/// Construct a <code>&'static [SpanLocation]</code>.\n///\n/// The returned `SpanLocation` is allocated statically and is cached between invocations. This\n/// `SpanLocation` will refer to the file and line at which this macro has been invoked, as well as\n/// to the item containing this macro invocation.\n///\n/// The resulting value may be used as an argument for the [`Client::span`] method.\n///\n/// # Example\n///\n/// ```rust\n/// let location: &'static tracy_client::SpanLocation = tracy_client::span_location!(\"some name\");\n/// ```\n#[macro_export]\nmacro_rules! span_location {\n    () => {{\n        struct S;\n        // String processing in `const` when, Oli?\n        static LOC: $crate::internal::Lazy<$crate::internal::SpanLocation> =\n            $crate::internal::Lazy::new(|| {\n                $crate::internal::make_span_location(\n                    $crate::internal::type_name::<S>(),\n                    $crate::internal::null(),\n                    concat!(file!(), \"\\0\").as_ptr(),\n                    line!(),\n                )\n            });\n        &*LOC\n    }};\n    ($name: expr) => {{\n        struct S;\n        // String processing in `const` when, Oli?\n        static LOC: $crate::internal::Lazy<$crate::internal::SpanLocation> =\n            $crate::internal::Lazy::new(|| {\n                $crate::internal::make_span_location(\n                    $crate::internal::type_name::<S>(),\n                    concat!($name, \"\\0\").as_ptr(),\n                    concat!(file!(), \"\\0\").as_ptr(),\n                    line!(),\n                )\n            });\n        &*LOC\n    }};\n}\n\n/// Start a new Tracy span with function, file, and line determined automatically.\n///\n/// # Panics\n///\n/// `span!` will panic if the Client isn't running at the time this macro is invoked.\n///\n/// # Examples\n///\n/// Begin a span region, which will be terminated once `_span` goes out of scope:\n///\n/// ```\n/// use tracy_client::{Client, span};\n/// # let _client = tracy_client::Client::start();\n/// let _span = span!(\"some span\");\n/// ```\n///\n/// It is also possible to enable collection of the callstack by specifying a limit of call stack\n/// frames to record:\n///\n/// ```\n/// use tracy_client::span;\n/// # let _client = tracy_client::Client::start();\n/// let _span = span!(\"some span\", 32);\n/// ```\n///\n/// Note, however, that collecting callstack introduces a non-trivial overhead at the point of\n/// instrumentation.\n#[macro_export]\nmacro_rules! span {\n    () => {\n        $crate::Client::running()\n            .expect(\"span! without a running Client\")\n            .span($crate::span_location!(), 0)\n    };\n    ($name: expr) => {\n        $crate::span!($name, 0)\n    };\n    ($name: expr, $callstack_depth: expr) => {{\n        let location = $crate::span_location!($name);\n        $crate::Client::running()\n            .expect(\"span! without a running Client\")\n            .span(location, $callstack_depth)\n    }};\n}\n"
  },
  {
    "path": "tracy-client/src/state.rs",
    "content": "use crate::Client;\n\n/// Client initialization and lifetime management.\nimpl Client {\n    /// Start the client.\n    ///\n    /// The client must be started with this function before any instrumentation is invoked\n    /// anywhere in the process. This function can be called multiple times to obtain multiple\n    /// `Client` values.\n    ///\n    /// The underlying client implementation will be started up only if it wasn't already running\n    /// yet.\n    ///\n    /// Note that when the `manual-lifetime` feature is used, it is a responsibility of the user\n    /// to stop `tracy` using the [`sys::___tracy_shutdown_profiler`] function. Keep in mind that\n    /// at the time this function is called there can be no other invocations to the tracy\n    /// profiler, even from other threads (or you may get a crash!)\n    ///\n    /// # Example\n    ///\n    /// ```rust\n    /// // fn main() {\n    ///     let _client = tracy_client::Client::start();\n    ///     // ...\n    /// // }\n    /// ```\n    pub fn start() -> Self {\n        #[cfg(not(feature = \"enable\"))]\n        return Self(());\n        #[cfg(all(feature = \"enable\", feature = \"manual-lifetime\"))]\n        return manual_lifetime::start();\n        #[cfg(all(feature = \"enable\", not(feature = \"manual-lifetime\")))]\n        return Self(());\n    }\n\n    /// Obtain a client handle, but only if the client is already running.\n    #[must_use]\n    pub fn running() -> Option<Self> {\n        if Self::is_running() {\n            Some(Self(()))\n        } else {\n            None\n        }\n    }\n\n    /// Is the client already running?\n    pub fn is_running() -> bool {\n        #[cfg(not(feature = \"enable\"))]\n        return true; // If the client is disabled, produce a \"no-op\" one so that users don’t need\n                     // to wory about conditional use of the instrumentation in their own code.\n        #[cfg(all(feature = \"enable\", feature = \"manual-lifetime\"))]\n        return manual_lifetime::is_running();\n        #[cfg(all(feature = \"enable\", not(feature = \"manual-lifetime\")))]\n        return true; // The client is started in life-before-main (or upon first use in case of\n                     // `delayed-init`\n    }\n\n    /// Is the client running and a profiler connected?\n    pub fn is_connected() -> bool {\n        #[cfg(not(feature = \"enable\"))]\n        return false;\n        #[cfg(feature = \"enable\")]\n        return Self::is_running() && unsafe { sys::___tracy_connected() != 0 };\n    }\n}\n\nimpl Clone for Client {\n    /// A cheaper alternative to [`Client::start`] or [`Client::running`]  when there is already a\n    /// handle handy.\n    fn clone(&self) -> Self {\n        // We already know that the state is `ENABLED`, no need to check.\n        Self(())\n    }\n}\n\n#[cfg(all(feature = \"enable\", feature = \"manual-lifetime\"))]\nmod manual_lifetime {\n    use std::sync::atomic::Ordering;\n    /// Enabling `Tracy` when it is already enabled, or Disabling when it is already disabled will\n    /// cause applications to crash. I personally think it would be better if this was a sort-of\n    /// reference counted kind-of thing so you could enable as many times as you wish and disable\n    /// just as many times without any reprecursions. At the very least this could significantly\n    /// help tests.\n    ///\n    /// We can also try to implement something like this ourselves. To do this we'd want to track 4\n    /// states that construct a following finite state machine:\n    ///\n    /// ```text\n    ///     0 = disabled  -> 1 = enabling\n    ///         ^                v\n    ///     3 = disabling <- 2 = enabled\n    /// ```\n    ///\n    /// And also include a reference count somewhere in there. Something we can throw in a static\n    /// would be ideal.\n    ///\n    /// Alas, Tracy's extensive use of thread-local storage presents us with another problem – we must\n    /// start up and shut down the client within the same thread. A most straightforward soution for\n    /// that would be to run a separate thread that would be dedicated entirely to just starting up and\n    /// shutting down the profiler.\n    ///\n    /// All that seems like a major pain to implement, and so we’ll punt on disabling entirely until\n    /// somebody comes with a good use-case warranting that sort of complexity.\n    #[cfg(not(loom))]\n    static CLIENT_STATE: std::sync::atomic::AtomicUsize = std::sync::atomic::AtomicUsize::new(0);\n    #[cfg(loom)]\n    loom::lazy_static! {\n        static ref CLIENT_STATE: loom::sync::atomic::AtomicUsize =\n            loom::sync::atomic::AtomicUsize::new(0);\n    }\n\n    const STATE_STEP: usize = 1; // Move forward by 1 step in the FSM\n    const STATE_DISABLED: usize = 0;\n    const STATE_ENABLING: usize = STATE_DISABLED + STATE_STEP;\n    const STATE_ENABLED: usize = STATE_ENABLING + STATE_STEP;\n\n    #[inline(always)]\n    fn spin_loop() {\n        #[cfg(loom)]\n        loom::thread::yield_now();\n        #[cfg(not(loom))]\n        std::hint::spin_loop();\n    }\n\n    pub(super) fn start() -> super::Client {\n        let mut old_state = CLIENT_STATE.load(Ordering::Relaxed);\n        loop {\n            match old_state {\n                STATE_ENABLED => return super::Client(()),\n                STATE_ENABLING => {\n                    while !is_running() {\n                        spin_loop();\n                    }\n                    return super::Client(());\n                }\n                STATE_DISABLED => {\n                    let result = CLIENT_STATE.compare_exchange_weak(\n                        old_state,\n                        STATE_ENABLING,\n                        Ordering::Relaxed,\n                        Ordering::Relaxed,\n                    );\n                    if let Err(next_old_state) = result {\n                        old_state = next_old_state;\n                        continue;\n                    } else {\n                        unsafe {\n                            // SAFE: This function must not be called if the profiler has\n                            // already been enabled. While in practice calling this function\n                            // multiple times will only serve to trigger an assertion, we\n                            // cannot exactly rely on this, since it is an undocumented\n                            // behaviour and the upstream might very well just decide to invoke\n                            // UB instead. In the case there are multiple copies of\n                            // `tracy-client` this invariant is not actually maintained, but\n                            // otherwise this is sound due to the `ENABLE_STATE` that we\n                            // manage.\n                            //\n                            // TODO: we _could_ define `ENABLE_STATE` in the `-sys` crate...\n                            let () = sys::___tracy_startup_profiler();\n                            CLIENT_STATE.store(STATE_ENABLED, Ordering::Release);\n                            return super::Client(());\n                        }\n                    }\n                }\n                _ => unreachable!(),\n            }\n        }\n    }\n\n    pub(super) fn is_running() -> bool {\n        return CLIENT_STATE.load(Ordering::Relaxed) == STATE_ENABLED;\n    }\n\n    #[cfg(test)]\n    mod test {\n        use super::*;\n\n        #[test]\n        fn state_transitions() {\n            assert_eq!(0, STATE_DISABLED);\n            assert_eq!(STATE_DISABLED.wrapping_add(STATE_STEP), STATE_ENABLING);\n            assert_eq!(STATE_ENABLING.wrapping_add(STATE_STEP), STATE_ENABLED);\n        }\n    }\n}\n"
  },
  {
    "path": "tracy-client/tests/loom.rs",
    "content": "#[cfg(loom)]\nmod loom {\n\n    use loom::thread;\n    use tracy_client::Client;\n\n    fn model<F>(f: F)\n    where\n        F: Fn() + Sync + Send + 'static,\n    {\n        #[cfg(not(loom))]\n        {\n            f()\n        }\n        #[cfg(loom)]\n        {\n            let mut builder = loom::model::Builder::new();\n            builder.preemption_bound = Some(3);\n            builder.check(f)\n        }\n    }\n\n    fn main() {\n        model(|| {\n            let client = Client::start();\n            assert!(Client::is_running());\n            drop(client);\n            unsafe {\n                ___tracy_shutdown_profiler();\n            }\n        });\n\n        model(|| {\n            let t1 = thread::spawn(|| {\n                let client = Client::start();\n                assert!(Client::is_running());\n                drop(client);\n            });\n            let client = Client::start();\n            assert!(Client::is_running());\n            drop(client);\n            t1.join().unwrap();\n            unsafe {\n                ___tracy_shutdown_profiler();\n            }\n        });\n\n        model(|| {\n            let t1 = thread::spawn(move || {\n                let client = Client::start();\n                assert!(Client::is_running());\n                let client2 = client.clone();\n                assert!(Client::is_running());\n                drop(client);\n                assert!(Client::is_running());\n                drop(client2);\n            });\n            let client = Client::start();\n            assert!(Client::is_running());\n            let client2 = client.clone();\n            assert!(Client::is_running());\n            drop(client2);\n            assert!(Client::is_running());\n            drop(client);\n            t1.join().unwrap();\n            unsafe {\n                ___tracy_shutdown_profiler();\n            }\n        });\n    }\n}\n\nfn main() {\n    #[cfg(loom)]\n    loom::main();\n}\n"
  },
  {
    "path": "tracy-client/tests/tests.rs",
    "content": "use std::time::Duration;\n\nuse tracy_client::*;\n\n#[global_allocator]\nstatic GLOBAL: ProfiledAllocator<std::alloc::System> =\n    ProfiledAllocator::new(std::alloc::System, 100);\n\nfn basic_zone() {\n    let client = Client::start();\n    let span = client.span(span_location!(\"basic_zone\"), 100);\n    span.emit_value(42);\n    span.emit_text(\"some text\");\n    for i in 322..420 {\n        span.emit_value(i);\n    }\n}\n\nfn alloc_zone() {\n    let client = Client::start();\n    let span = client.span_alloc(Some(\"alloc_zone\"), \"alloc_zone\", file!(), line!(), 100);\n    span.emit_value(42);\n    span.emit_color(0x00FF0000);\n    span.emit_text(\"some text\");\n}\n\nfn finish_frameset() {\n    let client = Client::start();\n    for _ in 0..10 {\n        client.frame_mark();\n    }\n    frame_mark();\n}\n\nfn finish_secondary_frameset() {\n    let client = Client::start();\n    for _ in 0..5 {\n        client.secondary_frame_mark(frame_name!(\"secondary frame\"));\n    }\n    secondary_frame_mark!(\"secondary frame macro\");\n}\n\nfn non_continuous_frameset() {\n    const NON_CONTINUOUS: FrameName = frame_name!(\"non continuous\");\n    let client = Client::start();\n    let _ = client.non_continuous_frame(NON_CONTINUOUS);\n    let _ = non_continuous_frame!(\"non continuous macro\");\n}\n\nfn plot_something() {\n    static TEMPERATURE: PlotName = plot_name!(\"temperature\");\n    let client = Client::start();\n    for i in 0..10 {\n        client.plot(TEMPERATURE, f64::from(i));\n    }\n\n    plot!(\"temperature\", 42.0);\n}\n\nfn allocations() {\n    let mut strings = Vec::new();\n    for i in 0..100 {\n        strings.push(format!(\"{i:?}\"));\n    }\n}\n\nfn fib(i: u16) -> u64 {\n    let span = span!();\n    span.emit_text(&format!(\"fib({i})\"));\n    let result = match i {\n        0 => 0,\n        1 => 1,\n        _ => fib(i - 1) + fib(i - 2),\n    };\n    span.emit_value(result);\n    result\n}\n\nfn message() {\n    let client = Client::start();\n    client.message(\"test message\", 100);\n    client.message(\"test message without stack\", 0);\n}\n\nfn tls_confusion() {\n    let client = Client::start();\n    let t1 = std::thread::spawn(move || {\n        drop(client);\n    });\n    let _ = t1.join();\n    let _ = Client::start();\n}\n\nfn set_thread_name() {\n    let _client = Client::start();\n    set_thread_name!(\"test thread\");\n}\n\nfn nameless_span() {\n    let client = Client::start();\n    let _ = span!();\n    let _ = client.span_alloc(None, \"nameless_span\", file!(), line!(), 0);\n    set_thread_name!(\"test thread\");\n}\n\nfn gpu() {\n    let client = Client::start();\n\n    let gpu_context = client\n        .new_gpu_context(Some(\"MyContext\"), GpuContextType::Vulkan, 1_000, 1.0)\n        .unwrap();\n\n    // cmd_buf.write_timestamp(...); to start a span\n    let span_loc = span_location!(\"MyGpuSpan1\");\n    let mut span1 = gpu_context.span(span_loc).unwrap();\n\n    // cmd_buf.write_timestamp(...); to end a span\n    span1.end_zone();\n\n    // cmd_buf.write_timestamp(...); to start a second span\n    let mut span2 = gpu_context\n        .span_alloc(\"MyGpuSpan2\", \"Blah::Blah2\", \"myfile.rs\", 14)\n        .unwrap();\n\n    // cmd_buf.write_timestamp(...); to end a second span\n    span2.end_zone();\n\n    // Some time later, when the timestamps are back\n    span1.upload_timestamp_start(100_000);\n    span1.upload_timestamp_end(110_000);\n    span2.upload_timestamp_start(120_000);\n    span2.upload_timestamp_end(130_000);\n}\n\nfn main() {\n    #[cfg(not(loom))]\n    {\n        basic_zone();\n        alloc_zone();\n        finish_frameset();\n        finish_secondary_frameset();\n        non_continuous_frameset();\n        plot_something();\n        message();\n        allocations();\n        tls_confusion();\n        nameless_span();\n        let thread = std::thread::spawn(|| {\n            let _client = Client::start();\n            fib(25);\n        });\n        thread.join().unwrap();\n        set_thread_name();\n        gpu();\n        // Sleep to give time to the client to send the data to the profiler.\n        std::thread::sleep(Duration::from_secs(5));\n    }\n}\n"
  },
  {
    "path": "tracy-client-sys/Cargo.toml",
    "content": "[package]\nname = \"tracy-client-sys\"\nversion = \"0.28.0\" # AUTO-BUMP\nauthors = [\"Simonas Kazlauskas <tracy-client-sys@kazlauskas.me>\"]\nbuild = \"build.rs\"\nlicense = \"(MIT OR Apache-2.0) AND BSD-3-Clause\"\nedition.workspace = true\nrust-version.workspace = true\nreadme = \"README.mkd\"\nrepository.workspace = true\nhomepage.workspace = true\ndocumentation = \"https://docs.rs/tracy-client-sys\"\ndescription = \"\"\"\nLow level bindings to the client libraries for the Tracy profiler\n\"\"\"\n\n[[test]]\nname = \"tests\"\npath = \"tests.rs\"\nharness = false\nrequired-features = [\"fibers\"]\n\n[dependencies]\n\n[target.\"cfg(windows)\".dependencies]\nwindows-targets = \">=0.48, <0.53\"\n\n[build-dependencies]\ncc = { version = \"1.0.83\", default-features = false }\n\n[features]\n# Refer to FEATURES.mkd for documentation on features.\ndefault = [ \"enable\", \"system-tracing\", \"context-switch-tracing\", \"sampling\", \"code-transfer\",\n            \"broadcast\", \"callstack-inlines\", \"crash-handler\" ]\nenable = []\nfibers = []\nsystem-tracing = []\ncontext-switch-tracing = []\nsampling = []\ncode-transfer = []\nbroadcast = []\nonly-localhost = []\nonly-ipv4 = []\ntimer-fallback = []\nondemand = []\nmanual-lifetime = [\"delayed-init\"]\ndelayed-init = []\ncallstack-inlines = []\nflush-on-exit = []\ndemangle = []\nverify = []\ndebuginfod = []\ncrash-handler = []\n\n[package.metadata.docs.rs]\nall-features = true\n"
  },
  {
    "path": "tracy-client-sys/build.rs",
    "content": "use std::{env::VarError, io::Write};\n\nmacro_rules! docs_rs {\n    () => {\n        option_env!(\"DOCS_RS\") == Some(\"1\")\n    };\n}\n\nfn link_dependencies() {\n    match std::env::var(\"CARGO_CFG_TARGET_OS\").as_deref() {\n        Ok(\"linux\" | \"android\") => println!(\"cargo:rustc-link-lib=dl\"),\n        Ok(\"freebsd\" | \"dragonfly\") => println!(\"cargo:rustc-link-lib=c\"),\n        Ok(\"windows\") => println!(\"cargo:rustc-link-lib=user32\"),\n        Ok(_) => {}\n        Err(e) => {\n            writeln!(::std::io::stderr(), \"Unable to get target_os=`{e}`!\")\n                .expect(\"could not report the error\");\n            ::std::process::exit(0xfd);\n        }\n    }\n    if std::env::var_os(\"CARGO_FEATURE_DEBUGINFOD\").is_some() && !docs_rs!() {\n        println!(\"cargo:rustc-link-lib=debuginfod\");\n    }\n}\n\nfn set_feature_defines(mut c: cc::Build) -> cc::Build {\n    if std::env::var_os(\"CARGO_FEATURE_ENABLE\").is_some() {\n        c.define(\"TRACY_ENABLE\", None);\n    }\n    if std::env::var_os(\"CARGO_FEATURE_TIMER_FALLBACK\").is_some() {\n        c.define(\"TRACY_TIMER_FALLBACK\", None);\n    }\n    if std::env::var_os(\"CARGO_FEATURE_ONDEMAND\").is_some() {\n        c.define(\"TRACY_ON_DEMAND\", None);\n    }\n    if std::env::var_os(\"CARGO_FEATURE_ONLY_LOCALHOST\").is_some() {\n        c.define(\"TRACY_ONLY_LOCALHOST\", None);\n    }\n    if std::env::var_os(\"CARGO_FEATURE_ONLY_IPV4\").is_some() {\n        c.define(\"TRACY_ONLY_IPV4\", None);\n    }\n    if std::env::var_os(\"CARGO_FEATURE_FIBERS\").is_some() {\n        c.define(\"TRACY_FIBERS\", None);\n    }\n    if std::env::var_os(\"CARGO_FEATURE_MANUAL_LIFETIME\").is_some() {\n        c.define(\"TRACY_MANUAL_LIFETIME\", None);\n    }\n    if std::env::var_os(\"CARGO_FEATURE_DELAYED_INIT\").is_some() {\n        c.define(\"TRACY_DELAYED_INIT\", None);\n    }\n    if std::env::var_os(\"CARGO_FEATURE_FLUSH_ON_EXIT\").is_some() {\n        c.define(\"TRACY_NO_EXIT\", None);\n    }\n    if std::env::var_os(\"CARGO_FEATURE_DEMANGLE\").is_some() {\n        c.define(\"TRACY_DEMANGLE\", None);\n    }\n    if std::env::var_os(\"CARGO_FEATURE_DEBUGINFOD\").is_some() && !docs_rs!() {\n        c.define(\"TRACY_DEBUGINFOD\", None);\n    }\n\n    // Note: these are inversed and check for `is_none`!\n    if std::env::var_os(\"CARGO_FEATURE_SYSTEM_TRACING\").is_none() {\n        c.define(\"TRACY_NO_SYSTEM_TRACING\", None);\n    }\n    if std::env::var_os(\"CARGO_FEATURE_CONTEXT_SWITCH_TRACING\").is_none() {\n        c.define(\"TRACY_NO_CONTEXT_SWITCH\", None);\n    }\n    if std::env::var_os(\"CARGO_FEATURE_SAMPLING\").is_none() {\n        c.define(\"TRACY_NO_SAMPLING\", None);\n    }\n    if std::env::var_os(\"CARGO_FEATURE_CODE_TRANSFER\").is_none() {\n        c.define(\"TRACY_NO_CODE_TRANSFER\", None);\n    }\n    if std::env::var_os(\"CARGO_FEATURE_BROADCAST\").is_none() {\n        c.define(\"TRACY_NO_BROADCAST\", None);\n    }\n    if std::env::var_os(\"CARGO_FEATURE_CALLSTACK_INLINES\").is_none() {\n        c.define(\"TRACY_NO_CALLSTACK_INLINES\", None);\n    }\n    if std::env::var_os(\"CARGO_FEATURE_VERIFY\").is_none() {\n        c.define(\"TRACY_NO_VERIFY\", None);\n    }\n    if std::env::var_os(\"CARGO_FEATURE_CRASH_HANDLER\").is_none() {\n        c.define(\"TRACY_NO_CRASH_HANDLER\", None);\n    }\n    c\n}\n\nfn build_tracy_client() {\n    if std::env::var_os(\"CARGO_FEATURE_ENABLE\").is_some() {\n        let mut builder = set_feature_defines(cc::Build::new());\n\n        if std::env::var(\"CARGO_CFG_TARGET_OS\").as_deref() == Ok(\"windows\") {\n            // Used for synchronizing access to the `dbghelp.dll` symbol helper.\n            // See the `dbghelp` module for more information.\n            builder.define(\"TRACY_DBGHELP_LOCK\", \"RustBacktraceMutex\");\n        }\n\n        let _ = builder\n            .file(\"tracy/TracyClient.cpp\")\n            .cargo_warnings(false)\n            .cpp(true);\n        if let Ok(tool) = builder.try_get_compiler() {\n            if tool.is_like_gnu() || tool.is_like_clang() {\n                // https://github.com/rust-lang/cc-rs/issues/855\n                builder.flag(\"-std=c++11\");\n            }\n        }\n        let _ = builder.try_flags_from_environment(\"TRACY_CLIENT_SYS_CXXFLAGS\");\n        builder.compile(\"libtracy-client.a\");\n        link_dependencies();\n    }\n}\n\nfn read_env_and_rerun_if_changed(var: &str) -> Result<String, VarError> {\n    println!(\"cargo:rerun-if-env-changed={}\", var);\n    std::env::var(var)\n}\n\nfn main() {\n    let client_lib = read_env_and_rerun_if_changed(\"TRACY_CLIENT_LIB\");\n    let client_lib_path = read_env_and_rerun_if_changed(\"TRACY_CLIENT_LIB_PATH\");\n    let kind = read_env_and_rerun_if_changed(\"TRACY_CLIENT_STATIC\");\n\n    if let Ok(lib) = client_lib {\n        if let Ok(lib_path) = client_lib_path {\n            println!(\"cargo:rustc-link-search=native={lib_path}\");\n        }\n        let mode = if kind.is_err() || kind.as_deref() == Ok(\"0\") {\n            \"dylib\"\n        } else {\n            link_dependencies();\n            \"static\"\n        };\n        println!(\"cargo:rustc-link-lib={mode}={lib}\");\n    } else {\n        build_tracy_client();\n    }\n}\n"
  },
  {
    "path": "tracy-client-sys/src/dbghelp.rs",
    "content": "//! On Windows, both Tracy and Rust use the `dbghelp.dll` symbol helper to resolve symbols for stack traces.\n//! `dbghelp.dll` is single threaded and requires synchronization to call any of its functions.\n//!\n//! The Rust standard library includes the `backtrace-rs` crate for capturing and resolving backtraces.\n//! When both the standard library and the `backtrace-rs` crate are used in the same program\n//! they need to synchronize their access to `dbghelp.dll`.\n//! They use a shared named Windows mutex for that, which we will use as well.\n//!\n//! Users of Tracy (like this crate) can define the `TRACY_DBGHELP_LOCK` variable for synchronizing access to `dbghelp.dll`.\n//! We set `TRACY_DBGHELP_LOCK=RustBacktraceMutex` in the build script.\n//! Tracy will call [`RustBacktraceMutexInit`], [`RustBacktraceMutexLock`], and [`RustBacktraceMutexUnlock`].\n//! In those functions a handle to the shared named mutex is created, the mutex is locked, and unlocked respectively.\n//!\n//! There is also an issue with initialization between Tracy and `backtrace-rs`.\n//! In particular, the `SymInitialize` function should only be called once per process\n//! and will return an error on subsequent calls.\n//! Both Tracy and `backtrace-rs` ignore errors of the `SymInitialize` function,\n//! so calling it multiple times is not an issue.\n\nuse std::sync::atomic::{AtomicPtr, Ordering};\n\n// Use the `windows_targets` crate and define all the things we need ourselves to avoid a dependency on `windows`\n#[allow(clippy::upper_case_acronyms)]\ntype BOOL = i32;\n#[allow(clippy::upper_case_acronyms)]\ntype HANDLE = *mut core::ffi::c_void;\n#[allow(clippy::upper_case_acronyms)]\ntype PWSTR = *mut u16;\n#[allow(clippy::upper_case_acronyms)]\ntype PCSTR = *const u8;\n#[allow(clippy::upper_case_acronyms)]\ntype PCWSTR = *const u16;\ntype WIN32_ERROR = u32;\n#[repr(C)]\nstruct SECURITY_ATTRIBUTES {\n    nLength: u32,\n    lpSecurityDescriptor: *mut core::ffi::c_void,\n    bInheritHandle: BOOL,\n}\n\nconst FALSE: BOOL = 0i32;\nconst TRUE: BOOL = 1i32;\nconst INFINITE: u32 = u32::MAX;\nconst WAIT_FAILED: u32 = 0xFFFFFFFF;\n\nwindows_targets::link!(\"kernel32.dll\" \"system\" fn GetCurrentProcessId() -> u32);\nwindows_targets::link!(\"kernel32.dll\" \"system\" fn CreateMutexA(lpmutexattributes: *const SECURITY_ATTRIBUTES, binitialowner: BOOL, lpname: PCSTR) -> HANDLE);\nwindows_targets::link!(\"kernel32.dll\" \"system\" fn GetLastError() -> WIN32_ERROR);\nwindows_targets::link!(\"kernel32.dll\" \"system\" fn WaitForSingleObject(hhandle: HANDLE, dwmilliseconds: u32) -> u32);\nwindows_targets::link!(\"kernel32.dll\" \"system\" fn ReleaseMutex(hmutex: HANDLE) -> BOOL);\nwindows_targets::link!(\"kernel32.dll\" \"system\" fn lstrlenW(lpstring : PCWSTR) -> i32);\nwindows_targets::link!(\"kernel32.dll\" \"system\" fn GetCurrentProcess() -> HANDLE);\n\nwindows_targets::link!(\"dbghelp.dll\" \"system\" fn SymInitializeW(hprocess: HANDLE, usersearchpath: PCWSTR, finvadeprocess: BOOL) -> BOOL);\nwindows_targets::link!(\"dbghelp.dll\" \"system\" fn SymGetSearchPathW(hprocess: HANDLE, searchpatha: PWSTR, searchpathlength: u32) -> BOOL);\nwindows_targets::link!(\"dbghelp.dll\" \"system\" fn SymSetSearchPathW(hprocess: HANDLE, searchpatha: PCWSTR) -> BOOL);\nwindows_targets::link!(\"dbghelp.dll\" \"system\" fn EnumerateLoadedModulesW64(hprocess: HANDLE, enumloadedmodulescallback: Option<unsafe extern \"system\" fn(modulename: PCWSTR, modulebase: u64, modulesize: u32, usercontext: *const core::ffi::c_void) -> BOOL>, usercontext: *const core::ffi::c_void) -> BOOL);\n\n/// Handle to the shared named Windows mutex that synchronizes access to the `dbghelp.dll` symbol helper,\n/// with the standard library and `backtrace-rs`.\n/// Gets initialized by [`RustBacktraceMutexInit`],\n/// and because there is no cleanup function, the handle is leaked.\nstatic RUST_BACKTRACE_MUTEX: AtomicPtr<core::ffi::c_void> = AtomicPtr::new(std::ptr::null_mut());\n\n#[no_mangle]\nextern \"C\" fn RustBacktraceMutexInit() {\n    unsafe {\n        // The name is the same one that the standard library and `backtrace-rs` use\n        let name = format!(\"Local\\\\RustBacktraceMutex{:08X}\\0\", GetCurrentProcessId());\n        // Creates a named mutex that is shared with the standard library and `backtrace-rs`\n        // to synchronize access to `dbghelp.dll` functions, which are single threaded.\n        let mutex = CreateMutexA(std::ptr::null(), FALSE, name.as_ptr());\n        assert!(!mutex.is_null());\n\n        // The old value is ignored because this function is only called once,\n        // and normally the handle to the mutex is leaked anyway.\n        RUST_BACKTRACE_MUTEX.store(mutex, Ordering::Release);\n    }\n\n    // We initialize `dbghelp.dll` symbol handler before Tracy does,\n    // and add the directory of all loaded modules to the symbol search path.\n    // This matches the behavior of the standard library and `backtrace-rs`,\n    // and ensures symbols for backtraces don't break when using this crate.\n    // Note that changing the symbol search path doesn't affect modules that were already loaded.\n    init_dbghelp();\n}\n\nfn init_dbghelp() {\n    unsafe {\n        RustBacktraceMutexLock();\n\n        SymInitializeW(GetCurrentProcess(), std::ptr::null(), FALSE);\n\n        let mut paths = vec![0; 1024];\n        if SymGetSearchPathW(\n            GetCurrentProcess(),\n            paths.as_mut_ptr(),\n            paths.len().try_into().unwrap(),\n        ) == TRUE\n        {\n            paths.truncate(lstrlenW(paths.as_ptr()).try_into().unwrap());\n        } else {\n            // As a fallback, use the current directory as a search path if `SymGetSearchPathW` fails,\n            // which can happen when the buffer wasn't big enough\n            paths = vec!['.' as u16];\n        }\n\n        // add the directory of all loaded modules to the symbol search path\n        if EnumerateLoadedModulesW64(\n            GetCurrentProcess(),\n            Some(loaded_modules_callback),\n            (&mut paths as *mut Vec<u16>).cast(),\n        ) == TRUE\n        {\n            paths.push(0); // add null terminator\n            SymSetSearchPathW(GetCurrentProcess(), paths.as_ptr());\n        }\n\n        RustBacktraceMutexUnlock();\n    }\n}\n\nunsafe extern \"system\" fn loaded_modules_callback(\n    module_name: PCWSTR,\n    _module_base: u64,\n    _module_size: u32,\n    user_context: *const core::ffi::c_void,\n) -> BOOL {\n    let path = unsafe {\n        std::slice::from_raw_parts(module_name, lstrlenW(module_name).try_into().unwrap())\n    };\n    let Some(last_separator) = path.iter().rposition(|&c| c == '/' as _ || c == '\\\\' as _) else {\n        return TRUE;\n    };\n    let dir = &path[..last_separator];\n\n    let paths = unsafe { &mut *user_context.cast::<Vec<u16>>().cast_mut() };\n    if paths.split(|&c| c == ';' as _).all(|slice| slice != dir) {\n        paths.push(';' as _);\n        paths.extend(dir);\n    }\n\n    TRUE // continue enumeration\n}\n\n#[no_mangle]\nextern \"C\" fn RustBacktraceMutexLock() {\n    unsafe {\n        let mutex = RUST_BACKTRACE_MUTEX.load(Ordering::Acquire);\n        if !mutex.is_null() {\n            assert_ne!(\n                WaitForSingleObject(mutex, INFINITE),\n                WAIT_FAILED,\n                \"{}\",\n                GetLastError()\n            );\n        }\n    }\n}\n\n#[no_mangle]\nextern \"C\" fn RustBacktraceMutexUnlock() {\n    unsafe {\n        let mutex = RUST_BACKTRACE_MUTEX.load(Ordering::Acquire);\n        if !mutex.is_null() {\n            assert_ne!(ReleaseMutex(mutex), 0, \"{}\", GetLastError());\n        }\n    }\n}\n"
  },
  {
    "path": "tracy-client-sys/src/generated.rs",
    "content": "pub const TracyPlotFormatEnum_TracyPlotFormatNumber: TracyPlotFormatEnum = 0;\npub const TracyPlotFormatEnum_TracyPlotFormatMemory: TracyPlotFormatEnum = 1;\npub const TracyPlotFormatEnum_TracyPlotFormatPercentage: TracyPlotFormatEnum = 2;\npub const TracyPlotFormatEnum_TracyPlotFormatWatt: TracyPlotFormatEnum = 3;\ntype TracyPlotFormatEnum = ::std::os::raw::c_uint;\nextern \"C\" {\n    pub fn ___tracy_set_thread_name(name: *const ::std::os::raw::c_char);\n}\n#[repr(C)]\n#[derive(Debug, Copy, Clone)]\npub struct ___tracy_source_location_data {\n    pub name: *const ::std::os::raw::c_char,\n    pub function: *const ::std::os::raw::c_char,\n    pub file: *const ::std::os::raw::c_char,\n    pub line: u32,\n    pub color: u32,\n}\n#[test]\nfn bindgen_test_layout____tracy_source_location_data() {\n    const UNINIT: ::std::mem::MaybeUninit<___tracy_source_location_data> =\n        ::std::mem::MaybeUninit::uninit();\n    let ptr = UNINIT.as_ptr();\n    assert_eq!(\n        ::std::mem::size_of::<___tracy_source_location_data>(),\n        32usize,\n        \"Size of ___tracy_source_location_data\"\n    );\n    assert_eq!(\n        ::std::mem::align_of::<___tracy_source_location_data>(),\n        8usize,\n        \"Alignment of ___tracy_source_location_data\"\n    );\n    assert_eq!(\n        unsafe { ::std::ptr::addr_of!((*ptr).name) as usize - ptr as usize },\n        0usize,\n        \"Offset of field: ___tracy_source_location_data::name\"\n    );\n    assert_eq!(\n        unsafe { ::std::ptr::addr_of!((*ptr).function) as usize - ptr as usize },\n        8usize,\n        \"Offset of field: ___tracy_source_location_data::function\"\n    );\n    assert_eq!(\n        unsafe { ::std::ptr::addr_of!((*ptr).file) as usize - ptr as usize },\n        16usize,\n        \"Offset of field: ___tracy_source_location_data::file\"\n    );\n    assert_eq!(\n        unsafe { ::std::ptr::addr_of!((*ptr).line) as usize - ptr as usize },\n        24usize,\n        \"Offset of field: ___tracy_source_location_data::line\"\n    );\n    assert_eq!(\n        unsafe { ::std::ptr::addr_of!((*ptr).color) as usize - ptr as usize },\n        28usize,\n        \"Offset of field: ___tracy_source_location_data::color\"\n    );\n}\n#[repr(C)]\n#[derive(Debug, Copy, Clone)]\npub struct ___tracy_c_zone_context {\n    pub id: u32,\n    pub active: i32,\n}\n#[test]\nfn bindgen_test_layout____tracy_c_zone_context() {\n    const UNINIT: ::std::mem::MaybeUninit<___tracy_c_zone_context> =\n        ::std::mem::MaybeUninit::uninit();\n    let ptr = UNINIT.as_ptr();\n    assert_eq!(\n        ::std::mem::size_of::<___tracy_c_zone_context>(),\n        8usize,\n        \"Size of ___tracy_c_zone_context\"\n    );\n    assert_eq!(\n        ::std::mem::align_of::<___tracy_c_zone_context>(),\n        4usize,\n        \"Alignment of ___tracy_c_zone_context\"\n    );\n    assert_eq!(\n        unsafe { ::std::ptr::addr_of!((*ptr).id) as usize - ptr as usize },\n        0usize,\n        \"Offset of field: ___tracy_c_zone_context::id\"\n    );\n    assert_eq!(\n        unsafe { ::std::ptr::addr_of!((*ptr).active) as usize - ptr as usize },\n        4usize,\n        \"Offset of field: ___tracy_c_zone_context::active\"\n    );\n}\n#[repr(C)]\n#[derive(Debug, Copy, Clone)]\npub struct ___tracy_gpu_time_data {\n    pub gpuTime: i64,\n    pub queryId: u16,\n    pub context: u8,\n}\n#[test]\nfn bindgen_test_layout____tracy_gpu_time_data() {\n    const UNINIT: ::std::mem::MaybeUninit<___tracy_gpu_time_data> =\n        ::std::mem::MaybeUninit::uninit();\n    let ptr = UNINIT.as_ptr();\n    assert_eq!(\n        ::std::mem::size_of::<___tracy_gpu_time_data>(),\n        16usize,\n        \"Size of ___tracy_gpu_time_data\"\n    );\n    assert_eq!(\n        ::std::mem::align_of::<___tracy_gpu_time_data>(),\n        8usize,\n        \"Alignment of ___tracy_gpu_time_data\"\n    );\n    assert_eq!(\n        unsafe { ::std::ptr::addr_of!((*ptr).gpuTime) as usize - ptr as usize },\n        0usize,\n        \"Offset of field: ___tracy_gpu_time_data::gpuTime\"\n    );\n    assert_eq!(\n        unsafe { ::std::ptr::addr_of!((*ptr).queryId) as usize - ptr as usize },\n        8usize,\n        \"Offset of field: ___tracy_gpu_time_data::queryId\"\n    );\n    assert_eq!(\n        unsafe { ::std::ptr::addr_of!((*ptr).context) as usize - ptr as usize },\n        10usize,\n        \"Offset of field: ___tracy_gpu_time_data::context\"\n    );\n}\n#[repr(C)]\n#[derive(Debug, Copy, Clone)]\npub struct ___tracy_gpu_zone_begin_data {\n    pub srcloc: u64,\n    pub queryId: u16,\n    pub context: u8,\n}\n#[test]\nfn bindgen_test_layout____tracy_gpu_zone_begin_data() {\n    const UNINIT: ::std::mem::MaybeUninit<___tracy_gpu_zone_begin_data> =\n        ::std::mem::MaybeUninit::uninit();\n    let ptr = UNINIT.as_ptr();\n    assert_eq!(\n        ::std::mem::size_of::<___tracy_gpu_zone_begin_data>(),\n        16usize,\n        \"Size of ___tracy_gpu_zone_begin_data\"\n    );\n    assert_eq!(\n        ::std::mem::align_of::<___tracy_gpu_zone_begin_data>(),\n        8usize,\n        \"Alignment of ___tracy_gpu_zone_begin_data\"\n    );\n    assert_eq!(\n        unsafe { ::std::ptr::addr_of!((*ptr).srcloc) as usize - ptr as usize },\n        0usize,\n        \"Offset of field: ___tracy_gpu_zone_begin_data::srcloc\"\n    );\n    assert_eq!(\n        unsafe { ::std::ptr::addr_of!((*ptr).queryId) as usize - ptr as usize },\n        8usize,\n        \"Offset of field: ___tracy_gpu_zone_begin_data::queryId\"\n    );\n    assert_eq!(\n        unsafe { ::std::ptr::addr_of!((*ptr).context) as usize - ptr as usize },\n        10usize,\n        \"Offset of field: ___tracy_gpu_zone_begin_data::context\"\n    );\n}\n#[repr(C)]\n#[derive(Debug, Copy, Clone)]\npub struct ___tracy_gpu_zone_begin_callstack_data {\n    pub srcloc: u64,\n    pub depth: i32,\n    pub queryId: u16,\n    pub context: u8,\n}\n#[test]\nfn bindgen_test_layout____tracy_gpu_zone_begin_callstack_data() {\n    const UNINIT: ::std::mem::MaybeUninit<___tracy_gpu_zone_begin_callstack_data> =\n        ::std::mem::MaybeUninit::uninit();\n    let ptr = UNINIT.as_ptr();\n    assert_eq!(\n        ::std::mem::size_of::<___tracy_gpu_zone_begin_callstack_data>(),\n        16usize,\n        \"Size of ___tracy_gpu_zone_begin_callstack_data\"\n    );\n    assert_eq!(\n        ::std::mem::align_of::<___tracy_gpu_zone_begin_callstack_data>(),\n        8usize,\n        \"Alignment of ___tracy_gpu_zone_begin_callstack_data\"\n    );\n    assert_eq!(\n        unsafe { ::std::ptr::addr_of!((*ptr).srcloc) as usize - ptr as usize },\n        0usize,\n        \"Offset of field: ___tracy_gpu_zone_begin_callstack_data::srcloc\"\n    );\n    assert_eq!(\n        unsafe { ::std::ptr::addr_of!((*ptr).depth) as usize - ptr as usize },\n        8usize,\n        \"Offset of field: ___tracy_gpu_zone_begin_callstack_data::depth\"\n    );\n    assert_eq!(\n        unsafe { ::std::ptr::addr_of!((*ptr).queryId) as usize - ptr as usize },\n        12usize,\n        \"Offset of field: ___tracy_gpu_zone_begin_callstack_data::queryId\"\n    );\n    assert_eq!(\n        unsafe { ::std::ptr::addr_of!((*ptr).context) as usize - ptr as usize },\n        14usize,\n        \"Offset of field: ___tracy_gpu_zone_begin_callstack_data::context\"\n    );\n}\n#[repr(C)]\n#[derive(Debug, Copy, Clone)]\npub struct ___tracy_gpu_zone_end_data {\n    pub queryId: u16,\n    pub context: u8,\n}\n#[test]\nfn bindgen_test_layout____tracy_gpu_zone_end_data() {\n    const UNINIT: ::std::mem::MaybeUninit<___tracy_gpu_zone_end_data> =\n        ::std::mem::MaybeUninit::uninit();\n    let ptr = UNINIT.as_ptr();\n    assert_eq!(\n        ::std::mem::size_of::<___tracy_gpu_zone_end_data>(),\n        4usize,\n        \"Size of ___tracy_gpu_zone_end_data\"\n    );\n    assert_eq!(\n        ::std::mem::align_of::<___tracy_gpu_zone_end_data>(),\n        2usize,\n        \"Alignment of ___tracy_gpu_zone_end_data\"\n    );\n    assert_eq!(\n        unsafe { ::std::ptr::addr_of!((*ptr).queryId) as usize - ptr as usize },\n        0usize,\n        \"Offset of field: ___tracy_gpu_zone_end_data::queryId\"\n    );\n    assert_eq!(\n        unsafe { ::std::ptr::addr_of!((*ptr).context) as usize - ptr as usize },\n        2usize,\n        \"Offset of field: ___tracy_gpu_zone_end_data::context\"\n    );\n}\n#[repr(C)]\n#[derive(Debug, Copy, Clone)]\npub struct ___tracy_gpu_new_context_data {\n    pub gpuTime: i64,\n    pub period: f32,\n    pub context: u8,\n    pub flags: u8,\n    pub type_: u8,\n}\n#[test]\nfn bindgen_test_layout____tracy_gpu_new_context_data() {\n    const UNINIT: ::std::mem::MaybeUninit<___tracy_gpu_new_context_data> =\n        ::std::mem::MaybeUninit::uninit();\n    let ptr = UNINIT.as_ptr();\n    assert_eq!(\n        ::std::mem::size_of::<___tracy_gpu_new_context_data>(),\n        16usize,\n        \"Size of ___tracy_gpu_new_context_data\"\n    );\n    assert_eq!(\n        ::std::mem::align_of::<___tracy_gpu_new_context_data>(),\n        8usize,\n        \"Alignment of ___tracy_gpu_new_context_data\"\n    );\n    assert_eq!(\n        unsafe { ::std::ptr::addr_of!((*ptr).gpuTime) as usize - ptr as usize },\n        0usize,\n        \"Offset of field: ___tracy_gpu_new_context_data::gpuTime\"\n    );\n    assert_eq!(\n        unsafe { ::std::ptr::addr_of!((*ptr).period) as usize - ptr as usize },\n        8usize,\n        \"Offset of field: ___tracy_gpu_new_context_data::period\"\n    );\n    assert_eq!(\n        unsafe { ::std::ptr::addr_of!((*ptr).context) as usize - ptr as usize },\n        12usize,\n        \"Offset of field: ___tracy_gpu_new_context_data::context\"\n    );\n    assert_eq!(\n        unsafe { ::std::ptr::addr_of!((*ptr).flags) as usize - ptr as usize },\n        13usize,\n        \"Offset of field: ___tracy_gpu_new_context_data::flags\"\n    );\n    assert_eq!(\n        unsafe { ::std::ptr::addr_of!((*ptr).type_) as usize - ptr as usize },\n        14usize,\n        \"Offset of field: ___tracy_gpu_new_context_data::type_\"\n    );\n}\n#[repr(C)]\n#[derive(Debug, Copy, Clone)]\npub struct ___tracy_gpu_context_name_data {\n    pub context: u8,\n    pub name: *const ::std::os::raw::c_char,\n    pub len: u16,\n}\n#[test]\nfn bindgen_test_layout____tracy_gpu_context_name_data() {\n    const UNINIT: ::std::mem::MaybeUninit<___tracy_gpu_context_name_data> =\n        ::std::mem::MaybeUninit::uninit();\n    let ptr = UNINIT.as_ptr();\n    assert_eq!(\n        ::std::mem::size_of::<___tracy_gpu_context_name_data>(),\n        24usize,\n        \"Size of ___tracy_gpu_context_name_data\"\n    );\n    assert_eq!(\n        ::std::mem::align_of::<___tracy_gpu_context_name_data>(),\n        8usize,\n        \"Alignment of ___tracy_gpu_context_name_data\"\n    );\n    assert_eq!(\n        unsafe { ::std::ptr::addr_of!((*ptr).context) as usize - ptr as usize },\n        0usize,\n        \"Offset of field: ___tracy_gpu_context_name_data::context\"\n    );\n    assert_eq!(\n        unsafe { ::std::ptr::addr_of!((*ptr).name) as usize - ptr as usize },\n        8usize,\n        \"Offset of field: ___tracy_gpu_context_name_data::name\"\n    );\n    assert_eq!(\n        unsafe { ::std::ptr::addr_of!((*ptr).len) as usize - ptr as usize },\n        16usize,\n        \"Offset of field: ___tracy_gpu_context_name_data::len\"\n    );\n}\n#[repr(C)]\n#[derive(Debug, Copy, Clone)]\npub struct ___tracy_gpu_calibration_data {\n    pub gpuTime: i64,\n    pub cpuDelta: i64,\n    pub context: u8,\n}\n#[test]\nfn bindgen_test_layout____tracy_gpu_calibration_data() {\n    const UNINIT: ::std::mem::MaybeUninit<___tracy_gpu_calibration_data> =\n        ::std::mem::MaybeUninit::uninit();\n    let ptr = UNINIT.as_ptr();\n    assert_eq!(\n        ::std::mem::size_of::<___tracy_gpu_calibration_data>(),\n        24usize,\n        \"Size of ___tracy_gpu_calibration_data\"\n    );\n    assert_eq!(\n        ::std::mem::align_of::<___tracy_gpu_calibration_data>(),\n        8usize,\n        \"Alignment of ___tracy_gpu_calibration_data\"\n    );\n    assert_eq!(\n        unsafe { ::std::ptr::addr_of!((*ptr).gpuTime) as usize - ptr as usize },\n        0usize,\n        \"Offset of field: ___tracy_gpu_calibration_data::gpuTime\"\n    );\n    assert_eq!(\n        unsafe { ::std::ptr::addr_of!((*ptr).cpuDelta) as usize - ptr as usize },\n        8usize,\n        \"Offset of field: ___tracy_gpu_calibration_data::cpuDelta\"\n    );\n    assert_eq!(\n        unsafe { ::std::ptr::addr_of!((*ptr).context) as usize - ptr as usize },\n        16usize,\n        \"Offset of field: ___tracy_gpu_calibration_data::context\"\n    );\n}\n#[repr(C)]\n#[derive(Debug, Copy, Clone)]\npub struct ___tracy_gpu_time_sync_data {\n    pub gpuTime: i64,\n    pub context: u8,\n}\n#[test]\nfn bindgen_test_layout____tracy_gpu_time_sync_data() {\n    const UNINIT: ::std::mem::MaybeUninit<___tracy_gpu_time_sync_data> =\n        ::std::mem::MaybeUninit::uninit();\n    let ptr = UNINIT.as_ptr();\n    assert_eq!(\n        ::std::mem::size_of::<___tracy_gpu_time_sync_data>(),\n        16usize,\n        \"Size of ___tracy_gpu_time_sync_data\"\n    );\n    assert_eq!(\n        ::std::mem::align_of::<___tracy_gpu_time_sync_data>(),\n        8usize,\n        \"Alignment of ___tracy_gpu_time_sync_data\"\n    );\n    assert_eq!(\n        unsafe { ::std::ptr::addr_of!((*ptr).gpuTime) as usize - ptr as usize },\n        0usize,\n        \"Offset of field: ___tracy_gpu_time_sync_data::gpuTime\"\n    );\n    assert_eq!(\n        unsafe { ::std::ptr::addr_of!((*ptr).context) as usize - ptr as usize },\n        8usize,\n        \"Offset of field: ___tracy_gpu_time_sync_data::context\"\n    );\n}\n#[repr(C)]\n#[derive(Debug, Copy, Clone)]\npub struct __tracy_lockable_context_data {\n    _unused: [u8; 0],\n}\ntype TracyCZoneCtx = ___tracy_c_zone_context;\nextern \"C\" {\n    pub fn ___tracy_alloc_srcloc(\n        line: u32,\n        source: *const ::std::os::raw::c_char,\n        sourceSz: usize,\n        function: *const ::std::os::raw::c_char,\n        functionSz: usize,\n        color: u32,\n    ) -> u64;\n}\nextern \"C\" {\n    pub fn ___tracy_alloc_srcloc_name(\n        line: u32,\n        source: *const ::std::os::raw::c_char,\n        sourceSz: usize,\n        function: *const ::std::os::raw::c_char,\n        functionSz: usize,\n        name: *const ::std::os::raw::c_char,\n        nameSz: usize,\n        color: u32,\n    ) -> u64;\n}\nextern \"C\" {\n    pub fn ___tracy_emit_zone_begin(\n        srcloc: *const ___tracy_source_location_data,\n        active: i32,\n    ) -> TracyCZoneCtx;\n}\nextern \"C\" {\n    pub fn ___tracy_emit_zone_begin_callstack(\n        srcloc: *const ___tracy_source_location_data,\n        depth: i32,\n        active: i32,\n    ) -> TracyCZoneCtx;\n}\nextern \"C\" {\n    pub fn ___tracy_emit_zone_begin_alloc(srcloc: u64, active: i32) -> TracyCZoneCtx;\n}\nextern \"C\" {\n    pub fn ___tracy_emit_zone_begin_alloc_callstack(\n        srcloc: u64,\n        depth: i32,\n        active: i32,\n    ) -> TracyCZoneCtx;\n}\nextern \"C\" {\n    pub fn ___tracy_emit_zone_end(ctx: TracyCZoneCtx);\n}\nextern \"C\" {\n    pub fn ___tracy_emit_zone_text(\n        ctx: TracyCZoneCtx,\n        txt: *const ::std::os::raw::c_char,\n        size: usize,\n    );\n}\nextern \"C\" {\n    pub fn ___tracy_emit_zone_name(\n        ctx: TracyCZoneCtx,\n        txt: *const ::std::os::raw::c_char,\n        size: usize,\n    );\n}\nextern \"C\" {\n    pub fn ___tracy_emit_zone_color(ctx: TracyCZoneCtx, color: u32);\n}\nextern \"C\" {\n    pub fn ___tracy_emit_zone_value(ctx: TracyCZoneCtx, value: u64);\n}\nextern \"C\" {\n    pub fn ___tracy_emit_gpu_zone_begin(arg1: ___tracy_gpu_zone_begin_data);\n}\nextern \"C\" {\n    pub fn ___tracy_emit_gpu_zone_begin_callstack(arg1: ___tracy_gpu_zone_begin_callstack_data);\n}\nextern \"C\" {\n    pub fn ___tracy_emit_gpu_zone_begin_alloc(arg1: ___tracy_gpu_zone_begin_data);\n}\nextern \"C\" {\n    pub fn ___tracy_emit_gpu_zone_begin_alloc_callstack(\n        arg1: ___tracy_gpu_zone_begin_callstack_data,\n    );\n}\nextern \"C\" {\n    pub fn ___tracy_emit_gpu_zone_end(data: ___tracy_gpu_zone_end_data);\n}\nextern \"C\" {\n    pub fn ___tracy_emit_gpu_time(arg1: ___tracy_gpu_time_data);\n}\nextern \"C\" {\n    pub fn ___tracy_emit_gpu_new_context(arg1: ___tracy_gpu_new_context_data);\n}\nextern \"C\" {\n    pub fn ___tracy_emit_gpu_context_name(arg1: ___tracy_gpu_context_name_data);\n}\nextern \"C\" {\n    pub fn ___tracy_emit_gpu_calibration(arg1: ___tracy_gpu_calibration_data);\n}\nextern \"C\" {\n    pub fn ___tracy_emit_gpu_time_sync(arg1: ___tracy_gpu_time_sync_data);\n}\nextern \"C\" {\n    pub fn ___tracy_emit_gpu_zone_begin_serial(arg1: ___tracy_gpu_zone_begin_data);\n}\nextern \"C\" {\n    pub fn ___tracy_emit_gpu_zone_begin_callstack_serial(\n        arg1: ___tracy_gpu_zone_begin_callstack_data,\n    );\n}\nextern \"C\" {\n    pub fn ___tracy_emit_gpu_zone_begin_alloc_serial(arg1: ___tracy_gpu_zone_begin_data);\n}\nextern \"C\" {\n    pub fn ___tracy_emit_gpu_zone_begin_alloc_callstack_serial(\n        arg1: ___tracy_gpu_zone_begin_callstack_data,\n    );\n}\nextern \"C\" {\n    pub fn ___tracy_emit_gpu_zone_end_serial(data: ___tracy_gpu_zone_end_data);\n}\nextern \"C\" {\n    pub fn ___tracy_emit_gpu_time_serial(arg1: ___tracy_gpu_time_data);\n}\nextern \"C\" {\n    pub fn ___tracy_emit_gpu_new_context_serial(arg1: ___tracy_gpu_new_context_data);\n}\nextern \"C\" {\n    pub fn ___tracy_emit_gpu_context_name_serial(arg1: ___tracy_gpu_context_name_data);\n}\nextern \"C\" {\n    pub fn ___tracy_emit_gpu_calibration_serial(arg1: ___tracy_gpu_calibration_data);\n}\nextern \"C\" {\n    pub fn ___tracy_emit_gpu_time_sync_serial(arg1: ___tracy_gpu_time_sync_data);\n}\nextern \"C\" {\n    pub fn ___tracy_connected() -> i32;\n}\nextern \"C\" {\n    pub fn ___tracy_emit_memory_alloc(ptr: *const ::std::os::raw::c_void, size: usize, secure: i32);\n}\nextern \"C\" {\n    pub fn ___tracy_emit_memory_alloc_callstack(\n        ptr: *const ::std::os::raw::c_void,\n        size: usize,\n        depth: i32,\n        secure: i32,\n    );\n}\nextern \"C\" {\n    pub fn ___tracy_emit_memory_free(ptr: *const ::std::os::raw::c_void, secure: i32);\n}\nextern \"C\" {\n    pub fn ___tracy_emit_memory_free_callstack(\n        ptr: *const ::std::os::raw::c_void,\n        depth: i32,\n        secure: i32,\n    );\n}\nextern \"C\" {\n    pub fn ___tracy_emit_memory_alloc_named(\n        ptr: *const ::std::os::raw::c_void,\n        size: usize,\n        secure: i32,\n        name: *const ::std::os::raw::c_char,\n    );\n}\nextern \"C\" {\n    pub fn ___tracy_emit_memory_alloc_callstack_named(\n        ptr: *const ::std::os::raw::c_void,\n        size: usize,\n        depth: i32,\n        secure: i32,\n        name: *const ::std::os::raw::c_char,\n    );\n}\nextern \"C\" {\n    pub fn ___tracy_emit_memory_free_named(\n        ptr: *const ::std::os::raw::c_void,\n        secure: i32,\n        name: *const ::std::os::raw::c_char,\n    );\n}\nextern \"C\" {\n    pub fn ___tracy_emit_memory_free_callstack_named(\n        ptr: *const ::std::os::raw::c_void,\n        depth: i32,\n        secure: i32,\n        name: *const ::std::os::raw::c_char,\n    );\n}\nextern \"C\" {\n    pub fn ___tracy_emit_memory_discard(name: *const ::std::os::raw::c_char, secure: i32);\n}\nextern \"C\" {\n    pub fn ___tracy_emit_memory_discard_callstack(\n        name: *const ::std::os::raw::c_char,\n        secure: i32,\n        depth: i32,\n    );\n}\nextern \"C\" {\n    pub fn ___tracy_emit_message(\n        txt: *const ::std::os::raw::c_char,\n        size: usize,\n        callstack_depth: i32,\n    );\n}\nextern \"C\" {\n    pub fn ___tracy_emit_messageL(txt: *const ::std::os::raw::c_char, callstack_depth: i32);\n}\nextern \"C\" {\n    pub fn ___tracy_emit_messageC(\n        txt: *const ::std::os::raw::c_char,\n        size: usize,\n        color: u32,\n        callstack_depth: i32,\n    );\n}\nextern \"C\" {\n    pub fn ___tracy_emit_messageLC(\n        txt: *const ::std::os::raw::c_char,\n        color: u32,\n        callstack_depth: i32,\n    );\n}\nextern \"C\" {\n    pub fn ___tracy_emit_frame_mark(name: *const ::std::os::raw::c_char);\n}\nextern \"C\" {\n    pub fn ___tracy_emit_frame_mark_start(name: *const ::std::os::raw::c_char);\n}\nextern \"C\" {\n    pub fn ___tracy_emit_frame_mark_end(name: *const ::std::os::raw::c_char);\n}\nextern \"C\" {\n    pub fn ___tracy_emit_frame_image(\n        image: *const ::std::os::raw::c_void,\n        w: u16,\n        h: u16,\n        offset: u8,\n        flip: i32,\n    );\n}\nextern \"C\" {\n    pub fn ___tracy_emit_plot(name: *const ::std::os::raw::c_char, val: f64);\n}\nextern \"C\" {\n    pub fn ___tracy_emit_plot_float(name: *const ::std::os::raw::c_char, val: f32);\n}\nextern \"C\" {\n    pub fn ___tracy_emit_plot_int(name: *const ::std::os::raw::c_char, val: i64);\n}\nextern \"C\" {\n    pub fn ___tracy_emit_plot_config(\n        name: *const ::std::os::raw::c_char,\n        type_: i32,\n        step: i32,\n        fill: i32,\n        color: u32,\n    );\n}\nextern \"C\" {\n    pub fn ___tracy_emit_message_appinfo(txt: *const ::std::os::raw::c_char, size: usize);\n}\nextern \"C\" {\n    pub fn ___tracy_announce_lockable_ctx(\n        srcloc: *const ___tracy_source_location_data,\n    ) -> *mut __tracy_lockable_context_data;\n}\nextern \"C\" {\n    pub fn ___tracy_terminate_lockable_ctx(lockdata: *mut __tracy_lockable_context_data);\n}\nextern \"C\" {\n    pub fn ___tracy_before_lock_lockable_ctx(lockdata: *mut __tracy_lockable_context_data) -> i32;\n}\nextern \"C\" {\n    pub fn ___tracy_after_lock_lockable_ctx(lockdata: *mut __tracy_lockable_context_data);\n}\nextern \"C\" {\n    pub fn ___tracy_after_unlock_lockable_ctx(lockdata: *mut __tracy_lockable_context_data);\n}\nextern \"C\" {\n    pub fn ___tracy_after_try_lock_lockable_ctx(\n        lockdata: *mut __tracy_lockable_context_data,\n        acquired: i32,\n    );\n}\nextern \"C\" {\n    pub fn ___tracy_mark_lockable_ctx(\n        lockdata: *mut __tracy_lockable_context_data,\n        srcloc: *const ___tracy_source_location_data,\n    );\n}\nextern \"C\" {\n    pub fn ___tracy_custom_name_lockable_ctx(\n        lockdata: *mut __tracy_lockable_context_data,\n        name: *const ::std::os::raw::c_char,\n        nameSz: usize,\n    );\n}\nextern \"C\" {\n    pub fn ___tracy_begin_sampling_profiler() -> ::std::os::raw::c_int;\n}\nextern \"C\" {\n    pub fn ___tracy_end_sampling_profiler();\n}\n"
  },
  {
    "path": "tracy-client-sys/src/generated_fibers.rs",
    "content": "extern \"C\" {\n    pub fn ___tracy_fiber_enter(fiber: *const ::std::os::raw::c_char);\n}\nextern \"C\" {\n    pub fn ___tracy_fiber_leave();\n}\n"
  },
  {
    "path": "tracy-client-sys/src/generated_manual_lifetime.rs",
    "content": "extern \"C\" {\n    pub fn ___tracy_startup_profiler();\n}\nextern \"C\" {\n    pub fn ___tracy_shutdown_profiler();\n}\n"
  },
  {
    "path": "tracy-client-sys/src/lib.rs",
    "content": "//! The Tracy Client and its low level API\n//!\n//! This crate embeds the C++ Tracy client library and exposes its API. For a higher-level API\n//! consider the `tracy-client` crate.\n//!\n//! # Important note\n//!\n//! Depending on the configuration Tracy may broadcast discovery packets to the local network and\n//! expose the data it collects in the background to that same network. Traces collected by Tracy\n//! may include source and assembly code as well.\n//!\n//! As thus, you may want make sure to only enable the `tracy-client-sys` crate conditionally, via\n//! the `enable` feature flag provided by this crate.\n//!\n//! In order to start tracing it is important that you first call the [`___tracy_startup_profiler`]\n//! function first to initialize the client. The [`___tracy_shutdown_profiler`] must not be called\n//! until it is guaranteed that there will be no more calls to any other Tracy APIs. This can be\n//! especially difficult to ensure if you have detached threads.\n//!\n//! # Features\n//!\n//! The following crate features are provided to customize the functionality of the Tracy client:\n//!\n//! * `manual-lifetime` – disables Tracy’s life-before-main initialization, requiring manual\n//!   initialization. Corresponds to the `TRACY_MANUAL_LIFETIME` define.\n//! * `delayed-init` – profiler data is gathered into one structure and initialized on the first\n//!   request rather than statically at the DLL load at the expense of atomic load on each request\n//!   to the profiler data. Corresponds to the `TRACY_DELAYED_INIT` define.\n#![doc = include_str!(\"../FEATURES.mkd\")]\n#![allow(\n    non_snake_case,\n    non_camel_case_types,\n    non_upper_case_globals,\n    unused_variables,\n    deref_nullptr\n)]\n\n#[cfg(feature = \"enable\")]\nmod generated;\n#[cfg(feature = \"enable\")]\npub use generated::*;\n\n#[cfg(all(feature = \"enable\", feature = \"manual-lifetime\"))]\nmod generated_manual_lifetime;\n#[cfg(all(feature = \"enable\", feature = \"manual-lifetime\"))]\npub use generated_manual_lifetime::*;\n\n#[cfg(all(feature = \"enable\", feature = \"fibers\"))]\nmod generated_fibers;\n#[cfg(all(feature = \"enable\", feature = \"fibers\"))]\npub use generated_fibers::{___tracy_fiber_enter, ___tracy_fiber_leave};\n\n#[cfg(all(feature = \"enable\", target_os = \"windows\"))]\nmod dbghelp;\n"
  },
  {
    "path": "tracy-client-sys/tests.rs",
    "content": "#[cfg(all(feature = \"enable\", test))]\nmod tests {\n    use tracy_client_sys::*;\n\n    fn test_emit_zone() {\n        unsafe {\n            let srcloc = ___tracy_source_location_data {\n                name: b\"name\\0\".as_ptr().cast(),\n                function: b\"function\\0\".as_ptr().cast(),\n                file: b\"file\\0\".as_ptr().cast(),\n                line: 42,\n                color: 0,\n            };\n            let zone_ctx = ___tracy_emit_zone_begin(&srcloc, 1);\n            ___tracy_emit_zone_end(zone_ctx);\n        }\n    }\n\n    fn test_emit_message_no_null() {\n        unsafe {\n            ___tracy_emit_message(b\"hello world\".as_ptr().cast(), 11, 1);\n        }\n    }\n\n    /// Cannot use a libtest harness here because we need manual control over\n    /// the profiler startup and shutdown.\n    pub(crate) fn main() {\n        unsafe {\n            ___tracy_startup_profiler();\n        }\n        test_emit_zone();\n        test_emit_message_no_null();\n        unsafe {\n            ___tracy_fiber_enter(b\"hello\".as_ptr().cast());\n            ___tracy_shutdown_profiler();\n        }\n    }\n}\n\nfn main() {\n    #[cfg(all(feature = \"enable\", test))]\n    tests::main();\n}\n"
  },
  {
    "path": "tracy-client-sys/tracy/LICENSE",
    "content": "Tracy Profiler (https://github.com/wolfpld/tracy) is licensed under the\n3-clause BSD license.\n\nCopyright (c) 2017-2025, Bartosz Taudul <wolf@nereid.pl>\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n    * Redistributions of source code must retain the above copyright\n      notice, this list of conditions and the following disclaimer.\n    * Redistributions in binary form must reproduce the above copyright\n      notice, this list of conditions and the following disclaimer in the\n      documentation and/or other materials provided with the distribution.\n    * Neither the name of the <organization> nor the\n      names of its contributors may be used to endorse or promote products\n      derived from this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\nANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\nWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY\nDIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\nLOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\nON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\nSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
  },
  {
    "path": "tracy-client-sys/tracy/TracyClient.F90",
    "content": "module tracy\n  use, intrinsic :: iso_c_binding, only: c_ptr, c_loc, c_char, c_null_char, &\n    & c_size_t, c_int8_t, c_int16_t, c_int32_t, c_int64_t, c_int, c_float, c_double, c_null_ptr\n  implicit none\n  private\n\n  integer(c_int32_t), parameter, public :: TRACY_PLOTFORMAT_NUMBER = 0\n  integer(c_int32_t), parameter, public :: TRACY_PLOTFORMAT_MEMORY = 1\n  integer(c_int32_t), parameter, public :: TRACY_PLOTFORMAT_PERCENTAGE = 2\n  integer(c_int32_t), parameter, public :: TRACY_PLOTFORMAT_WATT = 3\n\n  character(c_char), parameter, public :: tracy_null_char = c_null_char\n\n  type, bind(C) :: TracyColors_t\n    integer(c_int32_t) :: Snow = int(Z'fffafa', kind=c_int32_t)\n    integer(c_int32_t) :: GhostWhite = int(Z'f8f8ff', kind=c_int32_t)\n    integer(c_int32_t) :: WhiteSmoke = int(Z'f5f5f5', kind=c_int32_t)\n    integer(c_int32_t) :: Gainsboro = int(Z'dcdcdc', kind=c_int32_t)\n    integer(c_int32_t) :: FloralWhite = int(Z'fffaf0', kind=c_int32_t)\n    integer(c_int32_t) :: OldLace = int(Z'fdf5e6', kind=c_int32_t)\n    integer(c_int32_t) :: Linen = int(Z'faf0e6', kind=c_int32_t)\n    integer(c_int32_t) :: AntiqueWhite = int(Z'faebd7', kind=c_int32_t)\n    integer(c_int32_t) :: PapayaWhip = int(Z'ffefd5', kind=c_int32_t)\n    integer(c_int32_t) :: BlanchedAlmond = int(Z'ffebcd', kind=c_int32_t)\n    integer(c_int32_t) :: Bisque = int(Z'ffe4c4', kind=c_int32_t)\n    integer(c_int32_t) :: PeachPuff = int(Z'ffdab9', kind=c_int32_t)\n    integer(c_int32_t) :: NavajoWhite = int(Z'ffdead', kind=c_int32_t)\n    integer(c_int32_t) :: Moccasin = int(Z'ffe4b5', kind=c_int32_t)\n    integer(c_int32_t) :: Cornsilk = int(Z'fff8dc', kind=c_int32_t)\n    integer(c_int32_t) :: Ivory = int(Z'fffff0', kind=c_int32_t)\n    integer(c_int32_t) :: LemonChiffon = int(Z'fffacd', kind=c_int32_t)\n    integer(c_int32_t) :: Seashell = int(Z'fff5ee', kind=c_int32_t)\n    integer(c_int32_t) :: Honeydew = int(Z'f0fff0', kind=c_int32_t)\n    integer(c_int32_t) :: MintCream = int(Z'f5fffa', kind=c_int32_t)\n    integer(c_int32_t) :: Azure = int(Z'f0ffff', kind=c_int32_t)\n    integer(c_int32_t) :: AliceBlue = int(Z'f0f8ff', kind=c_int32_t)\n    integer(c_int32_t) :: Lavender = int(Z'e6e6fa', kind=c_int32_t)\n    integer(c_int32_t) :: LavenderBlush = int(Z'fff0f5', kind=c_int32_t)\n    integer(c_int32_t) :: MistyRose = int(Z'ffe4e1', kind=c_int32_t)\n    integer(c_int32_t) :: White = int(Z'ffffff', kind=c_int32_t)\n    integer(c_int32_t) :: Black = int(Z'000000', kind=c_int32_t)\n    integer(c_int32_t) :: DarkSlateGray = int(Z'2f4f4f', kind=c_int32_t)\n    integer(c_int32_t) :: DarkSlateGrey = int(Z'2f4f4f', kind=c_int32_t)\n    integer(c_int32_t) :: DimGray = int(Z'696969', kind=c_int32_t)\n    integer(c_int32_t) :: DimGrey = int(Z'696969', kind=c_int32_t)\n    integer(c_int32_t) :: SlateGray = int(Z'708090', kind=c_int32_t)\n    integer(c_int32_t) :: SlateGrey = int(Z'708090', kind=c_int32_t)\n    integer(c_int32_t) :: LightSlateGray = int(Z'778899', kind=c_int32_t)\n    integer(c_int32_t) :: LightSlateGrey = int(Z'778899', kind=c_int32_t)\n    integer(c_int32_t) :: Gray = int(Z'bebebe', kind=c_int32_t)\n    integer(c_int32_t) :: Grey = int(Z'bebebe', kind=c_int32_t)\n    integer(c_int32_t) :: X11Gray = int(Z'bebebe', kind=c_int32_t)\n    integer(c_int32_t) :: X11Grey = int(Z'bebebe', kind=c_int32_t)\n    integer(c_int32_t) :: WebGray = int(Z'808080', kind=c_int32_t)\n    integer(c_int32_t) :: WebGrey = int(Z'808080', kind=c_int32_t)\n    integer(c_int32_t) :: LightGrey = int(Z'd3d3d3', kind=c_int32_t)\n    integer(c_int32_t) :: LightGray = int(Z'd3d3d3', kind=c_int32_t)\n    integer(c_int32_t) :: MidnightBlue = int(Z'191970', kind=c_int32_t)\n    integer(c_int32_t) :: Navy = int(Z'000080', kind=c_int32_t)\n    integer(c_int32_t) :: NavyBlue = int(Z'000080', kind=c_int32_t)\n    integer(c_int32_t) :: CornflowerBlue = int(Z'6495ed', kind=c_int32_t)\n    integer(c_int32_t) :: DarkSlateBlue = int(Z'483d8b', kind=c_int32_t)\n    integer(c_int32_t) :: SlateBlue = int(Z'6a5acd', kind=c_int32_t)\n    integer(c_int32_t) :: MediumSlateBlue = int(Z'7b68ee', kind=c_int32_t)\n    integer(c_int32_t) :: LightSlateBlue = int(Z'8470ff', kind=c_int32_t)\n    integer(c_int32_t) :: MediumBlue = int(Z'0000cd', kind=c_int32_t)\n    integer(c_int32_t) :: RoyalBlue = int(Z'4169e1', kind=c_int32_t)\n    integer(c_int32_t) :: Blue = int(Z'0000ff', kind=c_int32_t)\n    integer(c_int32_t) :: DodgerBlue = int(Z'1e90ff', kind=c_int32_t)\n    integer(c_int32_t) :: DeepSkyBlue = int(Z'00bfff', kind=c_int32_t)\n    integer(c_int32_t) :: SkyBlue = int(Z'87ceeb', kind=c_int32_t)\n    integer(c_int32_t) :: LightSkyBlue = int(Z'87cefa', kind=c_int32_t)\n    integer(c_int32_t) :: SteelBlue = int(Z'4682b4', kind=c_int32_t)\n    integer(c_int32_t) :: LightSteelBlue = int(Z'b0c4de', kind=c_int32_t)\n    integer(c_int32_t) :: LightBlue = int(Z'add8e6', kind=c_int32_t)\n    integer(c_int32_t) :: PowderBlue = int(Z'b0e0e6', kind=c_int32_t)\n    integer(c_int32_t) :: PaleTurquoise = int(Z'afeeee', kind=c_int32_t)\n    integer(c_int32_t) :: DarkTurquoise = int(Z'00ced1', kind=c_int32_t)\n    integer(c_int32_t) :: MediumTurquoise = int(Z'48d1cc', kind=c_int32_t)\n    integer(c_int32_t) :: Turquoise = int(Z'40e0d0', kind=c_int32_t)\n    integer(c_int32_t) :: Cyan = int(Z'00ffff', kind=c_int32_t)\n    integer(c_int32_t) :: Aqua = int(Z'00ffff', kind=c_int32_t)\n    integer(c_int32_t) :: LightCyan = int(Z'e0ffff', kind=c_int32_t)\n    integer(c_int32_t) :: CadetBlue = int(Z'5f9ea0', kind=c_int32_t)\n    integer(c_int32_t) :: MediumAquamarine = int(Z'66cdaa', kind=c_int32_t)\n    integer(c_int32_t) :: Aquamarine = int(Z'7fffd4', kind=c_int32_t)\n    integer(c_int32_t) :: DarkGreen = int(Z'006400', kind=c_int32_t)\n    integer(c_int32_t) :: DarkOliveGreen = int(Z'556b2f', kind=c_int32_t)\n    integer(c_int32_t) :: DarkSeaGreen = int(Z'8fbc8f', kind=c_int32_t)\n    integer(c_int32_t) :: SeaGreen = int(Z'2e8b57', kind=c_int32_t)\n    integer(c_int32_t) :: MediumSeaGreen = int(Z'3cb371', kind=c_int32_t)\n    integer(c_int32_t) :: LightSeaGreen = int(Z'20b2aa', kind=c_int32_t)\n    integer(c_int32_t) :: PaleGreen = int(Z'98fb98', kind=c_int32_t)\n    integer(c_int32_t) :: SpringGreen = int(Z'00ff7f', kind=c_int32_t)\n    integer(c_int32_t) :: LawnGreen = int(Z'7cfc00', kind=c_int32_t)\n    integer(c_int32_t) :: Green = int(Z'00ff00', kind=c_int32_t)\n    integer(c_int32_t) :: Lime = int(Z'00ff00', kind=c_int32_t)\n    integer(c_int32_t) :: X11Green = int(Z'00ff00', kind=c_int32_t)\n    integer(c_int32_t) :: WebGreen = int(Z'008000', kind=c_int32_t)\n    integer(c_int32_t) :: Chartreuse = int(Z'7fff00', kind=c_int32_t)\n    integer(c_int32_t) :: MediumSpringGreen = int(Z'00fa9a', kind=c_int32_t)\n    integer(c_int32_t) :: GreenYellow = int(Z'adff2f', kind=c_int32_t)\n    integer(c_int32_t) :: LimeGreen = int(Z'32cd32', kind=c_int32_t)\n    integer(c_int32_t) :: YellowGreen = int(Z'9acd32', kind=c_int32_t)\n    integer(c_int32_t) :: ForestGreen = int(Z'228b22', kind=c_int32_t)\n    integer(c_int32_t) :: OliveDrab = int(Z'6b8e23', kind=c_int32_t)\n    integer(c_int32_t) :: DarkKhaki = int(Z'bdb76b', kind=c_int32_t)\n    integer(c_int32_t) :: Khaki = int(Z'f0e68c', kind=c_int32_t)\n    integer(c_int32_t) :: PaleGoldenrod = int(Z'eee8aa', kind=c_int32_t)\n    integer(c_int32_t) :: LightGoldenrodYellow = int(Z'fafad2', kind=c_int32_t)\n    integer(c_int32_t) :: LightYellow = int(Z'ffffe0', kind=c_int32_t)\n    integer(c_int32_t) :: Yellow = int(Z'ffff00', kind=c_int32_t)\n    integer(c_int32_t) :: Gold = int(Z'ffd700', kind=c_int32_t)\n    integer(c_int32_t) :: LightGoldenrod = int(Z'eedd82', kind=c_int32_t)\n    integer(c_int32_t) :: Goldenrod = int(Z'daa520', kind=c_int32_t)\n    integer(c_int32_t) :: DarkGoldenrod = int(Z'b8860b', kind=c_int32_t)\n    integer(c_int32_t) :: RosyBrown = int(Z'bc8f8f', kind=c_int32_t)\n    integer(c_int32_t) :: IndianRed = int(Z'cd5c5c', kind=c_int32_t)\n    integer(c_int32_t) :: SaddleBrown = int(Z'8b4513', kind=c_int32_t)\n    integer(c_int32_t) :: Sienna = int(Z'a0522d', kind=c_int32_t)\n    integer(c_int32_t) :: Peru = int(Z'cd853f', kind=c_int32_t)\n    integer(c_int32_t) :: Burlywood = int(Z'deb887', kind=c_int32_t)\n    integer(c_int32_t) :: Beige = int(Z'f5f5dc', kind=c_int32_t)\n    integer(c_int32_t) :: Wheat = int(Z'f5deb3', kind=c_int32_t)\n    integer(c_int32_t) :: SandyBrown = int(Z'f4a460', kind=c_int32_t)\n    integer(c_int32_t) :: Tan = int(Z'd2b48c', kind=c_int32_t)\n    integer(c_int32_t) :: Chocolate = int(Z'd2691e', kind=c_int32_t)\n    integer(c_int32_t) :: Firebrick = int(Z'b22222', kind=c_int32_t)\n    integer(c_int32_t) :: Brown = int(Z'a52a2a', kind=c_int32_t)\n    integer(c_int32_t) :: DarkSalmon = int(Z'e9967a', kind=c_int32_t)\n    integer(c_int32_t) :: Salmon = int(Z'fa8072', kind=c_int32_t)\n    integer(c_int32_t) :: LightSalmon = int(Z'ffa07a', kind=c_int32_t)\n    integer(c_int32_t) :: Orange = int(Z'ffa500', kind=c_int32_t)\n    integer(c_int32_t) :: DarkOrange = int(Z'ff8c00', kind=c_int32_t)\n    integer(c_int32_t) :: Coral = int(Z'ff7f50', kind=c_int32_t)\n    integer(c_int32_t) :: LightCoral = int(Z'f08080', kind=c_int32_t)\n    integer(c_int32_t) :: Tomato = int(Z'ff6347', kind=c_int32_t)\n    integer(c_int32_t) :: OrangeRed = int(Z'ff4500', kind=c_int32_t)\n    integer(c_int32_t) :: Red = int(Z'ff0000', kind=c_int32_t)\n    integer(c_int32_t) :: HotPink = int(Z'ff69b4', kind=c_int32_t)\n    integer(c_int32_t) :: DeepPink = int(Z'ff1493', kind=c_int32_t)\n    integer(c_int32_t) :: Pink = int(Z'ffc0cb', kind=c_int32_t)\n    integer(c_int32_t) :: LightPink = int(Z'ffb6c1', kind=c_int32_t)\n    integer(c_int32_t) :: PaleVioletRed = int(Z'db7093', kind=c_int32_t)\n    integer(c_int32_t) :: Maroon = int(Z'b03060', kind=c_int32_t)\n    integer(c_int32_t) :: X11Maroon = int(Z'b03060', kind=c_int32_t)\n    integer(c_int32_t) :: WebMaroon = int(Z'800000', kind=c_int32_t)\n    integer(c_int32_t) :: MediumVioletRed = int(Z'c71585', kind=c_int32_t)\n    integer(c_int32_t) :: VioletRed = int(Z'd02090', kind=c_int32_t)\n    integer(c_int32_t) :: Magenta = int(Z'ff00ff', kind=c_int32_t)\n    integer(c_int32_t) :: Fuchsia = int(Z'ff00ff', kind=c_int32_t)\n    integer(c_int32_t) :: Violet = int(Z'ee82ee', kind=c_int32_t)\n    integer(c_int32_t) :: Plum = int(Z'dda0dd', kind=c_int32_t)\n    integer(c_int32_t) :: Orchid = int(Z'da70d6', kind=c_int32_t)\n    integer(c_int32_t) :: MediumOrchid = int(Z'ba55d3', kind=c_int32_t)\n    integer(c_int32_t) :: DarkOrchid = int(Z'9932cc', kind=c_int32_t)\n    integer(c_int32_t) :: DarkViolet = int(Z'9400d3', kind=c_int32_t)\n    integer(c_int32_t) :: BlueViolet = int(Z'8a2be2', kind=c_int32_t)\n    integer(c_int32_t) :: Purple = int(Z'a020f0', kind=c_int32_t)\n    integer(c_int32_t) :: X11Purple = int(Z'a020f0', kind=c_int32_t)\n    integer(c_int32_t) :: WebPurple = int(Z'800080', kind=c_int32_t)\n    integer(c_int32_t) :: MediumPurple = int(Z'9370db', kind=c_int32_t)\n    integer(c_int32_t) :: Thistle = int(Z'd8bfd8', kind=c_int32_t)\n    integer(c_int32_t) :: Snow1 = int(Z'fffafa', kind=c_int32_t)\n    integer(c_int32_t) :: Snow2 = int(Z'eee9e9', kind=c_int32_t)\n    integer(c_int32_t) :: Snow3 = int(Z'cdc9c9', kind=c_int32_t)\n    integer(c_int32_t) :: Snow4 = int(Z'8b8989', kind=c_int32_t)\n    integer(c_int32_t) :: Seashell1 = int(Z'fff5ee', kind=c_int32_t)\n    integer(c_int32_t) :: Seashell2 = int(Z'eee5de', kind=c_int32_t)\n    integer(c_int32_t) :: Seashell3 = int(Z'cdc5bf', kind=c_int32_t)\n    integer(c_int32_t) :: Seashell4 = int(Z'8b8682', kind=c_int32_t)\n    integer(c_int32_t) :: AntiqueWhite1 = int(Z'ffefdb', kind=c_int32_t)\n    integer(c_int32_t) :: AntiqueWhite2 = int(Z'eedfcc', kind=c_int32_t)\n    integer(c_int32_t) :: AntiqueWhite3 = int(Z'cdc0b0', kind=c_int32_t)\n    integer(c_int32_t) :: AntiqueWhite4 = int(Z'8b8378', kind=c_int32_t)\n    integer(c_int32_t) :: Bisque1 = int(Z'ffe4c4', kind=c_int32_t)\n    integer(c_int32_t) :: Bisque2 = int(Z'eed5b7', kind=c_int32_t)\n    integer(c_int32_t) :: Bisque3 = int(Z'cdb79e', kind=c_int32_t)\n    integer(c_int32_t) :: Bisque4 = int(Z'8b7d6b', kind=c_int32_t)\n    integer(c_int32_t) :: PeachPuff1 = int(Z'ffdab9', kind=c_int32_t)\n    integer(c_int32_t) :: PeachPuff2 = int(Z'eecbad', kind=c_int32_t)\n    integer(c_int32_t) :: PeachPuff3 = int(Z'cdaf95', kind=c_int32_t)\n    integer(c_int32_t) :: PeachPuff4 = int(Z'8b7765', kind=c_int32_t)\n    integer(c_int32_t) :: NavajoWhite1 = int(Z'ffdead', kind=c_int32_t)\n    integer(c_int32_t) :: NavajoWhite2 = int(Z'eecfa1', kind=c_int32_t)\n    integer(c_int32_t) :: NavajoWhite3 = int(Z'cdb38b', kind=c_int32_t)\n    integer(c_int32_t) :: NavajoWhite4 = int(Z'8b795e', kind=c_int32_t)\n    integer(c_int32_t) :: LemonChiffon1 = int(Z'fffacd', kind=c_int32_t)\n    integer(c_int32_t) :: LemonChiffon2 = int(Z'eee9bf', kind=c_int32_t)\n    integer(c_int32_t) :: LemonChiffon3 = int(Z'cdc9a5', kind=c_int32_t)\n    integer(c_int32_t) :: LemonChiffon4 = int(Z'8b8970', kind=c_int32_t)\n    integer(c_int32_t) :: Cornsilk1 = int(Z'fff8dc', kind=c_int32_t)\n    integer(c_int32_t) :: Cornsilk2 = int(Z'eee8cd', kind=c_int32_t)\n    integer(c_int32_t) :: Cornsilk3 = int(Z'cdc8b1', kind=c_int32_t)\n    integer(c_int32_t) :: Cornsilk4 = int(Z'8b8878', kind=c_int32_t)\n    integer(c_int32_t) :: Ivory1 = int(Z'fffff0', kind=c_int32_t)\n    integer(c_int32_t) :: Ivory2 = int(Z'eeeee0', kind=c_int32_t)\n    integer(c_int32_t) :: Ivory3 = int(Z'cdcdc1', kind=c_int32_t)\n    integer(c_int32_t) :: Ivory4 = int(Z'8b8b83', kind=c_int32_t)\n    integer(c_int32_t) :: Honeydew1 = int(Z'f0fff0', kind=c_int32_t)\n    integer(c_int32_t) :: Honeydew2 = int(Z'e0eee0', kind=c_int32_t)\n    integer(c_int32_t) :: Honeydew3 = int(Z'c1cdc1', kind=c_int32_t)\n    integer(c_int32_t) :: Honeydew4 = int(Z'838b83', kind=c_int32_t)\n    integer(c_int32_t) :: LavenderBlush1 = int(Z'fff0f5', kind=c_int32_t)\n    integer(c_int32_t) :: LavenderBlush2 = int(Z'eee0e5', kind=c_int32_t)\n    integer(c_int32_t) :: LavenderBlush3 = int(Z'cdc1c5', kind=c_int32_t)\n    integer(c_int32_t) :: LavenderBlush4 = int(Z'8b8386', kind=c_int32_t)\n    integer(c_int32_t) :: MistyRose1 = int(Z'ffe4e1', kind=c_int32_t)\n    integer(c_int32_t) :: MistyRose2 = int(Z'eed5d2', kind=c_int32_t)\n    integer(c_int32_t) :: MistyRose3 = int(Z'cdb7b5', kind=c_int32_t)\n    integer(c_int32_t) :: MistyRose4 = int(Z'8b7d7b', kind=c_int32_t)\n    integer(c_int32_t) :: Azure1 = int(Z'f0ffff', kind=c_int32_t)\n    integer(c_int32_t) :: Azure2 = int(Z'e0eeee', kind=c_int32_t)\n    integer(c_int32_t) :: Azure3 = int(Z'c1cdcd', kind=c_int32_t)\n    integer(c_int32_t) :: Azure4 = int(Z'838b8b', kind=c_int32_t)\n    integer(c_int32_t) :: SlateBlue1 = int(Z'836fff', kind=c_int32_t)\n    integer(c_int32_t) :: SlateBlue2 = int(Z'7a67ee', kind=c_int32_t)\n    integer(c_int32_t) :: SlateBlue3 = int(Z'6959cd', kind=c_int32_t)\n    integer(c_int32_t) :: SlateBlue4 = int(Z'473c8b', kind=c_int32_t)\n    integer(c_int32_t) :: RoyalBlue1 = int(Z'4876ff', kind=c_int32_t)\n    integer(c_int32_t) :: RoyalBlue2 = int(Z'436eee', kind=c_int32_t)\n    integer(c_int32_t) :: RoyalBlue3 = int(Z'3a5fcd', kind=c_int32_t)\n    integer(c_int32_t) :: RoyalBlue4 = int(Z'27408b', kind=c_int32_t)\n    integer(c_int32_t) :: Blue1 = int(Z'0000ff', kind=c_int32_t)\n    integer(c_int32_t) :: Blue2 = int(Z'0000ee', kind=c_int32_t)\n    integer(c_int32_t) :: Blue3 = int(Z'0000cd', kind=c_int32_t)\n    integer(c_int32_t) :: Blue4 = int(Z'00008b', kind=c_int32_t)\n    integer(c_int32_t) :: DodgerBlue1 = int(Z'1e90ff', kind=c_int32_t)\n    integer(c_int32_t) :: DodgerBlue2 = int(Z'1c86ee', kind=c_int32_t)\n    integer(c_int32_t) :: DodgerBlue3 = int(Z'1874cd', kind=c_int32_t)\n    integer(c_int32_t) :: DodgerBlue4 = int(Z'104e8b', kind=c_int32_t)\n    integer(c_int32_t) :: SteelBlue1 = int(Z'63b8ff', kind=c_int32_t)\n    integer(c_int32_t) :: SteelBlue2 = int(Z'5cacee', kind=c_int32_t)\n    integer(c_int32_t) :: SteelBlue3 = int(Z'4f94cd', kind=c_int32_t)\n    integer(c_int32_t) :: SteelBlue4 = int(Z'36648b', kind=c_int32_t)\n    integer(c_int32_t) :: DeepSkyBlue1 = int(Z'00bfff', kind=c_int32_t)\n    integer(c_int32_t) :: DeepSkyBlue2 = int(Z'00b2ee', kind=c_int32_t)\n    integer(c_int32_t) :: DeepSkyBlue3 = int(Z'009acd', kind=c_int32_t)\n    integer(c_int32_t) :: DeepSkyBlue4 = int(Z'00688b', kind=c_int32_t)\n    integer(c_int32_t) :: SkyBlue1 = int(Z'87ceff', kind=c_int32_t)\n    integer(c_int32_t) :: SkyBlue2 = int(Z'7ec0ee', kind=c_int32_t)\n    integer(c_int32_t) :: SkyBlue3 = int(Z'6ca6cd', kind=c_int32_t)\n    integer(c_int32_t) :: SkyBlue4 = int(Z'4a708b', kind=c_int32_t)\n    integer(c_int32_t) :: LightSkyBlue1 = int(Z'b0e2ff', kind=c_int32_t)\n    integer(c_int32_t) :: LightSkyBlue2 = int(Z'a4d3ee', kind=c_int32_t)\n    integer(c_int32_t) :: LightSkyBlue3 = int(Z'8db6cd', kind=c_int32_t)\n    integer(c_int32_t) :: LightSkyBlue4 = int(Z'607b8b', kind=c_int32_t)\n    integer(c_int32_t) :: SlateGray1 = int(Z'c6e2ff', kind=c_int32_t)\n    integer(c_int32_t) :: SlateGray2 = int(Z'b9d3ee', kind=c_int32_t)\n    integer(c_int32_t) :: SlateGray3 = int(Z'9fb6cd', kind=c_int32_t)\n    integer(c_int32_t) :: SlateGray4 = int(Z'6c7b8b', kind=c_int32_t)\n    integer(c_int32_t) :: LightSteelBlue1 = int(Z'cae1ff', kind=c_int32_t)\n    integer(c_int32_t) :: LightSteelBlue2 = int(Z'bcd2ee', kind=c_int32_t)\n    integer(c_int32_t) :: LightSteelBlue3 = int(Z'a2b5cd', kind=c_int32_t)\n    integer(c_int32_t) :: LightSteelBlue4 = int(Z'6e7b8b', kind=c_int32_t)\n    integer(c_int32_t) :: LightBlue1 = int(Z'bfefff', kind=c_int32_t)\n    integer(c_int32_t) :: LightBlue2 = int(Z'b2dfee', kind=c_int32_t)\n    integer(c_int32_t) :: LightBlue3 = int(Z'9ac0cd', kind=c_int32_t)\n    integer(c_int32_t) :: LightBlue4 = int(Z'68838b', kind=c_int32_t)\n    integer(c_int32_t) :: LightCyan1 = int(Z'e0ffff', kind=c_int32_t)\n    integer(c_int32_t) :: LightCyan2 = int(Z'd1eeee', kind=c_int32_t)\n    integer(c_int32_t) :: LightCyan3 = int(Z'b4cdcd', kind=c_int32_t)\n    integer(c_int32_t) :: LightCyan4 = int(Z'7a8b8b', kind=c_int32_t)\n    integer(c_int32_t) :: PaleTurquoise1 = int(Z'bbffff', kind=c_int32_t)\n    integer(c_int32_t) :: PaleTurquoise2 = int(Z'aeeeee', kind=c_int32_t)\n    integer(c_int32_t) :: PaleTurquoise3 = int(Z'96cdcd', kind=c_int32_t)\n    integer(c_int32_t) :: PaleTurquoise4 = int(Z'668b8b', kind=c_int32_t)\n    integer(c_int32_t) :: CadetBlue1 = int(Z'98f5ff', kind=c_int32_t)\n    integer(c_int32_t) :: CadetBlue2 = int(Z'8ee5ee', kind=c_int32_t)\n    integer(c_int32_t) :: CadetBlue3 = int(Z'7ac5cd', kind=c_int32_t)\n    integer(c_int32_t) :: CadetBlue4 = int(Z'53868b', kind=c_int32_t)\n    integer(c_int32_t) :: Turquoise1 = int(Z'00f5ff', kind=c_int32_t)\n    integer(c_int32_t) :: Turquoise2 = int(Z'00e5ee', kind=c_int32_t)\n    integer(c_int32_t) :: Turquoise3 = int(Z'00c5cd', kind=c_int32_t)\n    integer(c_int32_t) :: Turquoise4 = int(Z'00868b', kind=c_int32_t)\n    integer(c_int32_t) :: Cyan1 = int(Z'00ffff', kind=c_int32_t)\n    integer(c_int32_t) :: Cyan2 = int(Z'00eeee', kind=c_int32_t)\n    integer(c_int32_t) :: Cyan3 = int(Z'00cdcd', kind=c_int32_t)\n    integer(c_int32_t) :: Cyan4 = int(Z'008b8b', kind=c_int32_t)\n    integer(c_int32_t) :: DarkSlateGray1 = int(Z'97ffff', kind=c_int32_t)\n    integer(c_int32_t) :: DarkSlateGray2 = int(Z'8deeee', kind=c_int32_t)\n    integer(c_int32_t) :: DarkSlateGray3 = int(Z'79cdcd', kind=c_int32_t)\n    integer(c_int32_t) :: DarkSlateGray4 = int(Z'528b8b', kind=c_int32_t)\n    integer(c_int32_t) :: Aquamarine1 = int(Z'7fffd4', kind=c_int32_t)\n    integer(c_int32_t) :: Aquamarine2 = int(Z'76eec6', kind=c_int32_t)\n    integer(c_int32_t) :: Aquamarine3 = int(Z'66cdaa', kind=c_int32_t)\n    integer(c_int32_t) :: Aquamarine4 = int(Z'458b74', kind=c_int32_t)\n    integer(c_int32_t) :: DarkSeaGreen1 = int(Z'c1ffc1', kind=c_int32_t)\n    integer(c_int32_t) :: DarkSeaGreen2 = int(Z'b4eeb4', kind=c_int32_t)\n    integer(c_int32_t) :: DarkSeaGreen3 = int(Z'9bcd9b', kind=c_int32_t)\n    integer(c_int32_t) :: DarkSeaGreen4 = int(Z'698b69', kind=c_int32_t)\n    integer(c_int32_t) :: SeaGreen1 = int(Z'54ff9f', kind=c_int32_t)\n    integer(c_int32_t) :: SeaGreen2 = int(Z'4eee94', kind=c_int32_t)\n    integer(c_int32_t) :: SeaGreen3 = int(Z'43cd80', kind=c_int32_t)\n    integer(c_int32_t) :: SeaGreen4 = int(Z'2e8b57', kind=c_int32_t)\n    integer(c_int32_t) :: PaleGreen1 = int(Z'9aff9a', kind=c_int32_t)\n    integer(c_int32_t) :: PaleGreen2 = int(Z'90ee90', kind=c_int32_t)\n    integer(c_int32_t) :: PaleGreen3 = int(Z'7ccd7c', kind=c_int32_t)\n    integer(c_int32_t) :: PaleGreen4 = int(Z'548b54', kind=c_int32_t)\n    integer(c_int32_t) :: SpringGreen1 = int(Z'00ff7f', kind=c_int32_t)\n    integer(c_int32_t) :: SpringGreen2 = int(Z'00ee76', kind=c_int32_t)\n    integer(c_int32_t) :: SpringGreen3 = int(Z'00cd66', kind=c_int32_t)\n    integer(c_int32_t) :: SpringGreen4 = int(Z'008b45', kind=c_int32_t)\n    integer(c_int32_t) :: Green1 = int(Z'00ff00', kind=c_int32_t)\n    integer(c_int32_t) :: Green2 = int(Z'00ee00', kind=c_int32_t)\n    integer(c_int32_t) :: Green3 = int(Z'00cd00', kind=c_int32_t)\n    integer(c_int32_t) :: Green4 = int(Z'008b00', kind=c_int32_t)\n    integer(c_int32_t) :: Chartreuse1 = int(Z'7fff00', kind=c_int32_t)\n    integer(c_int32_t) :: Chartreuse2 = int(Z'76ee00', kind=c_int32_t)\n    integer(c_int32_t) :: Chartreuse3 = int(Z'66cd00', kind=c_int32_t)\n    integer(c_int32_t) :: Chartreuse4 = int(Z'458b00', kind=c_int32_t)\n    integer(c_int32_t) :: OliveDrab1 = int(Z'c0ff3e', kind=c_int32_t)\n    integer(c_int32_t) :: OliveDrab2 = int(Z'b3ee3a', kind=c_int32_t)\n    integer(c_int32_t) :: OliveDrab3 = int(Z'9acd32', kind=c_int32_t)\n    integer(c_int32_t) :: OliveDrab4 = int(Z'698b22', kind=c_int32_t)\n    integer(c_int32_t) :: DarkOliveGreen1 = int(Z'caff70', kind=c_int32_t)\n    integer(c_int32_t) :: DarkOliveGreen2 = int(Z'bcee68', kind=c_int32_t)\n    integer(c_int32_t) :: DarkOliveGreen3 = int(Z'a2cd5a', kind=c_int32_t)\n    integer(c_int32_t) :: DarkOliveGreen4 = int(Z'6e8b3d', kind=c_int32_t)\n    integer(c_int32_t) :: Khaki1 = int(Z'fff68f', kind=c_int32_t)\n    integer(c_int32_t) :: Khaki2 = int(Z'eee685', kind=c_int32_t)\n    integer(c_int32_t) :: Khaki3 = int(Z'cdc673', kind=c_int32_t)\n    integer(c_int32_t) :: Khaki4 = int(Z'8b864e', kind=c_int32_t)\n    integer(c_int32_t) :: LightGoldenrod1 = int(Z'ffec8b', kind=c_int32_t)\n    integer(c_int32_t) :: LightGoldenrod2 = int(Z'eedc82', kind=c_int32_t)\n    integer(c_int32_t) :: LightGoldenrod3 = int(Z'cdbe70', kind=c_int32_t)\n    integer(c_int32_t) :: LightGoldenrod4 = int(Z'8b814c', kind=c_int32_t)\n    integer(c_int32_t) :: LightYellow1 = int(Z'ffffe0', kind=c_int32_t)\n    integer(c_int32_t) :: LightYellow2 = int(Z'eeeed1', kind=c_int32_t)\n    integer(c_int32_t) :: LightYellow3 = int(Z'cdcdb4', kind=c_int32_t)\n    integer(c_int32_t) :: LightYellow4 = int(Z'8b8b7a', kind=c_int32_t)\n    integer(c_int32_t) :: Yellow1 = int(Z'ffff00', kind=c_int32_t)\n    integer(c_int32_t) :: Yellow2 = int(Z'eeee00', kind=c_int32_t)\n    integer(c_int32_t) :: Yellow3 = int(Z'cdcd00', kind=c_int32_t)\n    integer(c_int32_t) :: Yellow4 = int(Z'8b8b00', kind=c_int32_t)\n    integer(c_int32_t) :: Gold1 = int(Z'ffd700', kind=c_int32_t)\n    integer(c_int32_t) :: Gold2 = int(Z'eec900', kind=c_int32_t)\n    integer(c_int32_t) :: Gold3 = int(Z'cdad00', kind=c_int32_t)\n    integer(c_int32_t) :: Gold4 = int(Z'8b7500', kind=c_int32_t)\n    integer(c_int32_t) :: Goldenrod1 = int(Z'ffc125', kind=c_int32_t)\n    integer(c_int32_t) :: Goldenrod2 = int(Z'eeb422', kind=c_int32_t)\n    integer(c_int32_t) :: Goldenrod3 = int(Z'cd9b1d', kind=c_int32_t)\n    integer(c_int32_t) :: Goldenrod4 = int(Z'8b6914', kind=c_int32_t)\n    integer(c_int32_t) :: DarkGoldenrod1 = int(Z'ffb90f', kind=c_int32_t)\n    integer(c_int32_t) :: DarkGoldenrod2 = int(Z'eead0e', kind=c_int32_t)\n    integer(c_int32_t) :: DarkGoldenrod3 = int(Z'cd950c', kind=c_int32_t)\n    integer(c_int32_t) :: DarkGoldenrod4 = int(Z'8b6508', kind=c_int32_t)\n    integer(c_int32_t) :: RosyBrown1 = int(Z'ffc1c1', kind=c_int32_t)\n    integer(c_int32_t) :: RosyBrown2 = int(Z'eeb4b4', kind=c_int32_t)\n    integer(c_int32_t) :: RosyBrown3 = int(Z'cd9b9b', kind=c_int32_t)\n    integer(c_int32_t) :: RosyBrown4 = int(Z'8b6969', kind=c_int32_t)\n    integer(c_int32_t) :: IndianRed1 = int(Z'ff6a6a', kind=c_int32_t)\n    integer(c_int32_t) :: IndianRed2 = int(Z'ee6363', kind=c_int32_t)\n    integer(c_int32_t) :: IndianRed3 = int(Z'cd5555', kind=c_int32_t)\n    integer(c_int32_t) :: IndianRed4 = int(Z'8b3a3a', kind=c_int32_t)\n    integer(c_int32_t) :: Sienna1 = int(Z'ff8247', kind=c_int32_t)\n    integer(c_int32_t) :: Sienna2 = int(Z'ee7942', kind=c_int32_t)\n    integer(c_int32_t) :: Sienna3 = int(Z'cd6839', kind=c_int32_t)\n    integer(c_int32_t) :: Sienna4 = int(Z'8b4726', kind=c_int32_t)\n    integer(c_int32_t) :: Burlywood1 = int(Z'ffd39b', kind=c_int32_t)\n    integer(c_int32_t) :: Burlywood2 = int(Z'eec591', kind=c_int32_t)\n    integer(c_int32_t) :: Burlywood3 = int(Z'cdaa7d', kind=c_int32_t)\n    integer(c_int32_t) :: Burlywood4 = int(Z'8b7355', kind=c_int32_t)\n    integer(c_int32_t) :: Wheat1 = int(Z'ffe7ba', kind=c_int32_t)\n    integer(c_int32_t) :: Wheat2 = int(Z'eed8ae', kind=c_int32_t)\n    integer(c_int32_t) :: Wheat3 = int(Z'cdba96', kind=c_int32_t)\n    integer(c_int32_t) :: Wheat4 = int(Z'8b7e66', kind=c_int32_t)\n    integer(c_int32_t) :: Tan1 = int(Z'ffa54f', kind=c_int32_t)\n    integer(c_int32_t) :: Tan2 = int(Z'ee9a49', kind=c_int32_t)\n    integer(c_int32_t) :: Tan3 = int(Z'cd853f', kind=c_int32_t)\n    integer(c_int32_t) :: Tan4 = int(Z'8b5a2b', kind=c_int32_t)\n    integer(c_int32_t) :: Chocolate1 = int(Z'ff7f24', kind=c_int32_t)\n    integer(c_int32_t) :: Chocolate2 = int(Z'ee7621', kind=c_int32_t)\n    integer(c_int32_t) :: Chocolate3 = int(Z'cd661d', kind=c_int32_t)\n    integer(c_int32_t) :: Chocolate4 = int(Z'8b4513', kind=c_int32_t)\n    integer(c_int32_t) :: Firebrick1 = int(Z'ff3030', kind=c_int32_t)\n    integer(c_int32_t) :: Firebrick2 = int(Z'ee2c2c', kind=c_int32_t)\n    integer(c_int32_t) :: Firebrick3 = int(Z'cd2626', kind=c_int32_t)\n    integer(c_int32_t) :: Firebrick4 = int(Z'8b1a1a', kind=c_int32_t)\n    integer(c_int32_t) :: Brown1 = int(Z'ff4040', kind=c_int32_t)\n    integer(c_int32_t) :: Brown2 = int(Z'ee3b3b', kind=c_int32_t)\n    integer(c_int32_t) :: Brown3 = int(Z'cd3333', kind=c_int32_t)\n    integer(c_int32_t) :: Brown4 = int(Z'8b2323', kind=c_int32_t)\n    integer(c_int32_t) :: Salmon1 = int(Z'ff8c69', kind=c_int32_t)\n    integer(c_int32_t) :: Salmon2 = int(Z'ee8262', kind=c_int32_t)\n    integer(c_int32_t) :: Salmon3 = int(Z'cd7054', kind=c_int32_t)\n    integer(c_int32_t) :: Salmon4 = int(Z'8b4c39', kind=c_int32_t)\n    integer(c_int32_t) :: LightSalmon1 = int(Z'ffa07a', kind=c_int32_t)\n    integer(c_int32_t) :: LightSalmon2 = int(Z'ee9572', kind=c_int32_t)\n    integer(c_int32_t) :: LightSalmon3 = int(Z'cd8162', kind=c_int32_t)\n    integer(c_int32_t) :: LightSalmon4 = int(Z'8b5742', kind=c_int32_t)\n    integer(c_int32_t) :: Orange1 = int(Z'ffa500', kind=c_int32_t)\n    integer(c_int32_t) :: Orange2 = int(Z'ee9a00', kind=c_int32_t)\n    integer(c_int32_t) :: Orange3 = int(Z'cd8500', kind=c_int32_t)\n    integer(c_int32_t) :: Orange4 = int(Z'8b5a00', kind=c_int32_t)\n    integer(c_int32_t) :: DarkOrange1 = int(Z'ff7f00', kind=c_int32_t)\n    integer(c_int32_t) :: DarkOrange2 = int(Z'ee7600', kind=c_int32_t)\n    integer(c_int32_t) :: DarkOrange3 = int(Z'cd6600', kind=c_int32_t)\n    integer(c_int32_t) :: DarkOrange4 = int(Z'8b4500', kind=c_int32_t)\n    integer(c_int32_t) :: Coral1 = int(Z'ff7256', kind=c_int32_t)\n    integer(c_int32_t) :: Coral2 = int(Z'ee6a50', kind=c_int32_t)\n    integer(c_int32_t) :: Coral3 = int(Z'cd5b45', kind=c_int32_t)\n    integer(c_int32_t) :: Coral4 = int(Z'8b3e2f', kind=c_int32_t)\n    integer(c_int32_t) :: Tomato1 = int(Z'ff6347', kind=c_int32_t)\n    integer(c_int32_t) :: Tomato2 = int(Z'ee5c42', kind=c_int32_t)\n    integer(c_int32_t) :: Tomato3 = int(Z'cd4f39', kind=c_int32_t)\n    integer(c_int32_t) :: Tomato4 = int(Z'8b3626', kind=c_int32_t)\n    integer(c_int32_t) :: OrangeRed1 = int(Z'ff4500', kind=c_int32_t)\n    integer(c_int32_t) :: OrangeRed2 = int(Z'ee4000', kind=c_int32_t)\n    integer(c_int32_t) :: OrangeRed3 = int(Z'cd3700', kind=c_int32_t)\n    integer(c_int32_t) :: OrangeRed4 = int(Z'8b2500', kind=c_int32_t)\n    integer(c_int32_t) :: Red1 = int(Z'ff0000', kind=c_int32_t)\n    integer(c_int32_t) :: Red2 = int(Z'ee0000', kind=c_int32_t)\n    integer(c_int32_t) :: Red3 = int(Z'cd0000', kind=c_int32_t)\n    integer(c_int32_t) :: Red4 = int(Z'8b0000', kind=c_int32_t)\n    integer(c_int32_t) :: DeepPink1 = int(Z'ff1493', kind=c_int32_t)\n    integer(c_int32_t) :: DeepPink2 = int(Z'ee1289', kind=c_int32_t)\n    integer(c_int32_t) :: DeepPink3 = int(Z'cd1076', kind=c_int32_t)\n    integer(c_int32_t) :: DeepPink4 = int(Z'8b0a50', kind=c_int32_t)\n    integer(c_int32_t) :: HotPink1 = int(Z'ff6eb4', kind=c_int32_t)\n    integer(c_int32_t) :: HotPink2 = int(Z'ee6aa7', kind=c_int32_t)\n    integer(c_int32_t) :: HotPink3 = int(Z'cd6090', kind=c_int32_t)\n    integer(c_int32_t) :: HotPink4 = int(Z'8b3a62', kind=c_int32_t)\n    integer(c_int32_t) :: Pink1 = int(Z'ffb5c5', kind=c_int32_t)\n    integer(c_int32_t) :: Pink2 = int(Z'eea9b8', kind=c_int32_t)\n    integer(c_int32_t) :: Pink3 = int(Z'cd919e', kind=c_int32_t)\n    integer(c_int32_t) :: Pink4 = int(Z'8b636c', kind=c_int32_t)\n    integer(c_int32_t) :: LightPink1 = int(Z'ffaeb9', kind=c_int32_t)\n    integer(c_int32_t) :: LightPink2 = int(Z'eea2ad', kind=c_int32_t)\n    integer(c_int32_t) :: LightPink3 = int(Z'cd8c95', kind=c_int32_t)\n    integer(c_int32_t) :: LightPink4 = int(Z'8b5f65', kind=c_int32_t)\n    integer(c_int32_t) :: PaleVioletRed1 = int(Z'ff82ab', kind=c_int32_t)\n    integer(c_int32_t) :: PaleVioletRed2 = int(Z'ee799f', kind=c_int32_t)\n    integer(c_int32_t) :: PaleVioletRed3 = int(Z'cd6889', kind=c_int32_t)\n    integer(c_int32_t) :: PaleVioletRed4 = int(Z'8b475d', kind=c_int32_t)\n    integer(c_int32_t) :: Maroon1 = int(Z'ff34b3', kind=c_int32_t)\n    integer(c_int32_t) :: Maroon2 = int(Z'ee30a7', kind=c_int32_t)\n    integer(c_int32_t) :: Maroon3 = int(Z'cd2990', kind=c_int32_t)\n    integer(c_int32_t) :: Maroon4 = int(Z'8b1c62', kind=c_int32_t)\n    integer(c_int32_t) :: VioletRed1 = int(Z'ff3e96', kind=c_int32_t)\n    integer(c_int32_t) :: VioletRed2 = int(Z'ee3a8c', kind=c_int32_t)\n    integer(c_int32_t) :: VioletRed3 = int(Z'cd3278', kind=c_int32_t)\n    integer(c_int32_t) :: VioletRed4 = int(Z'8b2252', kind=c_int32_t)\n    integer(c_int32_t) :: Magenta1 = int(Z'ff00ff', kind=c_int32_t)\n    integer(c_int32_t) :: Magenta2 = int(Z'ee00ee', kind=c_int32_t)\n    integer(c_int32_t) :: Magenta3 = int(Z'cd00cd', kind=c_int32_t)\n    integer(c_int32_t) :: Magenta4 = int(Z'8b008b', kind=c_int32_t)\n    integer(c_int32_t) :: Orchid1 = int(Z'ff83fa', kind=c_int32_t)\n    integer(c_int32_t) :: Orchid2 = int(Z'ee7ae9', kind=c_int32_t)\n    integer(c_int32_t) :: Orchid3 = int(Z'cd69c9', kind=c_int32_t)\n    integer(c_int32_t) :: Orchid4 = int(Z'8b4789', kind=c_int32_t)\n    integer(c_int32_t) :: Plum1 = int(Z'ffbbff', kind=c_int32_t)\n    integer(c_int32_t) :: Plum2 = int(Z'eeaeee', kind=c_int32_t)\n    integer(c_int32_t) :: Plum3 = int(Z'cd96cd', kind=c_int32_t)\n    integer(c_int32_t) :: Plum4 = int(Z'8b668b', kind=c_int32_t)\n    integer(c_int32_t) :: MediumOrchid1 = int(Z'e066ff', kind=c_int32_t)\n    integer(c_int32_t) :: MediumOrchid2 = int(Z'd15fee', kind=c_int32_t)\n    integer(c_int32_t) :: MediumOrchid3 = int(Z'b452cd', kind=c_int32_t)\n    integer(c_int32_t) :: MediumOrchid4 = int(Z'7a378b', kind=c_int32_t)\n    integer(c_int32_t) :: DarkOrchid1 = int(Z'bf3eff', kind=c_int32_t)\n    integer(c_int32_t) :: DarkOrchid2 = int(Z'b23aee', kind=c_int32_t)\n    integer(c_int32_t) :: DarkOrchid3 = int(Z'9a32cd', kind=c_int32_t)\n    integer(c_int32_t) :: DarkOrchid4 = int(Z'68228b', kind=c_int32_t)\n    integer(c_int32_t) :: Purple1 = int(Z'9b30ff', kind=c_int32_t)\n    integer(c_int32_t) :: Purple2 = int(Z'912cee', kind=c_int32_t)\n    integer(c_int32_t) :: Purple3 = int(Z'7d26cd', kind=c_int32_t)\n    integer(c_int32_t) :: Purple4 = int(Z'551a8b', kind=c_int32_t)\n    integer(c_int32_t) :: MediumPurple1 = int(Z'ab82ff', kind=c_int32_t)\n    integer(c_int32_t) :: MediumPurple2 = int(Z'9f79ee', kind=c_int32_t)\n    integer(c_int32_t) :: MediumPurple3 = int(Z'8968cd', kind=c_int32_t)\n    integer(c_int32_t) :: MediumPurple4 = int(Z'5d478b', kind=c_int32_t)\n    integer(c_int32_t) :: Thistle1 = int(Z'ffe1ff', kind=c_int32_t)\n    integer(c_int32_t) :: Thistle2 = int(Z'eed2ee', kind=c_int32_t)\n    integer(c_int32_t) :: Thistle3 = int(Z'cdb5cd', kind=c_int32_t)\n    integer(c_int32_t) :: Thistle4 = int(Z'8b7b8b', kind=c_int32_t)\n    integer(c_int32_t) :: Gray0 = int(Z'000000', kind=c_int32_t)\n    integer(c_int32_t) :: Grey0 = int(Z'000000', kind=c_int32_t)\n    integer(c_int32_t) :: Gray1 = int(Z'030303', kind=c_int32_t)\n    integer(c_int32_t) :: Grey1 = int(Z'030303', kind=c_int32_t)\n    integer(c_int32_t) :: Gray2 = int(Z'050505', kind=c_int32_t)\n    integer(c_int32_t) :: Grey2 = int(Z'050505', kind=c_int32_t)\n    integer(c_int32_t) :: Gray3 = int(Z'080808', kind=c_int32_t)\n    integer(c_int32_t) :: Grey3 = int(Z'080808', kind=c_int32_t)\n    integer(c_int32_t) :: Gray4 = int(Z'0a0a0a', kind=c_int32_t)\n    integer(c_int32_t) :: Grey4 = int(Z'0a0a0a', kind=c_int32_t)\n    integer(c_int32_t) :: Gray5 = int(Z'0d0d0d', kind=c_int32_t)\n    integer(c_int32_t) :: Grey5 = int(Z'0d0d0d', kind=c_int32_t)\n    integer(c_int32_t) :: Gray6 = int(Z'0f0f0f', kind=c_int32_t)\n    integer(c_int32_t) :: Grey6 = int(Z'0f0f0f', kind=c_int32_t)\n    integer(c_int32_t) :: Gray7 = int(Z'121212', kind=c_int32_t)\n    integer(c_int32_t) :: Grey7 = int(Z'121212', kind=c_int32_t)\n    integer(c_int32_t) :: Gray8 = int(Z'141414', kind=c_int32_t)\n    integer(c_int32_t) :: Grey8 = int(Z'141414', kind=c_int32_t)\n    integer(c_int32_t) :: Gray9 = int(Z'171717', kind=c_int32_t)\n    integer(c_int32_t) :: Grey9 = int(Z'171717', kind=c_int32_t)\n    integer(c_int32_t) :: Gray10 = int(Z'1a1a1a', kind=c_int32_t)\n    integer(c_int32_t) :: Grey10 = int(Z'1a1a1a', kind=c_int32_t)\n    integer(c_int32_t) :: Gray11 = int(Z'1c1c1c', kind=c_int32_t)\n    integer(c_int32_t) :: Grey11 = int(Z'1c1c1c', kind=c_int32_t)\n    integer(c_int32_t) :: Gray12 = int(Z'1f1f1f', kind=c_int32_t)\n    integer(c_int32_t) :: Grey12 = int(Z'1f1f1f', kind=c_int32_t)\n    integer(c_int32_t) :: Gray13 = int(Z'212121', kind=c_int32_t)\n    integer(c_int32_t) :: Grey13 = int(Z'212121', kind=c_int32_t)\n    integer(c_int32_t) :: Gray14 = int(Z'242424', kind=c_int32_t)\n    integer(c_int32_t) :: Grey14 = int(Z'242424', kind=c_int32_t)\n    integer(c_int32_t) :: Gray15 = int(Z'262626', kind=c_int32_t)\n    integer(c_int32_t) :: Grey15 = int(Z'262626', kind=c_int32_t)\n    integer(c_int32_t) :: Gray16 = int(Z'292929', kind=c_int32_t)\n    integer(c_int32_t) :: Grey16 = int(Z'292929', kind=c_int32_t)\n    integer(c_int32_t) :: Gray17 = int(Z'2b2b2b', kind=c_int32_t)\n    integer(c_int32_t) :: Grey17 = int(Z'2b2b2b', kind=c_int32_t)\n    integer(c_int32_t) :: Gray18 = int(Z'2e2e2e', kind=c_int32_t)\n    integer(c_int32_t) :: Grey18 = int(Z'2e2e2e', kind=c_int32_t)\n    integer(c_int32_t) :: Gray19 = int(Z'303030', kind=c_int32_t)\n    integer(c_int32_t) :: Grey19 = int(Z'303030', kind=c_int32_t)\n    integer(c_int32_t) :: Gray20 = int(Z'333333', kind=c_int32_t)\n    integer(c_int32_t) :: Grey20 = int(Z'333333', kind=c_int32_t)\n    integer(c_int32_t) :: Gray21 = int(Z'363636', kind=c_int32_t)\n    integer(c_int32_t) :: Grey21 = int(Z'363636', kind=c_int32_t)\n    integer(c_int32_t) :: Gray22 = int(Z'383838', kind=c_int32_t)\n    integer(c_int32_t) :: Grey22 = int(Z'383838', kind=c_int32_t)\n    integer(c_int32_t) :: Gray23 = int(Z'3b3b3b', kind=c_int32_t)\n    integer(c_int32_t) :: Grey23 = int(Z'3b3b3b', kind=c_int32_t)\n    integer(c_int32_t) :: Gray24 = int(Z'3d3d3d', kind=c_int32_t)\n    integer(c_int32_t) :: Grey24 = int(Z'3d3d3d', kind=c_int32_t)\n    integer(c_int32_t) :: Gray25 = int(Z'404040', kind=c_int32_t)\n    integer(c_int32_t) :: Grey25 = int(Z'404040', kind=c_int32_t)\n    integer(c_int32_t) :: Gray26 = int(Z'424242', kind=c_int32_t)\n    integer(c_int32_t) :: Grey26 = int(Z'424242', kind=c_int32_t)\n    integer(c_int32_t) :: Gray27 = int(Z'454545', kind=c_int32_t)\n    integer(c_int32_t) :: Grey27 = int(Z'454545', kind=c_int32_t)\n    integer(c_int32_t) :: Gray28 = int(Z'474747', kind=c_int32_t)\n    integer(c_int32_t) :: Grey28 = int(Z'474747', kind=c_int32_t)\n    integer(c_int32_t) :: Gray29 = int(Z'4a4a4a', kind=c_int32_t)\n    integer(c_int32_t) :: Grey29 = int(Z'4a4a4a', kind=c_int32_t)\n    integer(c_int32_t) :: Gray30 = int(Z'4d4d4d', kind=c_int32_t)\n    integer(c_int32_t) :: Grey30 = int(Z'4d4d4d', kind=c_int32_t)\n    integer(c_int32_t) :: Gray31 = int(Z'4f4f4f', kind=c_int32_t)\n    integer(c_int32_t) :: Grey31 = int(Z'4f4f4f', kind=c_int32_t)\n    integer(c_int32_t) :: Gray32 = int(Z'525252', kind=c_int32_t)\n    integer(c_int32_t) :: Grey32 = int(Z'525252', kind=c_int32_t)\n    integer(c_int32_t) :: Gray33 = int(Z'545454', kind=c_int32_t)\n    integer(c_int32_t) :: Grey33 = int(Z'545454', kind=c_int32_t)\n    integer(c_int32_t) :: Gray34 = int(Z'575757', kind=c_int32_t)\n    integer(c_int32_t) :: Grey34 = int(Z'575757', kind=c_int32_t)\n    integer(c_int32_t) :: Gray35 = int(Z'595959', kind=c_int32_t)\n    integer(c_int32_t) :: Grey35 = int(Z'595959', kind=c_int32_t)\n    integer(c_int32_t) :: Gray36 = int(Z'5c5c5c', kind=c_int32_t)\n    integer(c_int32_t) :: Grey36 = int(Z'5c5c5c', kind=c_int32_t)\n    integer(c_int32_t) :: Gray37 = int(Z'5e5e5e', kind=c_int32_t)\n    integer(c_int32_t) :: Grey37 = int(Z'5e5e5e', kind=c_int32_t)\n    integer(c_int32_t) :: Gray38 = int(Z'616161', kind=c_int32_t)\n    integer(c_int32_t) :: Grey38 = int(Z'616161', kind=c_int32_t)\n    integer(c_int32_t) :: Gray39 = int(Z'636363', kind=c_int32_t)\n    integer(c_int32_t) :: Grey39 = int(Z'636363', kind=c_int32_t)\n    integer(c_int32_t) :: Gray40 = int(Z'666666', kind=c_int32_t)\n    integer(c_int32_t) :: Grey40 = int(Z'666666', kind=c_int32_t)\n    integer(c_int32_t) :: Gray41 = int(Z'696969', kind=c_int32_t)\n    integer(c_int32_t) :: Grey41 = int(Z'696969', kind=c_int32_t)\n    integer(c_int32_t) :: Gray42 = int(Z'6b6b6b', kind=c_int32_t)\n    integer(c_int32_t) :: Grey42 = int(Z'6b6b6b', kind=c_int32_t)\n    integer(c_int32_t) :: Gray43 = int(Z'6e6e6e', kind=c_int32_t)\n    integer(c_int32_t) :: Grey43 = int(Z'6e6e6e', kind=c_int32_t)\n    integer(c_int32_t) :: Gray44 = int(Z'707070', kind=c_int32_t)\n    integer(c_int32_t) :: Grey44 = int(Z'707070', kind=c_int32_t)\n    integer(c_int32_t) :: Gray45 = int(Z'737373', kind=c_int32_t)\n    integer(c_int32_t) :: Grey45 = int(Z'737373', kind=c_int32_t)\n    integer(c_int32_t) :: Gray46 = int(Z'757575', kind=c_int32_t)\n    integer(c_int32_t) :: Grey46 = int(Z'757575', kind=c_int32_t)\n    integer(c_int32_t) :: Gray47 = int(Z'787878', kind=c_int32_t)\n    integer(c_int32_t) :: Grey47 = int(Z'787878', kind=c_int32_t)\n    integer(c_int32_t) :: Gray48 = int(Z'7a7a7a', kind=c_int32_t)\n    integer(c_int32_t) :: Grey48 = int(Z'7a7a7a', kind=c_int32_t)\n    integer(c_int32_t) :: Gray49 = int(Z'7d7d7d', kind=c_int32_t)\n    integer(c_int32_t) :: Grey49 = int(Z'7d7d7d', kind=c_int32_t)\n    integer(c_int32_t) :: Gray50 = int(Z'7f7f7f', kind=c_int32_t)\n    integer(c_int32_t) :: Grey50 = int(Z'7f7f7f', kind=c_int32_t)\n    integer(c_int32_t) :: Gray51 = int(Z'828282', kind=c_int32_t)\n    integer(c_int32_t) :: Grey51 = int(Z'828282', kind=c_int32_t)\n    integer(c_int32_t) :: Gray52 = int(Z'858585', kind=c_int32_t)\n    integer(c_int32_t) :: Grey52 = int(Z'858585', kind=c_int32_t)\n    integer(c_int32_t) :: Gray53 = int(Z'878787', kind=c_int32_t)\n    integer(c_int32_t) :: Grey53 = int(Z'878787', kind=c_int32_t)\n    integer(c_int32_t) :: Gray54 = int(Z'8a8a8a', kind=c_int32_t)\n    integer(c_int32_t) :: Grey54 = int(Z'8a8a8a', kind=c_int32_t)\n    integer(c_int32_t) :: Gray55 = int(Z'8c8c8c', kind=c_int32_t)\n    integer(c_int32_t) :: Grey55 = int(Z'8c8c8c', kind=c_int32_t)\n    integer(c_int32_t) :: Gray56 = int(Z'8f8f8f', kind=c_int32_t)\n    integer(c_int32_t) :: Grey56 = int(Z'8f8f8f', kind=c_int32_t)\n    integer(c_int32_t) :: Gray57 = int(Z'919191', kind=c_int32_t)\n    integer(c_int32_t) :: Grey57 = int(Z'919191', kind=c_int32_t)\n    integer(c_int32_t) :: Gray58 = int(Z'949494', kind=c_int32_t)\n    integer(c_int32_t) :: Grey58 = int(Z'949494', kind=c_int32_t)\n    integer(c_int32_t) :: Gray59 = int(Z'969696', kind=c_int32_t)\n    integer(c_int32_t) :: Grey59 = int(Z'969696', kind=c_int32_t)\n    integer(c_int32_t) :: Gray60 = int(Z'999999', kind=c_int32_t)\n    integer(c_int32_t) :: Grey60 = int(Z'999999', kind=c_int32_t)\n    integer(c_int32_t) :: Gray61 = int(Z'9c9c9c', kind=c_int32_t)\n    integer(c_int32_t) :: Grey61 = int(Z'9c9c9c', kind=c_int32_t)\n    integer(c_int32_t) :: Gray62 = int(Z'9e9e9e', kind=c_int32_t)\n    integer(c_int32_t) :: Grey62 = int(Z'9e9e9e', kind=c_int32_t)\n    integer(c_int32_t) :: Gray63 = int(Z'a1a1a1', kind=c_int32_t)\n    integer(c_int32_t) :: Grey63 = int(Z'a1a1a1', kind=c_int32_t)\n    integer(c_int32_t) :: Gray64 = int(Z'a3a3a3', kind=c_int32_t)\n    integer(c_int32_t) :: Grey64 = int(Z'a3a3a3', kind=c_int32_t)\n    integer(c_int32_t) :: Gray65 = int(Z'a6a6a6', kind=c_int32_t)\n    integer(c_int32_t) :: Grey65 = int(Z'a6a6a6', kind=c_int32_t)\n    integer(c_int32_t) :: Gray66 = int(Z'a8a8a8', kind=c_int32_t)\n    integer(c_int32_t) :: Grey66 = int(Z'a8a8a8', kind=c_int32_t)\n    integer(c_int32_t) :: Gray67 = int(Z'ababab', kind=c_int32_t)\n    integer(c_int32_t) :: Grey67 = int(Z'ababab', kind=c_int32_t)\n    integer(c_int32_t) :: Gray68 = int(Z'adadad', kind=c_int32_t)\n    integer(c_int32_t) :: Grey68 = int(Z'adadad', kind=c_int32_t)\n    integer(c_int32_t) :: Gray69 = int(Z'b0b0b0', kind=c_int32_t)\n    integer(c_int32_t) :: Grey69 = int(Z'b0b0b0', kind=c_int32_t)\n    integer(c_int32_t) :: Gray70 = int(Z'b3b3b3', kind=c_int32_t)\n    integer(c_int32_t) :: Grey70 = int(Z'b3b3b3', kind=c_int32_t)\n    integer(c_int32_t) :: Gray71 = int(Z'b5b5b5', kind=c_int32_t)\n    integer(c_int32_t) :: Grey71 = int(Z'b5b5b5', kind=c_int32_t)\n    integer(c_int32_t) :: Gray72 = int(Z'b8b8b8', kind=c_int32_t)\n    integer(c_int32_t) :: Grey72 = int(Z'b8b8b8', kind=c_int32_t)\n    integer(c_int32_t) :: Gray73 = int(Z'bababa', kind=c_int32_t)\n    integer(c_int32_t) :: Grey73 = int(Z'bababa', kind=c_int32_t)\n    integer(c_int32_t) :: Gray74 = int(Z'bdbdbd', kind=c_int32_t)\n    integer(c_int32_t) :: Grey74 = int(Z'bdbdbd', kind=c_int32_t)\n    integer(c_int32_t) :: Gray75 = int(Z'bfbfbf', kind=c_int32_t)\n    integer(c_int32_t) :: Grey75 = int(Z'bfbfbf', kind=c_int32_t)\n    integer(c_int32_t) :: Gray76 = int(Z'c2c2c2', kind=c_int32_t)\n    integer(c_int32_t) :: Grey76 = int(Z'c2c2c2', kind=c_int32_t)\n    integer(c_int32_t) :: Gray77 = int(Z'c4c4c4', kind=c_int32_t)\n    integer(c_int32_t) :: Grey77 = int(Z'c4c4c4', kind=c_int32_t)\n    integer(c_int32_t) :: Gray78 = int(Z'c7c7c7', kind=c_int32_t)\n    integer(c_int32_t) :: Grey78 = int(Z'c7c7c7', kind=c_int32_t)\n    integer(c_int32_t) :: Gray79 = int(Z'c9c9c9', kind=c_int32_t)\n    integer(c_int32_t) :: Grey79 = int(Z'c9c9c9', kind=c_int32_t)\n    integer(c_int32_t) :: Gray80 = int(Z'cccccc', kind=c_int32_t)\n    integer(c_int32_t) :: Grey80 = int(Z'cccccc', kind=c_int32_t)\n    integer(c_int32_t) :: Gray81 = int(Z'cfcfcf', kind=c_int32_t)\n    integer(c_int32_t) :: Grey81 = int(Z'cfcfcf', kind=c_int32_t)\n    integer(c_int32_t) :: Gray82 = int(Z'd1d1d1', kind=c_int32_t)\n    integer(c_int32_t) :: Grey82 = int(Z'd1d1d1', kind=c_int32_t)\n    integer(c_int32_t) :: Gray83 = int(Z'd4d4d4', kind=c_int32_t)\n    integer(c_int32_t) :: Grey83 = int(Z'd4d4d4', kind=c_int32_t)\n    integer(c_int32_t) :: Gray84 = int(Z'd6d6d6', kind=c_int32_t)\n    integer(c_int32_t) :: Grey84 = int(Z'd6d6d6', kind=c_int32_t)\n    integer(c_int32_t) :: Gray85 = int(Z'd9d9d9', kind=c_int32_t)\n    integer(c_int32_t) :: Grey85 = int(Z'd9d9d9', kind=c_int32_t)\n    integer(c_int32_t) :: Gray86 = int(Z'dbdbdb', kind=c_int32_t)\n    integer(c_int32_t) :: Grey86 = int(Z'dbdbdb', kind=c_int32_t)\n    integer(c_int32_t) :: Gray87 = int(Z'dedede', kind=c_int32_t)\n    integer(c_int32_t) :: Grey87 = int(Z'dedede', kind=c_int32_t)\n    integer(c_int32_t) :: Gray88 = int(Z'e0e0e0', kind=c_int32_t)\n    integer(c_int32_t) :: Grey88 = int(Z'e0e0e0', kind=c_int32_t)\n    integer(c_int32_t) :: Gray89 = int(Z'e3e3e3', kind=c_int32_t)\n    integer(c_int32_t) :: Grey89 = int(Z'e3e3e3', kind=c_int32_t)\n    integer(c_int32_t) :: Gray90 = int(Z'e5e5e5', kind=c_int32_t)\n    integer(c_int32_t) :: Grey90 = int(Z'e5e5e5', kind=c_int32_t)\n    integer(c_int32_t) :: Gray91 = int(Z'e8e8e8', kind=c_int32_t)\n    integer(c_int32_t) :: Grey91 = int(Z'e8e8e8', kind=c_int32_t)\n    integer(c_int32_t) :: Gray92 = int(Z'ebebeb', kind=c_int32_t)\n    integer(c_int32_t) :: Grey92 = int(Z'ebebeb', kind=c_int32_t)\n    integer(c_int32_t) :: Gray93 = int(Z'ededed', kind=c_int32_t)\n    integer(c_int32_t) :: Grey93 = int(Z'ededed', kind=c_int32_t)\n    integer(c_int32_t) :: Gray94 = int(Z'f0f0f0', kind=c_int32_t)\n    integer(c_int32_t) :: Grey94 = int(Z'f0f0f0', kind=c_int32_t)\n    integer(c_int32_t) :: Gray95 = int(Z'f2f2f2', kind=c_int32_t)\n    integer(c_int32_t) :: Grey95 = int(Z'f2f2f2', kind=c_int32_t)\n    integer(c_int32_t) :: Gray96 = int(Z'f5f5f5', kind=c_int32_t)\n    integer(c_int32_t) :: Grey96 = int(Z'f5f5f5', kind=c_int32_t)\n    integer(c_int32_t) :: Gray97 = int(Z'f7f7f7', kind=c_int32_t)\n    integer(c_int32_t) :: Grey97 = int(Z'f7f7f7', kind=c_int32_t)\n    integer(c_int32_t) :: Gray98 = int(Z'fafafa', kind=c_int32_t)\n    integer(c_int32_t) :: Grey98 = int(Z'fafafa', kind=c_int32_t)\n    integer(c_int32_t) :: Gray99 = int(Z'fcfcfc', kind=c_int32_t)\n    integer(c_int32_t) :: Grey99 = int(Z'fcfcfc', kind=c_int32_t)\n    integer(c_int32_t) :: Gray100 = int(Z'ffffff', kind=c_int32_t)\n    integer(c_int32_t) :: Grey100 = int(Z'ffffff', kind=c_int32_t)\n    integer(c_int32_t) :: DarkGrey = int(Z'a9a9a9', kind=c_int32_t)\n    integer(c_int32_t) :: DarkGray = int(Z'a9a9a9', kind=c_int32_t)\n    integer(c_int32_t) :: DarkBlue = int(Z'00008b', kind=c_int32_t)\n    integer(c_int32_t) :: DarkCyan = int(Z'008b8b', kind=c_int32_t)\n    integer(c_int32_t) :: DarkMagenta = int(Z'8b008b', kind=c_int32_t)\n    integer(c_int32_t) :: DarkRed = int(Z'8b0000', kind=c_int32_t)\n    integer(c_int32_t) :: LightGreen = int(Z'90ee90', kind=c_int32_t)\n    integer(c_int32_t) :: Crimson = int(Z'dc143c', kind=c_int32_t)\n    integer(c_int32_t) :: Indigo = int(Z'4b0082', kind=c_int32_t)\n    integer(c_int32_t) :: Olive = int(Z'808000', kind=c_int32_t)\n    integer(c_int32_t) :: RebeccaPurple = int(Z'663399', kind=c_int32_t)\n    integer(c_int32_t) :: Silver = int(Z'c0c0c0', kind=c_int32_t)\n    integer(c_int32_t) :: Teal = int(Z'008080', kind=c_int32_t)\n  end type\n\n  interface\n    subroutine impl_tracy_set_thread_name(name) bind(C, name=\"___tracy_set_thread_name\")\n      import\n      type(c_ptr), intent(in), value :: name\n    end subroutine impl_tracy_set_thread_name\n  end interface\n\n  type, bind(C) :: tracy_source_location_data\n    type(c_ptr) :: name\n    type(c_ptr) :: function\n    type(c_ptr) :: file\n    integer(c_int32_t) :: line\n    integer(c_int32_t) :: color\n  end type\n\n  type, bind(C) :: tracy_zone_context\n    integer(c_int32_t) :: id\n    integer(c_int32_t) :: active\n  end type\n\n  type, bind(C) :: tracy_gpu_time_data\n    integer(c_int64_t) :: gpuTime\n    integer(c_int16_t) :: queryId\n    integer(c_int8_t) :: context\n  end type\n\n  type, bind(C) :: tracy_gpu_zone_begin_data\n    integer(c_int64_t) :: srcloc\n    integer(c_int16_t) :: queryId\n    integer(c_int8_t) :: context\n  end type\n\n  type, bind(C) :: tracy_gpu_zone_begin_callstack_data\n    integer(c_int64_t) :: srcloc\n    integer(c_int32_t) :: depth\n    integer(c_int16_t) :: queryId\n    integer(c_int8_t) :: context\n  end type\n\n  type, bind(C) :: tracy_gpu_zone_end_data\n    integer(c_int16_t) :: queryId\n    integer(c_int8_t) :: context\n  end type\n\n  type, bind(C) :: tracy_gpu_new_context_data\n    integer(c_int64_t) :: gpuTime\n    real(c_float) :: period\n    integer(c_int8_t) :: context\n    integer(c_int8_t) :: flags\n    integer(c_int8_t) :: type\n  end type\n\n  type, bind(C) :: tracy_gpu_context_name_data\n    integer(c_int8_t) :: context\n    type(c_ptr) :: name\n    integer(c_int16_t) :: len\n  end type\n\n  type, bind(C) :: tracy_gpu_calibration_data\n    integer(c_int64_t) :: gpuTime\n    integer(c_int64_t) :: cpuDelta\n    integer(c_int8_t) :: context\n  end type\n\n  type, bind(C) :: tracy_gpu_time_sync_data\n    integer(c_int64_t) :: gpuTime\n    integer(c_int8_t) :: context\n  end type\n\n  ! tracy_lockable_context_data and related stuff is missed since Fortran does not have support of mutexes\n\n  interface\n    subroutine tracy_startup_profiler() bind(C, name=\"___tracy_startup_profiler\")\n    end subroutine tracy_startup_profiler\n    subroutine tracy_shutdown_profiler() bind(C, name=\"___tracy_shutdown_profiler\")\n    end subroutine tracy_shutdown_profiler\n    function impl_tracy_profiler_started() bind(C, name=\"___tracy_profiler_started\")\n      import\n      integer(c_int32_t) :: impl_tracy_profiler_started\n    end function impl_tracy_profiler_started\n  end interface\n\n  interface\n    function impl_tracy_alloc_srcloc(line, source, sourceSz, function_name, functionSz, color) &\n      bind(C, name=\"___tracy_alloc_srcloc\")\n      import\n      integer(c_int64_t) :: impl_tracy_alloc_srcloc\n      integer(c_int32_t), intent(in), value :: line\n      type(c_ptr), intent(in), value :: source\n      integer(c_size_t), intent(in), value :: sourceSz\n      type(c_ptr), intent(in), value :: function_name\n      integer(c_size_t), intent(in), value :: functionSz\n      integer(c_int32_t), intent(in), value :: color\n    end function impl_tracy_alloc_srcloc\n    function impl_tracy_alloc_srcloc_name(line, source, sourceSz, function_name, functionSz, zone_name, nameSz, color) &\n      bind(C, name=\"___tracy_alloc_srcloc_name\")\n      import\n      integer(c_int64_t) :: impl_tracy_alloc_srcloc_name\n      integer(c_int32_t), intent(in), value :: line\n      type(c_ptr), intent(in), value :: source\n      integer(c_size_t), intent(in), value :: sourceSz\n      type(c_ptr), intent(in), value :: function_name\n      integer(c_size_t), intent(in), value :: functionSz\n      type(c_ptr), intent(in), value :: zone_name\n      integer(c_size_t), intent(in), value :: nameSz\n      integer(c_int32_t), intent(in), value :: color\n    end function impl_tracy_alloc_srcloc_name\n  end interface\n\n  interface\n    type(tracy_zone_context) function impl_tracy_emit_zone_begin_callstack(srcloc, depth, active) &\n      bind(C, name=\"___tracy_emit_zone_begin_callstack\")\n      import\n      type(tracy_source_location_data), intent(in) :: srcloc\n      integer(c_int32_t), intent(in), value :: depth\n      integer(c_int32_t), intent(in), value :: active\n    end function impl_tracy_emit_zone_begin_callstack\n    type(tracy_zone_context) function impl_tracy_emit_zone_begin_alloc_callstack(srcloc, depth, active) &\n      bind(C, name=\"___tracy_emit_zone_begin_alloc_callstack\")\n      import\n      integer(c_int64_t), intent(in), value :: srcloc\n      integer(c_int32_t), intent(in), value :: depth\n      integer(c_int32_t), intent(in), value :: active\n    end function impl_tracy_emit_zone_begin_alloc_callstack\n  end interface\n  interface tracy_zone_begin\n    module procedure tracy_emit_zone_begin_id, tracy_emit_zone_begin_type\n  end interface tracy_zone_begin\n\n  interface\n    subroutine tracy_zone_end(ctx) bind(C, name=\"___tracy_emit_zone_end\")\n      import\n      type(tracy_zone_context), intent(in), value :: ctx\n    end subroutine tracy_zone_end\n  end interface\n\n  interface\n    subroutine tracy_emit_zone_text(ctx, txt, size) bind(C, name=\"___tracy_emit_zone_text\")\n      import\n      type(tracy_zone_context), intent(in), value :: ctx\n      type(c_ptr), intent(in), value :: txt\n      integer(c_size_t), intent(in), value :: size\n    end subroutine tracy_emit_zone_text\n    subroutine tracy_emit_zone_name(ctx, txt, size) bind(C, name=\"___tracy_emit_zone_name\")\n      import\n      type(tracy_zone_context), intent(in), value :: ctx\n      type(c_ptr), intent(in), value :: txt\n      integer(c_size_t), intent(in), value :: size\n    end subroutine tracy_emit_zone_name\n    subroutine tracy_emit_zone_color(ctx, color) bind(C, name=\"___tracy_emit_zone_color\")\n      import\n      type(tracy_zone_context), intent(in), value :: ctx\n      integer(c_int32_t), intent(in), value :: color\n    end subroutine tracy_emit_zone_color\n    subroutine tracy_emit_zone_value(ctx, value) bind(C, name=\"___tracy_emit_zone_value\")\n      import\n      type(tracy_zone_context), intent(in), value :: ctx\n      integer(c_int64_t), intent(in), value :: value\n    end subroutine tracy_emit_zone_value\n  end interface\n\n  ! GPU is not supported yet\n\n  interface\n    function impl_tracy_connected() bind(C, name=\"___tracy_connected\")\n      import\n      integer(c_int32_t) :: impl_tracy_connected\n    end function impl_tracy_connected\n  end interface\n\n  interface\n    subroutine impl_tracy_emit_memory_alloc_callstack(ptr, size, depth, secure) &\n      bind(C, name=\"___tracy_emit_memory_alloc_callstack\")\n      import\n      type(c_ptr), intent(in), value :: ptr\n      integer(c_size_t), intent(in), value :: size\n      integer(c_int32_t), intent(in), value :: depth\n      integer(c_int32_t), intent(in), value :: secure\n    end subroutine impl_tracy_emit_memory_alloc_callstack\n    subroutine impl_tracy_emit_memory_alloc_callstack_named(ptr, size, depth, secure, name) &\n      bind(C, name=\"___tracy_emit_memory_alloc_callstack_named\")\n      import\n      type(c_ptr), intent(in), value :: ptr\n      integer(c_size_t), intent(in), value :: size\n      integer(c_int32_t), intent(in), value :: depth\n      integer(c_int32_t), intent(in), value :: secure\n      type(c_ptr), intent(in), value :: name\n    end subroutine impl_tracy_emit_memory_alloc_callstack_named\n    subroutine impl_tracy_emit_memory_free_callstack(ptr, depth, secure) &\n      bind(C, name=\"___tracy_emit_memory_free_callstack\")\n      import\n      type(c_ptr), intent(in), value :: ptr\n      integer(c_int32_t), intent(in), value :: depth\n      integer(c_int32_t), intent(in), value :: secure\n    end subroutine impl_tracy_emit_memory_free_callstack\n    subroutine impl_tracy_emit_memory_free_callstack_named(ptr, depth, secure, name) &\n      bind(C, name=\"___tracy_emit_memory_free_callstack_named\")\n      import\n      type(c_ptr), intent(in), value :: ptr\n      integer(c_int32_t), intent(in), value :: depth\n      integer(c_int32_t), intent(in), value :: secure\n      type(c_ptr), intent(in), value :: name\n    end subroutine impl_tracy_emit_memory_free_callstack_named\n    subroutine impl_tracy_emit_memory_discard_callstack(name, secure, depth) &\n      bind(C, name=\"___tracy_emit_memory_discard_callstack\")\n      import\n      type(c_ptr), intent(in), value :: name\n      integer(c_int32_t), intent(in), value :: secure\n      integer(c_int32_t), intent(in), value :: depth\n    end subroutine impl_tracy_emit_memory_discard_callstack\n  end interface\n\n  interface\n    subroutine impl_tracy_emit_message(txt, size, depth) &\n      bind(C, name=\"___tracy_emit_message\")\n      import\n      type(c_ptr), intent(in), value :: txt\n      integer(c_size_t), value :: size\n      integer(c_int32_t), value :: depth\n    end subroutine impl_tracy_emit_message\n    subroutine impl_tracy_emit_messageC(txt, size, color, depth) &\n      bind(C, name=\"___tracy_emit_messageC\")\n      import\n      type(c_ptr), intent(in), value :: txt\n      integer(c_size_t), value :: size\n      integer(c_int32_t), value :: color\n      integer(c_int32_t), value :: depth\n    end subroutine impl_tracy_emit_messageC\n    subroutine impl_tracy_emit_message_appinfo(txt, size) &\n      bind(C, name=\"___tracy_emit_message_appinfo\")\n      import\n      type(c_ptr), intent(in), value :: txt\n      integer(c_size_t), value :: size\n    end subroutine impl_tracy_emit_message_appinfo\n  end interface\n\n  interface\n    subroutine impl_tracy_emit_frame_mark(name) &\n      bind(C, name=\"___tracy_emit_frame_mark\")\n      import\n      type(c_ptr), intent(in), value :: name\n    end subroutine impl_tracy_emit_frame_mark\n    subroutine impl_tracy_emit_frame_mark_start(name) &\n      bind(C, name=\"___tracy_emit_frame_mark_start\")\n      import\n      type(c_ptr), intent(in), value :: name\n    end subroutine impl_tracy_emit_frame_mark_start\n    subroutine impl_tracy_emit_frame_mark_end(name) &\n      bind(C, name=\"___tracy_emit_frame_mark_end\")\n      import\n      type(c_ptr), intent(in), value :: name\n    end subroutine impl_tracy_emit_frame_mark_end\n  end interface\n\n  interface\n    subroutine impl_tracy_emit_frame_image(image, w, h, offset, flip) &\n      bind(C, name=\"___tracy_emit_frame_image\")\n      import\n      type(c_ptr), intent(in), value :: image\n      integer(c_int16_t), intent(in), value :: w\n      integer(c_int16_t), intent(in), value :: h\n      integer(c_int8_t), intent(in), value :: offset\n      integer(c_int32_t), intent(in), value :: flip\n    end subroutine impl_tracy_emit_frame_image\n  end interface\n\n  interface\n    subroutine impl_tracy_emit_plot_int8(name, val) &\n      bind(C, name=\"___tracy_emit_plot_int\")\n      import\n      type(c_ptr), intent(in), value :: name\n      integer(c_int64_t), value :: val\n    end subroutine impl_tracy_emit_plot_int8\n    subroutine impl_tracy_emit_plot_real4(name, val) &\n      bind(C, name=\"___tracy_emit_plot_float\")\n      import\n      type(c_ptr), intent(in), value :: name\n      real(c_float), value :: val\n    end subroutine impl_tracy_emit_plot_real4\n    subroutine impl_tracy_emit_plot_real8(name, val) &\n      bind(C, name=\"___tracy_emit_plot\")\n      import\n      type(c_ptr), intent(in), value :: name\n      real(c_double), value :: val\n    end subroutine impl_tracy_emit_plot_real8\n  end interface\n  interface tracy_plot\n    module procedure tracy_plot_int8, tracy_plot_real4, tracy_plot_real8\n  end interface tracy_plot\n  interface\n    subroutine impl_tracy_emit_plot_config(name, type, step, fill, color) &\n      bind(C, name=\"___tracy_emit_plot_config\")\n      import\n      type(c_ptr), intent(in), value :: name\n      integer(c_int32_t), intent(in), value :: type\n      integer(c_int32_t), intent(in), value :: step\n      integer(c_int32_t), intent(in), value :: fill\n      integer(c_int32_t), intent(in), value :: color\n    end subroutine impl_tracy_emit_plot_config\n  end interface\n\n#ifdef TRACY_FIBERS\n  interface\n    subroutine impl_tracy_fiber_enter(fiber_name) &\n      bind(C, name=\"___tracy_fiber_enter\")\n      import\n      type(c_ptr), intent(in), value :: fiber_name\n    end subroutine impl_tracy_fiber_enter\n    subroutine tracy_fiber_leave() &\n      bind(C, name=\"___tracy_fiber_leave\")\n    end subroutine tracy_fiber_leave\n  end interface\n#endif\n  !\n  public :: tracy_zone_context\n  public :: tracy_source_location_data\n  !\n#ifndef __SUNPRO_F90\n  type(TracyColors_t), public, parameter :: TracyColors = TracyColors_t()\n#endif\n  !\n  public :: tracy_set_thread_name\n  public :: tracy_startup_profiler, tracy_shutdown_profiler, tracy_profiler_started\n  public :: tracy_connected\n  public :: tracy_appinfo\n  public :: tracy_alloc_srcloc\n  public :: tracy_zone_begin, tracy_zone_end\n  public :: tracy_zone_set_properties\n  public :: tracy_frame_mark, tracy_frame_start, tracy_frame_end\n  public :: tracy_memory_alloc, tracy_memory_free, tracy_memory_discard\n  public :: tracy_message\n  public :: tracy_image\n  public :: tracy_plot_config, tracy_plot\n#ifdef TRACY_FIBERS\n  public :: tracy_fiber_enter, tracy_fiber_leave\n#endif\ncontains\n  subroutine tracy_set_thread_name(name)\n    character(kind=c_char, len=*), intent(in) :: name\n    character(kind=c_char, len=:), allocatable, target :: alloc_name\n    allocate (character(kind=c_char, len=len(name) + 1) :: alloc_name)\n    alloc_name = name//c_null_char\n    call impl_tracy_set_thread_name(c_loc(alloc_name))\n  end subroutine tracy_set_thread_name\n\n  logical(1) function tracy_profiler_started()\n    tracy_profiler_started = impl_tracy_profiler_started() /= 0_c_int\n  end function tracy_profiler_started\n\n  integer(c_int64_t) function tracy_alloc_srcloc(line, source, function_name, zone_name, color)\n    integer(c_int32_t), intent(in) :: line\n    character(kind=c_char, len=*), target, intent(in) :: source, function_name\n    character(kind=c_char, len=*), target, intent(in), optional :: zone_name\n    integer(c_int32_t), intent(in), optional :: color\n    !\n    integer(c_int32_t) :: color_\n    !\n    color_ = 0_c_int32_t\n    if (present(color)) color_ = color\n    if (present(zone_name)) then\n      tracy_alloc_srcloc = impl_tracy_alloc_srcloc_name(line, &\n                                                        c_loc(source), len(source, kind=c_size_t), &\n                                                        c_loc(function_name), len(function_name, kind=c_size_t), &\n                                                        c_loc(zone_name), len(zone_name, kind=c_size_t), &\n                                                        color_)\n    else\n      tracy_alloc_srcloc = impl_tracy_alloc_srcloc(line, &\n                                                   c_loc(source), len(source, kind=c_size_t), &\n                                                   c_loc(function_name), len(function_name, kind=c_size_t), &\n                                                   color_)\n    end if\n  end function tracy_alloc_srcloc\n\n  type(tracy_zone_context) function tracy_emit_zone_begin_id(srcloc, depth, active)\n    integer(c_int64_t), intent(inout) :: srcloc\n    integer(c_int32_t), intent(in), optional :: depth\n    logical(1), intent(in), optional :: active\n    !\n    integer(c_int32_t) :: depth_\n    integer(c_int32_t) :: active_\n    active_ = 1_c_int32_t\n    depth_ = 0_c_int32_t\n    if (present(active)) then\n      if (active) then\n        active_ = 1_c_int32_t\n      else\n        active_ = 0_c_int32_t\n      end if\n    end if\n    if (present(depth)) depth_ = depth\n    tracy_emit_zone_begin_id = impl_tracy_emit_zone_begin_alloc_callstack(srcloc, depth_, active_)\n    srcloc = 0_c_int64_t\n  end function tracy_emit_zone_begin_id\n  type(tracy_zone_context) function tracy_emit_zone_begin_type(srcloc, depth, active)\n    type(tracy_source_location_data), intent(inout) :: srcloc\n    integer(c_int32_t), intent(in), optional :: depth\n    logical(1), intent(in), optional :: active\n    !\n    integer(c_int32_t) :: depth_\n    integer(c_int32_t) :: active_\n    active_ = 1_c_int32_t\n    depth_ = 0_c_int32_t\n    if (present(active)) then\n      if (active) then\n        active_ = 1_c_int32_t\n      else\n        active_ = 0_c_int32_t\n      end if\n    end if\n    if (present(depth)) depth_ = depth\n    tracy_emit_zone_begin_type = impl_tracy_emit_zone_begin_callstack(srcloc, depth_, active_)\n    srcloc = tracy_source_location_data(c_null_ptr, c_null_ptr, c_null_ptr, 0_c_int32_t, 0_c_int32_t)\n  end function tracy_emit_zone_begin_type\n\n  subroutine tracy_zone_set_properties(ctx, text, name, color, value)\n    type(tracy_zone_context), intent(in), value :: ctx\n    character(kind=c_char, len=*), target, intent(in), optional :: text\n    character(kind=c_char, len=*), target, intent(in), optional :: name\n    integer(c_int32_t), target, intent(in), optional :: color\n    integer(c_int64_t), target, intent(in), optional :: value\n    if (present(text)) then\n      call tracy_emit_zone_text(ctx, c_loc(text), len(text, kind=c_size_t))\n    end if\n    if (present(name)) then\n      call tracy_emit_zone_name(ctx, c_loc(name), len(name, kind=c_size_t))\n    end if\n    if (present(color)) then\n      call tracy_emit_zone_color(ctx, color)\n    end if\n    if (present(value)) then\n      call tracy_emit_zone_value(ctx, value)\n    end if\n  end subroutine tracy_zone_set_properties\n\n  logical(1) function tracy_connected()\n    tracy_connected = impl_tracy_connected() /= 0_c_int32_t\n  end function tracy_connected\n\n  subroutine tracy_memory_alloc(ptr, size, name, depth, secure)\n    type(c_ptr), intent(in) :: ptr\n    integer(c_size_t), intent(in) :: size\n    character(kind=c_char, len=*), target, intent(in), optional :: name\n    integer(c_int32_t), intent(in), optional :: depth\n    logical(1), intent(in), optional :: secure\n    !\n    integer(c_int32_t) :: depth_, secure_\n    secure_ = 0_c_int32_t\n    depth_ = 0_c_int32_t\n    if (present(secure)) then\n      if (secure) secure_ = 1_c_int32_t\n    end if\n    if (present(depth)) depth_ = depth\n    if (present(name)) then\n      call impl_tracy_emit_memory_alloc_callstack_named(ptr, size, depth_, secure_, c_loc(name))\n    else\n      call impl_tracy_emit_memory_alloc_callstack(ptr, size, depth_, secure_)\n    end if\n  end subroutine tracy_memory_alloc\n  subroutine tracy_memory_free(ptr, name, depth, secure)\n    type(c_ptr), intent(in) :: ptr\n    character(kind=c_char, len=*), target, intent(in), optional :: name\n    integer(c_int32_t), intent(in), optional :: depth\n    logical(1), intent(in), optional :: secure\n    !\n    integer(c_int32_t) :: depth_, secure_\n    secure_ = 0_c_int32_t\n    depth_ = 0_c_int32_t\n    if (present(secure)) then\n      if (secure) secure_ = 1_c_int32_t\n    end if\n    if (present(depth)) depth_ = depth\n    if (present(name)) then\n      call impl_tracy_emit_memory_free_callstack_named(ptr, depth_, secure_, c_loc(name))\n    else\n      call impl_tracy_emit_memory_free_callstack(ptr, depth_, secure_)\n    end if\n  end subroutine tracy_memory_free\n  subroutine tracy_memory_discard(name, depth, secure)\n    character(kind=c_char, len=*), target, intent(in) :: name\n    integer(c_int32_t), intent(in), optional :: depth\n    logical(1), intent(in), optional :: secure\n    !\n    integer(c_int32_t) :: depth_, secure_\n    secure_ = 0_c_int32_t\n    depth_ = 0_c_int32_t\n    if (present(secure)) then\n      if (secure) secure_ = 1_c_int32_t\n    end if\n    if (present(depth)) depth_ = depth\n    call impl_tracy_emit_memory_discard_callstack(c_loc(name), depth_, secure_)\n  end subroutine tracy_memory_discard\n\n  subroutine tracy_message(msg, color, depth)\n    character(kind=c_char, len=*), target, intent(in) :: msg\n    integer(c_int32_t), intent(in), optional :: color\n    integer(c_int32_t), intent(in), optional :: depth\n    !\n    integer(c_int32_t) :: depth_\n    depth_ = 0_c_int32_t\n    if (present(depth)) depth_ = depth\n    if (present(color)) then\n      call impl_tracy_emit_messageC(c_loc(msg), len(msg, kind=c_size_t), color, depth_)\n    else\n      call impl_tracy_emit_message(c_loc(msg), len(msg, kind=c_size_t), depth_)\n    end if\n  end subroutine tracy_message\n\n  subroutine tracy_appinfo(info)\n    character(kind=c_char, len=*), target, intent(in) :: info\n    call impl_tracy_emit_message_appinfo(c_loc(info), len(info, kind=c_size_t))\n  end subroutine tracy_appinfo\n\n  subroutine tracy_frame_mark(name)\n    character(kind=c_char, len=*), target, intent(in), optional :: name\n    if (present(name)) then\n      call impl_tracy_emit_frame_mark(c_loc(name))\n    else\n      call impl_tracy_emit_frame_mark(c_null_ptr)\n    end if\n  end subroutine tracy_frame_mark\n  subroutine tracy_frame_start(name)\n    character(kind=c_char, len=*), target, intent(in), optional :: name\n    if (present(name)) then\n      call impl_tracy_emit_frame_mark_start(c_loc(name))\n    else\n      call impl_tracy_emit_frame_mark_start(c_null_ptr)\n    end if\n  end subroutine tracy_frame_start\n  subroutine tracy_frame_end(name)\n    character(kind=c_char, len=*), target, intent(in), optional :: name\n    if (present(name)) then\n      call impl_tracy_emit_frame_mark_end(c_loc(name))\n    else\n      call impl_tracy_emit_frame_mark_end(c_null_ptr)\n    end if\n  end subroutine tracy_frame_end\n\n  subroutine tracy_image(image, w, h, offset, flip)\n    type(c_ptr), intent(in) :: image\n    integer(c_int16_t), intent(in) :: w, h\n    integer(c_int8_t), intent(in), optional :: offset\n    logical(1), intent(in), optional :: flip\n    !\n    integer(c_int32_t) :: flip_\n    integer(c_int8_t) :: offset_\n    flip_ = 0_c_int32_t\n    offset_ = 0_c_int8_t\n    if (present(flip)) then\n      if (flip) flip_ = 1_c_int32_t\n    end if\n    if (present(offset)) offset_ = offset\n    call impl_tracy_emit_frame_image(image, w, h, offset_, flip_)\n  end subroutine tracy_image\n\n  subroutine tracy_plot_int8(name, val)\n    character(kind=c_char, len=*), target, intent(in) :: name\n    integer(c_int64_t) :: val\n    call impl_tracy_emit_plot_int8(c_loc(name), val)\n  end subroutine tracy_plot_int8\n  subroutine tracy_plot_real4(name, val)\n    character(kind=c_char, len=*), target, intent(in) :: name\n    real(c_float) :: val\n    call impl_tracy_emit_plot_real4(c_loc(name), val)\n  end subroutine tracy_plot_real4\n  subroutine tracy_plot_real8(name, val)\n    character(kind=c_char, len=*), target, intent(in) :: name\n    real(c_double) :: val\n    call impl_tracy_emit_plot_real8(c_loc(name), val)\n  end subroutine tracy_plot_real8\n\n  subroutine tracy_plot_config(name, type, step, fill, color)\n    character(kind=c_char, len=*), target, intent(in) :: name\n    integer(c_int32_t), intent(in), optional :: type\n    logical(1), intent(in), optional :: step\n    logical(1), intent(in), optional :: fill\n    integer(c_int32_t), intent(in), optional :: color\n    !\n    integer(c_int32_t) :: type_, step_, fill_, color_\n    type_ = 0_c_int32_t\n    step_ = 0_c_int32_t\n    fill_ = 1_c_int32_t\n    color_ = 0_c_int32_t\n    if (present(type)) type_ = type\n    if (present(step)) then\n      if (step) step_ = 1_c_int32_t\n    end if\n    if (present(fill)) then\n      if (.not. fill) fill_ = 0_c_int32_t\n    end if\n    if (present(color)) color_ = color\n    call impl_tracy_emit_plot_config(c_loc(name), type_, step_, fill_, color_)\n  end subroutine tracy_plot_config\n\n#ifdef TRACY_FIBERS\n  subroutine tracy_fiber_enter(fiber_name)\n    character(kind=c_char, len=*), target, intent(in) :: fiber_name\n    call impl_tracy_fiber_enter(c_loc(fiber_name))\n  end subroutine tracy_fiber_enter\n#endif\nend module tracy\n"
  },
  {
    "path": "tracy-client-sys/tracy/TracyClient.cpp",
    "content": "//\n//          Tracy profiler\n//         ----------------\n//\n// For fast integration, compile and\n// link with this source file (and none\n// other) in your executable (or in the\n// main DLL / shared object on multi-DLL\n// projects).\n//\n\n// Define TRACY_ENABLE to enable profiler.\n\n#include \"common/TracySystem.cpp\"\n\n#ifdef TRACY_ENABLE\n\n#ifdef _MSC_VER\n#  pragma warning(push, 0)\n#endif\n\n#include \"common/tracy_lz4.cpp\"\n#include \"client/TracyProfiler.cpp\"\n#include \"client/TracyCallstack.cpp\"\n#include \"client/TracySysPower.cpp\"\n#include \"client/TracySysTime.cpp\"\n#include \"client/TracySysTrace.cpp\"\n#include \"common/TracySocket.cpp\"\n#include \"client/tracy_rpmalloc.cpp\"\n#include \"client/TracyDxt1.cpp\"\n#include \"client/TracyAlloc.cpp\"\n#include \"client/TracyOverride.cpp\"\n#include \"client/TracyKCore.cpp\"\n\n#ifdef TRACY_ROCPROF\n#  include \"client/TracyRocprof.cpp\"\n#endif\n#ifdef _MSC_VER\n#  pragma comment(lib, \"ws2_32.lib\")\n#  pragma comment(lib, \"advapi32.lib\")\n#  pragma comment(lib, \"user32.lib\")\n#  pragma warning(pop)\n#endif\n\n#endif\n"
  },
  {
    "path": "tracy-client-sys/tracy/client/TracyAlloc.cpp",
    "content": "#include \"../common/TracyAlloc.hpp\"\n\n#ifdef TRACY_USE_RPMALLOC\n\n#include <atomic>\n\n#include \"../common/TracyForceInline.hpp\"\n#include \"../common/TracyYield.hpp\"\n\nnamespace tracy\n{\n\nextern thread_local bool RpThreadInitDone;\nextern std::atomic<int> RpInitDone;\nextern std::atomic<int> RpInitLock;\n\ntracy_no_inline static void InitRpmallocPlumbing()\n{\n    const auto done = RpInitDone.load( std::memory_order_acquire );\n    if( !done )\n    {\n        int expected = 0;\n        while( !RpInitLock.compare_exchange_weak( expected, 1, std::memory_order_release, std::memory_order_relaxed ) ) { expected = 0; YieldThread(); }\n        const auto done = RpInitDone.load( std::memory_order_acquire );\n        if( !done )\n        {\n            rpmalloc_initialize();\n            RpInitDone.store( 1, std::memory_order_release );\n        }\n        RpInitLock.store( 0, std::memory_order_release );\n    }\n    rpmalloc_thread_initialize();\n    RpThreadInitDone = true;\n}\n\nTRACY_API void InitRpmalloc()\n{\n    if( !RpThreadInitDone ) InitRpmallocPlumbing();\n}\n\n}\n\n#endif\n"
  },
  {
    "path": "tracy-client-sys/tracy/client/TracyArmCpuTable.hpp",
    "content": "namespace tracy\n{\n\n#if defined __linux__ && defined __ARM_ARCH\n\nstatic const char* DecodeArmImplementer( uint32_t v )\n{\n    static char buf[16];\n    switch( v )\n    {\n    case 0x41: return \"ARM\";\n    case 0x42: return \"Broadcom\";\n    case 0x43: return \"Cavium\";\n    case 0x44: return \"DEC\";\n    case 0x46: return \"Fujitsu\";\n    case 0x48: return \"HiSilicon\";\n    case 0x49: return \"Infineon\";\n    case 0x4d: return \"Motorola\";\n    case 0x4e: return \"Nvidia\";\n    case 0x50: return \"Applied Micro\";\n    case 0x51: return \"Qualcomm\";\n    case 0x53: return \"Samsung\";\n    case 0x54: return \"Texas Instruments\";\n    case 0x56: return \"Marvell\";\n    case 0x61: return \"Apple\";\n    case 0x66: return \"Faraday\";\n    case 0x68: return \"HXT\";\n    case 0x69: return \"Intel\";\n    case 0xc0: return \"Ampere Computing\";\n    default: break;\n    }\n    sprintf( buf, \"0x%x\", v );\n    return buf;\n}\n\nstatic const char* DecodeArmPart( uint32_t impl, uint32_t part )\n{\n    static char buf[16];\n    switch( impl )\n    {\n    case 0x41:  // ARM\n        switch( part )\n        {\n        case 0x810: return \"810\";\n        case 0x920: return \"920\";\n        case 0x922: return \"922\";\n        case 0x926: return \"926\";\n        case 0x940: return \"940\";\n        case 0x946: return \"946\";\n        case 0x966: return \"966\";\n        case 0xa20: return \"1020\";\n        case 0xa22: return \"1022\";\n        case 0xa26: return \"1026\";\n        case 0xb02: return \"11 MPCore\";\n        case 0xb36: return \"1136\";\n        case 0xb56: return \"1156\";\n        case 0xb76: return \"1176\";\n        case 0xc05: return \" Cortex-A5\";\n        case 0xc07: return \" Cortex-A7\";\n        case 0xc08: return \" Cortex-A8\";\n        case 0xc09: return \" Cortex-A9\";\n        case 0xc0c: return \" Cortex-A12\";\n        case 0xc0d: return \" Rockchip RK3288\";\n        case 0xc0e: return \" Cortex-A17\";\n        case 0xc0f: return \" Cortex-A15\";\n        case 0xc14: return \" Cortex-R4\";\n        case 0xc15: return \" Cortex-R5\";\n        case 0xc17: return \" Cortex-R7\";\n        case 0xc18: return \" Cortex-R8\";\n        case 0xc20: return \" Cortex-M0\";\n        case 0xc21: return \" Cortex-M1\";\n        case 0xc23: return \" Cortex-M3\";\n        case 0xc24: return \" Cortex-M4\";\n        case 0xc27: return \" Cortex-M7\";\n        case 0xc60: return \" Cortex-M0+\";\n        case 0xd00: return \" AArch64 simulator\";\n        case 0xd01: return \" Cortex-A32\";\n        case 0xd02: return \" Cortex-A34\";\n        case 0xd03: return \" Cortex-A53\";\n        case 0xd04: return \" Cortex-A35\";\n        case 0xd05: return \" Cortex-A55\";\n        case 0xd06: return \" Cortex-A65\";\n        case 0xd07: return \" Cortex-A57\";\n        case 0xd08: return \" Cortex-A72\";\n        case 0xd09: return \" Cortex-A73\";\n        case 0xd0a: return \" Cortex-A75\";\n        case 0xd0b: return \" Cortex-A76\";\n        case 0xd0c: return \" Neoverse N1\";\n        case 0xd0d: return \" Cortex-A77\";\n        case 0xd0e: return \" Cortex-A76AE\";\n        case 0xd0f: return \" AEMv8\";\n        case 0xd13: return \" Cortex-R52\";\n        case 0xd20: return \" Cortex-M23\";\n        case 0xd21: return \" Cortex-M33\";\n        case 0xd22: return \" Cortex-M55\";\n        case 0xd40: return \" Neoverse V1\";\n        case 0xd41: return \" Cortex-A78\";\n        case 0xd42: return \" Cortex-A78AE\";\n        case 0xd43: return \" Cortex-A65AE\";\n        case 0xd44: return \" Cortex-X1\";\n        case 0xd47: return \" Cortex-A710\";\n        case 0xd48: return \" Cortex-X2\";\n        case 0xd49: return \" Neoverse N2\";\n        case 0xd4a: return \" Neoverse E1\";\n        case 0xd4b: return \" Cortex-A78C\";\n        case 0xd4c: return \" Cortex-X1C\";\n        default: break;\n        }\n    case 0x42:  // Broadcom\n        switch( part )\n        {\n        case 0xf: return \" Brahma B15\";\n        case 0x100: return \" Brahma B53\";\n        case 0x516: return \" ThunderX2\";\n        default: break;\n        }\n    case 0x43:  // Cavium\n        switch( part )\n        {\n        case 0xa0: return \" ThunderX\";\n        case 0xa1: return \" ThunderX 88XX\";\n        case 0xa2: return \" ThunderX 81XX\";\n        case 0xa3: return \" ThunderX 83XX\";\n        case 0xaf: return \" ThunderX2 99xx\";\n        case 0xb0: return \" OcteonTX2\";\n        case 0xb1: return \" OcteonTX2 T98\";\n        case 0xb2: return \" OcteonTX2 T96\";\n        case 0xb3: return \" OcteonTX2 F95\";\n        case 0xb4: return \" OcteonTX2 F95N\";\n        case 0xb5: return \" OcteonTX2 F95MM\";\n        case 0xb6: return \" OcteonTX2 F95O\";\n        case 0xb8: return \" ThunderX3 T110\";\n        default: break;\n        }\n    case 0x44:  // DEC\n        switch( part )\n        {\n        case 0xa10: return \" SA110\";\n        case 0xa11: return \" SA1100\";\n        default: break;\n        }\n    case 0x46:  // Fujitsu\n        switch( part )\n        {\n        case 0x1: return \" A64FX\";\n        default: break;\n        }\n    case 0x48:  // HiSilicon\n        switch( part )\n        {\n        case 0xd01: return \" TSV100\";\n        case 0xd40: return \" Kirin 980\";\n        default: break;\n        }\n    case 0x4e:  // Nvidia\n        switch( part )\n        {\n        case 0x0: return \" Denver\";\n        case 0x3: return \" Denver 2\";\n        case 0x4: return \" Carmel\";\n        default: break;\n        }\n    case 0x50:  // Applied Micro\n        switch( part )\n        {\n        case 0x0: return \" X-Gene\";\n        default: break;\n        }\n    case 0x51:  // Qualcomm\n        switch( part )\n        {\n        case 0xf: return \" Scorpion\";\n        case 0x2d: return \" Scorpion\";\n        case 0x4d: return \" Krait\";\n        case 0x6f: return \" Krait\";\n        case 0x200: return \" Kryo\";\n        case 0x201: return \" Kryo Silver (Snapdragon 821)\";\n        case 0x205: return \" Kryo Gold\";\n        case 0x211: return \" Kryo Silver (Snapdragon 820)\";\n        case 0x800: return \" Kryo 260 / 280 Gold\";\n        case 0x801: return \" Kryo 260 / 280 Silver\";\n        case 0x802: return \" Kryo 385 Gold\";\n        case 0x803: return \" Kryo 385 Silver\";\n        case 0x804: return \" Kryo 485 Gold\";\n        case 0x805: return \" Kryo 4xx/5xx Silver\";\n        case 0xc00: return \" Falkor\";\n        case 0xc01: return \" Saphira\";\n        default: break;\n        }\n    case 0x53:  // Samsung\n        switch( part )\n        {\n        case 0x1: return \" Exynos M1/M2\";\n        case 0x2: return \" Exynos M3\";\n        case 0x3: return \" Exynos M4\";\n        case 0x4: return \" Exynos M5\";\n        default: break;\n        }\n    case 0x54:  // Texas Instruments\n        switch( part )\n        {\n        case 0x925: return \" TI925\";\n        default: break;\n        }\n    case 0x56:  // Marvell\n        switch( part )\n        {\n        case 0x131: return \" Feroceon 88FR131\";\n        case 0x581: return \" PJ4 / PJ4B\";\n        case 0x584: return \" PJ4B-MP / PJ4C\";\n        default: break;\n        }\n    case 0x61:  // Apple\n        switch( part )\n        {\n        case 0x1: return \" Cyclone\";\n        case 0x2: return \" Typhoon\";\n        case 0x3: return \" Typhoon/Capri\";\n        case 0x4: return \" Twister\";\n        case 0x5: return \" Twister/Elba/Malta\";\n        case 0x6: return \" Hurricane\";\n        case 0x7: return \" Hurricane/Myst\";\n        case 0x22: return \" M1 Icestorm\";\n        case 0x23: return \" M1 Firestorm\";\n        case 0x24: return \" M1 Icestorm Pro\";\n        case 0x25: return \" M1 Firestorm Pro\";\n        case 0x28: return \" M1 Icestorm Max\";\n        case 0x29: return \" M1 Firestorm Max\";\n        default: break;\n        }\n    case 0x66:  // Faraday\n        switch( part )\n        {\n        case 0x526: return \" FA526\";\n        case 0x626: return \" FA626\";\n        default: break;\n        }\n    case 0x68:  // HXT\n        switch( part )\n        {\n        case 0x0: return \" Phecda\";\n        default: break;\n        }\n    case 0xc0:  // Ampere Computing\n        switch( part )\n        {\n        case 0xac3: return \" Ampere1\";\n        default: break;\n        }\n    default: break;\n    }\n    sprintf( buf, \" 0x%x\", part );\n    return buf;\n}\n\n#elif defined __APPLE__ && TARGET_OS_IPHONE == 1\n\nstatic const char* DecodeIosDevice( const char* id )\n{\n    static const char* DeviceTable[] = {\n        \"i386\", \"32-bit simulator\",\n        \"x86_64\", \"64-bit simulator\",\n        \"iPhone1,1\", \"iPhone\",\n        \"iPhone1,2\", \"iPhone 3G\",\n        \"iPhone2,1\", \"iPhone 3GS\",\n        \"iPhone3,1\", \"iPhone 4 (GSM)\",\n        \"iPhone3,2\", \"iPhone 4 (GSM)\",\n        \"iPhone3,3\", \"iPhone 4 (CDMA)\",\n        \"iPhone4,1\", \"iPhone 4S\",\n        \"iPhone5,1\", \"iPhone 5 (A1428)\",\n        \"iPhone5,2\", \"iPhone 5 (A1429)\",\n        \"iPhone5,3\", \"iPhone 5c (A1456/A1532)\",\n        \"iPhone5,4\", \"iPhone 5c (A1507/A1516/1526/A1529)\",\n        \"iPhone6,1\", \"iPhone 5s (A1433/A1533)\",\n        \"iPhone6,2\", \"iPhone 5s (A1457/A1518/A1528/A1530)\",\n        \"iPhone7,1\", \"iPhone 6 Plus\",\n        \"iPhone7,2\", \"iPhone 6\",\n        \"iPhone8,1\", \"iPhone 6S\",\n        \"iPhone8,2\", \"iPhone 6S Plus\",\n        \"iPhone8,4\", \"iPhone SE\",\n        \"iPhone9,1\", \"iPhone 7 (CDMA)\",\n        \"iPhone9,2\", \"iPhone 7 Plus (CDMA)\",\n        \"iPhone9,3\", \"iPhone 7 (GSM)\",\n        \"iPhone9,4\", \"iPhone 7 Plus (GSM)\",\n        \"iPhone10,1\", \"iPhone 8 (CDMA)\",\n        \"iPhone10,2\", \"iPhone 8 Plus (CDMA)\",\n        \"iPhone10,3\", \"iPhone X (CDMA)\",\n        \"iPhone10,4\", \"iPhone 8 (GSM)\",\n        \"iPhone10,5\", \"iPhone 8 Plus (GSM)\",\n        \"iPhone10,6\", \"iPhone X (GSM)\",\n        \"iPhone11,2\", \"iPhone XS\",\n        \"iPhone11,4\", \"iPhone XS Max\",\n        \"iPhone11,6\", \"iPhone XS Max China\",\n        \"iPhone11,8\", \"iPhone XR\",\n        \"iPhone12,1\", \"iPhone 11\",\n        \"iPhone12,3\", \"iPhone 11 Pro\",\n        \"iPhone12,5\", \"iPhone 11 Pro Max\",\n        \"iPhone12,8\", \"iPhone SE 2nd Gen\",\n        \"iPhone13,1\", \"iPhone 12 Mini\",\n        \"iPhone13,2\", \"iPhone 12\",\n        \"iPhone13,3\", \"iPhone 12 Pro\",\n        \"iPhone13,4\", \"iPhone 12 Pro Max\",\n        \"iPhone14,2\", \"iPhone 13 Pro\",\n        \"iPhone14,3\", \"iPhone 13 Pro Max\",\n        \"iPhone14,4\", \"iPhone 13 Mini\",\n        \"iPhone14,5\", \"iPhone 13\",\n        \"iPhone14,6\", \"iPhone SE 3rd Gen\",\n        \"iPhone14,7\", \"iPhone 14\",\n        \"iPhone14,8\", \"iPhone 14 Plus\",\n        \"iPhone15,2\", \"iPhone 14 Pro\",\n        \"iPhone15,3\", \"iPhone 14 Pro Max\",\n        \"iPhone15,4\", \"iPhone 15\",\n        \"iPhone15,5\", \"iPhone 15 Plus\",\n        \"iPhone16,1\", \"iPhone 15 Pro\",\n        \"iPhone16,2\", \"iPhone 15 Pro Max\",\n        \"iPad1,1\", \"iPad (A1219/A1337)\",\n        \"iPad2,1\", \"iPad 2 (A1395)\",\n        \"iPad2,2\", \"iPad 2 (A1396)\",\n        \"iPad2,3\", \"iPad 2 (A1397)\",\n        \"iPad2,4\", \"iPad 2 (A1395)\",\n        \"iPad2,5\", \"iPad Mini (A1432)\",\n        \"iPad2,6\", \"iPad Mini (A1454)\",\n        \"iPad2,7\", \"iPad Mini (A1455)\",\n        \"iPad3,1\", \"iPad 3 (A1416)\",\n        \"iPad3,2\", \"iPad 3 (A1403)\",\n        \"iPad3,3\", \"iPad 3 (A1430)\",\n        \"iPad3,4\", \"iPad 4 (A1458)\",\n        \"iPad3,5\", \"iPad 4 (A1459)\",\n        \"iPad3,6\", \"iPad 4 (A1460)\",\n        \"iPad4,1\", \"iPad Air (A1474)\",\n        \"iPad4,2\", \"iPad Air (A1475)\",\n        \"iPad4,3\", \"iPad Air (A1476)\",\n        \"iPad4,4\", \"iPad Mini 2 (A1489)\",\n        \"iPad4,5\", \"iPad Mini 2 (A1490)\",\n        \"iPad4,6\", \"iPad Mini 2 (A1491)\",\n        \"iPad4,7\", \"iPad Mini 3 (A1599)\",\n        \"iPad4,8\", \"iPad Mini 3 (A1600)\",\n        \"iPad4,9\", \"iPad Mini 3 (A1601)\",\n        \"iPad5,1\", \"iPad Mini 4 (A1538)\",\n        \"iPad5,2\", \"iPad Mini 4 (A1550)\",\n        \"iPad5,3\", \"iPad Air 2 (A1566)\",\n        \"iPad5,4\", \"iPad Air 2 (A1567)\",\n        \"iPad6,3\", \"iPad Pro 9.7\\\" (A1673)\",\n        \"iPad6,4\", \"iPad Pro 9.7\\\" (A1674)\",\n        \"iPad6,5\", \"iPad Pro 9.7\\\" (A1675)\",\n        \"iPad6,7\", \"iPad Pro 12.9\\\" (A1584)\",\n        \"iPad6,8\", \"iPad Pro 12.9\\\" (A1652)\",\n        \"iPad6,11\", \"iPad 5th gen (A1822)\",\n        \"iPad6,12\", \"iPad 5th gen (A1823)\",\n        \"iPad7,1\", \"iPad Pro 12.9\\\" 2nd gen (A1670)\",\n        \"iPad7,2\", \"iPad Pro 12.9\\\" 2nd gen (A1671/A1821)\",\n        \"iPad7,3\", \"iPad Pro 10.5\\\" (A1701)\",\n        \"iPad7,4\", \"iPad Pro 10.5\\\" (A1709)\",\n        \"iPad7,5\", \"iPad 6th gen (A1893)\",\n        \"iPad7,6\", \"iPad 6th gen (A1954)\",\n        \"iPad7,11\", \"iPad 7th gen 10.2\\\" (Wifi)\",\n        \"iPad7,12\", \"iPad 7th gen 10.2\\\" (Wifi+Cellular)\",\n        \"iPad8,1\", \"iPad Pro 11\\\" (A1980)\",\n        \"iPad8,2\", \"iPad Pro 11\\\" (A1980)\",\n        \"iPad8,3\", \"iPad Pro 11\\\" (A1934/A1979/A2013)\",\n        \"iPad8,4\", \"iPad Pro 11\\\" (A1934/A1979/A2013)\",\n        \"iPad8,5\", \"iPad Pro 12.9\\\" 3rd gen (A1876)\",\n        \"iPad8,6\", \"iPad Pro 12.9\\\" 3rd gen (A1876)\",\n        \"iPad8,7\", \"iPad Pro 12.9\\\" 3rd gen (A1895/A1983/A2014)\",\n        \"iPad8,8\", \"iPad Pro 12.9\\\" 3rd gen (A1895/A1983/A2014)\",\n        \"iPad8,9\", \"iPad Pro 11\\\" 2nd gen (Wifi)\",\n        \"iPad8,10\", \"iPad Pro 11\\\" 2nd gen (Wifi+Cellular)\",\n        \"iPad8,11\", \"iPad Pro 12.9\\\" 4th gen (Wifi)\",\n        \"iPad8,12\", \"iPad Pro 12.9\\\" 4th gen (Wifi+Cellular)\",\n        \"iPad11,1\", \"iPad Mini 5th gen (A2133)\",\n        \"iPad11,2\", \"iPad Mini 5th gen (A2124/A2125/A2126)\",\n        \"iPad11,3\", \"iPad Air 3rd gen (A2152)\",\n        \"iPad11,4\", \"iPad Air 3rd gen (A2123/A2153/A2154)\",\n        \"iPad11,6\", \"iPad 8th gen (WiFi)\",\n        \"iPad11,7\", \"iPad 8th gen (WiFi+Cellular)\",\n        \"iPad12,1\", \"iPad 9th Gen (WiFi)\",\n        \"iPad12,2\", \"iPad 9th Gen (WiFi+Cellular)\",\n        \"iPad13,1\", \"iPad Air 4th gen (WiFi)\",\n        \"iPad13,2\", \"iPad Air 4th gen (WiFi+Cellular)\",\n        \"iPad13,4\", \"iPad Pro 11\\\" 3rd gen\",\n        \"iPad13,5\", \"iPad Pro 11\\\" 3rd gen\",\n        \"iPad13,6\", \"iPad Pro 11\\\" 3rd gen\",\n        \"iPad13,7\", \"iPad Pro 11\\\" 3rd gen\",\n        \"iPad13,8\", \"iPad Pro 12.9\\\" 5th gen\",\n        \"iPad13,9\", \"iPad Pro 12.9\\\" 5th gen\",\n        \"iPad13,10\", \"iPad Pro 12.9\\\" 5th gen\",\n        \"iPad13,11\", \"iPad Pro 12.9\\\" 5th gen\",\n        \"iPad13,16\", \"iPad Air 5th Gen (WiFi)\",\n        \"iPad13,17\", \"iPad Air 5th Gen (WiFi+Cellular)\",\n        \"iPad13,18\", \"iPad 10th Gen\",\n        \"iPad13,19\", \"iPad 10th Gen\",\n        \"iPad14,1\", \"iPad mini 6th Gen (WiFi)\",\n        \"iPad14,2\", \"iPad mini 6th Gen (WiFi+Cellular)\",\n        \"iPad14,3\", \"iPad Pro 11\\\" 4th Gen\",\n        \"iPad14,4\", \"iPad Pro 11\\\" 4th Gen\",\n        \"iPad14,5\", \"iPad Pro 12.9\\\" 6th Gen\",\n        \"iPad14,6\", \"iPad Pro 12.9\\\" 6th Gen\",\n        \"iPod1,1\", \"iPod Touch\",\n        \"iPod2,1\", \"iPod Touch 2nd gen\",\n        \"iPod3,1\", \"iPod Touch 3rd gen\",\n        \"iPod4,1\", \"iPod Touch 4th gen\",\n        \"iPod5,1\", \"iPod Touch 5th gen\",\n        \"iPod7,1\", \"iPod Touch 6th gen\",\n        \"iPod9,1\", \"iPod Touch 7th gen\",\n        nullptr\n    };\n\n    auto ptr = DeviceTable;\n    while( *ptr )\n    {\n        if( strcmp( ptr[0], id ) == 0 ) return ptr[1];\n        ptr += 2;\n    }\n    return id;\n}\n\n#endif\n\n}\n"
  },
  {
    "path": "tracy-client-sys/tracy/client/TracyCallstack.cpp",
    "content": "#include <limits>\n#include <new>\n#include <stdio.h>\n#include <string.h>\n#include \"TracyCallstack.hpp\"\n#include \"TracyDebug.hpp\"\n#include \"TracyFastVector.hpp\"\n#include \"TracyStringHelpers.hpp\"\n#include \"../common/TracyAlloc.hpp\"\n#include \"../common/TracySystem.hpp\"\n\n\n#ifdef TRACY_HAS_CALLSTACK\n\n#if TRACY_HAS_CALLSTACK == 1\n#  ifndef NOMINMAX\n#    define NOMINMAX\n#  endif\n#  include <windows.h>\n#  include <psapi.h>\n#  include <algorithm>\n#  ifdef _MSC_VER\n#    pragma warning( push )\n#    pragma warning( disable : 4091 )\n#  endif\n#  include <dbghelp.h>\n#  pragma comment( lib, \"dbghelp.lib\" )\n#  ifdef _MSC_VER\n#    pragma warning( pop )\n#  endif\n#elif defined(TRACY_USE_LIBBACKTRACE)\n\n#  include \"../libbacktrace/backtrace.hpp\"\n#  include <algorithm>\n#  include <dlfcn.h>\n#  include <cxxabi.h>\n#  include <stdlib.h>\n\n// Implementation files\n#  include \"../libbacktrace/alloc.cpp\"\n#  include \"../libbacktrace/dwarf.cpp\"\n#  include \"../libbacktrace/fileline.cpp\"\n#  include \"../libbacktrace/mmapio.cpp\"\n#  include \"../libbacktrace/posix.cpp\"\n#  include \"../libbacktrace/sort.cpp\"\n#  include \"../libbacktrace/state.cpp\"\n#  if TRACY_HAS_CALLSTACK == 4\n#    include \"../libbacktrace/macho.cpp\"\n#  else\n#    include \"../libbacktrace/elf.cpp\"\n#  endif\n#  include \"../common/TracyStackFrames.cpp\"\n\n#elif TRACY_HAS_CALLSTACK == 5\n#  include <dlfcn.h>\n#  include <cxxabi.h>\n#endif\n\n#ifdef TRACY_DBGHELP_LOCK\n#  include \"TracyProfiler.hpp\"\n\n#  define DBGHELP_INIT TracyConcat( TRACY_DBGHELP_LOCK, Init() )\n#  define DBGHELP_LOCK TracyConcat( TRACY_DBGHELP_LOCK, Lock() );\n#  define DBGHELP_UNLOCK TracyConcat( TRACY_DBGHELP_LOCK, Unlock() );\n\nextern \"C\"\n{\n    void DBGHELP_INIT;\n    void DBGHELP_LOCK;\n    void DBGHELP_UNLOCK;\n};\n#endif\n\n#if defined(TRACY_USE_LIBBACKTRACE) || TRACY_HAS_CALLSTACK == 5\n// If you want to use your own demangling functionality (e.g. for another language),\n// define TRACY_DEMANGLE and provide your own implementation of the __tracy_demangle\n// function. The input parameter is a function name. The demangle function must\n// identify whether this name is mangled, and fail if it is not. Failure is indicated\n// by returning nullptr. If demangling succeeds, a pointer to the C string containing\n// demangled function must be returned. The demangling function is responsible for\n// managing memory for this string. It is expected that it will be internally reused.\n// When a call to ___tracy_demangle is made, previous contents of the string memory\n// do not need to be preserved. Function may return string of any length, but the\n// profiler can choose to truncate it.\nextern \"C\" const char* ___tracy_demangle( const char* mangled );\n\n#ifndef TRACY_DEMANGLE\nconstexpr size_t ___tracy_demangle_buffer_len = 1024*1024;\nchar* ___tracy_demangle_buffer;\n\nvoid ___tracy_init_demangle_buffer()\n{\n    ___tracy_demangle_buffer = (char*)tracy::tracy_malloc( ___tracy_demangle_buffer_len );\n}\n\nvoid ___tracy_free_demangle_buffer()\n{\n    tracy::tracy_free( ___tracy_demangle_buffer );\n}\n\nextern \"C\" const char* ___tracy_demangle( const char* mangled )\n{\n    if( !mangled || mangled[0] != '_' ) return nullptr;\n    if( strlen( mangled ) > ___tracy_demangle_buffer_len ) return nullptr;\n    int status;\n    size_t len = ___tracy_demangle_buffer_len;\n    return abi::__cxa_demangle( mangled, ___tracy_demangle_buffer, &len, &status );\n}\n#endif\n#endif\n\n#if defined(TRACY_USE_LIBBACKTRACE) && TRACY_HAS_CALLSTACK != 4 // dl_iterate_phdr is required for the current image cache. Need to move it to libbacktrace?\n#   define TRACY_HAS_DL_ITERATE_PHDR_TO_REFRESH_IMAGE_CACHE\n#   include <link.h>\n#endif\n\nnamespace tracy\n{\n\nstatic bool IsKernelAddress(uint64_t addr) {\n    return (addr >> 63) != 0;\n}\n\nvoid DestroyImageEntry( ImageEntry& entry )\n{\n    tracy_free( entry.m_path );\n    tracy_free( entry.m_name );\n}\n\nclass ImageCache\n{\npublic:\n    \n    ImageCache( size_t imageCacheCapacity = 512 )\n        : m_images( imageCacheCapacity )\n    {\n    }\n\n    ~ImageCache()\n    {\n        Clear();\n    }\n    \n    ImageEntry* AddEntry( const ImageEntry& entry )\n    {\n        if( m_sorted ) m_sorted = m_images.empty() || ( entry.m_startAddress < m_images.back().m_startAddress );\n        ImageEntry* newEntry = m_images.push_next();\n        *newEntry = entry;\n        return newEntry;\n    }\n\n    const ImageEntry* GetImageForAddress( uint64_t address )\n    {\n        Sort();\n\n        auto it = std::lower_bound( m_images.begin(), m_images.end(), address,\n            []( const ImageEntry& lhs, const uint64_t rhs ) { return lhs.m_startAddress > rhs; } );\n\n        if( it != m_images.end() && address < it->m_endAddress )\n        {\n            return it;\n        }\n        return nullptr;\n    }\n    \n    void Sort()\n    {\n        if( m_sorted ) return;\n\n        std::sort( m_images.begin(), m_images.end(),\n            []( const ImageEntry& lhs, const ImageEntry& rhs ) { return lhs.m_startAddress > rhs.m_startAddress; } );\n        m_sorted = true;\n    }\n\n    void Clear()\n    {\n        for( ImageEntry& entry : m_images )\n        {\n            DestroyImageEntry( entry );\n        }\n\n        m_sorted = true;\n        m_images.clear();\n    }\n\n    bool ContainsImage( uint64_t startAddress ) const\n    {\n        return std::any_of( m_images.begin(), m_images.end(), [startAddress]( const ImageEntry& entry ) { return startAddress == entry.m_startAddress; } );\n    }\nprotected:\n    tracy::FastVector<ImageEntry> m_images;\n    bool m_sorted = true;\n};\n\n#ifdef TRACY_HAS_DL_ITERATE_PHDR_TO_REFRESH_IMAGE_CACHE\n// when we have access to dl_iterate_phdr(), we can build a cache of address ranges to image paths\n// so we can quickly determine which image an address falls into.\n// We refresh this cache only when we hit an address that doesn't fall into any known range.\nclass ImageCacheDlIteratePhdr : public ImageCache\n{\npublic:\n\n    ImageCacheDlIteratePhdr()\n    {\n        Refresh();\n    }\n\n    ~ImageCacheDlIteratePhdr()\n    {\n    }\n\n    const ImageEntry* GetImageForAddress( uint64_t address )\n    {\n        const ImageEntry* entry = ImageCache::GetImageForAddress( address );\n        if( !entry )\n        {\n            Refresh();\n            return ImageCache::GetImageForAddress( address );\n        }\n        return entry;\n    }\n\nprivate:\n    bool m_updated = false;\n    bool m_haveMainImageName = false;\n\n    static int Callback( struct dl_phdr_info* info, size_t size, void* data )\n    {\n        ImageCacheDlIteratePhdr* cache = reinterpret_cast<ImageCacheDlIteratePhdr*>( data );\n\n        const auto startAddress = static_cast<uint64_t>( info->dlpi_addr );\n        if( cache->ContainsImage( startAddress ) ) return 0;\n\n        const uint32_t headerCount = info->dlpi_phnum;\n        assert( headerCount > 0);\n        const auto endAddress = static_cast<uint64_t>( info->dlpi_addr +\n            info->dlpi_phdr[info->dlpi_phnum - 1].p_vaddr + info->dlpi_phdr[info->dlpi_phnum - 1].p_memsz);\n\n        ImageEntry image{};\n        image.m_startAddress = startAddress;\n        image.m_endAddress = endAddress;\n\n        // the base executable name isn't provided when iterating with dl_iterate_phdr,\n        // we will have to patch the executable image name outside this callback\n        image.m_name = info->dlpi_name && info->dlpi_name[0] != '\\0' ? CopyStringFast( info->dlpi_name ) : nullptr;\n\n        cache->AddEntry( image );\n        cache->m_updated = true;\n\n        return 0;\n    }\n\n    void Refresh()\n    {\n        m_updated = false;\n        dl_iterate_phdr( Callback, this );\n\n        if( m_updated )\n        {\n            Sort();\n            // patch the main executable image name here, as calling dl_* functions inside the dl_iterate_phdr callback might cause deadlocks\n            UpdateMainImageName();\n        }\n    }\n\n    void UpdateMainImageName()\n    {\n        if( m_haveMainImageName )\n        {\n            return;\n        }\n\n        for( ImageEntry& entry : m_images )\n        {\n            if( entry.m_name == nullptr )\n            {\n                Dl_info dlInfo;\n                if( dladdr( (void *)entry.m_startAddress, &dlInfo ) )\n                {\n                    if( dlInfo.dli_fname )\n                    {\n                        size_t sz = strlen( dlInfo.dli_fname ) + 1;\n                        entry.m_name = (char*)tracy_malloc( sz );\n                        memcpy( entry.m_name, dlInfo.dli_fname, sz );\n                    }\n                }\n\n                // we only expect one entry to be null for the main executable entry\n                break;\n            }\n        }\n\n        m_haveMainImageName = true;\n    }\n    void Clear()\n    {\n        ImageCache::Clear();\n        m_haveMainImageName = false;\n    }\n};\nusing UserlandImageCache = ImageCacheDlIteratePhdr;\n#else\nusing UserlandImageCache = ImageCache;\n#endif //#ifdef TRACY_HAS_DL_ITERATE_PHDR_TO_REFRESH_IMAGE_CACHE\n\nstatic UserlandImageCache* s_imageCache;\nstatic ImageCache* s_krnlCache;\n\nvoid CreateImageCaches()\n{\n    assert( s_imageCache == nullptr && s_krnlCache == nullptr );\n    s_imageCache = new ( tracy_malloc( sizeof( UserlandImageCache ) ) ) UserlandImageCache();\n    s_krnlCache = new ( tracy_malloc( sizeof( ImageCache ) ) ) ImageCache();\n}\n\nvoid DestroyImageCaches()\n{\n    if( s_krnlCache != nullptr )\n    {\n        s_krnlCache->~ImageCache();\n        tracy_free( s_krnlCache );\n        s_krnlCache = nullptr;\n    }\n\n    if( s_imageCache != nullptr )\n    {\n        s_imageCache->~UserlandImageCache();\n        tracy_free( s_imageCache );\n        s_imageCache = nullptr;\n    }\n\n}\n\n\n// when \"TRACY_SYMBOL_OFFLINE_RESOLVE\" is set, instead of fully resolving symbols at runtime,\n// simply resolve the offset and image name (which will be enough the resolving to be done offline)\n#ifdef TRACY_SYMBOL_OFFLINE_RESOLVE\nconstexpr bool s_shouldResolveSymbolsOffline = true;\n#else\nstatic bool s_shouldResolveSymbolsOffline = false;\nbool ShouldResolveSymbolsOffline()\n{\n    const char* symbolOfflineResolve = GetEnvVar( \"TRACY_SYMBOL_OFFLINE_RESOLVE\" );\n    return (symbolOfflineResolve && symbolOfflineResolve[0] == '1');\n}\n#endif // #ifdef TRACY_SYMBOL_OFFLINE_RESOLVE\n\n#if TRACY_HAS_CALLSTACK == 1\n\nenum { MaxCbTrace = 64 };\nenum { MaxNameSize = 8*1024 };\n\nint cb_num;\nCallstackEntry cb_data[MaxCbTrace];\n\nextern \"C\"\n{\n    typedef DWORD (__stdcall *t_SymAddrIncludeInlineTrace)( HANDLE hProcess, DWORD64 Address );\n    typedef BOOL (__stdcall *t_SymQueryInlineTrace)( HANDLE hProcess, DWORD64 StartAddress, DWORD StartContext, DWORD64 StartRetAddress, DWORD64 CurAddress, LPDWORD CurContext, LPDWORD CurFrameIndex );\n    typedef BOOL (__stdcall *t_SymFromInlineContext)( HANDLE hProcess, DWORD64 Address, ULONG InlineContext, PDWORD64 Displacement, PSYMBOL_INFO Symbol );\n    typedef BOOL (__stdcall *t_SymGetLineFromInlineContext)( HANDLE hProcess, DWORD64 qwAddr, ULONG InlineContext, DWORD64 qwModuleBaseAddress, PDWORD pdwDisplacement, PIMAGEHLP_LINE64 Line64 );\n\n    t_SymAddrIncludeInlineTrace _SymAddrIncludeInlineTrace = 0;\n    t_SymQueryInlineTrace _SymQueryInlineTrace = 0;\n    t_SymFromInlineContext _SymFromInlineContext = 0;\n    t_SymGetLineFromInlineContext _SymGetLineFromInlineContext = 0;\n\n    typedef unsigned long (__stdcall *___tracy_t_RtlWalkFrameChain)( void**, unsigned long, unsigned long );\n    ___tracy_t_RtlWalkFrameChain ___tracy_RtlWalkFrameChainPtr = nullptr;\n    TRACY_API unsigned long ___tracy_RtlWalkFrameChain( void** callers, unsigned long count, unsigned long flags)\n    {\n        return ___tracy_RtlWalkFrameChainPtr(callers, count, flags);\n    }\n}\n\nvoid InitCallstackCritical()\n{\n    ___tracy_RtlWalkFrameChainPtr = (___tracy_t_RtlWalkFrameChain)GetProcAddress( GetModuleHandleA( \"ntdll.dll\" ), \"RtlWalkFrameChain\" );\n}\n\nvoid DbgHelpInit()\n{\n    if( s_shouldResolveSymbolsOffline ) return;\n\n    _SymAddrIncludeInlineTrace = (t_SymAddrIncludeInlineTrace)GetProcAddress(GetModuleHandleA(\"dbghelp.dll\"), \"SymAddrIncludeInlineTrace\");\n    _SymQueryInlineTrace = (t_SymQueryInlineTrace)GetProcAddress(GetModuleHandleA(\"dbghelp.dll\"), \"SymQueryInlineTrace\");\n    _SymFromInlineContext = (t_SymFromInlineContext)GetProcAddress(GetModuleHandleA(\"dbghelp.dll\"), \"SymFromInlineContext\");\n    _SymGetLineFromInlineContext = (t_SymGetLineFromInlineContext)GetProcAddress(GetModuleHandleA(\"dbghelp.dll\"), \"SymGetLineFromInlineContext\");\n\n#ifdef TRACY_DBGHELP_LOCK\n    DBGHELP_INIT;\n    DBGHELP_LOCK;\n#endif\n\n    SymInitialize( GetCurrentProcess(), nullptr, true );\n    SymSetOptions( SYMOPT_LOAD_LINES );\n\n#ifdef TRACY_DBGHELP_LOCK\n    DBGHELP_UNLOCK;\n#endif\n}\n\nDWORD64 DbgHelpLoadSymbolsForModule( const char* imageName, uint64_t baseOfDll, uint32_t bllSize )\n{\n    if( s_shouldResolveSymbolsOffline ) return 0;\n    return SymLoadModuleEx( GetCurrentProcess(), nullptr, imageName, nullptr, baseOfDll, bllSize, nullptr, 0 );\n}\n\nchar* FormatImageName( const char* imageName, uint32_t imageNameLength )\n{\n    // when doing offline symbol resolution, we must store the full path of the dll for the resolving to work\n    if( s_shouldResolveSymbolsOffline )\n    {\n        return CopyStringFast( imageName, imageNameLength );\n    }\n    else\n    {\n        const char* ptr = imageName + imageNameLength;\n        while( ptr > imageName && *ptr != '\\\\' && *ptr != '/' ) ptr--;\n        if( ptr > imageName ) ptr++;\n        const auto namelen = imageName + imageNameLength - ptr;\n\n        char* alloc = (char*)tracy_malloc_fast( namelen + 3 );\n        alloc[0] = '[';\n        memcpy( alloc + 1, ptr, namelen );\n        alloc[namelen + 1] = ']';\n        alloc[namelen + 2] = '\\0';\n        return alloc;\n    }\n}\n\nImageEntry* CacheModuleInfo( const char* imagePath, uint32_t imageNameLength, uint64_t baseOfDll, uint32_t dllSize )\n{\n    ImageEntry moduleEntry = {};\n    moduleEntry.m_startAddress = baseOfDll;\n    moduleEntry.m_endAddress = baseOfDll + dllSize;\n    moduleEntry.m_path = CopyStringFast( imagePath, imageNameLength );\n    moduleEntry.m_name = FormatImageName( imagePath, imageNameLength );\n\n    return s_imageCache->AddEntry( moduleEntry );\n}\n\nImageEntry* LoadSymbolsForModuleAndCache( const char* imagePath, uint32_t imageNameLength, uint64_t baseOfDll, uint32_t dllSize )\n{\n    DbgHelpLoadSymbolsForModule( imagePath, baseOfDll, dllSize );\n    return CacheModuleInfo( imagePath, imageNameLength, baseOfDll, dllSize );\n}\n\nstatic void CacheProcessDrivers()\n{\n    DWORD needed;\n    LPVOID dev[4096];\n    if( EnumDeviceDrivers( dev, sizeof(dev), &needed ) != 0 )\n    {\n        char windir[MAX_PATH];\n        if( !GetWindowsDirectoryA( windir, sizeof( windir ) ) ) memcpy( windir, \"c:\\\\windows\", 11 );\n        const auto windirlen = strlen( windir );\n\n        const auto sz = needed / sizeof( LPVOID );\n        for( size_t i=0; i<sz; i++ )\n        {\n            char fn[MAX_PATH];\n            const auto len = GetDeviceDriverBaseNameA( dev[i], fn, sizeof( fn ) );\n            if( len != 0 )\n            {\n                auto buf = (char*)tracy_malloc_fast( len+3 );\n                buf[0] = '<';\n                memcpy( buf+1, fn, len );\n                memcpy( buf+len+1, \">\", 2 );\n                \n                ImageEntry kernelDriver{};\n                kernelDriver.m_startAddress = (uint64_t)dev[i];\n                kernelDriver.m_endAddress = 0;\n                kernelDriver.m_name = buf;\n                kernelDriver.m_path = nullptr;\n\n                const auto len = GetDeviceDriverFileNameA( dev[i], fn, sizeof( fn ) );\n                if( len != 0 )\n                {\n                    char full[MAX_PATH];\n                    char* path = fn;\n\n                    if( memcmp( fn, \"\\\\SystemRoot\\\\\", 12 ) == 0 )\n                    {\n                        memcpy( full, windir, windirlen );\n                        strcpy( full + windirlen, fn + 11 );\n                        path = full;\n                    }\n\n                    DbgHelpLoadSymbolsForModule( path, (DWORD64)dev[i], 0 );\n                    \n                    kernelDriver.m_path = CopyString( path );\n                }\n\n                s_krnlCache->AddEntry(kernelDriver);\n            }\n        }\n        s_krnlCache->Sort();\n    }\n}\n\nstatic void CacheProcessModules()\n{\n    DWORD needed;\n    HANDLE proc = GetCurrentProcess();\n    HMODULE mod[1024];\n    if( EnumProcessModules( proc, mod, sizeof( mod ), &needed ) != 0 )\n    {\n        const auto sz = needed / sizeof( HMODULE );\n        for( size_t i=0; i<sz; i++ )\n        {\n            MODULEINFO info;\n            if( GetModuleInformation( proc, mod[i], &info, sizeof( info ) ) != 0 )\n            {\n                char name[1024];\n                const auto nameLength = GetModuleFileNameA( mod[i], name, 1021 );\n                if( nameLength > 0 )\n                {\n                    // This may be a new module loaded since our call to SymInitialize.\n                    // Just in case, force DbgHelp to load its pdb !\n                    LoadSymbolsForModuleAndCache( name, nameLength, (DWORD64)info.lpBaseOfDll, info.SizeOfImage );\n                }\n            }\n        }\n    }\n}\n\nvoid InitCallstack()\n{\n#ifndef TRACY_SYMBOL_OFFLINE_RESOLVE\n    s_shouldResolveSymbolsOffline = ShouldResolveSymbolsOffline();\n#endif //#ifndef TRACY_SYMBOL_OFFLINE_RESOLVE\n    if( s_shouldResolveSymbolsOffline )\n    {\n        TracyDebug(\"TRACY: enabling offline symbol resolving!\\n\");\n    }\n\n    CreateImageCaches();\n\n    DbgHelpInit();\n\n#ifdef TRACY_DBGHELP_LOCK\n    DBGHELP_LOCK;\n#endif\n\n    // use TRACY_NO_DBGHELP_INIT_LOAD=1 to disable preloading of driver\n    // and process module symbol loading at startup time - they will be loaded on demand later\n    // Sometimes this process can take a very long time and prevent resolving callstack frames\n    // symbols during that time.\n    const char* noInitLoadEnv = GetEnvVar( \"TRACY_NO_DBGHELP_INIT_LOAD\" );\n    const bool initTimeModuleLoad = !( noInitLoadEnv && noInitLoadEnv[0] == '1' );\n    if ( !initTimeModuleLoad )\n    {\n        TracyDebug(\"TRACY: skipping init time dbghelper module load\\n\");\n    }\n    else\n    {\n        CacheProcessDrivers();\n        CacheProcessModules();\n    }\n\n#ifdef TRACY_DBGHELP_LOCK\n    DBGHELP_UNLOCK;\n#endif\n}\n\nvoid EndCallstack()\n{\n    DestroyImageCaches();\n}\n\nconst char* DecodeCallstackPtrFast( uint64_t ptr )\n{\n    if( s_shouldResolveSymbolsOffline ) return \"[unresolved]\";\n\n    static char ret[MaxNameSize];\n    const auto proc = GetCurrentProcess();\n\n    char buf[sizeof( SYMBOL_INFO ) + MaxNameSize];\n    auto si = (SYMBOL_INFO*)buf;\n    si->SizeOfStruct = sizeof( SYMBOL_INFO );\n    si->MaxNameLen = MaxNameSize;\n\n#ifdef TRACY_DBGHELP_LOCK\n    DBGHELP_LOCK;\n#endif\n    if( SymFromAddr( proc, ptr, nullptr, si ) == 0 )\n    {\n        *ret = '\\0';\n    }\n    else\n    {\n        memcpy( ret, si->Name, si->NameLen );\n        ret[si->NameLen] = '\\0';\n    }\n#ifdef TRACY_DBGHELP_LOCK\n    DBGHELP_UNLOCK;\n#endif\n    return ret;\n}\n\nconst char* GetKernelModulePath( uint64_t addr )\n{\n    assert( IsKernelAddress( addr ) );\n    if( !s_krnlCache ) return nullptr;\n    const ImageEntry* imageEntry = s_krnlCache->GetImageForAddress( addr );\n    if( imageEntry ) return imageEntry->m_path;\n    return nullptr;\n}\n\nstruct ModuleNameAndBaseAddress\n{\n    const char* name;\n    uint64_t baseAddr;\n};\n\nModuleNameAndBaseAddress GetModuleNameAndPrepareSymbols( uint64_t addr )\n{\n    if( IsKernelAddress( addr ) )\n    {\n        const ImageEntry* entry = s_krnlCache->GetImageForAddress( addr );\n        if( entry != nullptr ) return ModuleNameAndBaseAddress{ entry->m_name, entry->m_startAddress };\n        return ModuleNameAndBaseAddress{ \"<kernel>\", addr };\n    }\n\n    const ImageEntry* entry = s_imageCache->GetImageForAddress( addr );\n    if( entry != nullptr ) return ModuleNameAndBaseAddress{ entry->m_name, entry->m_startAddress };\n\n    HANDLE proc = GetCurrentProcess();\n    // Do not use FreeLibrary because we set the flag GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT\n    // see https://learn.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-getmodulehandleexa to get more information\n    constexpr DWORD flag = GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT;\n    HMODULE mod = NULL;\n\n    InitRpmalloc();\n    if( GetModuleHandleExA( flag, (char*)addr, &mod ) != 0 )\n    {\n        MODULEINFO info;\n        if( GetModuleInformation( proc, mod, &info, sizeof( info ) ) != 0 )\n        {\n            const auto base = uint64_t( info.lpBaseOfDll );\n            if( addr >= base && addr < ( base + info.SizeOfImage ) )\n            {\n                char name[1024];\n                const auto nameLength = GetModuleFileNameA( mod, name, sizeof( name ) );\n                if( nameLength > 0 )\n                {\n                    // since this is the first time we encounter this module, load its symbols (needed for modules loaded after SymInitialize)\n                    ImageEntry* cachedModule = LoadSymbolsForModuleAndCache( name, nameLength, (DWORD64)info.lpBaseOfDll, info.SizeOfImage );\n                    return ModuleNameAndBaseAddress{ cachedModule->m_name, cachedModule->m_startAddress };\n                }\n            }\n        }\n    }\n\n    return ModuleNameAndBaseAddress{ \"[unknown]\", 0x0 };\n}\n\nCallstackSymbolData DecodeSymbolAddress( uint64_t ptr )\n{\n    CallstackSymbolData sym;\n\n    if( s_shouldResolveSymbolsOffline )\n    {\n        sym.file = \"[unknown]\";\n        sym.line = 0;\n        sym.needFree = false;\n        return sym;\n    }\n\n    IMAGEHLP_LINE64 line;\n    DWORD displacement = 0;\n    line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);\n#ifdef TRACY_DBGHELP_LOCK\n    DBGHELP_LOCK;\n#endif\n    const auto res = SymGetLineFromAddr64( GetCurrentProcess(), ptr, &displacement, &line );\n    if( res == 0 || line.LineNumber >= 0xF00000 )\n    {\n        sym.file = \"[unknown]\";\n        sym.line = 0;\n        sym.needFree = false;\n    }\n    else\n    {\n        sym.file = CopyString( line.FileName );\n        sym.line = line.LineNumber;\n        sym.needFree = true;\n    }\n#ifdef TRACY_DBGHELP_LOCK\n    DBGHELP_UNLOCK;\n#endif\n    return sym;\n}\n\nCallstackEntryData DecodeCallstackPtr( uint64_t ptr )\n{\n#ifdef TRACY_DBGHELP_LOCK\n    DBGHELP_LOCK;\n#endif\n\n    InitRpmalloc();\n\n    const ModuleNameAndBaseAddress moduleNameAndAddress = GetModuleNameAndPrepareSymbols( ptr );\n\n    if( s_shouldResolveSymbolsOffline )\n    {\n#ifdef TRACY_DBGHELP_LOCK\n        DBGHELP_UNLOCK;\n#endif\n\n        cb_data[0].symAddr = ptr - moduleNameAndAddress.baseAddr;\n        cb_data[0].symLen = 0;\n\n        cb_data[0].name = CopyStringFast(\"[unresolved]\");\n        cb_data[0].file = CopyStringFast(\"[unknown]\");\n        cb_data[0].line = 0;\n\n        return { cb_data, 1, moduleNameAndAddress.name };\n    }\n\n    int write;\n    const auto proc = GetCurrentProcess();\n\n#if !defined TRACY_NO_CALLSTACK_INLINES\n    BOOL doInline = FALSE;\n    DWORD ctx = 0;\n    DWORD inlineNum = 0;\n    if( _SymAddrIncludeInlineTrace )\n    {\n        inlineNum = _SymAddrIncludeInlineTrace( proc, ptr );\n        if( inlineNum > MaxCbTrace - 1 ) inlineNum = MaxCbTrace - 1;\n        DWORD idx;\n        if( inlineNum != 0 ) doInline = _SymQueryInlineTrace( proc, ptr, 0, ptr, ptr, &ctx, &idx );\n    }\n    if( doInline )\n    {\n        write = inlineNum;\n        cb_num = 1 + inlineNum;\n    }\n    else\n#endif\n    {\n        write = 0;\n        cb_num = 1;\n    }\n\n    char buf[sizeof( SYMBOL_INFO ) + MaxNameSize];\n    auto si = (SYMBOL_INFO*)buf;\n    si->SizeOfStruct = sizeof( SYMBOL_INFO );\n    si->MaxNameLen = MaxNameSize;\n\n    const auto symValid = SymFromAddr( proc, ptr, nullptr, si ) != 0;\n\n    IMAGEHLP_LINE64 line;\n    DWORD displacement = 0;\n    line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);\n\n    {\n        const char* filename;\n        const auto res = SymGetLineFromAddr64( proc, ptr, &displacement, &line );\n        if( res == 0 || line.LineNumber >= 0xF00000 )\n        {\n            filename = \"[unknown]\";\n            cb_data[write].line = 0;\n        }\n        else\n        {\n            filename = line.FileName;\n            cb_data[write].line = line.LineNumber;\n        }\n\n        cb_data[write].name = symValid ? CopyStringFast( si->Name, si->NameLen ) : CopyStringFast( moduleNameAndAddress.name );\n        cb_data[write].file = CopyStringFast( filename );\n        if( symValid )\n        {\n            cb_data[write].symLen = si->Size;\n            cb_data[write].symAddr = si->Address;\n        }\n        else\n        {\n            cb_data[write].symLen = 0;\n            cb_data[write].symAddr = 0;\n        }\n    }\n\n#if !defined TRACY_NO_CALLSTACK_INLINES\n    if( doInline )\n    {\n        for( DWORD i=0; i<inlineNum; i++ )\n        {\n            auto& cb = cb_data[i];\n            const auto symInlineValid = _SymFromInlineContext( proc, ptr, ctx, nullptr, si ) != 0;\n            const char* filename;\n            if( _SymGetLineFromInlineContext( proc, ptr, ctx, 0, &displacement, &line ) == 0 )\n            {\n                filename = \"[unknown]\";\n                cb.line = 0;\n            }\n            else\n            {\n                filename = line.FileName;\n                cb.line = line.LineNumber;\n            }\n\n            cb.name = symInlineValid ? CopyStringFast( si->Name, si->NameLen ) : CopyStringFast( moduleNameAndAddress.name );\n            cb.file = CopyStringFast( filename );\n            if( symInlineValid )\n            {\n                cb.symLen = si->Size;\n                cb.symAddr = si->Address;\n            }\n            else\n            {\n                cb.symLen = 0;\n                cb.symAddr = 0;\n            }\n\n            ctx++;\n        }\n    }\n#endif\n#ifdef TRACY_DBGHELP_LOCK\n    DBGHELP_UNLOCK;\n#endif\n\n    return { cb_data, uint8_t( cb_num ), moduleNameAndAddress.name };\n}\n\n#elif defined(TRACY_USE_LIBBACKTRACE)\n\nenum { MaxCbTrace = 64 };\n\nstruct backtrace_state* cb_bts = nullptr;\n\nint cb_num;\nCallstackEntry cb_data[MaxCbTrace];\nint cb_fixup;\n\n#ifdef TRACY_DEBUGINFOD\ndebuginfod_client* s_debuginfod;\n\nstruct DebugInfo\n{\n    uint8_t* buildid;\n    size_t buildid_size;\n    char* filename;\n    int fd;\n};\n\nstatic FastVector<DebugInfo>* s_di_known;\n#endif\n\n#ifdef __linux\nstruct KernelSymbol\n{\n    uint64_t addr;\n    uint32_t size;\n    const char* name;\n    const char* mod;\n};\n\nKernelSymbol* s_kernelSym = nullptr;\nsize_t s_kernelSymCnt;\n\nstatic void InitKernelSymbols()\n{\n    FILE* f = fopen( \"/proc/kallsyms\", \"rb\" );\n    if( !f ) return;\n    tracy::FastVector<KernelSymbol> tmpSym( 512 * 1024 );\n    size_t linelen = 16 * 1024;     // linelen must be big enough to prevent reallocs in getline()\n    auto linebuf = (char*)tracy_malloc( linelen );\n    ssize_t sz;\n    size_t validCnt = 0;\n    while( ( sz = getline( &linebuf, &linelen, f ) ) != -1 )\n    {\n        auto ptr = linebuf;\n        uint64_t addr = 0;\n        while( *ptr != ' ' )\n        {\n            auto v = *ptr;\n            if( v >= '0' && v <= '9' )\n            {\n                v -= '0';\n            }\n            else if( v >= 'a' && v <= 'f' )\n            {\n                v -= 'a';\n                v += 10;\n            }\n            else if( v >= 'A' && v <= 'F' )\n            {\n                v -= 'A';\n                v += 10;\n            }\n            else\n            {\n                assert( false );\n            }\n            assert( ( v & ~0xF ) == 0 );\n            addr <<= 4;\n            addr |= v;\n            ptr++;\n        }\n        if( addr == 0 ) continue;\n        ptr++;\n        const bool valid = *ptr == 'T' || *ptr == 't';\n        ptr += 2;\n        const auto namestart = ptr;\n        while( *ptr != '\\t' && *ptr != '\\n' ) ptr++;\n        const auto nameend = ptr;\n        const char* modstart = nullptr;\n        const char* modend;\n        if( *ptr == '\\t' )\n        {\n            ptr += 2;\n            modstart = ptr;\n            while( *ptr != ']' ) ptr++;\n            modend = ptr;\n        }\n\n        char* strname = nullptr;\n        char* strmod = nullptr;\n\n        if( valid )\n        {\n            validCnt++;\n\n            strname = (char*)tracy_malloc_fast( nameend - namestart + 1 );\n            memcpy( strname, namestart, nameend - namestart );\n            strname[nameend-namestart] = '\\0';\n\n            if( modstart )\n            {\n                strmod = (char*)tracy_malloc_fast( modend - modstart + 1 );\n                memcpy( strmod, modstart, modend - modstart );\n                strmod[modend-modstart] = '\\0';\n            }\n        }\n\n        auto sym = tmpSym.push_next();\n        sym->addr = addr;\n        sym->size = 0;\n        sym->name = strname;\n        sym->mod = strmod;\n    }\n    tracy_free_fast( linebuf );\n    fclose( f );\n    if( tmpSym.empty() ) return;\n\n    std::sort( tmpSym.begin(), tmpSym.end(), []( const KernelSymbol& lhs, const KernelSymbol& rhs ) { return lhs.addr < rhs.addr; } );\n    for( size_t i=0; i<tmpSym.size()-1; i++ )\n    {\n        if( tmpSym[i].name ) tmpSym[i].size = tmpSym[i+1].addr - tmpSym[i].addr;\n    }\n\n    s_kernelSymCnt = validCnt;\n    s_kernelSym = (KernelSymbol*)tracy_malloc_fast( sizeof( KernelSymbol ) * validCnt );\n    auto dst = s_kernelSym;\n    for( auto& v : tmpSym )\n    {\n        if( v.name ) *dst++ = v;\n    }\n    assert( dst == s_kernelSym + validCnt );\n\n    TracyDebug( \"Loaded %zu kernel symbols (%zu code sections)\\n\", tmpSym.size(), validCnt );\n}\n#endif\n\nchar* NormalizePath( const char* path )\n{\n    if( path[0] != '/' ) return nullptr;\n\n    const char* ptr = path;\n    const char* end = path + strlen( path );\n\n    char* res = (char*)tracy_malloc( end - ptr + 1 );\n    size_t rsz = 0;\n\n    while( ptr < end )\n    {\n        const char* next = ptr;\n        while( next < end && *next != '/' ) next++;\n        size_t lsz = next - ptr;\n        switch( lsz )\n        {\n        case 2:\n            if( memcmp( ptr, \"..\", 2 ) == 0 )\n            {\n                const char* back = res + rsz - 1;\n                while( back > res && *back != '/' ) back--;\n                rsz = back - res;\n                ptr = next + 1;\n                continue;\n            }\n            break;\n        case 1:\n            if( *ptr == '.' )\n            {\n                ptr = next + 1;\n                continue;\n            }\n            break;\n        case 0:\n            ptr = next + 1;\n            continue;\n        }\n        if( rsz != 1 ) res[rsz++] = '/';\n        memcpy( res+rsz, ptr, lsz );\n        rsz += lsz;\n        ptr = next + 1;\n    }\n\n    if( rsz == 0 )\n    {\n        memcpy( res, \"/\", 2 );\n    }\n    else\n    {\n        res[rsz] = '\\0';\n    }\n    return res;\n}\n\nvoid InitCallstackCritical()\n{\n}\n\nvoid InitCallstack()\n{\n    InitRpmalloc();\n\n#ifdef TRACY_HAS_DL_ITERATE_PHDR_TO_REFRESH_IMAGE_CACHE\n    CreateImageCaches();\n#endif //#ifdef TRACY_HAS_DL_ITERATE_PHDR_TO_REFRESH_IMAGE_CACHE\n\n#ifndef TRACY_SYMBOL_OFFLINE_RESOLVE\n    s_shouldResolveSymbolsOffline = ShouldResolveSymbolsOffline();\n#endif //#ifndef TRACY_SYMBOL_OFFLINE_RESOLVE\n    if( s_shouldResolveSymbolsOffline )\n    {\n        cb_bts = nullptr; // disable use of libbacktrace calls\n        TracyDebug(\"TRACY: enabling offline symbol resolving!\\n\");\n    }\n    else\n    {\n        cb_bts = backtrace_create_state( nullptr, 0, nullptr, nullptr );\n    }\n\n#ifndef TRACY_DEMANGLE\n    ___tracy_init_demangle_buffer();\n#endif\n\n#ifdef __linux\n    InitKernelSymbols();\n#endif\n#ifdef TRACY_DEBUGINFOD\n    s_debuginfod = debuginfod_begin();\n    s_di_known = (FastVector<DebugInfo>*)tracy_malloc( sizeof( FastVector<DebugInfo> ) );\n    new (s_di_known) FastVector<DebugInfo>( 16 );\n#endif\n}\n\n#ifdef TRACY_DEBUGINFOD\nvoid ClearDebugInfoVector( FastVector<DebugInfo>& vec )\n{\n    for( auto& v : vec )\n    {\n        tracy_free( v.buildid );\n        tracy_free( v.filename );\n        if( v.fd >= 0 ) close( v.fd );\n    }\n    vec.clear();\n}\n\nDebugInfo* FindDebugInfo( FastVector<DebugInfo>& vec, const uint8_t* buildid_data, size_t buildid_size )\n{\n    for( auto& v : vec )\n    {\n        if( v.buildid_size == buildid_size && memcmp( v.buildid, buildid_data, buildid_size ) == 0 )\n        {\n            return &v;\n        }\n    }\n    return nullptr;\n}\n\nint GetDebugInfoDescriptor( const char* buildid_data, size_t buildid_size, const char* filename )\n{\n    auto buildid = (uint8_t*)buildid_data;\n    auto it = FindDebugInfo( *s_di_known, buildid, buildid_size );\n    if( it ) return it->fd >= 0 ? dup( it->fd ) : -1;\n\n    int fd = debuginfod_find_debuginfo( s_debuginfod, buildid, buildid_size, nullptr );\n    it = s_di_known->push_next();\n    it->buildid_size = buildid_size;\n    it->buildid = (uint8_t*)tracy_malloc( buildid_size );\n    memcpy( it->buildid, buildid, buildid_size );\n    const auto fnsz = strlen( filename ) + 1;\n    it->filename = (char*)tracy_malloc( fnsz );\n    memcpy( it->filename, filename, fnsz );\n    it->fd = fd >= 0 ? fd : -1;\n    TracyDebug( \"DebugInfo descriptor query: %i, fn: %s\\n\", fd, filename );\n    return it->fd;\n}\n\nconst uint8_t* GetBuildIdForImage( const char* image, size_t& size )\n{\n    assert( image );\n    for( auto& v : *s_di_known )\n    {\n        if( strcmp( image, v.filename ) == 0 )\n        {\n            size = v.buildid_size;\n            return v.buildid;\n        }\n    }\n    return nullptr;\n}\n\ndebuginfod_client* GetDebuginfodClient()\n{\n    return s_debuginfod;\n}\n#endif\n\nvoid EndCallstack()\n{\n#ifdef TRACY_HAS_DL_ITERATE_PHDR_TO_REFRESH_IMAGE_CACHE\n    DestroyImageCaches();\n#endif //#ifdef TRACY_HAS_DL_ITERATE_PHDR_TO_REFRESH_IMAGE_CACHE\n#ifndef TRACY_DEMANGLE\n    ___tracy_free_demangle_buffer();\n#endif\n#ifdef TRACY_DEBUGINFOD\n    ClearDebugInfoVector( *s_di_known );\n    s_di_known->~FastVector<DebugInfo>();\n    tracy_free( s_di_known );\n\n    debuginfod_end( s_debuginfod );\n#endif\n}\n\nconst char* DecodeCallstackPtrFast( uint64_t ptr )\n{\n    static char ret[1024];\n    auto vptr = (void*)ptr;\n    const char* symname = nullptr;\n    Dl_info dlinfo;\n    if( dladdr( vptr, &dlinfo ) && dlinfo.dli_sname )\n    {\n        symname = dlinfo.dli_sname;\n    }\n    if( symname )\n    {\n        strcpy( ret, symname );\n    }\n    else\n    {\n        *ret = '\\0';\n    }\n    return ret;\n}\n\nstatic int SymbolAddressDataCb( void* data, uintptr_t pc, uintptr_t lowaddr, const char* fn, int lineno, const char* function )\n{\n    auto& sym = *(CallstackSymbolData*)data;\n    if( !fn )\n    {\n        sym.file = \"[unknown]\";\n        sym.line = 0;\n        sym.needFree = false;\n    }\n    else\n    {\n        sym.file = NormalizePath( fn );\n        if( !sym.file ) sym.file = CopyString( fn );\n        sym.line = lineno;\n        sym.needFree = true;\n    }\n\n    return 1;\n}\n\nstatic void SymbolAddressErrorCb( void* data, const char* /*msg*/, int /*errnum*/ )\n{\n    auto& sym = *(CallstackSymbolData*)data;\n    sym.file = \"[unknown]\";\n    sym.line = 0;\n    sym.needFree = false;\n}\n\nCallstackSymbolData DecodeSymbolAddress( uint64_t ptr )\n{\n    CallstackSymbolData sym;\n    if( cb_bts )\n    {\n        backtrace_pcinfo( cb_bts, ptr, SymbolAddressDataCb, SymbolAddressErrorCb, &sym );\n    }\n    else\n    {\n        SymbolAddressErrorCb(&sym, nullptr, 0);\n    }\n\n    return sym;\n}\n\nstatic int CallstackDataCb( void* /*data*/, uintptr_t pc, uintptr_t lowaddr, const char* fn, int lineno, const char* function )\n{\n    cb_data[cb_num].symLen = 0;\n    cb_data[cb_num].symAddr = (uint64_t)lowaddr;\n\n    if( !fn && !function )\n    {\n        const char* symname = nullptr;\n        auto vptr = (void*)pc;\n        ptrdiff_t symoff = 0;\n\n        Dl_info dlinfo;\n        if( dladdr( vptr, &dlinfo ) )\n        {\n            symname = dlinfo.dli_sname;\n            symoff = (char*)pc - (char*)dlinfo.dli_saddr;\n            const char* demangled = ___tracy_demangle( symname );\n            if( demangled ) symname = demangled;\n        }\n\n        if( !symname ) symname = \"[unknown]\";\n\n        if( symoff == 0 )\n        {\n            const auto len = std::min<size_t>( strlen( symname ), std::numeric_limits<uint16_t>::max() );\n            cb_data[cb_num].name = CopyStringFast( symname, len );\n        }\n        else\n        {\n            char buf[32];\n            const auto offlen = sprintf( buf, \" + %td\", symoff );\n            const auto namelen = std::min<size_t>( strlen( symname ), std::numeric_limits<uint16_t>::max() - offlen );\n            auto name = (char*)tracy_malloc_fast( namelen + offlen + 1 );\n            memcpy( name, symname, namelen );\n            memcpy( name + namelen, buf, offlen );\n            name[namelen + offlen] = '\\0';\n            cb_data[cb_num].name = name;\n        }\n\n        cb_data[cb_num].file = CopyStringFast( \"[unknown]\" );\n        cb_data[cb_num].line = 0;\n    }\n    else\n    {\n        if( !fn ) fn = \"[unknown]\";\n        if( !function )\n        {\n            function = \"[unknown]\";\n        }\n        else\n        {\n            const char* demangled = ___tracy_demangle( function );\n            if( demangled ) function = demangled;\n        }\n\n        const auto len = std::min<size_t>( strlen( function ), std::numeric_limits<uint16_t>::max() );\n        cb_data[cb_num].name = CopyStringFast( function, len );\n        cb_data[cb_num].file = NormalizePath( fn );\n        if( !cb_data[cb_num].file ) cb_data[cb_num].file = CopyStringFast( fn );\n        cb_data[cb_num].line = lineno;\n    }\n\n    if( ++cb_num >= MaxCbTrace )\n    {\n        return 1;\n    }\n    else\n    {\n        return 0;\n    }\n}\n\nstatic void CallstackErrorCb( void* /*data*/, const char* /*msg*/, int /*errnum*/ )\n{\n    for( int i=0; i<cb_num; i++ )\n    {\n        tracy_free_fast( (void*)cb_data[i].name );\n        tracy_free_fast( (void*)cb_data[i].file );\n    }\n\n    cb_data[0].name = CopyStringFast( \"[error]\" );\n    cb_data[0].file = CopyStringFast( \"[error]\" );\n    cb_data[0].line = 0;\n\n    cb_num = 1;\n}\n\nvoid SymInfoCallback( void* /*data*/, uintptr_t pc, const char* symname, uintptr_t symval, uintptr_t symsize )\n{\n    cb_data[cb_num-1].symLen = (uint32_t)symsize;\n    cb_data[cb_num-1].symAddr = (uint64_t)symval;\n}\n\nvoid SymInfoError( void* /*data*/, const char* /*msg*/, int /*errnum*/ )\n{\n    cb_data[cb_num-1].symLen = 0;\n    cb_data[cb_num-1].symAddr = 0;\n}\n\nvoid GetSymbolForOfflineResolve(void* address, uint64_t imageBaseAddress, CallstackEntry& cbEntry)\n{\n    // tagged with a string that we can identify as an unresolved symbol\n    cbEntry.name = CopyStringFast( \"[unresolved]\" );\n    // set .so relative offset so it can be resolved offline\n    cbEntry.symAddr = (uint64_t)address - imageBaseAddress;\n    cbEntry.symLen = 0x0;\n    cbEntry.file = CopyStringFast( \"[unknown]\" );\n    cbEntry.line = 0;\n}\n\nCallstackEntryData DecodeCallstackPtr( uint64_t ptr )\n{\n    InitRpmalloc();\n    if ( !IsKernelAddress( ptr ) )\n    {\n        const char* imageName = nullptr;\n        uint64_t imageBaseAddress = 0x0;\n\n#ifdef TRACY_HAS_DL_ITERATE_PHDR_TO_REFRESH_IMAGE_CACHE\n        const auto* image = s_imageCache->GetImageForAddress( ptr );\n        if( image )\n        {\n            imageName = image->m_name;\n            imageBaseAddress = uint64_t( image->m_startAddress );\n        }\n#else\n        Dl_info dlinfo;\n        if( dladdr( (void*)ptr, &dlinfo ) )\n        {\n            imageName = dlinfo.dli_fname;\n            imageBaseAddress = uint64_t( dlinfo.dli_fbase );\n        }\n#endif\n\n        if( s_shouldResolveSymbolsOffline )\n        {\n            cb_num = 1;\n            GetSymbolForOfflineResolve( (void*)ptr, imageBaseAddress, cb_data[0] );\n        }\n        else\n        {\n            cb_num = 0;\n            backtrace_pcinfo( cb_bts, ptr, CallstackDataCb, CallstackErrorCb, nullptr );\n            assert( cb_num > 0 );\n\n            backtrace_syminfo( cb_bts, ptr, SymInfoCallback, SymInfoError, nullptr );\n        }\n\n        return { cb_data, uint8_t( cb_num ), imageName ? imageName : \"[unknown]\" };\n    }\n#ifdef __linux\n    else if( s_kernelSym )\n    {\n        auto it = std::lower_bound( s_kernelSym, s_kernelSym + s_kernelSymCnt, ptr, []( const KernelSymbol& lhs, const uint64_t& rhs ) { return lhs.addr + lhs.size < rhs; } );\n        if( it != s_kernelSym + s_kernelSymCnt )\n        {\n            cb_data[0].name = CopyStringFast( it->name );\n            cb_data[0].file = CopyStringFast( \"<kernel>\" );\n            cb_data[0].line = 0;\n            cb_data[0].symLen = it->size;\n            cb_data[0].symAddr = it->addr;\n            return { cb_data, 1, it->mod ? it->mod : \"<kernel>\" };\n        }\n    }\n#endif\n\n    cb_data[0].name = CopyStringFast( \"[unknown]\" );\n    cb_data[0].file = CopyStringFast( \"<kernel>\" );\n    cb_data[0].line = 0;\n    cb_data[0].symLen = 0;\n    cb_data[0].symAddr = 0;\n    return { cb_data, 1, \"<kernel>\" };\n}\n\n#elif TRACY_HAS_CALLSTACK == 5\n\nvoid InitCallstackCritical()\n{\n}\n\nvoid InitCallstack()\n{\n    ___tracy_init_demangle_buffer();\n}\n\nvoid EndCallstack()\n{\n    ___tracy_free_demangle_buffer();\n}\n\nconst char* DecodeCallstackPtrFast( uint64_t ptr )\n{\n    static char ret[1024];\n    auto vptr = (void*)ptr;\n    const char* symname = nullptr;\n    Dl_info dlinfo;\n    if( dladdr( vptr, &dlinfo ) && dlinfo.dli_sname )\n    {\n        symname = dlinfo.dli_sname;\n    }\n    if( symname )\n    {\n        strcpy( ret, symname );\n    }\n    else\n    {\n        *ret = '\\0';\n    }\n    return ret;\n}\n\nCallstackSymbolData DecodeSymbolAddress( uint64_t ptr )\n{\n    const char* symloc = nullptr;\n    Dl_info dlinfo;\n    if( dladdr( (void*)ptr, &dlinfo ) ) symloc = dlinfo.dli_fname;\n    if( !symloc ) symloc = \"[unknown]\";\n    return CallstackSymbolData { symloc, 0, false, 0 };\n}\n\nCallstackEntryData DecodeCallstackPtr( uint64_t ptr )\n{\n    static CallstackEntry cb;\n    cb.line = 0;\n\n    const char* symname = nullptr;\n    const char* symloc = nullptr;\n    auto vptr = (void*)ptr;\n    ptrdiff_t symoff = 0;\n    void* symaddr = nullptr;\n\n    Dl_info dlinfo;\n    if( dladdr( vptr, &dlinfo ) )\n    {\n        symloc = dlinfo.dli_fname;\n        symname = dlinfo.dli_sname;\n        symoff = (char*)ptr - (char*)dlinfo.dli_saddr;\n        symaddr = dlinfo.dli_saddr;\n        const char* demangled = ___tracy_demangle( symname );\n        if( demangled ) symname = demangled;\n    }\n\n    if( !symname ) symname = \"[unknown]\";\n    if( !symloc ) symloc = \"[unknown]\";\n\n    if( symoff == 0 )\n    {\n        const auto len = std::min<size_t>( strlen( symname ), std::numeric_limits<uint16_t>::max() );\n        cb.name = CopyString( symname, len );\n    }\n    else\n    {\n        char buf[32];\n        const auto offlen = sprintf( buf, \" + %td\", symoff );\n        const auto namelen = std::min<size_t>( strlen( symname ), std::numeric_limits<uint16_t>::max() - offlen );\n        auto name = (char*)tracy_malloc( namelen + offlen + 1 );\n        memcpy( name, symname, namelen );\n        memcpy( name + namelen, buf, offlen );\n        name[namelen + offlen] = '\\0';\n        cb.name = name;\n    }\n\n    cb.file = CopyString( \"[unknown]\" );\n    cb.symLen = 0;\n    cb.symAddr = (uint64_t)symaddr;\n\n    return { &cb, 1, symloc };\n}\n\n#endif\n\n}\n\n#endif\n"
  },
  {
    "path": "tracy-client-sys/tracy/client/TracyCallstack.h",
    "content": "#ifndef __TRACYCALLSTACK_H__\n#define __TRACYCALLSTACK_H__\n\n#ifndef TRACY_NO_CALLSTACK\n\n#  if !defined _WIN32\n#    include <sys/param.h>\n#  endif\n\n#  if defined _WIN32\n#    include \"../common/TracyWinFamily.hpp\"\n#    if !defined TRACY_WIN32_NO_DESKTOP\n#      define TRACY_HAS_CALLSTACK 1\n#    endif\n#  elif defined __ANDROID__\n#    if !defined __arm__ || __ANDROID_API__ >= 21\n#      define TRACY_HAS_CALLSTACK 2\n#    else\n#      define TRACY_HAS_CALLSTACK 5\n#    endif\n#  elif defined __linux\n#    if defined _GNU_SOURCE && defined __GLIBC__\n#      define TRACY_HAS_CALLSTACK 3\n#    else\n#      define TRACY_HAS_CALLSTACK 2\n#    endif\n#  elif defined __APPLE__\n#    define TRACY_HAS_CALLSTACK 4\n#  elif defined BSD\n#    define TRACY_HAS_CALLSTACK 6\n#  endif\n\n#if TRACY_HAS_CALLSTACK == 2 || TRACY_HAS_CALLSTACK == 3 || TRACY_HAS_CALLSTACK == 4 || TRACY_HAS_CALLSTACK == 6\n#define TRACY_USE_LIBBACKTRACE\n#endif\n\n#endif\n\n#endif\n"
  },
  {
    "path": "tracy-client-sys/tracy/client/TracyCallstack.hpp",
    "content": "#ifndef __TRACYCALLSTACK_HPP__\n#define __TRACYCALLSTACK_HPP__\n\n#include <stdint.h>\n\n#include \"../common/TracyApi.h\"\n#include \"../common/TracyForceInline.hpp\"\n#include \"TracyCallstack.h\"\n\nnamespace tracy\n{\n\nstruct ImageEntry\n{\n    uint64_t m_startAddress = 0;\n    uint64_t m_endAddress = 0;\n    char* m_name = nullptr;\n    char* m_path = nullptr;\n};\n\n}\n\n#ifndef TRACY_HAS_CALLSTACK\n\nnamespace tracy\n{\nstatic constexpr bool has_callstack() { return false; }\nstatic tracy_force_inline void* Callstack( int32_t /*depth*/ ) { return nullptr; }\n}\n\n#else\n\n#if TRACY_HAS_CALLSTACK == 2 || TRACY_HAS_CALLSTACK == 5\n#  include <unwind.h>\n#elif TRACY_HAS_CALLSTACK >= 3\n#  ifdef TRACY_LIBUNWIND_BACKTRACE\n     // libunwind is, in general, significantly faster than execinfo based backtraces\n#    define UNW_LOCAL_ONLY\n#    include <libunwind.h>\n#  else\n#    include <execinfo.h>\n#  endif\n#endif\n\n#ifdef TRACY_DEBUGINFOD\n#  include <elfutils/debuginfod.h>\n#endif\n\n#include <assert.h>\n#include <stdint.h>\n\n#include \"../common/TracyAlloc.hpp\"\n\nnamespace tracy\n{\n\nstatic constexpr bool has_callstack() { return true; }\n\nstruct CallstackSymbolData\n{\n    const char* file;\n    uint32_t line;\n    bool needFree;\n    uint64_t symAddr;\n};\n\nstruct CallstackEntry\n{\n    const char* name;\n    const char* file;\n    uint32_t line;\n    uint32_t symLen;\n    uint64_t symAddr;\n};\n\nstruct CallstackEntryData\n{\n    const CallstackEntry* data;\n    uint8_t size;\n    const char* imageName;\n};\n\nCallstackSymbolData DecodeSymbolAddress( uint64_t ptr );\nconst char* DecodeCallstackPtrFast( uint64_t ptr );\nCallstackEntryData DecodeCallstackPtr( uint64_t ptr );\nvoid InitCallstack();\nvoid InitCallstackCritical();\nvoid EndCallstack();\nconst char* GetKernelModulePath( uint64_t addr );\n\n#ifdef TRACY_DEBUGINFOD\nconst uint8_t* GetBuildIdForImage( const char* image, size_t& size );\ndebuginfod_client* GetDebuginfodClient();\n#endif\n\n#if TRACY_HAS_CALLSTACK == 1\n\nextern \"C\"\n{\n    TRACY_API unsigned long ___tracy_RtlWalkFrameChain( void**, unsigned long, unsigned long );\n}\n\nstatic tracy_force_inline void* Callstack( int32_t depth )\n{\n    assert( depth >= 1 && depth < 63 );\n    auto trace = (uintptr_t*)tracy_malloc( ( 1 + depth ) * sizeof( uintptr_t ) );\n    const auto num = ___tracy_RtlWalkFrameChain( (void**)( trace + 1 ), depth, 0 );\n    *trace = num;\n    return trace;\n}\n\n#elif TRACY_HAS_CALLSTACK == 2 || TRACY_HAS_CALLSTACK == 5\n\nstruct BacktraceState\n{\n    void** current;\n    void** end;\n};\n\nstatic _Unwind_Reason_Code tracy_unwind_callback( struct _Unwind_Context* ctx, void* arg )\n{\n    auto state = (BacktraceState*)arg;\n    uintptr_t pc = _Unwind_GetIP( ctx );\n    if( pc )\n    {\n        if( state->current == state->end ) return _URC_END_OF_STACK;\n        *state->current++ = (void*)pc;\n    }\n    return _URC_NO_REASON;\n}\n\nstatic tracy_force_inline void* Callstack( int32_t depth )\n{\n    assert( depth >= 1 && depth < 63 );\n\n    auto trace = (uintptr_t*)tracy_malloc( ( 1 + depth ) * sizeof( uintptr_t ) );\n    BacktraceState state = { (void**)(trace+1), (void**)(trace+1+depth) };\n    _Unwind_Backtrace( tracy_unwind_callback, &state );\n\n    *trace = (uintptr_t*)state.current - trace + 1;\n\n    return trace;\n}\n\n#elif TRACY_HAS_CALLSTACK == 3 || TRACY_HAS_CALLSTACK == 4 || TRACY_HAS_CALLSTACK == 6\n\nstatic tracy_force_inline void* Callstack( int32_t depth )\n{\n    assert( depth >= 1 );\n\n    auto trace = (uintptr_t*)tracy_malloc( ( 1 + (size_t)depth ) * sizeof( uintptr_t ) );\n\n#ifdef TRACY_LIBUNWIND_BACKTRACE\n    size_t num =  unw_backtrace( (void**)(trace+1), depth );\n#else\n    const auto num = (size_t)backtrace( (void**)(trace+1), depth );\n#endif\n\n    *trace = num;\n\n    return trace;\n}\n\n#endif\n\n}\n\n#endif\n\n#endif\n"
  },
  {
    "path": "tracy-client-sys/tracy/client/TracyCpuid.hpp",
    "content": "#ifndef __TRACYCPUID_HPP__\n#define __TRACYCPUID_HPP__\n\n// Prior to GCC 11 the cpuid.h header did not have any include guards and thus\n// including it more than once would cause a compiler error due to symbol\n// redefinitions. In order to support older GCC versions, we have to wrap this\n// include between custom include guards to prevent this issue.\n// See also https://github.com/wolfpld/tracy/issues/452\n\n#include <cpuid.h>\n\n#endif\n"
  },
  {
    "path": "tracy-client-sys/tracy/client/TracyDebug.hpp",
    "content": "#ifndef __TRACYPRINT_HPP__\n#define __TRACYPRINT_HPP__\n\n#ifdef TRACY_VERBOSE\n#  include <stdio.h>\n#  define TracyDebug(...) fprintf( stderr, __VA_ARGS__ );\n#else\n#  define TracyDebug(...)\n#endif\n\n#endif\n"
  },
  {
    "path": "tracy-client-sys/tracy/client/TracyDxt1.cpp",
    "content": "#include \"TracyDxt1.hpp\"\n#include \"../common/TracyForceInline.hpp\"\n\n#include <assert.h>\n#include <stdint.h>\n#include <string.h>\n\n#ifdef __ARM_NEON\n#  include <arm_neon.h>\n#endif\n\n#if defined __AVX__ && !defined __SSE4_1__\n#  define __SSE4_1__\n#endif\n\n#if defined __SSE4_1__ || defined __AVX2__\n#  ifdef _MSC_VER\n#    include <intrin.h>\n#  else\n#    include <x86intrin.h>\n#    ifndef _mm256_cvtsi256_si32\n#      define _mm256_cvtsi256_si32( v ) ( _mm_cvtsi128_si32( _mm256_castsi256_si128( v ) ) )\n#    endif\n#  endif\n#endif\n\nnamespace tracy\n{\n\nstatic inline uint16_t to565( uint8_t r, uint8_t g, uint8_t b )\n{\n    return ( ( r & 0xF8 ) << 8 ) | ( ( g & 0xFC ) << 3 ) | ( b >> 3 );\n}\n\nstatic inline uint16_t to565( uint32_t c )\n{\n    return\n        ( ( c & 0xF80000 ) >> 19 ) |\n        ( ( c & 0x00FC00 ) >> 5 ) |\n        ( ( c & 0x0000F8 ) << 8 );\n}\n\nstatic const uint16_t DivTable[255*3+1] = {\n    0xffff, 0xffff, 0xffff, 0xffff, 0xcccc, 0xaaaa, 0x9249, 0x8000, 0x71c7, 0x6666, 0x5d17, 0x5555, 0x4ec4, 0x4924, 0x4444, 0x4000,\n    0x3c3c, 0x38e3, 0x35e5, 0x3333, 0x30c3, 0x2e8b, 0x2c85, 0x2aaa, 0x28f5, 0x2762, 0x25ed, 0x2492, 0x234f, 0x2222, 0x2108, 0x2000,\n    0x1f07, 0x1e1e, 0x1d41, 0x1c71, 0x1bac, 0x1af2, 0x1a41, 0x1999, 0x18f9, 0x1861, 0x17d0, 0x1745, 0x16c1, 0x1642, 0x15c9, 0x1555,\n    0x14e5, 0x147a, 0x1414, 0x13b1, 0x1352, 0x12f6, 0x129e, 0x1249, 0x11f7, 0x11a7, 0x115b, 0x1111, 0x10c9, 0x1084, 0x1041, 0x1000,\n    0x0fc0, 0x0f83, 0x0f48, 0x0f0f, 0x0ed7, 0x0ea0, 0x0e6c, 0x0e38, 0x0e07, 0x0dd6, 0x0da7, 0x0d79, 0x0d4c, 0x0d20, 0x0cf6, 0x0ccc,\n    0x0ca4, 0x0c7c, 0x0c56, 0x0c30, 0x0c0c, 0x0be8, 0x0bc5, 0x0ba2, 0x0b81, 0x0b60, 0x0b40, 0x0b21, 0x0b02, 0x0ae4, 0x0ac7, 0x0aaa,\n    0x0a8e, 0x0a72, 0x0a57, 0x0a3d, 0x0a23, 0x0a0a, 0x09f1, 0x09d8, 0x09c0, 0x09a9, 0x0991, 0x097b, 0x0964, 0x094f, 0x0939, 0x0924,\n    0x090f, 0x08fb, 0x08e7, 0x08d3, 0x08c0, 0x08ad, 0x089a, 0x0888, 0x0876, 0x0864, 0x0853, 0x0842, 0x0831, 0x0820, 0x0810, 0x0800,\n    0x07f0, 0x07e0, 0x07d1, 0x07c1, 0x07b3, 0x07a4, 0x0795, 0x0787, 0x0779, 0x076b, 0x075d, 0x0750, 0x0743, 0x0736, 0x0729, 0x071c,\n    0x070f, 0x0703, 0x06f7, 0x06eb, 0x06df, 0x06d3, 0x06c8, 0x06bc, 0x06b1, 0x06a6, 0x069b, 0x0690, 0x0685, 0x067b, 0x0670, 0x0666,\n    0x065c, 0x0652, 0x0648, 0x063e, 0x0634, 0x062b, 0x0621, 0x0618, 0x060f, 0x0606, 0x05fd, 0x05f4, 0x05eb, 0x05e2, 0x05d9, 0x05d1,\n    0x05c9, 0x05c0, 0x05b8, 0x05b0, 0x05a8, 0x05a0, 0x0598, 0x0590, 0x0588, 0x0581, 0x0579, 0x0572, 0x056b, 0x0563, 0x055c, 0x0555,\n    0x054e, 0x0547, 0x0540, 0x0539, 0x0532, 0x052b, 0x0525, 0x051e, 0x0518, 0x0511, 0x050b, 0x0505, 0x04fe, 0x04f8, 0x04f2, 0x04ec,\n    0x04e6, 0x04e0, 0x04da, 0x04d4, 0x04ce, 0x04c8, 0x04c3, 0x04bd, 0x04b8, 0x04b2, 0x04ad, 0x04a7, 0x04a2, 0x049c, 0x0497, 0x0492,\n    0x048d, 0x0487, 0x0482, 0x047d, 0x0478, 0x0473, 0x046e, 0x0469, 0x0465, 0x0460, 0x045b, 0x0456, 0x0452, 0x044d, 0x0448, 0x0444,\n    0x043f, 0x043b, 0x0436, 0x0432, 0x042d, 0x0429, 0x0425, 0x0421, 0x041c, 0x0418, 0x0414, 0x0410, 0x040c, 0x0408, 0x0404, 0x0400,\n    0x03fc, 0x03f8, 0x03f4, 0x03f0, 0x03ec, 0x03e8, 0x03e4, 0x03e0, 0x03dd, 0x03d9, 0x03d5, 0x03d2, 0x03ce, 0x03ca, 0x03c7, 0x03c3,\n    0x03c0, 0x03bc, 0x03b9, 0x03b5, 0x03b2, 0x03ae, 0x03ab, 0x03a8, 0x03a4, 0x03a1, 0x039e, 0x039b, 0x0397, 0x0394, 0x0391, 0x038e,\n    0x038b, 0x0387, 0x0384, 0x0381, 0x037e, 0x037b, 0x0378, 0x0375, 0x0372, 0x036f, 0x036c, 0x0369, 0x0366, 0x0364, 0x0361, 0x035e,\n    0x035b, 0x0358, 0x0355, 0x0353, 0x0350, 0x034d, 0x034a, 0x0348, 0x0345, 0x0342, 0x0340, 0x033d, 0x033a, 0x0338, 0x0335, 0x0333,\n    0x0330, 0x032e, 0x032b, 0x0329, 0x0326, 0x0324, 0x0321, 0x031f, 0x031c, 0x031a, 0x0317, 0x0315, 0x0313, 0x0310, 0x030e, 0x030c,\n    0x0309, 0x0307, 0x0305, 0x0303, 0x0300, 0x02fe, 0x02fc, 0x02fa, 0x02f7, 0x02f5, 0x02f3, 0x02f1, 0x02ef, 0x02ec, 0x02ea, 0x02e8,\n    0x02e6, 0x02e4, 0x02e2, 0x02e0, 0x02de, 0x02dc, 0x02da, 0x02d8, 0x02d6, 0x02d4, 0x02d2, 0x02d0, 0x02ce, 0x02cc, 0x02ca, 0x02c8,\n    0x02c6, 0x02c4, 0x02c2, 0x02c0, 0x02be, 0x02bc, 0x02bb, 0x02b9, 0x02b7, 0x02b5, 0x02b3, 0x02b1, 0x02b0, 0x02ae, 0x02ac, 0x02aa,\n    0x02a8, 0x02a7, 0x02a5, 0x02a3, 0x02a1, 0x02a0, 0x029e, 0x029c, 0x029b, 0x0299, 0x0297, 0x0295, 0x0294, 0x0292, 0x0291, 0x028f,\n    0x028d, 0x028c, 0x028a, 0x0288, 0x0287, 0x0285, 0x0284, 0x0282, 0x0280, 0x027f, 0x027d, 0x027c, 0x027a, 0x0279, 0x0277, 0x0276,\n    0x0274, 0x0273, 0x0271, 0x0270, 0x026e, 0x026d, 0x026b, 0x026a, 0x0268, 0x0267, 0x0265, 0x0264, 0x0263, 0x0261, 0x0260, 0x025e,\n    0x025d, 0x025c, 0x025a, 0x0259, 0x0257, 0x0256, 0x0255, 0x0253, 0x0252, 0x0251, 0x024f, 0x024e, 0x024d, 0x024b, 0x024a, 0x0249,\n    0x0247, 0x0246, 0x0245, 0x0243, 0x0242, 0x0241, 0x0240, 0x023e, 0x023d, 0x023c, 0x023b, 0x0239, 0x0238, 0x0237, 0x0236, 0x0234,\n    0x0233, 0x0232, 0x0231, 0x0230, 0x022e, 0x022d, 0x022c, 0x022b, 0x022a, 0x0229, 0x0227, 0x0226, 0x0225, 0x0224, 0x0223, 0x0222,\n    0x0220, 0x021f, 0x021e, 0x021d, 0x021c, 0x021b, 0x021a, 0x0219, 0x0218, 0x0216, 0x0215, 0x0214, 0x0213, 0x0212, 0x0211, 0x0210,\n    0x020f, 0x020e, 0x020d, 0x020c, 0x020b, 0x020a, 0x0209, 0x0208, 0x0207, 0x0206, 0x0205, 0x0204, 0x0203, 0x0202, 0x0201, 0x0200,\n    0x01ff, 0x01fe, 0x01fd, 0x01fc, 0x01fb, 0x01fa, 0x01f9, 0x01f8, 0x01f7, 0x01f6, 0x01f5, 0x01f4, 0x01f3, 0x01f2, 0x01f1, 0x01f0,\n    0x01ef, 0x01ee, 0x01ed, 0x01ec, 0x01eb, 0x01ea, 0x01e9, 0x01e9, 0x01e8, 0x01e7, 0x01e6, 0x01e5, 0x01e4, 0x01e3, 0x01e2, 0x01e1,\n    0x01e0, 0x01e0, 0x01df, 0x01de, 0x01dd, 0x01dc, 0x01db, 0x01da, 0x01da, 0x01d9, 0x01d8, 0x01d7, 0x01d6, 0x01d5, 0x01d4, 0x01d4,\n    0x01d3, 0x01d2, 0x01d1, 0x01d0, 0x01cf, 0x01cf, 0x01ce, 0x01cd, 0x01cc, 0x01cb, 0x01cb, 0x01ca, 0x01c9, 0x01c8, 0x01c7, 0x01c7,\n    0x01c6, 0x01c5, 0x01c4, 0x01c3, 0x01c3, 0x01c2, 0x01c1, 0x01c0, 0x01c0, 0x01bf, 0x01be, 0x01bd, 0x01bd, 0x01bc, 0x01bb, 0x01ba,\n    0x01ba, 0x01b9, 0x01b8, 0x01b7, 0x01b7, 0x01b6, 0x01b5, 0x01b4, 0x01b4, 0x01b3, 0x01b2, 0x01b2, 0x01b1, 0x01b0, 0x01af, 0x01af,\n    0x01ae, 0x01ad, 0x01ad, 0x01ac, 0x01ab, 0x01aa, 0x01aa, 0x01a9, 0x01a8, 0x01a8, 0x01a7, 0x01a6, 0x01a6, 0x01a5, 0x01a4, 0x01a4,\n    0x01a3, 0x01a2, 0x01a2, 0x01a1, 0x01a0, 0x01a0, 0x019f, 0x019e, 0x019e, 0x019d, 0x019c, 0x019c, 0x019b, 0x019a, 0x019a, 0x0199,\n    0x0198, 0x0198, 0x0197, 0x0197, 0x0196, 0x0195, 0x0195, 0x0194, 0x0193, 0x0193, 0x0192, 0x0192, 0x0191, 0x0190, 0x0190, 0x018f,\n    0x018f, 0x018e, 0x018d, 0x018d, 0x018c, 0x018b, 0x018b, 0x018a, 0x018a, 0x0189, 0x0189, 0x0188, 0x0187, 0x0187, 0x0186, 0x0186,\n    0x0185, 0x0184, 0x0184, 0x0183, 0x0183, 0x0182, 0x0182, 0x0181, 0x0180, 0x0180, 0x017f, 0x017f, 0x017e, 0x017e, 0x017d, 0x017d,\n    0x017c, 0x017b, 0x017b, 0x017a, 0x017a, 0x0179, 0x0179, 0x0178, 0x0178, 0x0177, 0x0177, 0x0176, 0x0175, 0x0175, 0x0174, 0x0174,\n    0x0173, 0x0173, 0x0172, 0x0172, 0x0171, 0x0171, 0x0170, 0x0170, 0x016f, 0x016f, 0x016e, 0x016e, 0x016d, 0x016d, 0x016c, 0x016c,\n    0x016b, 0x016b, 0x016a, 0x016a, 0x0169, 0x0169, 0x0168, 0x0168, 0x0167, 0x0167, 0x0166, 0x0166, 0x0165, 0x0165, 0x0164, 0x0164,\n    0x0163, 0x0163, 0x0162, 0x0162, 0x0161, 0x0161, 0x0160, 0x0160, 0x015f, 0x015f, 0x015e, 0x015e, 0x015d, 0x015d, 0x015d, 0x015c,\n    0x015c, 0x015b, 0x015b, 0x015a, 0x015a, 0x0159, 0x0159, 0x0158, 0x0158, 0x0158, 0x0157, 0x0157, 0x0156, 0x0156\n};\n\n#if defined __ARM_NEON && defined __aarch64__\nstatic const uint16_t DivTableNEON[255*3+1] = {\n    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,\n    0x0000, 0x1c71, 0x1af2, 0x1999, 0x1861, 0x1745, 0x1642, 0x1555, 0x147a, 0x13b1, 0x12f6, 0x1249, 0x11a7, 0x1111, 0x1084, 0x1000,\n    0x0f83, 0x0f0f, 0x0ea0, 0x0e38, 0x0dd6, 0x0d79, 0x0d20, 0x0ccc, 0x0c7c, 0x0c30, 0x0be8, 0x0ba2, 0x0b60, 0x0b21, 0x0ae4, 0x0aaa,\n    0x0a72, 0x0a3d, 0x0a0a, 0x09d8, 0x09a9, 0x097b, 0x094f, 0x0924, 0x08fb, 0x08d3, 0x08ad, 0x0888, 0x0864, 0x0842, 0x0820, 0x0800,\n    0x07e0, 0x07c1, 0x07a4, 0x0787, 0x076b, 0x0750, 0x0736, 0x071c, 0x0703, 0x06eb, 0x06d3, 0x06bc, 0x06a6, 0x0690, 0x067b, 0x0666,\n    0x0652, 0x063e, 0x062b, 0x0618, 0x0606, 0x05f4, 0x05e2, 0x05d1, 0x05c0, 0x05b0, 0x05a0, 0x0590, 0x0581, 0x0572, 0x0563, 0x0555,\n    0x0547, 0x0539, 0x052b, 0x051e, 0x0511, 0x0505, 0x04f8, 0x04ec, 0x04e0, 0x04d4, 0x04c8, 0x04bd, 0x04b2, 0x04a7, 0x049c, 0x0492,\n    0x0487, 0x047d, 0x0473, 0x0469, 0x0460, 0x0456, 0x044d, 0x0444, 0x043b, 0x0432, 0x0429, 0x0421, 0x0418, 0x0410, 0x0408, 0x0400,\n    0x03f8, 0x03f0, 0x03e8, 0x03e0, 0x03d9, 0x03d2, 0x03ca, 0x03c3, 0x03bc, 0x03b5, 0x03ae, 0x03a8, 0x03a1, 0x039b, 0x0394, 0x038e,\n    0x0387, 0x0381, 0x037b, 0x0375, 0x036f, 0x0369, 0x0364, 0x035e, 0x0358, 0x0353, 0x034d, 0x0348, 0x0342, 0x033d, 0x0338, 0x0333,\n    0x032e, 0x0329, 0x0324, 0x031f, 0x031a, 0x0315, 0x0310, 0x030c, 0x0307, 0x0303, 0x02fe, 0x02fa, 0x02f5, 0x02f1, 0x02ec, 0x02e8,\n    0x02e4, 0x02e0, 0x02dc, 0x02d8, 0x02d4, 0x02d0, 0x02cc, 0x02c8, 0x02c4, 0x02c0, 0x02bc, 0x02b9, 0x02b5, 0x02b1, 0x02ae, 0x02aa,\n    0x02a7, 0x02a3, 0x02a0, 0x029c, 0x0299, 0x0295, 0x0292, 0x028f, 0x028c, 0x0288, 0x0285, 0x0282, 0x027f, 0x027c, 0x0279, 0x0276,\n    0x0273, 0x0270, 0x026d, 0x026a, 0x0267, 0x0264, 0x0261, 0x025e, 0x025c, 0x0259, 0x0256, 0x0253, 0x0251, 0x024e, 0x024b, 0x0249,\n    0x0246, 0x0243, 0x0241, 0x023e, 0x023c, 0x0239, 0x0237, 0x0234, 0x0232, 0x0230, 0x022d, 0x022b, 0x0229, 0x0226, 0x0224, 0x0222,\n    0x021f, 0x021d, 0x021b, 0x0219, 0x0216, 0x0214, 0x0212, 0x0210, 0x020e, 0x020c, 0x020a, 0x0208, 0x0206, 0x0204, 0x0202, 0x0200,\n    0x01fe, 0x01fc, 0x01fa, 0x01f8, 0x01f6, 0x01f4, 0x01f2, 0x01f0, 0x01ee, 0x01ec, 0x01ea, 0x01e9, 0x01e7, 0x01e5, 0x01e3, 0x01e1,\n    0x01e0, 0x01de, 0x01dc, 0x01da, 0x01d9, 0x01d7, 0x01d5, 0x01d4, 0x01d2, 0x01d0, 0x01cf, 0x01cd, 0x01cb, 0x01ca, 0x01c8, 0x01c7,\n    0x01c5, 0x01c3, 0x01c2, 0x01c0, 0x01bf, 0x01bd, 0x01bc, 0x01ba, 0x01b9, 0x01b7, 0x01b6, 0x01b4, 0x01b3, 0x01b2, 0x01b0, 0x01af,\n    0x01ad, 0x01ac, 0x01aa, 0x01a9, 0x01a8, 0x01a6, 0x01a5, 0x01a4, 0x01a2, 0x01a1, 0x01a0, 0x019e, 0x019d, 0x019c, 0x019a, 0x0199,\n    0x0198, 0x0197, 0x0195, 0x0194, 0x0193, 0x0192, 0x0190, 0x018f, 0x018e, 0x018d, 0x018b, 0x018a, 0x0189, 0x0188, 0x0187, 0x0186,\n    0x0184, 0x0183, 0x0182, 0x0181, 0x0180, 0x017f, 0x017e, 0x017d, 0x017b, 0x017a, 0x0179, 0x0178, 0x0177, 0x0176, 0x0175, 0x0174,\n    0x0173, 0x0172, 0x0171, 0x0170, 0x016f, 0x016e, 0x016d, 0x016c, 0x016b, 0x016a, 0x0169, 0x0168, 0x0167, 0x0166, 0x0165, 0x0164,\n    0x0163, 0x0162, 0x0161, 0x0160, 0x015f, 0x015e, 0x015d, 0x015c, 0x015b, 0x015a, 0x0159, 0x0158, 0x0158, 0x0157, 0x0156, 0x0155,\n    0x0154, 0x0153, 0x0152, 0x0151, 0x0150, 0x0150, 0x014f, 0x014e, 0x014d, 0x014c, 0x014b, 0x014a, 0x014a, 0x0149, 0x0148, 0x0147,\n    0x0146, 0x0146, 0x0145, 0x0144, 0x0143, 0x0142, 0x0142, 0x0141, 0x0140, 0x013f, 0x013e, 0x013e, 0x013d, 0x013c, 0x013b, 0x013b,\n    0x013a, 0x0139, 0x0138, 0x0138, 0x0137, 0x0136, 0x0135, 0x0135, 0x0134, 0x0133, 0x0132, 0x0132, 0x0131, 0x0130, 0x0130, 0x012f,\n    0x012e, 0x012e, 0x012d, 0x012c, 0x012b, 0x012b, 0x012a, 0x0129, 0x0129, 0x0128, 0x0127, 0x0127, 0x0126, 0x0125, 0x0125, 0x0124,\n    0x0123, 0x0123, 0x0122, 0x0121, 0x0121, 0x0120, 0x0120, 0x011f, 0x011e, 0x011e, 0x011d, 0x011c, 0x011c, 0x011b, 0x011b, 0x011a,\n    0x0119, 0x0119, 0x0118, 0x0118, 0x0117, 0x0116, 0x0116, 0x0115, 0x0115, 0x0114, 0x0113, 0x0113, 0x0112, 0x0112, 0x0111, 0x0111,\n    0x0110, 0x010f, 0x010f, 0x010e, 0x010e, 0x010d, 0x010d, 0x010c, 0x010c, 0x010b, 0x010a, 0x010a, 0x0109, 0x0109, 0x0108, 0x0108,\n    0x0107, 0x0107, 0x0106, 0x0106, 0x0105, 0x0105, 0x0104, 0x0104, 0x0103, 0x0103, 0x0102, 0x0102, 0x0101, 0x0101, 0x0100, 0x0100,\n    0x00ff, 0x00ff, 0x00fe, 0x00fe, 0x00fd, 0x00fd, 0x00fc, 0x00fc, 0x00fb, 0x00fb, 0x00fa, 0x00fa, 0x00f9, 0x00f9, 0x00f8, 0x00f8,\n    0x00f7, 0x00f7, 0x00f6, 0x00f6, 0x00f5, 0x00f5, 0x00f4, 0x00f4, 0x00f4, 0x00f3, 0x00f3, 0x00f2, 0x00f2, 0x00f1, 0x00f1, 0x00f0,\n    0x00f0, 0x00f0, 0x00ef, 0x00ef, 0x00ee, 0x00ee, 0x00ed, 0x00ed, 0x00ed, 0x00ec, 0x00ec, 0x00eb, 0x00eb, 0x00ea, 0x00ea, 0x00ea,\n    0x00e9, 0x00e9, 0x00e8, 0x00e8, 0x00e7, 0x00e7, 0x00e7, 0x00e6, 0x00e6, 0x00e5, 0x00e5, 0x00e5, 0x00e4, 0x00e4, 0x00e3, 0x00e3,\n    0x00e3, 0x00e2, 0x00e2, 0x00e1, 0x00e1, 0x00e1, 0x00e0, 0x00e0, 0x00e0, 0x00df, 0x00df, 0x00de, 0x00de, 0x00de, 0x00dd, 0x00dd,\n    0x00dd, 0x00dc, 0x00dc, 0x00db, 0x00db, 0x00db, 0x00da, 0x00da, 0x00da, 0x00d9, 0x00d9, 0x00d9, 0x00d8, 0x00d8, 0x00d7, 0x00d7,\n    0x00d7, 0x00d6, 0x00d6, 0x00d6, 0x00d5, 0x00d5, 0x00d5, 0x00d4, 0x00d4, 0x00d4, 0x00d3, 0x00d3, 0x00d3, 0x00d2, 0x00d2, 0x00d2,\n    0x00d1, 0x00d1, 0x00d1, 0x00d0, 0x00d0, 0x00d0, 0x00cf, 0x00cf, 0x00cf, 0x00ce, 0x00ce, 0x00ce, 0x00cd, 0x00cd, 0x00cd, 0x00cc,\n    0x00cc, 0x00cc, 0x00cb, 0x00cb, 0x00cb, 0x00ca, 0x00ca, 0x00ca, 0x00c9, 0x00c9, 0x00c9, 0x00c9, 0x00c8, 0x00c8, 0x00c8, 0x00c7,\n    0x00c7, 0x00c7, 0x00c6, 0x00c6, 0x00c6, 0x00c5, 0x00c5, 0x00c5, 0x00c5, 0x00c4, 0x00c4, 0x00c4, 0x00c3, 0x00c3, 0x00c3, 0x00c3,\n    0x00c2, 0x00c2, 0x00c2, 0x00c1, 0x00c1, 0x00c1, 0x00c1, 0x00c0, 0x00c0, 0x00c0, 0x00bf, 0x00bf, 0x00bf, 0x00bf, 0x00be, 0x00be,\n    0x00be, 0x00bd, 0x00bd, 0x00bd, 0x00bd, 0x00bc, 0x00bc, 0x00bc, 0x00bc, 0x00bb, 0x00bb, 0x00bb, 0x00ba, 0x00ba, 0x00ba, 0x00ba,\n    0x00b9, 0x00b9, 0x00b9, 0x00b9, 0x00b8, 0x00b8, 0x00b8, 0x00b8, 0x00b7, 0x00b7, 0x00b7, 0x00b7, 0x00b6, 0x00b6, 0x00b6, 0x00b6,\n    0x00b5, 0x00b5, 0x00b5, 0x00b5, 0x00b4, 0x00b4, 0x00b4, 0x00b4, 0x00b3, 0x00b3, 0x00b3, 0x00b3, 0x00b2, 0x00b2, 0x00b2, 0x00b2,\n    0x00b1, 0x00b1, 0x00b1, 0x00b1, 0x00b0, 0x00b0, 0x00b0, 0x00b0, 0x00af, 0x00af, 0x00af, 0x00af, 0x00ae, 0x00ae, 0x00ae, 0x00ae,\n    0x00ae, 0x00ad, 0x00ad, 0x00ad, 0x00ad, 0x00ac, 0x00ac, 0x00ac, 0x00ac, 0x00ac, 0x00ab, 0x00ab, 0x00ab, 0x00ab,\n};\n#endif\n\n\nstatic tracy_force_inline uint64_t ProcessRGB( const uint8_t* src )\n{\n#ifdef __SSE4_1__\n    __m128i px0 = _mm_loadu_si128(((__m128i*)src) + 0);\n    __m128i px1 = _mm_loadu_si128(((__m128i*)src) + 1);\n    __m128i px2 = _mm_loadu_si128(((__m128i*)src) + 2);\n    __m128i px3 = _mm_loadu_si128(((__m128i*)src) + 3);\n\n    __m128i smask = _mm_set1_epi32( 0xF8FCF8 );\n    __m128i sd0 = _mm_and_si128( px0, smask );\n    __m128i sd1 = _mm_and_si128( px1, smask );\n    __m128i sd2 = _mm_and_si128( px2, smask );\n    __m128i sd3 = _mm_and_si128( px3, smask );\n\n    __m128i sc = _mm_shuffle_epi32(sd0, _MM_SHUFFLE(0, 0, 0, 0));\n\n    __m128i sc0 = _mm_cmpeq_epi8(sd0, sc);\n    __m128i sc1 = _mm_cmpeq_epi8(sd1, sc);\n    __m128i sc2 = _mm_cmpeq_epi8(sd2, sc);\n    __m128i sc3 = _mm_cmpeq_epi8(sd3, sc);\n\n    __m128i sm0 = _mm_and_si128(sc0, sc1);\n    __m128i sm1 = _mm_and_si128(sc2, sc3);\n    __m128i sm = _mm_and_si128(sm0, sm1);\n\n    if( _mm_testc_si128(sm, _mm_set1_epi32(-1)) )\n    {\n        return uint64_t( to565( src[0], src[1], src[2] ) ) << 16;\n    }\n\n    __m128i amask = _mm_set1_epi32( 0xFFFFFF );\n    px0 = _mm_and_si128( px0, amask );\n    px1 = _mm_and_si128( px1, amask );\n    px2 = _mm_and_si128( px2, amask );\n    px3 = _mm_and_si128( px3, amask );\n\n    __m128i min0 = _mm_min_epu8( px0, px1 );\n    __m128i min1 = _mm_min_epu8( px2, px3 );\n    __m128i min2 = _mm_min_epu8( min0, min1 );\n\n    __m128i max0 = _mm_max_epu8( px0, px1 );\n    __m128i max1 = _mm_max_epu8( px2, px3 );\n    __m128i max2 = _mm_max_epu8( max0, max1 );\n\n    __m128i min3 = _mm_shuffle_epi32( min2, _MM_SHUFFLE( 2, 3, 0, 1 ) );\n    __m128i max3 = _mm_shuffle_epi32( max2, _MM_SHUFFLE( 2, 3, 0, 1 ) );\n    __m128i min4 = _mm_min_epu8( min2, min3 );\n    __m128i max4 = _mm_max_epu8( max2, max3 );\n\n    __m128i min5 = _mm_shuffle_epi32( min4, _MM_SHUFFLE( 0, 0, 2, 2 ) );\n    __m128i max5 = _mm_shuffle_epi32( max4, _MM_SHUFFLE( 0, 0, 2, 2 ) );\n    __m128i rmin = _mm_min_epu8( min4, min5 );\n    __m128i rmax = _mm_max_epu8( max4, max5 );\n\n    __m128i range1 = _mm_subs_epu8( rmax, rmin );\n    __m128i range2 = _mm_sad_epu8( rmax, rmin );\n\n    uint32_t vrange = _mm_cvtsi128_si32( range2 ) >> 1;\n    __m128i range = _mm_set1_epi16( DivTable[vrange] );\n\n    __m128i inset1 = _mm_srli_epi16( range1, 4 );\n    __m128i inset = _mm_and_si128( inset1, _mm_set1_epi8( 0xF ) );\n    __m128i min = _mm_adds_epu8( rmin, inset );\n    __m128i max = _mm_subs_epu8( rmax, inset );\n\n    __m128i c0 = _mm_subs_epu8( px0, rmin );\n    __m128i c1 = _mm_subs_epu8( px1, rmin );\n    __m128i c2 = _mm_subs_epu8( px2, rmin );\n    __m128i c3 = _mm_subs_epu8( px3, rmin );\n\n    __m128i is0 = _mm_maddubs_epi16( c0, _mm_set1_epi8( 1 ) );\n    __m128i is1 = _mm_maddubs_epi16( c1, _mm_set1_epi8( 1 ) );\n    __m128i is2 = _mm_maddubs_epi16( c2, _mm_set1_epi8( 1 ) );\n    __m128i is3 = _mm_maddubs_epi16( c3, _mm_set1_epi8( 1 ) );\n\n    __m128i s0 = _mm_hadd_epi16( is0, is1 );\n    __m128i s1 = _mm_hadd_epi16( is2, is3 );\n\n    __m128i m0 = _mm_mulhi_epu16( s0, range );\n    __m128i m1 = _mm_mulhi_epu16( s1, range );\n\n    __m128i p0 = _mm_packus_epi16( m0, m1 );\n\n    __m128i p1 = _mm_or_si128( _mm_srai_epi32( p0, 6 ), _mm_srai_epi32( p0, 12 ) );\n    __m128i p2 = _mm_or_si128( _mm_srai_epi32( p0, 18 ), p0 );\n    __m128i p3 = _mm_or_si128( p1, p2 );\n    __m128i p =_mm_shuffle_epi8( p3, _mm_set1_epi32( 0x0C080400 ) );\n\n    uint32_t vmin = _mm_cvtsi128_si32( min );\n    uint32_t vmax = _mm_cvtsi128_si32( max );\n    uint32_t vp = _mm_cvtsi128_si32( p );\n\n    return uint64_t( ( uint64_t( to565( vmin ) ) << 16 ) | to565( vmax ) | ( uint64_t( vp ) << 32 ) );\n#elif defined __ARM_NEON\n#  ifdef __aarch64__\n    uint8x16x4_t px = vld4q_u8( src );\n\n    uint8x16_t lr = px.val[0];\n    uint8x16_t lg = px.val[1];\n    uint8x16_t lb = px.val[2];\n\n    uint8_t rmaxr = vmaxvq_u8( lr );\n    uint8_t rmaxg = vmaxvq_u8( lg );\n    uint8_t rmaxb = vmaxvq_u8( lb );\n\n    uint8_t rminr = vminvq_u8( lr );\n    uint8_t rming = vminvq_u8( lg );\n    uint8_t rminb = vminvq_u8( lb );\n\n    int rr = rmaxr - rminr;\n    int rg = rmaxg - rming;\n    int rb = rmaxb - rminb;\n\n    int vrange1 = rr + rg + rb;\n    uint16_t vrange2 = DivTableNEON[vrange1];\n\n    uint8_t insetr = rr >> 4;\n    uint8_t insetg = rg >> 4;\n    uint8_t insetb = rb >> 4;\n\n    uint8_t minr = rminr + insetr;\n    uint8_t ming = rming + insetg;\n    uint8_t minb = rminb + insetb;\n\n    uint8_t maxr = rmaxr - insetr;\n    uint8_t maxg = rmaxg - insetg;\n    uint8_t maxb = rmaxb - insetb;\n\n    uint8x16_t cr = vsubq_u8( lr, vdupq_n_u8( rminr ) );\n    uint8x16_t cg = vsubq_u8( lg, vdupq_n_u8( rming ) );\n    uint8x16_t cb = vsubq_u8( lb, vdupq_n_u8( rminb ) );\n\n    uint16x8_t is0l = vaddl_u8( vget_low_u8( cr ), vget_low_u8( cg ) );\n    uint16x8_t is0h = vaddl_u8( vget_high_u8( cr ), vget_high_u8( cg ) );\n    uint16x8_t is1l = vaddw_u8( is0l, vget_low_u8( cb ) );\n    uint16x8_t is1h = vaddw_u8( is0h, vget_high_u8( cb ) );\n\n    int16x8_t range = vdupq_n_s16( vrange2 );\n    uint16x8_t m0 = vreinterpretq_u16_s16( vqdmulhq_s16( vreinterpretq_s16_u16( is1l ), range ) );\n    uint16x8_t m1 = vreinterpretq_u16_s16( vqdmulhq_s16( vreinterpretq_s16_u16( is1h ), range ) );\n\n    uint8x8_t p00 = vmovn_u16( m0 );\n    uint8x8_t p01 = vmovn_u16( m1 );\n    uint8x16_t p0 = vcombine_u8( p00, p01 );\n\n    uint32x4_t p1 = vaddq_u32( vshrq_n_u32( vreinterpretq_u32_u8( p0 ), 6 ), vshrq_n_u32( vreinterpretq_u32_u8( p0 ), 12 ) );\n    uint32x4_t p2 = vaddq_u32( vshrq_n_u32( vreinterpretq_u32_u8( p0 ), 18 ), vreinterpretq_u32_u8( p0 ) );\n    uint32x4_t p3 = vaddq_u32( p1, p2 );\n\n    uint16x4x2_t p4 = vuzp_u16( vget_low_u16( vreinterpretq_u16_u32( p3 ) ), vget_high_u16( vreinterpretq_u16_u32( p3 ) ) );\n    uint8x8x2_t p = vuzp_u8( vreinterpret_u8_u16( p4.val[0] ), vreinterpret_u8_u16( p4.val[0] ) );\n\n    uint32_t vp;\n    vst1_lane_u32( &vp, vreinterpret_u32_u8( p.val[0] ), 0 );\n\n    return uint64_t( ( uint64_t( to565( minr, ming, minb ) ) << 16 ) | to565( maxr, maxg, maxb ) | ( uint64_t( vp ) << 32 ) );\n#  else\n    uint32x4_t px0 = vld1q_u32( (uint32_t*)src );\n    uint32x4_t px1 = vld1q_u32( (uint32_t*)src + 4 );\n    uint32x4_t px2 = vld1q_u32( (uint32_t*)src + 8 );\n    uint32x4_t px3 = vld1q_u32( (uint32_t*)src + 12 );\n\n    uint32x4_t smask = vdupq_n_u32( 0xF8FCF8 );\n    uint32x4_t sd0 = vandq_u32( smask, px0 );\n    uint32x4_t sd1 = vandq_u32( smask, px1 );\n    uint32x4_t sd2 = vandq_u32( smask, px2 );\n    uint32x4_t sd3 = vandq_u32( smask, px3 );\n\n    uint32x4_t sc = vdupq_n_u32( sd0[0] );\n\n    uint32x4_t sc0 = vceqq_u32( sd0, sc );\n    uint32x4_t sc1 = vceqq_u32( sd1, sc );\n    uint32x4_t sc2 = vceqq_u32( sd2, sc );\n    uint32x4_t sc3 = vceqq_u32( sd3, sc );\n\n    uint32x4_t sm0 = vandq_u32( sc0, sc1 );\n    uint32x4_t sm1 = vandq_u32( sc2, sc3 );\n    int64x2_t sm = vreinterpretq_s64_u32( vandq_u32( sm0, sm1 ) );\n\n    if( sm[0] == -1 && sm[1] == -1 )\n    {\n        return uint64_t( to565( src[0], src[1], src[2] ) ) << 16;\n    }\n\n    uint32x4_t mask = vdupq_n_u32( 0xFFFFFF );\n    uint8x16_t l0 = vreinterpretq_u8_u32( vandq_u32( mask, px0 ) );\n    uint8x16_t l1 = vreinterpretq_u8_u32( vandq_u32( mask, px1 ) );\n    uint8x16_t l2 = vreinterpretq_u8_u32( vandq_u32( mask, px2 ) );\n    uint8x16_t l3 = vreinterpretq_u8_u32( vandq_u32( mask, px3 ) );\n\n    uint8x16_t min0 = vminq_u8( l0, l1 );\n    uint8x16_t min1 = vminq_u8( l2, l3 );\n    uint8x16_t min2 = vminq_u8( min0, min1 );\n\n    uint8x16_t max0 = vmaxq_u8( l0, l1 );\n    uint8x16_t max1 = vmaxq_u8( l2, l3 );\n    uint8x16_t max2 = vmaxq_u8( max0, max1 );\n\n    uint8x16_t min3 = vreinterpretq_u8_u32( vrev64q_u32( vreinterpretq_u32_u8( min2 ) ) );\n    uint8x16_t max3 = vreinterpretq_u8_u32( vrev64q_u32( vreinterpretq_u32_u8( max2 ) ) );\n\n    uint8x16_t min4 = vminq_u8( min2, min3 );\n    uint8x16_t max4 = vmaxq_u8( max2, max3 );\n\n    uint8x16_t min5 = vcombine_u8( vget_high_u8( min4 ), vget_low_u8( min4 ) );\n    uint8x16_t max5 = vcombine_u8( vget_high_u8( max4 ), vget_low_u8( max4 ) );\n\n    uint8x16_t rmin = vminq_u8( min4, min5 );\n    uint8x16_t rmax = vmaxq_u8( max4, max5 );\n\n    uint8x16_t range1 = vsubq_u8( rmax, rmin );\n    uint8x8_t range2 = vget_low_u8( range1 );\n    uint8x8x2_t range3 = vzip_u8( range2, vdup_n_u8( 0 ) );\n    uint16x4_t range4 = vreinterpret_u16_u8( range3.val[0] );\n\n    uint16_t vrange1;\n    uint16x4_t range5 = vpadd_u16( range4, range4 );\n    uint16x4_t range6 = vpadd_u16( range5, range5 );\n    vst1_lane_u16( &vrange1, range6, 0 );\n\n    uint32_t vrange2 = ( 2 << 16 ) / uint32_t( vrange1 + 1 );\n    uint16x8_t range = vdupq_n_u16( vrange2 );\n\n    uint8x16_t inset = vshrq_n_u8( range1, 4 );\n    uint8x16_t min = vaddq_u8( rmin, inset );\n    uint8x16_t max = vsubq_u8( rmax, inset );\n\n    uint8x16_t c0 = vsubq_u8( l0, rmin );\n    uint8x16_t c1 = vsubq_u8( l1, rmin );\n    uint8x16_t c2 = vsubq_u8( l2, rmin );\n    uint8x16_t c3 = vsubq_u8( l3, rmin );\n\n    uint16x8_t is0 = vpaddlq_u8( c0 );\n    uint16x8_t is1 = vpaddlq_u8( c1 );\n    uint16x8_t is2 = vpaddlq_u8( c2 );\n    uint16x8_t is3 = vpaddlq_u8( c3 );\n\n    uint16x4_t is4 = vpadd_u16( vget_low_u16( is0 ), vget_high_u16( is0 ) );\n    uint16x4_t is5 = vpadd_u16( vget_low_u16( is1 ), vget_high_u16( is1 ) );\n    uint16x4_t is6 = vpadd_u16( vget_low_u16( is2 ), vget_high_u16( is2 ) );\n    uint16x4_t is7 = vpadd_u16( vget_low_u16( is3 ), vget_high_u16( is3 ) );\n\n    uint16x8_t s0 = vcombine_u16( is4, is5 );\n    uint16x8_t s1 = vcombine_u16( is6, is7 );\n\n    uint16x8_t m0 = vreinterpretq_u16_s16( vqdmulhq_s16( vreinterpretq_s16_u16( s0 ), vreinterpretq_s16_u16( range ) ) );\n    uint16x8_t m1 = vreinterpretq_u16_s16( vqdmulhq_s16( vreinterpretq_s16_u16( s1 ), vreinterpretq_s16_u16( range ) ) );\n\n    uint8x8_t p00 = vmovn_u16( m0 );\n    uint8x8_t p01 = vmovn_u16( m1 );\n    uint8x16_t p0 = vcombine_u8( p00, p01 );\n\n    uint32x4_t p1 = vaddq_u32( vshrq_n_u32( vreinterpretq_u32_u8( p0 ), 6 ), vshrq_n_u32( vreinterpretq_u32_u8( p0 ), 12 ) );\n    uint32x4_t p2 = vaddq_u32( vshrq_n_u32( vreinterpretq_u32_u8( p0 ), 18 ), vreinterpretq_u32_u8( p0 ) );\n    uint32x4_t p3 = vaddq_u32( p1, p2 );\n\n    uint16x4x2_t p4 = vuzp_u16( vget_low_u16( vreinterpretq_u16_u32( p3 ) ), vget_high_u16( vreinterpretq_u16_u32( p3 ) ) );\n    uint8x8x2_t p = vuzp_u8( vreinterpret_u8_u16( p4.val[0] ), vreinterpret_u8_u16( p4.val[0] ) );\n\n    uint32_t vmin, vmax, vp;\n    vst1q_lane_u32( &vmin, vreinterpretq_u32_u8( min ), 0 );\n    vst1q_lane_u32( &vmax, vreinterpretq_u32_u8( max ), 0 );\n    vst1_lane_u32( &vp, vreinterpret_u32_u8( p.val[0] ), 0 );\n\n    return uint64_t( ( uint64_t( to565( vmin ) ) << 16 ) | to565( vmax ) | ( uint64_t( vp ) << 32 ) );\n#  endif\n#else\n    uint32_t ref;\n    memcpy( &ref, src, 4 );\n    uint32_t refMask = ref & 0xF8FCF8;\n    auto stmp = src + 4;\n    for( int i=1; i<16; i++ )\n    {\n        uint32_t px;\n        memcpy( &px, stmp, 4 );\n        if( ( px & 0xF8FCF8 ) != refMask ) break;\n        stmp += 4;\n    }\n    if( stmp == src + 64 )\n    {\n        return uint64_t( to565( ref ) ) << 16;\n    }\n\n    uint8_t min[3] = { src[0], src[1], src[2] };\n    uint8_t max[3] = { src[0], src[1], src[2] };\n    auto tmp = src + 4;\n    for( int i=1; i<16; i++ )\n    {\n        for( int j=0; j<3; j++ )\n        {\n            if( tmp[j] < min[j] ) min[j] = tmp[j];\n            else if( tmp[j] > max[j] ) max[j] = tmp[j];\n        }\n        tmp += 4;\n    }\n\n    const uint32_t range = DivTable[max[0] - min[0] + max[1] - min[1] + max[2] - min[2]];\n    const uint32_t rmin = min[0] + min[1] + min[2];\n    for( int i=0; i<3; i++ )\n    {\n        const uint8_t inset = ( max[i] - min[i] ) >> 4;\n        min[i] += inset;\n        max[i] -= inset;\n    }\n\n    uint32_t data = 0;\n    for( int i=0; i<16; i++ )\n    {\n        const uint32_t c = src[0] + src[1] + src[2] - rmin;\n        const uint8_t idx = ( c * range ) >> 16;\n        data |= idx << (i*2);\n        src += 4;\n    }\n\n    return uint64_t( ( uint64_t( to565( min[0], min[1], min[2] ) ) << 16 ) | to565( max[0], max[1], max[2] ) | ( uint64_t( data ) << 32 ) );\n#endif\n}\n\n#ifdef __AVX2__\nstatic tracy_force_inline void ProcessRGB_AVX( const uint8_t* src, char*& dst )\n{\n    __m256i px0 = _mm256_loadu_si256(((__m256i*)src) + 0);\n    __m256i px1 = _mm256_loadu_si256(((__m256i*)src) + 1);\n    __m256i px2 = _mm256_loadu_si256(((__m256i*)src) + 2);\n    __m256i px3 = _mm256_loadu_si256(((__m256i*)src) + 3);\n\n    __m256i smask = _mm256_set1_epi32( 0xF8FCF8 );\n    __m256i sd0 = _mm256_and_si256( px0, smask );\n    __m256i sd1 = _mm256_and_si256( px1, smask );\n    __m256i sd2 = _mm256_and_si256( px2, smask );\n    __m256i sd3 = _mm256_and_si256( px3, smask );\n\n    __m256i sc = _mm256_shuffle_epi32(sd0, _MM_SHUFFLE(0, 0, 0, 0));\n\n    __m256i sc0 = _mm256_cmpeq_epi8( sd0, sc );\n    __m256i sc1 = _mm256_cmpeq_epi8( sd1, sc );\n    __m256i sc2 = _mm256_cmpeq_epi8( sd2, sc );\n    __m256i sc3 = _mm256_cmpeq_epi8( sd3, sc );\n\n    __m256i sm0 = _mm256_and_si256( sc0, sc1 );\n    __m256i sm1 = _mm256_and_si256( sc2, sc3 );\n    __m256i sm = _mm256_and_si256( sm0, sm1 );\n\n    const int64_t solid0 = 1 - _mm_testc_si128( _mm256_castsi256_si128( sm ), _mm_set1_epi32( -1 ) );\n    const int64_t solid1 = 1 - _mm_testc_si128( _mm256_extracti128_si256( sm, 1 ), _mm_set1_epi32( -1 ) );\n\n    if( solid0 + solid1 == 0 )\n    {\n        const auto c0 = uint64_t( to565( src[0], src[1], src[2] ) ) << 16;\n        const auto c1 = uint64_t( to565( src[16], src[17], src[18] ) ) << 16;\n        memcpy( dst, &c0, 8 );\n        memcpy( dst+8, &c1, 8 );\n        dst += 16;\n        return;\n    }\n\n    __m256i amask = _mm256_set1_epi32( 0xFFFFFF );\n    px0 = _mm256_and_si256( px0, amask );\n    px1 = _mm256_and_si256( px1, amask );\n    px2 = _mm256_and_si256( px2, amask );\n    px3 = _mm256_and_si256( px3, amask );\n\n    __m256i min0 = _mm256_min_epu8( px0, px1 );\n    __m256i min1 = _mm256_min_epu8( px2, px3 );\n    __m256i min2 = _mm256_min_epu8( min0, min1 );\n\n    __m256i max0 = _mm256_max_epu8( px0, px1 );\n    __m256i max1 = _mm256_max_epu8( px2, px3 );\n    __m256i max2 = _mm256_max_epu8( max0, max1 );\n\n    __m256i min3 = _mm256_shuffle_epi32( min2, _MM_SHUFFLE( 2, 3, 0, 1 ) );\n    __m256i max3 = _mm256_shuffle_epi32( max2, _MM_SHUFFLE( 2, 3, 0, 1 ) );\n    __m256i min4 = _mm256_min_epu8( min2, min3 );\n    __m256i max4 = _mm256_max_epu8( max2, max3 );\n\n    __m256i min5 = _mm256_shuffle_epi32( min4, _MM_SHUFFLE( 0, 0, 2, 2 ) );\n    __m256i max5 = _mm256_shuffle_epi32( max4, _MM_SHUFFLE( 0, 0, 2, 2 ) );\n    __m256i rmin = _mm256_min_epu8( min4, min5 );\n    __m256i rmax = _mm256_max_epu8( max4, max5 );\n\n    __m256i range1 = _mm256_subs_epu8( rmax, rmin );\n    __m256i range2 = _mm256_sad_epu8( rmax, rmin );\n\n    uint16_t vrange0 = DivTable[_mm256_cvtsi256_si32( range2 ) >> 1];\n    uint16_t vrange1 = DivTable[_mm256_extract_epi16( range2, 8 ) >> 1];\n    __m256i range00 = _mm256_set1_epi16( vrange0 );\n    __m256i range = _mm256_inserti128_si256( range00, _mm_set1_epi16( vrange1 ), 1 );\n\n    __m256i inset1 = _mm256_srli_epi16( range1, 4 );\n    __m256i inset = _mm256_and_si256( inset1, _mm256_set1_epi8( 0xF ) );\n    __m256i min = _mm256_adds_epu8( rmin, inset );\n    __m256i max = _mm256_subs_epu8( rmax, inset );\n\n    __m256i c0 = _mm256_subs_epu8( px0, rmin );\n    __m256i c1 = _mm256_subs_epu8( px1, rmin );\n    __m256i c2 = _mm256_subs_epu8( px2, rmin );\n    __m256i c3 = _mm256_subs_epu8( px3, rmin );\n\n    __m256i is0 = _mm256_maddubs_epi16( c0, _mm256_set1_epi8( 1 ) );\n    __m256i is1 = _mm256_maddubs_epi16( c1, _mm256_set1_epi8( 1 ) );\n    __m256i is2 = _mm256_maddubs_epi16( c2, _mm256_set1_epi8( 1 ) );\n    __m256i is3 = _mm256_maddubs_epi16( c3, _mm256_set1_epi8( 1 ) );\n\n    __m256i s0 = _mm256_hadd_epi16( is0, is1 );\n    __m256i s1 = _mm256_hadd_epi16( is2, is3 );\n\n    __m256i m0 = _mm256_mulhi_epu16( s0, range );\n    __m256i m1 = _mm256_mulhi_epu16( s1, range );\n\n    __m256i p0 = _mm256_packus_epi16( m0, m1 );\n\n    __m256i p1 = _mm256_or_si256( _mm256_srai_epi32( p0, 6 ), _mm256_srai_epi32( p0, 12 ) );\n    __m256i p2 = _mm256_or_si256( _mm256_srai_epi32( p0, 18 ), p0 );\n    __m256i p3 = _mm256_or_si256( p1, p2 );\n    __m256i p =_mm256_shuffle_epi8( p3, _mm256_set1_epi32( 0x0C080400 ) );\n\n    __m256i mm0 = _mm256_unpacklo_epi8( _mm256_setzero_si256(), min );\n    __m256i mm1 = _mm256_unpacklo_epi8( _mm256_setzero_si256(), max );\n    __m256i mm2 = _mm256_unpacklo_epi64( mm1, mm0 );\n    __m256i mmr = _mm256_slli_epi64( _mm256_srli_epi64( mm2, 11 ), 11 );\n    __m256i mmg = _mm256_slli_epi64( _mm256_srli_epi64( mm2, 26 ), 5 );\n    __m256i mmb = _mm256_srli_epi64( _mm256_slli_epi64( mm2, 16 ), 59 );\n    __m256i mm3 = _mm256_or_si256( mmr, mmg );\n    __m256i mm4 = _mm256_or_si256( mm3, mmb );\n    __m256i mm5 = _mm256_shuffle_epi8( mm4, _mm256_set1_epi32( 0x09080100 ) );\n\n    __m256i d0 = _mm256_unpacklo_epi32( mm5, p );\n    __m256i d1 = _mm256_permute4x64_epi64( d0, _MM_SHUFFLE( 3, 2, 2, 0 ) );\n    __m128i d2 = _mm256_castsi256_si128( d1 );\n\n    __m128i mask = _mm_set_epi64x( 0xFFFF0000 | -solid1, 0xFFFF0000 | -solid0 );\n    __m128i d3 = _mm_and_si128( d2, mask );\n    _mm_storeu_si128( (__m128i*)dst, d3 );\n    dst += 16;\n}\n#endif\n\nvoid CompressImageDxt1( const char* src, char* dst, int w, int h )\n{\n    assert( (w % 4) == 0 && (h % 4) == 0 );\n\n#ifdef __AVX2__\n    if( w%8 == 0 )\n    {\n        uint32_t buf[8*4];\n        int i = 0;\n\n        auto blocks = w * h / 32;\n        do\n        {\n            auto tmp = (char*)buf;\n            memcpy( tmp,        src,          8*4 );\n            memcpy( tmp + 8*4,  src + w * 4,  8*4 );\n            memcpy( tmp + 16*4, src + w * 8,  8*4 );\n            memcpy( tmp + 24*4, src + w * 12, 8*4 );\n            src += 8*4;\n            if( ++i == w/8 )\n            {\n                src += w * 3 * 4;\n                i = 0;\n            }\n\n            ProcessRGB_AVX( (uint8_t*)buf, dst );\n        }\n        while( --blocks );\n    }\n    else\n#endif\n    {\n        uint32_t buf[4*4];\n        int i = 0;\n\n        auto ptr = dst;\n        auto blocks = w * h / 16;\n        do\n        {\n            auto tmp = (char*)buf;\n            memcpy( tmp,        src,          4*4 );\n            memcpy( tmp + 4*4,  src + w * 4,  4*4 );\n            memcpy( tmp + 8*4,  src + w * 8,  4*4 );\n            memcpy( tmp + 12*4, src + w * 12, 4*4 );\n            src += 4*4;\n            if( ++i == w/4 )\n            {\n                src += w * 3 * 4;\n                i = 0;\n            }\n\n            const auto c = ProcessRGB( (uint8_t*)buf );\n            memcpy( ptr, &c, sizeof( uint64_t ) );\n            ptr += sizeof( uint64_t );\n        }\n        while( --blocks );\n    }\n}\n\n}\n"
  },
  {
    "path": "tracy-client-sys/tracy/client/TracyDxt1.hpp",
    "content": "#ifndef __TRACYDXT1_HPP__\n#define __TRACYDXT1_HPP__\n\nnamespace tracy\n{\n\nvoid CompressImageDxt1( const char* src, char* dst, int w, int h );\n\n}\n\n#endif\n"
  },
  {
    "path": "tracy-client-sys/tracy/client/TracyFastVector.hpp",
    "content": "#ifndef __TRACYFASTVECTOR_HPP__\n#define __TRACYFASTVECTOR_HPP__\n\n#include <assert.h>\n#include <stddef.h>\n\n#include \"../common/TracyAlloc.hpp\"\n#include \"../common/TracyForceInline.hpp\"\n\nnamespace tracy\n{\n\ntemplate<typename T>\nclass FastVector\n{\npublic:\n    using iterator = T*;\n    using const_iterator = const T*;\n\n    FastVector( size_t capacity )\n        : m_ptr( (T*)tracy_malloc( sizeof( T ) * capacity ) )\n        , m_write( m_ptr )\n        , m_end( m_ptr + capacity )\n    {\n        assert( capacity != 0 );\n    }\n\n    FastVector( const FastVector& ) = delete;\n    FastVector( FastVector&& ) = delete;\n\n    ~FastVector()\n    {\n        tracy_free( m_ptr );\n    }\n\n    FastVector& operator=( const FastVector& ) = delete;\n    FastVector& operator=( FastVector&& ) = delete;\n\n    bool empty() const { return m_ptr == m_write; }\n    size_t size() const { return m_write - m_ptr; }\n\n    T* data() { return m_ptr; }\n    const T* data() const { return m_ptr; };\n\n    T* begin() { return m_ptr; }\n    const T* begin() const { return m_ptr; }\n    T* end() { return m_write; }\n    const T* end() const { return m_write; }\n\n    T& front() { assert( !empty() ); return m_ptr[0]; }\n    const T& front() const { assert( !empty() ); return m_ptr[0]; }\n\n    T& back() { assert( !empty() ); return m_write[-1]; }\n    const T& back() const { assert( !empty() ); return m_write[-1]; }\n\n    T& operator[]( size_t idx ) { return m_ptr[idx]; }\n    const T& operator[]( size_t idx ) const { return m_ptr[idx]; }\n\n    T* push_next()\n    {\n        if( m_write == m_end ) AllocMore();\n        return m_write++;\n    }\n\n    T* prepare_next()\n    {\n        if( m_write == m_end ) AllocMore();\n        return m_write;\n    }\n\n    void commit_next()\n    {\n        m_write++;\n    }\n\n    void clear()\n    {\n        m_write = m_ptr;\n    }\n\n    void swap( FastVector& vec )\n    {\n        const auto ptr1 = m_ptr;\n        const auto ptr2 = vec.m_ptr;\n        const auto write1 = m_write;\n        const auto write2 = vec.m_write;\n        const auto end1 = m_end;\n        const auto end2 = vec.m_end;\n\n        m_ptr = ptr2;\n        vec.m_ptr = ptr1;\n        m_write = write2;\n        vec.m_write = write1;\n        m_end = end2;\n        vec.m_end = end1;\n    }\n\nprivate:\n    tracy_no_inline void AllocMore()\n    {\n        const auto cap = size_t( m_end - m_ptr ) * 2;\n        const auto size = size_t( m_write - m_ptr );\n        T* ptr = (T*)tracy_malloc( sizeof( T ) * cap );\n        memcpy( ptr, m_ptr, size * sizeof( T ) );\n        tracy_free_fast( m_ptr );\n        m_ptr = ptr;\n        m_write = m_ptr + size;\n        m_end = m_ptr + cap;\n    }\n\n    T* m_ptr;\n    T* m_write;\n    T* m_end;\n};\n\n}\n\n#endif\n"
  },
  {
    "path": "tracy-client-sys/tracy/client/TracyKCore.cpp",
    "content": "#ifdef __linux__\n\n#include <algorithm>\n#include <assert.h>\n#include <fcntl.h>\n#include <limits.h>\n#include <unistd.h>\n\n#include \"TracyDebug.hpp\"\n#include \"TracyKCore.hpp\"\n#include \"../common/TracyAlloc.hpp\"\n\n#if !defined(__GLIBC__) && !defined(__WORDSIZE)\n// include __WORDSIZE headers for musl\n#  include <bits/reg.h>\n#endif\n\nnamespace tracy\n{\n\nusing elf_half = uint16_t;\nusing elf_word = uint32_t;\nusing elf_sword = int32_t;\n\n#if __WORDSIZE == 32\n    using elf_addr = uint32_t;\n    using elf_off = uint32_t;\n    using elf_xword = uint32_t;\n#else\n    using elf_addr = uint64_t;\n    using elf_off = uint64_t;\n    using elf_xword = uint64_t;\n#endif\n\nstruct elf_ehdr\n{\n    unsigned char e_ident[16];\n    elf_half e_type;\n    elf_half e_machine;\n    elf_word e_version;\n    elf_addr e_entry;\n    elf_off e_phoff;\n    elf_off e_shoff;\n    elf_word e_flags;\n    elf_half e_ehsize;\n    elf_half e_phentsize;\n    elf_half e_phnum;\n    elf_half e_shentsize;\n    elf_half e_shnum;\n    elf_half e_shstrndx;\n};\n\nstruct elf_phdr\n{\n    elf_word p_type;\n    elf_word p_flags;\n    elf_off p_offset;\n    elf_addr p_vaddr;\n    elf_addr p_paddr;\n    elf_xword p_filesz;\n    elf_xword p_memsz;\n    uint64_t p_align;   // include 32-bit-only flags field for 32-bit compatibility\n};\n\nKCore::KCore()\n    : m_offsets( 16 )\n{\n    m_fd = open( \"/proc/kcore\", O_RDONLY );\n    if( m_fd == -1 ) return;\n\n    elf_ehdr ehdr;\n    if( read( m_fd, &ehdr, sizeof( ehdr ) ) != sizeof( ehdr ) ) goto err;\n\n    assert( ehdr.e_phentsize == sizeof( elf_phdr ) );\n\n    for( elf_half i=0; i<ehdr.e_phnum; i++ )\n    {\n        elf_phdr phdr;\n        if( lseek( m_fd, ehdr.e_phoff + i * ehdr.e_phentsize, SEEK_SET ) == -1 ) goto err;\n        if( read( m_fd, &phdr, sizeof( phdr ) ) != sizeof( phdr ) ) goto err;\n        if( phdr.p_type != 1 ) continue;\n\n        auto ptr = m_offsets.push_next();\n        ptr->start = phdr.p_vaddr;\n        ptr->size = phdr.p_memsz;\n        ptr->offset = phdr.p_offset;\n    }\n\n    std::sort( m_offsets.begin(), m_offsets.end(), []( const Offset& lhs, const Offset& rhs ) { return lhs.start < rhs.start; } );\n    TracyDebug( \"KCore: %zu segments found\\n\", m_offsets.size() );\n    return;\n\nerr:\n    close( m_fd );\n    m_fd = -1;\n}\n\nKCore::~KCore()\n{\n    if( m_fd != -1 ) close( m_fd );\n}\n\nvoid* KCore::Retrieve( uint64_t addr, uint64_t size ) const\n{\n    if( m_fd == -1 ) return nullptr;\n    auto it = std::lower_bound( m_offsets.begin(), m_offsets.end(), addr, []( const Offset& lhs, uint64_t rhs ) { return lhs.start + lhs.size < rhs; } );\n    if( it == m_offsets.end() ) return nullptr;\n    if( addr + size > it->start + it->size ) return nullptr;\n    if( lseek( m_fd, it->offset + addr - it->start, SEEK_SET ) == -1 ) return nullptr;\n    auto ptr = tracy_malloc( size );\n    if( read( m_fd, ptr, size ) != ssize_t( size ) )\n    {\n        tracy_free( ptr );\n        return nullptr;\n    }\n    return ptr;\n}\n\n}\n\n#endif"
  },
  {
    "path": "tracy-client-sys/tracy/client/TracyKCore.hpp",
    "content": "#ifndef __TRACYKCORE_HPP__\n#define __TRACYKCORE_HPP__\n\n#ifdef __linux__\n\n#include <stdint.h>\n\n#include \"TracyFastVector.hpp\"\n\nnamespace tracy\n{\n\nclass KCore\n{\n    struct Offset\n    {\n        uint64_t start;\n        uint64_t size;\n        uint64_t offset;\n    };\n\npublic:\n    KCore();\n    ~KCore();\n\n    void* Retrieve( uint64_t addr, uint64_t size ) const;\n\nprivate:\n    int m_fd;\n    FastVector<Offset> m_offsets;\n};\n\n}\n\n#endif\n\n#endif\n"
  },
  {
    "path": "tracy-client-sys/tracy/client/TracyLock.hpp",
    "content": "#ifndef __TRACYLOCK_HPP__\n#define __TRACYLOCK_HPP__\n\n#include <atomic>\n#include <limits>\n\n#include \"../common/TracySystem.hpp\"\n#include \"../common/TracyAlign.hpp\"\n#include \"TracyProfiler.hpp\"\n\nnamespace tracy\n{\n\nclass LockableCtx\n{\npublic:\n    tracy_force_inline LockableCtx( const SourceLocationData* srcloc )\n        : m_id( GetLockCounter().fetch_add( 1, std::memory_order_relaxed ) )\n#ifdef TRACY_ON_DEMAND\n        , m_lockCount( 0 )\n        , m_active( false )\n#endif\n    {\n        assert( m_id != (std::numeric_limits<uint32_t>::max)() );\n\n        auto item = Profiler::QueueSerial();\n        MemWrite( &item->hdr.type, QueueType::LockAnnounce );\n        MemWrite( &item->lockAnnounce.id, m_id );\n        MemWrite( &item->lockAnnounce.time, Profiler::GetTime() );\n        MemWrite( &item->lockAnnounce.lckloc, (uint64_t)srcloc );\n        MemWrite( &item->lockAnnounce.type, LockType::Lockable );\n#ifdef TRACY_ON_DEMAND\n        GetProfiler().DeferItem( *item );\n#endif\n        Profiler::QueueSerialFinish();\n    }\n\n    LockableCtx( const LockableCtx& ) = delete;\n    LockableCtx& operator=( const LockableCtx& ) = delete;\n\n    tracy_force_inline ~LockableCtx()\n    {\n        auto item = Profiler::QueueSerial();\n        MemWrite( &item->hdr.type, QueueType::LockTerminate );\n        MemWrite( &item->lockTerminate.id, m_id );\n        MemWrite( &item->lockTerminate.time, Profiler::GetTime() );\n#ifdef TRACY_ON_DEMAND\n        GetProfiler().DeferItem( *item );\n#endif\n        Profiler::QueueSerialFinish();\n    }\n\n    tracy_force_inline bool BeforeLock()\n    {\n#ifdef TRACY_ON_DEMAND\n        bool queue = false;\n        const auto locks = m_lockCount.fetch_add( 1, std::memory_order_relaxed );\n        const auto active = m_active.load( std::memory_order_relaxed );\n        if( locks == 0 || active )\n        {\n            const bool connected = GetProfiler().IsConnected();\n            if( active != connected ) m_active.store( connected, std::memory_order_relaxed );\n            if( connected ) queue = true;\n        }\n        if( !queue ) return false;\n#endif\n\n        auto item = Profiler::QueueSerial();\n        MemWrite( &item->hdr.type, QueueType::LockWait );\n        MemWrite( &item->lockWait.thread, GetThreadHandle() );\n        MemWrite( &item->lockWait.id, m_id );\n        MemWrite( &item->lockWait.time, Profiler::GetTime() );\n        Profiler::QueueSerialFinish();\n        return true;\n    }\n\n    tracy_force_inline void AfterLock()\n    {\n        auto item = Profiler::QueueSerial();\n        MemWrite( &item->hdr.type, QueueType::LockObtain );\n        MemWrite( &item->lockObtain.thread, GetThreadHandle() );\n        MemWrite( &item->lockObtain.id, m_id );\n        MemWrite( &item->lockObtain.time, Profiler::GetTime() );\n        Profiler::QueueSerialFinish();\n    }\n\n    tracy_force_inline void AfterUnlock()\n    {\n#ifdef TRACY_ON_DEMAND\n        m_lockCount.fetch_sub( 1, std::memory_order_relaxed );\n        if( !m_active.load( std::memory_order_relaxed ) ) return;\n        if( !GetProfiler().IsConnected() )\n        {\n            m_active.store( false, std::memory_order_relaxed );\n            return;\n        }\n#endif\n\n        auto item = Profiler::QueueSerial();\n        MemWrite( &item->hdr.type, QueueType::LockRelease );\n        MemWrite( &item->lockRelease.id, m_id );\n        MemWrite( &item->lockRelease.time, Profiler::GetTime() );\n        Profiler::QueueSerialFinish();\n    }\n\n    tracy_force_inline void AfterTryLock( bool acquired )\n    {\n#ifdef TRACY_ON_DEMAND\n        if( !acquired ) return;\n\n        bool queue = false;\n        const auto locks = m_lockCount.fetch_add( 1, std::memory_order_relaxed );\n        const auto active = m_active.load( std::memory_order_relaxed );\n        if( locks == 0 || active )\n        {\n            const bool connected = GetProfiler().IsConnected();\n            if( active != connected ) m_active.store( connected, std::memory_order_relaxed );\n            if( connected ) queue = true;\n        }\n        if( !queue ) return;\n#endif\n\n        if( acquired )\n        {\n            auto item = Profiler::QueueSerial();\n            MemWrite( &item->hdr.type, QueueType::LockObtain );\n            MemWrite( &item->lockObtain.thread, GetThreadHandle() );\n            MemWrite( &item->lockObtain.id, m_id );\n            MemWrite( &item->lockObtain.time, Profiler::GetTime() );\n            Profiler::QueueSerialFinish();\n        }\n    }\n\n    tracy_force_inline void Mark( const SourceLocationData* srcloc )\n    {\n#ifdef TRACY_ON_DEMAND\n        const auto active = m_active.load( std::memory_order_relaxed );\n        if( !active ) return;\n        const auto connected = GetProfiler().IsConnected();\n        if( !connected )\n        {\n            if( active ) m_active.store( false, std::memory_order_relaxed );\n            return;\n        }\n#endif\n\n        auto item = Profiler::QueueSerial();\n        MemWrite( &item->hdr.type, QueueType::LockMark );\n        MemWrite( &item->lockMark.thread, GetThreadHandle() );\n        MemWrite( &item->lockMark.id, m_id );\n        MemWrite( &item->lockMark.srcloc, (uint64_t)srcloc );\n        Profiler::QueueSerialFinish();\n    }\n\n    tracy_force_inline void CustomName( const char* name, size_t size )\n    {\n        assert( size < (std::numeric_limits<uint16_t>::max)() );\n        auto ptr = (char*)tracy_malloc( size );\n        memcpy( ptr, name, size );\n        auto item = Profiler::QueueSerial();\n        MemWrite( &item->hdr.type, QueueType::LockName );\n        MemWrite( &item->lockNameFat.id, m_id );\n        MemWrite( &item->lockNameFat.name, (uint64_t)ptr );\n        MemWrite( &item->lockNameFat.size, (uint16_t)size );\n#ifdef TRACY_ON_DEMAND\n        GetProfiler().DeferItem( *item );\n#endif\n        Profiler::QueueSerialFinish();\n    }\n\nprivate:\n    uint32_t m_id;\n\n#ifdef TRACY_ON_DEMAND\n    std::atomic<uint32_t> m_lockCount;\n    std::atomic<bool> m_active;\n#endif\n};\n\ntemplate<class T>\nclass Lockable\n{\npublic:\n    tracy_force_inline Lockable( const SourceLocationData* srcloc )\n        : m_ctx( srcloc )\n    {\n    }\n\n    Lockable( const Lockable& ) = delete;\n    Lockable& operator=( const Lockable& ) = delete;\n\n    tracy_force_inline void lock()\n    {\n        const auto runAfter = m_ctx.BeforeLock();\n        m_lockable.lock();\n        if( runAfter ) m_ctx.AfterLock();\n    }\n\n    tracy_force_inline void unlock()\n    {\n        m_lockable.unlock();\n        m_ctx.AfterUnlock();\n    }\n\n    tracy_force_inline bool try_lock()\n    {\n        const auto acquired = m_lockable.try_lock();\n        m_ctx.AfterTryLock( acquired );\n        return acquired;\n    }\n\n    tracy_force_inline void Mark( const SourceLocationData* srcloc )\n    {\n        m_ctx.Mark( srcloc );\n    }\n\n    tracy_force_inline void CustomName( const char* name, size_t size )\n    {\n        m_ctx.CustomName( name, size );\n    }\n\n    T m_lockable;\n\nprivate:\n    LockableCtx m_ctx;\n};\n\n\nclass SharedLockableCtx\n{\npublic:\n    tracy_force_inline SharedLockableCtx( const SourceLocationData* srcloc )\n        : m_id( GetLockCounter().fetch_add( 1, std::memory_order_relaxed ) )\n#ifdef TRACY_ON_DEMAND\n        , m_lockCount( 0 )\n        , m_active( false )\n#endif\n    {\n        assert( m_id != (std::numeric_limits<uint32_t>::max)() );\n\n        auto item = Profiler::QueueSerial();\n        MemWrite( &item->hdr.type, QueueType::LockAnnounce );\n        MemWrite( &item->lockAnnounce.id, m_id );\n        MemWrite( &item->lockAnnounce.time, Profiler::GetTime() );\n        MemWrite( &item->lockAnnounce.lckloc, (uint64_t)srcloc );\n        MemWrite( &item->lockAnnounce.type, LockType::SharedLockable );\n#ifdef TRACY_ON_DEMAND\n        GetProfiler().DeferItem( *item );\n#endif\n        Profiler::QueueSerialFinish();\n    }\n\n    SharedLockableCtx( const SharedLockableCtx& ) = delete;\n    SharedLockableCtx& operator=( const SharedLockableCtx& ) = delete;\n\n    tracy_force_inline ~SharedLockableCtx()\n    {\n        auto item = Profiler::QueueSerial();\n        MemWrite( &item->hdr.type, QueueType::LockTerminate );\n        MemWrite( &item->lockTerminate.id, m_id );\n        MemWrite( &item->lockTerminate.time, Profiler::GetTime() );\n#ifdef TRACY_ON_DEMAND\n        GetProfiler().DeferItem( *item );\n#endif\n        Profiler::QueueSerialFinish();\n    }\n\n    tracy_force_inline bool BeforeLock()\n    {\n#ifdef TRACY_ON_DEMAND\n        bool queue = false;\n        const auto locks = m_lockCount.fetch_add( 1, std::memory_order_relaxed );\n        const auto active = m_active.load( std::memory_order_relaxed );\n        if( locks == 0 || active )\n        {\n            const bool connected = GetProfiler().IsConnected();\n            if( active != connected ) m_active.store( connected, std::memory_order_relaxed );\n            if( connected ) queue = true;\n        }\n        if( !queue ) return false;\n#endif\n\n        auto item = Profiler::QueueSerial();\n        MemWrite( &item->hdr.type, QueueType::LockWait );\n        MemWrite( &item->lockWait.thread, GetThreadHandle() );\n        MemWrite( &item->lockWait.id, m_id );\n        MemWrite( &item->lockWait.time, Profiler::GetTime() );\n        Profiler::QueueSerialFinish();\n        return true;\n    }\n\n    tracy_force_inline void AfterLock()\n    {\n        auto item = Profiler::QueueSerial();\n        MemWrite( &item->hdr.type, QueueType::LockObtain );\n        MemWrite( &item->lockObtain.thread, GetThreadHandle() );\n        MemWrite( &item->lockObtain.id, m_id );\n        MemWrite( &item->lockObtain.time, Profiler::GetTime() );\n        Profiler::QueueSerialFinish();\n    }\n\n    tracy_force_inline void AfterUnlock()\n    {\n#ifdef TRACY_ON_DEMAND\n        m_lockCount.fetch_sub( 1, std::memory_order_relaxed );\n        if( !m_active.load( std::memory_order_relaxed ) ) return;\n        if( !GetProfiler().IsConnected() )\n        {\n            m_active.store( false, std::memory_order_relaxed );\n            return;\n        }\n#endif\n\n        auto item = Profiler::QueueSerial();\n        MemWrite( &item->hdr.type, QueueType::LockRelease );\n        MemWrite( &item->lockRelease.id, m_id );\n        MemWrite( &item->lockRelease.time, Profiler::GetTime() );\n        Profiler::QueueSerialFinish();\n    }\n\n    tracy_force_inline void AfterTryLock( bool acquired )\n    {\n#ifdef TRACY_ON_DEMAND\n        if( !acquired ) return;\n\n        bool queue = false;\n        const auto locks = m_lockCount.fetch_add( 1, std::memory_order_relaxed );\n        const auto active = m_active.load( std::memory_order_relaxed );\n        if( locks == 0 || active )\n        {\n            const bool connected = GetProfiler().IsConnected();\n            if( active != connected ) m_active.store( connected, std::memory_order_relaxed );\n            if( connected ) queue = true;\n        }\n        if( !queue ) return;\n#endif\n\n        if( acquired )\n        {\n            auto item = Profiler::QueueSerial();\n            MemWrite( &item->hdr.type, QueueType::LockObtain );\n            MemWrite( &item->lockObtain.thread, GetThreadHandle() );\n            MemWrite( &item->lockObtain.id, m_id );\n            MemWrite( &item->lockObtain.time, Profiler::GetTime() );\n            Profiler::QueueSerialFinish();\n        }\n    }\n\n    tracy_force_inline bool BeforeLockShared()\n    {\n#ifdef TRACY_ON_DEMAND\n        bool queue = false;\n        const auto locks = m_lockCount.fetch_add( 1, std::memory_order_relaxed );\n        const auto active = m_active.load( std::memory_order_relaxed );\n        if( locks == 0 || active )\n        {\n            const bool connected = GetProfiler().IsConnected();\n            if( active != connected ) m_active.store( connected, std::memory_order_relaxed );\n            if( connected ) queue = true;\n        }\n        if( !queue ) return false;\n#endif\n\n        auto item = Profiler::QueueSerial();\n        MemWrite( &item->hdr.type, QueueType::LockSharedWait );\n        MemWrite( &item->lockWait.thread, GetThreadHandle() );\n        MemWrite( &item->lockWait.id, m_id );\n        MemWrite( &item->lockWait.time, Profiler::GetTime() );\n        Profiler::QueueSerialFinish();\n        return true;\n    }\n\n    tracy_force_inline void AfterLockShared()\n    {\n        auto item = Profiler::QueueSerial();\n        MemWrite( &item->hdr.type, QueueType::LockSharedObtain );\n        MemWrite( &item->lockObtain.thread, GetThreadHandle() );\n        MemWrite( &item->lockObtain.id, m_id );\n        MemWrite( &item->lockObtain.time, Profiler::GetTime() );\n        Profiler::QueueSerialFinish();\n    }\n\n    tracy_force_inline void AfterUnlockShared()\n    {\n#ifdef TRACY_ON_DEMAND\n        m_lockCount.fetch_sub( 1, std::memory_order_relaxed );\n        if( !m_active.load( std::memory_order_relaxed ) ) return;\n        if( !GetProfiler().IsConnected() )\n        {\n            m_active.store( false, std::memory_order_relaxed );\n            return;\n        }\n#endif\n\n        auto item = Profiler::QueueSerial();\n        MemWrite( &item->hdr.type, QueueType::LockSharedRelease );\n        MemWrite( &item->lockReleaseShared.thread, GetThreadHandle() );\n        MemWrite( &item->lockReleaseShared.id, m_id );\n        MemWrite( &item->lockReleaseShared.time, Profiler::GetTime() );\n        Profiler::QueueSerialFinish();\n    }\n\n    tracy_force_inline void AfterTryLockShared( bool acquired )\n    {\n#ifdef TRACY_ON_DEMAND\n        if( !acquired ) return;\n\n        bool queue = false;\n        const auto locks = m_lockCount.fetch_add( 1, std::memory_order_relaxed );\n        const auto active = m_active.load( std::memory_order_relaxed );\n        if( locks == 0 || active )\n        {\n            const bool connected = GetProfiler().IsConnected();\n            if( active != connected ) m_active.store( connected, std::memory_order_relaxed );\n            if( connected ) queue = true;\n        }\n        if( !queue ) return;\n#endif\n\n        if( acquired )\n        {\n            auto item = Profiler::QueueSerial();\n            MemWrite( &item->hdr.type, QueueType::LockSharedObtain );\n            MemWrite( &item->lockObtain.thread, GetThreadHandle() );\n            MemWrite( &item->lockObtain.id, m_id );\n            MemWrite( &item->lockObtain.time, Profiler::GetTime() );\n            Profiler::QueueSerialFinish();\n        }\n    }\n\n    tracy_force_inline void Mark( const SourceLocationData* srcloc )\n    {\n#ifdef TRACY_ON_DEMAND\n        const auto active = m_active.load( std::memory_order_relaxed );\n        if( !active ) return;\n        const auto connected = GetProfiler().IsConnected();\n        if( !connected )\n        {\n            if( active ) m_active.store( false, std::memory_order_relaxed );\n            return;\n        }\n#endif\n\n        auto item = Profiler::QueueSerial();\n        MemWrite( &item->hdr.type, QueueType::LockMark );\n        MemWrite( &item->lockMark.thread, GetThreadHandle() );\n        MemWrite( &item->lockMark.id, m_id );\n        MemWrite( &item->lockMark.srcloc, (uint64_t)srcloc );\n        Profiler::QueueSerialFinish();\n    }\n\n    tracy_force_inline void CustomName( const char* name, size_t size )\n    {\n        assert( size < (std::numeric_limits<uint16_t>::max)() );\n        auto ptr = (char*)tracy_malloc( size );\n        memcpy( ptr, name, size );\n        auto item = Profiler::QueueSerial();\n        MemWrite( &item->hdr.type, QueueType::LockName );\n        MemWrite( &item->lockNameFat.id, m_id );\n        MemWrite( &item->lockNameFat.name, (uint64_t)ptr );\n        MemWrite( &item->lockNameFat.size, (uint16_t)size );\n#ifdef TRACY_ON_DEMAND\n        GetProfiler().DeferItem( *item );\n#endif\n        Profiler::QueueSerialFinish();\n    }\n\nprivate:\n    uint32_t m_id;\n\n#ifdef TRACY_ON_DEMAND\n    std::atomic<uint32_t> m_lockCount;\n    std::atomic<bool> m_active;\n#endif\n};\n\ntemplate<class T>\nclass SharedLockable\n{\npublic:\n    tracy_force_inline SharedLockable( const SourceLocationData* srcloc )\n        : m_ctx( srcloc )\n    {\n    }\n\n    SharedLockable( const SharedLockable& ) = delete;\n    SharedLockable& operator=( const SharedLockable& ) = delete;\n\n    tracy_force_inline void lock()\n    {\n        const auto runAfter = m_ctx.BeforeLock();\n        m_lockable.lock();\n        if( runAfter ) m_ctx.AfterLock();\n    }\n\n    tracy_force_inline void unlock()\n    {\n        m_lockable.unlock();\n        m_ctx.AfterUnlock();\n    }\n\n    tracy_force_inline bool try_lock()\n    {\n        const auto acquired = m_lockable.try_lock();\n        m_ctx.AfterTryLock( acquired );\n        return acquired;\n    }\n\n    tracy_force_inline void lock_shared()\n    {\n        const auto runAfter = m_ctx.BeforeLockShared();\n        m_lockable.lock_shared();\n        if( runAfter ) m_ctx.AfterLockShared();\n    }\n\n    tracy_force_inline void unlock_shared()\n    {\n        m_lockable.unlock_shared();\n        m_ctx.AfterUnlockShared();\n    }\n\n    tracy_force_inline bool try_lock_shared()\n    {\n        const auto acquired = m_lockable.try_lock_shared();\n        m_ctx.AfterTryLockShared( acquired );\n        return acquired;\n    }\n\n    tracy_force_inline void Mark( const SourceLocationData* srcloc )\n    {\n        m_ctx.Mark( srcloc );\n    }\n\n    tracy_force_inline void CustomName( const char* name, size_t size )\n    {\n        m_ctx.CustomName( name, size );\n    }\n\n    T m_lockable;\n\nprivate:\n    SharedLockableCtx m_ctx;\n};\n\n\n}\n\n#endif\n"
  },
  {
    "path": "tracy-client-sys/tracy/client/TracyOverride.cpp",
    "content": "#ifdef TRACY_ENABLE\n#  ifdef __linux__\n#    include \"TracyDebug.hpp\"\n#    ifdef TRACY_VERBOSE\n#      include <dlfcn.h>\n#      include <link.h>\n#    endif\n\nextern \"C\" int dlclose( void* hnd )\n{\n#ifdef TRACY_VERBOSE\n    struct link_map* lm;\n    if( dlinfo( hnd, RTLD_DI_LINKMAP, &lm ) == 0 )\n    {\n        TracyDebug( \"Overriding dlclose for %s\\n\", lm->l_name );\n    }\n    else\n    {\n        TracyDebug( \"Overriding dlclose for unknown object (%s)\\n\", dlerror() );\n    }\n#endif\n    return 0;\n}\n\n#  endif\n#endif\n"
  },
  {
    "path": "tracy-client-sys/tracy/client/TracyProfiler.cpp",
    "content": "#ifdef TRACY_ENABLE\n\n#ifdef _WIN32\n#  ifndef NOMINMAX\n#    define NOMINMAX\n#  endif\n#  include <winsock2.h>\n#  include <windows.h>\n#  include <tlhelp32.h>\n#  include <inttypes.h>\n#  include <intrin.h>\n#  include \"../common/TracyWinFamily.hpp\"\n#  ifndef _MSC_VER\n#    include <excpt.h>\n#  endif\n#else\n#  include <sys/time.h>\n#  include <sys/param.h>\n#endif\n\n#ifdef _GNU_SOURCE\n#  include <errno.h>\n#endif\n\n#ifdef __linux__\n#  include <dirent.h>\n#  include <pthread.h>\n#  include <sys/types.h>\n#  include <sys/syscall.h>\n#endif\n\n#if defined __APPLE__ || defined BSD\n#  include <sys/types.h>\n#  include <sys/sysctl.h>\n#endif\n\n#if defined __APPLE__\n#  include \"TargetConditionals.h\"\n#  include <mach-o/dyld.h>\n#endif\n\n#ifdef __ANDROID__\n#  include <sys/mman.h>\n#  include <sys/system_properties.h>\n#  include <stdio.h>\n#  include <stdint.h>\n#  include <algorithm>\n#  include <vector>\n#endif\n\n#ifdef __QNX__\n#  include <stdint.h>\n#  include <stdio.h>\n#  include <string.h>\n#  include <sys/syspage.h>\n#  include <sys/stat.h>\n#endif\n\n#include <algorithm>\n#include <assert.h>\n#include <atomic>\n#include <chrono>\n#include <limits>\n#include <new>\n#include <stdlib.h>\n#include <string.h>\n#include <sys/stat.h>\n#include <thread>\n\n#include \"../common/TracyAlign.hpp\"\n#include \"../common/TracyAlloc.hpp\"\n#include \"../common/TracySocket.hpp\"\n#include \"../common/TracySystem.hpp\"\n#include \"../common/TracyYield.hpp\"\n#include \"../common/tracy_lz4.hpp\"\n#include \"tracy_rpmalloc.hpp\"\n#include \"TracyCallstack.hpp\"\n#include \"TracyDebug.hpp\"\n#include \"TracyDxt1.hpp\"\n#include \"TracyScoped.hpp\"\n#include \"TracyProfiler.hpp\"\n#include \"TracyThread.hpp\"\n#include \"TracyArmCpuTable.hpp\"\n#include \"TracySysTrace.hpp\"\n#include \"../tracy/TracyC.h\"\n\n#if defined TRACY_MANUAL_LIFETIME && !defined(TRACY_DELAYED_INIT)\n#  error \"TRACY_MANUAL_LIFETIME requires enabled TRACY_DELAYED_INIT\"\n#endif\n\n#ifdef TRACY_PORT\n#  ifndef TRACY_DATA_PORT\n#    define TRACY_DATA_PORT TRACY_PORT\n#  endif\n#  ifndef TRACY_BROADCAST_PORT\n#    define TRACY_BROADCAST_PORT TRACY_PORT\n#  endif\n#endif\n\n#ifdef __APPLE__\n#  ifndef TRACY_DELAYED_INIT\n#    define TRACY_DELAYED_INIT\n#  endif\n#else\n#  ifdef __GNUC__\n#    define init_order( val ) __attribute__ ((init_priority(val)))\n#  else\n#    define init_order(x)\n#  endif\n#endif\n\n#if defined _WIN32\n#  include <lmcons.h>\nextern \"C\" typedef LONG (WINAPI *t_RtlGetVersion)( PRTL_OSVERSIONINFOW );\nextern \"C\" typedef BOOL (WINAPI *t_GetLogicalProcessorInformationEx)( LOGICAL_PROCESSOR_RELATIONSHIP, PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX, PDWORD );\nextern \"C\" typedef char* (WINAPI *t_WineGetVersion)();\nextern \"C\" typedef char* (WINAPI *t_WineGetBuildId)();\n#else\n#  include <unistd.h>\n#  include <limits.h>\n#  include <fcntl.h>\n#endif\n#if defined __linux__\n#  include <sys/sysinfo.h>\n#  include <sys/utsname.h>\n#endif\n\n#if !defined _WIN32 && ( defined __i386 || defined _M_IX86 || defined __x86_64__ || defined _M_X64 )\n#  include \"TracyCpuid.hpp\"\n#endif\n\n#if !( ( defined _WIN32 && _WIN32_WINNT >= _WIN32_WINNT_VISTA ) || defined __linux__ )\n#  include <mutex>\n#endif\n\n#ifdef __QNX__\nextern char* __progname;\n#endif\n\nnamespace tracy\n{\n\n#ifdef __ANDROID__\n// Implementation helpers of EnsureReadable(address).\n// This is so far only needed on Android, where it is common for libraries to be mapped\n// with only executable, not readable, permissions. Typical example (line from /proc/self/maps):\n/*\n746b63b000-746b6dc000 --xp 00042000 07:48 35                             /apex/com.android.runtime/lib64/bionic/libc.so\n*/\n// See https://github.com/wolfpld/tracy/issues/125 .\n// To work around this, we parse /proc/self/maps and we use mprotect to set read permissions\n// on any mappings that contain symbols addresses hit by HandleSymbolCodeQuery.\n\nnamespace {\n// Holds some information about a single memory mapping.\nstruct MappingInfo {\n    // Start of address range. Inclusive.\n    uintptr_t start_address;\n    // End of address range. Exclusive, so the mapping is the half-open interval\n    // [start, end) and its length in bytes is `end - start`. As in /proc/self/maps.\n    uintptr_t end_address;\n    // Read/Write/Executable permissions.\n    bool perm_r, perm_w, perm_x;\n};\n}  // anonymous namespace\n\n   // Internal implementation helper for LookUpMapping(address).\n   //\n   // Parses /proc/self/maps returning a vector<MappingInfo>.\n   // /proc/self/maps is assumed to be sorted by ascending address, so the resulting\n   // vector is sorted by ascending address too.\nstatic std::vector<MappingInfo> ParseMappings()\n{\n    std::vector<MappingInfo> result;\n    FILE* file = fopen( \"/proc/self/maps\", \"r\" );\n    if( !file ) return result;\n    char line[1024];\n    while( fgets( line, sizeof( line ), file ) )\n    {\n        uintptr_t start_addr;\n        uintptr_t end_addr;\n#if defined(__LP64__)\n        if( sscanf( line, \"%lx-%lx\", &start_addr, &end_addr ) != 2 ) continue;\n#else\n        if (sscanf( line, \"%dx-%dx\", &start_addr, &end_addr ) != 2 ) continue;\n#endif\n        char* first_space = strchr( line, ' ' );\n        if( !first_space ) continue;\n        char* perm = first_space + 1;\n        char* second_space = strchr( perm, ' ' );\n        if( !second_space || second_space - perm != 4 ) continue;\n        result.emplace_back();\n        auto& mapping = result.back();\n        mapping.start_address = start_addr;\n        mapping.end_address = end_addr;\n        mapping.perm_r = perm[0] == 'r';\n        mapping.perm_w = perm[1] == 'w';\n        mapping.perm_x = perm[2] == 'x';\n    }\n    fclose( file );\n    return result;\n}\n\n// Internal implementation helper for LookUpMapping(address).\n//\n// Takes as input an `address` and a known vector `mappings`, assumed to be\n// sorted by increasing addresses, as /proc/self/maps seems to be.\n// Returns a pointer to the MappingInfo describing the mapping that this\n// address belongs to, or nullptr if the address isn't in `mappings`.\nstatic MappingInfo* LookUpMapping(std::vector<MappingInfo>& mappings, uintptr_t address)\n{\n    // Comparison function for std::lower_bound. Returns true if all addresses in `m1`\n    // are lower than `addr`.\n    auto Compare = []( const MappingInfo& m1, uintptr_t addr ) {\n        // '<=' because the address ranges are half-open intervals, [start, end).\n        return m1.end_address <= addr;\n    };\n    auto iter = std::lower_bound( mappings.begin(), mappings.end(), address, Compare );\n    if( iter == mappings.end() || iter->start_address > address) {\n        return nullptr;\n    }\n    return &*iter;\n}\n\n// Internal implementation helper for EnsureReadable(address).\n//\n// Takes as input an `address` and returns a pointer to a MappingInfo\n// describing the mapping that this address belongs to, or nullptr if\n// the address isn't in any known mapping.\n//\n// This function is stateful and not reentrant (assumes to be called from\n// only one thread). It holds a vector of mappings parsed from /proc/self/maps.\n//\n// Attempts to react to mappings changes by re-parsing /proc/self/maps.\nstatic MappingInfo* LookUpMapping(uintptr_t address)\n{\n    // Static state managed by this function. Not constant, we mutate that state as\n    // we turn some mappings readable. Initially parsed once here, updated as needed below.\n    static std::vector<MappingInfo> s_mappings = ParseMappings();\n    MappingInfo* mapping = LookUpMapping( s_mappings, address );\n    if( mapping ) return mapping;\n\n    // This address isn't in any known mapping. Try parsing again, maybe\n    // mappings changed.\n    s_mappings = ParseMappings();\n    return LookUpMapping( s_mappings, address );\n}\n\n// Internal implementation helper for EnsureReadable(address).\n//\n// Attempts to make the specified `mapping` readable if it isn't already.\n// Returns true if and only if the mapping is readable.\nstatic bool EnsureReadable( MappingInfo& mapping )\n{\n    if( mapping.perm_r )\n    {\n        // The mapping is already readable.\n        return true;\n    }\n    int prot = PROT_READ;\n    if( mapping.perm_w ) prot |= PROT_WRITE;\n    if( mapping.perm_x ) prot |= PROT_EXEC;\n    if( mprotect( reinterpret_cast<void*>( mapping.start_address ),\n        mapping.end_address - mapping.start_address, prot ) == -1 )\n    {\n        // Failed to make the mapping readable. Shouldn't happen, hasn't\n        // been observed yet. If it happened in practice, we should consider\n        // adding a bool to MappingInfo to track this to avoid retrying mprotect\n        // everytime on such mappings.\n        return false;\n    }\n    // The mapping is now readable. Update `mapping` so the next call will be fast.\n    mapping.perm_r = true;\n    return true;\n}\n\n// Attempts to set the read permission on the entire mapping containing the\n// specified address. Returns true if and only if the mapping is now readable.\nstatic bool EnsureReadable( uintptr_t address )\n{\n    MappingInfo* mapping = LookUpMapping(address);\n    return mapping && EnsureReadable( *mapping );\n}\n#elif defined WIN32\nstatic bool EnsureReadable( uintptr_t address )\n{\n    MEMORY_BASIC_INFORMATION memInfo;\n    VirtualQuery( reinterpret_cast<void*>( address ), &memInfo, sizeof( memInfo ) );\n    return memInfo.Protect != PAGE_NOACCESS;\n}\n#else\nstatic bool EnsureReadable( uintptr_t address )\n{\n    return true;\n}\n#endif\n\n#ifndef TRACY_DELAYED_INIT\n\nstruct InitTimeWrapper\n{\n    int64_t val;\n};\n\nstruct ProducerWrapper\n{\n    tracy::moodycamel::ConcurrentQueue<QueueItem>::ExplicitProducer* ptr;\n};\n\nstruct ThreadHandleWrapper\n{\n    uint32_t val;\n};\n#endif\n\n\n#if defined __i386 || defined _M_IX86 || defined __x86_64__ || defined _M_X64\nstatic inline void CpuId( uint32_t* regs, uint32_t leaf )\n{\n    memset(regs, 0, sizeof(uint32_t) * 4);\n#if defined _MSC_VER\n    __cpuidex( (int*)regs, leaf, 0 );\n#else\n    __get_cpuid( leaf, regs, regs+1, regs+2, regs+3 );\n#endif\n}\n\nstatic void InitFailure( const char* msg )\n{\n#if defined TRACY_GDK\n    const char* format = \"Tracy Profiler initialization failure: %s\\n\";\n    const int length = snprintf( nullptr, 0, format, msg );\n    char* buffer = (char*)alloca( length + 1 );\n    snprintf( buffer, length + 1, format, msg );\n    OutputDebugStringA( buffer );\n#elif defined _WIN32\n    bool hasConsole = false;\n    bool reopen = false;\n    const auto attached = AttachConsole( ATTACH_PARENT_PROCESS );\n    if( attached )\n    {\n        hasConsole = true;\n        reopen = true;\n    }\n    else\n    {\n        const auto err = GetLastError();\n        if( err == ERROR_ACCESS_DENIED )\n        {\n            hasConsole = true;\n        }\n    }\n    if( hasConsole )\n    {\n        fprintf( stderr, \"Tracy Profiler initialization failure: %s\\n\", msg );\n        if( reopen )\n        {\n            freopen( \"CONOUT$\", \"w\", stderr );\n            fprintf( stderr, \"Tracy Profiler initialization failure: %s\\n\", msg );\n        }\n    }\n    else\n    {\n#  ifndef TRACY_UWP\n        MessageBoxA( nullptr, msg, \"Tracy Profiler initialization failure\", MB_ICONSTOP );\n#  endif\n    }\n#else\n    fprintf( stderr, \"Tracy Profiler initialization failure: %s\\n\", msg );\n#endif\n    exit( 1 );\n}\n\nstatic bool CheckHardwareSupportsInvariantTSC()\n{\n    const char* noCheck = GetEnvVar( \"TRACY_NO_INVARIANT_CHECK\" );\n    if( noCheck && noCheck[0] == '1' ) return true;\n\n    uint32_t regs[4];\n    CpuId( regs, 1 );\n    if( !( regs[3] & ( 1 << 4 ) ) )\n    {\n#if !defined TRACY_TIMER_QPC && !defined TRACY_TIMER_FALLBACK\n        InitFailure( \"CPU doesn't support RDTSC instruction.\" );\n#else\n        return false;\n#endif\n    }\n    CpuId( regs, 0x80000007 );\n    if( regs[3] & ( 1 << 8 ) ) return true;\n\n    return false;\n}\n\n#if defined TRACY_TIMER_FALLBACK && defined TRACY_HW_TIMER\nbool HardwareSupportsInvariantTSC()\n{\n    static bool cachedResult = CheckHardwareSupportsInvariantTSC();\n    return cachedResult;\n}\n#endif\n\nstatic int64_t SetupHwTimer()\n{\n#if !defined TRACY_TIMER_QPC && !defined TRACY_TIMER_FALLBACK\n    if( !CheckHardwareSupportsInvariantTSC() )\n    {\n#if defined _WIN32\n        InitFailure( \"CPU doesn't support invariant TSC.\\nDefine TRACY_NO_INVARIANT_CHECK=1 to ignore this error, *if you know what you are doing*.\\nAlternatively you may rebuild the application with the TRACY_TIMER_QPC or TRACY_TIMER_FALLBACK define to use lower resolution timer.\" );\n#else\n        InitFailure( \"CPU doesn't support invariant TSC.\\nDefine TRACY_NO_INVARIANT_CHECK=1 to ignore this error, *if you know what you are doing*.\\nAlternatively you may rebuild the application with the TRACY_TIMER_FALLBACK define to use lower resolution timer.\" );\n#endif\n    }\n#endif\n\n    return Profiler::GetTime();\n}\n#else\nstatic int64_t SetupHwTimer()\n{\n    return Profiler::GetTime();\n}\n#endif\n\nstatic const char* GetProcessName()\n{\n    const char* processName = \"unknown\";\n#ifdef _WIN32\n    static char buf[_MAX_PATH];\n    GetModuleFileNameA( nullptr, buf, _MAX_PATH );\n    const char* ptr = buf;\n    while( *ptr != '\\0' ) ptr++;\n    while( ptr > buf && *ptr != '\\\\' && *ptr != '/' ) ptr--;\n    if( ptr > buf ) ptr++;\n    processName = ptr;\n#elif defined __ANDROID__\n#  if __ANDROID_API__ >= 21\n    auto buf = getprogname();\n    if( buf ) processName = buf;\n#  endif\n#elif defined __linux__ && defined _GNU_SOURCE\n    if( program_invocation_short_name ) processName = program_invocation_short_name;\n#elif defined __APPLE__ || defined BSD\n    auto buf = getprogname();\n    if( buf ) processName = buf;\n#elif defined __QNX__\n    processName = __progname;\n#endif\n    return processName;\n}\n\nstatic const char* GetProcessExecutablePath()\n{\n#ifdef _WIN32\n    static char buf[_MAX_PATH];\n    GetModuleFileNameA( nullptr, buf, _MAX_PATH );\n    return buf;\n#elif defined __ANDROID__\n    return nullptr;\n#elif defined __linux__ && defined _GNU_SOURCE\n    return program_invocation_name;\n#elif defined __APPLE__\n    static char buf[1024];\n    uint32_t size = 1024;\n    _NSGetExecutablePath( buf, &size );\n    return buf;\n#elif defined __DragonFly__\n    static char buf[1024];\n    readlink( \"/proc/curproc/file\", buf, 1024 );\n    return buf;\n#elif defined __FreeBSD__\n    static char buf[1024];\n    int mib[4];\n    mib[0] = CTL_KERN;\n    mib[1] = KERN_PROC;\n    mib[2] = KERN_PROC_PATHNAME;\n    mib[3] = -1;\n    size_t cb = 1024;\n    sysctl( mib, 4, buf, &cb, nullptr, 0 );\n    return buf;\n#elif defined __NetBSD__\n    static char buf[1024];\n    readlink( \"/proc/curproc/exe\", buf, 1024 );\n    return buf;\n#elif defined __QNX__\n    static char buf[_PC_PATH_MAX + 1];\n    _cmdname(buf);\n    return buf;\n#else\n    return nullptr;\n#endif\n}\n\n#if defined __linux__ && defined __ARM_ARCH\nstatic uint32_t GetHex( char*& ptr, int skip )\n{\n    uint32_t ret;\n    ptr += skip;\n    char* end;\n    if( ptr[0] == '0' && ptr[1] == 'x' )\n    {\n        ptr += 2;\n        ret = strtol( ptr, &end, 16 );\n    }\n    else\n    {\n        ret = strtol( ptr, &end, 10 );\n    }\n    ptr = end;\n    return ret;\n}\n#endif\n\nstatic const char* GetHostInfo()\n{\n    static char buf[1024];\n    auto ptr = buf;\n#if defined _WIN32\n#  if defined TRACY_WIN32_NO_DESKTOP\n    auto GetVersion = &::GetVersionEx;\n#  else\n    auto GetVersion = (t_RtlGetVersion)GetProcAddress( GetModuleHandleA( \"ntdll.dll\" ), \"RtlGetVersion\" );\n#  endif\n    if( !GetVersion )\n    {\n#  ifdef __MINGW32__\n        ptr += sprintf( ptr, \"OS: Windows (MingW)\\n\" );\n#  else\n        ptr += sprintf( ptr, \"OS: Windows\\n\" );\n#  endif\n    }\n    else\n    {\n        RTL_OSVERSIONINFOW ver = { sizeof( RTL_OSVERSIONINFOW ) };\n        GetVersion( &ver );\n\n#  ifdef __MINGW32__\n        ptr += sprintf( ptr, \"OS: Windows %i.%i.%i (MingW)\\n\", (int)ver.dwMajorVersion, (int)ver.dwMinorVersion, (int)ver.dwBuildNumber );\n#  else\n        auto WineGetVersion = (t_WineGetVersion)GetProcAddress( GetModuleHandleA( \"ntdll.dll\" ), \"wine_get_version\" );\n        auto WineGetBuildId = (t_WineGetBuildId)GetProcAddress( GetModuleHandleA( \"ntdll.dll\" ), \"wine_get_build_id\" );\n        if( WineGetVersion && WineGetBuildId )\n        {\n            ptr += sprintf( ptr, \"OS: Windows %lu.%lu.%lu (Wine %s [%s])\\n\", ver.dwMajorVersion, ver.dwMinorVersion, ver.dwBuildNumber, WineGetVersion(), WineGetBuildId() );\n        }\n        else\n        {\n            ptr += sprintf( ptr, \"OS: Windows %lu.%lu.%lu\\n\", ver.dwMajorVersion, ver.dwMinorVersion, ver.dwBuildNumber );\n        }\n#  endif\n    }\n#elif defined __linux__\n    struct utsname utsName;\n    uname( &utsName );\n#  if defined __ANDROID__\n    ptr += sprintf( ptr, \"OS: Linux %s (Android)\\n\", utsName.release );\n#  else\n    ptr += sprintf( ptr, \"OS: Linux %s\\n\", utsName.release );\n#  endif\n#elif defined __APPLE__\n#  if TARGET_OS_IPHONE == 1\n    ptr += sprintf( ptr, \"OS: Darwin (iOS)\\n\" );\n#  elif TARGET_OS_MAC == 1\n    ptr += sprintf( ptr, \"OS: Darwin (OSX)\\n\" );\n#  else\n    ptr += sprintf( ptr, \"OS: Darwin (unknown)\\n\" );\n#  endif\n#elif defined __DragonFly__\n    ptr += sprintf( ptr, \"OS: BSD (DragonFly)\\n\" );\n#elif defined __FreeBSD__\n    ptr += sprintf( ptr, \"OS: BSD (FreeBSD)\\n\" );\n#elif defined __NetBSD__\n    ptr += sprintf( ptr, \"OS: BSD (NetBSD)\\n\" );\n#elif defined __OpenBSD__\n    ptr += sprintf( ptr, \"OS: BSD (OpenBSD)\\n\" );\n#elif defined __QNX__\n    ptr += sprintf( ptr, \"OS: QNX\\n\" );\n#else\n    ptr += sprintf( ptr, \"OS: unknown\\n\" );\n#endif\n\n#if defined _MSC_VER\n#  if defined __clang__\n    ptr += sprintf( ptr, \"Compiler: MSVC clang-cl %i.%i.%i\\n\", __clang_major__, __clang_minor__, __clang_patchlevel__ );\n#  else\n    ptr += sprintf( ptr, \"Compiler: MSVC %i\\n\", _MSC_VER );\n#  endif\n#elif defined __clang__\n    ptr += sprintf( ptr, \"Compiler: clang %i.%i.%i\\n\", __clang_major__, __clang_minor__, __clang_patchlevel__ );\n#elif defined __GNUC__\n    ptr += sprintf( ptr, \"Compiler: gcc %i.%i.%i\\n\", __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__ );\n#else\n    ptr += sprintf( ptr, \"Compiler: unknown\\n\" );\n#endif\n\n#if defined _WIN32\n    InitWinSock();\n\n    char hostname[512];\n    gethostname( hostname, 512 );\n\n#  if defined TRACY_WIN32_NO_DESKTOP\n    const char* user = \"\";\n#  else\n    DWORD userSz = UNLEN+1;\n    char user[UNLEN+1];\n    GetUserNameA( user, &userSz );\n#  endif\n\n    ptr += sprintf( ptr, \"User: %s@%s\\n\", user, hostname );\n#else\n    char hostname[_POSIX_HOST_NAME_MAX]{};\n    gethostname( hostname, _POSIX_HOST_NAME_MAX );\n#  if defined __ANDROID__\n    const auto login = getlogin();\n    if( login )\n    {\n        ptr += sprintf( ptr, \"User: %s@%s\\n\", login, hostname );\n    }\n    else\n    {\n        ptr += sprintf( ptr, \"User: (?)@%s\\n\", hostname );\n    }\n#  else\n    char user[_POSIX_LOGIN_NAME_MAX]{};\n    getlogin_r( user, _POSIX_LOGIN_NAME_MAX );\n    ptr += sprintf( ptr, \"User: %s@%s\\n\", user, hostname );\n#  endif\n#endif\n\n#if defined __i386 || defined _M_IX86\n    ptr += sprintf( ptr, \"Arch: x86\\n\" );\n#elif defined __x86_64__ || defined _M_X64\n    ptr += sprintf( ptr, \"Arch: x64\\n\" );\n#elif defined __aarch64__\n    ptr += sprintf( ptr, \"Arch: ARM64\\n\" );\n#elif defined __ARM_ARCH\n    ptr += sprintf( ptr, \"Arch: ARM\\n\" );\n#else\n    ptr += sprintf( ptr, \"Arch: unknown\\n\" );\n#endif\n\n#if defined __i386 || defined _M_IX86 || defined __x86_64__ || defined _M_X64\n    uint32_t regs[4];\n    char cpuModel[4*4*3+1] = {};\n    auto modelPtr = cpuModel;\n    for( uint32_t i=0x80000002; i<0x80000005; ++i )\n    {\n        CpuId( regs, i );\n        memcpy( modelPtr, regs, sizeof( regs ) ); modelPtr += sizeof( regs );\n    }\n\n    ptr += sprintf( ptr, \"CPU: %s\\n\", cpuModel );\n#elif defined __linux__ && defined __ARM_ARCH\n    bool cpuFound = false;\n    FILE* fcpuinfo = fopen( \"/proc/cpuinfo\", \"rb\" );\n    if( fcpuinfo )\n    {\n        enum { BufSize = 4*1024 };\n        char buf[BufSize];\n        const auto sz = fread( buf, 1, BufSize, fcpuinfo );\n        fclose( fcpuinfo );\n        const auto end = buf + sz;\n        auto cptr = buf;\n\n        uint32_t impl = 0;\n        uint32_t var = 0;\n        uint32_t part = 0;\n        uint32_t rev = 0;\n\n        while( end - cptr > 20 )\n        {\n            while( end - cptr > 20 && memcmp( cptr, \"CPU \", 4 ) != 0 )\n            {\n                cptr += 4;\n                while( end - cptr > 20 && *cptr != '\\n' ) cptr++;\n                cptr++;\n            }\n            if( end - cptr <= 20 ) break;\n            cptr += 4;\n            if( memcmp( cptr, \"implementer\\t: \", 14 ) == 0 )\n            {\n                if( impl != 0 ) break;\n                impl = GetHex( cptr, 14 );\n            }\n            else if( memcmp( cptr, \"variant\\t: \", 10 ) == 0 ) var = GetHex( cptr, 10 );\n            else if( memcmp( cptr, \"part\\t: \", 7 ) == 0 ) part = GetHex( cptr, 7 );\n            else if( memcmp( cptr, \"revision\\t: \", 11 ) == 0 ) rev = GetHex( cptr, 11 );\n            while( *cptr != '\\n' && *cptr != '\\0' ) cptr++;\n            cptr++;\n        }\n\n        if( impl != 0 || var != 0 || part != 0 || rev != 0 )\n        {\n            cpuFound = true;\n            ptr += sprintf( ptr, \"CPU: %s%s r%ip%i\\n\", DecodeArmImplementer( impl ), DecodeArmPart( impl, part ), var, rev );\n        }\n    }\n    if( !cpuFound )\n    {\n        ptr += sprintf( ptr, \"CPU: unknown\\n\" );\n    }\n#elif defined __APPLE__ && TARGET_OS_IPHONE == 1\n    {\n        size_t sz;\n        sysctlbyname( \"hw.machine\", nullptr, &sz, nullptr, 0 );\n        auto str = (char*)tracy_malloc( sz );\n        sysctlbyname( \"hw.machine\", str, &sz, nullptr, 0 );\n        ptr += sprintf( ptr, \"Device: %s\\n\", DecodeIosDevice( str ) );\n        tracy_free( str );\n    }\n#else\n    ptr += sprintf( ptr, \"CPU: unknown\\n\" );\n#endif\n#ifdef __ANDROID__\n    char deviceModel[PROP_VALUE_MAX+1];\n    char deviceManufacturer[PROP_VALUE_MAX+1];\n    __system_property_get( \"ro.product.model\", deviceModel );\n    __system_property_get( \"ro.product.manufacturer\", deviceManufacturer );\n    ptr += sprintf( ptr, \"Device: %s %s\\n\", deviceManufacturer, deviceModel );\n#endif\n\n    ptr += sprintf( ptr, \"CPU cores: %i\\n\", std::thread::hardware_concurrency() );\n\n#if defined _WIN32\n    MEMORYSTATUSEX statex;\n    statex.dwLength = sizeof( statex );\n    GlobalMemoryStatusEx( &statex );\n#  ifdef _MSC_VER\n    ptr += sprintf( ptr, \"RAM: %I64u MB\\n\", statex.ullTotalPhys / 1024 / 1024 );\n#  else\n    ptr += sprintf( ptr, \"RAM: %llu MB\\n\", statex.ullTotalPhys / 1024 / 1024 );\n#  endif\n#elif defined __linux__\n    struct sysinfo sysInfo;\n    sysinfo( &sysInfo );\n    ptr += sprintf( ptr, \"RAM: %lu MB\\n\", sysInfo.totalram / 1024 / 1024 );\n#elif defined __APPLE__\n    size_t memSize;\n    size_t sz = sizeof( memSize );\n    sysctlbyname( \"hw.memsize\", &memSize, &sz, nullptr, 0 );\n    ptr += sprintf( ptr, \"RAM: %zu MB\\n\", memSize / 1024 / 1024 );\n#elif defined BSD\n    size_t memSize;\n    size_t sz = sizeof( memSize );\n    sysctlbyname( \"hw.physmem\", &memSize, &sz, nullptr, 0 );\n    ptr += sprintf( ptr, \"RAM: %zu MB\\n\", memSize / 1024 / 1024 );\n#elif defined __QNX__\n    struct asinfo_entry *entries = SYSPAGE_ENTRY(asinfo);\n    size_t count = SYSPAGE_ENTRY_SIZE(asinfo) / sizeof(struct asinfo_entry);\n    char *strings = SYSPAGE_ENTRY(strings)->data;\n\n    uint64_t memSize = 0;\n    size_t i;\n    for (i = 0; i < count; i++) {\n        struct asinfo_entry *entry = &entries[i];\n        if (strcmp(strings + entry->name, \"ram\") == 0) {\n            memSize += entry->end - entry->start + 1;\n        }\n    }\n    memSize = memSize / 1024 / 1024;\n    ptr += sprintf( ptr, \"RAM: %llu MB\\n\", memSize);\n#else\n    ptr += sprintf( ptr, \"RAM: unknown\\n\" );\n#endif\n\n    return buf;\n}\n\nstatic uint64_t GetPid()\n{\n#if defined _WIN32\n    return uint64_t( GetCurrentProcessId() );\n#else\n    return uint64_t( getpid() );\n#endif\n}\n\nvoid Profiler::AckServerQuery()\n{\n    QueueItem item;\n    MemWrite( &item.hdr.type, QueueType::AckServerQueryNoop );\n    NeedDataSize( QueueDataSize[(int)QueueType::AckServerQueryNoop] );\n    AppendDataUnsafe( &item, QueueDataSize[(int)QueueType::AckServerQueryNoop] );\n}\n\nvoid Profiler::AckSymbolCodeNotAvailable()\n{\n    QueueItem item;\n    MemWrite( &item.hdr.type, QueueType::AckSymbolCodeNotAvailable );\n    NeedDataSize( QueueDataSize[(int)QueueType::AckSymbolCodeNotAvailable] );\n    AppendDataUnsafe( &item, QueueDataSize[(int)QueueType::AckSymbolCodeNotAvailable] );\n}\n\nstatic BroadcastMessage& GetBroadcastMessage( const char* procname, size_t pnsz, int& len, int port )\n{\n    static BroadcastMessage msg;\n\n    msg.broadcastVersion = BroadcastVersion;\n    msg.protocolVersion = ProtocolVersion;\n    msg.listenPort = port;\n    msg.pid = GetPid();\n\n    memcpy( msg.programName, procname, pnsz );\n    memset( msg.programName + pnsz, 0, WelcomeMessageProgramNameSize - pnsz );\n\n    len = int( offsetof( BroadcastMessage, programName ) + pnsz + 1 );\n    return msg;\n}\n\n#if defined _WIN32 && !defined TRACY_WIN32_NO_DESKTOP && !defined TRACY_NO_CRASH_HANDLER\nstatic DWORD s_profilerThreadId = 0;\nstatic DWORD s_symbolThreadId = 0;\nstatic char s_crashText[1024];\n\nLONG WINAPI CrashFilter( PEXCEPTION_POINTERS pExp )\n{\n    if( !GetProfiler().IsConnected() ) return EXCEPTION_CONTINUE_SEARCH;\n\n    const unsigned ec = pExp->ExceptionRecord->ExceptionCode;\n    auto msgPtr = s_crashText;\n    switch( ec )\n    {\n    case EXCEPTION_ACCESS_VIOLATION:\n        msgPtr += sprintf( msgPtr, \"Exception EXCEPTION_ACCESS_VIOLATION (0x%x). \", ec );\n        switch( pExp->ExceptionRecord->ExceptionInformation[0] )\n        {\n        case 0:\n            msgPtr += sprintf( msgPtr, \"Read violation at address 0x%\" PRIxPTR \".\", pExp->ExceptionRecord->ExceptionInformation[1] );\n            break;\n        case 1:\n            msgPtr += sprintf( msgPtr, \"Write violation at address 0x%\" PRIxPTR \".\", pExp->ExceptionRecord->ExceptionInformation[1] );\n            break;\n        case 8:\n            msgPtr += sprintf( msgPtr, \"DEP violation at address 0x%\" PRIxPTR \".\", pExp->ExceptionRecord->ExceptionInformation[1] );\n            break;\n        default:\n            break;\n        }\n        break;\n    case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:\n        msgPtr += sprintf( msgPtr, \"Exception EXCEPTION_ARRAY_BOUNDS_EXCEEDED (0x%x). \", ec );\n        break;\n    case EXCEPTION_DATATYPE_MISALIGNMENT:\n        msgPtr += sprintf( msgPtr, \"Exception EXCEPTION_DATATYPE_MISALIGNMENT (0x%x). \", ec );\n        break;\n    case EXCEPTION_FLT_DIVIDE_BY_ZERO:\n        msgPtr += sprintf( msgPtr, \"Exception EXCEPTION_FLT_DIVIDE_BY_ZERO (0x%x). \", ec );\n        break;\n    case EXCEPTION_ILLEGAL_INSTRUCTION:\n        msgPtr += sprintf( msgPtr, \"Exception EXCEPTION_ILLEGAL_INSTRUCTION (0x%x). \", ec );\n        break;\n    case EXCEPTION_IN_PAGE_ERROR:\n        msgPtr += sprintf( msgPtr, \"Exception EXCEPTION_IN_PAGE_ERROR (0x%x). \", ec );\n        break;\n    case EXCEPTION_INT_DIVIDE_BY_ZERO:\n        msgPtr += sprintf( msgPtr, \"Exception EXCEPTION_INT_DIVIDE_BY_ZERO (0x%x). \", ec );\n        break;\n    case EXCEPTION_PRIV_INSTRUCTION:\n        msgPtr += sprintf( msgPtr, \"Exception EXCEPTION_PRIV_INSTRUCTION (0x%x). \", ec );\n        break;\n    case EXCEPTION_STACK_OVERFLOW:\n        msgPtr += sprintf( msgPtr, \"Exception EXCEPTION_STACK_OVERFLOW (0x%x). \", ec );\n        break;\n    default:\n        return EXCEPTION_CONTINUE_SEARCH;\n    }\n\n    {\n        GetProfiler().SendCallstack( 60, \"KiUserExceptionDispatcher\" );\n\n        TracyQueuePrepare( QueueType::CrashReport );\n        item->crashReport.time = Profiler::GetTime();\n        item->crashReport.text = (uint64_t)s_crashText;\n        TracyQueueCommit( crashReportThread );\n    }\n\n    HANDLE h = CreateToolhelp32Snapshot( TH32CS_SNAPTHREAD, 0 );\n    if( h == INVALID_HANDLE_VALUE ) return EXCEPTION_CONTINUE_SEARCH;\n\n    THREADENTRY32 te = { sizeof( te ) };\n    if( !Thread32First( h, &te ) )\n    {\n        CloseHandle( h );\n        return EXCEPTION_CONTINUE_SEARCH;\n    }\n\n    const auto pid = GetCurrentProcessId();\n    const auto tid = GetCurrentThreadId();\n\n    do\n    {\n        if( te.th32OwnerProcessID == pid && te.th32ThreadID != tid && te.th32ThreadID != s_profilerThreadId && te.th32ThreadID != s_symbolThreadId )\n        {\n            HANDLE th = OpenThread( THREAD_SUSPEND_RESUME, FALSE, te.th32ThreadID );\n            if( th != INVALID_HANDLE_VALUE )\n            {\n                SuspendThread( th );\n                CloseHandle( th );\n            }\n        }\n    }\n    while( Thread32Next( h, &te ) );\n    CloseHandle( h );\n\n    {\n        TracyLfqPrepare( QueueType::Crash );\n        TracyLfqCommit;\n    }\n\n    std::this_thread::sleep_for( std::chrono::milliseconds( 500 ) );\n    GetProfiler().RequestShutdown();\n    while( !GetProfiler().HasShutdownFinished() ) { std::this_thread::sleep_for( std::chrono::milliseconds( 10 ) ); };\n\n    return EXCEPTION_CONTINUE_SEARCH;\n}\n#endif\n\n#if defined _WIN32 && !defined _MSC_VER\nLONG WINAPI CrashFilterExecute( PEXCEPTION_POINTERS pExp )\n{\n    return EXCEPTION_EXECUTE_HANDLER;\n}\n#endif\n\nstatic Profiler* s_instance = nullptr;\nstatic Thread* s_thread;\n#ifndef TRACY_NO_FRAME_IMAGE\nstatic Thread* s_compressThread;\n#endif\n#ifdef TRACY_HAS_CALLSTACK\nstatic Thread* s_symbolThread;\nstd::atomic<bool> s_symbolThreadGone { false };\n#endif\n#ifdef TRACY_HAS_SYSTEM_TRACING\nstatic std::atomic<Thread*> s_sysTraceThread(nullptr);\n#endif\n\n#if defined __linux__ && !defined TRACY_NO_CRASH_HANDLER\n#  ifndef TRACY_CRASH_SIGNAL\n#    define TRACY_CRASH_SIGNAL SIGPWR\n#  endif\n\nstatic long s_profilerTid = 0;\nstatic long s_symbolTid = 0;\nstatic char s_crashText[1024];\nstatic std::atomic<bool> s_alreadyCrashed( false );\n\nstatic void ThreadFreezer( int /*signal*/ )\n{\n    for(;;) sleep( 1000 );\n}\n\nstatic inline void HexPrint( char*& ptr, uint64_t val )\n{\n    if( val == 0 )\n    {\n        *ptr++ = '0';\n        return;\n    }\n\n    static const char HexTable[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };\n    char buf[16];\n    auto bptr = buf;\n\n    do\n    {\n        *bptr++ = HexTable[val%16];\n        val /= 16;\n    }\n    while( val > 0 );\n\n    do\n    {\n        *ptr++ = *--bptr;\n    }\n    while( bptr != buf );\n}\n\nstatic void CrashHandler( int signal, siginfo_t* info, void* /*ucontext*/ )\n{\n    bool expected = false;\n    if( !s_alreadyCrashed.compare_exchange_strong( expected, true ) ) ThreadFreezer( signal );\n\n    struct sigaction act = {};\n    act.sa_handler = SIG_DFL;\n    sigaction( SIGABRT, &act, nullptr );\n\n    auto msgPtr = s_crashText;\n    switch( signal )\n    {\n    case SIGILL:\n        strcpy( msgPtr, \"Illegal Instruction.\\n\" );\n        while( *msgPtr ) msgPtr++;\n        switch( info->si_code )\n        {\n        case ILL_ILLOPC:\n            strcpy( msgPtr, \"Illegal opcode.\\n\" );\n            break;\n        case ILL_ILLOPN:\n            strcpy( msgPtr, \"Illegal operand.\\n\" );\n            break;\n        case ILL_ILLADR:\n            strcpy( msgPtr, \"Illegal addressing mode.\\n\" );\n            break;\n        case ILL_ILLTRP:\n            strcpy( msgPtr, \"Illegal trap.\\n\" );\n            break;\n        case ILL_PRVOPC:\n            strcpy( msgPtr, \"Privileged opcode.\\n\" );\n            break;\n        case ILL_PRVREG:\n            strcpy( msgPtr, \"Privileged register.\\n\" );\n            break;\n        case ILL_COPROC:\n            strcpy( msgPtr, \"Coprocessor error.\\n\" );\n            break;\n        case ILL_BADSTK:\n            strcpy( msgPtr, \"Internal stack error.\\n\" );\n            break;\n        default:\n            break;\n        }\n        break;\n    case SIGFPE:\n        strcpy( msgPtr, \"Floating-point exception.\\n\" );\n        while( *msgPtr ) msgPtr++;\n        switch( info->si_code )\n        {\n        case FPE_INTDIV:\n            strcpy( msgPtr, \"Integer divide by zero.\\n\" );\n            break;\n        case FPE_INTOVF:\n            strcpy( msgPtr, \"Integer overflow.\\n\" );\n            break;\n        case FPE_FLTDIV:\n            strcpy( msgPtr, \"Floating-point divide by zero.\\n\" );\n            break;\n        case FPE_FLTOVF:\n            strcpy( msgPtr, \"Floating-point overflow.\\n\" );\n            break;\n        case FPE_FLTUND:\n            strcpy( msgPtr, \"Floating-point underflow.\\n\" );\n            break;\n        case FPE_FLTRES:\n            strcpy( msgPtr, \"Floating-point inexact result.\\n\" );\n            break;\n        case FPE_FLTINV:\n            strcpy( msgPtr, \"Floating-point invalid operation.\\n\" );\n            break;\n        case FPE_FLTSUB:\n            strcpy( msgPtr, \"Subscript out of range.\\n\" );\n            break;\n        default:\n            break;\n        }\n        break;\n    case SIGSEGV:\n        strcpy( msgPtr, \"Invalid memory reference.\\n\" );\n        while( *msgPtr ) msgPtr++;\n        switch( info->si_code )\n        {\n        case SEGV_MAPERR:\n            strcpy( msgPtr, \"Address not mapped to object.\\n\" );\n            break;\n        case SEGV_ACCERR:\n            strcpy( msgPtr, \"Invalid permissions for mapped object.\\n\" );\n            break;\n#  ifdef SEGV_BNDERR\n        case SEGV_BNDERR:\n            strcpy( msgPtr, \"Failed address bound checks.\\n\" );\n            break;\n#  endif\n#  ifdef SEGV_PKUERR\n        case SEGV_PKUERR:\n            strcpy( msgPtr, \"Access was denied by memory protection keys.\\n\" );\n            break;\n#  endif\n        default:\n            break;\n        }\n        break;\n    case SIGPIPE:\n        strcpy( msgPtr, \"Broken pipe.\\n\" );\n        while( *msgPtr ) msgPtr++;\n        break;\n    case SIGBUS:\n        strcpy( msgPtr, \"Bus error.\\n\" );\n        while( *msgPtr ) msgPtr++;\n        switch( info->si_code )\n        {\n        case BUS_ADRALN:\n            strcpy( msgPtr, \"Invalid address alignment.\\n\" );\n            break;\n        case BUS_ADRERR:\n            strcpy( msgPtr, \"Nonexistent physical address.\\n\" );\n            break;\n        case BUS_OBJERR:\n            strcpy( msgPtr, \"Object-specific hardware error.\\n\" );\n            break;\n#  ifdef BUS_MCEERR_AR\n        case BUS_MCEERR_AR:\n            strcpy( msgPtr, \"Hardware memory error consumed on a machine check; action required.\\n\" );\n            break;\n#  endif\n#  ifdef BUS_MCEERR_AO\n        case BUS_MCEERR_AO:\n            strcpy( msgPtr, \"Hardware memory error detected in process but not consumed; action optional.\\n\" );\n            break;\n#  endif\n        default:\n            break;\n        }\n        break;\n    case SIGABRT:\n        strcpy( msgPtr, \"Abort signal from abort().\\n\" );\n        break;\n    default:\n        abort();\n    }\n    while( *msgPtr ) msgPtr++;\n\n    if( signal != SIGPIPE )\n    {\n        strcpy( msgPtr, \"Fault address: 0x\" );\n        while( *msgPtr ) msgPtr++;\n        HexPrint( msgPtr, uint64_t( info->si_addr ) );\n        *msgPtr++ = '\\n';\n    }\n\n    {\n        GetProfiler().SendCallstack( 60, \"__kernel_rt_sigreturn\" );\n\n        TracyQueuePrepare( QueueType::CrashReport );\n        item->crashReport.time = Profiler::GetTime();\n        item->crashReport.text = (uint64_t)s_crashText;\n        TracyQueueCommit( crashReportThread );\n    }\n\n    DIR* dp = opendir( \"/proc/self/task\" );\n    if( !dp ) abort();\n\n    const auto selfTid = syscall( SYS_gettid );\n\n    struct dirent* ep;\n    while( ( ep = readdir( dp ) ) != nullptr )\n    {\n        if( ep->d_name[0] == '.' ) continue;\n        int tid = atoi( ep->d_name );\n        if( tid != selfTid && tid != s_profilerTid && tid != s_symbolTid )\n        {\n            syscall( SYS_tkill, tid, TRACY_CRASH_SIGNAL );\n        }\n    }\n    closedir( dp );\n\n#ifdef TRACY_HAS_CALLSTACK\n    if( selfTid == s_symbolTid ) s_symbolThreadGone.store( true, std::memory_order_release );\n#endif\n\n    TracyLfqPrepare( QueueType::Crash );\n    TracyLfqCommit;\n\n    std::this_thread::sleep_for( std::chrono::milliseconds( 500 ) );\n    GetProfiler().RequestShutdown();\n    while( !GetProfiler().HasShutdownFinished() ) { std::this_thread::sleep_for( std::chrono::milliseconds( 10 ) ); };\n\n    abort();\n}\n#endif\n\n#ifdef TRACY_HAS_SYSTEM_TRACING\nstatic void StartSystemTracing( int64_t& samplingPeriod )\n{\n    assert( s_sysTraceThread == nullptr );\n\n    // use TRACY_NO_SYS_TRACE=1 to force disabling sys tracing (even if available in the underlying system)\n    // as it can have significant impact on the size of the traces\n    const char* noSysTrace = GetEnvVar( \"TRACY_NO_SYS_TRACE\" );\n    const bool disableSystrace = ( noSysTrace && noSysTrace[0] == '1' );\n    if( disableSystrace )\n    {\n        TracyDebug( \"TRACY: Sys Trace was disabled by 'TRACY_NO_SYS_TRACE=1'\\n\" );\n    }\n    else if( SysTraceStart( samplingPeriod ) )\n    {\n        Thread* sysTraceThread = (Thread*)tracy_malloc( sizeof( Thread ) );\n        new( sysTraceThread ) Thread( SysTraceWorker, nullptr );\n        Thread* prev = s_sysTraceThread.exchange( sysTraceThread );\n        assert( prev == nullptr );\n        std::this_thread::sleep_for( std::chrono::milliseconds( 1 ) );\n    }\n}\n\nstatic void StopSystemTracing()\n{\n    Thread* sysTraceThread = s_sysTraceThread.exchange( nullptr );\n    if( sysTraceThread )\n    {\n        SysTraceStop();\n        sysTraceThread->~Thread();\n        tracy_free( sysTraceThread );\n    }\n}\n#endif\n\nbool Profiler::BeginSamplingProfiling()\n{\n#if !defined(TRACY_HAS_SYSTEM_TRACING)\n    return false;\n#elif defined(TRACY_SAMPLING_PROFILER_MANUAL_START)\n    StartSystemTracing( m_samplingPeriod );\n#endif\n    return true;\n}\nvoid Profiler::EndSamplingProfiling()\n{\n#if defined(TRACY_HAS_SYSTEM_TRACING) && defined(TRACY_SAMPLING_PROFILER_MANUAL_START)\n    StopSystemTracing();\n#endif\n}\n\nenum { QueuePrealloc = 256 * 1024 };\n\nTRACY_API int64_t GetFrequencyQpc()\n{\n#if defined _WIN32\n    LARGE_INTEGER t;\n    QueryPerformanceFrequency( &t );\n    return t.QuadPart;\n#else\n    return 0;\n#endif\n}\n\n#ifdef TRACY_DELAYED_INIT\nstruct ThreadNameData;\nTRACY_API moodycamel::ConcurrentQueue<QueueItem>& GetQueue();\n\nstruct ProfilerData\n{\n    int64_t initTime = SetupHwTimer();\n    moodycamel::ConcurrentQueue<QueueItem> queue;\n    Profiler profiler;\n    std::atomic<uint32_t> lockCounter { 0 };\n    std::atomic<uint8_t> gpuCtxCounter { 0 };\n    std::atomic<ThreadNameData*> threadNameData { nullptr };\n};\n\nstruct ProducerWrapper\n{\n    ProducerWrapper( ProfilerData& data ) : detail( data.queue ), ptr( data.queue.get_explicit_producer( detail ) ) {}\n    moodycamel::ProducerToken detail;\n    tracy::moodycamel::ConcurrentQueue<QueueItem>::ExplicitProducer* ptr;\n};\n\nstruct ProfilerThreadData\n{\n    ProfilerThreadData( ProfilerData& data ) : token( data ), gpuCtx( { nullptr } ) {}\n    ProducerWrapper token;\n    GpuCtxWrapper gpuCtx;\n#  ifdef TRACY_ON_DEMAND\n    LuaZoneState luaZoneState;\n#  endif\n};\n\nstd::atomic<int> RpInitDone { 0 };\nstd::atomic<int> RpInitLock { 0 };\nthread_local bool RpThreadInitDone = false;\nthread_local bool RpThreadShutdown = false;\n\n#  ifdef TRACY_MANUAL_LIFETIME\nProfilerData* s_profilerData = nullptr;\nstatic ProfilerThreadData& GetProfilerThreadData();\nstatic std::atomic<bool> s_isProfilerStarted { false };\nTRACY_API void StartupProfiler()\n{\n    s_profilerData = (ProfilerData*)tracy_malloc( sizeof( ProfilerData ) );\n    new (s_profilerData) ProfilerData();\n    s_profilerData->profiler.SpawnWorkerThreads();\n    GetProfilerThreadData().token = ProducerWrapper( *s_profilerData );\n    s_isProfilerStarted.store( true, std::memory_order_seq_cst );\n}\nstatic ProfilerData& GetProfilerData()\n{\n    assert( s_profilerData );\n    return *s_profilerData;\n}\nTRACY_API void ShutdownProfiler()\n{\n    s_isProfilerStarted.store( false, std::memory_order_seq_cst );\n    s_profilerData->~ProfilerData();\n    tracy_free( s_profilerData );\n    s_profilerData = nullptr;\n    rpmalloc_finalize();\n    RpThreadInitDone = false;\n    RpInitDone.store( 0, std::memory_order_release );\n}\nTRACY_API bool IsProfilerStarted()\n{\n    return s_isProfilerStarted.load( std::memory_order_seq_cst );\n}\n#  else\nstatic std::atomic<int> profilerDataLock { 0 };\nstatic std::atomic<ProfilerData*> profilerData { nullptr };\n\nstatic ProfilerData& GetProfilerData()\n{\n    auto ptr = profilerData.load( std::memory_order_acquire );\n    if( !ptr )\n    {\n        int expected = 0;\n        while( !profilerDataLock.compare_exchange_weak( expected, 1, std::memory_order_release, std::memory_order_relaxed ) ) { expected = 0; YieldThread(); }\n        ptr = profilerData.load( std::memory_order_acquire );\n        if( !ptr )\n        {\n            ptr = (ProfilerData*)tracy_malloc( sizeof( ProfilerData ) );\n            new (ptr) ProfilerData();\n            profilerData.store( ptr, std::memory_order_release );\n        }\n        profilerDataLock.store( 0, std::memory_order_release );\n    }\n    return *ptr;\n}\n#  endif\n\n// GCC prior to 8.4 had a bug with function-inline thread_local variables. Versions of glibc beginning with\n// 2.18 may attempt to work around this issue, which manifests as a crash while running static destructors\n// if this function is compiled into a shared object. Unfortunately, centos7 ships with glibc 2.17. If running\n// on old GCC, use the old-fashioned way as a workaround\n// See: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85400\n#if !defined(__clang__) && defined(__GNUC__) && ((__GNUC__ < 8) || ((__GNUC__ == 8) && (__GNUC_MINOR__ < 4)))\nstruct ProfilerThreadDataKey\n{\npublic:\n    ProfilerThreadDataKey()\n    {\n        int val = pthread_key_create(&m_key, sDestructor);\n        static_cast<void>(val); // unused\n        assert(val == 0);\n    }\n    ~ProfilerThreadDataKey()\n    {\n        int val = pthread_key_delete(m_key);\n        static_cast<void>(val); // unused\n        assert(val == 0);\n    }\n    ProfilerThreadData& get()\n    {\n        void* p = pthread_getspecific(m_key);\n        if (!p)\n        {\n            p = (ProfilerThreadData*)tracy_malloc( sizeof( ProfilerThreadData ) );\n            new (p) ProfilerThreadData(GetProfilerData());\n            pthread_setspecific(m_key, p);\n        }\n        return *static_cast<ProfilerThreadData*>(p);\n    }\nprivate:\n    pthread_key_t m_key;\n\n    static void sDestructor(void* p)\n    {\n        ((ProfilerThreadData*)p)->~ProfilerThreadData();\n        tracy_free(p);\n    }\n};\n\nstatic ProfilerThreadData& GetProfilerThreadData()\n{\n    static ProfilerThreadDataKey key;\n    return key.get();\n}\n#else\nstatic ProfilerThreadData& GetProfilerThreadData()\n{\n    thread_local ProfilerThreadData data( GetProfilerData() );\n    return data;\n}\n#endif\n\nTRACY_API moodycamel::ConcurrentQueue<QueueItem>::ExplicitProducer* GetToken() { return GetProfilerThreadData().token.ptr; }\nTRACY_API Profiler& GetProfiler() { return GetProfilerData().profiler; }\nTRACY_API moodycamel::ConcurrentQueue<QueueItem>& GetQueue() { return GetProfilerData().queue; }\nTRACY_API int64_t GetInitTime() { return GetProfilerData().initTime; }\nTRACY_API std::atomic<uint32_t>& GetLockCounter() { return GetProfilerData().lockCounter; }\nTRACY_API std::atomic<uint8_t>& GetGpuCtxCounter() { return GetProfilerData().gpuCtxCounter; }\nTRACY_API GpuCtxWrapper& GetGpuCtx() { return GetProfilerThreadData().gpuCtx; }\nTRACY_API uint32_t GetThreadHandle() { return detail::GetThreadHandleImpl(); }\nstd::atomic<ThreadNameData*>& GetThreadNameData() { return GetProfilerData().threadNameData; }\n\n#  ifdef TRACY_ON_DEMAND\nTRACY_API LuaZoneState& GetLuaZoneState() { return GetProfilerThreadData().luaZoneState; }\n#  endif\n\n#  ifndef TRACY_MANUAL_LIFETIME\nnamespace\n{\n    const auto& __profiler_init = GetProfiler();\n}\n#  endif\n\n#else\n\n// MSVC static initialization order solution. gcc/clang uses init_order() to avoid all this.\n\n// 1a. But s_queue is needed for initialization of variables in point 2.\nextern moodycamel::ConcurrentQueue<QueueItem> s_queue;\n\n// 2. If these variables would be in the .CRT$XCB section, they would be initialized only in main thread.\nthread_local moodycamel::ProducerToken init_order(107) s_token_detail( s_queue );\nthread_local ProducerWrapper init_order(108) s_token { s_queue.get_explicit_producer( s_token_detail ) };\nthread_local ThreadHandleWrapper init_order(104) s_threadHandle { detail::GetThreadHandleImpl() };\n\n#  ifdef _MSC_VER\n// 1. Initialize these static variables before all other variables.\n#    pragma warning( disable : 4075 )\n#    pragma init_seg( \".CRT$XCB\" )\n#  endif\n\nstatic InitTimeWrapper init_order(101) s_initTime { SetupHwTimer() };\nstd::atomic<int> init_order(102) RpInitDone( 0 );\nstd::atomic<int> init_order(102) RpInitLock( 0 );\nthread_local bool RpThreadInitDone = false;\nthread_local bool RpThreadShutdown = false;\nmoodycamel::ConcurrentQueue<QueueItem> init_order(103) s_queue( QueuePrealloc );\nstd::atomic<uint32_t> init_order(104) s_lockCounter( 0 );\nstd::atomic<uint8_t> init_order(104) s_gpuCtxCounter( 0 );\n\nthread_local GpuCtxWrapper init_order(104) s_gpuCtx { nullptr };\n\nstruct ThreadNameData;\nstatic std::atomic<ThreadNameData*> init_order(104) s_threadNameDataInstance( nullptr );\nstd::atomic<ThreadNameData*>& s_threadNameData = s_threadNameDataInstance;\n\n#  ifdef TRACY_ON_DEMAND\nthread_local LuaZoneState init_order(104) s_luaZoneState { 0, false };\n#  endif\n\nstatic Profiler init_order(105) s_profiler;\n\nTRACY_API moodycamel::ConcurrentQueue<QueueItem>::ExplicitProducer* GetToken() { return s_token.ptr; }\nTRACY_API Profiler& GetProfiler() { return s_profiler; }\nTRACY_API moodycamel::ConcurrentQueue<QueueItem>& GetQueue() { return s_queue; }\nTRACY_API int64_t GetInitTime() { return s_initTime.val; }\nTRACY_API std::atomic<uint32_t>& GetLockCounter() { return s_lockCounter; }\nTRACY_API std::atomic<uint8_t>& GetGpuCtxCounter() { return s_gpuCtxCounter; }\nTRACY_API GpuCtxWrapper& GetGpuCtx() { return s_gpuCtx; }\nTRACY_API uint32_t GetThreadHandle() { return s_threadHandle.val; }\n\nstd::atomic<ThreadNameData*>& GetThreadNameData() { return s_threadNameData; }\n\n#  ifdef TRACY_ON_DEMAND\nTRACY_API LuaZoneState& GetLuaZoneState() { return s_luaZoneState; }\n#  endif\n#endif\n\nTRACY_API bool ProfilerAvailable() { return s_instance != nullptr; }\nTRACY_API bool ProfilerAllocatorAvailable() { return !RpThreadShutdown; }\n\nTRACY_API bool BeginSamplingProfiling() { return GetProfiler().BeginSamplingProfiling(); }\nTRACY_API void EndSamplingProfiling() { return GetProfiler().EndSamplingProfiling(); }\n\nconstexpr static size_t SafeSendBufferSize = 65536;\n\nProfiler::Profiler()\n    : m_timeBegin( 0 )\n    , m_mainThread( detail::GetThreadHandleImpl() )\n    , m_epoch( std::chrono::duration_cast<std::chrono::seconds>( std::chrono::system_clock::now().time_since_epoch() ).count() )\n    , m_shutdown( false )\n    , m_shutdownManual( false )\n    , m_shutdownFinished( false )\n    , m_sock( nullptr )\n    , m_broadcast( nullptr )\n    , m_noExit( false )\n    , m_userPort( 0 )\n    , m_zoneId( 1 )\n    , m_samplingPeriod( 0 )\n    , m_stream( LZ4_createStream() )\n    , m_buffer( (char*)tracy_malloc( TargetFrameSize*3 ) )\n    , m_bufferOffset( 0 )\n    , m_bufferStart( 0 )\n    , m_lz4Buf( (char*)tracy_malloc( LZ4Size + sizeof( lz4sz_t ) ) )\n    , m_serialQueue( 1024*1024 )\n    , m_serialDequeue( 1024*1024 )\n#ifndef TRACY_NO_FRAME_IMAGE\n    , m_fiQueue( 16 )\n    , m_fiDequeue( 16 )\n#endif\n    , m_symbolQueue( 8*1024 )\n    , m_frameCount( 0 )\n    , m_isConnected( false )\n#ifdef TRACY_ON_DEMAND\n    , m_connectionId( 0 )\n    , m_symbolsBusy( false )\n    , m_deferredQueue( 64*1024 )\n#endif\n    , m_paramCallback( nullptr )\n    , m_sourceCallback( nullptr )\n    , m_queryImage( nullptr )\n    , m_queryData( nullptr )\n    , m_crashHandlerInstalled( false )\n    , m_programName( nullptr )\n{\n    assert( !s_instance );\n    s_instance = this;\n\n#ifndef TRACY_DELAYED_INIT\n#  ifdef _MSC_VER\n    // 3. But these variables need to be initialized in main thread within the .CRT$XCB section. Do it here.\n    s_token_detail = moodycamel::ProducerToken( s_queue );\n    s_token = ProducerWrapper { s_queue.get_explicit_producer( s_token_detail ) };\n    s_threadHandle = ThreadHandleWrapper { m_mainThread };\n#  endif\n#endif\n\n    CalibrateTimer();\n    CalibrateDelay();\n    ReportTopology();\n\n#ifdef __linux__\n    m_kcore = (KCore*)tracy_malloc( sizeof( KCore ) );\n    new(m_kcore) KCore();\n#endif\n\n#ifndef TRACY_NO_EXIT\n    const char* noExitEnv = GetEnvVar( \"TRACY_NO_EXIT\" );\n    if( noExitEnv && noExitEnv[0] == '1' )\n    {\n        m_noExit = true;\n    }\n#endif\n\n    const char* userPort = GetEnvVar( \"TRACY_PORT\" );\n    if( userPort )\n    {\n        m_userPort = atoi( userPort );\n    }\n\n    m_safeSendBuffer = (char*)tracy_malloc( SafeSendBufferSize );\n\n#ifndef _WIN32\n    pipe(m_pipe);\n#  if defined __APPLE__ || defined BSD\n    // FreeBSD/XNU don't have F_SETPIPE_SZ, so use the default\n    m_pipeBufSize = 16384;\n#  else\n    m_pipeBufSize = (int)(ptrdiff_t)SafeSendBufferSize;\n    while( fcntl( m_pipe[0], F_SETPIPE_SZ, m_pipeBufSize ) < 0 && errno == EPERM ) m_pipeBufSize /= 2; // too big; reduce\n    m_pipeBufSize = fcntl( m_pipe[0], F_GETPIPE_SZ );\n#  endif\n    fcntl( m_pipe[1], F_SETFL, O_NONBLOCK );\n#endif\n\n#if !defined(TRACY_DELAYED_INIT) || !defined(TRACY_MANUAL_LIFETIME)\n    SpawnWorkerThreads();\n#endif\n}\n\nvoid Profiler::InstallCrashHandler()\n{\n\n#if defined __linux__ && !defined TRACY_NO_CRASH_HANDLER\n    struct sigaction threadFreezer = {};\n    threadFreezer.sa_handler = ThreadFreezer;\n    sigaction( TRACY_CRASH_SIGNAL, &threadFreezer, &m_prevSignal.pwr );\n\n    struct sigaction crashHandler = {};\n    crashHandler.sa_sigaction = CrashHandler;\n    crashHandler.sa_flags = SA_SIGINFO;\n    sigaction( SIGILL, &crashHandler, &m_prevSignal.ill );\n    sigaction( SIGFPE, &crashHandler, &m_prevSignal.fpe );\n    sigaction( SIGSEGV, &crashHandler, &m_prevSignal.segv );\n    sigaction( SIGPIPE, &crashHandler, &m_prevSignal.pipe );\n    sigaction( SIGBUS, &crashHandler, &m_prevSignal.bus );\n    sigaction( SIGABRT, &crashHandler, &m_prevSignal.abrt );\n#endif\n\n#if defined _WIN32 && !defined TRACY_WIN32_NO_DESKTOP && !defined TRACY_NO_CRASH_HANDLER\n    // We cannot use Vectored Exception handling because it catches application-wide frame-based SEH blocks. We only\n    // want to catch unhandled exceptions.\n    m_prevHandler = reinterpret_cast<void*>( SetUnhandledExceptionFilter( CrashFilter ) );\n#endif\n\n#ifndef TRACY_NO_CRASH_HANDLER\n    m_crashHandlerInstalled = true;\n#endif\n\n}\n\nvoid Profiler::RemoveCrashHandler()\n{\n#if defined _WIN32 && !defined TRACY_WIN32_NO_DESKTOP && !defined TRACY_NO_CRASH_HANDLER\n    if( m_crashHandlerInstalled )\n    {\n        auto prev = SetUnhandledExceptionFilter( (LPTOP_LEVEL_EXCEPTION_FILTER)m_prevHandler );\n        if( prev != CrashFilter ) SetUnhandledExceptionFilter( prev ); // A different exception filter was installed over ours => put it back\n    }\n#endif\n\n#if defined __linux__ && !defined TRACY_NO_CRASH_HANDLER\n    if( m_crashHandlerInstalled )\n    {\n        auto restore = []( int signum, struct sigaction* prev ) {\n            struct sigaction old;\n            sigaction( signum, prev, &old );\n            if( old.sa_sigaction != CrashHandler ) sigaction( signum, &old, nullptr ); // A different signal handler was installed over ours => put it back\n        };\n        restore( TRACY_CRASH_SIGNAL, &m_prevSignal.pwr );\n        restore( SIGILL, &m_prevSignal.ill );\n        restore( SIGFPE, &m_prevSignal.fpe );\n        restore( SIGSEGV, &m_prevSignal.segv );\n        restore( SIGPIPE, &m_prevSignal.pipe );\n        restore( SIGBUS, &m_prevSignal.bus );\n        restore( SIGABRT, &m_prevSignal.abrt );\n    }\n#endif\n    m_crashHandlerInstalled = false;\n}\n\nvoid Profiler::SpawnWorkerThreads()\n{\n#if defined(TRACY_HAS_SYSTEM_TRACING) && !defined(TRACY_SAMPLING_PROFILER_MANUAL_START)\n    StartSystemTracing( m_samplingPeriod );\n#endif\n\n    s_thread = (Thread*)tracy_malloc( sizeof( Thread ) );\n    new(s_thread) Thread( LaunchWorker, this );\n\n#ifndef TRACY_NO_FRAME_IMAGE\n    s_compressThread = (Thread*)tracy_malloc( sizeof( Thread ) );\n    new(s_compressThread) Thread( LaunchCompressWorker, this );\n#endif\n\n#ifdef TRACY_HAS_CALLSTACK\n    s_symbolThread = (Thread*)tracy_malloc( sizeof( Thread ) );\n    new(s_symbolThread) Thread( LaunchSymbolWorker, this );\n#endif\n\n#if defined _WIN32 && !defined TRACY_WIN32_NO_DESKTOP && !defined TRACY_NO_CRASH_HANDLER\n    s_profilerThreadId = GetThreadId( s_thread->Handle() );\n#  ifdef TRACY_HAS_CALLSTACK\n    s_symbolThreadId = GetThreadId( s_symbolThread->Handle() );\n#  endif\n#endif\n\n#ifdef TRACY_HAS_CALLSTACK\n    InitCallstackCritical();\n#endif\n\n    m_timeBegin.store( GetTime(), std::memory_order_relaxed );\n}\n\nProfiler::~Profiler()\n{\n    m_shutdown.store( true, std::memory_order_relaxed );\n\n    RemoveCrashHandler();\n\n#ifdef TRACY_HAS_SYSTEM_TRACING\n    StopSystemTracing();\n#endif\n\n#ifdef TRACY_HAS_CALLSTACK\n    s_symbolThread->~Thread();\n    tracy_free( s_symbolThread );\n#endif\n\n#ifndef TRACY_NO_FRAME_IMAGE\n    s_compressThread->~Thread();\n    tracy_free( s_compressThread );\n#endif\n\n    s_thread->~Thread();\n    tracy_free( s_thread );\n\n#ifdef TRACY_HAS_CALLSTACK\n    EndCallstack();\n#endif\n\n#ifdef __linux__\n    m_kcore->~KCore();\n    tracy_free( m_kcore );\n#endif\n\n#ifndef _WIN32\n    close( m_pipe[0] );\n    close( m_pipe[1] );\n#endif\n    tracy_free( m_safeSendBuffer );\n\n    tracy_free( m_lz4Buf );\n    tracy_free( m_buffer );\n    LZ4_freeStream( (LZ4_stream_t*)m_stream );\n\n    if( m_sock )\n    {\n        m_sock->~Socket();\n        tracy_free( m_sock );\n    }\n\n    if( m_broadcast )\n    {\n        m_broadcast->~UdpBroadcast();\n        tracy_free( m_broadcast );\n    }\n\n    assert( s_instance );\n    s_instance = nullptr;\n}\n\nbool Profiler::ShouldExit()\n{\n    return s_instance->m_shutdown.load( std::memory_order_relaxed );\n}\n\nvoid Profiler::Worker()\n{\n#if defined __linux__ && !defined TRACY_NO_CRASH_HANDLER\n    s_profilerTid = syscall( SYS_gettid );\n#endif\n\n    ThreadExitHandler threadExitHandler;\n\n    SetThreadName( \"Tracy Profiler\" );\n\n#ifdef TRACY_DATA_PORT\n    const bool dataPortSearch = false;\n    auto dataPort = m_userPort != 0 ? m_userPort : TRACY_DATA_PORT;\n#else\n    const bool dataPortSearch = m_userPort == 0;\n    auto dataPort = m_userPort != 0 ? m_userPort : 8086;\n#endif\n#ifdef TRACY_BROADCAST_PORT\n    const auto broadcastPort = TRACY_BROADCAST_PORT;\n#else\n    const auto broadcastPort = 8086;\n#endif\n\n    while( m_timeBegin.load( std::memory_order_relaxed ) == 0 ) std::this_thread::sleep_for( std::chrono::milliseconds( 10 ) );\n\n#ifdef TRACY_USE_RPMALLOC\n    rpmalloc_thread_initialize();\n#endif\n\n    m_exectime = 0;\n    const auto execname = GetProcessExecutablePath();\n    if( execname )\n    {\n        struct stat st;\n        if( stat( execname, &st ) == 0 )\n        {\n            m_exectime = (uint64_t)st.st_mtime;\n        }\n    }\n\n    const auto procname = GetProcessName();\n    const auto pnsz = std::min<size_t>( strlen( procname ), WelcomeMessageProgramNameSize - 1 );\n\n    const auto hostinfo = GetHostInfo();\n    const auto hisz = std::min<size_t>( strlen( hostinfo ), WelcomeMessageHostInfoSize - 1 );\n\n    const uint64_t pid = GetPid();\n\n    uint8_t flags = 0;\n\n#ifdef TRACY_ON_DEMAND\n    flags |= WelcomeFlag::OnDemand;\n#endif\n#if defined TRACY_IGNORE_MEMORY_FAULTS || defined __APPLE__\n    flags |= WelcomeFlag::IgnoreMemFaults;\n#endif\n#ifndef TRACY_NO_CODE_TRANSFER\n    flags |= WelcomeFlag::CodeTransfer;\n#endif\n#ifdef _WIN32\n    flags |= WelcomeFlag::CombineSamples;\n#  ifndef TRACY_NO_CONTEXT_SWITCH\n    flags |= WelcomeFlag::IdentifySamples;\n#  endif\n#endif\n\n#if defined __i386 || defined _M_IX86\n    uint8_t cpuArch = CpuArchX86;\n#elif defined __x86_64__ || defined _M_X64\n    uint8_t cpuArch = CpuArchX64;\n#elif defined __aarch64__\n    uint8_t cpuArch = CpuArchArm64;\n#elif defined __ARM_ARCH\n    uint8_t cpuArch = CpuArchArm32;\n#else\n    uint8_t cpuArch = CpuArchUnknown;\n#endif\n\n#if defined __i386 || defined _M_IX86 || defined __x86_64__ || defined _M_X64\n    uint32_t regs[4];\n    char manufacturer[12];\n    CpuId( regs, 0 );\n    memcpy( manufacturer, regs+1, 4 );\n    memcpy( manufacturer+4, regs+3, 4 );\n    memcpy( manufacturer+8, regs+2, 4 );\n\n    CpuId( regs, 1 );\n    uint32_t cpuId = ( regs[0] & 0xFFF ) | ( ( regs[0] & 0xFFF0000 ) >> 4 );\n#else\n    const char manufacturer[12] = {};\n    uint32_t cpuId = 0;\n#endif\n\n    WelcomeMessage welcome;\n    MemWrite( &welcome.timerMul, m_timerMul );\n    MemWrite( &welcome.initBegin, GetInitTime() );\n    MemWrite( &welcome.initEnd, m_timeBegin.load( std::memory_order_relaxed ) );\n    MemWrite( &welcome.resolution, m_resolution );\n    MemWrite( &welcome.epoch, m_epoch );\n    MemWrite( &welcome.exectime, m_exectime );\n    MemWrite( &welcome.pid, pid );\n    MemWrite( &welcome.samplingPeriod, m_samplingPeriod );\n    MemWrite( &welcome.flags, flags );\n    MemWrite( &welcome.cpuArch, cpuArch );\n    memcpy( welcome.cpuManufacturer, manufacturer, 12 );\n    MemWrite( &welcome.cpuId, cpuId );\n    memcpy( welcome.programName, procname, pnsz );\n    memset( welcome.programName + pnsz, 0, WelcomeMessageProgramNameSize - pnsz );\n    memcpy( welcome.hostInfo, hostinfo, hisz );\n    memset( welcome.hostInfo + hisz, 0, WelcomeMessageHostInfoSize - hisz );\n\n    moodycamel::ConsumerToken token( GetQueue() );\n\n    ListenSocket listen;\n    bool isListening = false;\n    if( !dataPortSearch )\n    {\n        isListening = listen.Listen( dataPort, 4 );\n    }\n    else\n    {\n        for( uint32_t i=0; i<20; i++ )\n        {\n            if( listen.Listen( dataPort+i, 4 ) )\n            {\n                dataPort += i;\n                isListening = true;\n                break;\n            }\n        }\n    }\n    if( !isListening )\n    {\n        for(;;)\n        {\n            if( ShouldExit() )\n            {\n                m_shutdownFinished.store( true, std::memory_order_relaxed );\n                return;\n            }\n\n            ClearQueues( token );\n            std::this_thread::sleep_for( std::chrono::milliseconds( 10 ) );\n        }\n    }\n\n#ifndef TRACY_NO_BROADCAST\n    m_broadcast = (UdpBroadcast*)tracy_malloc( sizeof( UdpBroadcast ) );\n    new(m_broadcast) UdpBroadcast();\n#  ifdef TRACY_ONLY_LOCALHOST\n    const char* addr = \"127.255.255.255\";\n#  elif defined TRACY_CLIENT_ADDRESS\n    const char* addr = TRACY_CLIENT_ADDRESS;\n#  elif defined __QNX__\n     // global broadcast address of 255.255.255.255 is not well-supported by QNX,\n     // use the interface broadcast address instead, e.g. \"const char* addr = 192.168.1.255;\"\n#    error Need to specify TRACY_CLIENT_ADDRESS for a QNX target.\n#  else\n    const char* addr = \"255.255.255.255\";\n#  endif\n    if( !m_broadcast->Open( addr, broadcastPort ) )\n    {\n        m_broadcast->~UdpBroadcast();\n        tracy_free( m_broadcast );\n        m_broadcast = nullptr;\n    }\n#endif\n\n    int broadcastLen = 0;\n    auto& broadcastMsg = GetBroadcastMessage( procname, pnsz, broadcastLen, dataPort );\n    uint64_t lastBroadcast = 0;\n\n    // Connections loop.\n    // Each iteration of the loop handles whole connection. Multiple iterations will only\n    // happen in the on-demand mode or when handshake fails.\n    for(;;)\n    {\n        // Wait for incoming connection\n        for(;;)\n        {\n#ifndef TRACY_NO_EXIT\n            if( !m_noExit && ShouldExit() )\n            {\n                if( m_broadcast )\n                {\n                    broadcastMsg.activeTime = -1;\n                    m_broadcast->Send( broadcastPort, &broadcastMsg, broadcastLen );\n                }\n                m_shutdownFinished.store( true, std::memory_order_relaxed );\n                return;\n            }\n#endif\n            m_sock = listen.Accept();\n            if( m_sock ) break;\n#ifndef TRACY_ON_DEMAND\n            ProcessSysTime();\n#  ifdef TRACY_HAS_SYSPOWER\n            m_sysPower.Tick();\n#  endif\n#endif\n\n            if( m_broadcast )\n            {\n                const auto t = std::chrono::high_resolution_clock::now().time_since_epoch().count();\n                if( t - lastBroadcast > 3000000000 )  // 3s\n                {\n                    m_programNameLock.lock();\n                    if( m_programName )\n                    {\n                        broadcastMsg = GetBroadcastMessage( m_programName, strlen( m_programName ), broadcastLen, dataPort );\n                        m_programName = nullptr;\n                    }\n                    m_programNameLock.unlock();\n\n                    lastBroadcast = t;\n                    const auto ts = std::chrono::duration_cast<std::chrono::seconds>( std::chrono::system_clock::now().time_since_epoch() ).count();\n                    broadcastMsg.activeTime = int32_t( ts - m_epoch );\n                    assert( broadcastMsg.activeTime >= 0 );\n                    m_broadcast->Send( broadcastPort, &broadcastMsg, broadcastLen );\n                }\n            }\n        }\n\n        if( m_broadcast )\n        {\n            lastBroadcast = 0;\n            broadcastMsg.activeTime = -1;\n            m_broadcast->Send( broadcastPort, &broadcastMsg, broadcastLen );\n        }\n\n        // Handshake\n        {\n            char shibboleth[HandshakeShibbolethSize];\n            auto res = m_sock->ReadRaw( shibboleth, HandshakeShibbolethSize, 2000 );\n            if( !res || memcmp( shibboleth, HandshakeShibboleth, HandshakeShibbolethSize ) != 0 )\n            {\n                m_sock->~Socket();\n                tracy_free( m_sock );\n                m_sock = nullptr;\n                continue;\n            }\n\n            uint32_t protocolVersion;\n            res = m_sock->ReadRaw( &protocolVersion, sizeof( protocolVersion ), 2000 );\n            if( !res )\n            {\n                m_sock->~Socket();\n                tracy_free( m_sock );\n                m_sock = nullptr;\n                continue;\n            }\n\n            if( protocolVersion != ProtocolVersion )\n            {\n                HandshakeStatus status = HandshakeProtocolMismatch;\n                m_sock->Send( &status, sizeof( status ) );\n                m_sock->~Socket();\n                tracy_free( m_sock );\n                m_sock = nullptr;\n                continue;\n            }\n        }\n\n#ifdef TRACY_ON_DEMAND\n        while( m_symbolsBusy.load( std::memory_order_acquire ) ) { YieldThread(); }\n        m_symbolsBusy.store( true, std::memory_order_release );\n        const auto currentTime = GetTime();\n        ClearQueues( token );\n        m_connectionId.fetch_add( 1, std::memory_order_release );\n#endif\n        m_isConnected.store( true, std::memory_order_release );\n        InstallCrashHandler();\n\n        HandshakeStatus handshake = HandshakeWelcome;\n        m_sock->Send( &handshake, sizeof( handshake ) );\n\n        LZ4_resetStream( (LZ4_stream_t*)m_stream );\n        m_sock->Send( &welcome, sizeof( welcome ) );\n\n        m_threadCtx = 0;\n        m_refTimeSerial = 0;\n        m_refTimeCtx = 0;\n        m_refTimeGpu = 0;\n\n#ifdef TRACY_ON_DEMAND\n        OnDemandPayloadMessage onDemand;\n        onDemand.frames = m_frameCount.load( std::memory_order_relaxed );\n        onDemand.currentTime = currentTime;\n\n        m_sock->Send( &onDemand, sizeof( onDemand ) );\n\n        m_deferredLock.lock();\n        for( auto& item : m_deferredQueue )\n        {\n            uint64_t ptr;\n            uint16_t size;\n            const auto idx = MemRead<uint8_t>( &item.hdr.idx );\n            switch( (QueueType)idx )\n            {\n            case QueueType::MessageAppInfo:\n                ptr = MemRead<uint64_t>( &item.messageFat.text );\n                size = MemRead<uint16_t>( &item.messageFat.size );\n                SendSingleString( (const char*)ptr, size );\n                break;\n            case QueueType::LockName:\n                ptr = MemRead<uint64_t>( &item.lockNameFat.name );\n                size = MemRead<uint16_t>( &item.lockNameFat.size );\n                SendSingleString( (const char*)ptr, size );\n                break;\n            case QueueType::GpuContextName:\n                ptr = MemRead<uint64_t>( &item.gpuContextNameFat.ptr );\n                size = MemRead<uint16_t>( &item.gpuContextNameFat.size );\n                SendSingleString( (const char*)ptr, size );\n                break;\n            default:\n                break;\n            }\n            AppendData( &item, QueueDataSize[idx] );\n        }\n        m_deferredLock.unlock();\n#endif\n\n        // Main communications loop\n        int keepAlive = 0;\n        for(;;)\n        {\n            ProcessSysTime();\n#ifdef TRACY_HAS_SYSPOWER\n            m_sysPower.Tick();\n#endif\n            const auto status = Dequeue( token );\n            const auto serialStatus = DequeueSerial();\n            if( status == DequeueStatus::ConnectionLost || serialStatus == DequeueStatus::ConnectionLost )\n            {\n                break;\n            }\n            else if( status == DequeueStatus::QueueEmpty && serialStatus == DequeueStatus::QueueEmpty )\n            {\n                if( m_bufferOffset != m_bufferStart )\n                {\n                    if( !CommitData() ) break;\n                }\n                if( keepAlive == 500 )\n                {\n                    QueueItem ka;\n                    ka.hdr.type = QueueType::KeepAlive;\n                    AppendData( &ka, QueueDataSize[ka.hdr.idx] );\n                    if( !CommitData() ) break;\n\n                    keepAlive = 0;\n                }\n                else if( !m_sock->HasData() )\n                {\n                    keepAlive++;\n                    std::this_thread::sleep_for( std::chrono::milliseconds( 10 ) );\n                }\n            }\n            else\n            {\n                keepAlive = 0;\n            }\n\n            bool connActive = true;\n            while( m_sock->HasData() )\n            {\n                connActive = HandleServerQuery();\n                if( !connActive ) break;\n            }\n            if( !connActive || ShouldExit() ) break;\n        }\n        if( ShouldExit() ) break;\n\n        m_isConnected.store( false, std::memory_order_release );\n        RemoveCrashHandler();\n\n#ifdef TRACY_ON_DEMAND\n        m_bufferOffset = 0;\n        m_bufferStart = 0;\n#endif\n\n        m_sock->~Socket();\n        tracy_free( m_sock );\n        m_sock = nullptr;\n\n#ifndef TRACY_ON_DEMAND\n        // Client is no longer available here. Accept incoming connections, but reject handshake.\n        for(;;)\n        {\n            if( ShouldExit() )\n            {\n                m_shutdownFinished.store( true, std::memory_order_relaxed );\n                return;\n            }\n\n            ClearQueues( token );\n\n            m_sock = listen.Accept();\n            if( m_sock )\n            {\n                char shibboleth[HandshakeShibbolethSize];\n                auto res = m_sock->ReadRaw( shibboleth, HandshakeShibbolethSize, 1000 );\n                if( !res || memcmp( shibboleth, HandshakeShibboleth, HandshakeShibbolethSize ) != 0 )\n                {\n                    m_sock->~Socket();\n                    tracy_free( m_sock );\n                    m_sock = nullptr;\n                    continue;\n                }\n\n                uint32_t protocolVersion;\n                res = m_sock->ReadRaw( &protocolVersion, sizeof( protocolVersion ), 1000 );\n                if( !res )\n                {\n                    m_sock->~Socket();\n                    tracy_free( m_sock );\n                    m_sock = nullptr;\n                    continue;\n                }\n\n                HandshakeStatus status = HandshakeNotAvailable;\n                m_sock->Send( &status, sizeof( status ) );\n                m_sock->~Socket();\n                tracy_free( m_sock );\n            }\n        }\n#endif\n    }\n    // End of connections loop\n\n    // Wait for symbols thread to terminate. Symbol resolution will continue in this thread.\n#ifdef TRACY_HAS_CALLSTACK\n    while( s_symbolThreadGone.load() == false ) { YieldThread(); }\n#endif\n\n#ifdef TRACY_HAS_SYSTEM_TRACING\n    // On a typical shutdown scenario, the (global) Profiler object is destroyed by\n    // the C++ runtime when the client program returns from \"main\", and ~Profiler()\n    // takes care of calling StopSystemTracing(). However, a client may decide to\n    // manually RequestShutdown(), in which case ~Profile() may not execute before\n    // this Worker() thread goes through its teardown stages and reaches this point.\n    // To ensure that system tracing does not keep pushing data to the worker queue \n    // indefinitely (thus preventing this worker from terminating), we have to call\n    // StopSystemTracing() here as well to be safe:\n    StopSystemTracing();\n#endif\n\n    // Send items remaining in queues.\n    for(;;)\n    {\n        const auto status = Dequeue( token );\n        const auto serialStatus = DequeueSerial();\n        if( status == DequeueStatus::ConnectionLost || serialStatus == DequeueStatus::ConnectionLost )\n        {\n            m_shutdownFinished.store( true, std::memory_order_relaxed );\n            return;\n        }\n        else if( status == DequeueStatus::QueueEmpty && serialStatus == DequeueStatus::QueueEmpty )\n        {\n            if( m_bufferOffset != m_bufferStart ) CommitData();\n            break;\n        }\n\n        while( m_sock->HasData() )\n        {\n            if( !HandleServerQuery() )\n            {\n                m_shutdownFinished.store( true, std::memory_order_relaxed );\n                return;\n            }\n        }\n\n#ifdef TRACY_HAS_CALLSTACK\n        for(;;)\n        {\n            auto si = m_symbolQueue.front();\n            if( !si ) break;\n            HandleSymbolQueueItem( *si );\n            m_symbolQueue.pop();\n        }\n#endif\n    }\n\n    // Send client termination notice to the server\n    QueueItem terminate;\n    MemWrite( &terminate.hdr.type, QueueType::Terminate );\n    if( !SendData( (const char*)&terminate, 1 ) )\n    {\n        m_shutdownFinished.store( true, std::memory_order_relaxed );\n        return;\n    }\n    // Handle remaining server queries\n    for(;;)\n    {\n        while( m_sock->HasData() )\n        {\n            if( !HandleServerQuery() )\n            {\n                m_shutdownFinished.store( true, std::memory_order_relaxed );\n                return;\n            }\n        }\n#ifdef TRACY_HAS_CALLSTACK\n        for(;;)\n        {\n            auto si = m_symbolQueue.front();\n            if( !si ) break;\n            HandleSymbolQueueItem( *si );\n            m_symbolQueue.pop();\n        }\n#endif\n        const auto status = Dequeue( token );\n        const auto serialStatus = DequeueSerial();\n        if( status == DequeueStatus::ConnectionLost || serialStatus == DequeueStatus::ConnectionLost )\n        {\n            m_shutdownFinished.store( true, std::memory_order_relaxed );\n            return;\n        }\n        if( m_bufferOffset != m_bufferStart )\n        {\n            if( !CommitData() )\n            {\n                m_shutdownFinished.store( true, std::memory_order_relaxed );\n                return;\n            }\n        }\n    }\n}\n\n#ifndef TRACY_NO_FRAME_IMAGE\nvoid Profiler::CompressWorker()\n{\n    ThreadExitHandler threadExitHandler;\n    SetThreadName( \"Tracy DXT1\" );\n    while( m_timeBegin.load( std::memory_order_relaxed ) == 0 ) std::this_thread::sleep_for( std::chrono::milliseconds( 10 ) );\n\n#ifdef TRACY_USE_RPMALLOC\n    rpmalloc_thread_initialize();\n#endif\n\n    for(;;)\n    {\n        const auto shouldExit = ShouldExit();\n\n        {\n            bool lockHeld = true;\n            while( !m_fiLock.try_lock() )\n            {\n                if( m_shutdownManual.load( std::memory_order_relaxed ) )\n                {\n                    lockHeld = false;\n                    break;\n                }\n            }\n            if( !m_fiQueue.empty() ) m_fiQueue.swap( m_fiDequeue );\n            if( lockHeld )\n            {\n                m_fiLock.unlock();\n            }\n        }\n\n        const auto sz = m_fiDequeue.size();\n        if( sz > 0 )\n        {\n            auto fi = m_fiDequeue.data();\n            auto end = fi + sz;\n            while( fi != end )\n            {\n                const auto w = fi->w;\n                const auto h = fi->h;\n                const auto csz = size_t( w * h / 2 );\n                auto etc1buf = (char*)tracy_malloc( csz );\n                CompressImageDxt1( (const char*)fi->image, etc1buf, w, h );\n                tracy_free( fi->image );\n\n                TracyLfqPrepare( QueueType::FrameImage );\n                MemWrite( &item->frameImageFat.image, (uint64_t)etc1buf );\n                MemWrite( &item->frameImageFat.frame, fi->frame );\n                MemWrite( &item->frameImageFat.w, w );\n                MemWrite( &item->frameImageFat.h, h );\n                uint8_t flip = fi->flip;\n                MemWrite( &item->frameImageFat.flip, flip );\n                TracyLfqCommit;\n\n                fi++;\n            }\n            m_fiDequeue.clear();\n        }\n        else\n        {\n            std::this_thread::sleep_for( std::chrono::milliseconds( 20 ) );\n        }\n\n        if( shouldExit )\n        {\n            return;\n        }\n    }\n}\n#endif\n\nstatic void FreeAssociatedMemory( const QueueItem& item )\n{\n    if( item.hdr.idx >= (int)QueueType::Terminate ) return;\n\n    uint64_t ptr;\n    switch( item.hdr.type )\n    {\n    case QueueType::ZoneText:\n    case QueueType::ZoneName:\n        ptr = MemRead<uint64_t>( &item.zoneTextFat.text );\n        tracy_free( (void*)ptr );\n        break;\n    case QueueType::MessageColor:\n    case QueueType::MessageColorCallstack:\n        ptr = MemRead<uint64_t>( &item.messageColorFat.text );\n        tracy_free( (void*)ptr );\n        break;\n    case QueueType::Message:\n    case QueueType::MessageCallstack:\n#ifndef TRACY_ON_DEMAND\n    case QueueType::MessageAppInfo:\n#endif\n        ptr = MemRead<uint64_t>( &item.messageFat.text );\n        tracy_free( (void*)ptr );\n        break;\n    case QueueType::ZoneBeginAllocSrcLoc:\n    case QueueType::ZoneBeginAllocSrcLocCallstack:\n        ptr = MemRead<uint64_t>( &item.zoneBegin.srcloc );\n        tracy_free( (void*)ptr );\n        break;\n    case QueueType::GpuZoneBeginAllocSrcLoc:\n    case QueueType::GpuZoneBeginAllocSrcLocCallstack:\n    case QueueType::GpuZoneBeginAllocSrcLocSerial:\n    case QueueType::GpuZoneBeginAllocSrcLocCallstackSerial:\n        ptr = MemRead<uint64_t>( &item.gpuZoneBegin.srcloc );\n        tracy_free( (void*)ptr );\n        break;\n    case QueueType::CallstackSerial:\n    case QueueType::Callstack:\n        ptr = MemRead<uint64_t>( &item.callstackFat.ptr );\n        tracy_free( (void*)ptr );\n        break;\n    case QueueType::CallstackAlloc:\n        ptr = MemRead<uint64_t>( &item.callstackAllocFat.nativePtr );\n        tracy_free( (void*)ptr );\n        ptr = MemRead<uint64_t>( &item.callstackAllocFat.ptr );\n        tracy_free( (void*)ptr );\n        break;\n    case QueueType::CallstackSample:\n    case QueueType::CallstackSampleContextSwitch:\n        ptr = MemRead<uint64_t>( &item.callstackSampleFat.ptr );\n        tracy_free( (void*)ptr );\n        break;\n    case QueueType::FrameImage:\n        ptr = MemRead<uint64_t>( &item.frameImageFat.image );\n        tracy_free( (void*)ptr );\n        break;\n#ifdef TRACY_HAS_CALLSTACK\n    case QueueType::CallstackFrameSize:\n    {\n        InitRpmalloc();\n        auto size = MemRead<uint8_t>( &item.callstackFrameSizeFat.size );\n        auto data = (const CallstackEntry*)MemRead<uint64_t>( &item.callstackFrameSizeFat.data );\n        for( uint8_t i=0; i<size; i++ )\n        {\n            const auto& frame = data[i];\n            tracy_free_fast( (void*)frame.name );\n            tracy_free_fast( (void*)frame.file );\n        }\n        tracy_free_fast( (void*)data );\n        break;\n    }\n    case QueueType::SymbolInformation:\n    {\n        uint8_t needFree = MemRead<uint8_t>( &item.symbolInformationFat.needFree );\n        if( needFree )\n        {\n            ptr = MemRead<uint64_t>( &item.symbolInformationFat.fileString );\n            tracy_free( (void*)ptr );\n        }\n        break;\n    }\n    case QueueType::SymbolCodeMetadata:\n        ptr = MemRead<uint64_t>( &item.symbolCodeMetadata.ptr );\n        tracy_free( (void*)ptr );\n        break;\n#endif\n#ifndef TRACY_ON_DEMAND\n    case QueueType::LockName:\n        ptr = MemRead<uint64_t>( &item.lockNameFat.name );\n        tracy_free( (void*)ptr );\n        break;\n    case QueueType::GpuContextName:\n        ptr = MemRead<uint64_t>( &item.gpuContextNameFat.ptr );\n        tracy_free( (void*)ptr );\n        break;\n#endif\n    case QueueType::GpuAnnotationName:\n        ptr = MemRead<uint64_t>( &item.gpuAnnotationNameFat.ptr );\n        tracy_free( (void*)ptr );\n        break;\n#ifdef TRACY_ON_DEMAND\n    case QueueType::MessageAppInfo:\n    case QueueType::GpuContextName:\n        // Don't free memory associated with deferred messages.\n        break;\n#endif\n#ifdef TRACY_HAS_SYSTEM_TRACING\n    case QueueType::ExternalNameMetadata:\n        ptr = MemRead<uint64_t>( &item.externalNameMetadata.name );\n        tracy_free( (void*)ptr );\n        ptr = MemRead<uint64_t>( &item.externalNameMetadata.threadName );\n        tracy_free_fast( (void*)ptr );\n        break;\n#endif\n    case QueueType::SourceCodeMetadata:\n        ptr = MemRead<uint64_t>( &item.sourceCodeMetadata.ptr );\n        tracy_free( (void*)ptr );\n        break;\n    default:\n        break;\n    }\n}\n\nvoid Profiler::ClearQueues( moodycamel::ConsumerToken& token )\n{\n    for(;;)\n    {\n        const auto sz = GetQueue().try_dequeue_bulk_single( token, [](const uint64_t&){}, []( QueueItem* item, size_t sz ) { assert( sz > 0 ); while( sz-- > 0 ) FreeAssociatedMemory( *item++ ); } );\n        if( sz == 0 ) break;\n    }\n\n    ClearSerial();\n}\n\nvoid Profiler::ClearSerial()\n{\n    bool lockHeld = true;\n    while( !m_serialLock.try_lock() )\n    {\n        if( m_shutdownManual.load( std::memory_order_relaxed ) )\n        {\n            lockHeld = false;\n            break;\n        }\n    }\n    for( auto& v : m_serialQueue ) FreeAssociatedMemory( v );\n    m_serialQueue.clear();\n    if( lockHeld )\n    {\n        m_serialLock.unlock();\n    }\n\n    for( auto& v : m_serialDequeue ) FreeAssociatedMemory( v );\n    m_serialDequeue.clear();\n}\n\nProfiler::DequeueStatus Profiler::Dequeue( moodycamel::ConsumerToken& token )\n{\n    bool connectionLost = false;\n    const auto sz = GetQueue().try_dequeue_bulk_single( token,\n        [this, &connectionLost] ( const uint32_t& threadId )\n        {\n            if( ThreadCtxCheck( threadId ) == ThreadCtxStatus::ConnectionLost ) connectionLost = true;\n        },\n        [this, &connectionLost] ( QueueItem* item, size_t sz )\n        {\n            if( connectionLost ) return;\n            InitRpmalloc();\n            assert( sz > 0 );\n            int64_t refThread = m_refTimeThread;\n            int64_t refCtx = m_refTimeCtx;\n            int64_t refGpu = m_refTimeGpu;\n            while( sz-- > 0 )\n            {\n                uint64_t ptr;\n                uint16_t size;\n                auto idx = MemRead<uint8_t>( &item->hdr.idx );\n                if( idx < (int)QueueType::Terminate )\n                {\n                    switch( (QueueType)idx )\n                    {\n                    case QueueType::ZoneText:\n                    case QueueType::ZoneName:\n                        ptr = MemRead<uint64_t>( &item->zoneTextFat.text );\n                        size = MemRead<uint16_t>( &item->zoneTextFat.size );\n                        SendSingleString( (const char*)ptr, size );\n                        tracy_free_fast( (void*)ptr );\n                        break;\n                    case QueueType::Message:\n                    case QueueType::MessageCallstack:\n                        ptr = MemRead<uint64_t>( &item->messageFat.text );\n                        size = MemRead<uint16_t>( &item->messageFat.size );\n                        SendSingleString( (const char*)ptr, size );\n                        tracy_free_fast( (void*)ptr );\n                        break;\n                    case QueueType::MessageColor:\n                    case QueueType::MessageColorCallstack:\n                        ptr = MemRead<uint64_t>( &item->messageColorFat.text );\n                        size = MemRead<uint16_t>( &item->messageColorFat.size );\n                        SendSingleString( (const char*)ptr, size );\n                        tracy_free_fast( (void*)ptr );\n                        break;\n                    case QueueType::MessageAppInfo:\n                        ptr = MemRead<uint64_t>( &item->messageFat.text );\n                        size = MemRead<uint16_t>( &item->messageFat.size );\n                        SendSingleString( (const char*)ptr, size );\n#ifndef TRACY_ON_DEMAND\n                        tracy_free_fast( (void*)ptr );\n#endif\n                        break;\n                    case QueueType::ZoneBeginAllocSrcLoc:\n                    case QueueType::ZoneBeginAllocSrcLocCallstack:\n                    {\n                        int64_t t = MemRead<int64_t>( &item->zoneBegin.time );\n                        int64_t dt = t - refThread;\n                        refThread = t;\n                        MemWrite( &item->zoneBegin.time, dt );\n                        ptr = MemRead<uint64_t>( &item->zoneBegin.srcloc );\n                        SendSourceLocationPayload( ptr );\n                        tracy_free_fast( (void*)ptr );\n                        break;\n                    }\n                    case QueueType::Callstack:\n                        ptr = MemRead<uint64_t>( &item->callstackFat.ptr );\n                        SendCallstackPayload( ptr );\n                        tracy_free_fast( (void*)ptr );\n                        break;\n                    case QueueType::CallstackAlloc:\n                        ptr = MemRead<uint64_t>( &item->callstackAllocFat.nativePtr );\n                        if( ptr != 0 )\n                        {\n                            CutCallstack( (void*)ptr, \"lua_pcall\" );\n                            SendCallstackPayload( ptr );\n                            tracy_free_fast( (void*)ptr );\n                        }\n                        ptr = MemRead<uint64_t>( &item->callstackAllocFat.ptr );\n                        SendCallstackAlloc( ptr );\n                        tracy_free_fast( (void*)ptr );\n                        break;\n                    case QueueType::CallstackSample:\n                    case QueueType::CallstackSampleContextSwitch:\n                    {\n                        ptr = MemRead<uint64_t>( &item->callstackSampleFat.ptr );\n                        SendCallstackPayload64( ptr );\n                        tracy_free_fast( (void*)ptr );\n                        int64_t t = MemRead<int64_t>( &item->callstackSampleFat.time );\n                        int64_t dt = t - refCtx;\n                        refCtx = t;\n                        MemWrite( &item->callstackSampleFat.time, dt );\n                        break;\n                    }\n                    case QueueType::FrameImage:\n                    {\n                        ptr = MemRead<uint64_t>( &item->frameImageFat.image );\n                        const auto w = MemRead<uint16_t>( &item->frameImageFat.w );\n                        const auto h = MemRead<uint16_t>( &item->frameImageFat.h );\n                        const auto csz = size_t( w * h / 2 );\n                        SendLongString( ptr, (const char*)ptr, csz, QueueType::FrameImageData );\n                        tracy_free_fast( (void*)ptr );\n                        break;\n                    }\n                    case QueueType::ZoneBegin:\n                    case QueueType::ZoneBeginCallstack:\n                    {\n                        int64_t t = MemRead<int64_t>( &item->zoneBegin.time );\n                        int64_t dt = t - refThread;\n                        refThread = t;\n                        MemWrite( &item->zoneBegin.time, dt );\n                        break;\n                    }\n                    case QueueType::ZoneEnd:\n                    {\n                        int64_t t = MemRead<int64_t>( &item->zoneEnd.time );\n                        int64_t dt = t - refThread;\n                        refThread = t;\n                        MemWrite( &item->zoneEnd.time, dt );\n                        break;\n                    }\n                    case QueueType::GpuZoneBegin:\n                    case QueueType::GpuZoneBeginCallstack:\n                    {\n                        int64_t t = MemRead<int64_t>( &item->gpuZoneBegin.cpuTime );\n                        int64_t dt = t - refThread;\n                        refThread = t;\n                        MemWrite( &item->gpuZoneBegin.cpuTime, dt );\n                        break;\n                    }\n                    case QueueType::GpuZoneBeginAllocSrcLoc:\n                    case QueueType::GpuZoneBeginAllocSrcLocCallstack:\n                    {\n                        int64_t t = MemRead<int64_t>( &item->gpuZoneBegin.cpuTime );\n                        int64_t dt = t - refThread;\n                        refThread = t;\n                        MemWrite( &item->gpuZoneBegin.cpuTime, dt );\n                        ptr = MemRead<uint64_t>( &item->gpuZoneBegin.srcloc );\n                        SendSourceLocationPayload( ptr );\n                        tracy_free_fast( (void*)ptr );\n                        break;\n                    }\n                    case QueueType::GpuZoneEnd:\n                    {\n                        int64_t t = MemRead<int64_t>( &item->gpuZoneEnd.cpuTime );\n                        int64_t dt = t - refThread;\n                        refThread = t;\n                        MemWrite( &item->gpuZoneEnd.cpuTime, dt );\n                        break;\n                    }\n                    case QueueType::GpuContextName:\n                        ptr = MemRead<uint64_t>( &item->gpuContextNameFat.ptr );\n                        size = MemRead<uint16_t>( &item->gpuContextNameFat.size );\n                        SendSingleString( (const char*)ptr, size );\n#ifndef TRACY_ON_DEMAND\n                        tracy_free_fast( (void*)ptr );\n#endif\n                        break;\n                    case QueueType::GpuAnnotationName:\n                        ptr = MemRead<uint64_t>( &item->gpuAnnotationNameFat.ptr );\n                        size = MemRead<uint16_t>( &item->gpuAnnotationNameFat.size );\n                        SendSingleString( (const char*)ptr, size );\n                        tracy_free_fast( (void*)ptr );\n                        break;\n                    case QueueType::PlotDataInt:\n                    case QueueType::PlotDataFloat:\n                    case QueueType::PlotDataDouble:\n                    {\n                        int64_t t = MemRead<int64_t>( &item->plotDataInt.time );\n                        int64_t dt = t - refThread;\n                        refThread = t;\n                        MemWrite( &item->plotDataInt.time, dt );\n                        break;\n                    }\n                    case QueueType::ContextSwitch:\n                    {\n                        int64_t t = MemRead<int64_t>( &item->contextSwitch.time );\n                        int64_t dt = t - refCtx;\n                        refCtx = t;\n                        MemWrite( &item->contextSwitch.time, dt );\n                        break;\n                    }\n                    case QueueType::ThreadWakeup:\n                    {\n                        int64_t t = MemRead<int64_t>( &item->threadWakeup.time );\n                        int64_t dt = t - refCtx;\n                        refCtx = t;\n                        MemWrite( &item->threadWakeup.time, dt );\n                        break;\n                    }\n                    case QueueType::GpuTime:\n                    {\n                        int64_t t = MemRead<int64_t>( &item->gpuTime.gpuTime );\n                        int64_t dt = t - refGpu;\n                        refGpu = t;\n                        MemWrite( &item->gpuTime.gpuTime, dt );\n                        break;\n                    }\n#ifdef TRACY_HAS_CALLSTACK\n                    case QueueType::CallstackFrameSize:\n                    {\n                        auto data = (const CallstackEntry*)MemRead<uint64_t>( &item->callstackFrameSizeFat.data );\n                        auto datasz = MemRead<uint8_t>( &item->callstackFrameSizeFat.size );\n                        auto imageName = (const char*)MemRead<uint64_t>( &item->callstackFrameSizeFat.imageName );\n                        SendSingleString( imageName );\n                        AppendData( item++, QueueDataSize[idx] );\n\n                        for( uint8_t i=0; i<datasz; i++ )\n                        {\n                            const auto& frame = data[i];\n\n                            SendSingleString( frame.name );\n                            SendSecondString( frame.file );\n\n                            QueueItem item;\n                            MemWrite( &item.hdr.type, QueueType::CallstackFrame );\n                            MemWrite( &item.callstackFrame.line, frame.line );\n                            MemWrite( &item.callstackFrame.symAddr, frame.symAddr );\n                            MemWrite( &item.callstackFrame.symLen, frame.symLen );\n\n                            AppendData( &item, QueueDataSize[(int)QueueType::CallstackFrame] );\n\n                            tracy_free_fast( (void*)frame.name );\n                            tracy_free_fast( (void*)frame.file );\n                        }\n                        tracy_free_fast( (void*)data );\n                        continue;\n                    }\n                    case QueueType::SymbolInformation:\n                    {\n                        auto fileString = (const char*)MemRead<uint64_t>( &item->symbolInformationFat.fileString );\n                        auto needFree = MemRead<uint8_t>( &item->symbolInformationFat.needFree );\n                        SendSingleString( fileString );\n                        if( needFree ) tracy_free_fast( (void*)fileString );\n                        break;\n                    }\n                    case QueueType::SymbolCodeMetadata:\n                    {\n                        auto symbol = MemRead<uint64_t>( &item->symbolCodeMetadata.symbol );\n                        auto ptr = (const char*)MemRead<uint64_t>( &item->symbolCodeMetadata.ptr );\n                        auto size = MemRead<uint32_t>( &item->symbolCodeMetadata.size );\n                        SendLongString( symbol, ptr, size, QueueType::SymbolCode );\n                        tracy_free_fast( (void*)ptr );\n                        ++item;\n                        continue;\n                    }\n#endif\n#ifdef TRACY_HAS_SYSTEM_TRACING\n                    case QueueType::ExternalNameMetadata:\n                    {\n                        auto thread = MemRead<uint64_t>( &item->externalNameMetadata.thread );\n                        auto name = (const char*)MemRead<uint64_t>( &item->externalNameMetadata.name );\n                        auto threadName = (const char*)MemRead<uint64_t>( &item->externalNameMetadata.threadName );\n                        SendString( thread, threadName, QueueType::ExternalThreadName );\n                        SendString( thread, name, QueueType::ExternalName );\n                        tracy_free_fast( (void*)threadName );\n                        tracy_free_fast( (void*)name );\n                        ++item;\n                        continue;\n                    }\n#endif\n                    case QueueType::SourceCodeMetadata:\n                    {\n                        auto ptr = (const char*)MemRead<uint64_t>( &item->sourceCodeMetadata.ptr );\n                        auto size = MemRead<uint32_t>( &item->sourceCodeMetadata.size );\n                        auto id = MemRead<uint32_t>( &item->sourceCodeMetadata.id );\n                        SendLongString( (uint64_t)id, ptr, size, QueueType::SourceCode );\n                        tracy_free_fast( (void*)ptr );\n                        ++item;\n                        continue;\n                    }\n                    default:\n                        assert( false );\n                        break;\n                    }\n                }\n                if( !AppendData( item++, QueueDataSize[idx] ) )\n                {\n                    connectionLost = true;\n                    m_refTimeThread = refThread;\n                    m_refTimeCtx = refCtx;\n                    m_refTimeGpu = refGpu;\n                    return;\n                }\n            }\n            m_refTimeThread = refThread;\n            m_refTimeCtx = refCtx;\n            m_refTimeGpu = refGpu;\n        }\n    );\n    if( connectionLost ) return DequeueStatus::ConnectionLost;\n    return sz > 0 ? DequeueStatus::DataDequeued : DequeueStatus::QueueEmpty;\n}\n\nProfiler::DequeueStatus Profiler::DequeueContextSwitches( tracy::moodycamel::ConsumerToken& token, int64_t& timeStop )\n{\n    const auto sz = GetQueue().try_dequeue_bulk_single( token, [] ( const uint64_t& ) {},\n        [this, &timeStop] ( QueueItem* item, size_t sz )\n        {\n            assert( sz > 0 );\n            int64_t refCtx = m_refTimeCtx;\n            while( sz-- > 0 )\n            {\n                FreeAssociatedMemory( *item );\n                if( timeStop < 0 ) return;\n                const auto idx = MemRead<uint8_t>( &item->hdr.idx );\n                if( idx == (uint8_t)QueueType::ContextSwitch )\n                {\n                    const auto csTime = MemRead<int64_t>( &item->contextSwitch.time );\n                    if( csTime > timeStop )\n                    {\n                        timeStop = -1;\n                        m_refTimeCtx = refCtx;\n                        return;\n                    }\n                    int64_t dt = csTime - refCtx;\n                    refCtx = csTime;\n                    MemWrite( &item->contextSwitch.time, dt );\n                    if( !AppendData( item, QueueDataSize[(int)QueueType::ContextSwitch] ) )\n                    {\n                        timeStop = -2;\n                        m_refTimeCtx = refCtx;\n                        return;\n                    }\n                }\n                else if( idx == (uint8_t)QueueType::ThreadWakeup )\n                {\n                    const auto csTime = MemRead<int64_t>( &item->threadWakeup.time );\n                    if( csTime > timeStop )\n                    {\n                        timeStop = -1;\n                        m_refTimeCtx = refCtx;\n                        return;\n                    }\n                    int64_t dt = csTime - refCtx;\n                    refCtx = csTime;\n                    MemWrite( &item->threadWakeup.time, dt );\n                    if( !AppendData( item, QueueDataSize[(int)QueueType::ThreadWakeup] ) )\n                    {\n                        timeStop = -2;\n                        m_refTimeCtx = refCtx;\n                        return;\n                    }\n                }\n                item++;\n            }\n            m_refTimeCtx = refCtx;\n        }\n    );\n\n    if( timeStop == -2 ) return DequeueStatus::ConnectionLost;\n    return ( timeStop == -1 || sz > 0 ) ? DequeueStatus::DataDequeued : DequeueStatus::QueueEmpty;\n}\n\n#define ThreadCtxCheckSerial( _name ) \\\n    uint32_t thread = MemRead<uint32_t>( &item->_name.thread ); \\\n    switch( ThreadCtxCheck( thread ) ) \\\n    { \\\n    case ThreadCtxStatus::Same: break; \\\n    case ThreadCtxStatus::Changed: assert( m_refTimeThread == 0 ); refThread = 0; break; \\\n    case ThreadCtxStatus::ConnectionLost: return DequeueStatus::ConnectionLost; \\\n    default: assert( false ); break; \\\n    }\n\nProfiler::DequeueStatus Profiler::DequeueSerial()\n{\n    {\n        bool lockHeld = true;\n        while( !m_serialLock.try_lock() )\n        {\n            if( m_shutdownManual.load( std::memory_order_relaxed ) )\n            {\n                lockHeld = false;\n                break;\n            }\n        }\n        if( !m_serialQueue.empty() ) m_serialQueue.swap( m_serialDequeue );\n        if( lockHeld )\n        {\n            m_serialLock.unlock();\n        }\n    }\n\n    DequeueStatus dequeueStatus = DequeueStatus::QueueEmpty;\n\n    const auto sz = m_serialDequeue.size();\n    if( sz > 0 )\n    {\n        dequeueStatus = DequeueStatus::DataDequeued;\n\n        InitRpmalloc();\n        int64_t refSerial = m_refTimeSerial;\n        int64_t refGpu = m_refTimeGpu;\n#ifdef TRACY_FIBERS\n        int64_t refThread = m_refTimeThread;\n#endif\n        auto item = m_serialDequeue.data();\n        auto end = item + sz;\n        while( item != end )\n        {\n            uint64_t ptr;\n            auto idx = MemRead<uint8_t>( &item->hdr.idx );\n            if( idx < (int)QueueType::Terminate )\n            {\n                switch( (QueueType)idx )\n                {\n                case QueueType::CallstackSerial:\n                    ptr = MemRead<uint64_t>( &item->callstackFat.ptr );\n                    SendCallstackPayload( ptr );\n                    tracy_free_fast( (void*)ptr );\n                    break;\n                case QueueType::LockWait:\n                case QueueType::LockSharedWait:\n                {\n                    int64_t t = MemRead<int64_t>( &item->lockWait.time );\n                    int64_t dt = t - refSerial;\n                    refSerial = t;\n                    MemWrite( &item->lockWait.time, dt );\n                    break;\n                }\n                case QueueType::LockObtain:\n                case QueueType::LockSharedObtain:\n                {\n                    int64_t t = MemRead<int64_t>( &item->lockObtain.time );\n                    int64_t dt = t - refSerial;\n                    refSerial = t;\n                    MemWrite( &item->lockObtain.time, dt );\n                    break;\n                }\n                case QueueType::LockRelease:\n                case QueueType::LockSharedRelease:\n                {\n                    int64_t t = MemRead<int64_t>( &item->lockRelease.time );\n                    int64_t dt = t - refSerial;\n                    refSerial = t;\n                    MemWrite( &item->lockRelease.time, dt );\n                    break;\n                }\n                case QueueType::LockName:\n                {\n                    ptr = MemRead<uint64_t>( &item->lockNameFat.name );\n                    uint16_t size = MemRead<uint16_t>( &item->lockNameFat.size );\n                    SendSingleString( (const char*)ptr, size );\n#ifndef TRACY_ON_DEMAND\n                    tracy_free_fast( (void*)ptr );\n#endif\n                    break;\n                }\n                case QueueType::MemAlloc:\n                case QueueType::MemAllocNamed:\n                case QueueType::MemAllocCallstack:\n                case QueueType::MemAllocCallstackNamed:\n                {\n                    int64_t t = MemRead<int64_t>( &item->memAlloc.time );\n                    int64_t dt = t - refSerial;\n                    refSerial = t;\n                    MemWrite( &item->memAlloc.time, dt );\n                    break;\n                }\n                case QueueType::MemFree:\n                case QueueType::MemFreeNamed:\n                case QueueType::MemFreeCallstack:\n                case QueueType::MemFreeCallstackNamed:\n                {\n                    int64_t t = MemRead<int64_t>( &item->memFree.time );\n                    int64_t dt = t - refSerial;\n                    refSerial = t;\n                    MemWrite( &item->memFree.time, dt );\n                    break;\n                }\n                case QueueType::MemDiscard:\n                case QueueType::MemDiscardCallstack:\n                {\n                    int64_t t = MemRead<int64_t>( &item->memDiscard.time );\n                    int64_t dt = t - refSerial;\n                    refSerial = t;\n                    MemWrite( &item->memDiscard.time, dt );\n                    break;\n                }\n                case QueueType::GpuZoneBeginSerial:\n                case QueueType::GpuZoneBeginCallstackSerial:\n                {\n                    int64_t t = MemRead<int64_t>( &item->gpuZoneBegin.cpuTime );\n                    int64_t dt = t - refSerial;\n                    refSerial = t;\n                    MemWrite( &item->gpuZoneBegin.cpuTime, dt );\n                    break;\n                }\n                case QueueType::GpuZoneBeginAllocSrcLocSerial:\n                case QueueType::GpuZoneBeginAllocSrcLocCallstackSerial:\n                {\n                    int64_t t = MemRead<int64_t>( &item->gpuZoneBegin.cpuTime );\n                    int64_t dt = t - refSerial;\n                    refSerial = t;\n                    MemWrite( &item->gpuZoneBegin.cpuTime, dt );\n                    ptr = MemRead<uint64_t>( &item->gpuZoneBegin.srcloc );\n                    SendSourceLocationPayload( ptr );\n                    tracy_free_fast( (void*)ptr );\n                    break;\n                }\n                case QueueType::GpuZoneEndSerial:\n                {\n                    int64_t t = MemRead<int64_t>( &item->gpuZoneEnd.cpuTime );\n                    int64_t dt = t - refSerial;\n                    refSerial = t;\n                    MemWrite( &item->gpuZoneEnd.cpuTime, dt );\n                    break;\n                }\n                case QueueType::GpuTime:\n                {\n                    int64_t t = MemRead<int64_t>( &item->gpuTime.gpuTime );\n                    int64_t dt = t - refGpu;\n                    refGpu = t;\n                    MemWrite( &item->gpuTime.gpuTime, dt );\n                    break;\n                }\n                case QueueType::GpuContextName:\n                {\n                    ptr = MemRead<uint64_t>( &item->gpuContextNameFat.ptr );\n                    uint16_t size = MemRead<uint16_t>( &item->gpuContextNameFat.size );\n                    SendSingleString( (const char*)ptr, size );\n#ifndef TRACY_ON_DEMAND\n                    tracy_free_fast( (void*)ptr );\n#endif\n                    break;\n                }\n                case QueueType::GpuAnnotationName:\n                {\n                    ptr = MemRead<uint64_t>( &item->gpuAnnotationNameFat.ptr );\n                    uint16_t size = MemRead<uint16_t>( &item->gpuAnnotationNameFat.size );\n                    SendSingleString( (const char*)ptr, size );\n                    tracy_free_fast( (void*)ptr );\n                    break;\n                }\n#ifdef TRACY_FIBERS\n                case QueueType::ZoneBegin:\n                case QueueType::ZoneBeginCallstack:\n                {\n                    ThreadCtxCheckSerial( zoneBeginThread );\n                    int64_t t = MemRead<int64_t>( &item->zoneBegin.time );\n                    int64_t dt = t - refThread;\n                    refThread = t;\n                    MemWrite( &item->zoneBegin.time, dt );\n                    break;\n                }\n                case QueueType::ZoneBeginAllocSrcLoc:\n                case QueueType::ZoneBeginAllocSrcLocCallstack:\n                {\n                    ThreadCtxCheckSerial( zoneBeginThread );\n                    int64_t t = MemRead<int64_t>( &item->zoneBegin.time );\n                    int64_t dt = t - refThread;\n                    refThread = t;\n                    MemWrite( &item->zoneBegin.time, dt );\n                    ptr = MemRead<uint64_t>( &item->zoneBegin.srcloc );\n                    SendSourceLocationPayload( ptr );\n                    tracy_free_fast( (void*)ptr );\n                    break;\n                }\n                case QueueType::ZoneEnd:\n                {\n                    ThreadCtxCheckSerial( zoneEndThread );\n                    int64_t t = MemRead<int64_t>( &item->zoneEnd.time );\n                    int64_t dt = t - refThread;\n                    refThread = t;\n                    MemWrite( &item->zoneEnd.time, dt );\n                    break;\n                }\n                case QueueType::ZoneText:\n                case QueueType::ZoneName:\n                {\n                    ThreadCtxCheckSerial( zoneTextFatThread );\n                    ptr = MemRead<uint64_t>( &item->zoneTextFat.text );\n                    uint16_t size = MemRead<uint16_t>( &item->zoneTextFat.size );\n                    SendSingleString( (const char*)ptr, size );\n                    tracy_free_fast( (void*)ptr );\n                    break;\n                }\n                case QueueType::Message:\n                case QueueType::MessageCallstack:\n                {\n                    ThreadCtxCheckSerial( messageFatThread );\n                    ptr = MemRead<uint64_t>( &item->messageFat.text );\n                    uint16_t size = MemRead<uint16_t>( &item->messageFat.size );\n                    SendSingleString( (const char*)ptr, size );\n                    tracy_free_fast( (void*)ptr );\n                    break;\n                }\n                case QueueType::MessageColor:\n                case QueueType::MessageColorCallstack:\n                {\n                    ThreadCtxCheckSerial( messageColorFatThread );\n                    ptr = MemRead<uint64_t>( &item->messageColorFat.text );\n                    uint16_t size = MemRead<uint16_t>( &item->messageColorFat.size );\n                    SendSingleString( (const char*)ptr, size );\n                    tracy_free_fast( (void*)ptr );\n                    break;\n                }\n                case QueueType::Callstack:\n                {\n                    ThreadCtxCheckSerial( callstackFatThread );\n                    ptr = MemRead<uint64_t>( &item->callstackFat.ptr );\n                    SendCallstackPayload( ptr );\n                    tracy_free_fast( (void*)ptr );\n                    break;\n                }\n                case QueueType::CallstackAlloc:\n                {\n                    ThreadCtxCheckSerial( callstackAllocFatThread );\n                    ptr = MemRead<uint64_t>( &item->callstackAllocFat.nativePtr );\n                    if( ptr != 0 )\n                    {\n                        CutCallstack( (void*)ptr, \"lua_pcall\" );\n                        SendCallstackPayload( ptr );\n                        tracy_free_fast( (void*)ptr );\n                    }\n                    ptr = MemRead<uint64_t>( &item->callstackAllocFat.ptr );\n                    SendCallstackAlloc( ptr );\n                    tracy_free_fast( (void*)ptr );\n                    break;\n                }\n                case QueueType::FiberEnter:\n                {\n                    ThreadCtxCheckSerial( fiberEnter );\n                    int64_t t = MemRead<int64_t>( &item->fiberEnter.time );\n                    int64_t dt = t - refThread;\n                    refThread = t;\n                    MemWrite( &item->fiberEnter.time, dt );\n                    break;\n                }\n                case QueueType::FiberLeave:\n                {\n                    ThreadCtxCheckSerial( fiberLeave );\n                    int64_t t = MemRead<int64_t>( &item->fiberLeave.time );\n                    int64_t dt = t - refThread;\n                    refThread = t;\n                    MemWrite( &item->fiberLeave.time, dt );\n                    break;\n                }\n#endif\n                default:\n                    assert( false );\n                    break;\n                }\n            }\n#ifdef TRACY_FIBERS\n            else\n            {\n                switch( (QueueType)idx )\n                {\n                case QueueType::ZoneColor:\n                {\n                    ThreadCtxCheckSerial( zoneColorThread );\n                    break;\n                }\n                case QueueType::ZoneValue:\n                {\n                    ThreadCtxCheckSerial( zoneValueThread );\n                    break;\n                }\n                case QueueType::ZoneValidation:\n                {\n                    ThreadCtxCheckSerial( zoneValidationThread );\n                    break;\n                }\n                case QueueType::MessageLiteral:\n                case QueueType::MessageLiteralCallstack:\n                {\n                    ThreadCtxCheckSerial( messageLiteralThread );\n                    break;\n                }\n                case QueueType::MessageLiteralColor:\n                case QueueType::MessageLiteralColorCallstack:\n                {\n                    ThreadCtxCheckSerial( messageColorLiteralThread );\n                    break;\n                }\n                case QueueType::CrashReport:\n                {\n                    ThreadCtxCheckSerial( crashReportThread );\n                    break;\n                }\n                default:\n                    break;\n                }\n            }\n#endif\n            if( dequeueStatus != DequeueStatus::ConnectionLost && !AppendData( item, QueueDataSize[idx] ) )\n            {\n                dequeueStatus = DequeueStatus::ConnectionLost;\n            }\n            item++;\n        }\n        m_refTimeSerial = refSerial;\n        m_refTimeGpu = refGpu;\n#ifdef TRACY_FIBERS\n        m_refTimeThread = refThread;\n#endif\n        m_serialDequeue.clear();\n    }\n    return dequeueStatus;\n}\n\nProfiler::ThreadCtxStatus Profiler::ThreadCtxCheck( uint32_t threadId )\n{\n    if( m_threadCtx == threadId ) return ThreadCtxStatus::Same;\n    QueueItem item;\n    MemWrite( &item.hdr.type, QueueType::ThreadContext );\n    MemWrite( &item.threadCtx.thread, threadId );\n    if( !AppendData( &item, QueueDataSize[(int)QueueType::ThreadContext] ) ) return ThreadCtxStatus::ConnectionLost;\n    m_threadCtx = threadId;\n    m_refTimeThread = 0;\n    return ThreadCtxStatus::Changed;\n}\n\nbool Profiler::CommitData()\n{\n    bool ret = SendData( m_buffer + m_bufferStart, m_bufferOffset - m_bufferStart );\n    if( m_bufferOffset > TargetFrameSize * 2 ) m_bufferOffset = 0;\n    m_bufferStart = m_bufferOffset;\n    return ret;\n}\n\nchar* Profiler::SafeCopyProlog( const char* data, size_t size )\n{\n    bool success = true;\n    char* buf = m_safeSendBuffer;\n#ifndef NDEBUG\n    assert( !m_inUse.exchange(true) );\n#endif\n\n    if( size > SafeSendBufferSize ) buf = (char*)tracy_malloc( size );\n\n#ifdef _WIN32\n#  ifdef _MSC_VER\n    __try\n    {\n        memcpy( buf, data, size );\n    }\n    __except( 1 /*EXCEPTION_EXECUTE_HANDLER*/ )\n    {\n        success = false;\n    }\n#  else\n    memcpy( buf, data, size );\n#  endif\n#else\n    // Send through the pipe to ensure safe reads\n    for( size_t offset = 0; offset != size; /*in loop*/ )\n    {\n        size_t sendsize = size - offset;\n        ssize_t result1, result2;\n        while( ( result1 = write( m_pipe[1], data + offset, sendsize ) ) < 0 && errno == EINTR ) { /* retry */ }\n        if( result1 < 0 )\n        {\n            success = false;\n            break;\n        }\n        while( ( result2 = read( m_pipe[0], buf + offset, result1 ) ) < 0 && errno == EINTR ) { /* retry */ }\n        if( result2 != result1 )\n        {\n            success = false;\n            break;\n        }\n        offset += result1;\n    }\n#endif\n\n    if( success ) return buf;\n\n    SafeCopyEpilog( buf );\n    return nullptr;\n}\n\nvoid Profiler::SafeCopyEpilog( char* buf )\n{\n    if( buf != m_safeSendBuffer ) tracy_free( buf );\n\n#ifndef NDEBUG\n    m_inUse.store( false );\n#endif\n}\n\nbool Profiler::SendData( const char* data, size_t len )\n{\n    const lz4sz_t lz4sz = LZ4_compress_fast_continue( (LZ4_stream_t*)m_stream, data, m_lz4Buf + sizeof( lz4sz_t ), (int)len, LZ4Size, 1 );\n    memcpy( m_lz4Buf, &lz4sz, sizeof( lz4sz ) );\n    return m_sock->Send( m_lz4Buf, lz4sz + sizeof( lz4sz_t ) ) != -1;\n}\n\nvoid Profiler::SendString( uint64_t str, const char* ptr, size_t len, QueueType type )\n{\n    assert( type == QueueType::StringData ||\n            type == QueueType::ThreadName ||\n            type == QueueType::PlotName ||\n            type == QueueType::FrameName ||\n            type == QueueType::ExternalName ||\n            type == QueueType::ExternalThreadName ||\n            type == QueueType::FiberName );\n\n    QueueItem item;\n    MemWrite( &item.hdr.type, type );\n    MemWrite( &item.stringTransfer.ptr, str );\n\n    assert( len <= std::numeric_limits<uint16_t>::max() );\n    auto l16 = uint16_t( len );\n\n    NeedDataSize( QueueDataSize[(int)type] + sizeof( l16 ) + l16 );\n\n    AppendDataUnsafe( &item, QueueDataSize[(int)type] );\n    AppendDataUnsafe( &l16, sizeof( l16 ) );\n    AppendDataUnsafe( ptr, l16 );\n}\n\nvoid Profiler::SendSingleString( const char* ptr, size_t len )\n{\n    QueueItem item;\n    MemWrite( &item.hdr.type, QueueType::SingleStringData );\n\n    assert( len <= std::numeric_limits<uint16_t>::max() );\n    auto l16 = uint16_t( len );\n\n    NeedDataSize( QueueDataSize[(int)QueueType::SingleStringData] + sizeof( l16 ) + l16 );\n\n    AppendDataUnsafe( &item, QueueDataSize[(int)QueueType::SingleStringData] );\n    AppendDataUnsafe( &l16, sizeof( l16 ) );\n    AppendDataUnsafe( ptr, l16 );\n}\n\nvoid Profiler::SendSecondString( const char* ptr, size_t len )\n{\n    QueueItem item;\n    MemWrite( &item.hdr.type, QueueType::SecondStringData );\n\n    assert( len <= std::numeric_limits<uint16_t>::max() );\n    auto l16 = uint16_t( len );\n\n    NeedDataSize( QueueDataSize[(int)QueueType::SecondStringData] + sizeof( l16 ) + l16 );\n\n    AppendDataUnsafe( &item, QueueDataSize[(int)QueueType::SecondStringData] );\n    AppendDataUnsafe( &l16, sizeof( l16 ) );\n    AppendDataUnsafe( ptr, l16 );\n}\n\nvoid Profiler::SendLongString( uint64_t str, const char* ptr, size_t len, QueueType type )\n{\n    assert( type == QueueType::FrameImageData ||\n            type == QueueType::SymbolCode ||\n            type == QueueType::SourceCode );\n\n    QueueItem item;\n    MemWrite( &item.hdr.type, type );\n    MemWrite( &item.stringTransfer.ptr, str );\n\n    assert( len <= std::numeric_limits<uint32_t>::max() );\n    assert( QueueDataSize[(int)type] + sizeof( uint32_t ) + len <= TargetFrameSize );\n    auto l32 = uint32_t( len );\n\n    NeedDataSize( QueueDataSize[(int)type] + sizeof( l32 ) + l32 );\n\n    AppendDataUnsafe( &item, QueueDataSize[(int)type] );\n    AppendDataUnsafe( &l32, sizeof( l32 ) );\n    AppendDataUnsafe( ptr, l32 );\n}\n\nvoid Profiler::SendSourceLocation( uint64_t ptr )\n{\n    auto srcloc = (const SourceLocationData*)ptr;\n    QueueItem item;\n    MemWrite( &item.hdr.type, QueueType::SourceLocation );\n    MemWrite( &item.srcloc.name, (uint64_t)srcloc->name );\n    MemWrite( &item.srcloc.file, (uint64_t)srcloc->file );\n    MemWrite( &item.srcloc.function, (uint64_t)srcloc->function );\n    MemWrite( &item.srcloc.line, srcloc->line );\n    MemWrite( &item.srcloc.b, uint8_t( ( srcloc->color       ) & 0xFF ) );\n    MemWrite( &item.srcloc.g, uint8_t( ( srcloc->color >> 8  ) & 0xFF ) );\n    MemWrite( &item.srcloc.r, uint8_t( ( srcloc->color >> 16 ) & 0xFF ) );\n    AppendData( &item, QueueDataSize[(int)QueueType::SourceLocation] );\n}\n\nvoid Profiler::SendSourceLocationPayload( uint64_t _ptr )\n{\n    auto ptr = (const char*)_ptr;\n\n    QueueItem item;\n    MemWrite( &item.hdr.type, QueueType::SourceLocationPayload );\n    MemWrite( &item.stringTransfer.ptr, _ptr );\n\n    uint16_t len;\n    memcpy( &len, ptr, sizeof( len ) );\n    assert( len > 2 );\n    len -= 2;\n    ptr += 2;\n\n    NeedDataSize( QueueDataSize[(int)QueueType::SourceLocationPayload] + sizeof( len ) + len );\n\n    AppendDataUnsafe( &item, QueueDataSize[(int)QueueType::SourceLocationPayload] );\n    AppendDataUnsafe( &len, sizeof( len ) );\n    AppendDataUnsafe( ptr, len );\n}\n\nvoid Profiler::SendCallstackPayload( uint64_t _ptr )\n{\n    auto ptr = (uintptr_t*)_ptr;\n\n    QueueItem item;\n    MemWrite( &item.hdr.type, QueueType::CallstackPayload );\n    MemWrite( &item.stringTransfer.ptr, _ptr );\n\n    const auto sz = *ptr++;\n    const auto len = sz * sizeof( uint64_t );\n    const auto l16 = uint16_t( len );\n\n    NeedDataSize( QueueDataSize[(int)QueueType::CallstackPayload] + sizeof( l16 ) + l16 );\n\n    AppendDataUnsafe( &item, QueueDataSize[(int)QueueType::CallstackPayload] );\n    AppendDataUnsafe( &l16, sizeof( l16 ) );\n\n    if( compile_time_condition<sizeof( uintptr_t ) == sizeof( uint64_t )>::value )\n    {\n        AppendDataUnsafe( ptr, sizeof( uint64_t ) * sz );\n    }\n    else\n    {\n        for( uintptr_t i=0; i<sz; i++ )\n        {\n            const auto val = uint64_t( *ptr++ );\n            AppendDataUnsafe( &val, sizeof( uint64_t ) );\n        }\n    }\n}\n\nvoid Profiler::SendCallstackPayload64( uint64_t _ptr )\n{\n    auto ptr = (uint64_t*)_ptr;\n\n    QueueItem item;\n    MemWrite( &item.hdr.type, QueueType::CallstackPayload );\n    MemWrite( &item.stringTransfer.ptr, _ptr );\n\n    const auto sz = *ptr++;\n    const auto len = sz * sizeof( uint64_t );\n    const auto l16 = uint16_t( len );\n\n    NeedDataSize( QueueDataSize[(int)QueueType::CallstackPayload] + sizeof( l16 ) + l16 );\n\n    AppendDataUnsafe( &item, QueueDataSize[(int)QueueType::CallstackPayload] );\n    AppendDataUnsafe( &l16, sizeof( l16 ) );\n    AppendDataUnsafe( ptr, sizeof( uint64_t ) * sz );\n}\n\nvoid Profiler::SendCallstackAlloc( uint64_t _ptr )\n{\n    auto ptr = (const char*)_ptr;\n\n    QueueItem item;\n    MemWrite( &item.hdr.type, QueueType::CallstackAllocPayload );\n    MemWrite( &item.stringTransfer.ptr, _ptr );\n\n    uint16_t len;\n    memcpy( &len, ptr, 2 );\n    ptr += 2;\n\n    NeedDataSize( QueueDataSize[(int)QueueType::CallstackAllocPayload] + sizeof( len ) + len );\n\n    AppendDataUnsafe( &item, QueueDataSize[(int)QueueType::CallstackAllocPayload] );\n    AppendDataUnsafe( &len, sizeof( len ) );\n    AppendDataUnsafe( ptr, len );\n}\n\nvoid Profiler::QueueCallstackFrame( uint64_t ptr )\n{\n#ifdef TRACY_HAS_CALLSTACK\n    m_symbolQueue.emplace( SymbolQueueItem { SymbolQueueItemType::CallstackFrame, ptr } );\n#else\n    AckServerQuery();\n#endif\n}\n\nvoid Profiler::QueueSymbolQuery( uint64_t symbol )\n{\n#ifdef TRACY_HAS_CALLSTACK\n    // Special handling for kernel frames\n    if( symbol >> 63 != 0 )\n    {\n        SendSingleString( \"<kernel>\" );\n        QueueItem item;\n        MemWrite( &item.hdr.type, QueueType::SymbolInformation );\n        MemWrite( &item.symbolInformation.line, 0 );\n        MemWrite( &item.symbolInformation.symAddr, symbol );\n        AppendData( &item, QueueDataSize[(int)QueueType::SymbolInformation] );\n    }\n    else\n    {\n        m_symbolQueue.emplace( SymbolQueueItem { SymbolQueueItemType::SymbolQuery, symbol } );\n    }\n#else\n    AckServerQuery();\n#endif\n}\n\nvoid Profiler::QueueExternalName( uint64_t ptr )\n{\n#ifdef TRACY_HAS_SYSTEM_TRACING\n    m_symbolQueue.emplace( SymbolQueueItem { SymbolQueueItemType::ExternalName, ptr } );\n#endif\n}\n\nvoid Profiler::QueueKernelCode( uint64_t symbol, uint32_t size )\n{\n    assert( symbol >> 63 != 0 );\n#ifdef TRACY_HAS_CALLSTACK\n    m_symbolQueue.emplace( SymbolQueueItem { SymbolQueueItemType::KernelCode, symbol, size } );\n#else\n    AckSymbolCodeNotAvailable();\n#endif\n}\n\nvoid Profiler::QueueSourceCodeQuery( uint32_t id )\n{\n    assert( m_exectime != 0 );\n    assert( m_queryData );\n    m_symbolQueue.emplace( SymbolQueueItem { SymbolQueueItemType::SourceCode, uint64_t( m_queryData ), uint64_t( m_queryImage ), id } );\n    m_queryData = nullptr;\n    m_queryImage = nullptr;\n}\n\n#ifdef TRACY_HAS_CALLSTACK\nvoid Profiler::HandleSymbolQueueItem( const SymbolQueueItem& si )\n{\n    switch( si.type )\n    {\n    case SymbolQueueItemType::CallstackFrame:\n    {\n        const auto frameData = DecodeCallstackPtr( si.ptr );\n        auto data = tracy_malloc_fast( sizeof( CallstackEntry ) * frameData.size );\n        memcpy( data, frameData.data, sizeof( CallstackEntry ) * frameData.size );\n        TracyLfqPrepare( QueueType::CallstackFrameSize );\n        MemWrite( &item->callstackFrameSizeFat.ptr, si.ptr );\n        MemWrite( &item->callstackFrameSizeFat.size, frameData.size );\n        MemWrite( &item->callstackFrameSizeFat.data, (uint64_t)data );\n        MemWrite( &item->callstackFrameSizeFat.imageName, (uint64_t)frameData.imageName );\n        TracyLfqCommit;\n        break;\n    }\n    case SymbolQueueItemType::SymbolQuery:\n    {\n#ifdef __ANDROID__\n        // On Android it's common for code to be in mappings that are only executable\n        // but not readable.\n        if( !EnsureReadable( si.ptr ) )\n        {\n            TracyLfqPrepare( QueueType::AckServerQueryNoop );\n            TracyLfqCommit;\n            break;\n        }\n#endif\n        const auto sym = DecodeSymbolAddress( si.ptr );\n        TracyLfqPrepare( QueueType::SymbolInformation );\n        MemWrite( &item->symbolInformationFat.line, sym.line );\n        MemWrite( &item->symbolInformationFat.symAddr, si.ptr );\n        MemWrite( &item->symbolInformationFat.fileString, (uint64_t)sym.file );\n        MemWrite( &item->symbolInformationFat.needFree, (uint8_t)sym.needFree );\n        TracyLfqCommit;\n        break;\n    }\n#ifdef TRACY_HAS_SYSTEM_TRACING\n    case SymbolQueueItemType::ExternalName:\n    {\n        const char* threadName;\n        const char* name;\n        SysTraceGetExternalName( si.ptr, threadName, name );\n        TracyLfqPrepare( QueueType::ExternalNameMetadata );\n        MemWrite( &item->externalNameMetadata.thread, si.ptr );\n        MemWrite( &item->externalNameMetadata.name, (uint64_t)name );\n        MemWrite( &item->externalNameMetadata.threadName, (uint64_t)threadName );\n        TracyLfqCommit;\n        break;\n    }\n#endif\n    case SymbolQueueItemType::KernelCode:\n    {\n#ifdef _WIN32\n        auto mod = GetKernelModulePath( si.ptr );\n        if( mod )\n        {\n            auto fn = DecodeCallstackPtrFast( si.ptr );\n            if( *fn )\n            {\n                auto hnd = LoadLibraryExA( mod, nullptr, DONT_RESOLVE_DLL_REFERENCES );\n                if( hnd )\n                {\n                    auto ptr = (const void*)GetProcAddress( hnd, fn );\n                    if( ptr )\n                    {\n                        auto buf = (char*)tracy_malloc( si.extra );\n                        memcpy( buf, ptr, si.extra );\n                        FreeLibrary( hnd );\n                        TracyLfqPrepare( QueueType::SymbolCodeMetadata );\n                        MemWrite( &item->symbolCodeMetadata.symbol, si.ptr );\n                        MemWrite( &item->symbolCodeMetadata.ptr, (uint64_t)buf );\n                        MemWrite( &item->symbolCodeMetadata.size, (uint32_t)si.extra );\n                        TracyLfqCommit;\n                        break;\n                    }\n                    FreeLibrary( hnd );\n                }\n            }\n        }\n#elif defined __linux__\n        void* data = m_kcore->Retrieve( si.ptr, si.extra );\n        if( data )\n        {\n            TracyLfqPrepare( QueueType::SymbolCodeMetadata );\n            MemWrite( &item->symbolCodeMetadata.symbol, si.ptr );\n            MemWrite( &item->symbolCodeMetadata.ptr, (uint64_t)data );\n            MemWrite( &item->symbolCodeMetadata.size, (uint32_t)si.extra );\n            TracyLfqCommit;\n            break;\n        }\n#endif\n        TracyLfqPrepare( QueueType::AckSymbolCodeNotAvailable );\n        TracyLfqCommit;\n        break;\n    }\n    case SymbolQueueItemType::SourceCode:\n        HandleSourceCodeQuery( (char*)si.ptr, (char*)si.extra, si.id );\n        break;\n    default:\n        assert( false );\n        break;\n    }\n}\n\nvoid Profiler::SymbolWorker()\n{\n#if defined __linux__ && !defined TRACY_NO_CRASH_HANDLER\n    s_symbolTid = syscall( SYS_gettid );\n#endif\n\n    ThreadExitHandler threadExitHandler;\n    SetThreadName( \"Tracy Symbol Worker\" );\n#ifdef TRACY_USE_RPMALLOC\n    InitRpmalloc();\n#endif\n    InitCallstack();\n    while( m_timeBegin.load( std::memory_order_relaxed ) == 0 ) std::this_thread::sleep_for( std::chrono::milliseconds( 10 ) );\n\n    for(;;)\n    {\n        const auto shouldExit = ShouldExit();\n#ifdef TRACY_ON_DEMAND\n        if( !IsConnected() )\n        {\n            if( shouldExit )\n            {\n                s_symbolThreadGone.store( true, std::memory_order_release );\n                return;\n            }\n            while( m_symbolQueue.front() ) m_symbolQueue.pop();\n            std::this_thread::sleep_for( std::chrono::milliseconds( 20 ) );\n            m_symbolsBusy.store( false, std::memory_order_release );\n            continue;\n        }\n#endif\n        auto si = m_symbolQueue.front();\n        if( si )\n        {\n            HandleSymbolQueueItem( *si );\n            m_symbolQueue.pop();\n        }\n        else\n        {\n            if( shouldExit )\n            {\n                s_symbolThreadGone.store( true, std::memory_order_release );\n                return;\n            }\n            std::this_thread::sleep_for( std::chrono::milliseconds( 20 ) );\n        }\n    }\n}\n#endif\n\nbool Profiler::HandleServerQuery()\n{\n    ServerQueryPacket payload;\n    if( !m_sock->Read( &payload, sizeof( payload ), 10 ) ) return false;\n\n    uint8_t type;\n    uint64_t ptr;\n    memcpy( &type, &payload.type, sizeof( payload.type ) );\n    memcpy( &ptr, &payload.ptr, sizeof( payload.ptr ) );\n\n    switch( type )\n    {\n    case ServerQueryString:\n        SendString( ptr, (const char*)ptr, QueueType::StringData );\n        break;\n    case ServerQueryThreadString:\n        if( ptr == m_mainThread )\n        {\n            SendString( ptr, \"Main thread\", 11, QueueType::ThreadName );\n        }\n        else\n        {\n            auto t = GetThreadNameData( (uint32_t)ptr );\n            if( t )\n            {\n                SendString( ptr, t->name, QueueType::ThreadName );\n                if( t->groupHint != 0 )\n                {\n                    TracyLfqPrepare( QueueType::ThreadGroupHint );\n                    MemWrite( &item->threadGroupHint.thread, (uint32_t)ptr );\n                    MemWrite( &item->threadGroupHint.groupHint, t->groupHint );\n                    TracyLfqCommit;\n                }\n            }\n            else\n            {\n                SendString( ptr, GetThreadName( (uint32_t)ptr ), QueueType::ThreadName );\n            }\n        }\n        break;\n    case ServerQuerySourceLocation:\n        SendSourceLocation( ptr );\n        break;\n    case ServerQueryPlotName:\n        SendString( ptr, (const char*)ptr, QueueType::PlotName );\n        break;\n    case ServerQueryTerminate:\n        return false;\n    case ServerQueryCallstackFrame:\n        QueueCallstackFrame( ptr );\n        break;\n    case ServerQueryFrameName:\n        SendString( ptr, (const char*)ptr, QueueType::FrameName );\n        break;\n    case ServerQueryDisconnect:\n        HandleDisconnect();\n        return false;\n#ifdef TRACY_HAS_SYSTEM_TRACING\n    case ServerQueryExternalName:\n        QueueExternalName( ptr );\n        break;\n#endif\n    case ServerQueryParameter:\n        HandleParameter( ptr );\n        break;\n    case ServerQuerySymbol:\n        QueueSymbolQuery( ptr );\n        break;\n#ifndef TRACY_NO_CODE_TRANSFER\n    case ServerQuerySymbolCode:\n        HandleSymbolCodeQuery( ptr, payload.extra );\n        break;\n#endif\n    case ServerQuerySourceCode:\n        QueueSourceCodeQuery( uint32_t( ptr ) );\n        break;\n    case ServerQueryDataTransfer:\n        if( m_queryData )\n        {\n            assert( !m_queryImage );\n            m_queryImage = m_queryData;\n        }\n        m_queryDataPtr = m_queryData = (char*)tracy_malloc( ptr + 11 );\n        AckServerQuery();\n        break;\n    case ServerQueryDataTransferPart:\n        memcpy( m_queryDataPtr, &ptr, 8 );\n        memcpy( m_queryDataPtr+8, &payload.extra, 4 );\n        m_queryDataPtr += 12;\n        AckServerQuery();\n        break;\n#ifdef TRACY_FIBERS\n    case ServerQueryFiberName:\n        SendString( ptr, (const char*)ptr, QueueType::FiberName );\n        break;\n#endif\n    default:\n        assert( false );\n        break;\n    }\n\n    return true;\n}\n\nvoid Profiler::HandleDisconnect()\n{\n    moodycamel::ConsumerToken token( GetQueue() );\n\n#ifdef TRACY_HAS_SYSTEM_TRACING\n    if( s_sysTraceThread )\n    {\n        auto timestamp = GetTime();\n        for(;;)\n        {\n            const auto status = DequeueContextSwitches( token, timestamp );\n            if( status == DequeueStatus::ConnectionLost )\n            {\n                return;\n            }\n            else if( status == DequeueStatus::QueueEmpty )\n            {\n                if( m_bufferOffset != m_bufferStart )\n                {\n                    if( !CommitData() ) return;\n                }\n            }\n            if( timestamp < 0 )\n            {\n                if( m_bufferOffset != m_bufferStart )\n                {\n                    if( !CommitData() ) return;\n                }\n                break;\n            }\n            ClearSerial();\n            if( m_sock->HasData() )\n            {\n                while( m_sock->HasData() )\n                {\n                    if( !HandleServerQuery() ) return;\n                }\n                if( m_bufferOffset != m_bufferStart )\n                {\n                    if( !CommitData() ) return;\n                }\n            }\n            else\n            {\n                if( m_bufferOffset != m_bufferStart )\n                {\n                    if( !CommitData() ) return;\n                }\n                std::this_thread::sleep_for( std::chrono::milliseconds( 10 ) );\n            }\n        }\n    }\n#endif\n\n    QueueItem terminate;\n    MemWrite( &terminate.hdr.type, QueueType::Terminate );\n    if( !SendData( (const char*)&terminate, 1 ) ) return;\n    for(;;)\n    {\n        ClearQueues( token );\n        if( m_sock->HasData() )\n        {\n            while( m_sock->HasData() )\n            {\n                if( !HandleServerQuery() ) return;\n            }\n            if( m_bufferOffset != m_bufferStart )\n            {\n                if( !CommitData() ) return;\n            }\n        }\n        else\n        {\n            if( m_bufferOffset != m_bufferStart )\n            {\n                if( !CommitData() ) return;\n            }\n            std::this_thread::sleep_for( std::chrono::milliseconds( 10 ) );\n        }\n    }\n}\n\nvoid Profiler::CalibrateTimer()\n{\n    m_timerMul = 1.;\n\n#ifdef TRACY_HW_TIMER\n\n#  if !defined TRACY_TIMER_QPC && defined TRACY_TIMER_FALLBACK\n    const bool needCalibration = HardwareSupportsInvariantTSC();\n#  else\n    const bool needCalibration = true;\n#  endif\n    if( needCalibration )\n    {\n        std::atomic_signal_fence( std::memory_order_acq_rel );\n        const auto t0 = std::chrono::high_resolution_clock::now();\n        const auto r0 = GetTime();\n        std::atomic_signal_fence( std::memory_order_acq_rel );\n        std::this_thread::sleep_for( std::chrono::milliseconds( 200 ) );\n        std::atomic_signal_fence( std::memory_order_acq_rel );\n        const auto t1 = std::chrono::high_resolution_clock::now();\n        const auto r1 = GetTime();\n        std::atomic_signal_fence( std::memory_order_acq_rel );\n\n        const auto dt = std::chrono::duration_cast<std::chrono::nanoseconds>( t1 - t0 ).count();\n        const auto dr = r1 - r0;\n\n        m_timerMul = double( dt ) / double( dr );\n    }\n#endif\n}\n\nvoid Profiler::CalibrateDelay()\n{\n    constexpr int Iterations = 50000;\n\n    auto mindiff = std::numeric_limits<int64_t>::max();\n    for( int i=0; i<Iterations * 10; i++ )\n    {\n        const auto t0i = GetTime();\n        const auto t1i = GetTime();\n        const auto dti = t1i - t0i;\n        if( dti > 0 && dti < mindiff ) mindiff = dti;\n    }\n    m_resolution = mindiff;\n}\n\nvoid Profiler::ReportTopology()\n{\n#ifndef TRACY_DELAYED_INIT\n    struct CpuData\n    {\n        uint32_t package;\n        uint32_t die;\n        uint32_t core;\n        uint32_t thread;\n    };\n\n#if defined _WIN32\n#  if defined TRACY_WIN32_NO_DESKTOP\n    t_GetLogicalProcessorInformationEx _GetLogicalProcessorInformationEx = &::GetLogicalProcessorInformationEx;\n#  else\n    t_GetLogicalProcessorInformationEx _GetLogicalProcessorInformationEx = (t_GetLogicalProcessorInformationEx)GetProcAddress( GetModuleHandleA( \"kernel32.dll\" ), \"GetLogicalProcessorInformationEx\" );\n#  endif\n    if( !_GetLogicalProcessorInformationEx ) return;\n\n    SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX* packageInfo = nullptr;\n    SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX* dieInfo = nullptr;\n    SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX* coreInfo = nullptr;\n\n    DWORD psz = 0;\n    _GetLogicalProcessorInformationEx( RelationProcessorPackage, nullptr, &psz );\n    if( GetLastError() == ERROR_INSUFFICIENT_BUFFER )\n    {\n        packageInfo = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)tracy_malloc( psz );\n        auto res = _GetLogicalProcessorInformationEx( RelationProcessorPackage, packageInfo, &psz );\n        assert( res );\n    }\n    else\n    {\n        psz = 0;\n    }\n\n    DWORD dsz = 0;\n    _GetLogicalProcessorInformationEx( RelationProcessorDie, nullptr, &dsz );\n    if( GetLastError() == ERROR_INSUFFICIENT_BUFFER )\n    {\n        dieInfo = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)tracy_malloc( dsz );\n        auto res = _GetLogicalProcessorInformationEx( RelationProcessorDie, dieInfo, &dsz );\n        assert( res );\n    }\n    else\n    {\n        dsz = 0;\n    }\n\n    DWORD csz = 0;\n    _GetLogicalProcessorInformationEx( RelationProcessorCore, nullptr, &csz );\n    if( GetLastError() == ERROR_INSUFFICIENT_BUFFER )\n    {\n        coreInfo = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)tracy_malloc( csz );\n        auto res = _GetLogicalProcessorInformationEx( RelationProcessorCore, coreInfo, &csz );\n        assert( res );\n    }\n    else\n    {\n        csz = 0;\n    }\n\n    SYSTEM_INFO sysinfo;\n    GetSystemInfo( &sysinfo );\n    const uint32_t numcpus = sysinfo.dwNumberOfProcessors;\n\n    auto cpuData = (CpuData*)tracy_malloc( sizeof( CpuData ) * numcpus );\n    memset( cpuData, 0, sizeof( CpuData ) * numcpus );\n    for( uint32_t i=0; i<numcpus; i++ ) cpuData[i].thread = i;\n\n    int idx = 0;\n    auto ptr = packageInfo;\n    while( (char*)ptr < ((char*)packageInfo) + psz )\n    {\n        assert( ptr->Relationship == RelationProcessorPackage );\n        // FIXME account for GroupCount\n        auto mask = ptr->Processor.GroupMask[0].Mask;\n        int core = 0;\n        while( mask != 0 )\n        {\n            if( mask & 1 ) cpuData[core].package = idx;\n            core++;\n            mask >>= 1;\n        }\n        ptr = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)(((char*)ptr) + ptr->Size);\n        idx++;\n    }\n\n    idx = 0;\n    ptr = dieInfo;\n    while( (char*)ptr < ((char*)dieInfo) + dsz )\n    {\n        assert( ptr->Relationship == RelationProcessorDie );\n        // FIXME account for GroupCount\n        auto mask = ptr->Processor.GroupMask[0].Mask;\n        int core = 0;\n        while( mask != 0 )\n        {\n            if( mask & 1 ) cpuData[core].die = idx;\n            core++;\n            mask >>= 1;\n        }\n        ptr = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)(((char*)ptr) + ptr->Size);\n        idx++;\n    }\n\n    idx = 0;\n    ptr = coreInfo;\n    while( (char*)ptr < ((char*)coreInfo) + csz )\n    {\n        assert( ptr->Relationship == RelationProcessorCore );\n        // FIXME account for GroupCount\n        auto mask = ptr->Processor.GroupMask[0].Mask;\n        int core = 0;\n        while( mask != 0 )\n        {\n            if( mask & 1 ) cpuData[core].core = idx;\n            core++;\n            mask >>= 1;\n        }\n        ptr = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)(((char*)ptr) + ptr->Size);\n        idx++;\n    }\n\n    for( uint32_t i=0; i<numcpus; i++ )\n    {\n        auto& data = cpuData[i];\n\n        TracyLfqPrepare( QueueType::CpuTopology );\n        MemWrite( &item->cpuTopology.package, data.package );\n        MemWrite( &item->cpuTopology.die, data.die );\n        MemWrite( &item->cpuTopology.core, data.core );\n        MemWrite( &item->cpuTopology.thread, data.thread );\n\n#ifdef TRACY_ON_DEMAND\n        DeferItem( *item );\n#endif\n\n        TracyLfqCommit;\n    }\n\n    tracy_free( cpuData );\n    tracy_free( coreInfo );\n    tracy_free( packageInfo );\n#elif defined __linux__\n    const int numcpus = std::thread::hardware_concurrency();\n    auto cpuData = (CpuData*)tracy_malloc( sizeof( CpuData ) * numcpus );\n    memset( cpuData, 0, sizeof( CpuData ) * numcpus );\n\n    const char* basePath = \"/sys/devices/system/cpu/cpu\";\n    for( int i=0; i<numcpus; i++ )\n    {\n        char path[1024];\n        sprintf( path, \"%s%i/topology/physical_package_id\", basePath, i );\n        char buf[1024];\n        FILE* f = fopen( path, \"rb\" );\n        if( !f )\n        {\n            tracy_free( cpuData );\n            return;\n        }\n        auto read = fread( buf, 1, 1024, f );\n        buf[read] = '\\0';\n        fclose( f );\n        cpuData[i].package = uint32_t( atoi( buf ) );\n        cpuData[i].thread = i;\n\n        sprintf( path, \"%s%i/topology/core_id\", basePath, i );\n        f = fopen( path, \"rb\" );\n        if( f )\n        {\n            read = fread( buf, 1, 1024, f );\n            buf[read] = '\\0';\n            fclose( f );\n            cpuData[i].core = uint32_t( atoi( buf ) );\n        }\n\n        sprintf( path, \"%s%i/topology/die_id\", basePath, i );\n        f = fopen( path, \"rb\" );\n        if( f )\n        {\n            read = fread( buf, 1, 1024, f );\n            buf[read] = '\\0';\n            fclose( f );\n            cpuData[i].die = uint32_t( atoi( buf ) );\n        }\n    }\n\n    for( int i=0; i<numcpus; i++ )\n    {\n        auto& data = cpuData[i];\n\n        TracyLfqPrepare( QueueType::CpuTopology );\n        MemWrite( &item->cpuTopology.package, data.package );\n        MemWrite( &item->cpuTopology.die, data.die );\n        MemWrite( &item->cpuTopology.core, data.core );\n        MemWrite( &item->cpuTopology.thread, data.thread );\n\n#ifdef TRACY_ON_DEMAND\n        DeferItem( *item );\n#endif\n\n        TracyLfqCommit;\n    }\n\n    tracy_free( cpuData );\n#endif\n#endif\n}\n\nvoid Profiler::SendCallstack( int32_t depth, const char* skipBefore )\n{\n#ifdef TRACY_HAS_CALLSTACK\n    auto ptr = Callstack( depth );\n    CutCallstack( ptr, skipBefore );\n\n    TracyQueuePrepare( QueueType::Callstack );\n    MemWrite( &item->callstackFat.ptr, (uint64_t)ptr );\n    TracyQueueCommit( callstackFatThread );\n#endif\n}\n\nvoid Profiler::CutCallstack( void* callstack, const char* skipBefore )\n{\n#ifdef TRACY_HAS_CALLSTACK\n    auto data = (uintptr_t*)callstack;\n    const auto sz = *data++;\n    uintptr_t i;\n    for( i=0; i<sz; i++ )\n    {\n        auto name = DecodeCallstackPtrFast( uint64_t( data[i] ) );\n        const bool found = strcmp( name, skipBefore ) == 0;\n        if( found )\n        {\n            i++;\n            break;\n        }\n    }\n\n    if( i != sz )\n    {\n        memmove( data, data + i, ( sz - i ) * sizeof( uintptr_t* ) );\n        *--data = sz - i;\n    }\n#endif\n}\n\n#ifdef TRACY_HAS_SYSTIME\nvoid Profiler::ProcessSysTime()\n{\n    if( m_shutdown.load( std::memory_order_relaxed ) ) return;\n    auto t = std::chrono::high_resolution_clock::now().time_since_epoch().count();\n    if( t - m_sysTimeLast > 100000000 )    // 100 ms\n    {\n        auto sysTime = m_sysTime.Get();\n        if( sysTime >= 0 )\n        {\n            m_sysTimeLast = t;\n\n            TracyLfqPrepare( QueueType::SysTimeReport );\n            MemWrite( &item->sysTime.time, GetTime() );\n            MemWrite( &item->sysTime.sysTime, sysTime );\n            TracyLfqCommit;\n        }\n    }\n}\n#endif\n\nvoid Profiler::HandleParameter( uint64_t payload )\n{\n    assert( m_paramCallback );\n    const auto idx = uint32_t( payload >> 32 );\n    const auto val = int32_t( payload & 0xFFFFFFFF );\n    m_paramCallback( m_paramCallbackData, idx, val );\n    AckServerQuery();\n}\n\nvoid Profiler::HandleSymbolCodeQuery( uint64_t symbol, uint32_t size )\n{\n    if( symbol >> 63 != 0 )\n    {\n        QueueKernelCode( symbol, size );\n    }\n    else\n    {\n        auto&& lambda = [ this, symbol ]( const char* buf, size_t size ) {\n            SendLongString( symbol, buf, size, QueueType::SymbolCode );\n        };\n\n        // 'symbol' may have come from a module that has since unloaded, perform a safe copy before sending\n        if( !WithSafeCopy( (const char*)symbol, size, lambda ) ) AckSymbolCodeNotAvailable();\n    }\n}\n\nvoid Profiler::HandleSourceCodeQuery( char* data, char* image, uint32_t id )\n{\n    bool ok = false;\n    FILE* f = fopen( data, \"rb\" );\n    if( f )\n    {\n        struct stat st;\n        if( fstat( fileno( f ), &st ) == 0 && (uint64_t)st.st_mtime < m_exectime && st.st_size < ( TargetFrameSize - 16 ) )\n        {\n            auto ptr = (char*)tracy_malloc_fast( st.st_size );\n            auto rd = fread( ptr, 1, st.st_size, f );\n            if( rd == (size_t)st.st_size )\n            {\n                TracyLfqPrepare( QueueType::SourceCodeMetadata );\n                MemWrite( &item->sourceCodeMetadata.ptr, (uint64_t)ptr );\n                MemWrite( &item->sourceCodeMetadata.size, (uint32_t)rd );\n                MemWrite( &item->sourceCodeMetadata.id, id );\n                TracyLfqCommit;\n                ok = true;\n            }\n            else\n            {\n                tracy_free_fast( ptr );\n            }\n        }\n        fclose( f );\n    }\n\n#ifdef TRACY_DEBUGINFOD\n    else if( image && data[0] == '/' )\n    {\n        size_t size;\n        auto buildid = GetBuildIdForImage( image, size );\n        if( buildid )\n        {\n            auto d = debuginfod_find_source( GetDebuginfodClient(), buildid, size, data, nullptr );\n            TracyDebug( \"DebugInfo source query: %s, fn: %s, image: %s\\n\", d >= 0 ? \" ok \" : \"fail\", data, image );\n            if( d >= 0 )\n            {\n                struct stat st;\n                fstat( d, &st );\n                if( st.st_size < ( TargetFrameSize - 16 ) )\n                {\n                    lseek( d, 0, SEEK_SET );\n                    auto ptr = (char*)tracy_malloc_fast( st.st_size );\n                    auto rd = read( d, ptr, st.st_size );\n                    if( rd == (size_t)st.st_size )\n                    {\n                        TracyLfqPrepare( QueueType::SourceCodeMetadata );\n                        MemWrite( &item->sourceCodeMetadata.ptr, (uint64_t)ptr );\n                        MemWrite( &item->sourceCodeMetadata.size, (uint32_t)rd );\n                        MemWrite( &item->sourceCodeMetadata.id, id );\n                        TracyLfqCommit;\n                        ok = true;\n                    }\n                    else\n                    {\n                        tracy_free_fast( ptr );\n                    }\n                }\n                close( d );\n            }\n        }\n    }\n    else\n    {\n        TracyDebug( \"DebugInfo invalid query fn: %s, image: %s\\n\", data, image );\n    }\n#endif\n\n    if( !ok && m_sourceCallback )\n    {\n        size_t sz;\n        char* ptr = m_sourceCallback( m_sourceCallbackData, data, sz );\n        if( ptr )\n        {\n            if( sz < ( TargetFrameSize - 16 ) )\n            {\n                TracyLfqPrepare( QueueType::SourceCodeMetadata );\n                MemWrite( &item->sourceCodeMetadata.ptr, (uint64_t)ptr );\n                MemWrite( &item->sourceCodeMetadata.size, (uint32_t)sz );\n                MemWrite( &item->sourceCodeMetadata.id, id );\n                TracyLfqCommit;\n                ok = true;\n            }\n            else\n            {\n                tracy_free_fast( ptr );\n            }\n        }\n    }\n\n    if( !ok )\n    {\n        TracyLfqPrepare( QueueType::AckSourceCodeNotAvailable );\n        MemWrite( &item->sourceCodeNotAvailable, id );\n        TracyLfqCommit;\n    }\n\n    tracy_free_fast( data );\n    tracy_free_fast( image );\n}\n\n#if defined _WIN32 && defined TRACY_TIMER_QPC\nint64_t Profiler::GetTimeQpc()\n{\n    LARGE_INTEGER t;\n    QueryPerformanceCounter( &t );\n    return t.QuadPart;\n}\n#endif\n\n}\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nTRACY_API TracyCZoneCtx ___tracy_emit_zone_begin( const struct ___tracy_source_location_data* srcloc, int32_t active )\n{\n    ___tracy_c_zone_context ctx;\n#ifdef TRACY_ON_DEMAND\n    ctx.active = active && tracy::GetProfiler().IsConnected();\n#else\n    ctx.active = active;\n#endif\n    if( !ctx.active ) return ctx;\n    const auto id = tracy::GetProfiler().GetNextZoneId();\n    ctx.id = id;\n\n#ifndef TRACY_NO_VERIFY\n    {\n        TracyQueuePrepareC( tracy::QueueType::ZoneValidation );\n        tracy::MemWrite( &item->zoneValidation.id, id );\n        TracyQueueCommitC( zoneValidationThread );\n    }\n#endif\n    {\n        TracyQueuePrepareC( tracy::QueueType::ZoneBegin );\n        tracy::MemWrite( &item->zoneBegin.time, tracy::Profiler::GetTime() );\n        tracy::MemWrite( &item->zoneBegin.srcloc, (uint64_t)srcloc );\n        TracyQueueCommitC( zoneBeginThread );\n    }\n    return ctx;\n}\n\nTRACY_API TracyCZoneCtx ___tracy_emit_zone_begin_callstack( const struct ___tracy_source_location_data* srcloc, int32_t depth, int32_t active )\n{\n    ___tracy_c_zone_context ctx;\n#ifdef TRACY_ON_DEMAND\n    ctx.active = active && tracy::GetProfiler().IsConnected();\n#else\n    ctx.active = active;\n#endif\n    if( !ctx.active ) return ctx;\n    const auto id = tracy::GetProfiler().GetNextZoneId();\n    ctx.id = id;\n\n#ifndef TRACY_NO_VERIFY\n    {\n        TracyQueuePrepareC( tracy::QueueType::ZoneValidation );\n        tracy::MemWrite( &item->zoneValidation.id, id );\n        TracyQueueCommitC( zoneValidationThread );\n    }\n#endif\n    auto zoneQueue = tracy::QueueType::ZoneBegin;\n    if( depth > 0 && tracy::has_callstack() )\n    {\n        tracy::GetProfiler().SendCallstack( depth );\n        zoneQueue = tracy::QueueType::ZoneBeginCallstack;\n    }\n    TracyQueuePrepareC( zoneQueue );\n    tracy::MemWrite( &item->zoneBegin.time, tracy::Profiler::GetTime() );\n    tracy::MemWrite( &item->zoneBegin.srcloc, (uint64_t)srcloc );\n    TracyQueueCommitC( zoneBeginThread );\n\n    return ctx;\n}\n\nTRACY_API TracyCZoneCtx ___tracy_emit_zone_begin_alloc( uint64_t srcloc, int32_t active )\n{\n    ___tracy_c_zone_context ctx;\n#ifdef TRACY_ON_DEMAND\n    ctx.active = active && tracy::GetProfiler().IsConnected();\n#else\n    ctx.active = active;\n#endif\n    if( !ctx.active )\n    {\n        tracy::tracy_free( (void*)srcloc );\n        return ctx;\n    }\n    const auto id = tracy::GetProfiler().GetNextZoneId();\n    ctx.id = id;\n\n#ifndef TRACY_NO_VERIFY\n    {\n        TracyQueuePrepareC( tracy::QueueType::ZoneValidation );\n        tracy::MemWrite( &item->zoneValidation.id, id );\n        TracyQueueCommitC( zoneValidationThread );\n    }\n#endif\n    {\n        TracyQueuePrepareC( tracy::QueueType::ZoneBeginAllocSrcLoc );\n        tracy::MemWrite( &item->zoneBegin.time, tracy::Profiler::GetTime() );\n        tracy::MemWrite( &item->zoneBegin.srcloc, srcloc );\n        TracyQueueCommitC( zoneBeginThread );\n    }\n    return ctx;\n}\n\nTRACY_API TracyCZoneCtx ___tracy_emit_zone_begin_alloc_callstack( uint64_t srcloc, int32_t depth, int32_t active )\n{\n    ___tracy_c_zone_context ctx;\n#ifdef TRACY_ON_DEMAND\n    ctx.active = active && tracy::GetProfiler().IsConnected();\n#else\n    ctx.active = active;\n#endif\n    if( !ctx.active )\n    {\n        tracy::tracy_free( (void*)srcloc );\n        return ctx;\n    }\n    const auto id = tracy::GetProfiler().GetNextZoneId();\n    ctx.id = id;\n\n#ifndef TRACY_NO_VERIFY\n    {\n        TracyQueuePrepareC( tracy::QueueType::ZoneValidation );\n        tracy::MemWrite( &item->zoneValidation.id, id );\n        TracyQueueCommitC( zoneValidationThread );\n    }\n#endif\n    auto zoneQueue = tracy::QueueType::ZoneBeginAllocSrcLoc;\n    if( depth > 0 && tracy::has_callstack() )\n    {\n        tracy::GetProfiler().SendCallstack( depth );\n        zoneQueue = tracy::QueueType::ZoneBeginAllocSrcLocCallstack;\n    }\n    TracyQueuePrepareC( zoneQueue );\n    tracy::MemWrite( &item->zoneBegin.time, tracy::Profiler::GetTime() );\n    tracy::MemWrite( &item->zoneBegin.srcloc, srcloc );\n    TracyQueueCommitC( zoneBeginThread );\n\n    return ctx;\n}\n\nTRACY_API void ___tracy_emit_zone_end( TracyCZoneCtx ctx )\n{\n    if( !ctx.active ) return;\n#ifndef TRACY_NO_VERIFY\n    {\n        TracyQueuePrepareC( tracy::QueueType::ZoneValidation );\n        tracy::MemWrite( &item->zoneValidation.id, ctx.id );\n        TracyQueueCommitC( zoneValidationThread );\n    }\n#endif\n    {\n        TracyQueuePrepareC( tracy::QueueType::ZoneEnd );\n        tracy::MemWrite( &item->zoneEnd.time, tracy::Profiler::GetTime() );\n        TracyQueueCommitC( zoneEndThread );\n    }\n}\n\nTRACY_API void ___tracy_emit_zone_text( TracyCZoneCtx ctx, const char* txt, size_t size )\n{\n    assert( size < std::numeric_limits<uint16_t>::max() );\n    if( !ctx.active ) return;\n    auto ptr = (char*)tracy::tracy_malloc( size );\n    memcpy( ptr, txt, size );\n#ifndef TRACY_NO_VERIFY\n    {\n        TracyQueuePrepareC( tracy::QueueType::ZoneValidation );\n        tracy::MemWrite( &item->zoneValidation.id, ctx.id );\n        TracyQueueCommitC( zoneValidationThread );\n    }\n#endif\n    {\n        TracyQueuePrepareC( tracy::QueueType::ZoneText );\n        tracy::MemWrite( &item->zoneTextFat.text, (uint64_t)ptr );\n        tracy::MemWrite( &item->zoneTextFat.size, (uint16_t)size );\n        TracyQueueCommitC( zoneTextFatThread );\n    }\n}\n\nTRACY_API void ___tracy_emit_zone_name( TracyCZoneCtx ctx, const char* txt, size_t size )\n{\n    assert( size < std::numeric_limits<uint16_t>::max() );\n    if( !ctx.active ) return;\n    auto ptr = (char*)tracy::tracy_malloc( size );\n    memcpy( ptr, txt, size );\n#ifndef TRACY_NO_VERIFY\n    {\n        TracyQueuePrepareC( tracy::QueueType::ZoneValidation );\n        tracy::MemWrite( &item->zoneValidation.id, ctx.id );\n        TracyQueueCommitC( zoneValidationThread );\n    }\n#endif\n    {\n        TracyQueuePrepareC( tracy::QueueType::ZoneName );\n        tracy::MemWrite( &item->zoneTextFat.text, (uint64_t)ptr );\n        tracy::MemWrite( &item->zoneTextFat.size, (uint16_t)size );\n        TracyQueueCommitC( zoneTextFatThread );\n    }\n}\n\nTRACY_API void ___tracy_emit_zone_color( TracyCZoneCtx ctx, uint32_t color ) {\n    if( !ctx.active ) return;\n#ifndef TRACY_NO_VERIFY\n    {\n        TracyQueuePrepareC( tracy::QueueType::ZoneValidation );\n        tracy::MemWrite( &item->zoneValidation.id, ctx.id );\n        TracyQueueCommitC( zoneValidationThread );\n    }\n#endif\n    {\n        TracyQueuePrepareC( tracy::QueueType::ZoneColor );\n        tracy::MemWrite( &item->zoneColor.b, uint8_t( ( color       ) & 0xFF ) );\n        tracy::MemWrite( &item->zoneColor.g, uint8_t( ( color >> 8  ) & 0xFF ) );\n        tracy::MemWrite( &item->zoneColor.r, uint8_t( ( color >> 16 ) & 0xFF ) );\n        TracyQueueCommitC( zoneColorThread );\n    }\n}\n\nTRACY_API void ___tracy_emit_zone_value( TracyCZoneCtx ctx, uint64_t value )\n{\n    if( !ctx.active ) return;\n#ifndef TRACY_NO_VERIFY\n    {\n        TracyQueuePrepareC( tracy::QueueType::ZoneValidation );\n        tracy::MemWrite( &item->zoneValidation.id, ctx.id );\n        TracyQueueCommitC( zoneValidationThread );\n    }\n#endif\n    {\n        TracyQueuePrepareC( tracy::QueueType::ZoneValue );\n        tracy::MemWrite( &item->zoneValue.value, value );\n        TracyQueueCommitC( zoneValueThread );\n    }\n}\n\nTRACY_API void ___tracy_emit_memory_alloc( const void* ptr, size_t size, int32_t secure ) { tracy::Profiler::MemAlloc( ptr, size, secure != 0 ); }\nTRACY_API void ___tracy_emit_memory_alloc_callstack( const void* ptr, size_t size, int32_t depth, int32_t secure )\n{\n    if( depth > 0 && tracy::has_callstack() )\n    {\n        tracy::Profiler::MemAllocCallstack( ptr, size, depth, secure != 0 );\n    }\n    else\n    {\n        tracy::Profiler::MemAlloc( ptr, size, secure != 0 );\n    }\n}\nTRACY_API void ___tracy_emit_memory_free( const void* ptr, int32_t secure ) { tracy::Profiler::MemFree( ptr, secure != 0 ); }\nTRACY_API void ___tracy_emit_memory_free_callstack( const void* ptr, int32_t depth, int32_t secure )\n{\n    if( depth > 0 && tracy::has_callstack() )\n    {\n        tracy::Profiler::MemFreeCallstack( ptr, depth, secure != 0 );\n    }\n    else\n    {\n        tracy::Profiler::MemFree( ptr, secure != 0 );\n    }\n}\nTRACY_API void ___tracy_emit_memory_discard( const char* name, int32_t secure ) { tracy::Profiler::MemDiscard( name, secure != 0 ); }\nTRACY_API void ___tracy_emit_memory_discard_callstack( const char* name, int32_t secure, int32_t depth )\n{\n    if( depth > 0 && tracy::has_callstack() )\n    {\n        tracy::Profiler::MemDiscardCallstack( name, secure != 0, depth );\n    }\n    else\n    {\n        tracy::Profiler::MemDiscard( name, secure != 0 );\n    }\n}\nTRACY_API void ___tracy_emit_memory_alloc_named( const void* ptr, size_t size, int32_t secure, const char* name ) { tracy::Profiler::MemAllocNamed( ptr, size, secure != 0, name ); }\nTRACY_API void ___tracy_emit_memory_alloc_callstack_named( const void* ptr, size_t size, int32_t depth, int32_t secure, const char* name )\n{\n    if( depth > 0 && tracy::has_callstack() )\n    {\n        tracy::Profiler::MemAllocCallstackNamed( ptr, size, depth, secure != 0, name );\n    }\n    else\n    {\n        tracy::Profiler::MemAllocNamed( ptr, size, secure != 0, name );\n    }\n}\nTRACY_API void ___tracy_emit_memory_free_named( const void* ptr, int32_t secure, const char* name ) { tracy::Profiler::MemFreeNamed( ptr, secure != 0, name ); }\nTRACY_API void ___tracy_emit_memory_free_callstack_named( const void* ptr, int32_t depth, int32_t secure, const char* name )\n{\n    if( depth > 0 && tracy::has_callstack() )\n    {\n        tracy::Profiler::MemFreeCallstackNamed( ptr, depth, secure != 0, name );\n    }\n    else\n    {\n        tracy::Profiler::MemFreeNamed( ptr, secure != 0, name );\n    }\n}\nTRACY_API void ___tracy_emit_frame_mark( const char* name ) { tracy::Profiler::SendFrameMark( name ); }\nTRACY_API void ___tracy_emit_frame_mark_start( const char* name ) { tracy::Profiler::SendFrameMark( name, tracy::QueueType::FrameMarkMsgStart ); }\nTRACY_API void ___tracy_emit_frame_mark_end( const char* name ) { tracy::Profiler::SendFrameMark( name, tracy::QueueType::FrameMarkMsgEnd ); }\nTRACY_API void ___tracy_emit_frame_image( const void* image, uint16_t w, uint16_t h, uint8_t offset, int32_t flip ) { tracy::Profiler::SendFrameImage( image, w, h, offset, flip != 0 ); }\nTRACY_API void ___tracy_emit_plot( const char* name, double val ) { tracy::Profiler::PlotData( name, val ); }\nTRACY_API void ___tracy_emit_plot_float( const char* name, float val ) { tracy::Profiler::PlotData( name, val ); }\nTRACY_API void ___tracy_emit_plot_int( const char* name, int64_t val ) { tracy::Profiler::PlotData( name, val ); }\nTRACY_API void ___tracy_emit_plot_config( const char* name, int32_t type, int32_t step, int32_t fill, uint32_t color ) { tracy::Profiler::ConfigurePlot( name, tracy::PlotFormatType(type), step != 0, fill != 0, color ); }\nTRACY_API void ___tracy_emit_message( const char* txt, size_t size, int32_t callstack_depth ) { tracy::Profiler::Message( txt, size, callstack_depth ); }\nTRACY_API void ___tracy_emit_messageL( const char* txt, int32_t callstack_depth ) { tracy::Profiler::Message( txt, callstack_depth ); }\nTRACY_API void ___tracy_emit_messageC( const char* txt, size_t size, uint32_t color, int32_t callstack_depth ) { tracy::Profiler::MessageColor( txt, size, color, callstack_depth ); }\nTRACY_API void ___tracy_emit_messageLC( const char* txt, uint32_t color, int32_t callstack_depth ) { tracy::Profiler::MessageColor( txt, color, callstack_depth ); }\nTRACY_API void ___tracy_emit_message_appinfo( const char* txt, size_t size ) { tracy::Profiler::MessageAppInfo( txt, size ); }\n\nTRACY_API uint64_t ___tracy_alloc_srcloc( uint32_t line, const char* source, size_t sourceSz, const char* function, size_t functionSz, uint32_t color ) {\n    return tracy::Profiler::AllocSourceLocation( line, source, sourceSz, function, functionSz, color );\n}\n\nTRACY_API uint64_t ___tracy_alloc_srcloc_name( uint32_t line, const char* source, size_t sourceSz, const char* function, size_t functionSz, const char* name, size_t nameSz, uint32_t color ) {\n    return tracy::Profiler::AllocSourceLocation( line, source, sourceSz, function, functionSz, name, nameSz, color );\n}\n\nTRACY_API void ___tracy_emit_gpu_zone_begin( const struct ___tracy_gpu_zone_begin_data data )\n{\n    TracyLfqPrepareC( tracy::QueueType::GpuZoneBegin );\n    tracy::MemWrite( &item->gpuZoneBegin.cpuTime, tracy::Profiler::GetTime() );\n    tracy::MemWrite( &item->gpuZoneBegin.thread, tracy::GetThreadHandle() );\n    tracy::MemWrite( &item->gpuZoneBegin.srcloc, data.srcloc );\n    tracy::MemWrite( &item->gpuZoneBegin.queryId, data.queryId );\n    tracy::MemWrite( &item->gpuZoneBegin.context, data.context );\n    TracyLfqCommitC;\n}\n\nTRACY_API void ___tracy_emit_gpu_zone_begin_callstack( const struct ___tracy_gpu_zone_begin_callstack_data data )\n{\n    tracy::GetProfiler().SendCallstack( data.depth );\n    TracyLfqPrepareC( tracy::QueueType::GpuZoneBeginCallstack );\n    tracy::MemWrite( &item->gpuZoneBegin.thread, tracy::GetThreadHandle() );\n    tracy::MemWrite( &item->gpuZoneBegin.cpuTime, tracy::Profiler::GetTime() );\n    tracy::MemWrite( &item->gpuZoneBegin.queryId, data.queryId );\n    tracy::MemWrite( &item->gpuZoneBegin.context, data.context );\n    tracy::MemWrite( &item->gpuZoneBegin.srcloc, data.srcloc );\n    TracyLfqCommitC;\n}\n\nTRACY_API void ___tracy_emit_gpu_zone_begin_alloc( const struct ___tracy_gpu_zone_begin_data data )\n{\n    TracyLfqPrepareC( tracy::QueueType::GpuZoneBeginAllocSrcLoc  );\n    tracy::MemWrite( &item->gpuZoneBegin.cpuTime, tracy::Profiler::GetTime() );\n    tracy::MemWrite( &item->gpuZoneBegin.thread, tracy::GetThreadHandle() );\n    tracy::MemWrite( &item->gpuZoneBegin.srcloc, data.srcloc );\n    tracy::MemWrite( &item->gpuZoneBegin.queryId, data.queryId );\n    tracy::MemWrite( &item->gpuZoneBegin.context, data.context );\n    TracyLfqCommitC;\n}\n\nTRACY_API void ___tracy_emit_gpu_zone_begin_alloc_callstack( const struct ___tracy_gpu_zone_begin_callstack_data data )\n{\n    tracy::GetProfiler().SendCallstack( data.depth );\n    TracyLfqPrepareC( tracy::QueueType::GpuZoneBeginAllocSrcLocCallstack  );\n    tracy::MemWrite( &item->gpuZoneBegin.cpuTime, tracy::Profiler::GetTime() );\n    tracy::MemWrite( &item->gpuZoneBegin.thread, tracy::GetThreadHandle() );\n    tracy::MemWrite( &item->gpuZoneBegin.srcloc, data.srcloc );\n    tracy::MemWrite( &item->gpuZoneBegin.queryId, data.queryId );\n    tracy::MemWrite( &item->gpuZoneBegin.context, data.context );\n    TracyLfqCommitC;\n}\n\nTRACY_API void ___tracy_emit_gpu_time( const struct ___tracy_gpu_time_data data )\n{\n    TracyLfqPrepareC( tracy::QueueType::GpuTime );\n    tracy::MemWrite( &item->gpuTime.gpuTime, data.gpuTime );\n    tracy::MemWrite( &item->gpuTime.queryId, data.queryId );\n    tracy::MemWrite( &item->gpuTime.context, data.context );\n    TracyLfqCommitC;\n}\n\nTRACY_API void ___tracy_emit_gpu_zone_end( const struct ___tracy_gpu_zone_end_data data )\n{\n    TracyLfqPrepareC( tracy::QueueType::GpuZoneEnd );\n    tracy::MemWrite( &item->gpuZoneEnd.cpuTime, tracy::Profiler::GetTime() );\n    memset( &item->gpuZoneEnd.thread, 0, sizeof( item->gpuZoneEnd.thread ) );\n    tracy::MemWrite( &item->gpuZoneEnd.queryId, data.queryId );\n    tracy::MemWrite( &item->gpuZoneEnd.context, data.context );\n    TracyLfqCommitC;\n}\n\nTRACY_API void ___tracy_emit_gpu_new_context( ___tracy_gpu_new_context_data data )\n{\n    TracyLfqPrepareC( tracy::QueueType::GpuNewContext );\n    tracy::MemWrite( &item->gpuNewContext.cpuTime, tracy::Profiler::GetTime() );\n    tracy::MemWrite( &item->gpuNewContext.thread, tracy::GetThreadHandle() );\n    tracy::MemWrite( &item->gpuNewContext.gpuTime, data.gpuTime );\n    tracy::MemWrite( &item->gpuNewContext.period, data.period );\n    tracy::MemWrite( &item->gpuNewContext.context, data.context );\n    tracy::MemWrite( &item->gpuNewContext.flags, data.flags );\n    tracy::MemWrite( &item->gpuNewContext.type, data.type );\n\n#ifdef TRACY_ON_DEMAND\n    tracy::GetProfiler().DeferItem( *item );\n#endif\n\n    TracyLfqCommitC;\n}\n\nTRACY_API void ___tracy_emit_gpu_context_name( const struct ___tracy_gpu_context_name_data data )\n{\n    auto ptr = (char*)tracy::tracy_malloc( data.len );\n    memcpy( ptr, data.name, data.len );\n\n    TracyLfqPrepareC( tracy::QueueType::GpuContextName );\n    tracy::MemWrite( &item->gpuContextNameFat.context, data.context );\n    tracy::MemWrite( &item->gpuContextNameFat.ptr, (uint64_t)ptr );\n    tracy::MemWrite( &item->gpuContextNameFat.size, data.len );\n\n#ifdef TRACY_ON_DEMAND\n    tracy::GetProfiler().DeferItem( *item );\n#endif\n\n    TracyLfqCommitC;\n}\n\nTRACY_API void ___tracy_emit_gpu_calibration( const struct ___tracy_gpu_calibration_data data )\n{\n    TracyLfqPrepareC( tracy::QueueType::GpuCalibration );\n    tracy::MemWrite( &item->gpuCalibration.cpuTime, tracy::Profiler::GetTime() );\n    tracy::MemWrite( &item->gpuCalibration.gpuTime, data.gpuTime );\n    tracy::MemWrite( &item->gpuCalibration.cpuDelta, data.cpuDelta );\n    tracy::MemWrite( &item->gpuCalibration.context, data.context );\n    TracyLfqCommitC;\n}\n\nTRACY_API void ___tracy_emit_gpu_time_sync( const struct ___tracy_gpu_time_sync_data data )\n{\n    TracyLfqPrepareC( tracy::QueueType::GpuTimeSync );\n    tracy::MemWrite( &item->gpuTimeSync.cpuTime, tracy::Profiler::GetTime() );\n    tracy::MemWrite( &item->gpuTimeSync.gpuTime, data.gpuTime );\n    tracy::MemWrite( &item->gpuTimeSync.context, data.context );\n    TracyLfqCommitC;\n}\n\nTRACY_API void ___tracy_emit_gpu_zone_begin_serial( const struct ___tracy_gpu_zone_begin_data data )\n{\n    auto item = tracy::Profiler::QueueSerial();\n    tracy::MemWrite( &item->hdr.type, tracy::QueueType::GpuZoneBeginSerial );\n    tracy::MemWrite( &item->gpuZoneBegin.cpuTime, tracy::Profiler::GetTime() );\n    tracy::MemWrite( &item->gpuZoneBegin.srcloc, data.srcloc );\n    tracy::MemWrite( &item->gpuZoneBegin.thread, tracy::GetThreadHandle() );\n    tracy::MemWrite( &item->gpuZoneBegin.queryId, data.queryId );\n    tracy::MemWrite( &item->gpuZoneBegin.context, data.context );\n    tracy::Profiler::QueueSerialFinish();\n}\n\nTRACY_API void ___tracy_emit_gpu_zone_begin_callstack_serial( const struct ___tracy_gpu_zone_begin_callstack_data data )\n{\n    auto item = tracy::Profiler::QueueSerialCallstack( tracy::Callstack( data.depth ) );\n    tracy::MemWrite( &item->hdr.type, tracy::QueueType::GpuZoneBeginCallstackSerial );\n    tracy::MemWrite( &item->gpuZoneBegin.cpuTime, tracy::Profiler::GetTime() );\n    tracy::MemWrite( &item->gpuZoneBegin.srcloc, data.srcloc );\n    tracy::MemWrite( &item->gpuZoneBegin.thread, tracy::GetThreadHandle() );\n    tracy::MemWrite( &item->gpuZoneBegin.queryId, data.queryId );\n    tracy::MemWrite( &item->gpuZoneBegin.context, data.context );\n    tracy::Profiler::QueueSerialFinish();\n}\n\nTRACY_API void ___tracy_emit_gpu_zone_begin_alloc_serial( const struct ___tracy_gpu_zone_begin_data data )\n{\n    auto item = tracy::Profiler::QueueSerial();\n    tracy::MemWrite( &item->hdr.type, tracy::QueueType::GpuZoneBeginAllocSrcLocSerial );\n    tracy::MemWrite( &item->gpuZoneBegin.cpuTime, tracy::Profiler::GetTime() );\n    tracy::MemWrite( &item->gpuZoneBegin.thread, tracy::GetThreadHandle() );\n    tracy::MemWrite( &item->gpuZoneBegin.srcloc, data.srcloc );\n    tracy::MemWrite( &item->gpuZoneBegin.queryId, data.queryId );\n    tracy::MemWrite( &item->gpuZoneBegin.context, data.context );\n    tracy::Profiler::QueueSerialFinish();\n}\n\nTRACY_API void ___tracy_emit_gpu_zone_begin_alloc_callstack_serial( const struct ___tracy_gpu_zone_begin_callstack_data data )\n{\n    auto item = tracy::Profiler::QueueSerialCallstack( tracy::Callstack( data.depth ) );\n    tracy::MemWrite( &item->hdr.type, tracy::QueueType::GpuZoneBeginAllocSrcLocCallstackSerial );\n    tracy::MemWrite( &item->gpuZoneBegin.cpuTime, tracy::Profiler::GetTime() );\n    tracy::MemWrite( &item->gpuZoneBegin.thread, tracy::GetThreadHandle() );\n    tracy::MemWrite( &item->gpuZoneBegin.srcloc, data.srcloc );\n    tracy::MemWrite( &item->gpuZoneBegin.queryId, data.queryId );\n    tracy::MemWrite( &item->gpuZoneBegin.context, data.context );\n    tracy::Profiler::QueueSerialFinish();\n}\n\nTRACY_API void ___tracy_emit_gpu_time_serial( const struct ___tracy_gpu_time_data data )\n{\n    auto item = tracy::Profiler::QueueSerial();\n    tracy::MemWrite( &item->hdr.type, tracy::QueueType::GpuTime );\n    tracy::MemWrite( &item->gpuTime.gpuTime, data.gpuTime );\n    tracy::MemWrite( &item->gpuTime.queryId, data.queryId );\n    tracy::MemWrite( &item->gpuTime.context, data.context );\n    tracy::Profiler::QueueSerialFinish();\n}\n\nTRACY_API void ___tracy_emit_gpu_zone_end_serial( const struct ___tracy_gpu_zone_end_data data )\n{\n    auto item = tracy::Profiler::QueueSerial();\n    tracy::MemWrite( &item->hdr.type, tracy::QueueType::GpuZoneEndSerial );\n    tracy::MemWrite( &item->gpuZoneEnd.cpuTime, tracy::Profiler::GetTime() );\n    memset( &item->gpuZoneEnd.thread, 0, sizeof( item->gpuZoneEnd.thread ) );\n    tracy::MemWrite( &item->gpuZoneEnd.queryId, data.queryId );\n    tracy::MemWrite( &item->gpuZoneEnd.context, data.context );\n    tracy::Profiler::QueueSerialFinish();\n}\n\nTRACY_API void ___tracy_emit_gpu_new_context_serial( ___tracy_gpu_new_context_data data )\n{\n    auto item = tracy::Profiler::QueueSerial();\n    tracy::MemWrite( &item->hdr.type, tracy::QueueType::GpuNewContext );\n    tracy::MemWrite( &item->gpuNewContext.cpuTime, tracy::Profiler::GetTime() );\n    tracy::MemWrite( &item->gpuNewContext.thread, tracy::GetThreadHandle() );\n    tracy::MemWrite( &item->gpuNewContext.gpuTime, data.gpuTime );\n    tracy::MemWrite( &item->gpuNewContext.period, data.period );\n    tracy::MemWrite( &item->gpuNewContext.context, data.context );\n    tracy::MemWrite( &item->gpuNewContext.flags, data.flags );\n    tracy::MemWrite( &item->gpuNewContext.type, data.type );\n\n#ifdef TRACY_ON_DEMAND\n    tracy::GetProfiler().DeferItem( *item );\n#endif\n\n    tracy::Profiler::QueueSerialFinish();\n}\n\nTRACY_API void ___tracy_emit_gpu_context_name_serial( const struct ___tracy_gpu_context_name_data data )\n{\n    auto ptr = (char*)tracy::tracy_malloc( data.len );\n    memcpy( ptr, data.name, data.len );\n\n    auto item = tracy::Profiler::QueueSerial();\n    tracy::MemWrite( &item->hdr.type, tracy::QueueType::GpuContextName );\n    tracy::MemWrite( &item->gpuContextNameFat.context, data.context );\n    tracy::MemWrite( &item->gpuContextNameFat.ptr, (uint64_t)ptr );\n    tracy::MemWrite( &item->gpuContextNameFat.size, data.len );\n\n#ifdef TRACY_ON_DEMAND\n    tracy::GetProfiler().DeferItem( *item );\n#endif\n\n    tracy::Profiler::QueueSerialFinish();\n}\n\nTRACY_API void ___tracy_emit_gpu_calibration_serial( const struct ___tracy_gpu_calibration_data data )\n{\n    auto item = tracy::Profiler::QueueSerial();\n    tracy::MemWrite( &item->hdr.type, tracy::QueueType::GpuCalibration );\n    tracy::MemWrite( &item->gpuCalibration.cpuTime, tracy::Profiler::GetTime() );\n    tracy::MemWrite( &item->gpuCalibration.gpuTime, data.gpuTime );\n    tracy::MemWrite( &item->gpuCalibration.cpuDelta, data.cpuDelta );\n    tracy::MemWrite( &item->gpuCalibration.context, data.context );\n    tracy::Profiler::QueueSerialFinish();\n}\n\nTRACY_API void ___tracy_emit_gpu_time_sync_serial( const struct ___tracy_gpu_time_sync_data data )\n{\n    auto item = tracy::Profiler::QueueSerial();\n    tracy::MemWrite( &item->hdr.type, tracy::QueueType::GpuTimeSync );\n    tracy::MemWrite( &item->gpuTimeSync.cpuTime, tracy::Profiler::GetTime() );\n    tracy::MemWrite( &item->gpuTimeSync.gpuTime, data.gpuTime );\n    tracy::MemWrite( &item->gpuTimeSync.context, data.context );\n    tracy::Profiler::QueueSerialFinish();\n}\n\nstruct __tracy_lockable_context_data\n{\n    uint32_t m_id;\n#ifdef TRACY_ON_DEMAND\n    std::atomic<uint32_t> m_lockCount;\n    std::atomic<bool> m_active;\n#endif\n};\n\nTRACY_API struct __tracy_lockable_context_data* ___tracy_announce_lockable_ctx( const struct ___tracy_source_location_data* srcloc )\n{\n    struct __tracy_lockable_context_data *lockdata = (__tracy_lockable_context_data*)tracy::tracy_malloc( sizeof( __tracy_lockable_context_data ) );\n    lockdata->m_id =tracy:: GetLockCounter().fetch_add( 1, std::memory_order_relaxed );\n#ifdef TRACY_ON_DEMAND\n    new(&lockdata->m_lockCount) std::atomic<uint32_t>( 0 );\n    new(&lockdata->m_active) std::atomic<bool>( false );\n#endif\n    assert( lockdata->m_id != (std::numeric_limits<uint32_t>::max)() );\n\n    auto item = tracy::Profiler::QueueSerial();\n    tracy::MemWrite( &item->hdr.type, tracy::QueueType::LockAnnounce );\n    tracy::MemWrite( &item->lockAnnounce.id, lockdata->m_id );\n    tracy::MemWrite( &item->lockAnnounce.time, tracy::Profiler::GetTime() );\n    tracy::MemWrite( &item->lockAnnounce.lckloc, (uint64_t)srcloc );\n    tracy::MemWrite( &item->lockAnnounce.type, tracy::LockType::Lockable );\n#ifdef TRACY_ON_DEMAND\n    tracy::GetProfiler().DeferItem( *item );\n#endif\n    tracy::Profiler::QueueSerialFinish();\n\n    return lockdata;\n}\n\nTRACY_API void ___tracy_terminate_lockable_ctx( struct __tracy_lockable_context_data* lockdata )\n{\n    auto item = tracy::Profiler::QueueSerial();\n    tracy::MemWrite( &item->hdr.type, tracy::QueueType::LockTerminate );\n    tracy::MemWrite( &item->lockTerminate.id, lockdata->m_id );\n    tracy::MemWrite( &item->lockTerminate.time, tracy::Profiler::GetTime() );\n#ifdef TRACY_ON_DEMAND\n    tracy::GetProfiler().DeferItem( *item );\n#endif\n    tracy::Profiler::QueueSerialFinish();\n\n#ifdef TRACY_ON_DEMAND\n    lockdata->m_lockCount.~atomic();\n    lockdata->m_active.~atomic();\n#endif\n    tracy::tracy_free((void*)lockdata);\n}\n\nTRACY_API int32_t ___tracy_before_lock_lockable_ctx( struct __tracy_lockable_context_data* lockdata )\n{\n#ifdef TRACY_ON_DEMAND\n    bool queue = false;\n    const auto locks = lockdata->m_lockCount.fetch_add( 1, std::memory_order_relaxed );\n    const auto active = lockdata->m_active.load( std::memory_order_relaxed );\n    if( locks == 0 || active )\n    {\n        const bool connected = tracy::GetProfiler().IsConnected();\n        if( active != connected ) lockdata->m_active.store( connected, std::memory_order_relaxed );\n        if( connected ) queue = true;\n    }\n    if( !queue ) return static_cast<int32_t>(false);\n#endif\n\n    auto item = tracy::Profiler::QueueSerial();\n    tracy::MemWrite( &item->hdr.type, tracy::QueueType::LockWait );\n    tracy::MemWrite( &item->lockWait.thread, tracy::GetThreadHandle() );\n    tracy::MemWrite( &item->lockWait.id, lockdata->m_id );\n    tracy::MemWrite( &item->lockWait.time, tracy::Profiler::GetTime() );\n    tracy::Profiler::QueueSerialFinish();\n    return static_cast<int32_t>(true);\n}\n\nTRACY_API void ___tracy_after_lock_lockable_ctx( struct __tracy_lockable_context_data* lockdata )\n{\n    auto item = tracy::Profiler::QueueSerial();\n    tracy::MemWrite( &item->hdr.type, tracy::QueueType::LockObtain );\n    tracy::MemWrite( &item->lockObtain.thread, tracy::GetThreadHandle() );\n    tracy::MemWrite( &item->lockObtain.id, lockdata->m_id );\n    tracy::MemWrite( &item->lockObtain.time, tracy::Profiler::GetTime() );\n    tracy::Profiler::QueueSerialFinish();\n}\n\nTRACY_API void ___tracy_after_unlock_lockable_ctx( struct __tracy_lockable_context_data* lockdata )\n{\n#ifdef TRACY_ON_DEMAND\n    lockdata->m_lockCount.fetch_sub( 1, std::memory_order_relaxed );\n    if( !lockdata->m_active.load( std::memory_order_relaxed ) ) return;\n    if( !tracy::GetProfiler().IsConnected() )\n    {\n        lockdata->m_active.store( false, std::memory_order_relaxed );\n        return;\n    }\n#endif\n\n    auto item = tracy::Profiler::QueueSerial();\n    tracy::MemWrite( &item->hdr.type, tracy::QueueType::LockRelease );\n    tracy::MemWrite( &item->lockRelease.id, lockdata->m_id );\n    tracy::MemWrite( &item->lockRelease.time, tracy::Profiler::GetTime() );\n    tracy::Profiler::QueueSerialFinish();\n}\n\nTRACY_API void ___tracy_after_try_lock_lockable_ctx( struct __tracy_lockable_context_data* lockdata, int32_t acquired )\n{\n#ifdef TRACY_ON_DEMAND\n    if( !acquired ) return;\n\n    bool queue = false;\n    const auto locks = lockdata->m_lockCount.fetch_add( 1, std::memory_order_relaxed );\n    const auto active = lockdata->m_active.load( std::memory_order_relaxed );\n    if( locks == 0 || active )\n    {\n        const bool connected = tracy::GetProfiler().IsConnected();\n        if( active != connected ) lockdata->m_active.store( connected, std::memory_order_relaxed );\n        if( connected ) queue = true;\n    }\n    if( !queue ) return;\n#endif\n\n    if( acquired )\n    {\n        auto item = tracy::Profiler::QueueSerial();\n        tracy::MemWrite( &item->hdr.type, tracy::QueueType::LockObtain );\n        tracy::MemWrite( &item->lockObtain.thread, tracy::GetThreadHandle() );\n        tracy::MemWrite( &item->lockObtain.id, lockdata->m_id );\n        tracy::MemWrite( &item->lockObtain.time, tracy::Profiler::GetTime() );\n        tracy::Profiler::QueueSerialFinish();\n    }\n}\n\nTRACY_API void ___tracy_mark_lockable_ctx( struct __tracy_lockable_context_data* lockdata, const struct ___tracy_source_location_data* srcloc )\n{\n#ifdef TRACY_ON_DEMAND\n    const auto active = lockdata->m_active.load( std::memory_order_relaxed );\n    if( !active ) return;\n    const auto connected = tracy::GetProfiler().IsConnected();\n    if( !connected )\n    {\n        if( active ) lockdata->m_active.store( false, std::memory_order_relaxed );\n        return;\n    }\n#endif\n\n    auto item = tracy::Profiler::QueueSerial();\n    tracy::MemWrite( &item->hdr.type, tracy::QueueType::LockMark );\n    tracy::MemWrite( &item->lockMark.thread, tracy::GetThreadHandle() );\n    tracy::MemWrite( &item->lockMark.id, lockdata->m_id );\n    tracy::MemWrite( &item->lockMark.srcloc, (uint64_t)srcloc );\n    tracy::Profiler::QueueSerialFinish();\n}\n\nTRACY_API void ___tracy_custom_name_lockable_ctx( struct __tracy_lockable_context_data* lockdata, const char* name, size_t nameSz )\n{\n    assert( nameSz < (std::numeric_limits<uint16_t>::max)() );\n    auto ptr = (char*)tracy::tracy_malloc( nameSz );\n    memcpy( ptr, name, nameSz );\n    auto item = tracy::Profiler::QueueSerial();\n    tracy::MemWrite( &item->hdr.type, tracy::QueueType::LockName );\n    tracy::MemWrite( &item->lockNameFat.id, lockdata->m_id );\n    tracy::MemWrite( &item->lockNameFat.name, (uint64_t)ptr );\n    tracy::MemWrite( &item->lockNameFat.size, (uint16_t)nameSz );\n#ifdef TRACY_ON_DEMAND\n    tracy::GetProfiler().DeferItem( *item );\n#endif\n    tracy::Profiler::QueueSerialFinish();\n}\n\nTRACY_API int32_t ___tracy_connected( void )\n{\n    return static_cast<int32_t>( tracy::GetProfiler().IsConnected() );\n}\n\n#ifdef TRACY_FIBERS\nTRACY_API void ___tracy_fiber_enter( const char* fiber ){ tracy::Profiler::EnterFiber( fiber, 0 ); }\nTRACY_API void ___tracy_fiber_leave( void ){ tracy::Profiler::LeaveFiber(); }\n#endif\n\n#  if defined TRACY_MANUAL_LIFETIME && defined TRACY_DELAYED_INIT\nTRACY_API void ___tracy_startup_profiler( void )\n{\n    tracy::StartupProfiler();\n}\n\nTRACY_API void ___tracy_shutdown_profiler( void )\n{\n    tracy::ShutdownProfiler();\n}\n\nTRACY_API int32_t ___tracy_profiler_started( void )\n{\n    return static_cast<int32_t>( tracy::s_isProfilerStarted.load( std::memory_order_seq_cst ) );\n}\n#  endif\n\nTRACY_API int ___tracy_begin_sampling_profiling( void ) {\n    return tracy::BeginSamplingProfiling() ? 1 : 0;\n}\n\nTRACY_API void ___tracy_end_sampling_profiling( void ) {\n    tracy::EndSamplingProfiling();\n}\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "tracy-client-sys/tracy/client/TracyProfiler.hpp",
    "content": "#ifndef __TRACYPROFILER_HPP__\n#define __TRACYPROFILER_HPP__\n\n#include <assert.h>\n#include <atomic>\n#include <stdint.h>\n#include <string.h>\n#include <time.h>\n\n#include \"tracy_concurrentqueue.h\"\n#include \"tracy_SPSCQueue.h\"\n#include \"TracyCallstack.hpp\"\n#include \"TracyKCore.hpp\"\n#include \"TracySysPower.hpp\"\n#include \"TracySysTime.hpp\"\n#include \"TracyFastVector.hpp\"\n#include \"../common/TracyQueue.hpp\"\n#include \"../common/TracyAlign.hpp\"\n#include \"../common/TracyAlloc.hpp\"\n#include \"../common/TracyMutex.hpp\"\n#include \"../common/TracyProtocol.hpp\"\n\n#if defined _WIN32\n#  include <intrin.h>\n#endif\n#ifdef __APPLE__\n#  include <TargetConditionals.h>\n#  include <mach/mach_time.h>\n#endif\n\n#if ( (defined _WIN32 && !(defined _M_ARM64 || defined _M_ARM)) || ( defined __i386 || defined _M_IX86 || defined __x86_64__ || defined _M_X64 ) || ( defined TARGET_OS_IOS && TARGET_OS_IOS == 1 ) )\n#  define TRACY_HW_TIMER\n#endif\n\n#ifdef __linux__\n#  include <signal.h>\n#endif\n\n#if defined TRACY_TIMER_FALLBACK || !defined TRACY_HW_TIMER\n#  include <chrono>\n#endif\n\n#ifndef TracyConcat\n#  define TracyConcat(x,y) TracyConcatIndirect(x,y)\n#endif\n#ifndef TracyConcatIndirect\n#  define TracyConcatIndirect(x,y) x##y\n#endif\n\nnamespace tracy\n{\n#if defined(TRACY_DELAYED_INIT) && defined(TRACY_MANUAL_LIFETIME)\nTRACY_API void StartupProfiler();\nTRACY_API void ShutdownProfiler();\nTRACY_API bool IsProfilerStarted();\n#  define TracyIsStarted tracy::IsProfilerStarted()\n#else\n#  define TracyIsStarted true\n#endif\n\nTRACY_API bool BeginSamplingProfiling();\nTRACY_API void EndSamplingProfiling();\n\nclass GpuCtx;\nclass Profiler;\nclass Socket;\nclass UdpBroadcast;\n\nstruct GpuCtxWrapper\n{\n    GpuCtx* ptr;\n};\n\nTRACY_API moodycamel::ConcurrentQueue<QueueItem>::ExplicitProducer* GetToken();\nTRACY_API Profiler& GetProfiler();\nTRACY_API std::atomic<uint32_t>& GetLockCounter();\nTRACY_API std::atomic<uint8_t>& GetGpuCtxCounter();\nTRACY_API GpuCtxWrapper& GetGpuCtx();\nTRACY_API uint32_t GetThreadHandle();\nTRACY_API bool ProfilerAvailable();\nTRACY_API bool ProfilerAllocatorAvailable();\nTRACY_API int64_t GetFrequencyQpc();\n\n#if defined TRACY_TIMER_FALLBACK && defined TRACY_HW_TIMER && ( defined __i386 || defined _M_IX86 || defined __x86_64__ || defined _M_X64 )\nTRACY_API bool HardwareSupportsInvariantTSC();  // check, if we need fallback scenario\n#else\n#  if defined TRACY_HW_TIMER\ntracy_force_inline bool HardwareSupportsInvariantTSC()\n{\n    return true;  // this is checked at startup\n}\n#  else\ntracy_force_inline bool HardwareSupportsInvariantTSC()\n{\n    return false;\n}\n#  endif\n#endif\n\n\nstruct SourceLocationData\n{\n    const char* name;\n    const char* function;\n    const char* file;\n    uint32_t line;\n    uint32_t color;\n};\n\n#ifdef TRACY_ON_DEMAND\nstruct LuaZoneState\n{\n    uint32_t counter;\n    bool active;\n};\n#endif\n\n\n#define TracyLfqPrepare( _type ) \\\n    tracy::moodycamel::ConcurrentQueueDefaultTraits::index_t __magic; \\\n    auto __token = tracy::GetToken(); \\\n    auto& __tail = __token->get_tail_index(); \\\n    auto item = __token->enqueue_begin( __magic ); \\\n    tracy::MemWrite( &item->hdr.type, _type );\n\n#define TracyLfqCommit \\\n    __tail.store( __magic + 1, std::memory_order_release );\n\n#define TracyLfqPrepareC( _type ) \\\n    tracy::moodycamel::ConcurrentQueueDefaultTraits::index_t __magic; \\\n    auto __token = tracy::GetToken(); \\\n    auto& __tail = __token->get_tail_index(); \\\n    auto item = __token->enqueue_begin( __magic ); \\\n    tracy::MemWrite( &item->hdr.type, _type );\n\n#define TracyLfqCommitC \\\n    __tail.store( __magic + 1, std::memory_order_release );\n\n\n#ifdef TRACY_FIBERS\n#  define TracyQueuePrepare( _type ) \\\n    auto item = tracy::Profiler::QueueSerial(); \\\n    tracy::MemWrite( &item->hdr.type, _type );\n#  define TracyQueueCommit( _name ) \\\n    tracy::MemWrite( &item->_name.thread, tracy::GetThreadHandle() ); \\\n    tracy::Profiler::QueueSerialFinish();\n#  define TracyQueuePrepareC( _type ) \\\n    auto item = tracy::Profiler::QueueSerial(); \\\n    tracy::MemWrite( &item->hdr.type, _type );\n#  define TracyQueueCommitC( _name ) \\\n    tracy::MemWrite( &item->_name.thread, tracy::GetThreadHandle() ); \\\n    tracy::Profiler::QueueSerialFinish();\n#else\n#  define TracyQueuePrepare( _type ) TracyLfqPrepare( _type )\n#  define TracyQueueCommit( _name ) TracyLfqCommit\n#  define TracyQueuePrepareC( _type ) TracyLfqPrepareC( _type )\n#  define TracyQueueCommitC( _name ) TracyLfqCommitC\n#endif\n\n\ntypedef void(*ParameterCallback)( void* data, uint32_t idx, int32_t val );\ntypedef char*(*SourceContentsCallback)( void* data, const char* filename, size_t& size );\n\nclass Profiler\n{\n    struct FrameImageQueueItem\n    {\n        void* image;\n        uint32_t frame;\n        uint16_t w;\n        uint16_t h;\n        bool flip;\n    };\n\n    enum class SymbolQueueItemType\n    {\n        CallstackFrame,\n        SymbolQuery,\n        ExternalName,\n        KernelCode,\n        SourceCode\n    };\n\n    struct SymbolQueueItem\n    {\n        SymbolQueueItemType type;\n        uint64_t ptr;\n        uint64_t extra;\n        uint32_t id;\n    };\n\npublic:\n    Profiler();\n    ~Profiler();\n\n    void SpawnWorkerThreads();\n\n    static tracy_force_inline int64_t GetTime()\n    {\n#ifdef TRACY_HW_TIMER\n#  if defined TARGET_OS_IOS && TARGET_OS_IOS == 1\n        if( HardwareSupportsInvariantTSC() ) return mach_absolute_time();\n#  elif defined _WIN32\n#    ifdef TRACY_TIMER_QPC\n        return GetTimeQpc();\n#    else\n        if( HardwareSupportsInvariantTSC() ) return int64_t( __rdtsc() );\n#    endif\n#  elif defined __i386 || defined _M_IX86\n        if( HardwareSupportsInvariantTSC() )\n        {\n            uint32_t eax, edx;\n            asm volatile ( \"rdtsc\" : \"=a\" (eax), \"=d\" (edx) );\n            return ( uint64_t( edx ) << 32 ) + uint64_t( eax );\n        }\n#  elif defined __x86_64__ || defined _M_X64\n        if( HardwareSupportsInvariantTSC() )\n        {\n            uint64_t rax, rdx;\n#ifdef TRACY_PATCHABLE_NOPSLEDS\n            // Some external tooling (such as rr) wants to patch our rdtsc and replace it by a\n            // branch to control the external input seen by a program. This kind of patching is\n            // not generally possible depending on the surrounding code and can lead to significant\n            // slowdowns if the compiler generated unlucky code and rr and tracy are used together.\n            // To avoid this, use the rr-safe `nopl 0(%rax, %rax, 1); rdtsc` instruction sequence,\n            // which rr promises will be patchable independent of the surrounding code.\n            asm volatile (\n                    // This is nopl 0(%rax, %rax, 1), but assemblers are inconsistent about whether\n                    // they emit that as a 4 or 5 byte sequence and we need to be guaranteed to use\n                    // the 5 byte one.\n                    \".byte 0x0f, 0x1f, 0x44, 0x00, 0x00\\n\\t\"\n                    \"rdtsc\" : \"=a\" (rax), \"=d\" (rdx) );\n#else\n            asm volatile ( \"rdtsc\" : \"=a\" (rax), \"=d\" (rdx) );\n#endif\n            return (int64_t)(( rdx << 32 ) + rax);\n        }\n#  else\n#    error \"TRACY_HW_TIMER detection logic needs fixing\"\n#  endif\n#endif\n\n#if !defined TRACY_HW_TIMER || defined TRACY_TIMER_FALLBACK\n#  if defined __linux__ && defined CLOCK_MONOTONIC_RAW\n        struct timespec ts;\n        clock_gettime( CLOCK_MONOTONIC_RAW, &ts );\n        return int64_t( ts.tv_sec ) * 1000000000ll + int64_t( ts.tv_nsec );\n#  else\n        return std::chrono::duration_cast<std::chrono::nanoseconds>( std::chrono::high_resolution_clock::now().time_since_epoch() ).count();\n#  endif\n#endif\n\n#if !defined TRACY_TIMER_FALLBACK\n        return 0;  // unreachable branch\n#endif\n    }\n\n    bool BeginSamplingProfiling();\n    void EndSamplingProfiling();\n\n    tracy_force_inline uint32_t GetNextZoneId()\n    {\n        return m_zoneId.fetch_add( 1, std::memory_order_relaxed );\n    }\n\n    static tracy_force_inline QueueItem* QueueSerial()\n    {\n        auto& p = GetProfiler();\n        p.m_serialLock.lock();\n        return p.m_serialQueue.prepare_next();\n    }\n\n    static tracy_force_inline QueueItem* QueueSerialCallstack( void* ptr )\n    {\n        auto& p = GetProfiler();\n        p.m_serialLock.lock();\n        p.SendCallstackSerial( ptr );\n        return p.m_serialQueue.prepare_next();\n    }\n\n    static tracy_force_inline void QueueSerialFinish()\n    {\n        auto& p = GetProfiler();\n        p.m_serialQueue.commit_next();\n        p.m_serialLock.unlock();\n    }\n\n    static tracy_force_inline void SendFrameMark( const char* name )\n    {\n        if( !name ) GetProfiler().m_frameCount.fetch_add( 1, std::memory_order_relaxed );\n#ifdef TRACY_ON_DEMAND\n        if( !GetProfiler().IsConnected() ) return;\n#endif\n        auto item = QueueSerial();\n        MemWrite( &item->hdr.type, QueueType::FrameMarkMsg );\n        MemWrite( &item->frameMark.time, GetTime() );\n        MemWrite( &item->frameMark.name, uint64_t( name ) );\n        QueueSerialFinish();\n    }\n\n    static tracy_force_inline void SendFrameMark( const char* name, QueueType type )\n    {\n        assert( type == QueueType::FrameMarkMsgStart || type == QueueType::FrameMarkMsgEnd );\n#ifdef TRACY_ON_DEMAND\n        if( !GetProfiler().IsConnected() ) return;\n#endif\n        auto item = QueueSerial();\n        MemWrite( &item->hdr.type, type );\n        MemWrite( &item->frameMark.time, GetTime() );\n        MemWrite( &item->frameMark.name, uint64_t( name ) );\n        QueueSerialFinish();\n    }\n\n    static tracy_force_inline void SendFrameImage( const void* image, uint16_t w, uint16_t h, uint8_t offset, bool flip )\n    {\n#ifndef TRACY_NO_FRAME_IMAGE\n        auto& profiler = GetProfiler();\n        assert( profiler.m_frameCount.load( std::memory_order_relaxed ) < (std::numeric_limits<uint32_t>::max)() );\n#  ifdef TRACY_ON_DEMAND\n        if( !profiler.IsConnected() ) return;\n#  endif\n        const auto sz = size_t( w ) * size_t( h ) * 4;\n        auto ptr = (char*)tracy_malloc( sz );\n        memcpy( ptr, image, sz );\n\n        profiler.m_fiLock.lock();\n        auto fi = profiler.m_fiQueue.prepare_next();\n        fi->image = ptr;\n        fi->frame = uint32_t( profiler.m_frameCount.load( std::memory_order_relaxed ) - offset );\n        fi->w = w;\n        fi->h = h;\n        fi->flip = flip;\n        profiler.m_fiQueue.commit_next();\n        profiler.m_fiLock.unlock();\n#else\n        static_cast<void>(image); // unused\n        static_cast<void>(w); // unused\n        static_cast<void>(h); // unused\n        static_cast<void>(offset); // unused\n        static_cast<void>(flip); // unused\n#endif\n    }\n\n    static tracy_force_inline void PlotData( const char* name, int64_t val )\n    {\n#ifdef TRACY_ON_DEMAND\n        if( !GetProfiler().IsConnected() ) return;\n#endif\n        TracyLfqPrepare( QueueType::PlotDataInt );\n        MemWrite( &item->plotDataInt.name, (uint64_t)name );\n        MemWrite( &item->plotDataInt.time, GetTime() );\n        MemWrite( &item->plotDataInt.val, val );\n        TracyLfqCommit;\n    }\n\n    static tracy_force_inline void PlotData( const char* name, float val )\n    {\n#ifdef TRACY_ON_DEMAND\n        if( !GetProfiler().IsConnected() ) return;\n#endif\n        TracyLfqPrepare( QueueType::PlotDataFloat );\n        MemWrite( &item->plotDataFloat.name, (uint64_t)name );\n        MemWrite( &item->plotDataFloat.time, GetTime() );\n        MemWrite( &item->plotDataFloat.val, val );\n        TracyLfqCommit;\n    }\n\n    static tracy_force_inline void PlotData( const char* name, double val )\n    {\n#ifdef TRACY_ON_DEMAND\n        if( !GetProfiler().IsConnected() ) return;\n#endif\n        TracyLfqPrepare( QueueType::PlotDataDouble );\n        MemWrite( &item->plotDataDouble.name, (uint64_t)name );\n        MemWrite( &item->plotDataDouble.time, GetTime() );\n        MemWrite( &item->plotDataDouble.val, val );\n        TracyLfqCommit;\n    }\n\n    static tracy_force_inline void ConfigurePlot( const char* name, PlotFormatType type, bool step, bool fill, uint32_t color )\n    {\n        TracyLfqPrepare( QueueType::PlotConfig );\n        MemWrite( &item->plotConfig.name, (uint64_t)name );\n        MemWrite( &item->plotConfig.type, (uint8_t)type );\n        MemWrite( &item->plotConfig.step, (uint8_t)step );\n        MemWrite( &item->plotConfig.fill, (uint8_t)fill );\n        MemWrite( &item->plotConfig.color, color );\n\n#ifdef TRACY_ON_DEMAND\n        GetProfiler().DeferItem( *item );\n#endif\n\n        TracyLfqCommit;\n    }\n\n    static tracy_force_inline void Message( const char* txt, size_t size, int32_t callstack_depth )\n    {\n        assert( size < (std::numeric_limits<uint16_t>::max)() );\n#ifdef TRACY_ON_DEMAND\n        if( !GetProfiler().IsConnected() ) return;\n#endif\n        if( callstack_depth != 0 && has_callstack() )\n        {\n            tracy::GetProfiler().SendCallstack( callstack_depth );\n        }\n\n        auto ptr = (char*)tracy_malloc( size );\n        memcpy( ptr, txt, size );\n\n        TracyQueuePrepare( callstack_depth == 0 ? QueueType::Message : QueueType::MessageCallstack );\n        MemWrite( &item->messageFat.time, GetTime() );\n        MemWrite( &item->messageFat.text, (uint64_t)ptr );\n        MemWrite( &item->messageFat.size, (uint16_t)size );\n        TracyQueueCommit( messageFatThread );\n    }\n\n    static tracy_force_inline void Message( const char* txt, int32_t callstack_depth )\n    {\n#ifdef TRACY_ON_DEMAND\n        if( !GetProfiler().IsConnected() ) return;\n#endif\n        if( callstack_depth != 0 && has_callstack() )\n        {\n            tracy::GetProfiler().SendCallstack( callstack_depth );\n        }\n\n        TracyQueuePrepare( callstack_depth == 0 ? QueueType::MessageLiteral : QueueType::MessageLiteralCallstack );\n        MemWrite( &item->messageLiteral.time, GetTime() );\n        MemWrite( &item->messageLiteral.text, (uint64_t)txt );\n        TracyQueueCommit( messageLiteralThread );\n    }\n\n    static tracy_force_inline void MessageColor( const char* txt, size_t size, uint32_t color, int32_t callstack_depth )\n    {\n        assert( size < (std::numeric_limits<uint16_t>::max)() );\n#ifdef TRACY_ON_DEMAND\n        if( !GetProfiler().IsConnected() ) return;\n#endif\n        if( callstack_depth != 0 && has_callstack() )\n        {\n            tracy::GetProfiler().SendCallstack( callstack_depth );\n        }\n\n        auto ptr = (char*)tracy_malloc( size );\n        memcpy( ptr, txt, size );\n\n        TracyQueuePrepare( callstack_depth == 0 ? QueueType::MessageColor : QueueType::MessageColorCallstack );\n        MemWrite( &item->messageColorFat.time, GetTime() );\n        MemWrite( &item->messageColorFat.text, (uint64_t)ptr );\n        MemWrite( &item->messageColorFat.b, uint8_t( ( color       ) & 0xFF ) );\n        MemWrite( &item->messageColorFat.g, uint8_t( ( color >> 8  ) & 0xFF ) );\n        MemWrite( &item->messageColorFat.r, uint8_t( ( color >> 16 ) & 0xFF ) );\n        MemWrite( &item->messageColorFat.size, (uint16_t)size );\n        TracyQueueCommit( messageColorFatThread );\n    }\n\n    static tracy_force_inline void MessageColor( const char* txt, uint32_t color, int32_t callstack_depth )\n    {\n#ifdef TRACY_ON_DEMAND\n        if( !GetProfiler().IsConnected() ) return;\n#endif\n        if( callstack_depth != 0 && has_callstack() )\n        {\n            tracy::GetProfiler().SendCallstack( callstack_depth );\n        }\n\n        TracyQueuePrepare( callstack_depth == 0 ? QueueType::MessageLiteralColor : QueueType::MessageLiteralColorCallstack );\n        MemWrite( &item->messageColorLiteral.time, GetTime() );\n        MemWrite( &item->messageColorLiteral.text, (uint64_t)txt );\n        MemWrite( &item->messageColorLiteral.b, uint8_t( ( color       ) & 0xFF ) );\n        MemWrite( &item->messageColorLiteral.g, uint8_t( ( color >> 8  ) & 0xFF ) );\n        MemWrite( &item->messageColorLiteral.r, uint8_t( ( color >> 16 ) & 0xFF ) );\n        TracyQueueCommit( messageColorLiteralThread );\n    }\n\n    static tracy_force_inline void MessageAppInfo( const char* txt, size_t size )\n    {\n        assert( size < (std::numeric_limits<uint16_t>::max)() );\n        auto ptr = (char*)tracy_malloc( size );\n        memcpy( ptr, txt, size );\n        TracyLfqPrepare( QueueType::MessageAppInfo );\n        MemWrite( &item->messageFat.time, GetTime() );\n        MemWrite( &item->messageFat.text, (uint64_t)ptr );\n        MemWrite( &item->messageFat.size, (uint16_t)size );\n\n#ifdef TRACY_ON_DEMAND\n        GetProfiler().DeferItem( *item );\n#endif\n\n        TracyLfqCommit;\n    }\n\n    static tracy_force_inline void MemAlloc( const void* ptr, size_t size, bool secure )\n    {\n        if( secure && !ProfilerAvailable() ) return;\n#ifdef TRACY_ON_DEMAND\n        if( !GetProfiler().IsConnected() ) return;\n#endif\n        const auto thread = GetThreadHandle();\n\n        GetProfiler().m_serialLock.lock();\n        SendMemAlloc( QueueType::MemAlloc, thread, ptr, size );\n        GetProfiler().m_serialLock.unlock();\n    }\n\n    static tracy_force_inline void MemFree( const void* ptr, bool secure )\n    {\n        if( secure && !ProfilerAvailable() ) return;\n#ifdef TRACY_ON_DEMAND\n        if( !GetProfiler().IsConnected() ) return;\n#endif\n        const auto thread = GetThreadHandle();\n\n        GetProfiler().m_serialLock.lock();\n        SendMemFree( QueueType::MemFree, thread, ptr );\n        GetProfiler().m_serialLock.unlock();\n    }\n\n    static tracy_force_inline void MemAllocCallstack( const void* ptr, size_t size, int32_t depth, bool secure )\n    {\n        if( secure && !ProfilerAvailable() ) return;\n        if( depth > 0 && has_callstack() )\n        {\n            auto& profiler = GetProfiler();\n#  ifdef TRACY_ON_DEMAND\n            if( !profiler.IsConnected() ) return;\n#  endif\n            const auto thread = GetThreadHandle();\n\n            auto callstack = Callstack( depth );\n\n            profiler.m_serialLock.lock();\n            SendCallstackSerial( callstack );\n            SendMemAlloc( QueueType::MemAllocCallstack, thread, ptr, size );\n            profiler.m_serialLock.unlock();\n        }\n        else\n        {\n            MemAlloc( ptr, size, secure );\n        }\n    }\n\n    static tracy_force_inline void MemFreeCallstack( const void* ptr, int32_t depth, bool secure )\n    {\n        if( secure && !ProfilerAvailable() ) return;\n        if( !ProfilerAllocatorAvailable() )\n        {\n            MemFree( ptr, secure );\n            return;\n        }\n        if( depth > 0 && has_callstack() )\n        {\n            auto& profiler = GetProfiler();\n#  ifdef TRACY_ON_DEMAND\n            if( !profiler.IsConnected() ) return;\n#  endif\n            const auto thread = GetThreadHandle();\n\n            auto callstack = Callstack( depth );\n\n            profiler.m_serialLock.lock();\n            SendCallstackSerial( callstack );\n            SendMemFree( QueueType::MemFreeCallstack, thread, ptr );\n            profiler.m_serialLock.unlock();\n        }\n        else\n        {\n            MemFree( ptr, secure );\n        }\n    }\n\n    static tracy_force_inline void MemAllocNamed( const void* ptr, size_t size, bool secure, const char* name )\n    {\n        if( secure && !ProfilerAvailable() ) return;\n#ifdef TRACY_ON_DEMAND\n        if( !GetProfiler().IsConnected() ) return;\n#endif\n        const auto thread = GetThreadHandle();\n\n        GetProfiler().m_serialLock.lock();\n        SendMemName( name );\n        SendMemAlloc( QueueType::MemAllocNamed, thread, ptr, size );\n        GetProfiler().m_serialLock.unlock();\n    }\n\n    static tracy_force_inline void MemFreeNamed( const void* ptr, bool secure, const char* name )\n    {\n        if( secure && !ProfilerAvailable() ) return;\n#ifdef TRACY_ON_DEMAND\n        if( !GetProfiler().IsConnected() ) return;\n#endif\n        const auto thread = GetThreadHandle();\n\n        GetProfiler().m_serialLock.lock();\n        SendMemName( name );\n        SendMemFree( QueueType::MemFreeNamed, thread, ptr );\n        GetProfiler().m_serialLock.unlock();\n    }\n\n    static tracy_force_inline void MemAllocCallstackNamed( const void* ptr, size_t size, int32_t depth, bool secure, const char* name )\n    {\n        if( secure && !ProfilerAvailable() ) return;\n        if( depth > 0 && has_callstack() )\n        {\n            auto& profiler = GetProfiler();\n#  ifdef TRACY_ON_DEMAND\n            if( !profiler.IsConnected() ) return;\n#  endif\n            const auto thread = GetThreadHandle();\n\n            auto callstack = Callstack( depth );\n\n            profiler.m_serialLock.lock();\n            SendCallstackSerial( callstack );\n            SendMemName( name );\n            SendMemAlloc( QueueType::MemAllocCallstackNamed, thread, ptr, size );\n            profiler.m_serialLock.unlock();\n        }\n        else\n        {\n            MemAllocNamed( ptr, size, secure, name );\n        }\n    }\n\n    static tracy_force_inline void MemFreeCallstackNamed( const void* ptr, int32_t depth, bool secure, const char* name )\n    {\n        if( secure && !ProfilerAvailable() ) return;\n        if( depth > 0 && has_callstack() )\n        {\n            auto& profiler = GetProfiler();\n#  ifdef TRACY_ON_DEMAND\n            if( !profiler.IsConnected() ) return;\n#  endif\n            const auto thread = GetThreadHandle();\n\n            auto callstack = Callstack( depth );\n\n            profiler.m_serialLock.lock();\n            SendCallstackSerial( callstack );\n            SendMemName( name );\n            SendMemFree( QueueType::MemFreeCallstackNamed, thread, ptr );\n            profiler.m_serialLock.unlock();\n        }\n        else\n        {\n            MemFreeNamed( ptr, secure, name );\n        }\n    }\n\n    static tracy_force_inline void MemDiscard( const char* name, bool secure )\n    {\n        if( secure && !ProfilerAvailable() ) return;\n#ifdef TRACY_ON_DEMAND\n        if( !GetProfiler().IsConnected() ) return;\n#endif\n        const auto thread = GetThreadHandle();\n\n        GetProfiler().m_serialLock.lock();\n        SendMemDiscard( QueueType::MemDiscard, thread, name );\n        GetProfiler().m_serialLock.unlock();\n    }\n\n    static tracy_force_inline void MemDiscardCallstack( const char* name, bool secure, int32_t depth )\n    {\n        if( secure && !ProfilerAvailable() ) return;\n        if( depth > 0 && has_callstack() )\n        {\n#  ifdef TRACY_ON_DEMAND\n            if( !GetProfiler().IsConnected() ) return;\n#  endif\n            const auto thread = GetThreadHandle();\n\n            auto callstack = Callstack( depth );\n\n            GetProfiler().m_serialLock.lock();\n            SendCallstackSerial( callstack );\n            SendMemDiscard( QueueType::MemDiscard, thread, name );\n            GetProfiler().m_serialLock.unlock();\n        }\n        else\n        {\n            MemDiscard( name, secure );\n        }\n    }\n\n    static tracy_force_inline void SendCallstack( int32_t depth )\n    {\n        if( depth > 0 && has_callstack() )\n        {\n            auto ptr = Callstack( depth );\n            TracyQueuePrepare( QueueType::Callstack );\n            MemWrite( &item->callstackFat.ptr, (uint64_t)ptr );\n            TracyQueueCommit( callstackFatThread );\n        }\n    }\n\n    static tracy_force_inline void ParameterRegister( ParameterCallback cb, void* data )\n    {\n        auto& profiler = GetProfiler();\n        profiler.m_paramCallback = cb;\n        profiler.m_paramCallbackData = data;\n    }\n\n    static tracy_force_inline void ParameterSetup( uint32_t idx, const char* name, bool isBool, int32_t val )\n    {\n        TracyLfqPrepare( QueueType::ParamSetup );\n        tracy::MemWrite( &item->paramSetup.idx, idx );\n        tracy::MemWrite( &item->paramSetup.name, (uint64_t)name );\n        tracy::MemWrite( &item->paramSetup.isBool, (uint8_t)isBool );\n        tracy::MemWrite( &item->paramSetup.val, val );\n\n#ifdef TRACY_ON_DEMAND\n        GetProfiler().DeferItem( *item );\n#endif\n\n        TracyLfqCommit;\n    }\n\n    static tracy_force_inline void SourceCallbackRegister( SourceContentsCallback cb, void* data )\n    {\n        auto& profiler = GetProfiler();\n        profiler.m_sourceCallback = cb;\n        profiler.m_sourceCallbackData = data;\n    }\n\n#ifdef TRACY_FIBERS\n    static tracy_force_inline void EnterFiber( const char* fiber, int32_t groupHint )\n    {\n#ifdef TRACY_ON_DEMAND\n        if( !GetProfiler().IsConnected() ) return;\n#endif\n        TracyQueuePrepare( QueueType::FiberEnter );\n        MemWrite( &item->fiberEnter.time, GetTime() );\n        MemWrite( &item->fiberEnter.fiber, (uint64_t)fiber );\n        MemWrite( &item->fiberEnter.groupHint, groupHint );\n        TracyQueueCommit( fiberEnter );\n    }\n\n    static tracy_force_inline void LeaveFiber()\n    {\n#ifdef TRACY_ON_DEMAND\n        if( !GetProfiler().IsConnected() ) return;\n#endif\n        TracyQueuePrepare( QueueType::FiberLeave );\n        MemWrite( &item->fiberLeave.time, GetTime() );\n        TracyQueueCommit( fiberLeave );\n    }\n#endif\n\n    void SendCallstack( int32_t depth, const char* skipBefore );\n    static void CutCallstack( void* callstack, const char* skipBefore );\n\n    static bool ShouldExit();\n\n    tracy_force_inline bool IsConnected() const\n    {\n        return m_isConnected.load( std::memory_order_acquire );\n    }\n\n    tracy_force_inline void SetProgramName( const char* name )\n    {\n        m_programNameLock.lock();\n        m_programName = name;\n        m_programNameLock.unlock();\n    }\n\n#ifdef TRACY_ON_DEMAND\n    tracy_force_inline uint64_t ConnectionId() const\n    {\n        return m_connectionId.load( std::memory_order_acquire );\n    }\n\n    tracy_force_inline void DeferItem( const QueueItem& item )\n    {\n        m_deferredLock.lock();\n        auto dst = m_deferredQueue.push_next();\n        memcpy( dst, &item, sizeof( item ) );\n        m_deferredLock.unlock();\n    }\n#endif\n\n    void RequestShutdown() { m_shutdown.store( true, std::memory_order_relaxed ); m_shutdownManual.store( true, std::memory_order_relaxed ); }\n    bool HasShutdownFinished() const { return m_shutdownFinished.load( std::memory_order_relaxed ); }\n\n    void SendString( uint64_t str, const char* ptr, QueueType type ) { SendString( str, ptr, strlen( ptr ), type ); }\n    void SendString( uint64_t str, const char* ptr, size_t len, QueueType type );\n    void SendSingleString( const char* ptr ) { SendSingleString( ptr, strlen( ptr ) ); }\n    void SendSingleString( const char* ptr, size_t len );\n    void SendSecondString( const char* ptr ) { SendSecondString( ptr, strlen( ptr ) ); }\n    void SendSecondString( const char* ptr, size_t len );\n\n\n    // Allocated source location data layout:\n    //  2b  payload size\n    //  4b  color\n    //  4b  source line\n    //  fsz function name\n    //  1b  null terminator\n    //  ssz source file name\n    //  1b  null terminator\n    //  nsz zone name (optional)\n\n    static tracy_force_inline uint64_t AllocSourceLocation( uint32_t line, const char* source, const char* function, uint32_t color = 0 )\n    {\n        return AllocSourceLocation( line, source, function, nullptr, 0, color );\n    }\n\n    static tracy_force_inline uint64_t AllocSourceLocation( uint32_t line, const char* source, const char* function, const char* name, size_t nameSz, uint32_t color = 0 )\n    {\n        return AllocSourceLocation( line, source, strlen(source), function, strlen(function), name, nameSz, color );\n    }\n\n    static tracy_force_inline uint64_t AllocSourceLocation( uint32_t line, const char* source, size_t sourceSz, const char* function, size_t functionSz, uint32_t color = 0 )\n    {\n        return AllocSourceLocation( line, source, sourceSz, function, functionSz, nullptr, 0, color );\n    }\n\n    static tracy_force_inline uint64_t AllocSourceLocation( uint32_t line, const char* source, size_t sourceSz, const char* function, size_t functionSz, const char* name, size_t nameSz, uint32_t color = 0 )\n    {\n        const auto sz32 = uint32_t( 2 + 4 + 4 + functionSz + 1 + sourceSz + 1 + nameSz );\n        assert( sz32 <= (std::numeric_limits<uint16_t>::max)() );\n        const auto sz = uint16_t( sz32 );\n        auto ptr = (char*)tracy_malloc( sz );\n        memcpy( ptr, &sz, 2 );\n        memcpy( ptr + 2, &color, 4 );\n        memcpy( ptr + 6, &line, 4 );\n        memcpy( ptr + 10, function, functionSz );\n        ptr[10 + functionSz] = '\\0';\n        memcpy( ptr + 10 + functionSz + 1, source, sourceSz );\n        ptr[10 + functionSz + 1 + sourceSz] = '\\0';\n        if( nameSz != 0 )\n        {\n            memcpy( ptr + 10 + functionSz + 1 + sourceSz + 1, name, nameSz );\n        }\n        return uint64_t( ptr );\n    }\n\nprivate:\n    enum class DequeueStatus { DataDequeued, ConnectionLost, QueueEmpty };\n    enum class ThreadCtxStatus { Same, Changed, ConnectionLost };\n\n    static void LaunchWorker( void* ptr ) { ((Profiler*)ptr)->Worker(); }\n    void Worker();\n\n#ifndef TRACY_NO_FRAME_IMAGE\n    static void LaunchCompressWorker( void* ptr ) { ((Profiler*)ptr)->CompressWorker(); }\n    void CompressWorker();\n#endif\n\n#ifdef TRACY_HAS_CALLSTACK\n    static void LaunchSymbolWorker( void* ptr ) { ((Profiler*)ptr)->SymbolWorker(); }\n    void SymbolWorker();\n    void HandleSymbolQueueItem( const SymbolQueueItem& si );\n#endif\n\n    void InstallCrashHandler();\n    void RemoveCrashHandler();\n\n    void ClearQueues( tracy::moodycamel::ConsumerToken& token );\n    void ClearSerial();\n    DequeueStatus Dequeue( tracy::moodycamel::ConsumerToken& token );\n    DequeueStatus DequeueContextSwitches( tracy::moodycamel::ConsumerToken& token, int64_t& timeStop );\n    DequeueStatus DequeueSerial();\n    ThreadCtxStatus ThreadCtxCheck( uint32_t threadId );\n    bool CommitData();\n\n    tracy_force_inline bool AppendData( const void* data, size_t len )\n    {\n        const auto ret = NeedDataSize( len );\n        AppendDataUnsafe( data, len );\n        return ret;\n    }\n\n    tracy_force_inline bool NeedDataSize( size_t len )\n    {\n        assert( len <= TargetFrameSize );\n        bool ret = true;\n        if( m_bufferOffset - m_bufferStart + (int)len > TargetFrameSize )\n        {\n            ret = CommitData();\n        }\n        return ret;\n    }\n\n    tracy_force_inline void AppendDataUnsafe( const void* data, size_t len )\n    {\n        memcpy( m_buffer + m_bufferOffset, data, len );\n        m_bufferOffset += int( len );\n    }\n\n    char* SafeCopyProlog( const char* p, size_t size );\n    void SafeCopyEpilog( char* buf );\n\n    template<class Callable> // must be void( const char* buf, size_t size )\n    bool WithSafeCopy( const char* p, size_t size, Callable&& callable )\n    {\n        if( char* buf = SafeCopyProlog( p, size ) )\n        {\n            callable( buf, size );\n            SafeCopyEpilog( buf );\n            return true;\n        }\n        return false;\n    }\n\n    bool SendData( const char* data, size_t len );\n    void SendLongString( uint64_t ptr, const char* str, size_t len, QueueType type );\n    void SendSourceLocation( uint64_t ptr );\n    void SendSourceLocationPayload( uint64_t ptr );\n    void SendCallstackPayload( uint64_t ptr );\n    void SendCallstackPayload64( uint64_t ptr );\n    void SendCallstackAlloc( uint64_t ptr );\n\n    void QueueCallstackFrame( uint64_t ptr );\n    void QueueSymbolQuery( uint64_t symbol );\n    void QueueExternalName( uint64_t ptr );\n    void QueueKernelCode( uint64_t symbol, uint32_t size );\n    void QueueSourceCodeQuery( uint32_t id );\n\n    bool HandleServerQuery();\n    void HandleDisconnect();\n    void HandleParameter( uint64_t payload );\n    void HandleSymbolCodeQuery( uint64_t symbol, uint32_t size );\n    void HandleSourceCodeQuery( char* data, char* image, uint32_t id );\n\n    void AckServerQuery();\n    void AckSymbolCodeNotAvailable();\n\n    void CalibrateTimer();\n    void CalibrateDelay();\n    void ReportTopology();\n\n    static tracy_force_inline void SendCallstackSerial( void* ptr )\n    {\n        if( has_callstack() )\n        {\n            auto item = GetProfiler().m_serialQueue.prepare_next();\n            MemWrite( &item->hdr.type, QueueType::CallstackSerial );\n            MemWrite( &item->callstackFat.ptr, (uint64_t)ptr );\n            GetProfiler().m_serialQueue.commit_next();\n        }\n    }\n\n    static tracy_force_inline void SendMemAlloc( QueueType type, const uint32_t thread, const void* ptr, size_t size )\n    {\n        assert( type == QueueType::MemAlloc || type == QueueType::MemAllocCallstack || type == QueueType::MemAllocNamed || type == QueueType::MemAllocCallstackNamed );\n\n        auto item = GetProfiler().m_serialQueue.prepare_next();\n        MemWrite( &item->hdr.type, type );\n        MemWrite( &item->memAlloc.time, GetTime() );\n        MemWrite( &item->memAlloc.thread, thread );\n        MemWrite( &item->memAlloc.ptr, (uint64_t)ptr );\n        if( compile_time_condition<sizeof( size ) == 4>::value )\n        {\n            memcpy( &item->memAlloc.size, &size, 4 );\n            memset( &item->memAlloc.size + 4, 0, 2 );\n        }\n        else\n        {\n            assert( sizeof( size ) == 8 );\n            memcpy( &item->memAlloc.size, &size, 4 );\n            memcpy( ((char*)&item->memAlloc.size)+4, ((char*)&size)+4, 2 );\n        }\n        GetProfiler().m_serialQueue.commit_next();\n    }\n\n    static tracy_force_inline void SendMemFree( QueueType type, const uint32_t thread, const void* ptr )\n    {\n        assert( type == QueueType::MemFree || type == QueueType::MemFreeCallstack || type == QueueType::MemFreeNamed || type == QueueType::MemFreeCallstackNamed );\n\n        auto item = GetProfiler().m_serialQueue.prepare_next();\n        MemWrite( &item->hdr.type, type );\n        MemWrite( &item->memFree.time, GetTime() );\n        MemWrite( &item->memFree.thread, thread );\n        MemWrite( &item->memFree.ptr, (uint64_t)ptr );\n        GetProfiler().m_serialQueue.commit_next();\n    }\n\n    static tracy_force_inline void SendMemDiscard( QueueType type, const uint32_t thread, const char* name )\n    {\n        assert( type == QueueType::MemDiscard || type == QueueType::MemDiscardCallstack );\n\n        auto item = GetProfiler().m_serialQueue.prepare_next();\n        MemWrite( &item->hdr.type, type );\n        MemWrite( &item->memDiscard.time, GetTime() );\n        MemWrite( &item->memDiscard.thread, thread );\n        MemWrite( &item->memDiscard.name, (uint64_t)name );\n        GetProfiler().m_serialQueue.commit_next();\n    }\n\n    static tracy_force_inline void SendMemName( const char* name )\n    {\n        assert( name );\n        auto item = GetProfiler().m_serialQueue.prepare_next();\n        MemWrite( &item->hdr.type, QueueType::MemNamePayload );\n        MemWrite( &item->memName.name, (uint64_t)name );\n        GetProfiler().m_serialQueue.commit_next();\n    }\n\n#if defined _WIN32 && defined TRACY_TIMER_QPC\n    static int64_t GetTimeQpc();\n#endif\n\n    double m_timerMul;\n    uint64_t m_resolution;\n    std::atomic<int64_t> m_timeBegin;\n    uint32_t m_mainThread;\n    uint64_t m_epoch, m_exectime;\n    std::atomic<bool> m_shutdown;\n    std::atomic<bool> m_shutdownManual;\n    std::atomic<bool> m_shutdownFinished;\n    Socket* m_sock;\n    UdpBroadcast* m_broadcast;\n    bool m_noExit;\n    uint32_t m_userPort;\n    std::atomic<uint32_t> m_zoneId;\n    int64_t m_samplingPeriod;\n\n    uint32_t m_threadCtx;\n    int64_t m_refTimeThread;\n    int64_t m_refTimeSerial;\n    int64_t m_refTimeCtx;\n    int64_t m_refTimeGpu;\n\n    void* m_stream;     // LZ4_stream_t*\n    char* m_buffer;\n    int m_bufferOffset;\n    int m_bufferStart;\n\n    char* m_lz4Buf;\n\n    FastVector<QueueItem> m_serialQueue, m_serialDequeue;\n    TracyMutex m_serialLock;\n\n#ifndef TRACY_NO_FRAME_IMAGE\n    FastVector<FrameImageQueueItem> m_fiQueue, m_fiDequeue;\n    TracyMutex m_fiLock;\n#endif\n\n    SPSCQueue<SymbolQueueItem> m_symbolQueue;\n\n    std::atomic<uint64_t> m_frameCount;\n    std::atomic<bool> m_isConnected;\n#ifdef TRACY_ON_DEMAND\n    std::atomic<uint64_t> m_connectionId;\n    std::atomic<bool> m_symbolsBusy;\n\n    TracyMutex m_deferredLock;\n    FastVector<QueueItem> m_deferredQueue;\n#endif\n\n#ifdef TRACY_HAS_SYSTIME\n    void ProcessSysTime();\n\n    SysTime m_sysTime;\n    uint64_t m_sysTimeLast = 0;\n#else\n    void ProcessSysTime() {}\n#endif\n\n#ifdef TRACY_HAS_SYSPOWER\n    SysPower m_sysPower;\n#endif\n\n    ParameterCallback m_paramCallback;\n    void* m_paramCallbackData;\n    SourceContentsCallback m_sourceCallback;\n    void* m_sourceCallbackData;\n\n    char* m_queryImage;\n    char* m_queryData;\n    char* m_queryDataPtr;\n\n#ifndef NDEBUG\n    // m_safeSendBuffer and m_pipe should only be used by the Tracy Profiler thread; this ensures that in debug builds.\n    std::atomic_bool m_inUse{ false };\n#endif\n    char* m_safeSendBuffer;\n\n#if defined _WIN32\n    void* m_prevHandler;\n#else\n    int m_pipe[2];\n    int m_pipeBufSize;\n#endif\n\n#ifdef __linux__\n    struct {\n        struct sigaction pwr, ill, fpe, segv, pipe, bus, abrt;\n    } m_prevSignal;\n    KCore* m_kcore;\n#endif\n    bool m_crashHandlerInstalled;\n\n    const char* m_programName;\n    TracyMutex m_programNameLock;\n};\n\n}\n\n#endif\n"
  },
  {
    "path": "tracy-client-sys/tracy/client/TracyRingBuffer.hpp",
    "content": "#include <atomic>\n#include <assert.h>\n#include <errno.h>\n#include <linux/perf_event.h>\n#include <stdint.h>\n#include <string.h>\n#include <sys/ioctl.h>\n#include <sys/mman.h>\n#include <unistd.h>\n\n#include \"TracyDebug.hpp\"\n\nnamespace tracy\n{\n\nclass RingBuffer\n{\npublic:\n    RingBuffer( unsigned int size, int fd, int id, int cpu = -1 )\n        : m_size( size )\n        , m_id( id )\n        , m_cpu( cpu )\n        , m_fd( fd )\n    {\n        const auto pageSize = uint32_t( getpagesize() );\n        assert( size >= pageSize );\n        assert( __builtin_popcount( size ) == 1 );\n        m_mapSize = size + pageSize;\n        auto mapAddr = mmap( nullptr, m_mapSize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0 );\n        if( mapAddr == MAP_FAILED )\n        {\n            TracyDebug( \"mmap failed: errno %i (%s)\\n\", errno, strerror( errno ) );\n            m_fd = 0;\n            m_metadata = nullptr;\n            close( fd );\n            return;\n        }\n        m_metadata = (perf_event_mmap_page*)mapAddr;\n        assert( m_metadata->data_offset == pageSize );\n        m_buffer = ((char*)mapAddr) + pageSize;\n        m_tail = m_metadata->data_tail;\n    }\n\n    ~RingBuffer()\n    {\n        if( m_metadata ) munmap( m_metadata, m_mapSize );\n        if( m_fd ) close( m_fd );\n    }\n\n    RingBuffer( const RingBuffer& ) = delete;\n    RingBuffer& operator=( const RingBuffer& ) = delete;\n\n    RingBuffer( RingBuffer&& other )\n    {\n        memcpy( (char*)&other, (char*)this, sizeof( RingBuffer ) );\n        m_metadata = nullptr;\n        m_fd = 0;\n    }\n\n    RingBuffer& operator=( RingBuffer&& other )\n    {\n        memcpy( (char*)&other, (char*)this, sizeof( RingBuffer ) );\n        m_metadata = nullptr;\n        m_fd = 0;\n        return *this;\n    }\n\n    bool IsValid() const { return m_metadata != nullptr; }\n    int GetId() const { return m_id; }\n    int GetCpu() const { return m_cpu; }\n\n    void Enable()\n    {\n        ioctl( m_fd, PERF_EVENT_IOC_ENABLE, 0 );\n    }\n\n    void Read( void* dst, uint64_t offset, uint64_t cnt )\n    {\n        const auto size = m_size;\n        auto src = ( m_tail + offset ) % size;\n        if( src + cnt <= size )\n        {\n            memcpy( dst, m_buffer + src, cnt );\n        }\n        else\n        {\n            const auto s0 = size - src;\n            const auto buf = m_buffer;\n            memcpy( dst, buf + src, s0 );\n            memcpy( (char*)dst + s0, buf, cnt - s0 );\n        }\n    }\n\n    void Advance( uint64_t cnt )\n    {\n        m_tail += cnt;\n        StoreTail();\n    }\n\n    bool CheckTscCaps() const\n    {\n        return m_metadata->cap_user_time_zero;\n    }\n\n    int64_t ConvertTimeToTsc( int64_t timestamp ) const\n    {\n        if( !m_metadata->cap_user_time_zero ) return 0;\n        const auto time = timestamp - m_metadata->time_zero;\n        const auto quot = time / m_metadata->time_mult;\n        const auto rem = time % m_metadata->time_mult;\n        return ( quot << m_metadata->time_shift ) + ( rem << m_metadata->time_shift ) / m_metadata->time_mult;\n    }\n\n    uint64_t LoadHead() const\n    {\n        return std::atomic_load_explicit( (const volatile std::atomic<uint64_t>*)&m_metadata->data_head, std::memory_order_acquire );\n    }\n\n    uint64_t GetTail() const\n    {\n        return m_tail;\n    }\n\nprivate:\n    void StoreTail()\n    {\n        std::atomic_store_explicit( (volatile std::atomic<uint64_t>*)&m_metadata->data_tail, m_tail, std::memory_order_release );\n    }\n\n    unsigned int m_size;\n    uint64_t m_tail;\n    char* m_buffer;\n    int m_id;\n    int m_cpu;\n    perf_event_mmap_page* m_metadata;\n\n    size_t m_mapSize;\n    int m_fd;\n};\n\n}\n"
  },
  {
    "path": "tracy-client-sys/tracy/client/TracyRocprof.cpp",
    "content": "#include \"../server/tracy_robin_hood.h\"\n#include \"TracyProfiler.hpp\"\n#include \"TracyThread.hpp\"\n#include \"tracy/TracyC.h\"\n#include <rocprofiler-sdk/registration.h>\n#include <rocprofiler-sdk/rocprofiler.h>\n\n#include <iostream>\n#include <mutex>\n#include <set>\n#include <shared_mutex>\n#include <sstream>\n#include <time.h>\n#include <unordered_map>\n#include <vector>\n\n#define ROCPROFILER_CALL( result, msg )                                                                                \\\n    {                                                                                                                  \\\n        rocprofiler_status_t CHECKSTATUS = result;                                                                     \\\n        if( CHECKSTATUS != ROCPROFILER_STATUS_SUCCESS )                                                                \\\n        {                                                                                                              \\\n            std::string status_msg = rocprofiler_get_status_string( CHECKSTATUS );                                     \\\n            std::cerr << \"[\" #result \"][\" << __FILE__ << \":\" << __LINE__ << \"] \" << msg << \" failed with error code \"  \\\n                      << CHECKSTATUS << \": \" << status_msg << std::endl;                                               \\\n            std::stringstream errmsg{};                                                                                \\\n            errmsg << \"[\" #result \"][\" << __FILE__ << \":\" << __LINE__ << \"] \" << msg \" failure (\" << status_msg        \\\n                   << \")\";                                                                                             \\\n            throw std::runtime_error( errmsg.str() );                                                                  \\\n        }                                                                                                              \\\n    }\n\nnamespace\n{\n\nusing kernel_symbol_data_t = rocprofiler_callback_tracing_code_object_kernel_symbol_register_data_t;\n\nstruct DispatchData\n{\n    int64_t launch_start;\n    int64_t launch_end;\n    uint32_t thread_id;\n    uint16_t query_id;\n};\n\nstruct ToolData\n{\n    uint32_t version;\n    const char* runtime_version;\n    uint32_t priority;\n    rocprofiler_client_id_t client_id;\n    uint8_t context_id;\n    bool init;\n    uint64_t query_id;\n    int64_t previous_cpu_time;\n    tracy::unordered_map<rocprofiler_kernel_id_t, kernel_symbol_data_t> client_kernels;\n    tracy::unordered_map<rocprofiler_dispatch_id_t, DispatchData> dispatch_data;\n    tracy::unordered_set<std::string> counter_names = { \"SQ_WAVES\", \"GL2C_MISS\", \"GL2C_HIT\" };\n    std::unique_ptr<tracy::Thread> cal_thread;\n    std::mutex mut{};\n};\n\nusing namespace tracy;\n\nrocprofiler_context_id_t& get_client_ctx()\n{\n    static rocprofiler_context_id_t ctx{ 0 };\n    return ctx;\n}\n\nconst char* CTX_NAME = \"rocprofv3\";\n\nuint8_t gpu_context_allocate( ToolData* data )\n{\n\n    timespec ts;\n    clock_gettime( CLOCK_BOOTTIME, &ts );\n    uint64_t cpu_timestamp = Profiler::GetTime();\n    uint64_t gpu_timestamp = ( (uint64_t)ts.tv_sec * 1000000000 ) + ts.tv_nsec;\n    float timestamp_period = 1.0f;\n    data->previous_cpu_time = cpu_timestamp;\n\n    // Allocate the process-unique GPU context ID. There's a max of 255 available;\n    // if we are recreating devices a lot we may exceed that. Don't do that, or\n    // wrap around and get weird (but probably still usable) numbers.\n    uint8_t context_id = tracy::GetGpuCtxCounter().fetch_add( 1, std::memory_order_relaxed );\n    if( context_id >= 255 )\n    {\n        context_id %= 255;\n    }\n\n    uint8_t context_flags = 0;\n#ifdef TRACY_ROCPROF_CALIBRATION\n    // Tell tracy we'll be passing calibrated timestamps and not to mess with\n    // the times. We'll periodically send GpuCalibration events in case the\n    // times drift.\n    context_flags |= tracy::GpuContextCalibration;\n#endif\n    {\n        auto* item = tracy::Profiler::QueueSerial();\n        tracy::MemWrite( &item->hdr.type, tracy::QueueType::GpuNewContext );\n        tracy::MemWrite( &item->gpuNewContext.cpuTime, cpu_timestamp );\n        tracy::MemWrite( &item->gpuNewContext.gpuTime, gpu_timestamp );\n        memset( &item->gpuNewContext.thread, 0, sizeof( item->gpuNewContext.thread ) );\n        tracy::MemWrite( &item->gpuNewContext.period, timestamp_period );\n        tracy::MemWrite( &item->gpuNewContext.context, context_id );\n        tracy::MemWrite( &item->gpuNewContext.flags, context_flags );\n        tracy::MemWrite( &item->gpuNewContext.type, tracy::GpuContextType::Rocprof );\n        tracy::Profiler::QueueSerialFinish();\n    }\n\n    // Send the name of the context along.\n    // NOTE: Tracy will unconditionally free the name so we must clone it here.\n    // Since internally Tracy will use its own rpmalloc implementation we must\n    // make sure we allocate from the same source.\n    size_t name_length = strlen( CTX_NAME );\n    char* cloned_name = (char*)tracy::tracy_malloc( name_length );\n    memcpy( cloned_name, CTX_NAME, name_length );\n    {\n        auto* item = tracy::Profiler::QueueSerial();\n        tracy::MemWrite( &item->hdr.type, tracy::QueueType::GpuContextName );\n        tracy::MemWrite( &item->gpuContextNameFat.context, context_id );\n        tracy::MemWrite( &item->gpuContextNameFat.ptr, (uint64_t)cloned_name );\n        tracy::MemWrite( &item->gpuContextNameFat.size, name_length );\n        tracy::Profiler::QueueSerialFinish();\n    }\n\n    return context_id;\n}\n\nuint64_t kernel_src_loc( ToolData* data, uint64_t kernel_id )\n{\n    uint64_t src_loc = 0;\n    auto _lk = std::unique_lock{ data->mut };\n    rocprofiler_kernel_id_t kid = kernel_id;\n    if( data->client_kernels.count( kid ) )\n    {\n        auto& sym_data = data->client_kernels[kid];\n        const char* name = sym_data.kernel_name;\n        size_t name_len = strlen( name );\n        uint32_t line = 0;\n        src_loc = tracy::Profiler::AllocSourceLocation( line, NULL, 0, name, name_len, NULL, 0 );\n    }\n    return src_loc;\n}\n\nvoid record_interval( ToolData* data, rocprofiler_timestamp_t start_timestamp, rocprofiler_timestamp_t end_timestamp,\n                      uint64_t src_loc, rocprofiler_dispatch_id_t dispatch_id )\n{\n\n    uint16_t query_id = 0;\n    uint8_t context_id = data->context_id;\n\n    {\n        auto _lk = std::unique_lock{ data->mut };\n        query_id = data->query_id;\n        data->query_id++;\n        if( dispatch_id != UINT64_MAX )\n        {\n            DispatchData& dispatch_data = data->dispatch_data[dispatch_id];\n            dispatch_data.query_id = query_id;\n            dispatch_data.thread_id = tracy::GetThreadHandle();\n        }\n    }\n\n    uint64_t cpu_start_time = 0, cpu_end_time = 0;\n    if( dispatch_id == UINT64_MAX )\n    {\n        cpu_start_time = tracy::Profiler::GetTime();\n        cpu_end_time = tracy::Profiler::GetTime();\n    }\n    else\n    {\n        auto _lk = std::unique_lock{ data->mut };\n        DispatchData& dispatch_data = data->dispatch_data[dispatch_id];\n        cpu_start_time = dispatch_data.launch_start;\n        cpu_end_time = dispatch_data.launch_end;\n    }\n\n    if( src_loc != 0 )\n    {\n        {\n            auto* item = tracy::Profiler::QueueSerial();\n            tracy::MemWrite( &item->hdr.type, tracy::QueueType::GpuZoneBeginAllocSrcLocSerial );\n            tracy::MemWrite( &item->gpuZoneBegin.cpuTime, cpu_start_time );\n            tracy::MemWrite( &item->gpuZoneBegin.srcloc, (uint64_t)src_loc );\n            tracy::MemWrite( &item->gpuZoneBegin.thread, tracy::GetThreadHandle() );\n            tracy::MemWrite( &item->gpuZoneBegin.queryId, query_id );\n            tracy::MemWrite( &item->gpuZoneBegin.context, context_id );\n            tracy::Profiler::QueueSerialFinish();\n        }\n    }\n    else\n    {\n        static const ___tracy_source_location_data src_loc = { NULL, NULL, NULL, 0, 0 };\n        {\n            auto* item = tracy::Profiler::QueueSerial();\n            tracy::MemWrite( &item->hdr.type, tracy::QueueType::GpuZoneBeginSerial );\n            tracy::MemWrite( &item->gpuZoneBegin.cpuTime, cpu_start_time );\n            tracy::MemWrite( &item->gpuZoneBegin.srcloc, (uint64_t)&src_loc );\n            tracy::MemWrite( &item->gpuZoneBegin.thread, tracy::GetThreadHandle() );\n            tracy::MemWrite( &item->gpuZoneBegin.queryId, query_id );\n            tracy::MemWrite( &item->gpuZoneBegin.context, context_id );\n            tracy::Profiler::QueueSerialFinish();\n        }\n    }\n\n    {\n        auto* item = tracy::Profiler::QueueSerial();\n        tracy::MemWrite( &item->hdr.type, tracy::QueueType::GpuTime );\n        tracy::MemWrite( &item->gpuTime.gpuTime, start_timestamp );\n        tracy::MemWrite( &item->gpuTime.queryId, query_id );\n        tracy::MemWrite( &item->gpuTime.context, context_id );\n        tracy::Profiler::QueueSerialFinish();\n    }\n\n    {\n        auto* item = tracy::Profiler::QueueSerial();\n        tracy::MemWrite( &item->hdr.type, tracy::QueueType::GpuZoneEndSerial );\n        tracy::MemWrite( &item->gpuZoneEnd.cpuTime, cpu_end_time );\n        tracy::MemWrite( &item->gpuZoneEnd.thread, tracy::GetThreadHandle() );\n        tracy::MemWrite( &item->gpuZoneEnd.queryId, query_id );\n        tracy::MemWrite( &item->gpuZoneEnd.context, context_id );\n        tracy::Profiler::QueueSerialFinish();\n    }\n\n    {\n        auto* item = tracy::Profiler::QueueSerial();\n        tracy::MemWrite( &item->hdr.type, tracy::QueueType::GpuTime );\n        tracy::MemWrite( &item->gpuTime.gpuTime, end_timestamp );\n        tracy::MemWrite( &item->gpuTime.queryId, query_id );\n        tracy::MemWrite( &item->gpuTime.context, context_id );\n        tracy::Profiler::QueueSerialFinish();\n    }\n}\n\nvoid record_callback( rocprofiler_dispatch_counting_service_data_t dispatch_data,\n                      rocprofiler_record_counter_t* record_data, size_t record_count,\n                      rocprofiler_user_data_t /*user_data*/, void* callback_data )\n{\n    assert( callback_data != nullptr );\n    ToolData* data = static_cast<ToolData*>( callback_data );\n    if( !data->init ) return;\n\n    std::unordered_map<rocprofiler_counter_instance_id_t, double> sums;\n    for( size_t i = 0; i < record_count; ++i )\n    {\n        auto _counter_id = rocprofiler_counter_id_t{};\n        ROCPROFILER_CALL( rocprofiler_query_record_counter_id( record_data[i].id, &_counter_id ),\n                          \"query record counter id\" );\n        sums[_counter_id.handle] += record_data[i].counter_value;\n    }\n\n    uint16_t query_id = 0;\n    uint32_t thread_id = 0;\n    {\n        auto _lk = std::unique_lock{ data->mut };\n        // An assumption is made here that the counter values are supplied after the dispatch\n        // complete callback.\n        assert( data->dispatch_data.count( dispatch_data.dispatch_info.dispatch_id ) );\n        DispatchData& ddata = data->dispatch_data[dispatch_data.dispatch_info.dispatch_id];\n        query_id = ddata.query_id;\n        thread_id = ddata.thread_id;\n    }\n\n    for( auto& p : sums )\n    {\n        auto* item = tracy::Profiler::QueueSerial();\n        tracy::MemWrite( &item->hdr.type, tracy::QueueType::GpuZoneAnnotation );\n        tracy::MemWrite( &item->zoneAnnotation.noteId, p.first );\n        tracy::MemWrite( &item->zoneAnnotation.queryId, query_id );\n        tracy::MemWrite( &item->zoneAnnotation.thread, thread_id );\n        tracy::MemWrite( &item->zoneAnnotation.value, p.second );\n        tracy::MemWrite( &item->zoneAnnotation.context, data->context_id );\n        tracy::Profiler::QueueSerialFinish();\n    }\n}\n\n/**\n * Callback from rocprofiler when an kernel dispatch is enqueued into the HSA queue.\n * rocprofiler_counter_config_id_t* is a return to specify what counters to collect\n * for this dispatch (dispatch_packet).\n */\nvoid dispatch_callback( rocprofiler_dispatch_counting_service_data_t dispatch_data,\n                        rocprofiler_profile_config_id_t* config, rocprofiler_user_data_t* /*user_data*/,\n                        void* callback_data )\n{\n    assert( callback_data != nullptr );\n    ToolData* data = static_cast<ToolData*>( callback_data );\n    if( !data->init ) return;\n\n    /**\n     * This simple example uses the same profile counter set for all agents.\n     * We store this in a cache to prevent constructing many identical profile counter\n     * sets. We first check the cache to see if we have already constructed a counter\"\n     * set for the agent. If we have, return it. Otherwise, construct a new profile counter\n     * set.\n     */\n    static std::shared_mutex m_mutex = {};\n    static std::unordered_map<uint64_t, rocprofiler_profile_config_id_t> profile_cache = {};\n\n    auto search_cache = [&]()\n    {\n        if( auto pos = profile_cache.find( dispatch_data.dispatch_info.agent_id.handle ); pos != profile_cache.end() )\n        {\n            *config = pos->second;\n            return true;\n        }\n        return false;\n    };\n\n    {\n        auto rlock = std::shared_lock{ m_mutex };\n        if( search_cache() ) return;\n    }\n\n    auto wlock = std::unique_lock{ m_mutex };\n    if( search_cache() ) return;\n\n    // GPU Counter IDs\n    std::vector<rocprofiler_counter_id_t> gpu_counters;\n\n    // Iterate through the agents and get the counters available on that agent\n    ROCPROFILER_CALL(\n        rocprofiler_iterate_agent_supported_counters(\n            dispatch_data.dispatch_info.agent_id,\n            []( rocprofiler_agent_id_t, rocprofiler_counter_id_t* counters, size_t num_counters, void* user_data )\n            {\n                std::vector<rocprofiler_counter_id_t>* vec =\n                    static_cast<std::vector<rocprofiler_counter_id_t>*>( user_data );\n                for( size_t i = 0; i < num_counters; i++ )\n                {\n                    vec->push_back( counters[i] );\n                }\n                return ROCPROFILER_STATUS_SUCCESS;\n            },\n            static_cast<void*>( &gpu_counters ) ),\n        \"Could not fetch supported counters\" );\n\n    std::vector<rocprofiler_counter_id_t> collect_counters;\n    collect_counters.reserve( data->counter_names.size() );\n    // Look for the counters contained in counters_to_collect in gpu_counters\n    for( auto& counter : gpu_counters )\n    {\n        rocprofiler_counter_info_v0_t info;\n        ROCPROFILER_CALL(\n            rocprofiler_query_counter_info( counter, ROCPROFILER_COUNTER_INFO_VERSION_0, static_cast<void*>( &info ) ),\n            \"Could not query info\" );\n        if( data->counter_names.count( std::string( info.name ) ) > 0 )\n        {\n            collect_counters.push_back( counter );\n\n            size_t name_length = strlen( info.name );\n            char* cloned_name = (char*)tracy::tracy_malloc( name_length );\n            memcpy( cloned_name, info.name, name_length );\n            {\n                auto* item = tracy::Profiler::QueueSerial();\n                tracy::MemWrite( &item->hdr.type, tracy::QueueType::GpuAnnotationName );\n                tracy::MemWrite( &item->gpuAnnotationNameFat.context, data->context_id );\n                tracy::MemWrite( &item->gpuAnnotationNameFat.noteId, counter.handle );\n                tracy::MemWrite( &item->gpuAnnotationNameFat.ptr, (uint64_t)cloned_name );\n                tracy::MemWrite( &item->gpuAnnotationNameFat.size, name_length );\n                tracy::Profiler::QueueSerialFinish();\n            }\n        }\n    }\n\n    // Create a colleciton profile for the counters\n    rocprofiler_profile_config_id_t profile = { .handle = 0 };\n    ROCPROFILER_CALL( rocprofiler_create_profile_config( dispatch_data.dispatch_info.agent_id, collect_counters.data(),\n                                                         collect_counters.size(), &profile ),\n                      \"Could not construct profile cfg\" );\n\n    profile_cache.emplace( dispatch_data.dispatch_info.agent_id.handle, profile );\n    // Return the profile to collect those counters for this dispatch\n    *config = profile;\n}\n\nvoid tool_callback_tracing_callback( rocprofiler_callback_tracing_record_t record, rocprofiler_user_data_t* user_data,\n                                     void* callback_data )\n{\n    assert( callback_data != nullptr );\n    ToolData* data = static_cast<ToolData*>( callback_data );\n    if( !data->init ) return;\n\n    if( record.kind == ROCPROFILER_CALLBACK_TRACING_CODE_OBJECT &&\n        record.operation == ROCPROFILER_CODE_OBJECT_DEVICE_KERNEL_SYMBOL_REGISTER )\n    {\n        auto* sym_data = static_cast<kernel_symbol_data_t*>( record.payload );\n\n        if( record.phase == ROCPROFILER_CALLBACK_PHASE_LOAD )\n        {\n            auto _lk = std::unique_lock{ data->mut };\n            data->client_kernels.emplace( sym_data->kernel_id, *sym_data );\n        }\n        else if( record.phase == ROCPROFILER_CALLBACK_PHASE_UNLOAD )\n        {\n            auto _lk = std::unique_lock{ data->mut };\n            data->client_kernels.erase( sym_data->kernel_id );\n        }\n    }\n    else if( record.kind == ROCPROFILER_CALLBACK_TRACING_KERNEL_DISPATCH )\n    {\n        auto* rdata = static_cast<rocprofiler_callback_tracing_kernel_dispatch_data_t*>( record.payload );\n        if( record.operation == ROCPROFILER_KERNEL_DISPATCH_ENQUEUE )\n        {\n            if( record.phase == ROCPROFILER_CALLBACK_PHASE_ENTER )\n            {\n                auto _lk = std::unique_lock{ data->mut };\n                data->dispatch_data[rdata->dispatch_info.dispatch_id].launch_start = tracy::Profiler::GetTime();\n            }\n            else if( record.phase == ROCPROFILER_CALLBACK_PHASE_EXIT )\n            {\n                auto _lk = std::unique_lock{ data->mut };\n                data->dispatch_data[rdata->dispatch_info.dispatch_id].launch_end = tracy::Profiler::GetTime();\n            }\n        }\n        else if( record.operation == ROCPROFILER_KERNEL_DISPATCH_COMPLETE )\n        {\n            uint64_t src_loc = kernel_src_loc( data, rdata->dispatch_info.kernel_id );\n            record_interval( data, rdata->start_timestamp, rdata->end_timestamp, src_loc,\n                             rdata->dispatch_info.dispatch_id );\n        }\n    }\n    else if( record.kind == ROCPROFILER_CALLBACK_TRACING_MEMORY_COPY &&\n             record.operation != ROCPROFILER_MEMORY_COPY_NONE && record.phase == ROCPROFILER_CALLBACK_PHASE_EXIT )\n    {\n        auto* rdata = static_cast<rocprofiler_callback_tracing_memory_copy_data_t*>( record.payload );\n        const char* name = nullptr;\n        switch( record.operation )\n        {\n        case ROCPROFILER_MEMORY_COPY_DEVICE_TO_DEVICE:\n            name = \"DeviceToDeviceCopy\";\n            break;\n        case ROCPROFILER_MEMORY_COPY_DEVICE_TO_HOST:\n            name = \"DeviceToHostCopy\";\n            break;\n        case ROCPROFILER_MEMORY_COPY_HOST_TO_DEVICE:\n            name = \"HostToDeviceCopy\";\n            break;\n        case ROCPROFILER_MEMORY_COPY_HOST_TO_HOST:\n            name = \"HostToHostCopy\";\n            break;\n        }\n        size_t name_len = strlen( name );\n        uint64_t src_loc = tracy::Profiler::AllocSourceLocation( 0, NULL, 0, name, name_len, NULL, 0 );\n        record_interval( data, rdata->start_timestamp, rdata->end_timestamp, src_loc, UINT64_MAX );\n    }\n}\n\nvoid calibration_thread( void* ptr )\n{\n    while( !TracyIsStarted )\n        ;\n    ToolData* data = static_cast<ToolData*>( ptr );\n    data->context_id = gpu_context_allocate( data );\n    const char* user_counters = GetEnvVar( \"TRACY_ROCPROF_COUNTERS\" );\n    if( user_counters )\n    {\n        data->counter_names.clear();\n        std::stringstream ss( user_counters );\n        std::string counter;\n        while( std::getline( ss, counter, ',' ) ) data->counter_names.insert( counter );\n    }\n    data->init = true;\n\n#ifdef TRACY_ROCPROF_CALIBRATION\n    while( data->init )\n    {\n        sleep( 1 );\n\n        timespec ts;\n        // HSA performs a linear interpolation of GPU time to CLOCK_BOOTTIME. However, this is\n        // subject to network time updates and can drift relative to tracy's clock.\n        clock_gettime( CLOCK_BOOTTIME, &ts );\n        int64_t cpu_timestamp = Profiler::GetTime();\n        int64_t gpu_timestamp = ts.tv_nsec + ts.tv_sec * 1e9L;\n\n        if( cpu_timestamp > data->previous_cpu_time )\n        {\n            auto* item = tracy::Profiler::QueueSerial();\n            tracy::MemWrite( &item->hdr.type, tracy::QueueType::GpuCalibration );\n            tracy::MemWrite( &item->gpuCalibration.gpuTime, gpu_timestamp );\n            tracy::MemWrite( &item->gpuCalibration.cpuTime, cpu_timestamp );\n            tracy::MemWrite( &item->gpuCalibration.cpuDelta, cpu_timestamp - data->previous_cpu_time );\n            tracy::MemWrite( &item->gpuCalibration.context, data->context_id );\n            tracy::Profiler::QueueSerialFinish();\n            data->previous_cpu_time = cpu_timestamp;\n        }\n    }\n#endif\n}\n\nint tool_init( rocprofiler_client_finalize_t fini_func, void* user_data )\n{\n    ToolData* data = static_cast<ToolData*>( user_data );\n    data->cal_thread = std::make_unique<tracy::Thread>( calibration_thread, data );\n\n    ROCPROFILER_CALL( rocprofiler_create_context( &get_client_ctx() ), \"context creation failed\" );\n\n    ROCPROFILER_CALL( rocprofiler_configure_callback_dispatch_counting_service( get_client_ctx(), dispatch_callback,\n                                                                                user_data, record_callback, user_data ),\n                      \"Could not setup counting service\" );\n\n    rocprofiler_tracing_operation_t ops[] = { ROCPROFILER_CODE_OBJECT_DEVICE_KERNEL_SYMBOL_REGISTER };\n    ROCPROFILER_CALL( rocprofiler_configure_callback_tracing_service( get_client_ctx(),\n                                                                      ROCPROFILER_CALLBACK_TRACING_CODE_OBJECT, ops, 1,\n                                                                      tool_callback_tracing_callback, user_data ),\n                      \"callback tracing service failed to configure\" );\n\n    rocprofiler_tracing_operation_t ops2[] = { ROCPROFILER_KERNEL_DISPATCH_COMPLETE,\n                                               ROCPROFILER_KERNEL_DISPATCH_ENQUEUE };\n    ROCPROFILER_CALL(\n        rocprofiler_configure_callback_tracing_service( get_client_ctx(), ROCPROFILER_CALLBACK_TRACING_KERNEL_DISPATCH,\n                                                        ops2, 2, tool_callback_tracing_callback, user_data ),\n        \"callback tracing service failed to configure\" );\n\n    ROCPROFILER_CALL( rocprofiler_configure_callback_tracing_service( get_client_ctx(),\n                                                                      ROCPROFILER_CALLBACK_TRACING_MEMORY_COPY, nullptr,\n                                                                      0, tool_callback_tracing_callback, user_data ),\n                      \"callback tracing service failed to configure\" );\n\n    ROCPROFILER_CALL( rocprofiler_start_context( get_client_ctx() ), \"start context\" );\n    return 0;\n}\n\nvoid tool_fini( void* tool_data_v )\n{\n    rocprofiler_stop_context( get_client_ctx() );\n\n    ToolData* data = static_cast<ToolData*>( tool_data_v );\n    data->init = false;\n    data->cal_thread.reset();\n}\n}\n\nextern \"C\"\n{\n    rocprofiler_tool_configure_result_t* rocprofiler_configure( uint32_t version, const char* runtime_version,\n                                                                uint32_t priority, rocprofiler_client_id_t* client_id )\n    {\n        // If not the first tool to register, indicate that the tool doesn't want to do anything\n        if( priority > 0 ) return nullptr;\n\n        // (optional) Provide a name for this tool to rocprofiler\n        client_id->name = \"Tracy\";\n\n        // (optional) create configure data\n        static ToolData data = ToolData{ version, runtime_version, priority, *client_id, 0, false, 0, 0 };\n\n        // construct configure result\n        static auto cfg = rocprofiler_tool_configure_result_t{ sizeof( rocprofiler_tool_configure_result_t ),\n                                                               &tool_init, &tool_fini, static_cast<void*>( &data ) };\n\n        return &cfg;\n    }\n}\n"
  },
  {
    "path": "tracy-client-sys/tracy/client/TracyScoped.hpp",
    "content": "#ifndef __TRACYSCOPED_HPP__\n#define __TRACYSCOPED_HPP__\n\n#include <limits>\n#include <stdarg.h>\n#include <stdint.h>\n#include <string.h>\n\n#include \"../common/TracySystem.hpp\"\n#include \"../common/TracyAlign.hpp\"\n#include \"../common/TracyAlloc.hpp\"\n#include \"TracyProfiler.hpp\"\n#include \"TracyCallstack.hpp\"\n\n#if (defined(__GNUC__) || defined(__clang__))\n#  define TRACY_ATTRIBUTE_FORMAT_PRINTF(fmt_idx, arg_idx) \\\n     __attribute__((format(printf, fmt_idx, arg_idx)))\n#else\n#  define TRACY_ATTRIBUTE_FORMAT_PRINTF(fmt_idx, arg_idx)\n#endif\nnamespace tracy\n{\n\nclass ScopedZone\n{\npublic:\n    ScopedZone( const ScopedZone& ) = delete;\n    ScopedZone( ScopedZone&& ) = delete;\n    ScopedZone& operator=( const ScopedZone& ) = delete;\n    ScopedZone& operator=( ScopedZone&& ) = delete;\n\n    tracy_force_inline ScopedZone( const SourceLocationData* srcloc, int32_t depth = -1, bool is_active = true )\n#ifdef TRACY_ON_DEMAND\n        : m_active( is_active && GetProfiler().IsConnected() )\n#else\n        : m_active( is_active )\n#endif\n    {\n        if( !m_active ) return;\n#ifdef TRACY_ON_DEMAND\n        m_connectionId = GetProfiler().ConnectionId();\n#endif\n        auto zoneQueue = QueueType::ZoneBegin;\n        if( depth > 0 && has_callstack() )\n        {\n            GetProfiler().SendCallstack( depth );\n            zoneQueue = QueueType::ZoneBeginCallstack;\n        }\n        TracyQueuePrepare( zoneQueue );\n        MemWrite( &item->zoneBegin.time, Profiler::GetTime() );\n        MemWrite( &item->zoneBegin.srcloc, (uint64_t)srcloc );\n        TracyQueueCommit( zoneBeginThread );\n    }\n\n    tracy_force_inline ScopedZone( uint32_t line, const char* source, size_t sourceSz, const char* function, size_t functionSz, const char* name, size_t nameSz, uint32_t color, int32_t depth = -1, bool is_active = true )\n#ifdef TRACY_ON_DEMAND\n        : m_active( is_active && GetProfiler().IsConnected() )\n#else\n        : m_active( is_active )\n#endif\n    {\n        if( !m_active ) return;\n#ifdef TRACY_ON_DEMAND\n        m_connectionId = GetProfiler().ConnectionId();\n#endif\n        auto zoneQueue = QueueType::ZoneBeginAllocSrcLoc;\n        if( depth > 0 && has_callstack() )\n        {\n            GetProfiler().SendCallstack( depth );\n            zoneQueue = QueueType::ZoneBeginAllocSrcLocCallstack;\n        }\n        TracyQueuePrepare( zoneQueue );\n        const auto srcloc =\n            Profiler::AllocSourceLocation( line, source, sourceSz, function, functionSz, name, nameSz, color );\n        MemWrite( &item->zoneBegin.time, Profiler::GetTime() );\n        MemWrite( &item->zoneBegin.srcloc, srcloc );\n        TracyQueueCommit( zoneBeginThread );\n    }\n\n    tracy_force_inline ScopedZone( uint32_t line, const char* source, size_t sourceSz, const char* function, size_t functionSz, const char* name, size_t nameSz, int32_t depth, bool is_active = true ) : ScopedZone( line, source, sourceSz, function, functionSz, name, nameSz, 0, depth, is_active ) {}\n\n    tracy_force_inline ~ScopedZone()\n    {\n        if( !m_active ) return;\n#ifdef TRACY_ON_DEMAND\n        if( GetProfiler().ConnectionId() != m_connectionId ) return;\n#endif\n        TracyQueuePrepare( QueueType::ZoneEnd );\n        MemWrite( &item->zoneEnd.time, Profiler::GetTime() );\n        TracyQueueCommit( zoneEndThread );\n    }\n\n    tracy_force_inline void Text( const char* txt, size_t size )\n    {\n        assert( size < (std::numeric_limits<uint16_t>::max)() );\n        if( !m_active ) return;\n#ifdef TRACY_ON_DEMAND\n        if( GetProfiler().ConnectionId() != m_connectionId ) return;\n#endif\n        auto ptr = (char*)tracy_malloc( size );\n        memcpy( ptr, txt, size );\n        TracyQueuePrepare( QueueType::ZoneText );\n        MemWrite( &item->zoneTextFat.text, (uint64_t)ptr );\n        MemWrite( &item->zoneTextFat.size, (uint16_t)size );\n        TracyQueueCommit( zoneTextFatThread );\n    }\n\n    void TextFmt( const char* fmt, ... ) TRACY_ATTRIBUTE_FORMAT_PRINTF(2, 3)\n    {\n        if( !m_active ) return;\n#ifdef TRACY_ON_DEMAND\n        if( GetProfiler().ConnectionId() != m_connectionId ) return;\n#endif\n        va_list args;\n        va_start( args, fmt );\n        auto size = vsnprintf( nullptr, 0, fmt, args );\n        va_end( args );\n        if( size < 0 ) return;\n        assert( size < (std::numeric_limits<uint16_t>::max)() );\n\n        char* ptr = (char*)tracy_malloc( size_t( size ) + 1 );\n        va_start( args, fmt );\n        vsnprintf( ptr, size_t( size ) + 1, fmt, args );\n        va_end( args );\n\n        TracyQueuePrepare( QueueType::ZoneText );\n        MemWrite( &item->zoneTextFat.text, (uint64_t)ptr );\n        MemWrite( &item->zoneTextFat.size, (uint16_t)size );\n        TracyQueueCommit( zoneTextFatThread );\n    }\n\n    tracy_force_inline void Name( const char* txt, size_t size )\n    {\n        assert( size < (std::numeric_limits<uint16_t>::max)() );\n        if( !m_active ) return;\n#ifdef TRACY_ON_DEMAND\n        if( GetProfiler().ConnectionId() != m_connectionId ) return;\n#endif\n        auto ptr = (char*)tracy_malloc( size );\n        memcpy( ptr, txt, size );\n        TracyQueuePrepare( QueueType::ZoneName );\n        MemWrite( &item->zoneTextFat.text, (uint64_t)ptr );\n        MemWrite( &item->zoneTextFat.size, (uint16_t)size );\n        TracyQueueCommit( zoneTextFatThread );\n    }\n\n    void NameFmt( const char* fmt, ... ) TRACY_ATTRIBUTE_FORMAT_PRINTF(2, 3)\n    {\n        if( !m_active ) return;\n#ifdef TRACY_ON_DEMAND\n        if( GetProfiler().ConnectionId() != m_connectionId ) return;\n#endif\n        va_list args;\n        va_start( args, fmt );\n        auto size = vsnprintf( nullptr, 0, fmt, args );\n        va_end( args );\n        if( size < 0 ) return;\n        assert( size < (std::numeric_limits<uint16_t>::max)() );\n\n        char* ptr = (char*)tracy_malloc( size_t( size ) + 1 );\n        va_start( args, fmt );\n        vsnprintf( ptr, size_t( size ) + 1, fmt, args );\n        va_end( args );\n\n        TracyQueuePrepare( QueueType::ZoneName );\n        MemWrite( &item->zoneTextFat.text, (uint64_t)ptr );\n        MemWrite( &item->zoneTextFat.size, (uint16_t)size );\n        TracyQueueCommit( zoneTextFatThread );\n    }\n\n    tracy_force_inline void Color( uint32_t color )\n    {\n        if( !m_active ) return;\n#ifdef TRACY_ON_DEMAND\n        if( GetProfiler().ConnectionId() != m_connectionId ) return;\n#endif\n        TracyQueuePrepare( QueueType::ZoneColor );\n        MemWrite( &item->zoneColor.b, uint8_t( ( color       ) & 0xFF ) );\n        MemWrite( &item->zoneColor.g, uint8_t( ( color >> 8  ) & 0xFF ) );\n        MemWrite( &item->zoneColor.r, uint8_t( ( color >> 16 ) & 0xFF ) );\n        TracyQueueCommit( zoneColorThread );\n    }\n\n    tracy_force_inline void Value( uint64_t value )\n    {\n        if( !m_active ) return;\n#ifdef TRACY_ON_DEMAND\n        if( GetProfiler().ConnectionId() != m_connectionId ) return;\n#endif\n        TracyQueuePrepare( QueueType::ZoneValue );\n        MemWrite( &item->zoneValue.value, value );\n        TracyQueueCommit( zoneValueThread );\n    }\n\n    tracy_force_inline bool IsActive() const { return m_active; }\n\nprivate:\n    const bool m_active;\n\n#ifdef TRACY_ON_DEMAND\n    uint64_t m_connectionId = 0;\n#endif\n};\n\n}\n\n#endif\n"
  },
  {
    "path": "tracy-client-sys/tracy/client/TracyStringHelpers.hpp",
    "content": "#ifndef __TRACYSTRINGHELPERS_HPP__\n#define __TRACYSTRINGHELPERS_HPP__\n\n#include <assert.h>\n#include <string.h>\n\n#include \"../common/TracyAlloc.hpp\"\n#include \"../common/TracyForceInline.hpp\"\n\nnamespace tracy\n{\n\nstatic tracy_force_inline char* CopyString( const char* src, size_t sz )\n{\n    auto dst = (char*)tracy_malloc( sz + 1 );\n    memcpy( dst, src, sz );\n    dst[sz] = '\\0';\n    return dst;\n}\n\nstatic tracy_force_inline char* CopyString( const char* src )\n{\n    return CopyString( src, strlen( src ) );\n}\n\nstatic tracy_force_inline char* CopyStringFast( const char* src, size_t sz )\n{\n    auto dst = (char*)tracy_malloc_fast( sz + 1 );\n    memcpy( dst, src, sz );\n    dst[sz] = '\\0';\n    return dst;\n}\n\nstatic tracy_force_inline char* CopyStringFast( const char* src )\n{\n    return CopyStringFast( src, strlen( src ) );\n}\n\n}\n\n#endif\n"
  },
  {
    "path": "tracy-client-sys/tracy/client/TracySysPower.cpp",
    "content": "#include \"TracySysPower.hpp\"\n\n#ifdef TRACY_HAS_SYSPOWER\n\n#include <sys/types.h>\n#include <dirent.h>\n#include <chrono>\n#include <inttypes.h>\n#include <stdio.h>\n#include <string.h>\n\n#include \"TracyDebug.hpp\"\n#include \"TracyProfiler.hpp\"\n#include \"../common/TracyAlloc.hpp\"\n\nnamespace tracy\n{\n\nSysPower::SysPower()\n    : m_domains( 4 )\n    , m_lastTime( 0 )\n{\n    ScanDirectory( \"/sys/devices/virtual/powercap/intel-rapl\", -1 );\n}\n\nSysPower::~SysPower()\n{\n    for( auto& v : m_domains )\n    {\n        fclose( v.handle );\n        // Do not release v.name, as it may be still needed\n    }\n}\n\nvoid SysPower::Tick()\n{\n    auto t = std::chrono::high_resolution_clock::now().time_since_epoch().count();\n    if( t - m_lastTime > 10000000 )    // 10 ms\n    {\n        m_lastTime = t;\n        for( auto& v : m_domains )\n        {\n            char tmp[32];\n            if( fread( tmp, 1, 32, v.handle ) > 0 )\n            {\n                rewind( v.handle );\n                auto p = (uint64_t)atoll( tmp );\n                uint64_t delta;\n                if( p >= v.value )\n                {\n                    delta = p - v.value;\n                }\n                else\n                {\n                    delta = v.overflow - v.value + p;\n                }\n                v.value = p;\n\n                TracyLfqPrepare( QueueType::SysPowerReport );\n                MemWrite( &item->sysPower.time, Profiler::GetTime() );\n                MemWrite( &item->sysPower.delta, delta );\n                MemWrite( &item->sysPower.name, (uint64_t)v.name );\n                TracyLfqCommit;\n            }\n        }\n    }\n}\n\nvoid SysPower::ScanDirectory( const char* path, int parent )\n{\n    DIR* dir = opendir( path );\n    if( !dir ) return;\n    struct dirent* ent;\n    uint64_t maxRange = 0;\n    char* name = nullptr;\n    FILE* handle = nullptr;\n    while( ( ent = readdir( dir ) ) )\n    {\n        if( ent->d_type == DT_REG )\n        {\n            if( strcmp( ent->d_name, \"max_energy_range_uj\" ) == 0 )\n            {\n                char tmp[PATH_MAX];\n                snprintf( tmp, PATH_MAX, \"%s/max_energy_range_uj\", path );\n                FILE* f = fopen( tmp, \"r\" );\n                if( f )\n                {\n                    (void)fscanf( f, \"%\" PRIu64, &maxRange );\n                    fclose( f );\n                }\n            }\n            else if( strcmp( ent->d_name, \"name\" ) == 0 )\n            {\n                char tmp[PATH_MAX];\n                snprintf( tmp, PATH_MAX, \"%s/name\", path );\n                FILE* f = fopen( tmp, \"r\" );\n                if( f )\n                {\n                    char ntmp[128];\n                    if( fgets( ntmp, 128, f ) )\n                    {\n                        // Last character is newline, skip it\n                        const auto sz = strlen( ntmp ) - 1;\n                        if( parent < 0 )\n                        {\n                            name = (char*)tracy_malloc( sz + 1 );\n                            memcpy( name, ntmp, sz );\n                            name[sz] = '\\0';\n                        }\n                        else\n                        {\n                            const auto p = m_domains[parent];\n                            const auto psz = strlen( p.name );\n                            name = (char*)tracy_malloc( psz + sz + 2 );\n                            memcpy( name, p.name, psz );\n                            name[psz] = ':';\n                            memcpy( name+psz+1, ntmp, sz );\n                            name[psz+sz+1] = '\\0';\n                        }\n                    }\n                    fclose( f );\n                }\n            }\n            else if( strcmp( ent->d_name, \"energy_uj\" ) == 0 )\n            {\n                char tmp[PATH_MAX];\n                snprintf( tmp, PATH_MAX, \"%s/energy_uj\", path );\n                handle = fopen( tmp, \"r\" );\n            }\n        }\n        if( name && handle && maxRange > 0 ) break;\n    }\n    if( name && handle && maxRange > 0 )\n    {\n        parent = (int)m_domains.size();\n        Domain* domain = m_domains.push_next();\n        domain->value = 0;\n        domain->overflow = maxRange;\n        domain->handle = handle;\n        domain->name = name;\n        TracyDebug( \"Power domain id %i, %s found at %s\\n\", parent, name, path );\n    }\n    else\n    {\n        if( name ) tracy_free( name );\n        if( handle ) fclose( handle );\n    }\n\n    rewinddir( dir );\n    while( ( ent = readdir( dir ) ) )\n    {\n        if( ent->d_type == DT_DIR && strncmp( ent->d_name, \"intel-rapl:\", 11 ) == 0 )\n        {\n            char tmp[PATH_MAX];\n            snprintf( tmp, PATH_MAX, \"%s/%s\", path, ent->d_name );\n            ScanDirectory( tmp, parent );\n        }\n    }\n    closedir( dir );\n}\n\n}\n\n#endif\n"
  },
  {
    "path": "tracy-client-sys/tracy/client/TracySysPower.hpp",
    "content": "#ifndef __TRACYSYSPOWER_HPP__\n#define __TRACYSYSPOWER_HPP__\n\n#if defined __linux__\n#  define TRACY_HAS_SYSPOWER\n#endif\n\n#ifdef TRACY_HAS_SYSPOWER\n\n#include <stdint.h>\n#include <stdio.h>\n\n#include \"TracyFastVector.hpp\"\n\nnamespace tracy\n{\n\nclass SysPower\n{\n    struct Domain\n    {\n        uint64_t value;\n        uint64_t overflow;\n        FILE* handle;\n        const char* name;\n    };\n\npublic:\n    SysPower();\n    ~SysPower();\n\n    void Tick();\n\nprivate:\n    void ScanDirectory( const char* path, int parent );\n\n    FastVector<Domain> m_domains;\n    uint64_t m_lastTime;\n};\n\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "tracy-client-sys/tracy/client/TracySysTime.cpp",
    "content": "#include \"TracySysTime.hpp\"\n\n#ifdef TRACY_HAS_SYSTIME\n\n#  if defined _WIN32\n#    include <windows.h>\n#    include \"../common/TracyWinFamily.hpp\"\n#  elif defined __linux__\n#    include <stdio.h>\n#    include <inttypes.h>\n#  elif defined __APPLE__\n#    include <mach/mach_host.h>\n#    include <mach/host_info.h>\n#  elif defined BSD\n#    include <sys/types.h>\n#    include <sys/sysctl.h>\n#  endif\n\nnamespace tracy\n{\n\n#  if defined _WIN32\n\nstatic inline uint64_t ConvertTime( const FILETIME& t )\n{\n    return ( uint64_t( t.dwHighDateTime ) << 32 ) | uint64_t( t.dwLowDateTime );\n}\n\nvoid SysTime::ReadTimes()\n{\n    FILETIME kernelTime;\n    FILETIME userTime;\n\n#    if defined TRACY_GDK\n    FILETIME creationTime;\n    FILETIME exitTime;\n\n    GetProcessTimes( GetCurrentProcess(), &creationTime, &exitTime, &kernelTime, &userTime );\n\n    idle = 0;\n#    else\n    FILETIME idleTime;\n\n    GetSystemTimes( &idleTime, &kernelTime, &userTime );\n\n    idle = ConvertTime( idleTime );\n#    endif\n\n    const auto kernel = ConvertTime( kernelTime );\n    const auto user = ConvertTime( userTime );\n    used = kernel + user;\n}\n\n#  elif defined __linux__\n\nvoid SysTime::ReadTimes()\n{\n    uint64_t user, nice, system;\n    FILE* f = fopen( \"/proc/stat\", \"r\" );\n    if( f )\n    {\n        int read = fscanf( f, \"cpu %\" PRIu64 \" %\" PRIu64 \" %\" PRIu64\" %\" PRIu64, &user, &nice, &system, &idle );\n        fclose( f );\n        if (read == 4)\n        {\n            used = user + nice + system;\n        }\n    }\n}\n\n#  elif defined __APPLE__\n\nvoid SysTime::ReadTimes()\n{\n    host_cpu_load_info_data_t info;\n    mach_msg_type_number_t cnt = HOST_CPU_LOAD_INFO_COUNT;\n    host_statistics( mach_host_self(), HOST_CPU_LOAD_INFO, reinterpret_cast<host_info_t>( &info ), &cnt );\n    used = info.cpu_ticks[CPU_STATE_USER] + info.cpu_ticks[CPU_STATE_NICE] + info.cpu_ticks[CPU_STATE_SYSTEM];\n    idle = info.cpu_ticks[CPU_STATE_IDLE];\n}\n\n#  elif defined BSD\n\nvoid SysTime::ReadTimes()\n{\n    u_long data[5];\n    size_t sz = sizeof( data );\n    sysctlbyname( \"kern.cp_time\", &data, &sz, nullptr, 0 );\n    used = data[0] + data[1] + data[2] + data[3];\n    idle = data[4];\n}\n\n#endif\n\nSysTime::SysTime()\n{\n    ReadTimes();\n}\n\nfloat SysTime::Get()\n{\n    const auto oldUsed = used;\n    const auto oldIdle = idle;\n\n    ReadTimes();\n\n    const auto diffIdle = idle - oldIdle;\n    const auto diffUsed = used - oldUsed;\n\n#if defined _WIN32\n    return diffUsed == 0 ? -1 : ( diffUsed - diffIdle ) * 100.f / diffUsed;\n#elif defined __linux__ || defined __APPLE__ || defined BSD\n    const auto total = diffUsed + diffIdle;\n    return total == 0 ? -1 : diffUsed * 100.f / total;\n#endif\n}\n\n}\n\n#endif\n"
  },
  {
    "path": "tracy-client-sys/tracy/client/TracySysTime.hpp",
    "content": "#ifndef __TRACYSYSTIME_HPP__\n#define __TRACYSYSTIME_HPP__\n\n#if defined _WIN32 || defined __linux__ || defined __APPLE__\n#  define TRACY_HAS_SYSTIME\n#else\n#  include <sys/param.h>\n#endif\n\n#ifdef BSD\n#  define TRACY_HAS_SYSTIME\n#endif\n\n#ifdef TRACY_HAS_SYSTIME\n\n#include <stdint.h>\n\nnamespace tracy\n{\n\nclass SysTime\n{\npublic:\n    SysTime();\n    float Get();\n\n    void ReadTimes();\n\nprivate:\n    uint64_t idle, used;\n};\n\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "tracy-client-sys/tracy/client/TracySysTrace.cpp",
    "content": "#include \"TracyDebug.hpp\"\n#include \"TracyStringHelpers.hpp\"\n#include \"TracySysTrace.hpp\"\n#include \"../common/TracySystem.hpp\"\n\n#ifdef TRACY_HAS_SYSTEM_TRACING\n\n#ifndef TRACY_SAMPLING_HZ\n#  if defined _WIN32\n#    define TRACY_SAMPLING_HZ 8000\n#  elif defined __linux__\n#    define TRACY_SAMPLING_HZ 10000\n#  endif\n#endif\n\nnamespace tracy\n{\n\nstatic int GetSamplingFrequency()\n{\n    int samplingHz = TRACY_SAMPLING_HZ;\n\n    auto env = GetEnvVar( \"TRACY_SAMPLING_HZ\" );\n    if( env )\n    {\n        int val = atoi( env );\n        if( val > 0 ) samplingHz = val;\n    }\n\n#if defined _WIN32\n    return samplingHz > 8000 ? 8000 : ( samplingHz < 1 ? 1 : samplingHz );\n#else\n    return samplingHz > 1000000 ? 1000000 : ( samplingHz < 1 ? 1 : samplingHz );\n#endif\n}\n\nstatic int GetSamplingPeriod()\n{\n    return 1000000000 / GetSamplingFrequency();\n}\n\n}\n\n#  if defined _WIN32\n\n#    ifndef NOMINMAX\n#      define NOMINMAX\n#    endif\n\n#    define INITGUID\n#    include <assert.h>\n#    include <string.h>\n#    include <windows.h>\n#    include <dbghelp.h>\n#    include <evntrace.h>\n#    include <evntcons.h>\n#    include <psapi.h>\n#    include <winternl.h>\n\n#    include \"../common/TracyAlloc.hpp\"\n#    include \"../common/TracySystem.hpp\"\n#    include \"TracyProfiler.hpp\"\n#    include \"TracyThread.hpp\"\n\nnamespace tracy\n{\n\nstatic const GUID PerfInfoGuid = { 0xce1dbfb4, 0x137e, 0x4da6, { 0x87, 0xb0, 0x3f, 0x59, 0xaa, 0x10, 0x2c, 0xbc } };\nstatic const GUID DxgKrnlGuid  = { 0x802ec45a, 0x1e99, 0x4b83, { 0x99, 0x20, 0x87, 0xc9, 0x82, 0x77, 0xba, 0x9d } };\nstatic const GUID ThreadV2Guid = { 0x3d6fa8d1, 0xfe05, 0x11d0, { 0x9d, 0xda, 0x00, 0xc0, 0x4f, 0xd7, 0xba, 0x7c } };\n\n\nstatic TRACEHANDLE s_traceHandle;\nstatic TRACEHANDLE s_traceHandle2;\nstatic EVENT_TRACE_PROPERTIES* s_prop;\nstatic DWORD s_pid;\n\nstatic EVENT_TRACE_PROPERTIES* s_propVsync;\nstatic TRACEHANDLE s_traceHandleVsync;\nstatic TRACEHANDLE s_traceHandleVsync2;\nThread* s_threadVsync = nullptr;\n\nstruct CSwitch\n{\n    uint32_t    newThreadId;\n    uint32_t    oldThreadId;\n    int8_t      newThreadPriority;\n    int8_t      oldThreadPriority;\n    uint8_t     previousCState;\n    int8_t      spareByte;\n    int8_t      oldThreadWaitReason;\n    int8_t      oldThreadWaitMode;\n    int8_t      oldThreadState;\n    int8_t      oldThreadWaitIdealProcessor;\n    uint32_t    newThreadWaitTime;\n    uint32_t    reserved;\n};\n\nstruct ReadyThread\n{\n    uint32_t    threadId;\n    int8_t      adjustReason;\n    int8_t      adjustIncrement;\n    int8_t      flag;\n    int8_t      reserverd;\n};\n\nstruct ThreadTrace\n{\n    uint32_t processId;\n    uint32_t threadId;\n    uint32_t stackBase;\n    uint32_t stackLimit;\n    uint32_t userStackBase;\n    uint32_t userStackLimit;\n    uint32_t startAddr;\n    uint32_t win32StartAddr;\n    uint32_t tebBase;\n    uint32_t subProcessTag;\n};\n\nstruct StackWalkEvent\n{\n    uint64_t eventTimeStamp;\n    uint32_t stackProcess;\n    uint32_t stackThread;\n    uint64_t stack[192];\n};\n\nstruct VSyncInfo\n{\n    void*       dxgAdapter;\n    uint32_t    vidPnTargetId;\n    uint64_t    scannedPhysicalAddress;\n    uint32_t    vidPnSourceId;\n    uint32_t    frameNumber;\n    int64_t     frameQpcTime;\n    void*       hFlipDevice;\n    uint32_t    flipType;\n    uint64_t    flipFenceId;\n};\n\nextern \"C\" typedef NTSTATUS (WINAPI *t_NtQueryInformationThread)( HANDLE, THREADINFOCLASS, PVOID, ULONG, PULONG );\nextern \"C\" typedef BOOL (WINAPI *t_EnumProcessModules)( HANDLE, HMODULE*, DWORD, LPDWORD );\nextern \"C\" typedef BOOL (WINAPI *t_GetModuleInformation)( HANDLE, HMODULE, LPMODULEINFO, DWORD );\nextern \"C\" typedef DWORD (WINAPI *t_GetModuleBaseNameA)( HANDLE, HMODULE, LPSTR, DWORD );\nextern \"C\" typedef HRESULT (WINAPI *t_GetThreadDescription)( HANDLE, PWSTR* );\n\nt_NtQueryInformationThread NtQueryInformationThread = (t_NtQueryInformationThread)GetProcAddress( GetModuleHandleA( \"ntdll.dll\" ), \"NtQueryInformationThread\" );\nt_EnumProcessModules _EnumProcessModules = (t_EnumProcessModules)GetProcAddress( GetModuleHandleA( \"kernel32.dll\" ), \"K32EnumProcessModules\" );\nt_GetModuleInformation _GetModuleInformation = (t_GetModuleInformation)GetProcAddress( GetModuleHandleA( \"kernel32.dll\" ), \"K32GetModuleInformation\" );\nt_GetModuleBaseNameA _GetModuleBaseNameA = (t_GetModuleBaseNameA)GetProcAddress( GetModuleHandleA( \"kernel32.dll\" ), \"K32GetModuleBaseNameA\" );\n\nstatic t_GetThreadDescription _GetThreadDescription = 0;\n\n\nvoid WINAPI EventRecordCallback( PEVENT_RECORD record )\n{\n#ifdef TRACY_ON_DEMAND\n    if( !GetProfiler().IsConnected() ) return;\n#endif\n\n    const auto& hdr = record->EventHeader;\n    switch( hdr.ProviderId.Data1 )\n    {\n    case 0x3d6fa8d1:    // Thread Guid\n        if( hdr.EventDescriptor.Opcode == 36 )\n        {\n            const auto cswitch = (const CSwitch*)record->UserData;\n\n            TracyLfqPrepare( QueueType::ContextSwitch );\n            MemWrite( &item->contextSwitch.time, hdr.TimeStamp.QuadPart );\n            MemWrite( &item->contextSwitch.oldThread, cswitch->oldThreadId );\n            MemWrite( &item->contextSwitch.newThread, cswitch->newThreadId );\n            MemWrite( &item->contextSwitch.cpu, record->BufferContext.ProcessorNumber );\n            MemWrite( &item->contextSwitch.oldThreadWaitReason, cswitch->oldThreadWaitReason );\n            MemWrite( &item->contextSwitch.oldThreadState, cswitch->oldThreadState );\n            MemWrite( &item->contextSwitch.newThreadPriority, cswitch->newThreadPriority );\n            MemWrite( &item->contextSwitch.oldThreadPriority, cswitch->oldThreadPriority );\n            MemWrite( &item->contextSwitch.previousCState, cswitch->previousCState );\n            TracyLfqCommit;\n        }\n        else if( hdr.EventDescriptor.Opcode == 50 )\n        {\n            const auto rt = (const ReadyThread*)record->UserData;\n\n            TracyLfqPrepare( QueueType::ThreadWakeup );\n            MemWrite( &item->threadWakeup.time, hdr.TimeStamp.QuadPart );\n            MemWrite( &item->threadWakeup.cpu, record->BufferContext.ProcessorNumber );\n            MemWrite( &item->threadWakeup.thread, rt->threadId );\n            MemWrite( &item->threadWakeup.adjustReason, rt->adjustReason );\n            MemWrite( &item->threadWakeup.adjustIncrement, rt->adjustIncrement );\n            TracyLfqCommit;\n        }\n        else if( hdr.EventDescriptor.Opcode == 1 || hdr.EventDescriptor.Opcode == 3 )\n        {\n            const auto tt = (const ThreadTrace*)record->UserData;\n\n            uint64_t tid = tt->threadId;\n            if( tid == 0 ) return;\n            uint64_t pid = tt->processId;\n            TracyLfqPrepare( QueueType::TidToPid );\n            MemWrite( &item->tidToPid.tid, tid );\n            MemWrite( &item->tidToPid.pid, pid );\n            TracyLfqCommit;\n        }\n        break;\n    case 0xdef2fe46:    // StackWalk Guid\n        if( hdr.EventDescriptor.Opcode == 32 )\n        {\n            const auto sw = (const StackWalkEvent*)record->UserData;\n            if( sw->stackProcess == s_pid )\n            {\n                const uint64_t sz = ( record->UserDataLength - 16 ) / 8;\n                if( sz > 0 )\n                {\n                    auto trace = (uint64_t*)tracy_malloc( ( 1 + sz ) * sizeof( uint64_t ) );\n                    memcpy( trace, &sz, sizeof( uint64_t ) );\n                    memcpy( trace+1, sw->stack, sizeof( uint64_t ) * sz );\n                    TracyLfqPrepare( QueueType::CallstackSample );\n                    MemWrite( &item->callstackSampleFat.time, sw->eventTimeStamp );\n                    MemWrite( &item->callstackSampleFat.thread, sw->stackThread );\n                    MemWrite( &item->callstackSampleFat.ptr, (uint64_t)trace );\n                    TracyLfqCommit;\n                }\n            }\n        }\n        break;\n    default:\n        break;\n    }\n}\n\nvoid WINAPI EventRecordCallbackVsync( PEVENT_RECORD record )\n{\n#ifdef TRACY_ON_DEMAND\n    if( !GetProfiler().IsConnected() ) return;\n#endif\n\n    const auto& hdr = record->EventHeader;\n\n    // Check for Lost_Event (6a399ae0-4bc6-4de9-870b-3657f8947e7e)\n    if( hdr.ProviderId.Data1 == 0x6A399AE0 ) return;\n\n    assert( hdr.ProviderId.Data1 == 0x802EC45A );\n    assert( hdr.EventDescriptor.Id == 0x0011 );\n\n    const auto vs = (const VSyncInfo*)record->UserData;\n\n    TracyLfqPrepare( QueueType::FrameVsync );\n    MemWrite( &item->frameVsync.time, hdr.TimeStamp.QuadPart );\n    MemWrite( &item->frameVsync.id, vs->vidPnTargetId );\n    TracyLfqCommit;\n}\n\nstatic void SetupVsync()\n{\n#if _WIN32_WINNT >= _WIN32_WINNT_WINBLUE && !defined(__MINGW32__)\n    const auto psz = sizeof( EVENT_TRACE_PROPERTIES ) + MAX_PATH;\n    s_propVsync = (EVENT_TRACE_PROPERTIES*)tracy_malloc( psz );\n    memset( s_propVsync, 0, sizeof( EVENT_TRACE_PROPERTIES ) );\n    s_propVsync->LogFileMode = EVENT_TRACE_REAL_TIME_MODE;\n    s_propVsync->Wnode.BufferSize = psz;\n#ifdef TRACY_TIMER_QPC\n    s_propVsync->Wnode.ClientContext = 1;\n#else\n    s_propVsync->Wnode.ClientContext = 3;\n#endif\n    s_propVsync->LoggerNameOffset = sizeof( EVENT_TRACE_PROPERTIES );\n    strcpy( ((char*)s_propVsync) + sizeof( EVENT_TRACE_PROPERTIES ), \"TracyVsync\" );\n\n    auto backup = tracy_malloc( psz );\n    memcpy( backup, s_propVsync, psz );\n\n    const auto controlStatus = ControlTraceA( 0, \"TracyVsync\", s_propVsync, EVENT_TRACE_CONTROL_STOP );\n    if( controlStatus != ERROR_SUCCESS && controlStatus != ERROR_WMI_INSTANCE_NOT_FOUND )\n    {\n        tracy_free( backup );\n        tracy_free( s_propVsync );\n        return;\n    }\n\n    memcpy( s_propVsync, backup, psz );\n    tracy_free( backup );\n\n    const auto startStatus = StartTraceA( &s_traceHandleVsync, \"TracyVsync\", s_propVsync );\n    if( startStatus != ERROR_SUCCESS )\n    {\n        tracy_free( s_propVsync );\n        return;\n    }\n\n    EVENT_FILTER_EVENT_ID fe = {};\n    fe.FilterIn = TRUE;\n    fe.Count = 1;\n    fe.Events[0] = 0x0011;  // VSyncDPC_Info\n\n    EVENT_FILTER_DESCRIPTOR desc = {};\n    desc.Ptr = (ULONGLONG)&fe;\n    desc.Size = sizeof( fe );\n    desc.Type = EVENT_FILTER_TYPE_EVENT_ID;\n\n    ENABLE_TRACE_PARAMETERS params = {};\n    params.Version = ENABLE_TRACE_PARAMETERS_VERSION_2;\n    params.EnableProperty = EVENT_ENABLE_PROPERTY_IGNORE_KEYWORD_0;\n    params.SourceId = s_propVsync->Wnode.Guid;\n    params.EnableFilterDesc = &desc;\n    params.FilterDescCount = 1;\n\n    uint64_t mask = 0x4000000000000001;   // Microsoft_Windows_DxgKrnl_Performance | Base\n    if( EnableTraceEx2( s_traceHandleVsync, &DxgKrnlGuid, EVENT_CONTROL_CODE_ENABLE_PROVIDER, TRACE_LEVEL_INFORMATION, mask, mask, 0, &params ) != ERROR_SUCCESS )\n    {\n        tracy_free( s_propVsync );\n        return;\n    }\n\n    char loggerName[MAX_PATH];\n    strcpy( loggerName, \"TracyVsync\" );\n\n    EVENT_TRACE_LOGFILEA log = {};\n    log.LoggerName = loggerName;\n    log.ProcessTraceMode = PROCESS_TRACE_MODE_REAL_TIME | PROCESS_TRACE_MODE_EVENT_RECORD | PROCESS_TRACE_MODE_RAW_TIMESTAMP;\n    log.EventRecordCallback = EventRecordCallbackVsync;\n\n    s_traceHandleVsync2 = OpenTraceA( &log );\n    if( s_traceHandleVsync2 == (TRACEHANDLE)INVALID_HANDLE_VALUE )\n    {\n        CloseTrace( s_traceHandleVsync );\n        tracy_free( s_propVsync );\n        return;\n    }\n\n    s_threadVsync = (Thread*)tracy_malloc( sizeof( Thread ) );\n    new(s_threadVsync) Thread( [] (void*) {\n        ThreadExitHandler threadExitHandler;\n        SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL );\n        SetThreadName( \"Tracy Vsync\" );\n        ProcessTrace( &s_traceHandleVsync2, 1, nullptr, nullptr );\n    }, nullptr );\n#endif\n}\n\nstatic int GetSamplingInterval()\n{\n    return GetSamplingPeriod() / 100;\n}\n\nbool SysTraceStart( int64_t& samplingPeriod )\n{\n    if( !_GetThreadDescription ) _GetThreadDescription = (t_GetThreadDescription)GetProcAddress( GetModuleHandleA( \"kernel32.dll\" ), \"GetThreadDescription\" );\n\n    s_pid = GetCurrentProcessId();\n\n#if defined _WIN64\n    constexpr bool isOs64Bit = true;\n#else\n    BOOL _iswow64;\n    IsWow64Process( GetCurrentProcess(), &_iswow64 );\n    const bool isOs64Bit = _iswow64;\n#endif\n\n    TOKEN_PRIVILEGES priv = {};\n    priv.PrivilegeCount = 1;\n    priv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;\n    if( LookupPrivilegeValue( nullptr, SE_SYSTEM_PROFILE_NAME, &priv.Privileges[0].Luid ) == 0 ) return false;\n\n    HANDLE pt;\n    if( OpenProcessToken( GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &pt ) == 0 ) return false;\n    const auto adjust = AdjustTokenPrivileges( pt, FALSE, &priv, 0, nullptr, nullptr );\n    CloseHandle( pt );\n    if( adjust == 0 ) return false;\n    const auto status = GetLastError();\n    if( status != ERROR_SUCCESS ) return false;\n\n    if( isOs64Bit )\n    {\n        TRACE_PROFILE_INTERVAL interval = {};\n        interval.Interval = GetSamplingInterval();\n        const auto intervalStatus = TraceSetInformation( 0, TraceSampledProfileIntervalInfo, &interval, sizeof( interval ) );\n        if( intervalStatus != ERROR_SUCCESS ) return false;\n        samplingPeriod = GetSamplingPeriod();\n    }\n\n    const auto psz = sizeof( EVENT_TRACE_PROPERTIES ) + sizeof( KERNEL_LOGGER_NAME );\n    s_prop = (EVENT_TRACE_PROPERTIES*)tracy_malloc( psz );\n    memset( s_prop, 0, sizeof( EVENT_TRACE_PROPERTIES ) );\n    ULONG flags = 0;\n#ifndef TRACY_NO_CONTEXT_SWITCH\n    flags = EVENT_TRACE_FLAG_CSWITCH | EVENT_TRACE_FLAG_DISPATCHER | EVENT_TRACE_FLAG_THREAD;\n#endif\n#ifndef TRACY_NO_SAMPLING\n    if( isOs64Bit ) flags |= EVENT_TRACE_FLAG_PROFILE;\n#endif\n    s_prop->EnableFlags = flags;\n    s_prop->LogFileMode = EVENT_TRACE_REAL_TIME_MODE;\n    s_prop->Wnode.BufferSize = psz;\n    s_prop->Wnode.Flags = WNODE_FLAG_TRACED_GUID;\n#ifdef TRACY_TIMER_QPC\n    s_prop->Wnode.ClientContext = 1;\n#else\n    s_prop->Wnode.ClientContext = 3;\n#endif\n    s_prop->Wnode.Guid = SystemTraceControlGuid;\n    s_prop->BufferSize = 1024;\n    s_prop->MinimumBuffers = std::thread::hardware_concurrency() * 4;\n    s_prop->MaximumBuffers = std::thread::hardware_concurrency() * 6;\n    s_prop->LoggerNameOffset = sizeof( EVENT_TRACE_PROPERTIES );\n    memcpy( ((char*)s_prop) + sizeof( EVENT_TRACE_PROPERTIES ), KERNEL_LOGGER_NAME, sizeof( KERNEL_LOGGER_NAME ) );\n\n    auto backup = tracy_malloc( psz );\n    memcpy( backup, s_prop, psz );\n\n    const auto controlStatus = ControlTrace( 0, KERNEL_LOGGER_NAME, s_prop, EVENT_TRACE_CONTROL_STOP );\n    if( controlStatus != ERROR_SUCCESS && controlStatus != ERROR_WMI_INSTANCE_NOT_FOUND )\n    {\n        tracy_free( backup );\n        tracy_free( s_prop );\n        return false;\n    }\n\n    memcpy( s_prop, backup, psz );\n    tracy_free( backup );\n\n    const auto startStatus = StartTrace( &s_traceHandle, KERNEL_LOGGER_NAME, s_prop );\n    if( startStatus != ERROR_SUCCESS )\n    {\n        tracy_free( s_prop );\n        return false;\n    }\n\n#ifndef TRACY_NO_SAMPLING\n    if( isOs64Bit )\n    {\n        CLASSIC_EVENT_ID stackId[2] = {};\n        stackId[0].EventGuid = PerfInfoGuid;\n        stackId[0].Type = 46;\n        stackId[1].EventGuid = ThreadV2Guid;\n        stackId[1].Type = 36;\n        const auto stackStatus = TraceSetInformation( s_traceHandle, TraceStackTracingInfo, &stackId, sizeof( stackId ) );\n        if( stackStatus != ERROR_SUCCESS )\n        {\n            tracy_free( s_prop );\n            return false;\n        }\n    }\n#endif\n\n#ifdef UNICODE\n    WCHAR KernelLoggerName[sizeof( KERNEL_LOGGER_NAME )];\n#else\n    char KernelLoggerName[sizeof( KERNEL_LOGGER_NAME )];\n#endif\n    memcpy( KernelLoggerName, KERNEL_LOGGER_NAME, sizeof( KERNEL_LOGGER_NAME ) );\n    EVENT_TRACE_LOGFILE log = {};\n    log.LoggerName = KernelLoggerName;\n    log.ProcessTraceMode = PROCESS_TRACE_MODE_REAL_TIME | PROCESS_TRACE_MODE_EVENT_RECORD | PROCESS_TRACE_MODE_RAW_TIMESTAMP;\n    log.EventRecordCallback = EventRecordCallback;\n\n    s_traceHandle2 = OpenTrace( &log );\n    if( s_traceHandle2 == (TRACEHANDLE)INVALID_HANDLE_VALUE )\n    {\n        CloseTrace( s_traceHandle );\n        tracy_free( s_prop );\n        return false;\n    }\n\n#ifndef TRACY_NO_VSYNC_CAPTURE\n    SetupVsync();\n#endif\n\n    return true;\n}\n\nvoid SysTraceStop()\n{\n    if( s_threadVsync )\n    {\n        CloseTrace( s_traceHandleVsync2 );\n        CloseTrace( s_traceHandleVsync );\n        s_threadVsync->~Thread();\n        tracy_free( s_threadVsync );\n    }\n\n    CloseTrace( s_traceHandle2 );\n    CloseTrace( s_traceHandle );\n}\n\nvoid SysTraceWorker( void* ptr )\n{\n    ThreadExitHandler threadExitHandler;\n    SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL );\n    SetThreadName( \"Tracy SysTrace\" );\n    ProcessTrace( &s_traceHandle2, 1, 0, 0 );\n    ControlTrace( 0, KERNEL_LOGGER_NAME, s_prop, EVENT_TRACE_CONTROL_STOP );\n    tracy_free( s_prop );\n}\n\nvoid SysTraceGetExternalName( uint64_t thread, const char*& threadName, const char*& name )\n{\n    bool threadSent = false;\n    auto hnd = OpenThread( THREAD_QUERY_INFORMATION, FALSE, DWORD( thread ) );\n    if( hnd == 0 )\n    {\n        hnd = OpenThread( THREAD_QUERY_LIMITED_INFORMATION, FALSE, DWORD( thread ) );\n    }\n    if( hnd != 0 )\n    {\n        if( _GetThreadDescription )\n        {\n            PWSTR tmp;\n            if ( SUCCEEDED( _GetThreadDescription( hnd, &tmp ) ) )\n            {\n                char buf[256];\n                auto ret = wcstombs( buf, tmp, 256 );\n                LocalFree(tmp);\n                if( ret != 0 )\n                {\n                    threadName = CopyString( buf, ret );\n                    threadSent = true;\n                }\n            }\n        }\n        const auto pid = GetProcessIdOfThread( hnd );\n        if( !threadSent && NtQueryInformationThread && _EnumProcessModules && _GetModuleInformation && _GetModuleBaseNameA )\n        {\n            void* ptr;\n            ULONG retlen;\n            auto status = NtQueryInformationThread( hnd, (THREADINFOCLASS)9 /*ThreadQuerySetWin32StartAddress*/, &ptr, sizeof( &ptr ), &retlen );\n            if( status == 0 )\n            {\n                const auto phnd = OpenProcess( PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid );\n                if( phnd != INVALID_HANDLE_VALUE )\n                {\n                    MEMORY_BASIC_INFORMATION vmeminfo;\n                    SIZE_T infosize = VirtualQueryEx( phnd, ptr, &vmeminfo, sizeof( vmeminfo ) );\n                    if( infosize == sizeof( vmeminfo ) )\n                    {\n                        if (vmeminfo.Type == MEM_IMAGE)\n                        {\n                            // for MEM_IMAGE regions, vmeminfo.AllocationBase _is_ the HMODULE\n                            HMODULE mod = (HMODULE)vmeminfo.AllocationBase;\n                            MODULEINFO info;\n                            if( _GetModuleInformation( phnd, mod, &info, sizeof( info ) ) != 0 )\n                            {\n                                char buf2[1024];\n                                const auto modlen = _GetModuleBaseNameA( phnd, mod, buf2, 1024 );\n                                if( modlen != 0 )\n                                {\n                                    threadName = CopyString( buf2, modlen );\n                                    threadSent = true;\n                                }\n                            }\n                        }\n                    }\n                    CloseHandle( phnd );\n                }\n            }\n        }\n        CloseHandle( hnd );\n        if( !threadSent )\n        {\n            threadName = CopyString( \"???\", 3 );\n            threadSent = true;\n        }\n        if( pid != 0 )\n        {\n            {\n                uint64_t _pid = pid;\n                TracyLfqPrepare( QueueType::TidToPid );\n                MemWrite( &item->tidToPid.tid, thread );\n                MemWrite( &item->tidToPid.pid, _pid );\n                TracyLfqCommit;\n            }\n            if( pid == 4 )\n            {\n                name = CopyStringFast( \"System\", 6 );\n                return;\n            }\n            else\n            {\n                const auto phnd = OpenProcess( PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid );\n                if( phnd != INVALID_HANDLE_VALUE )\n                {\n                    char buf2[1024];\n                    const auto sz = GetProcessImageFileNameA( phnd, buf2, 1024 );\n                    CloseHandle( phnd );\n                    if( sz != 0 )\n                    {\n                        auto ptr = buf2 + sz - 1;\n                        while( ptr > buf2 && *ptr != '\\\\' ) ptr--;\n                        if( *ptr == '\\\\' ) ptr++;\n                        name = CopyStringFast( ptr );\n                        return;\n                    }\n                }\n            }\n        }\n    }\n\n    if( !threadSent )\n    {\n        threadName = CopyString( \"???\", 3 );\n    }\n    name = CopyStringFast( \"???\", 3 );\n}\n\n}\n\n#  elif defined __linux__\n\n#    include <sys/types.h>\n#    include <sys/stat.h>\n#    include <sys/wait.h>\n#    include <fcntl.h>\n#    include <inttypes.h>\n#    include <limits>\n#    include <mntent.h>\n#    include <poll.h>\n#    include <stdio.h>\n#    include <stdlib.h>\n#    include <string.h>\n#    include <unistd.h>\n#    include <atomic>\n#    include <thread>\n#    include <linux/perf_event.h>\n#    include <linux/version.h>\n#    include <sys/mman.h>\n#    include <sys/ioctl.h>\n#    include <sys/syscall.h>\n\n#    if defined __i386 || defined __x86_64__\n#      include \"TracyCpuid.hpp\"\n#    endif\n\n#    include \"TracyProfiler.hpp\"\n#    include \"TracyRingBuffer.hpp\"\n#    include \"TracyThread.hpp\"\n\nnamespace tracy\n{\n\nstatic std::atomic<bool> traceActive { false };\nstatic int s_numCpus = 0;\nstatic int s_numBuffers = 0;\nstatic int s_ctxBufferIdx = 0;\n\nstatic RingBuffer* s_ring = nullptr;\n\nstatic const int ThreadHashSize = 4 * 1024;\nstatic uint32_t s_threadHash[ThreadHashSize] = {};\n\nstatic bool CurrentProcOwnsThread( uint32_t tid )\n{\n    const auto hash = tid & ( ThreadHashSize-1 );\n    const auto hv = s_threadHash[hash];\n    if( hv == tid ) return true;\n    if( hv == -tid ) return false;\n\n    char path[256];\n    sprintf( path, \"/proc/self/task/%d\", tid );\n    struct stat st;\n    if( stat( path, &st ) == 0 )\n    {\n        s_threadHash[hash] = tid;\n        return true;\n    }\n    else\n    {\n        s_threadHash[hash] = -tid;\n        return false;\n    }\n}\n\nstatic int perf_event_open( struct perf_event_attr* hw_event, pid_t pid, int cpu, int group_fd, unsigned long flags )\n{\n    return syscall( __NR_perf_event_open, hw_event, pid, cpu, group_fd, flags );\n}\n\nenum TraceEventId\n{\n    EventCallstack,\n    EventCpuCycles,\n    EventInstructionsRetired,\n    EventCacheReference,\n    EventCacheMiss,\n    EventBranchRetired,\n    EventBranchMiss,\n    EventVsync,\n    EventContextSwitch,\n    EventWaking,\n};\n\nstatic void ProbePreciseIp( perf_event_attr& pe, unsigned long long config0, unsigned long long config1, pid_t pid )\n{\n    pe.config = config1;\n    pe.precise_ip = 3;\n    while( pe.precise_ip != 0 )\n    {\n        const int fd = perf_event_open( &pe, pid, 0, -1, PERF_FLAG_FD_CLOEXEC );\n        if( fd != -1 )\n        {\n            close( fd );\n            break;\n        }\n        pe.precise_ip--;\n    }\n    pe.config = config0;\n    while( pe.precise_ip != 0 )\n    {\n        const int fd = perf_event_open( &pe, pid, 0, -1, PERF_FLAG_FD_CLOEXEC );\n        if( fd != -1 )\n        {\n            close( fd );\n            break;\n        }\n        pe.precise_ip--;\n    }\n    TracyDebug( \"  Probed precise_ip: %i\\n\", pe.precise_ip );\n}\n\nstatic void ProbePreciseIp( perf_event_attr& pe, pid_t pid )\n{\n    pe.precise_ip = 3;\n    while( pe.precise_ip != 0 )\n    {\n        const int fd = perf_event_open( &pe, pid, 0, -1, PERF_FLAG_FD_CLOEXEC );\n        if( fd != -1 )\n        {\n            close( fd );\n            break;\n        }\n        pe.precise_ip--;\n    }\n    TracyDebug( \"  Probed precise_ip: %i\\n\", pe.precise_ip );\n}\n\nstatic bool IsGenuineIntel()\n{\n#if defined __i386 || defined __x86_64__\n    uint32_t regs[4] = {};\n    __get_cpuid( 0, regs, regs+1, regs+2, regs+3 );\n    char manufacturer[12];\n    memcpy( manufacturer, regs+1, 4 );\n    memcpy( manufacturer+4, regs+3, 4 );\n    memcpy( manufacturer+8, regs+2, 4 );\n    return memcmp( manufacturer, \"GenuineIntel\", 12 ) == 0;\n#else\n    return false;\n#endif\n}\n\nstatic const char* ReadFile( const char* path )\n{\n    int fd = open( path, O_RDONLY );\n    if( fd < 0 ) return nullptr;\n\n    static char tmp[64];\n    const auto cnt = read( fd, tmp, 63 );\n    close( fd );\n    if( cnt < 0 ) return nullptr;\n    tmp[cnt] = '\\0';\n    return tmp;\n}\n\nstatic const char* ReadFile( const char* base, const char* path )\n{\n    const auto blen = strlen( base );\n    const auto plen = strlen( path );\n\n    auto tmp = (char*)tracy_malloc( blen + plen + 1 );\n    memcpy( tmp, base, blen );\n    memcpy( tmp + blen, path, plen );\n    tmp[blen+plen] = '\\0';\n\n    auto res = ReadFile( tmp );\n    tracy_free( tmp );\n    return res;\n}\n\nstatic char* GetTraceFsPath()\n{\n    auto f = setmntent( \"/proc/mounts\", \"r\" );\n    if( !f ) return nullptr;\n\n    char* ret = nullptr;\n    while( auto ent = getmntent( f ) )\n    {\n        if( strcmp( ent->mnt_fsname, \"tracefs\" ) == 0 )\n        {\n            auto len = strlen( ent->mnt_dir );\n            ret = (char*)tracy_malloc( len + 1 );\n            memcpy( ret, ent->mnt_dir, len );\n            ret[len] = '\\0';\n            break;\n        }\n    }\n    endmntent( f );\n    return ret;\n}\n\nbool SysTraceStart( int64_t& samplingPeriod )\n{\n#ifndef CLOCK_MONOTONIC_RAW\n    return false;\n#endif\n\n    const auto paranoidLevelStr = ReadFile( \"/proc/sys/kernel/perf_event_paranoid\" );\n    if( !paranoidLevelStr ) return false;\n#ifdef TRACY_VERBOSE\n    int paranoidLevel = 2;\n    paranoidLevel = atoi( paranoidLevelStr );\n    TracyDebug( \"perf_event_paranoid: %i\\n\", paranoidLevel );\n#endif\n\n    auto traceFsPath = GetTraceFsPath();\n    if( !traceFsPath ) return false;\n    TracyDebug( \"tracefs path: %s\\n\", traceFsPath );\n\n    int switchId = -1, wakingId = -1, vsyncId = -1;\n    const auto switchIdStr = ReadFile( traceFsPath, \"/events/sched/sched_switch/id\" );\n    if( switchIdStr ) switchId = atoi( switchIdStr );\n    const auto wakingIdStr = ReadFile( traceFsPath, \"/events/sched/sched_waking/id\" );\n    if( wakingIdStr ) wakingId = atoi( wakingIdStr );\n    const auto vsyncIdStr = ReadFile( traceFsPath, \"/events/drm/drm_vblank_event/id\" );\n    if( vsyncIdStr ) vsyncId = atoi( vsyncIdStr );\n\n    tracy_free( traceFsPath );\n\n    TracyDebug( \"sched_switch id: %i\\n\", switchId );\n    TracyDebug( \"sched_waking id: %i\\n\", wakingId );\n    TracyDebug( \"drm_vblank_event id: %i\\n\", vsyncId );\n\n#ifdef TRACY_NO_SAMPLING\n    const bool noSoftwareSampling = true;\n#else\n    const char* noSoftwareSamplingEnv = GetEnvVar( \"TRACY_NO_SAMPLING\" );\n    const bool noSoftwareSampling = noSoftwareSamplingEnv && noSoftwareSamplingEnv[0] == '1';\n#endif\n\n#ifdef TRACY_NO_SAMPLE_RETIREMENT\n    const bool noRetirement = true;\n#else\n    const char* noRetirementEnv = GetEnvVar( \"TRACY_NO_SAMPLE_RETIREMENT\" );\n    const bool noRetirement = noRetirementEnv && noRetirementEnv[0] == '1';\n#endif\n\n#ifdef TRACY_NO_SAMPLE_CACHE\n    const bool noCache = true;\n#else\n    const char* noCacheEnv = GetEnvVar( \"TRACY_NO_SAMPLE_CACHE\" );\n    const bool noCache = noCacheEnv && noCacheEnv[0] == '1';\n#endif\n\n#ifdef TRACY_NO_SAMPLE_BRANCH\n    const bool noBranch = true;\n#else\n    const char* noBranchEnv = GetEnvVar( \"TRACY_NO_SAMPLE_BRANCH\" );\n    const bool noBranch = noBranchEnv && noBranchEnv[0] == '1';\n#endif\n\n#ifdef TRACY_NO_CONTEXT_SWITCH\n    const bool noCtxSwitch = true;\n#else\n    const char* noCtxSwitchEnv = GetEnvVar( \"TRACY_NO_CONTEXT_SWITCH\" );\n    const bool noCtxSwitch = noCtxSwitchEnv && noCtxSwitchEnv[0] == '1';\n#endif\n\n#ifdef TRACY_NO_VSYNC_CAPTURE\n    const bool noVsync = true;\n#else\n    const char* noVsyncEnv = GetEnvVar( \"TRACY_NO_VSYNC_CAPTURE\" );\n    const bool noVsync = noVsyncEnv && noVsyncEnv[0] == '1';\n#endif\n\n    samplingPeriod = GetSamplingPeriod();\n    uint32_t currentPid = (uint32_t)getpid();\n\n    s_numCpus = (int)std::thread::hardware_concurrency();\n\n    const auto maxNumBuffers = s_numCpus * (\n        1 +     // software sampling\n        2 +     // CPU cycles + instructions retired\n        2 +     // cache reference + miss\n        2 +     // branch retired + miss\n        2 +     // context switches + waking ups\n        1       // vsync\n    );\n    s_ring = (RingBuffer*)tracy_malloc( sizeof( RingBuffer ) * maxNumBuffers );\n    s_numBuffers = 0;\n\n    // software sampling\n    perf_event_attr pe = {};\n    pe.type = PERF_TYPE_SOFTWARE;\n    pe.size = sizeof( perf_event_attr );\n    pe.config = PERF_COUNT_SW_CPU_CLOCK;\n    pe.sample_freq = GetSamplingFrequency();\n    pe.sample_type = PERF_SAMPLE_TID | PERF_SAMPLE_TIME | PERF_SAMPLE_CALLCHAIN;\n#if LINUX_VERSION_CODE >= KERNEL_VERSION( 4, 8, 0 )\n    pe.sample_max_stack = 127;\n#endif\n    pe.disabled = 1;\n    pe.freq = 1;\n    pe.inherit = 1;\n#if !defined TRACY_HW_TIMER || !( defined __i386 || defined _M_IX86 || defined __x86_64__ || defined _M_X64 )\n    pe.use_clockid = 1;\n    pe.clockid = CLOCK_MONOTONIC_RAW;\n#endif\n\n    if( !noSoftwareSampling )\n    {\n        TracyDebug( \"Setup software sampling\\n\" );\n        ProbePreciseIp( pe, currentPid );\n        for( int i=0; i<s_numCpus; i++ )\n        {\n            int fd = perf_event_open( &pe, currentPid, i, -1, PERF_FLAG_FD_CLOEXEC );\n            if( fd == -1 )\n            {\n                pe.exclude_kernel = 1;\n                ProbePreciseIp( pe, currentPid );\n                fd = perf_event_open( &pe, currentPid, i, -1, PERF_FLAG_FD_CLOEXEC );\n                if( fd == -1 )\n                {\n                    TracyDebug( \"  Failed to setup!\\n\");\n                    break;\n                }\n                TracyDebug( \"  No access to kernel samples\\n\" );\n            }\n            new( s_ring+s_numBuffers ) RingBuffer( 64*1024, fd, EventCallstack );\n            if( s_ring[s_numBuffers].IsValid() )\n            {\n                s_numBuffers++;\n                TracyDebug( \"  Core %i ok\\n\", i );\n            }\n        }\n    }\n\n    // CPU cycles + instructions retired\n    pe = {};\n    pe.type = PERF_TYPE_HARDWARE;\n    pe.size = sizeof( perf_event_attr );\n    pe.sample_freq = 5000;\n    pe.sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TIME;\n    pe.disabled = 1;\n    pe.exclude_kernel = 1;\n    pe.exclude_guest = 1;\n    pe.exclude_hv = 1;\n    pe.freq = 1;\n    pe.inherit = 1;\n#if !defined TRACY_HW_TIMER || !( defined __i386 || defined _M_IX86 || defined __x86_64__ || defined _M_X64 )\n    pe.use_clockid = 1;\n    pe.clockid = CLOCK_MONOTONIC_RAW;\n#endif\n\n    if( !noRetirement )\n    {\n        TracyDebug( \"Setup sampling cycles + retirement\\n\" );\n        ProbePreciseIp( pe, PERF_COUNT_HW_CPU_CYCLES, PERF_COUNT_HW_INSTRUCTIONS, currentPid );\n        for( int i=0; i<s_numCpus; i++ )\n        {\n            const int fd = perf_event_open( &pe, currentPid, i, -1, PERF_FLAG_FD_CLOEXEC );\n            if( fd != -1 )\n            {\n                new( s_ring+s_numBuffers ) RingBuffer( 64*1024, fd, EventCpuCycles );\n                if( s_ring[s_numBuffers].IsValid() )\n                {\n                    s_numBuffers++;\n                    TracyDebug( \"  Core %i ok\\n\", i );\n                }\n            }\n        }\n\n        pe.config = PERF_COUNT_HW_INSTRUCTIONS;\n        for( int i=0; i<s_numCpus; i++ )\n        {\n            const int fd = perf_event_open( &pe, currentPid, i, -1, PERF_FLAG_FD_CLOEXEC );\n            if( fd != -1 )\n            {\n                new( s_ring+s_numBuffers ) RingBuffer( 64*1024, fd, EventInstructionsRetired );\n                if( s_ring[s_numBuffers].IsValid() )\n                {\n                    s_numBuffers++;\n                    TracyDebug( \"  Core %i ok\\n\", i );\n                }\n            }\n        }\n    }\n\n    // cache reference + miss\n    if( !noCache )\n    {\n        TracyDebug( \"Setup sampling CPU cache references + misses\\n\" );\n        ProbePreciseIp( pe, PERF_COUNT_HW_CACHE_REFERENCES, PERF_COUNT_HW_CACHE_MISSES, currentPid );\n        if( IsGenuineIntel() )\n        {\n            pe.precise_ip = 0;\n            TracyDebug( \"  CPU is GenuineIntel, forcing precise_ip down to 0\\n\" );\n        }\n        for( int i=0; i<s_numCpus; i++ )\n        {\n            const int fd = perf_event_open( &pe, currentPid, i, -1, PERF_FLAG_FD_CLOEXEC );\n            if( fd != -1 )\n            {\n                new( s_ring+s_numBuffers ) RingBuffer( 64*1024, fd, EventCacheReference );\n                if( s_ring[s_numBuffers].IsValid() )\n                {\n                    s_numBuffers++;\n                    TracyDebug( \"  Core %i ok\\n\", i );\n                }\n            }\n        }\n\n        pe.config = PERF_COUNT_HW_CACHE_MISSES;\n        for( int i=0; i<s_numCpus; i++ )\n        {\n            const int fd = perf_event_open( &pe, currentPid, i, -1, PERF_FLAG_FD_CLOEXEC );\n            if( fd != -1 )\n            {\n                new( s_ring+s_numBuffers ) RingBuffer( 64*1024, fd, EventCacheMiss );\n                if( s_ring[s_numBuffers].IsValid() )\n                {\n                    s_numBuffers++;\n                    TracyDebug( \"  Core %i ok\\n\", i );\n                }\n            }\n        }\n    }\n\n    // branch retired + miss\n    if( !noBranch )\n    {\n        TracyDebug( \"Setup sampling CPU branch retirements + misses\\n\" );\n        ProbePreciseIp( pe, PERF_COUNT_HW_BRANCH_INSTRUCTIONS, PERF_COUNT_HW_BRANCH_MISSES, currentPid );\n        for( int i=0; i<s_numCpus; i++ )\n        {\n            const int fd = perf_event_open( &pe, currentPid, i, -1, PERF_FLAG_FD_CLOEXEC );\n            if( fd != -1 )\n            {\n                new( s_ring+s_numBuffers ) RingBuffer( 64*1024, fd, EventBranchRetired );\n                if( s_ring[s_numBuffers].IsValid() )\n                {\n                    s_numBuffers++;\n                    TracyDebug( \"  Core %i ok\\n\", i );\n                }\n            }\n        }\n\n        pe.config = PERF_COUNT_HW_BRANCH_MISSES;\n        for( int i=0; i<s_numCpus; i++ )\n        {\n            const int fd = perf_event_open( &pe, currentPid, i, -1, PERF_FLAG_FD_CLOEXEC );\n            if( fd != -1 )\n            {\n                new( s_ring+s_numBuffers ) RingBuffer( 64*1024, fd, EventBranchMiss );\n                if( s_ring[s_numBuffers].IsValid() )\n                {\n                    s_numBuffers++;\n                    TracyDebug( \"  Core %i ok\\n\", i );\n                }\n            }\n        }\n    }\n\n    s_ctxBufferIdx = s_numBuffers;\n\n    // vsync\n    if( !noVsync && vsyncId != -1 )\n    {\n        pe = {};\n        pe.type = PERF_TYPE_TRACEPOINT;\n        pe.size = sizeof( perf_event_attr );\n        pe.sample_period = 1;\n        pe.sample_type = PERF_SAMPLE_TIME | PERF_SAMPLE_RAW;\n        pe.disabled = 1;\n        pe.config = vsyncId;\n#if !defined TRACY_HW_TIMER || !( defined __i386 || defined _M_IX86 || defined __x86_64__ || defined _M_X64 )\n        pe.use_clockid = 1;\n        pe.clockid = CLOCK_MONOTONIC_RAW;\n#endif\n\n        TracyDebug( \"Setup vsync capture\\n\" );\n        for( int i=0; i<s_numCpus; i++ )\n        {\n            const int fd = perf_event_open( &pe, -1, i, -1, PERF_FLAG_FD_CLOEXEC );\n            if( fd != -1 )\n            {\n                new( s_ring+s_numBuffers ) RingBuffer( 64*1024, fd, EventVsync, i );\n                if( s_ring[s_numBuffers].IsValid() )\n                {\n                    s_numBuffers++;\n                    TracyDebug( \"  Core %i ok\\n\", i );\n                }\n            }\n        }\n    }\n\n    // context switches\n    if( !noCtxSwitch && switchId != -1 )\n    {\n        pe = {};\n        pe.type = PERF_TYPE_TRACEPOINT;\n        pe.size = sizeof( perf_event_attr );\n        pe.sample_period = 1;\n        pe.sample_type = PERF_SAMPLE_TIME | PERF_SAMPLE_RAW | PERF_SAMPLE_CALLCHAIN;\n#if LINUX_VERSION_CODE >= KERNEL_VERSION( 4, 8, 0 )\n        pe.sample_max_stack = 127;\n#endif\n        pe.disabled = 1;\n        pe.inherit = 1;\n        pe.config = switchId;\n#if !defined TRACY_HW_TIMER || !( defined __i386 || defined _M_IX86 || defined __x86_64__ || defined _M_X64 )\n        pe.use_clockid = 1;\n        pe.clockid = CLOCK_MONOTONIC_RAW;\n#endif\n\n        TracyDebug( \"Setup context switch capture\\n\" );\n        for( int i=0; i<s_numCpus; i++ )\n        {\n            const int fd = perf_event_open( &pe, -1, i, -1, PERF_FLAG_FD_CLOEXEC );\n            if( fd != -1 )\n            {\n                new( s_ring+s_numBuffers ) RingBuffer( 256*1024, fd, EventContextSwitch, i );\n                if( s_ring[s_numBuffers].IsValid() )\n                {\n                    s_numBuffers++;\n                    TracyDebug( \"  Core %i ok\\n\", i );\n                }\n            }\n        }\n\n        if( wakingId != -1 )\n        {\n            pe = {};\n            pe.type = PERF_TYPE_TRACEPOINT;\n            pe.size = sizeof( perf_event_attr );\n            pe.sample_period = 1;\n            pe.sample_type = PERF_SAMPLE_TIME | PERF_SAMPLE_RAW;\n            // Coult ask for callstack here\n            //pe.sample_type |= PERF_SAMPLE_CALLCHAIN;\n            pe.disabled = 1;\n            pe.inherit = 1;\n            pe.config = wakingId;\n            pe.read_format = 0;\n#if !defined TRACY_HW_TIMER || !( defined __i386 || defined _M_IX86 || defined __x86_64__ || defined _M_X64 )\n            pe.use_clockid = 1;\n            pe.clockid = CLOCK_MONOTONIC_RAW;\n#endif\n\n            TracyDebug( \"Setup waking up capture\\n\" );\n            for( int i=0; i<s_numCpus; i++ )\n            {\n                const int fd = perf_event_open( &pe, -1, i, -1, PERF_FLAG_FD_CLOEXEC );\n                if( fd != -1 )\n                {\n                    new( s_ring+s_numBuffers ) RingBuffer( 64*1024, fd, EventWaking, i );\n                    if( s_ring[s_numBuffers].IsValid() )\n                    {\n                        s_numBuffers++;\n                        TracyDebug( \"  Core %i ok\\n\", i );\n                    }\n                }\n            }\n        }\n    }\n\n    TracyDebug( \"Ringbuffers in use: %i\\n\", s_numBuffers );\n\n    traceActive.store( true, std::memory_order_relaxed );\n    return true;\n}\n\nvoid SysTraceStop()\n{\n    traceActive.store( false, std::memory_order_relaxed );\n}\n\nstatic uint64_t* GetCallstackBlock( uint64_t cnt, RingBuffer& ring, uint64_t offset )\n{\n    auto trace = (uint64_t*)tracy_malloc_fast( ( 1 + cnt ) * sizeof( uint64_t ) );\n    ring.Read( trace+1, offset, sizeof( uint64_t ) * cnt );\n\n#if defined __x86_64__ || defined _M_X64\n    // remove non-canonical pointers\n    do\n    {\n        const auto test = (int64_t)trace[cnt];\n        const auto m1 = test >> 63;\n        const auto m2 = test >> 47;\n        if( m1 == m2 ) break;\n    }\n    while( --cnt > 0 );\n    for( uint64_t j=1; j<cnt; j++ )\n    {\n        const auto test = (int64_t)trace[j];\n        const auto m1 = test >> 63;\n        const auto m2 = test >> 47;\n        if( m1 != m2 ) trace[j] = 0;\n    }\n#endif\n\n    for( uint64_t j=1; j<=cnt; j++ )\n    {\n        if( trace[j] >= (uint64_t)-4095 )       // PERF_CONTEXT_MAX\n        {\n            memmove( trace+j, trace+j+1, sizeof( uint64_t ) * ( cnt - j ) );\n            cnt--;\n        }\n    }\n\n    memcpy( trace, &cnt, sizeof( uint64_t ) );\n    return trace;\n}\n\nvoid SysTraceWorker( void* ptr )\n{\n    ThreadExitHandler threadExitHandler;\n    SetThreadName( \"Tracy Sampling\" );\n    InitRpmalloc();\n    sched_param sp = { 99 };\n    if( pthread_setschedparam( pthread_self(), SCHED_FIFO, &sp ) != 0 ) TracyDebug( \"Failed to increase SysTraceWorker thread priority!\\n\" );\n    auto ctxBufferIdx = s_ctxBufferIdx;\n    auto ringArray = s_ring;\n    auto numBuffers = s_numBuffers;\n    for( int i=0; i<numBuffers; i++ ) ringArray[i].Enable();\n    for(;;)\n    {\n#ifdef TRACY_ON_DEMAND\n        if( !GetProfiler().IsConnected() )\n        {\n            if( !traceActive.load( std::memory_order_relaxed ) ) break;\n            for( int i=0; i<numBuffers; i++ )\n            {\n                auto& ring = ringArray[i];\n                const auto head = ring.LoadHead();\n                const auto tail = ring.GetTail();\n                if( head != tail )\n                {\n                    const auto end = head - tail;\n                    ring.Advance( end );\n                }\n            }\n            if( !traceActive.load( std::memory_order_relaxed ) ) break;\n            std::this_thread::sleep_for( std::chrono::milliseconds( 10 ) );\n            continue;\n        }\n#endif\n\n        bool hadData = false;\n        for( int i=0; i<ctxBufferIdx; i++ )\n        {\n            if( !traceActive.load( std::memory_order_relaxed ) ) break;\n            auto& ring = ringArray[i];\n            const auto head = ring.LoadHead();\n            const auto tail = ring.GetTail();\n            if( head == tail ) continue;\n            assert( head > tail );\n            hadData = true;\n\n            const auto id = ring.GetId();\n            assert( id != EventContextSwitch );\n            const auto end = head - tail;\n            uint64_t pos = 0;\n            if( id == EventCallstack )\n            {\n                while( pos < end )\n                {\n                    perf_event_header hdr;\n                    ring.Read( &hdr, pos, sizeof( perf_event_header ) );\n                    if( hdr.type == PERF_RECORD_SAMPLE )\n                    {\n                        auto offset = pos + sizeof( perf_event_header );\n\n                        // Layout:\n                        //   u32 pid, tid\n                        //   u64 time\n                        //   u64 cnt\n                        //   u64 ip[cnt]\n\n                        uint32_t tid;\n                        uint64_t t0;\n                        uint64_t cnt;\n\n                        offset += sizeof( uint32_t );\n                        ring.Read( &tid, offset, sizeof( uint32_t ) );\n                        offset += sizeof( uint32_t );\n                        ring.Read( &t0, offset, sizeof( uint64_t ) );\n                        offset += sizeof( uint64_t );\n                        ring.Read( &cnt, offset, sizeof( uint64_t ) );\n                        offset += sizeof( uint64_t );\n\n                        if( cnt > 0 )\n                        {\n#if defined TRACY_HW_TIMER && ( defined __i386 || defined _M_IX86 || defined __x86_64__ || defined _M_X64 )\n                            t0 = ring.ConvertTimeToTsc( t0 );\n#endif\n                            auto trace = GetCallstackBlock( cnt, ring, offset );\n\n                            TracyLfqPrepare( QueueType::CallstackSample );\n                            MemWrite( &item->callstackSampleFat.time, t0 );\n                            MemWrite( &item->callstackSampleFat.thread, tid );\n                            MemWrite( &item->callstackSampleFat.ptr, (uint64_t)trace );\n                            TracyLfqCommit;\n                        }\n                    }\n                    pos += hdr.size;\n                }\n            }\n            else\n            {\n                while( pos < end )\n                {\n                    perf_event_header hdr;\n                    ring.Read( &hdr, pos, sizeof( perf_event_header ) );\n                    if( hdr.type == PERF_RECORD_SAMPLE )\n                    {\n                        auto offset = pos + sizeof( perf_event_header );\n\n                        // Layout:\n                        //   u64 ip\n                        //   u64 time\n\n                        uint64_t ip, t0;\n                        ring.Read( &ip, offset, sizeof( uint64_t ) );\n                        offset += sizeof( uint64_t );\n                        ring.Read( &t0, offset, sizeof( uint64_t ) );\n\n#if defined TRACY_HW_TIMER && ( defined __i386 || defined _M_IX86 || defined __x86_64__ || defined _M_X64 )\n                        t0 = ring.ConvertTimeToTsc( t0 );\n#endif\n                        QueueType type;\n                        switch( id )\n                        {\n                        case EventCpuCycles:\n                            type = QueueType::HwSampleCpuCycle;\n                            break;\n                        case EventInstructionsRetired:\n                            type = QueueType::HwSampleInstructionRetired;\n                            break;\n                        case EventCacheReference:\n                            type = QueueType::HwSampleCacheReference;\n                            break;\n                        case EventCacheMiss:\n                            type = QueueType::HwSampleCacheMiss;\n                            break;\n                        case EventBranchRetired:\n                            type = QueueType::HwSampleBranchRetired;\n                            break;\n                        case EventBranchMiss:\n                            type = QueueType::HwSampleBranchMiss;\n                            break;\n                        default:\n                            abort();\n                        }\n\n                        TracyLfqPrepare( type );\n                        MemWrite( &item->hwSample.ip, ip );\n                        MemWrite( &item->hwSample.time, t0 );\n                        TracyLfqCommit;\n                    }\n                    pos += hdr.size;\n                }\n            }\n            assert( pos == end );\n            ring.Advance( end );\n        }\n        if( !traceActive.load( std::memory_order_relaxed ) ) break;\n\n        if( ctxBufferIdx != numBuffers )\n        {\n            const auto ctxBufNum = numBuffers - ctxBufferIdx;\n\n            int activeNum = 0;\n            uint16_t active[512];\n            uint32_t end[512];\n            uint32_t pos[512];\n            for( int i=0; i<ctxBufNum; i++ )\n            {\n                const auto rbIdx = ctxBufferIdx + i;\n                const auto rbHead = ringArray[rbIdx].LoadHead();\n                const auto rbTail = ringArray[rbIdx].GetTail();\n                const auto rbActive = rbHead != rbTail;\n\n                if( rbActive )\n                {\n                    active[activeNum] = (uint16_t)i;\n                    activeNum++;\n                    end[i] = rbHead - rbTail;\n                    pos[i] = 0;\n                }\n                else\n                {\n                    end[i] = 0;\n                }\n            }\n            if( activeNum > 0 )\n            {\n                hadData = true;\n                while( activeNum > 0 )\n                {\n                    // Find the earliest event from the active buffers\n                    int sel = -1;\n                    int selPos;\n                    int64_t t0 = std::numeric_limits<int64_t>::max();\n                    for( int i=0; i<activeNum; i++ )\n                    {\n                        auto idx = active[i];\n                        auto rbPos = pos[idx];\n                        assert( rbPos < end[idx] );\n                        const auto rbIdx = ctxBufferIdx + idx;\n                        perf_event_header hdr;\n                        ringArray[rbIdx].Read( &hdr, rbPos, sizeof( perf_event_header ) );\n                        if( hdr.type == PERF_RECORD_SAMPLE )\n                        {\n                            int64_t rbTime;\n                            ringArray[rbIdx].Read( &rbTime, rbPos + sizeof( perf_event_header ), sizeof( int64_t ) );\n                            if( rbTime < t0 )\n                            {\n                                t0 = rbTime;\n                                sel = idx;\n                                selPos = i;\n                            }\n                        }\n                        else\n                        {\n                            rbPos += hdr.size;\n                            if( rbPos == end[idx] )\n                            {\n                                memmove( active+i, active+i+1, sizeof(*active) * ( activeNum - i - 1 ) );\n                                activeNum--;\n                                i--;\n                            }\n                            else\n                            {\n                                pos[idx] = rbPos;\n                            }\n                        }\n                    }\n                    // Found any event\n                    if( sel >= 0 )\n                    {\n                        auto& ring = ringArray[ctxBufferIdx + sel];\n                        auto rbPos = pos[sel];\n                        auto offset = rbPos;\n                        perf_event_header hdr;\n                        ring.Read( &hdr, offset, sizeof( perf_event_header ) );\n\n#if defined TRACY_HW_TIMER && ( defined __i386 || defined _M_IX86 || defined __x86_64__ || defined _M_X64 )\n                        t0 = ring.ConvertTimeToTsc( t0 );\n#endif\n\n                        const auto rid = ring.GetId();\n                        if( rid == EventContextSwitch )\n                        {\n                            // Layout: See /sys/kernel/debug/tracing/events/sched/sched_switch/format\n                            //   u64 time    // PERF_SAMPLE_TIME\n                            //   u64 cnt     // PERF_SAMPLE_CALLCHAIN\n                            //   u64 ip[cnt] // PERF_SAMPLE_CALLCHAIN\n                            //   u32 size\n                            //   u8  data[size]\n                            // Data (not ABI stable, but has not changed since it was added, in 2009):\n                            //   u8  hdr[8]\n                            //   u8  prev_comm[16]\n                            //   u32 prev_pid\n                            //   u32 prev_prio\n                            //   lng prev_state\n                            //   u8  next_comm[16]\n                            //   u32 next_pid\n                            //   u32 next_prio\n\n                            offset += sizeof( perf_event_header ) + sizeof( uint64_t );\n\n                            uint64_t cnt;\n                            ring.Read( &cnt, offset, sizeof( uint64_t ) );\n                            offset += sizeof( uint64_t );\n                            const auto traceOffset = offset;\n                            offset += sizeof( uint64_t ) * cnt + sizeof( uint32_t ) + 8 + 16;\n\n                            uint32_t prev_pid, prev_prio;\n                            uint32_t next_pid, next_prio;\n                            long prev_state;\n\n                            ring.Read( &prev_pid, offset, sizeof( uint32_t ) );\n                            offset += sizeof( uint32_t );\n                            ring.Read( &prev_prio, offset, sizeof( uint32_t ) );\n                            offset += sizeof( uint32_t );\n                            ring.Read( &prev_state, offset, sizeof( long ) );\n                            offset += sizeof( long ) + 16;\n                            ring.Read( &next_pid, offset, sizeof( uint32_t ) );\n                            offset += sizeof( uint32_t );\n                            ring.Read( &next_prio, offset, sizeof( uint32_t ) );\n\n                            uint8_t oldThreadWaitReason = 100;\n                            uint8_t oldThreadState;\n\n                            if(      prev_state & 0x0001 ) oldThreadState = 104;\n                            else if( prev_state & 0x0002 ) oldThreadState = 101;\n                            else if( prev_state & 0x0004 ) oldThreadState = 105;\n                            else if( prev_state & 0x0008 ) oldThreadState = 106;\n                            else if( prev_state & 0x0010 ) oldThreadState = 108;\n                            else if( prev_state & 0x0020 ) oldThreadState = 109;\n                            else if( prev_state & 0x0040 ) oldThreadState = 110;\n                            else if( prev_state & 0x0080 ) oldThreadState = 102;\n                            else                           oldThreadState = 103;\n\n                            TracyLfqPrepare( QueueType::ContextSwitch );\n                            MemWrite( &item->contextSwitch.time, t0 );\n                            MemWrite( &item->contextSwitch.oldThread, prev_pid );\n                            MemWrite( &item->contextSwitch.newThread, next_pid );\n                            MemWrite( &item->contextSwitch.cpu, uint8_t( ring.GetCpu() ) );\n                            MemWrite( &item->contextSwitch.oldThreadWaitReason, oldThreadWaitReason );\n                            MemWrite( &item->contextSwitch.oldThreadState, oldThreadState );\n                            MemWrite( &item->contextSwitch.previousCState, uint8_t( 0 ) );\n                            MemWrite( &item->contextSwitch.newThreadPriority, int8_t( next_prio ) );\n                            MemWrite( &item->contextSwitch.oldThreadPriority, int8_t( prev_prio ) );\n                            TracyLfqCommit;\n\n                            if( cnt > 0 && prev_pid != 0 && CurrentProcOwnsThread( prev_pid ) )\n                            {\n                                auto trace = GetCallstackBlock( cnt, ring, traceOffset );\n\n                                TracyLfqPrepare( QueueType::CallstackSampleContextSwitch );\n                                MemWrite( &item->callstackSampleFat.time, t0 );\n                                MemWrite( &item->callstackSampleFat.thread, prev_pid );\n                                MemWrite( &item->callstackSampleFat.ptr, (uint64_t)trace );\n                                TracyLfqCommit;\n                            }\n                        }\n                        else if( rid == EventWaking)\n                        {\n                            // See /sys/kernel/debug/tracing/events/sched/sched_waking/format\n                            // Layout:\n                            //   u64 time // PERF_SAMPLE_TIME\n                            //   u32 size\n                            //   u8  data[size]\n                            // Data:\n                            //   u8  hdr[8]\n                            //   u8  comm[16]\n                            //   u32 pid\n                            //   i32 prio\n                            //   i32 target_cpu\n                            const uint32_t dataOffset = sizeof( perf_event_header ) + sizeof( uint64_t ) + sizeof( uint32_t ); \n                            offset += dataOffset + 8 + 16;\n                            uint32_t pid;\n                            ring.Read( &pid, offset, sizeof( uint32_t ) );\n                            \n                            TracyLfqPrepare( QueueType::ThreadWakeup );\n                            MemWrite( &item->threadWakeup.time, t0 );\n                            MemWrite( &item->threadWakeup.thread, pid );\n                            MemWrite( &item->threadWakeup.cpu, (uint8_t)ring.GetCpu() );\n\n                            int8_t adjustReason = -1; // Does not exist on Linux\n                            int8_t adjustIncrement = 0; // Should perhaps store the new prio?\n                            MemWrite( &item->threadWakeup.adjustReason, adjustReason );\n                            MemWrite( &item->threadWakeup.adjustIncrement, adjustIncrement );\n                            TracyLfqCommit;\n                        }\n                        else\n                        {\n                            assert( rid == EventVsync );\n                            // Layout:\n                            //   u64 time\n                            //   u32 size\n                            //   u8  data[size]\n                            // Data (not ABI stable):\n                            //   u8  hdr[8]\n                            //   i32 crtc\n                            //   u32 seq\n                            //   i64 ktime\n                            //   u8  high precision\n\n                            offset += sizeof( perf_event_header ) + sizeof( uint64_t ) + sizeof( uint32_t ) + 8;\n\n                            int32_t crtc;\n                            ring.Read( &crtc, offset, sizeof( int32_t ) );\n\n                            // Note: The timestamp value t0 might be off by a number of microseconds from the\n                            // true hardware vblank event. The ktime value should be used instead, but it is\n                            // measured in CLOCK_MONOTONIC time. Tracy only supports the timestamp counter\n                            // register (TSC) or CLOCK_MONOTONIC_RAW clock.\n#if 0\n                            offset += sizeof( uint32_t ) * 2;\n                            int64_t ktime;\n                            ring.Read( &ktime, offset, sizeof( int64_t ) );\n#endif\n\n                            TracyLfqPrepare( QueueType::FrameVsync );\n                            MemWrite( &item->frameVsync.id, crtc );\n                            MemWrite( &item->frameVsync.time, t0 );\n                            TracyLfqCommit;\n                        }\n\n                        rbPos += hdr.size;\n                        if( rbPos == end[sel] )\n                        {\n                            memmove( active+selPos, active+selPos+1, sizeof(*active) * ( activeNum - selPos - 1 ) );\n                            activeNum--;\n                        }\n                        else\n                        {\n                            pos[sel] = rbPos;\n                        }\n                    }\n                }\n                for( int i=0; i<ctxBufNum; i++ )\n                {\n                    if( end[i] != 0 ) ringArray[ctxBufferIdx + i].Advance( end[i] );\n                }\n            }\n        }\n        if( !traceActive.load( std::memory_order_relaxed ) ) break;\n        if( !hadData )\n        {\n            std::this_thread::sleep_for( std::chrono::milliseconds( 1 ) );\n        }\n    }\n\n    for( int i=0; i<numBuffers; i++ ) ringArray[i].~RingBuffer();\n    tracy_free_fast( ringArray );\n}\n\nvoid SysTraceGetExternalName( uint64_t thread, const char*& threadName, const char*& name )\n{\n    FILE* f;\n    char fn[256];\n    sprintf( fn, \"/proc/%\" PRIu64 \"/comm\", thread );\n    f = fopen( fn, \"rb\" );\n    if( f )\n    {\n        char buf[256];\n        const auto sz = fread( buf, 1, 256, f );\n        if( sz > 0 && buf[sz-1] == '\\n' ) buf[sz-1] = '\\0';\n        threadName = CopyString( buf );\n        fclose( f );\n    }\n    else\n    {\n        threadName = CopyString( \"???\", 3 );\n    }\n\n    sprintf( fn, \"/proc/%\" PRIu64 \"/status\", thread );\n    f = fopen( fn, \"rb\" );\n    if( f )\n    {\n        char* tmp = (char*)tracy_malloc_fast( 8*1024 );\n        const auto fsz = (ptrdiff_t)fread( tmp, 1, 8*1024, f );\n        fclose( f );\n\n        int pid = -1;\n        auto line = tmp;\n        for(;;)\n        {\n            if( memcmp( \"Tgid:\\t\", line, 6 ) == 0 )\n            {\n                pid = atoi( line + 6 );\n                break;\n            }\n            while( line - tmp < fsz && *line != '\\n' ) line++;\n            if( *line != '\\n' ) break;\n            line++;\n        }\n        tracy_free_fast( tmp );\n\n        if( pid >= 0 )\n        {\n            {\n                uint64_t _pid = pid;\n                TracyLfqPrepare( QueueType::TidToPid );\n                MemWrite( &item->tidToPid.tid, thread );\n                MemWrite( &item->tidToPid.pid, _pid );\n                TracyLfqCommit;\n            }\n            sprintf( fn, \"/proc/%i/comm\", pid );\n            f = fopen( fn, \"rb\" );\n            if( f )\n            {\n                char buf[256];\n                const auto sz = fread( buf, 1, 256, f );\n                if( sz > 0 && buf[sz-1] == '\\n' ) buf[sz-1] = '\\0';\n                name = CopyStringFast( buf );\n                fclose( f );\n                return;\n            }\n        }\n    }\n    name = CopyStringFast( \"???\", 3 );\n}\n\n}\n\n#  endif\n\n#endif\n"
  },
  {
    "path": "tracy-client-sys/tracy/client/TracySysTrace.hpp",
    "content": "#ifndef __TRACYSYSTRACE_HPP__\n#define __TRACYSYSTRACE_HPP__\n\n#if !defined TRACY_NO_SYSTEM_TRACING && ( defined _WIN32 || defined __linux__ )\n#  include \"../common/TracyWinFamily.hpp\"\n#  if !defined TRACY_WIN32_NO_DESKTOP\n#    define TRACY_HAS_SYSTEM_TRACING\n#  endif\n#endif\n\n#ifdef TRACY_HAS_SYSTEM_TRACING\n\n#include <stdint.h>\n\nnamespace tracy\n{\n\nbool SysTraceStart( int64_t& samplingPeriod );\nvoid SysTraceStop();\nvoid SysTraceWorker( void* ptr );\n\nvoid SysTraceGetExternalName( uint64_t thread, const char*& threadName, const char*& name );\n\n}\n\n#endif\n\n#endif\n"
  },
  {
    "path": "tracy-client-sys/tracy/client/TracyThread.hpp",
    "content": "#ifndef __TRACYTHREAD_HPP__\n#define __TRACYTHREAD_HPP__\n\n#if defined _WIN32\n#  include <windows.h>\n#else\n#  include <pthread.h>\n#endif\n\n#ifdef TRACY_MANUAL_LIFETIME\n#  include \"tracy_rpmalloc.hpp\"\n#endif\n\nnamespace tracy\n{\n\n#ifdef TRACY_MANUAL_LIFETIME\nextern thread_local bool RpThreadInitDone;\n#endif\n\nclass ThreadExitHandler\n{\npublic:\n    ~ThreadExitHandler()\n    {\n#ifdef TRACY_MANUAL_LIFETIME\n        rpmalloc_thread_finalize( 1 );\n        RpThreadInitDone = false;\n#endif\n    }\n};\n\n#if defined _WIN32\n\nclass Thread\n{\npublic:\n    Thread( void(*func)( void* ptr ), void* ptr )\n        : m_func( func )\n        , m_ptr( ptr )\n        , m_hnd( CreateThread( nullptr, 0, Launch, this, 0, nullptr ) )\n    {}\n\n    ~Thread()\n    {\n        WaitForSingleObject( m_hnd, INFINITE );\n        CloseHandle( m_hnd );\n    }\n\n    HANDLE Handle() const { return m_hnd; }\n\nprivate:\n    static DWORD WINAPI Launch( void* ptr ) { ((Thread*)ptr)->m_func( ((Thread*)ptr)->m_ptr ); return 0; }\n\n    void(*m_func)( void* ptr );\n    void* m_ptr;\n    HANDLE m_hnd;\n};\n\n#else\n\nclass Thread\n{\npublic:\n    Thread( void(*func)( void* ptr ), void* ptr )\n        : m_func( func )\n        , m_ptr( ptr )\n    {\n        pthread_create( &m_thread, nullptr, Launch, this );\n    }\n\n    ~Thread()\n    {\n        pthread_join( m_thread, nullptr );\n    }\n\n    pthread_t Handle() const { return m_thread; }\n\nprivate:\n    static void* Launch( void* ptr ) { ((Thread*)ptr)->m_func( ((Thread*)ptr)->m_ptr ); return nullptr; }\n    void(*m_func)( void* ptr );\n    void* m_ptr;\n    pthread_t m_thread;\n};\n\n#endif\n\n}\n\n#endif\n"
  },
  {
    "path": "tracy-client-sys/tracy/client/tracy_SPSCQueue.h",
    "content": "/*\nCopyright (c) 2020 Erik Rigtorp <erik@rigtorp.se>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n */\n\n#pragma once\n\n#include <atomic>\n#include <cassert>\n#include <cstddef>\n#include <stdexcept>\n#include <type_traits> // std::enable_if, std::is_*_constructible\n\n#include \"../common/TracyAlloc.hpp\"\n\n#if defined (_MSC_VER)\n#pragma warning(push)\n#pragma warning(disable:4324)\n#endif\n\nnamespace tracy {\n\ntemplate <typename T> class SPSCQueue {\npublic:\n  explicit SPSCQueue(const size_t capacity)\n      : capacity_(capacity) {\n    capacity_++; // Needs one slack element\n    slots_ = (T*)tracy_malloc(sizeof(T) * (capacity_ + 2 * kPadding));\n\n    static_assert(alignof(SPSCQueue<T>) == kCacheLineSize, \"\");\n    static_assert(sizeof(SPSCQueue<T>) >= 3 * kCacheLineSize, \"\");\n    assert(reinterpret_cast<char *>(&readIdx_) -\n               reinterpret_cast<char *>(&writeIdx_) >=\n           static_cast<std::ptrdiff_t>(kCacheLineSize));\n  }\n\n  ~SPSCQueue() {\n    while (front()) {\n      pop();\n    }\n    tracy_free(slots_);\n  }\n\n  // non-copyable and non-movable\n  SPSCQueue(const SPSCQueue &) = delete;\n  SPSCQueue &operator=(const SPSCQueue &) = delete;\n\n  template <typename... Args>\n  void emplace(Args &&...args) noexcept(\n      std::is_nothrow_constructible<T, Args &&...>::value) {\n    static_assert(std::is_constructible<T, Args &&...>::value,\n                  \"T must be constructible with Args&&...\");\n    auto const writeIdx = writeIdx_.load(std::memory_order_relaxed);\n    auto nextWriteIdx = writeIdx + 1;\n    if (nextWriteIdx == capacity_) {\n      nextWriteIdx = 0;\n    }\n    while (nextWriteIdx == readIdxCache_) {\n      readIdxCache_ = readIdx_.load(std::memory_order_acquire);\n    }\n    new (&slots_[writeIdx + kPadding]) T(std::forward<Args>(args)...);\n    writeIdx_.store(nextWriteIdx, std::memory_order_release);\n  }\n\n  T *front() noexcept {\n    auto const readIdx = readIdx_.load(std::memory_order_relaxed);\n    if (readIdx == writeIdxCache_) {\n      writeIdxCache_ = writeIdx_.load(std::memory_order_acquire);\n      if (writeIdxCache_ == readIdx) {\n        return nullptr;\n      }\n    }\n    return &slots_[readIdx + kPadding];\n  }\n\n  void pop() noexcept {\n    static_assert(std::is_nothrow_destructible<T>::value,\n                  \"T must be nothrow destructible\");\n    auto const readIdx = readIdx_.load(std::memory_order_relaxed);\n    assert(writeIdx_.load(std::memory_order_acquire) != readIdx);\n    slots_[readIdx + kPadding].~T();\n    auto nextReadIdx = readIdx + 1;\n    if (nextReadIdx == capacity_) {\n      nextReadIdx = 0;\n    }\n    readIdx_.store(nextReadIdx, std::memory_order_release);\n  }\n\n  size_t size() const noexcept {\n    std::ptrdiff_t diff = writeIdx_.load(std::memory_order_acquire) -\n                          readIdx_.load(std::memory_order_acquire);\n    if (diff < 0) {\n      diff += capacity_;\n    }\n    return static_cast<size_t>(diff);\n  }\n\n  bool empty() const noexcept {\n      return writeIdx_.load(std::memory_order_acquire) ==\n          readIdx_.load(std::memory_order_acquire);\n  }\n\n  size_t capacity() const noexcept { return capacity_ - 1; }\n\nprivate:\n  static constexpr size_t kCacheLineSize = 64;\n\n  // Padding to avoid false sharing between slots_ and adjacent allocations\n  static constexpr size_t kPadding = (kCacheLineSize - 1) / sizeof(T) + 1;\n\nprivate:\n  size_t capacity_;\n  T *slots_;\n\n  // Align to cache line size in order to avoid false sharing\n  // readIdxCache_ and writeIdxCache_ is used to reduce the amount of cache\n  // coherency traffic\n  alignas(kCacheLineSize) std::atomic<size_t> writeIdx_ = {0};\n  alignas(kCacheLineSize) size_t readIdxCache_ = 0;\n  alignas(kCacheLineSize) std::atomic<size_t> readIdx_ = {0};\n  alignas(kCacheLineSize) size_t writeIdxCache_ = 0;\n\n  // Padding to avoid adjacent allocations to share cache line with\n  // writeIdxCache_\n  char padding_[kCacheLineSize - sizeof(SPSCQueue<T>::writeIdxCache_)];\n};\n} // namespace rigtorp\n\n#if defined (_MSC_VER)\n#pragma warning(pop)\n#endif\n"
  },
  {
    "path": "tracy-client-sys/tracy/client/tracy_concurrentqueue.h",
    "content": "﻿// Provides a C++11 implementation of a multi-producer, multi-consumer lock-free queue.\n// An overview, including benchmark results, is provided here:\n//     http://moodycamel.com/blog/2014/a-fast-general-purpose-lock-free-queue-for-c++\n// The full design is also described in excruciating detail at:\n//    http://moodycamel.com/blog/2014/detailed-design-of-a-lock-free-queue\n\n// Simplified BSD license:\n// Copyright (c) 2013-2016, Cameron Desrochers.\n// All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without modification,\n// are permitted provided that the following conditions are met:\n//\n// - Redistributions of source code must retain the above copyright notice, this list of\n// conditions and the following disclaimer.\n// - Redistributions in binary form must reproduce the above copyright notice, this list of\n// conditions and the following disclaimer in the documentation and/or other materials\n// provided with the distribution.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY\n// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL\n// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\n// OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR\n// TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n\n#pragma once\n\n#include \"../common/TracyAlloc.hpp\"\n#include \"../common/TracyForceInline.hpp\"\n#include \"../common/TracySystem.hpp\"\n\n#if defined(__GNUC__)\n// Disable -Wconversion warnings (spuriously triggered when Traits::size_t and\n// Traits::index_t are set to < 32 bits, causing integer promotion, causing warnings\n// upon assigning any computed values)\n#pragma GCC diagnostic push\n#pragma GCC diagnostic ignored \"-Wconversion\"\n#endif\n\n#if defined(__APPLE__)\n#include \"TargetConditionals.h\"\n#endif\n\n#include <atomic>\t\t// Requires C++11. Sorry VS2010.\n#include <cassert>\n#include <cstddef>              // for max_align_t\n#include <cstdint>\n#include <cstdlib>\n#include <type_traits>\n#include <algorithm>\n#include <utility>\n#include <limits>\n#include <climits>\t\t// for CHAR_BIT\n#include <array>\n#include <thread>\t\t// partly for __WINPTHREADS_VERSION if on MinGW-w64 w/ POSIX threading\n\nnamespace tracy\n{\n\n// Compiler-specific likely/unlikely hints\nnamespace moodycamel { namespace details {\n#if defined(__GNUC__)\n\tinline bool cqLikely(bool x) { return __builtin_expect((x), true); }\n\tinline bool cqUnlikely(bool x) { return __builtin_expect((x), false); }\n#else\n\tinline bool cqLikely(bool x) { return x; }\n\tinline bool cqUnlikely(bool x) { return x; }\n#endif\n} }\n\nnamespace\n{\n    // to avoid MSVC warning 4127: conditional expression is constant\n    template <bool>\n    struct compile_time_condition\n    {\n        static const bool value = false;\n    };\n    template <>\n    struct compile_time_condition<true>\n    {\n        static const bool value = true;\n    };\n}\n\nnamespace moodycamel {\nnamespace details {\n\ttemplate<typename T>\n\tstruct const_numeric_max {\n\t\tstatic_assert(std::is_integral<T>::value, \"const_numeric_max can only be used with integers\");\n\t\tstatic const T value = std::numeric_limits<T>::is_signed\n\t\t\t? (static_cast<T>(1) << (sizeof(T) * CHAR_BIT - 1)) - static_cast<T>(1)\n\t\t\t: static_cast<T>(-1);\n\t};\n\n#if defined(__GLIBCXX__)\n\ttypedef ::max_align_t std_max_align_t;      // libstdc++ forgot to add it to std:: for a while\n#else\n\ttypedef std::max_align_t std_max_align_t;   // Others (e.g. MSVC) insist it can *only* be accessed via std::\n#endif\n\n\t// Some platforms have incorrectly set max_align_t to a type with <8 bytes alignment even while supporting\n\t// 8-byte aligned scalar values (*cough* 32-bit iOS). Work around this with our own union. See issue #64.\n\ttypedef union {\n\t\tstd_max_align_t x;\n\t\tlong long y;\n\t\tvoid* z;\n\t} max_align_t;\n}\n\n// Default traits for the ConcurrentQueue. To change some of the\n// traits without re-implementing all of them, inherit from this\n// struct and shadow the declarations you wish to be different;\n// since the traits are used as a template type parameter, the\n// shadowed declarations will be used where defined, and the defaults\n// otherwise.\nstruct ConcurrentQueueDefaultTraits\n{\n\t// General-purpose size type. std::size_t is strongly recommended.\n\ttypedef std::size_t size_t;\n\n\t// The type used for the enqueue and dequeue indices. Must be at least as\n\t// large as size_t. Should be significantly larger than the number of elements\n\t// you expect to hold at once, especially if you have a high turnover rate;\n\t// for example, on 32-bit x86, if you expect to have over a hundred million\n\t// elements or pump several million elements through your queue in a very\n\t// short space of time, using a 32-bit type *may* trigger a race condition.\n\t// A 64-bit int type is recommended in that case, and in practice will\n\t// prevent a race condition no matter the usage of the queue. Note that\n\t// whether the queue is lock-free with a 64-int type depends on the whether\n\t// std::atomic<std::uint64_t> is lock-free, which is platform-specific.\n\ttypedef std::size_t index_t;\n\n\t// Internally, all elements are enqueued and dequeued from multi-element\n\t// blocks; this is the smallest controllable unit. If you expect few elements\n\t// but many producers, a smaller block size should be favoured. For few producers\n\t// and/or many elements, a larger block size is preferred. A sane default\n\t// is provided. Must be a power of 2.\n\tstatic const size_t BLOCK_SIZE = 64*1024;\n\n\t// For explicit producers (i.e. when using a producer token), the block is\n\t// checked for being empty by iterating through a list of flags, one per element.\n\t// For large block sizes, this is too inefficient, and switching to an atomic\n\t// counter-based approach is faster. The switch is made for block sizes strictly\n\t// larger than this threshold.\n\tstatic const size_t EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD = 32;\n\n\t// How many full blocks can be expected for a single explicit producer? This should\n\t// reflect that number's maximum for optimal performance. Must be a power of 2.\n\tstatic const size_t EXPLICIT_INITIAL_INDEX_SIZE = 32;\n\n\t// Controls the number of items that an explicit consumer (i.e. one with a token)\n\t// must consume before it causes all consumers to rotate and move on to the next\n\t// internal queue.\n\tstatic const std::uint32_t EXPLICIT_CONSUMER_CONSUMPTION_QUOTA_BEFORE_ROTATE = 256;\n\n\t// The maximum number of elements (inclusive) that can be enqueued to a sub-queue.\n\t// Enqueue operations that would cause this limit to be surpassed will fail. Note\n\t// that this limit is enforced at the block level (for performance reasons), i.e.\n\t// it's rounded up to the nearest block size.\n\tstatic const size_t MAX_SUBQUEUE_SIZE = details::const_numeric_max<size_t>::value;\n\n\n\t// Memory allocation can be customized if needed.\n\t// malloc should return nullptr on failure, and handle alignment like std::malloc.\n#if defined(malloc) || defined(free)\n\t// Gah, this is 2015, stop defining macros that break standard code already!\n\t// Work around malloc/free being special macros:\n\tstatic inline void* WORKAROUND_malloc(size_t size) { return malloc(size); }\n\tstatic inline void WORKAROUND_free(void* ptr) { return free(ptr); }\n\tstatic inline void* (malloc)(size_t size) { return WORKAROUND_malloc(size); }\n\tstatic inline void (free)(void* ptr) { return WORKAROUND_free(ptr); }\n#else\n\tstatic inline void* malloc(size_t size) { return tracy::tracy_malloc(size); }\n\tstatic inline void free(void* ptr) { return tracy::tracy_free(ptr); }\n#endif\n};\n\n\n// When producing or consuming many elements, the most efficient way is to:\n//    1) Use one of the bulk-operation methods of the queue with a token\n//    2) Failing that, use the bulk-operation methods without a token\n//    3) Failing that, create a token and use that with the single-item methods\n//    4) Failing that, use the single-parameter methods of the queue\n// Having said that, don't create tokens willy-nilly -- ideally there should be\n// a maximum of one token per thread (of each kind).\nstruct ProducerToken;\nstruct ConsumerToken;\n\ntemplate<typename T, typename Traits> class ConcurrentQueue;\n\n\nnamespace details\n{\n\tstruct ConcurrentQueueProducerTypelessBase\n\t{\n\t\tConcurrentQueueProducerTypelessBase* next;\n\t\tstd::atomic<bool> inactive;\n\t\tProducerToken* token;\n        uint32_t threadId;\n\n\t\tConcurrentQueueProducerTypelessBase()\n\t\t\t: next(nullptr), inactive(false), token(nullptr), threadId(0)\n\t\t{\n\t\t}\n\t};\n\n\ttemplate<typename T>\n\tstatic inline bool circular_less_than(T a, T b)\n\t{\n\t\tstatic_assert(std::is_integral<T>::value && !std::numeric_limits<T>::is_signed, \"circular_less_than is intended to be used only with unsigned integer types\");\n\t\treturn static_cast<T>(a - b) > static_cast<T>(static_cast<T>(1) << (static_cast<T>(sizeof(T) * CHAR_BIT - 1)));\n\t\t// Note: extra parens around rhs of operator<< is MSVC bug: https://developercommunity2.visualstudio.com/t/C4554-triggers-when-both-lhs-and-rhs-is/10034931\n\t\t//       silencing the bug requires #pragma warning(disable: 4554) around the calling code and has no effect when done here.\n\t}\n\n\ttemplate<typename U>\n\tstatic inline char* align_for(char* ptr)\n\t{\n\t\tconst std::size_t alignment = std::alignment_of<U>::value;\n\t\treturn ptr + (alignment - (reinterpret_cast<std::uintptr_t>(ptr) % alignment)) % alignment;\n\t}\n\n\ttemplate<typename T>\n\tstatic inline T ceil_to_pow_2(T x)\n\t{\n\t\tstatic_assert(std::is_integral<T>::value && !std::numeric_limits<T>::is_signed, \"ceil_to_pow_2 is intended to be used only with unsigned integer types\");\n\n\t\t// Adapted from http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2\n\t\t--x;\n\t\tx |= x >> 1;\n\t\tx |= x >> 2;\n\t\tx |= x >> 4;\n\t\tfor (std::size_t i = 1; i < sizeof(T); i <<= 1) {\n\t\t\tx |= x >> (i << 3);\n\t\t}\n\t\t++x;\n\t\treturn x;\n\t}\n\n\ttemplate<typename T>\n\tstatic inline void swap_relaxed(std::atomic<T>& left, std::atomic<T>& right)\n\t{\n\t\tT temp = std::move(left.load(std::memory_order_relaxed));\n\t\tleft.store(std::move(right.load(std::memory_order_relaxed)), std::memory_order_relaxed);\n\t\tright.store(std::move(temp), std::memory_order_relaxed);\n\t}\n\n\ttemplate<typename T>\n\tstatic inline T const& nomove(T const& x)\n\t{\n\t\treturn x;\n\t}\n\n\ttemplate<bool Enable>\n\tstruct nomove_if\n\t{\n\t\ttemplate<typename T>\n\t\tstatic inline T const& eval(T const& x)\n\t\t{\n\t\t\treturn x;\n\t\t}\n\t};\n\n\ttemplate<>\n\tstruct nomove_if<false>\n\t{\n\t\ttemplate<typename U>\n\t\tstatic inline auto eval(U&& x)\n\t\t\t-> decltype(std::forward<U>(x))\n\t\t{\n\t\t\treturn std::forward<U>(x);\n\t\t}\n\t};\n\n\ttemplate<typename It>\n\tstatic inline auto deref_noexcept(It& it) noexcept -> decltype(*it)\n\t{\n\t\treturn *it;\n\t}\n\n#if defined(__clang__) || !defined(__GNUC__) || __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)\n\ttemplate<typename T> struct is_trivially_destructible : std::is_trivially_destructible<T> { };\n#else\n\ttemplate<typename T> struct is_trivially_destructible : std::has_trivial_destructor<T> { };\n#endif\n\n\ttemplate<typename T> struct static_is_lock_free_num { enum { value = 0 }; };\n\ttemplate<> struct static_is_lock_free_num<signed char> { enum { value = ATOMIC_CHAR_LOCK_FREE }; };\n\ttemplate<> struct static_is_lock_free_num<short> { enum { value = ATOMIC_SHORT_LOCK_FREE }; };\n\ttemplate<> struct static_is_lock_free_num<int> { enum { value = ATOMIC_INT_LOCK_FREE }; };\n\ttemplate<> struct static_is_lock_free_num<long> { enum { value = ATOMIC_LONG_LOCK_FREE }; };\n\ttemplate<> struct static_is_lock_free_num<long long> { enum { value = ATOMIC_LLONG_LOCK_FREE }; };\n\ttemplate<typename T> struct static_is_lock_free : static_is_lock_free_num<typename std::make_signed<T>::type> {  };\n\ttemplate<> struct static_is_lock_free<bool> { enum { value = ATOMIC_BOOL_LOCK_FREE }; };\n\ttemplate<typename U> struct static_is_lock_free<U*> { enum { value = ATOMIC_POINTER_LOCK_FREE }; };\n}\n\n\nstruct ProducerToken\n{\n\ttemplate<typename T, typename Traits>\n\texplicit ProducerToken(ConcurrentQueue<T, Traits>& queue);\n\n\tProducerToken(ProducerToken&& other) noexcept\n\t\t: producer(other.producer)\n\t{\n\t\tother.producer = nullptr;\n\t\tif (producer != nullptr) {\n\t\t\tproducer->token = this;\n\t\t}\n\t}\n\n\tinline ProducerToken& operator=(ProducerToken&& other) noexcept\n\t{\n\t\tswap(other);\n\t\treturn *this;\n\t}\n\n\tvoid swap(ProducerToken& other) noexcept\n\t{\n\t\tstd::swap(producer, other.producer);\n\t\tif (producer != nullptr) {\n\t\t\tproducer->token = this;\n\t\t}\n\t\tif (other.producer != nullptr) {\n\t\t\tother.producer->token = &other;\n\t\t}\n\t}\n\n\t// A token is always valid unless:\n\t//     1) Memory allocation failed during construction\n\t//     2) It was moved via the move constructor\n\t//        (Note: assignment does a swap, leaving both potentially valid)\n\t//     3) The associated queue was destroyed\n\t// Note that if valid() returns true, that only indicates\n\t// that the token is valid for use with a specific queue,\n\t// but not which one; that's up to the user to track.\n\tinline bool valid() const { return producer != nullptr; }\n\n\t~ProducerToken()\n\t{\n\t\tif (producer != nullptr) {\n\t\t\tproducer->token = nullptr;\n\t\t\tproducer->inactive.store(true, std::memory_order_release);\n\t\t}\n\t}\n\n\t// Disable copying and assignment\n\tProducerToken(ProducerToken const&) = delete;\n\tProducerToken& operator=(ProducerToken const&) = delete;\n\nprivate:\n\ttemplate<typename T, typename Traits> friend class ConcurrentQueue;\n\nprotected:\n\tdetails::ConcurrentQueueProducerTypelessBase* producer;\n};\n\n\nstruct ConsumerToken\n{\n\ttemplate<typename T, typename Traits>\n\texplicit ConsumerToken(ConcurrentQueue<T, Traits>& q);\n\n\tConsumerToken(ConsumerToken&& other) noexcept\n\t\t: initialOffset(other.initialOffset), lastKnownGlobalOffset(other.lastKnownGlobalOffset), itemsConsumedFromCurrent(other.itemsConsumedFromCurrent), currentProducer(other.currentProducer), desiredProducer(other.desiredProducer)\n\t{\n\t}\n\n\tinline ConsumerToken& operator=(ConsumerToken&& other) noexcept\n\t{\n\t\tswap(other);\n\t\treturn *this;\n\t}\n\n\tvoid swap(ConsumerToken& other) noexcept\n\t{\n\t\tstd::swap(initialOffset, other.initialOffset);\n\t\tstd::swap(lastKnownGlobalOffset, other.lastKnownGlobalOffset);\n\t\tstd::swap(itemsConsumedFromCurrent, other.itemsConsumedFromCurrent);\n\t\tstd::swap(currentProducer, other.currentProducer);\n\t\tstd::swap(desiredProducer, other.desiredProducer);\n\t}\n\n\t// Disable copying and assignment\n\tConsumerToken(ConsumerToken const&) = delete;\n\tConsumerToken& operator=(ConsumerToken const&) = delete;\n\nprivate:\n\ttemplate<typename T, typename Traits> friend class ConcurrentQueue;\n\nprivate: // but shared with ConcurrentQueue\n\tstd::uint32_t initialOffset;\n\tstd::uint32_t lastKnownGlobalOffset;\n\tstd::uint32_t itemsConsumedFromCurrent;\n\tdetails::ConcurrentQueueProducerTypelessBase* currentProducer;\n\tdetails::ConcurrentQueueProducerTypelessBase* desiredProducer;\n};\n\n\ntemplate<typename T, typename Traits = ConcurrentQueueDefaultTraits>\nclass ConcurrentQueue\n{\npublic:\n    struct ExplicitProducer;\n\n\ttypedef moodycamel::ProducerToken producer_token_t;\n\ttypedef moodycamel::ConsumerToken consumer_token_t;\n\n\ttypedef typename Traits::index_t index_t;\n\ttypedef typename Traits::size_t size_t;\n\n\tstatic const size_t BLOCK_SIZE = static_cast<size_t>(Traits::BLOCK_SIZE);\n\tstatic const size_t EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD = static_cast<size_t>(Traits::EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD);\n\tstatic const size_t EXPLICIT_INITIAL_INDEX_SIZE = static_cast<size_t>(Traits::EXPLICIT_INITIAL_INDEX_SIZE);\n\tstatic const std::uint32_t EXPLICIT_CONSUMER_CONSUMPTION_QUOTA_BEFORE_ROTATE = static_cast<std::uint32_t>(Traits::EXPLICIT_CONSUMER_CONSUMPTION_QUOTA_BEFORE_ROTATE);\n#ifdef _MSC_VER\n#pragma warning(push)\n#pragma warning(disable: 4307)\t\t// + integral constant overflow (that's what the ternary expression is for!)\n#pragma warning(disable: 4309)\t\t// static_cast: Truncation of constant value\n#endif\n\tstatic const size_t MAX_SUBQUEUE_SIZE = (details::const_numeric_max<size_t>::value - static_cast<size_t>(Traits::MAX_SUBQUEUE_SIZE) < BLOCK_SIZE) ? details::const_numeric_max<size_t>::value : ((static_cast<size_t>(Traits::MAX_SUBQUEUE_SIZE) + (BLOCK_SIZE - 1)) / BLOCK_SIZE * BLOCK_SIZE);\n#ifdef _MSC_VER\n#pragma warning(pop)\n#endif\n\n\tstatic_assert(!std::numeric_limits<size_t>::is_signed && std::is_integral<size_t>::value, \"Traits::size_t must be an unsigned integral type\");\n\tstatic_assert(!std::numeric_limits<index_t>::is_signed && std::is_integral<index_t>::value, \"Traits::index_t must be an unsigned integral type\");\n\tstatic_assert(sizeof(index_t) >= sizeof(size_t), \"Traits::index_t must be at least as wide as Traits::size_t\");\n\tstatic_assert((BLOCK_SIZE > 1) && !(BLOCK_SIZE & (BLOCK_SIZE - 1)), \"Traits::BLOCK_SIZE must be a power of 2 (and at least 2)\");\n\tstatic_assert((EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD > 1) && !(EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD & (EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD - 1)), \"Traits::EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD must be a power of 2 (and greater than 1)\");\n\tstatic_assert((EXPLICIT_INITIAL_INDEX_SIZE > 1) && !(EXPLICIT_INITIAL_INDEX_SIZE & (EXPLICIT_INITIAL_INDEX_SIZE - 1)), \"Traits::EXPLICIT_INITIAL_INDEX_SIZE must be a power of 2 (and greater than 1)\");\n\npublic:\n\t// Creates a queue with at least `capacity` element slots; note that the\n\t// actual number of elements that can be inserted without additional memory\n\t// allocation depends on the number of producers and the block size (e.g. if\n\t// the block size is equal to `capacity`, only a single block will be allocated\n\t// up-front, which means only a single producer will be able to enqueue elements\n\t// without an extra allocation -- blocks aren't shared between producers).\n\t// This method is not thread safe -- it is up to the user to ensure that the\n\t// queue is fully constructed before it starts being used by other threads (this\n\t// includes making the memory effects of construction visible, possibly with a\n\t// memory barrier).\n\texplicit ConcurrentQueue(size_t capacity = 6 * BLOCK_SIZE)\n\t\t: producerListTail(nullptr),\n\t\tproducerCount(0),\n\t\tinitialBlockPoolIndex(0),\n\t\tnextExplicitConsumerId(0),\n\t\tglobalExplicitConsumerOffset(0)\n\t{\n\t\tpopulate_initial_block_list(capacity / BLOCK_SIZE + ((capacity & (BLOCK_SIZE - 1)) == 0 ? 0 : 1));\n\t}\n\n\t// Computes the correct amount of pre-allocated blocks for you based\n\t// on the minimum number of elements you want available at any given\n\t// time, and the maximum concurrent number of each type of producer.\n\tConcurrentQueue(size_t minCapacity, size_t maxExplicitProducers)\n\t\t: producerListTail(nullptr),\n\t\tproducerCount(0),\n\t\tinitialBlockPoolIndex(0),\n\t\tnextExplicitConsumerId(0),\n\t\tglobalExplicitConsumerOffset(0)\n\t{\n\t\tsize_t blocks = (((minCapacity + BLOCK_SIZE - 1) / BLOCK_SIZE) - 1) * (maxExplicitProducers + 1) + 2 * (maxExplicitProducers);\n\t\tpopulate_initial_block_list(blocks);\n\t}\n\n\t// Note: The queue should not be accessed concurrently while it's\n\t// being deleted. It's up to the user to synchronize this.\n\t// This method is not thread safe.\n\t~ConcurrentQueue()\n\t{\n\t\t// Destroy producers\n\t\tauto ptr = producerListTail.load(std::memory_order_relaxed);\n\t\twhile (ptr != nullptr) {\n\t\t\tauto next = ptr->next_prod();\n\t\t\tif (ptr->token != nullptr) {\n\t\t\t\tptr->token->producer = nullptr;\n\t\t\t}\n\t\t\tdestroy(ptr);\n\t\t\tptr = next;\n\t\t}\n\n\t\t// Destroy global free list\n\t\tauto block = freeList.head_unsafe();\n\t\twhile (block != nullptr) {\n\t\t\tauto next = block->freeListNext.load(std::memory_order_relaxed);\n\t\t\tif (block->dynamicallyAllocated) {\n\t\t\t\tdestroy(block);\n\t\t\t}\n\t\t\tblock = next;\n\t\t}\n\n\t\t// Destroy initial free list\n\t\tdestroy_array(initialBlockPool, initialBlockPoolSize);\n\t}\n\n\t// Disable copying and copy assignment\n\tConcurrentQueue(ConcurrentQueue const&) = delete;\n    ConcurrentQueue(ConcurrentQueue&& other) = delete;\n\tConcurrentQueue& operator=(ConcurrentQueue const&) = delete;\n    ConcurrentQueue& operator=(ConcurrentQueue&& other) = delete;\n\npublic:\n    tracy_force_inline T* enqueue_begin(producer_token_t const& token, index_t& currentTailIndex)\n    {\n        return static_cast<ExplicitProducer*>(token.producer)->ConcurrentQueue::ExplicitProducer::enqueue_begin(currentTailIndex);\n    }\n\n\ttemplate<class NotifyThread, class ProcessData>\n    size_t try_dequeue_bulk_single(consumer_token_t& token, NotifyThread notifyThread, ProcessData processData )\n    {\n        if (token.desiredProducer == nullptr || token.lastKnownGlobalOffset != globalExplicitConsumerOffset.load(std::memory_order_relaxed)) {\n            if (!update_current_producer_after_rotation(token)) {\n                return 0;\n            }\n        }\n\n        size_t count = static_cast<ProducerBase*>(token.currentProducer)->dequeue_bulk(notifyThread, processData);\n        token.itemsConsumedFromCurrent += static_cast<std::uint32_t>(count);\n\n        auto tail = producerListTail.load(std::memory_order_acquire);\n        auto ptr = static_cast<ProducerBase*>(token.currentProducer)->next_prod();\n        if (ptr == nullptr) {\n            ptr = tail;\n        }\n        if( count == 0 )\n        {\n            while (ptr != static_cast<ProducerBase*>(token.currentProducer)) {\n                auto dequeued = ptr->dequeue_bulk(notifyThread, processData);\n                if (dequeued != 0) {\n                    token.currentProducer = ptr;\n                    token.itemsConsumedFromCurrent = static_cast<std::uint32_t>(dequeued);\n                    return dequeued;\n                }\n                ptr = ptr->next_prod();\n                if (ptr == nullptr) {\n                    ptr = tail;\n                }\n            }\n            return 0;\n        }\n        else\n        {\n            token.currentProducer = ptr;\n            token.itemsConsumedFromCurrent = 0;\n            return count;\n        }\n    }\n\n\n\t// Returns an estimate of the total number of elements currently in the queue. This\n\t// estimate is only accurate if the queue has completely stabilized before it is called\n\t// (i.e. all enqueue and dequeue operations have completed and their memory effects are\n\t// visible on the calling thread, and no further operations start while this method is\n\t// being called).\n\t// Thread-safe.\n\tsize_t size_approx() const\n\t{\n\t\tsize_t size = 0;\n\t\tfor (auto ptr = producerListTail.load(std::memory_order_acquire); ptr != nullptr; ptr = ptr->next_prod()) {\n\t\t\tsize += ptr->size_approx();\n\t\t}\n\t\treturn size;\n\t}\n\n\n\t// Returns true if the underlying atomic variables used by\n\t// the queue are lock-free (they should be on most platforms).\n\t// Thread-safe.\n\tstatic bool is_lock_free()\n\t{\n\t\treturn\n\t\t\tdetails::static_is_lock_free<bool>::value == 2 &&\n\t\t\tdetails::static_is_lock_free<size_t>::value == 2 &&\n\t\t\tdetails::static_is_lock_free<std::uint32_t>::value == 2 &&\n\t\t\tdetails::static_is_lock_free<index_t>::value == 2 &&\n\t\t\tdetails::static_is_lock_free<void*>::value == 2;\n\t}\n\n\nprivate:\n\tfriend struct ProducerToken;\n\tfriend struct ConsumerToken;\n\tfriend struct ExplicitProducer;\n\n\n\t///////////////////////////////\n\t// Queue methods\n\t///////////////////////////////\n\n\tinline bool update_current_producer_after_rotation(consumer_token_t& token)\n\t{\n\t\t// Ah, there's been a rotation, figure out where we should be!\n\t\tauto tail = producerListTail.load(std::memory_order_acquire);\n\t\tif (token.desiredProducer == nullptr && tail == nullptr) {\n\t\t\treturn false;\n\t\t}\n\t\tauto prodCount = producerCount.load(std::memory_order_relaxed);\n\t\tauto globalOffset = globalExplicitConsumerOffset.load(std::memory_order_relaxed);\n\t\tif (details::cqUnlikely(token.desiredProducer == nullptr)) {\n\t\t\t// Aha, first time we're dequeueing anything.\n\t\t\t// Figure out our local position\n\t\t\t// Note: offset is from start, not end, but we're traversing from end -- subtract from count first\n\t\t\tstd::uint32_t offset = prodCount - 1 - (token.initialOffset % prodCount);\n\t\t\ttoken.desiredProducer = tail;\n\t\t\tfor (std::uint32_t i = 0; i != offset; ++i) {\n\t\t\t\ttoken.desiredProducer = static_cast<ProducerBase*>(token.desiredProducer)->next_prod();\n\t\t\t\tif (token.desiredProducer == nullptr) {\n\t\t\t\t\ttoken.desiredProducer = tail;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tstd::uint32_t delta = globalOffset - token.lastKnownGlobalOffset;\n\t\tif (delta >= prodCount) {\n\t\t\tdelta = delta % prodCount;\n\t\t}\n\t\tfor (std::uint32_t i = 0; i != delta; ++i) {\n\t\t\ttoken.desiredProducer = static_cast<ProducerBase*>(token.desiredProducer)->next_prod();\n\t\t\tif (token.desiredProducer == nullptr) {\n\t\t\t\ttoken.desiredProducer = tail;\n\t\t\t}\n\t\t}\n\n\t\ttoken.lastKnownGlobalOffset = globalOffset;\n\t\ttoken.currentProducer = token.desiredProducer;\n\t\ttoken.itemsConsumedFromCurrent = 0;\n\t\treturn true;\n\t}\n\n\n\t///////////////////////////\n\t// Free list\n\t///////////////////////////\n\n\ttemplate <typename N>\n\tstruct FreeListNode\n\t{\n\t\tFreeListNode() : freeListRefs(0), freeListNext(nullptr) { }\n\n\t\tstd::atomic<std::uint32_t> freeListRefs;\n\t\tstd::atomic<N*> freeListNext;\n\t};\n\n\t// A simple CAS-based lock-free free list. Not the fastest thing in the world under heavy contention, but\n\t// simple and correct (assuming nodes are never freed until after the free list is destroyed), and fairly\n\t// speedy under low contention.\n\ttemplate<typename N>\t\t// N must inherit FreeListNode or have the same fields (and initialization of them)\n\tstruct FreeList\n\t{\n\t\tFreeList() : freeListHead(nullptr) { }\n\t\tFreeList(FreeList&& other) : freeListHead(other.freeListHead.load(std::memory_order_relaxed)) { other.freeListHead.store(nullptr, std::memory_order_relaxed); }\n\t\tvoid swap(FreeList& other) { details::swap_relaxed(freeListHead, other.freeListHead); }\n\n\t\tFreeList(FreeList const&) = delete;\n\t\tFreeList& operator=(FreeList const&) = delete;\n\n\t\tinline void add(N* node)\n\t\t{\n\t\t\t// We know that the should-be-on-freelist bit is 0 at this point, so it's safe to\n\t\t\t// set it using a fetch_add\n\t\t\tif (node->freeListRefs.fetch_add(SHOULD_BE_ON_FREELIST, std::memory_order_acq_rel) == 0) {\n\t\t\t\t// Oh look! We were the last ones referencing this node, and we know\n\t\t\t\t// we want to add it to the free list, so let's do it!\n\t\t \t\tadd_knowing_refcount_is_zero(node);\n\t\t\t}\n\t\t}\n\n\t\tinline N* try_get()\n\t\t{\n\t\t\tauto head = freeListHead.load(std::memory_order_acquire);\n\t\t\twhile (head != nullptr) {\n\t\t\t\tauto prevHead = head;\n\t\t\t\tauto refs = head->freeListRefs.load(std::memory_order_relaxed);\n\t\t\t\tif ((refs & REFS_MASK) == 0 || !head->freeListRefs.compare_exchange_strong(refs, refs + 1, std::memory_order_acquire, std::memory_order_relaxed)) {\n\t\t\t\t\thead = freeListHead.load(std::memory_order_acquire);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// Good, reference count has been incremented (it wasn't at zero), which means we can read the\n\t\t\t\t// next and not worry about it changing between now and the time we do the CAS\n\t\t\t\tauto next = head->freeListNext.load(std::memory_order_relaxed);\n\t\t\t\tif (freeListHead.compare_exchange_strong(head, next, std::memory_order_acquire, std::memory_order_relaxed)) {\n\t\t\t\t\t// Yay, got the node. This means it was on the list, which means shouldBeOnFreeList must be false no\n\t\t\t\t\t// matter the refcount (because nobody else knows it's been taken off yet, it can't have been put back on).\n\t\t\t\t\tassert((head->freeListRefs.load(std::memory_order_relaxed) & SHOULD_BE_ON_FREELIST) == 0);\n\n\t\t\t\t\t// Decrease refcount twice, once for our ref, and once for the list's ref\n\t\t\t\t\thead->freeListRefs.fetch_sub(2, std::memory_order_release);\n\t\t\t\t\treturn head;\n\t\t\t\t}\n\n\t\t\t\t// OK, the head must have changed on us, but we still need to decrease the refcount we increased.\n\t\t\t\t// Note that we don't need to release any memory effects, but we do need to ensure that the reference\n\t\t\t\t// count decrement happens-after the CAS on the head.\n\t\t\t\trefs = prevHead->freeListRefs.fetch_sub(1, std::memory_order_acq_rel);\n\t\t\t\tif (refs == SHOULD_BE_ON_FREELIST + 1) {\n\t\t\t\t\tadd_knowing_refcount_is_zero(prevHead);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn nullptr;\n\t\t}\n\n\t\t// Useful for traversing the list when there's no contention (e.g. to destroy remaining nodes)\n\t\tN* head_unsafe() const { return freeListHead.load(std::memory_order_relaxed); }\n\n\tprivate:\n\t\tinline void add_knowing_refcount_is_zero(N* node)\n\t\t{\n\t\t\t// Since the refcount is zero, and nobody can increase it once it's zero (except us, and we run\n\t\t\t// only one copy of this method per node at a time, i.e. the single thread case), then we know\n\t\t\t// we can safely change the next pointer of the node; however, once the refcount is back above\n\t\t\t// zero, then other threads could increase it (happens under heavy contention, when the refcount\n\t\t\t// goes to zero in between a load and a refcount increment of a node in try_get, then back up to\n\t\t\t// something non-zero, then the refcount increment is done by the other thread) -- so, if the CAS\n\t\t\t// to add the node to the actual list fails, decrease the refcount and leave the add operation to\n\t\t\t// the next thread who puts the refcount back at zero (which could be us, hence the loop).\n\t\t\tauto head = freeListHead.load(std::memory_order_relaxed);\n\t\t\twhile (true) {\n\t\t\t\tnode->freeListNext.store(head, std::memory_order_relaxed);\n\t\t\t\tnode->freeListRefs.store(1, std::memory_order_release);\n\t\t\t\tif (!freeListHead.compare_exchange_strong(head, node, std::memory_order_release, std::memory_order_relaxed)) {\n\t\t\t\t\t// Hmm, the add failed, but we can only try again when the refcount goes back to zero\n\t\t\t\t\tif (node->freeListRefs.fetch_add(SHOULD_BE_ON_FREELIST - 1, std::memory_order_release) == 1) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\tprivate:\n\t\t// Implemented like a stack, but where node order doesn't matter (nodes are inserted out of order under contention)\n\t\tstd::atomic<N*> freeListHead;\n\n\tstatic const std::uint32_t REFS_MASK = 0x7FFFFFFF;\n\tstatic const std::uint32_t SHOULD_BE_ON_FREELIST = 0x80000000;\n\t};\n\n\n\t///////////////////////////\n\t// Block\n\t///////////////////////////\n\n\tstruct Block\n\t{\n\t\tBlock()\n\t\t\t: next(nullptr), elementsCompletelyDequeued(0), freeListRefs(0), freeListNext(nullptr), shouldBeOnFreeList(false), dynamicallyAllocated(true)\n\t\t{\n\t\t}\n\n\t\tinline bool is_empty() const\n\t\t{\n\t\t\tif (compile_time_condition<BLOCK_SIZE <= EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD>::value) {\n\t\t\t\t// Check flags\n\t\t\t\tfor (size_t i = 0; i < BLOCK_SIZE; ++i) {\n\t\t\t\t\tif (!emptyFlags[i].load(std::memory_order_relaxed)) {\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Aha, empty; make sure we have all other memory effects that happened before the empty flags were set\n\t\t\t\tstd::atomic_thread_fence(std::memory_order_acquire);\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Check counter\n\t\t\t\tif (elementsCompletelyDequeued.load(std::memory_order_relaxed) == BLOCK_SIZE) {\n\t\t\t\t\tstd::atomic_thread_fence(std::memory_order_acquire);\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\tassert(elementsCompletelyDequeued.load(std::memory_order_relaxed) <= BLOCK_SIZE);\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\t// Returns true if the block is now empty (does not apply in explicit context)\n\t\tinline bool set_empty(index_t i)\n\t\t{\n\t\t\tif (BLOCK_SIZE <= EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD) {\n\t\t\t\t// Set flag\n\t\t\t\tassert(!emptyFlags[BLOCK_SIZE - 1 - static_cast<size_t>(i & static_cast<index_t>(BLOCK_SIZE - 1))].load(std::memory_order_relaxed));\n\t\t\t\temptyFlags[BLOCK_SIZE - 1 - static_cast<size_t>(i & static_cast<index_t>(BLOCK_SIZE - 1))].store(true, std::memory_order_release);\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Increment counter\n\t\t\t\tauto prevVal = elementsCompletelyDequeued.fetch_add(1, std::memory_order_release);\n\t\t\t\tassert(prevVal < BLOCK_SIZE);\n\t\t\t\treturn prevVal == BLOCK_SIZE - 1;\n\t\t\t}\n\t\t}\n\n\t\t// Sets multiple contiguous item statuses to 'empty' (assumes no wrapping and count > 0).\n\t\t// Returns true if the block is now empty (does not apply in explicit context).\n\t\tinline bool set_many_empty(index_t i, size_t count)\n\t\t{\n\t\t\tif (compile_time_condition<BLOCK_SIZE <= EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD>::value) {\n\t\t\t\t// Set flags\n\t\t\t\tstd::atomic_thread_fence(std::memory_order_release);\n\t\t\t\ti = BLOCK_SIZE - 1 - static_cast<size_t>(i & static_cast<index_t>(BLOCK_SIZE - 1)) - count + 1;\n\t\t\t\tfor (size_t j = 0; j != count; ++j) {\n\t\t\t\t\tassert(!emptyFlags[i + j].load(std::memory_order_relaxed));\n\t\t\t\t\temptyFlags[i + j].store(true, std::memory_order_relaxed);\n\t\t\t\t}\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Increment counter\n\t\t\t\tauto prevVal = elementsCompletelyDequeued.fetch_add(count, std::memory_order_release);\n\t\t\t\tassert(prevVal + count <= BLOCK_SIZE);\n\t\t\t\treturn prevVal + count == BLOCK_SIZE;\n\t\t\t}\n\t\t}\n\n\t\tinline void set_all_empty()\n\t\t{\n\t\t\tif (BLOCK_SIZE <= EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD) {\n\t\t\t\t// Set all flags\n\t\t\t\tfor (size_t i = 0; i != BLOCK_SIZE; ++i) {\n\t\t\t\t\temptyFlags[i].store(true, std::memory_order_relaxed);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Reset counter\n\t\t\t\telementsCompletelyDequeued.store(BLOCK_SIZE, std::memory_order_relaxed);\n\t\t\t}\n\t\t}\n\n\t\tinline void reset_empty()\n\t\t{\n\t\t\tif (compile_time_condition<BLOCK_SIZE <= EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD>::value) {\n\t\t\t\t// Reset flags\n\t\t\t\tfor (size_t i = 0; i != BLOCK_SIZE; ++i) {\n\t\t\t\t\temptyFlags[i].store(false, std::memory_order_relaxed);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Reset counter\n\t\t\t\telementsCompletelyDequeued.store(0, std::memory_order_relaxed);\n\t\t\t}\n\t\t}\n\n\t\tinline T* operator[](index_t idx) noexcept { return static_cast<T*>(static_cast<void*>(elements)) + static_cast<size_t>(idx & static_cast<index_t>(BLOCK_SIZE - 1)); }\n\t\tinline T const* operator[](index_t idx) const noexcept { return static_cast<T const*>(static_cast<void const*>(elements)) + static_cast<size_t>(idx & static_cast<index_t>(BLOCK_SIZE - 1)); }\n\n\tprivate:\n\t\t// IMPORTANT: This must be the first member in Block, so that if T depends on the alignment of\n\t\t// addresses returned by malloc, that alignment will be preserved. Apparently clang actually\n\t\t// generates code that uses this assumption for AVX instructions in some cases. Ideally, we\n\t\t// should also align Block to the alignment of T in case it's higher than malloc's 16-byte\n\t\t// alignment, but this is hard to do in a cross-platform way. Assert for this case:\n\t\tstatic_assert(std::alignment_of<T>::value <= std::alignment_of<details::max_align_t>::value, \"The queue does not support super-aligned types at this time\");\n\t\t// Additionally, we need the alignment of Block itself to be a multiple of max_align_t since\n\t\t// otherwise the appropriate padding will not be added at the end of Block in order to make\n\t\t// arrays of Blocks all be properly aligned (not just the first one). We use a union to force\n\t\t// this.\n\t\tunion {\n\t\t\tchar elements[sizeof(T) * BLOCK_SIZE];\n\t\t\tdetails::max_align_t dummy;\n\t\t};\n\tpublic:\n\t\tBlock* next;\n\t\tstd::atomic<size_t> elementsCompletelyDequeued;\n\t\tstd::atomic<bool> emptyFlags[BLOCK_SIZE <= EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD ? BLOCK_SIZE : 1];\n\tpublic:\n\t\tstd::atomic<std::uint32_t> freeListRefs;\n\t\tstd::atomic<Block*> freeListNext;\n\t\tstd::atomic<bool> shouldBeOnFreeList;\n\t\tbool dynamicallyAllocated;\t\t// Perhaps a better name for this would be 'isNotPartOfInitialBlockPool'\n\t};\n\tstatic_assert(std::alignment_of<Block>::value >= std::alignment_of<details::max_align_t>::value, \"Internal error: Blocks must be at least as aligned as the type they are wrapping\");\n\n\n\t///////////////////////////\n\t// Producer base\n\t///////////////////////////\n\n\tstruct ProducerBase : public details::ConcurrentQueueProducerTypelessBase\n\t{\n\t\tProducerBase(ConcurrentQueue* parent_) :\n\t\t\ttailIndex(0),\n\t\t\theadIndex(0),\n\t\t\tdequeueOptimisticCount(0),\n\t\t\tdequeueOvercommit(0),\n\t\t\ttailBlock(nullptr),\n\t\t\tparent(parent_)\n\t\t{\n\t\t}\n\n\t\tvirtual ~ProducerBase() { };\n\n\t\ttemplate<class NotifyThread, class ProcessData>\n\t\tinline size_t dequeue_bulk(NotifyThread notifyThread, ProcessData processData)\n\t\t{\n\t\t\treturn static_cast<ExplicitProducer*>(this)->dequeue_bulk(notifyThread, processData);\n\t\t}\n\n\t\tinline ProducerBase* next_prod() const { return static_cast<ProducerBase*>(next); }\n\n\t\tinline size_t size_approx() const\n\t\t{\n\t\t\tauto tail = tailIndex.load(std::memory_order_relaxed);\n\t\t\tauto head = headIndex.load(std::memory_order_relaxed);\n\t\t\treturn details::circular_less_than(head, tail) ? static_cast<size_t>(tail - head) : 0;\n\t\t}\n\n\t\tinline index_t getTail() const { return tailIndex.load(std::memory_order_relaxed); }\n\tprotected:\n\t\tstd::atomic<index_t> tailIndex;\t\t// Where to enqueue to next\n\t\tstd::atomic<index_t> headIndex;\t\t// Where to dequeue from next\n\n\t\tstd::atomic<index_t> dequeueOptimisticCount;\n\t\tstd::atomic<index_t> dequeueOvercommit;\n\n\t\tBlock* tailBlock;\n\n\tpublic:\n\t\tConcurrentQueue* parent;\n\t};\n\n\n    public:\n\t///////////////////////////\n\t// Explicit queue\n\t///////////////////////////\n\tstruct ExplicitProducer : public ProducerBase\n\t{\n\t\texplicit ExplicitProducer(ConcurrentQueue* _parent) :\n\t\t\tProducerBase(_parent),\n\t\t\tblockIndex(nullptr),\n\t\t\tpr_blockIndexSlotsUsed(0),\n\t\t\tpr_blockIndexSize(EXPLICIT_INITIAL_INDEX_SIZE >> 1),\n\t\t\tpr_blockIndexFront(0),\n\t\t\tpr_blockIndexEntries(nullptr),\n\t\t\tpr_blockIndexRaw(nullptr)\n\t\t{\n\t\t\tsize_t poolBasedIndexSize = details::ceil_to_pow_2(_parent->initialBlockPoolSize) >> 1;\n\t\t\tif (poolBasedIndexSize > pr_blockIndexSize) {\n\t\t\t\tpr_blockIndexSize = poolBasedIndexSize;\n\t\t\t}\n\n\t\t\tnew_block_index(0);\t\t// This creates an index with double the number of current entries, i.e. EXPLICIT_INITIAL_INDEX_SIZE\n\t\t}\n\n\t\t~ExplicitProducer()\n\t\t{\n\t\t\t// Destruct any elements not yet dequeued.\n\t\t\t// Since we're in the destructor, we can assume all elements\n\t\t\t// are either completely dequeued or completely not (no halfways).\n\t\t\tif (this->tailBlock != nullptr) {\t\t// Note this means there must be a block index too\n\t\t\t\t// First find the block that's partially dequeued, if any\n\t\t\t\tBlock* halfDequeuedBlock = nullptr;\n\t\t\t\tif ((this->headIndex.load(std::memory_order_relaxed) & static_cast<index_t>(BLOCK_SIZE - 1)) != 0) {\n\t\t\t\t\t// The head's not on a block boundary, meaning a block somewhere is partially dequeued\n\t\t\t\t\t// (or the head block is the tail block and was fully dequeued, but the head/tail are still not on a boundary)\n\t\t\t\t\tsize_t i = (pr_blockIndexFront - pr_blockIndexSlotsUsed) & (pr_blockIndexSize - 1);\n\t\t\t\t\twhile (details::circular_less_than<index_t>(pr_blockIndexEntries[i].base + BLOCK_SIZE, this->headIndex.load(std::memory_order_relaxed))) {\n\t\t\t\t\t\ti = (i + 1) & (pr_blockIndexSize - 1);\n\t\t\t\t\t}\n\t\t\t\t\tassert(details::circular_less_than<index_t>(pr_blockIndexEntries[i].base, this->headIndex.load(std::memory_order_relaxed)));\n\t\t\t\t\thalfDequeuedBlock = pr_blockIndexEntries[i].block;\n\t\t\t\t}\n\n\t\t\t\t// Start at the head block (note the first line in the loop gives us the head from the tail on the first iteration)\n\t\t\t\tauto block = this->tailBlock;\n\t\t\t\tdo {\n\t\t\t\t\tblock = block->next;\n\t\t\t\t\tif (block->ConcurrentQueue::Block::is_empty()) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tsize_t i = 0;\t// Offset into block\n\t\t\t\t\tif (block == halfDequeuedBlock) {\n\t\t\t\t\t\ti = static_cast<size_t>(this->headIndex.load(std::memory_order_relaxed) & static_cast<index_t>(BLOCK_SIZE - 1));\n\t\t\t\t\t}\n\n\t\t\t\t\t// Walk through all the items in the block; if this is the tail block, we need to stop when we reach the tail index\n\t\t\t\t\tauto lastValidIndex = (this->tailIndex.load(std::memory_order_relaxed) & static_cast<index_t>(BLOCK_SIZE - 1)) == 0 ? BLOCK_SIZE : static_cast<size_t>(this->tailIndex.load(std::memory_order_relaxed) & static_cast<index_t>(BLOCK_SIZE - 1));\n\t\t\t\t\twhile (i != BLOCK_SIZE && (block != this->tailBlock || i != lastValidIndex)) {\n\t\t\t\t\t\t(*block)[i++]->~T();\n\t\t\t\t\t}\n\t\t\t\t} while (block != this->tailBlock);\n\t\t\t}\n\n\t\t\t// Destroy all blocks that we own\n\t\t\tif (this->tailBlock != nullptr) {\n\t\t\t\tauto block = this->tailBlock;\n\t\t\t\tdo {\n\t\t\t\t\tauto nextBlock = block->next;\n\t\t\t\t\tif (block->dynamicallyAllocated) {\n\t\t\t\t\t\tdestroy(block);\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tthis->parent->add_block_to_free_list(block);\n\t\t\t\t\t}\n\t\t\t\t\tblock = nextBlock;\n\t\t\t\t} while (block != this->tailBlock);\n\t\t\t}\n\n\t\t\t// Destroy the block indices\n\t\t\tauto header = static_cast<BlockIndexHeader*>(pr_blockIndexRaw);\n\t\t\twhile (header != nullptr) {\n\t\t\t\tauto prev = static_cast<BlockIndexHeader*>(header->prev);\n\t\t\t\theader->~BlockIndexHeader();\n\t\t\t\t(Traits::free)(header);\n\t\t\t\theader = prev;\n\t\t\t}\n\t\t}\n\n        inline void enqueue_begin_alloc(index_t currentTailIndex)\n        {\n            // We reached the end of a block, start a new one\n            if (this->tailBlock != nullptr && this->tailBlock->next->ConcurrentQueue::Block::is_empty()) {\n                // We can re-use the block ahead of us, it's empty!\n                this->tailBlock = this->tailBlock->next;\n                this->tailBlock->ConcurrentQueue::Block::reset_empty();\n\n                // We'll put the block on the block index (guaranteed to be room since we're conceptually removing the\n                // last block from it first -- except instead of removing then adding, we can just overwrite).\n                // Note that there must be a valid block index here, since even if allocation failed in the ctor,\n                // it would have been re-attempted when adding the first block to the queue; since there is such\n                // a block, a block index must have been successfully allocated.\n            }\n            else {\n                // We're going to need a new block; check that the block index has room\n                if (pr_blockIndexRaw == nullptr || pr_blockIndexSlotsUsed == pr_blockIndexSize) {\n                    // Hmm, the circular block index is already full -- we'll need\n                    // to allocate a new index. Note pr_blockIndexRaw can only be nullptr if\n                    // the initial allocation failed in the constructor.\n                    new_block_index(pr_blockIndexSlotsUsed);\n                }\n\n                // Insert a new block in the circular linked list\n                auto newBlock = this->parent->ConcurrentQueue::requisition_block();\n                newBlock->ConcurrentQueue::Block::reset_empty();\n                if (this->tailBlock == nullptr) {\n                    newBlock->next = newBlock;\n                }\n                else {\n                    newBlock->next = this->tailBlock->next;\n                    this->tailBlock->next = newBlock;\n                }\n                this->tailBlock = newBlock;\n                ++pr_blockIndexSlotsUsed;\n            }\n\n            // Add block to block index\n            auto& entry = blockIndex.load(std::memory_order_relaxed)->entries[pr_blockIndexFront];\n            entry.base = currentTailIndex;\n            entry.block = this->tailBlock;\n            blockIndex.load(std::memory_order_relaxed)->front.store(pr_blockIndexFront, std::memory_order_release);\n            pr_blockIndexFront = (pr_blockIndexFront + 1) & (pr_blockIndexSize - 1);\n        }\n\n        tracy_force_inline T* enqueue_begin(index_t& currentTailIndex)\n        {\n            currentTailIndex = this->tailIndex.load(std::memory_order_relaxed);\n            if (details::cqUnlikely((currentTailIndex & static_cast<index_t>(BLOCK_SIZE - 1)) == 0)) {\n                this->enqueue_begin_alloc(currentTailIndex);\n            }\n            return (*this->tailBlock)[currentTailIndex];\n        }\n\n        tracy_force_inline std::atomic<index_t>& get_tail_index()\n        {\n            return this->tailIndex;\n        }\n\n\t\ttemplate<class NotifyThread, class ProcessData>\n\t\tsize_t dequeue_bulk(NotifyThread notifyThread, ProcessData processData)\n\t\t{\n\t\t\tauto tail = this->tailIndex.load(std::memory_order_relaxed);\n\t\t\tauto overcommit = this->dequeueOvercommit.load(std::memory_order_relaxed);\n\t\t\tauto desiredCount = static_cast<size_t>(tail - (this->dequeueOptimisticCount.load(std::memory_order_relaxed) - overcommit));\n\t\t\tif (details::circular_less_than<size_t>(0, desiredCount)) {\n\t\t\t\tdesiredCount = desiredCount < 8192 ? desiredCount : 8192;\n\t\t\t\tstd::atomic_thread_fence(std::memory_order_acquire);\n\n\t\t\t\tauto myDequeueCount = this->dequeueOptimisticCount.fetch_add(desiredCount, std::memory_order_relaxed);\n\t\t\t\tassert(overcommit <= myDequeueCount);\n\n\t\t\t\ttail = this->tailIndex.load(std::memory_order_acquire);\n\t\t\t\tauto actualCount = static_cast<size_t>(tail - (myDequeueCount - overcommit));\n\t\t\t\tif (details::circular_less_than<size_t>(0, actualCount)) {\n\t\t\t\t\tactualCount = desiredCount < actualCount ? desiredCount : actualCount;\n\t\t\t\t\tif (actualCount < desiredCount) {\n\t\t\t\t\t\tthis->dequeueOvercommit.fetch_add(desiredCount - actualCount, std::memory_order_release);\n\t\t\t\t\t}\n\n\t\t\t\t\t// Get the first index. Note that since there's guaranteed to be at least actualCount elements, this\n\t\t\t\t\t// will never exceed tail.\n\t\t\t\t\tauto firstIndex = this->headIndex.fetch_add(actualCount, std::memory_order_acq_rel);\n\n\t\t\t\t\t// Determine which block the first element is in\n\t\t\t\t\tauto localBlockIndex = blockIndex.load(std::memory_order_acquire);\n\t\t\t\t\tauto localBlockIndexHead = localBlockIndex->front.load(std::memory_order_acquire);\n\n\t\t\t\t\tauto headBase = localBlockIndex->entries[localBlockIndexHead].base;\n\t\t\t\t\tauto firstBlockBaseIndex = firstIndex & ~static_cast<index_t>(BLOCK_SIZE - 1);\n\t\t\t\t\tauto offset = static_cast<size_t>(static_cast<typename std::make_signed<index_t>::type>(firstBlockBaseIndex - headBase) / BLOCK_SIZE);\n\t\t\t\t\tauto indexIndex = (localBlockIndexHead + offset) & (localBlockIndex->size - 1);\n\n\t\t\t\t\tnotifyThread( this->threadId );\n\n\t\t\t\t\t// Iterate the blocks and dequeue\n\t\t\t\t\tauto index = firstIndex;\n\t\t\t\t\tdo {\n\t\t\t\t\t\tauto firstIndexInBlock = index;\n\t\t\t\t\t\tauto endIndex = (index & ~static_cast<index_t>(BLOCK_SIZE - 1)) + static_cast<index_t>(BLOCK_SIZE);\n\t\t\t\t\t\tendIndex = details::circular_less_than<index_t>(firstIndex + static_cast<index_t>(actualCount), endIndex) ? firstIndex + static_cast<index_t>(actualCount) : endIndex;\n\t\t\t\t\t\tauto block = localBlockIndex->entries[indexIndex].block;\n\n\t\t\t\t\t\tconst auto sz = endIndex - index;\n\t\t\t\t\t\tprocessData( (*block)[index], sz );\n\t\t\t\t\t\tindex += sz;\n\n\t\t\t\t\t\tblock->ConcurrentQueue::Block::set_many_empty(firstIndexInBlock, static_cast<size_t>(endIndex - firstIndexInBlock));\n\t\t\t\t\t\tindexIndex = (indexIndex + 1) & (localBlockIndex->size - 1);\n\t\t\t\t\t} while (index != firstIndex + actualCount);\n\n\t\t\t\t\treturn actualCount;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t// Wasn't anything to dequeue after all; make the effective dequeue count eventually consistent\n\t\t\t\t\tthis->dequeueOvercommit.fetch_add(desiredCount, std::memory_order_release);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn 0;\n\t\t}\n\n\tprivate:\n\t\tstruct BlockIndexEntry\n\t\t{\n\t\t\tindex_t base;\n\t\t\tBlock* block;\n\t\t};\n\n\t\tstruct BlockIndexHeader\n\t\t{\n\t\t\tsize_t size;\n\t\t\tstd::atomic<size_t> front;\t\t// Current slot (not next, like pr_blockIndexFront)\n\t\t\tBlockIndexEntry* entries;\n\t\t\tvoid* prev;\n\t\t};\n\n\n\t\tbool new_block_index(size_t numberOfFilledSlotsToExpose)\n\t\t{\n\t\t\tauto prevBlockSizeMask = pr_blockIndexSize - 1;\n\n\t\t\t// Create the new block\n\t\t\tpr_blockIndexSize <<= 1;\n\t\t\tauto newRawPtr = static_cast<char*>((Traits::malloc)(sizeof(BlockIndexHeader) + std::alignment_of<BlockIndexEntry>::value - 1 + sizeof(BlockIndexEntry) * pr_blockIndexSize));\n\t\t\tif (newRawPtr == nullptr) {\n\t\t\t\tpr_blockIndexSize >>= 1;\t\t// Reset to allow graceful retry\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tauto newBlockIndexEntries = reinterpret_cast<BlockIndexEntry*>(details::align_for<BlockIndexEntry>(newRawPtr + sizeof(BlockIndexHeader)));\n\n\t\t\t// Copy in all the old indices, if any\n\t\t\tsize_t j = 0;\n\t\t\tif (pr_blockIndexSlotsUsed != 0) {\n\t\t\t\tauto i = (pr_blockIndexFront - pr_blockIndexSlotsUsed) & prevBlockSizeMask;\n\t\t\t\tdo {\n\t\t\t\t\tnewBlockIndexEntries[j++] = pr_blockIndexEntries[i];\n\t\t\t\t\ti = (i + 1) & prevBlockSizeMask;\n\t\t\t\t} while (i != pr_blockIndexFront);\n\t\t\t}\n\n\t\t\t// Update everything\n\t\t\tauto header = new (newRawPtr) BlockIndexHeader;\n\t\t\theader->size = pr_blockIndexSize;\n\t\t\theader->front.store(numberOfFilledSlotsToExpose - 1, std::memory_order_relaxed);\n\t\t\theader->entries = newBlockIndexEntries;\n\t\t\theader->prev = pr_blockIndexRaw;\t\t// we link the new block to the old one so we can free it later\n\n\t\t\tpr_blockIndexFront = j;\n\t\t\tpr_blockIndexEntries = newBlockIndexEntries;\n\t\t\tpr_blockIndexRaw = newRawPtr;\n\t\t\tblockIndex.store(header, std::memory_order_release);\n\n\t\t\treturn true;\n\t\t}\n\n\tprivate:\n\t\tstd::atomic<BlockIndexHeader*> blockIndex;\n\n\t\t// To be used by producer only -- consumer must use the ones in referenced by blockIndex\n\t\tsize_t pr_blockIndexSlotsUsed;\n\t\tsize_t pr_blockIndexSize;\n\t\tsize_t pr_blockIndexFront;\t\t// Next slot (not current)\n\t\tBlockIndexEntry* pr_blockIndexEntries;\n\t\tvoid* pr_blockIndexRaw;\n\t};\n\n    ExplicitProducer* get_explicit_producer(producer_token_t const& token)\n    {\n        return static_cast<ExplicitProducer*>(token.producer);\n    }\n\n    private:\n\n\t//////////////////////////////////\n\t// Block pool manipulation\n\t//////////////////////////////////\n\n\tvoid populate_initial_block_list(size_t blockCount)\n\t{\n\t\tinitialBlockPoolSize = blockCount;\n\t\tif (initialBlockPoolSize == 0) {\n\t\t\tinitialBlockPool = nullptr;\n\t\t\treturn;\n\t\t}\n\n\t\tinitialBlockPool = create_array<Block>(blockCount);\n\t\tif (initialBlockPool == nullptr) {\n\t\t\tinitialBlockPoolSize = 0;\n\t\t}\n\t\tfor (size_t i = 0; i < initialBlockPoolSize; ++i) {\n\t\t\tinitialBlockPool[i].dynamicallyAllocated = false;\n\t\t}\n\t}\n\n\tinline Block* try_get_block_from_initial_pool()\n\t{\n\t\tif (initialBlockPoolIndex.load(std::memory_order_relaxed) >= initialBlockPoolSize) {\n\t\t\treturn nullptr;\n\t\t}\n\n\t\tauto index = initialBlockPoolIndex.fetch_add(1, std::memory_order_relaxed);\n\n\t\treturn index < initialBlockPoolSize ? (initialBlockPool + index) : nullptr;\n\t}\n\n\tinline void add_block_to_free_list(Block* block)\n\t{\n\t\tfreeList.add(block);\n\t}\n\n\tinline void add_blocks_to_free_list(Block* block)\n\t{\n\t\twhile (block != nullptr) {\n\t\t\tauto next = block->next;\n\t\t\tadd_block_to_free_list(block);\n\t\t\tblock = next;\n\t\t}\n\t}\n\n\tinline Block* try_get_block_from_free_list()\n\t{\n\t\treturn freeList.try_get();\n\t}\n\n\t// Gets a free block from one of the memory pools, or allocates a new one (if applicable)\n\tBlock* requisition_block()\n\t{\n\t\tauto block = try_get_block_from_initial_pool();\n\t\tif (block != nullptr) {\n\t\t\treturn block;\n\t\t}\n\n\t\tblock = try_get_block_from_free_list();\n\t\tif (block != nullptr) {\n\t\t\treturn block;\n\t\t}\n\n\t\treturn create<Block>();\n\t}\n\n\n\t//////////////////////////////////\n\t// Producer list manipulation\n\t//////////////////////////////////\n\n\tProducerBase* recycle_or_create_producer()\n\t{\n\t\tbool recycled;\n\t\treturn recycle_or_create_producer(recycled);\n\t}\n\n    ProducerBase* recycle_or_create_producer(bool& recycled)\n    {\n        // Try to re-use one first\n        for (auto ptr = producerListTail.load(std::memory_order_acquire); ptr != nullptr; ptr = ptr->next_prod()) {\n            if (ptr->inactive.load(std::memory_order_relaxed)) {\n                if( ptr->size_approx() == 0 )\n                {\n                    bool expected = true;\n                    if (ptr->inactive.compare_exchange_strong(expected, /* desired */ false, std::memory_order_acquire, std::memory_order_relaxed)) {\n                        // We caught one! It's been marked as activated, the caller can have it\n                        recycled = true;\n                        return ptr;\n                    }\n                }\n            }\n        }\n\n        recycled = false;\n        return add_producer(static_cast<ProducerBase*>(create<ExplicitProducer>(this)));\n    }\n\n\tProducerBase* add_producer(ProducerBase* producer)\n\t{\n\t\t// Handle failed memory allocation\n\t\tif (producer == nullptr) {\n\t\t\treturn nullptr;\n\t\t}\n\n\t\tproducerCount.fetch_add(1, std::memory_order_relaxed);\n\n\t\t// Add it to the lock-free list\n\t\tauto prevTail = producerListTail.load(std::memory_order_relaxed);\n\t\tdo {\n\t\t\tproducer->next = prevTail;\n\t\t} while (!producerListTail.compare_exchange_weak(prevTail, producer, std::memory_order_release, std::memory_order_relaxed));\n\n\t\treturn producer;\n\t}\n\n\tvoid reown_producers()\n\t{\n\t\t// After another instance is moved-into/swapped-with this one, all the\n\t\t// producers we stole still think their parents are the other queue.\n\t\t// So fix them up!\n\t\tfor (auto ptr = producerListTail.load(std::memory_order_relaxed); ptr != nullptr; ptr = ptr->next_prod()) {\n\t\t\tptr->parent = this;\n\t\t}\n\t}\n\n\t//////////////////////////////////\n\t// Utility functions\n\t//////////////////////////////////\n\n\ttemplate<typename U>\n\tstatic inline U* create_array(size_t count)\n\t{\n\t\tassert(count > 0);\n\t\treturn static_cast<U*>((Traits::malloc)(sizeof(U) * count));\n\t}\n\n\ttemplate<typename U>\n\tstatic inline void destroy_array(U* p, size_t count)\n\t{\n\t\t((void)count);\n\t\tif (p != nullptr) {\n\t\t\tassert(count > 0);\n\t\t\t(Traits::free)(p);\n\t\t}\n\t}\n\n\ttemplate<typename U>\n\tstatic inline U* create()\n\t{\n\t\tauto p = (Traits::malloc)(sizeof(U));\n\t\treturn new (p) U;\n\t}\n\n\ttemplate<typename U, typename A1>\n\tstatic inline U* create(A1&& a1)\n\t{\n\t\tauto p = (Traits::malloc)(sizeof(U));\n\t\treturn new (p) U(std::forward<A1>(a1));\n\t}\n\n\ttemplate<typename U>\n\tstatic inline void destroy(U* p)\n\t{\n\t\tif (p != nullptr) {\n\t\t\tp->~U();\n\t\t}\n\t\t(Traits::free)(p);\n\t}\n\nprivate:\n\tstd::atomic<ProducerBase*> producerListTail;\n\tstd::atomic<std::uint32_t> producerCount;\n\n\tstd::atomic<size_t> initialBlockPoolIndex;\n\tBlock* initialBlockPool;\n\tsize_t initialBlockPoolSize;\n\n\tFreeList<Block> freeList;\n\n\tstd::atomic<std::uint32_t> nextExplicitConsumerId;\n\tstd::atomic<std::uint32_t> globalExplicitConsumerOffset;\n};\n\n\ntemplate<typename T, typename Traits>\nProducerToken::ProducerToken(ConcurrentQueue<T, Traits>& queue)\n\t: producer(queue.recycle_or_create_producer())\n{\n\tif (producer != nullptr) {\n\t\tproducer->token = this;\n        producer->threadId = detail::GetThreadHandleImpl();\n\t}\n}\n\ntemplate<typename T, typename Traits>\nConsumerToken::ConsumerToken(ConcurrentQueue<T, Traits>& queue)\n\t: itemsConsumedFromCurrent(0), currentProducer(nullptr), desiredProducer(nullptr)\n{\n\tinitialOffset = queue.nextExplicitConsumerId.fetch_add(1, std::memory_order_release);\n\tlastKnownGlobalOffset = static_cast<std::uint32_t>(-1);\n}\n\ntemplate<typename T, typename Traits>\ninline void swap(ConcurrentQueue<T, Traits>& a, ConcurrentQueue<T, Traits>& b) noexcept\n{\n\ta.swap(b);\n}\n\ninline void swap(ProducerToken& a, ProducerToken& b) noexcept\n{\n\ta.swap(b);\n}\n\ninline void swap(ConsumerToken& a, ConsumerToken& b) noexcept\n{\n\ta.swap(b);\n}\n\n}\n\n} /* namespace tracy */\n\n#if defined(__GNUC__)\n#pragma GCC diagnostic pop\n#endif\n"
  },
  {
    "path": "tracy-client-sys/tracy/client/tracy_rpmalloc.cpp",
    "content": "#ifdef TRACY_ENABLE\n\n/* rpmalloc.c  -  Memory allocator  -  Public Domain  -  2016-2020 Mattias Jansson\n *\n * This library provides a cross-platform lock free thread caching malloc implementation in C11.\n * The latest source code is always available at\n *\n * https://github.com/mjansson/rpmalloc\n *\n * This library is put in the public domain; you can redistribute it and/or modify it without any restrictions.\n *\n */\n\n#include \"tracy_rpmalloc.hpp\"\n\n#define BUILD_DYNAMIC_LINK 1\n\n////////////\n///\n/// Build time configurable limits\n///\n//////\n\n#if defined(__clang__)\n#pragma clang diagnostic ignored \"-Wunused-macros\"\n#pragma clang diagnostic ignored \"-Wunused-function\"\n#if __has_warning(\"-Wreserved-identifier\")\n#pragma clang diagnostic ignored \"-Wreserved-identifier\"\n#endif\n#elif defined(__GNUC__)\n#pragma GCC diagnostic ignored \"-Wunused-macros\"\n#pragma GCC diagnostic ignored \"-Wunused-function\"\n#pragma GCC diagnostic ignored \"-Warray-bounds\"\n#endif\n\n#ifndef HEAP_ARRAY_SIZE\n//! Size of heap hashmap\n#define HEAP_ARRAY_SIZE           47\n#endif\n#ifndef ENABLE_THREAD_CACHE\n//! Enable per-thread cache\n#define ENABLE_THREAD_CACHE       1\n#endif\n#ifndef ENABLE_GLOBAL_CACHE\n//! Enable global cache shared between all threads, requires thread cache\n#define ENABLE_GLOBAL_CACHE       1\n#endif\n#ifndef ENABLE_VALIDATE_ARGS\n//! Enable validation of args to public entry points\n#define ENABLE_VALIDATE_ARGS      0\n#endif\n#ifndef ENABLE_STATISTICS\n//! Enable statistics collection\n#define ENABLE_STATISTICS         0\n#endif\n#ifndef ENABLE_ASSERTS\n//! Enable asserts\n#define ENABLE_ASSERTS            0\n#endif\n#ifndef ENABLE_OVERRIDE\n//! Override standard library malloc/free and new/delete entry points\n#define ENABLE_OVERRIDE           0\n#endif\n#ifndef ENABLE_PRELOAD\n//! Support preloading\n#define ENABLE_PRELOAD            0\n#endif\n#ifndef DISABLE_UNMAP\n//! Disable unmapping memory pages (also enables unlimited cache)\n#define DISABLE_UNMAP             0\n#endif\n#ifndef ENABLE_UNLIMITED_CACHE\n//! Enable unlimited global cache (no unmapping until finalization)\n#define ENABLE_UNLIMITED_CACHE    0\n#endif\n#ifndef ENABLE_ADAPTIVE_THREAD_CACHE\n//! Enable adaptive thread cache size based on use heuristics\n#define ENABLE_ADAPTIVE_THREAD_CACHE 0\n#endif\n#ifndef DEFAULT_SPAN_MAP_COUNT\n//! Default number of spans to map in call to map more virtual memory (default values yield 4MiB here)\n#define DEFAULT_SPAN_MAP_COUNT    64\n#endif\n#ifndef GLOBAL_CACHE_MULTIPLIER\n//! Multiplier for global cache\n#define GLOBAL_CACHE_MULTIPLIER   8\n#endif\n\n#if DISABLE_UNMAP && !ENABLE_GLOBAL_CACHE\n#error Must use global cache if unmap is disabled\n#endif\n\n#if DISABLE_UNMAP\n#undef ENABLE_UNLIMITED_CACHE\n#define ENABLE_UNLIMITED_CACHE 1\n#endif\n\n#if !ENABLE_GLOBAL_CACHE\n#undef ENABLE_UNLIMITED_CACHE\n#define ENABLE_UNLIMITED_CACHE 0\n#endif\n\n#if !ENABLE_THREAD_CACHE\n#undef ENABLE_ADAPTIVE_THREAD_CACHE\n#define ENABLE_ADAPTIVE_THREAD_CACHE 0\n#endif\n\n#if defined(_WIN32) || defined(__WIN32__) || defined(_WIN64)\n#  define PLATFORM_WINDOWS 1\n#  define PLATFORM_POSIX 0\n#else\n#  define PLATFORM_WINDOWS 0\n#  define PLATFORM_POSIX 1\n#endif\n\n/// Platform and arch specifics\n#if defined(_MSC_VER) && !defined(__clang__)\n#  pragma warning (disable: 5105)\n#  ifndef FORCEINLINE\n#    define FORCEINLINE inline __forceinline\n#  endif\n#else\n#  ifndef FORCEINLINE\n#    define FORCEINLINE inline __attribute__((__always_inline__))\n#  endif\n#endif\n#if PLATFORM_WINDOWS\n#  ifndef WIN32_LEAN_AND_MEAN\n#    define WIN32_LEAN_AND_MEAN\n#  endif\n#  include <windows.h>\n#  if ENABLE_VALIDATE_ARGS\n#    include <intsafe.h>\n#  endif\n#else\n#  include <unistd.h>\n#  include <stdio.h>\n#  include <stdlib.h>\n#  include <time.h>\n#  if defined(__linux__) || defined(__ANDROID__)\n#    include <sys/prctl.h>\n#    if !defined(PR_SET_VMA)\n#      define PR_SET_VMA 0x53564d41\n#      define PR_SET_VMA_ANON_NAME 0\n#    endif\n#  endif\n#  if defined(__APPLE__)\n#    include <TargetConditionals.h>\n#    if !TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR\n#    include <mach/mach.h>\n#    include <mach/vm_statistics.h>\n#    endif\n#    include <pthread.h>\n#  endif\n#  if defined(__HAIKU__) || defined(__TINYC__)\n#    include <pthread.h>\n#  endif\n#endif\n\n#include <stdint.h>\n#include <string.h>\n#include <errno.h>\n\n#if defined(_WIN32) && (!defined(BUILD_DYNAMIC_LINK) || !BUILD_DYNAMIC_LINK)\n#include <fibersapi.h>\nstatic DWORD fls_key;\n#endif\n\n#if PLATFORM_POSIX\n#  include <sys/mman.h>\n#  include <sched.h>\n#  ifdef __FreeBSD__\n#    include <sys/sysctl.h>\n#    define MAP_HUGETLB MAP_ALIGNED_SUPER\n#    ifndef PROT_MAX\n#      define PROT_MAX(f) 0\n#    endif\n#  else\n#    define PROT_MAX(f) 0\n#  endif\n#  ifdef __sun\nextern int madvise(caddr_t, size_t, int);\n#  endif\n#  ifndef MAP_UNINITIALIZED\n#    define MAP_UNINITIALIZED 0\n#  endif\n#endif\n#include <errno.h>\n\n#if ENABLE_ASSERTS\n#  undef NDEBUG\n#  if defined(_MSC_VER) && !defined(_DEBUG)\n#    define _DEBUG\n#  endif\n#  include <assert.h>\n#define RPMALLOC_TOSTRING_M(x) #x\n#define RPMALLOC_TOSTRING(x) RPMALLOC_TOSTRING_M(x)\n#define rpmalloc_assert(truth, message)                                                                      \\\n\tdo {                                                                                                     \\\n\t\tif (!(truth)) {                                                                                      \\\n\t\t\tif (_memory_config.error_callback) {                                                             \\\n\t\t\t\t_memory_config.error_callback(                                                               \\\n\t\t\t\t    message \" (\" RPMALLOC_TOSTRING(truth) \") at \" __FILE__ \":\" RPMALLOC_TOSTRING(__LINE__)); \\\n\t\t\t} else {                                                                                         \\\n\t\t\t\tassert((truth) && message);                                                                  \\\n\t\t\t}                                                                                                \\\n\t\t}                                                                                                    \\\n\t} while (0)\n#else\n#  define rpmalloc_assert(truth, message) do {} while(0)\n#endif\n#if ENABLE_STATISTICS\n#  include <stdio.h>\n#endif\n\n//////\n///\n/// Atomic access abstraction (since MSVC does not do C11 yet)\n///\n//////\n\n#include <atomic>\n\ntypedef std::atomic<int32_t> atomic32_t;\ntypedef std::atomic<int64_t> atomic64_t;\ntypedef std::atomic<void*> atomicptr_t;\n\nstatic FORCEINLINE int32_t atomic_load32(atomic32_t* src) { return std::atomic_load_explicit(src, std::memory_order_relaxed); }\nstatic FORCEINLINE void    atomic_store32(atomic32_t* dst, int32_t val) { std::atomic_store_explicit(dst, val, std::memory_order_relaxed); }\nstatic FORCEINLINE int32_t atomic_incr32(atomic32_t* val) { return std::atomic_fetch_add_explicit(val, 1, std::memory_order_relaxed) + 1; }\nstatic FORCEINLINE int32_t atomic_decr32(atomic32_t* val) { return std::atomic_fetch_add_explicit(val, -1, std::memory_order_relaxed) - 1; }\nstatic FORCEINLINE int32_t atomic_add32(atomic32_t* val, int32_t add) { return std::atomic_fetch_add_explicit(val, add, std::memory_order_relaxed) + add; }\nstatic FORCEINLINE int     atomic_cas32_acquire(atomic32_t* dst, int32_t val, int32_t ref) { return std::atomic_compare_exchange_weak_explicit(dst, &ref, val, std::memory_order_acquire, std::memory_order_relaxed); }\nstatic FORCEINLINE void    atomic_store32_release(atomic32_t* dst, int32_t val) { std::atomic_store_explicit(dst, val, std::memory_order_release); }\nstatic FORCEINLINE int64_t atomic_load64(atomic64_t* val) { return std::atomic_load_explicit(val, std::memory_order_relaxed); }\nstatic FORCEINLINE int64_t atomic_add64(atomic64_t* val, int64_t add) { return std::atomic_fetch_add_explicit(val, add, std::memory_order_relaxed) + add; }\nstatic FORCEINLINE void*   atomic_load_ptr(atomicptr_t* src) { return std::atomic_load_explicit(src, std::memory_order_relaxed); }\nstatic FORCEINLINE void    atomic_store_ptr(atomicptr_t* dst, void* val) { std::atomic_store_explicit(dst, val, std::memory_order_relaxed); }\nstatic FORCEINLINE void    atomic_store_ptr_release(atomicptr_t* dst, void* val) { std::atomic_store_explicit(dst, val, std::memory_order_release); }\nstatic FORCEINLINE void*   atomic_exchange_ptr_acquire(atomicptr_t* dst, void* val) { return std::atomic_exchange_explicit(dst, val, std::memory_order_acquire); }\nstatic FORCEINLINE int     atomic_cas_ptr(atomicptr_t* dst, void* val, void* ref) { return std::atomic_compare_exchange_weak_explicit(dst, &ref, val, std::memory_order_relaxed, std::memory_order_relaxed); }\n\n#if defined(_MSC_VER) && !defined(__clang__)\n\n#define EXPECTED(x) (x)\n#define UNEXPECTED(x) (x)\n\n#else\n\n#define EXPECTED(x) __builtin_expect((x), 1)\n#define UNEXPECTED(x) __builtin_expect((x), 0)\n\n#endif\n\n////////////\n///\n/// Statistics related functions (evaluate to nothing when statistics not enabled)\n///\n//////\n\n#if ENABLE_STATISTICS\n#  define _rpmalloc_stat_inc(counter) atomic_incr32(counter)\n#  define _rpmalloc_stat_dec(counter) atomic_decr32(counter)\n#  define _rpmalloc_stat_add(counter, value) atomic_add32(counter, (int32_t)(value))\n#  define _rpmalloc_stat_add64(counter, value) atomic_add64(counter, (int64_t)(value))\n#  define _rpmalloc_stat_add_peak(counter, value, peak) do { int32_t _cur_count = atomic_add32(counter, (int32_t)(value)); if (_cur_count > (peak)) peak = _cur_count; } while (0)\n#  define _rpmalloc_stat_sub(counter, value) atomic_add32(counter, -(int32_t)(value))\n#  define _rpmalloc_stat_inc_alloc(heap, class_idx) do { \\\n\tint32_t alloc_current = atomic_incr32(&heap->size_class_use[class_idx].alloc_current); \\\n\tif (alloc_current > heap->size_class_use[class_idx].alloc_peak) \\\n\t\theap->size_class_use[class_idx].alloc_peak = alloc_current; \\\n\tatomic_incr32(&heap->size_class_use[class_idx].alloc_total); \\\n} while(0)\n#  define _rpmalloc_stat_inc_free(heap, class_idx) do { \\\n\tatomic_decr32(&heap->size_class_use[class_idx].alloc_current); \\\n\tatomic_incr32(&heap->size_class_use[class_idx].free_total); \\\n} while(0)\n#else\n#  define _rpmalloc_stat_inc(counter) do {} while(0)\n#  define _rpmalloc_stat_dec(counter) do {} while(0)\n#  define _rpmalloc_stat_add(counter, value) do {} while(0)\n#  define _rpmalloc_stat_add64(counter, value) do {} while(0)\n#  define _rpmalloc_stat_add_peak(counter, value, peak) do {} while (0)\n#  define _rpmalloc_stat_sub(counter, value) do {} while(0)\n#  define _rpmalloc_stat_inc_alloc(heap, class_idx) do {} while(0)\n#  define _rpmalloc_stat_inc_free(heap, class_idx) do {} while(0)\n#endif\n\n\n///\n/// Preconfigured limits and sizes\n///\n\n//! Granularity of a small allocation block (must be power of two)\n#define SMALL_GRANULARITY         16\n//! Small granularity shift count\n#define SMALL_GRANULARITY_SHIFT   4\n//! Number of small block size classes\n#define SMALL_CLASS_COUNT         65\n//! Maximum size of a small block\n#define SMALL_SIZE_LIMIT          (SMALL_GRANULARITY * (SMALL_CLASS_COUNT - 1))\n//! Granularity of a medium allocation block\n#define MEDIUM_GRANULARITY        512\n//! Medium granularity shift count\n#define MEDIUM_GRANULARITY_SHIFT  9\n//! Number of medium block size classes\n#define MEDIUM_CLASS_COUNT        61\n//! Total number of small + medium size classes\n#define SIZE_CLASS_COUNT          (SMALL_CLASS_COUNT + MEDIUM_CLASS_COUNT)\n//! Number of large block size classes\n#define LARGE_CLASS_COUNT         63\n//! Maximum size of a medium block\n#define MEDIUM_SIZE_LIMIT         (SMALL_SIZE_LIMIT + (MEDIUM_GRANULARITY * MEDIUM_CLASS_COUNT))\n//! Maximum size of a large block\n#define LARGE_SIZE_LIMIT          ((LARGE_CLASS_COUNT * _memory_span_size) - SPAN_HEADER_SIZE)\n//! Size of a span header (must be a multiple of SMALL_GRANULARITY and a power of two)\n#define SPAN_HEADER_SIZE          128\n//! Number of spans in thread cache\n#define MAX_THREAD_SPAN_CACHE     400\n//! Number of spans to transfer between thread and global cache\n#define THREAD_SPAN_CACHE_TRANSFER 64\n//! Number of spans in thread cache for large spans (must be greater than LARGE_CLASS_COUNT / 2)\n#define MAX_THREAD_SPAN_LARGE_CACHE 100\n//! Number of spans to transfer between thread and global cache for large spans\n#define THREAD_SPAN_LARGE_CACHE_TRANSFER 6\n\nstatic_assert((SMALL_GRANULARITY & (SMALL_GRANULARITY - 1)) == 0, \"Small granularity must be power of two\");\nstatic_assert((SPAN_HEADER_SIZE & (SPAN_HEADER_SIZE - 1)) == 0, \"Span header size must be power of two\");\n\n#if ENABLE_VALIDATE_ARGS\n//! Maximum allocation size to avoid integer overflow\n#undef  MAX_ALLOC_SIZE\n#define MAX_ALLOC_SIZE            (((size_t)-1) - _memory_span_size)\n#endif\n\n#define pointer_offset(ptr, ofs) (void*)((char*)(ptr) + (ptrdiff_t)(ofs))\n#define pointer_diff(first, second) (ptrdiff_t)((const char*)(first) - (const char*)(second))\n\n#define INVALID_POINTER ((void*)((uintptr_t)-1))\n\n#define SIZE_CLASS_LARGE SIZE_CLASS_COUNT\n#define SIZE_CLASS_HUGE ((uint32_t)-1)\n\n////////////\n///\n/// Data types\n///\n//////\n\nnamespace tracy\n{\n\n//! A memory heap, per thread\ntypedef struct heap_t heap_t;\n//! Span of memory pages\ntypedef struct span_t span_t;\n//! Span list\ntypedef struct span_list_t span_list_t;\n//! Span active data\ntypedef struct span_active_t span_active_t;\n//! Size class definition\ntypedef struct size_class_t size_class_t;\n//! Global cache\ntypedef struct global_cache_t global_cache_t;\n\n//! Flag indicating span is the first (master) span of a split superspan\n#define SPAN_FLAG_MASTER 1U\n//! Flag indicating span is a secondary (sub) span of a split superspan\n#define SPAN_FLAG_SUBSPAN 2U\n//! Flag indicating span has blocks with increased alignment\n#define SPAN_FLAG_ALIGNED_BLOCKS 4U\n//! Flag indicating an unmapped master span\n#define SPAN_FLAG_UNMAPPED_MASTER 8U\n\n#if ENABLE_ADAPTIVE_THREAD_CACHE || ENABLE_STATISTICS\nstruct span_use_t {\n\t//! Current number of spans used (actually used, not in cache)\n\tatomic32_t current;\n\t//! High water mark of spans used\n\tatomic32_t high;\n#if ENABLE_STATISTICS\n\t//! Number of spans in deferred list\n\tatomic32_t spans_deferred;\n\t//! Number of spans transitioned to global cache\n\tatomic32_t spans_to_global;\n\t//! Number of spans transitioned from global cache\n\tatomic32_t spans_from_global;\n\t//! Number of spans transitioned to thread cache\n\tatomic32_t spans_to_cache;\n\t//! Number of spans transitioned from thread cache\n\tatomic32_t spans_from_cache;\n\t//! Number of spans transitioned to reserved state\n\tatomic32_t spans_to_reserved;\n\t//! Number of spans transitioned from reserved state\n\tatomic32_t spans_from_reserved;\n\t//! Number of raw memory map calls\n\tatomic32_t spans_map_calls;\n#endif\n};\ntypedef struct span_use_t span_use_t;\n#endif\n\n#if ENABLE_STATISTICS\nstruct size_class_use_t {\n\t//! Current number of allocations\n\tatomic32_t alloc_current;\n\t//! Peak number of allocations\n\tint32_t alloc_peak;\n\t//! Total number of allocations\n\tatomic32_t alloc_total;\n\t//! Total number of frees\n\tatomic32_t free_total;\n\t//! Number of spans in use\n\tatomic32_t spans_current;\n\t//! Number of spans transitioned to cache\n\tint32_t spans_peak;\n\t//! Number of spans transitioned to cache\n\tatomic32_t spans_to_cache;\n\t//! Number of spans transitioned from cache\n\tatomic32_t spans_from_cache;\n\t//! Number of spans transitioned from reserved state\n\tatomic32_t spans_from_reserved;\n\t//! Number of spans mapped\n\tatomic32_t spans_map_calls;\n\tint32_t unused;\n};\ntypedef struct size_class_use_t size_class_use_t;\n#endif\n\n// A span can either represent a single span of memory pages with size declared by span_map_count configuration variable,\n// or a set of spans in a continuous region, a super span. Any reference to the term \"span\" usually refers to both a single\n// span or a super span. A super span can further be divided into multiple spans (or this, super spans), where the first\n// (super)span is the master and subsequent (super)spans are subspans. The master span keeps track of how many subspans\n// that are still alive and mapped in virtual memory, and once all subspans and master have been unmapped the entire\n// superspan region is released and unmapped (on Windows for example, the entire superspan range has to be released\n// in the same call to release the virtual memory range, but individual subranges can be decommitted individually\n// to reduce physical memory use).\nstruct span_t {\n\t//! Free list\n\tvoid*       free_list;\n\t//! Total block count of size class\n\tuint32_t    block_count;\n\t//! Size class\n\tuint32_t    size_class;\n\t//! Index of last block initialized in free list\n\tuint32_t    free_list_limit;\n\t//! Number of used blocks remaining when in partial state\n\tuint32_t    used_count;\n\t//! Deferred free list\n\tatomicptr_t free_list_deferred;\n\t//! Size of deferred free list, or list of spans when part of a cache list\n\tuint32_t    list_size;\n\t//! Size of a block\n\tuint32_t    block_size;\n\t//! Flags and counters\n\tuint32_t    flags;\n\t//! Number of spans\n\tuint32_t    span_count;\n\t//! Total span counter for master spans\n\tuint32_t    total_spans;\n\t//! Offset from master span for subspans\n\tuint32_t    offset_from_master;\n\t//! Remaining span counter, for master spans\n\tatomic32_t  remaining_spans;\n\t//! Alignment offset\n\tuint32_t    align_offset;\n\t//! Owning heap\n\theap_t*     heap;\n\t//! Next span\n\tspan_t*     next;\n\t//! Previous span\n\tspan_t*     prev;\n};\nstatic_assert(sizeof(span_t) <= SPAN_HEADER_SIZE, \"span size mismatch\");\n\nstruct span_cache_t {\n\tsize_t       count;\n\tspan_t*      span[MAX_THREAD_SPAN_CACHE];\n};\ntypedef struct span_cache_t span_cache_t;\n\nstruct span_large_cache_t {\n\tsize_t       count;\n\tspan_t*      span[MAX_THREAD_SPAN_LARGE_CACHE];\n};\ntypedef struct span_large_cache_t span_large_cache_t;\n\nstruct heap_size_class_t {\n\t//! Free list of active span\n\tvoid*        free_list;\n\t//! Double linked list of partially used spans with free blocks.\n\t//  Previous span pointer in head points to tail span of list.\n\tspan_t*      partial_span;\n\t//! Early level cache of fully free spans\n\tspan_t*      cache;\n};\ntypedef struct heap_size_class_t heap_size_class_t;\n\n// Control structure for a heap, either a thread heap or a first class heap if enabled\nstruct heap_t {\n\t//! Owning thread ID\n\tuintptr_t    owner_thread;\n\t//! Free lists for each size class\n\theap_size_class_t size_class[SIZE_CLASS_COUNT];\n#if ENABLE_THREAD_CACHE\n\t//! Arrays of fully freed spans, single span\n\tspan_cache_t span_cache;\n#endif\n\t//! List of deferred free spans (single linked list)\n\tatomicptr_t  span_free_deferred;\n\t//! Number of full spans\n\tsize_t       full_span_count;\n\t//! Mapped but unused spans\n\tspan_t*      span_reserve;\n\t//! Master span for mapped but unused spans\n\tspan_t*      span_reserve_master;\n\t//! Number of mapped but unused spans\n\tuint32_t     spans_reserved;\n\t//! Child count\n\tatomic32_t   child_count;\n\t//! Next heap in id list\n\theap_t*      next_heap;\n\t//! Next heap in orphan list\n\theap_t*      next_orphan;\n\t//! Heap ID\n\tint32_t      id;\n\t//! Finalization state flag\n\tint          finalize;\n\t//! Master heap owning the memory pages\n\theap_t*      master_heap;\n#if ENABLE_THREAD_CACHE\n\t//! Arrays of fully freed spans, large spans with > 1 span count\n\tspan_large_cache_t span_large_cache[LARGE_CLASS_COUNT - 1];\n#endif\n#if RPMALLOC_FIRST_CLASS_HEAPS\n\t//! Double linked list of fully utilized spans with free blocks for each size class.\n\t//  Previous span pointer in head points to tail span of list.\n\tspan_t*      full_span[SIZE_CLASS_COUNT];\n\t//! Double linked list of large and huge spans allocated by this heap\n\tspan_t*      large_huge_span;\n#endif\n#if ENABLE_ADAPTIVE_THREAD_CACHE || ENABLE_STATISTICS\n\t//! Current and high water mark of spans used per span count\n\tspan_use_t   span_use[LARGE_CLASS_COUNT];\n#endif\n#if ENABLE_STATISTICS\n\t//! Allocation stats per size class\n\tsize_class_use_t size_class_use[SIZE_CLASS_COUNT + 1];\n\t//! Number of bytes transitioned thread -> global\n\tatomic64_t   thread_to_global;\n\t//! Number of bytes transitioned global -> thread\n\tatomic64_t   global_to_thread;\n#endif\n};\n\n// Size class for defining a block size bucket\nstruct size_class_t {\n\t//! Size of blocks in this class\n\tuint32_t block_size;\n\t//! Number of blocks in each chunk\n\tuint16_t block_count;\n\t//! Class index this class is merged with\n\tuint16_t class_idx;\n};\nstatic_assert(sizeof(size_class_t) == 8, \"Size class size mismatch\");\n\nstruct global_cache_t {\n\t//! Cache lock\n\tatomic32_t lock;\n\t//! Cache count\n\tuint32_t count;\n#if ENABLE_STATISTICS\n\t//! Insert count\n\tsize_t insert_count;\n\t//! Extract count\n\tsize_t extract_count;\n#endif\n\t//! Cached spans\n\tspan_t* span[GLOBAL_CACHE_MULTIPLIER * MAX_THREAD_SPAN_CACHE];\n\t//! Unlimited cache overflow\n\tspan_t* overflow;\n};\n\n////////////\n///\n/// Global data\n///\n//////\n\n//! Default span size (64KiB)\n#define _memory_default_span_size (64 * 1024)\n#define _memory_default_span_size_shift 16\n#define _memory_default_span_mask (~((uintptr_t)(_memory_span_size - 1)))\n\n//! Initialized flag\nstatic int _rpmalloc_initialized;\n//! Main thread ID\nstatic uintptr_t _rpmalloc_main_thread_id;\n//! Configuration\nstatic rpmalloc_config_t _memory_config;\n//! Memory page size\nstatic size_t _memory_page_size;\n//! Shift to divide by page size\nstatic size_t _memory_page_size_shift;\n//! Granularity at which memory pages are mapped by OS\nstatic size_t _memory_map_granularity;\n#if RPMALLOC_CONFIGURABLE\n//! Size of a span of memory pages\nstatic size_t _memory_span_size;\n//! Shift to divide by span size\nstatic size_t _memory_span_size_shift;\n//! Mask to get to start of a memory span\nstatic uintptr_t _memory_span_mask;\n#else\n//! Hardwired span size\n#define _memory_span_size _memory_default_span_size\n#define _memory_span_size_shift _memory_default_span_size_shift\n#define _memory_span_mask _memory_default_span_mask\n#endif\n//! Number of spans to map in each map call\nstatic size_t _memory_span_map_count;\n//! Number of spans to keep reserved in each heap\nstatic size_t _memory_heap_reserve_count;\n//! Global size classes\nstatic size_class_t _memory_size_class[SIZE_CLASS_COUNT];\n//! Run-time size limit of medium blocks\nstatic size_t _memory_medium_size_limit;\n//! Heap ID counter\nstatic atomic32_t _memory_heap_id;\n//! Huge page support\nstatic int _memory_huge_pages;\n#if ENABLE_GLOBAL_CACHE\n//! Global span cache\nstatic global_cache_t _memory_span_cache[LARGE_CLASS_COUNT];\n#endif\n//! Global reserved spans\nstatic span_t* _memory_global_reserve;\n//! Global reserved count\nstatic size_t _memory_global_reserve_count;\n//! Global reserved master\nstatic span_t* _memory_global_reserve_master;\n//! All heaps\nstatic heap_t* _memory_heaps[HEAP_ARRAY_SIZE];\n//! Used to restrict access to mapping memory for huge pages\nstatic atomic32_t _memory_global_lock;\n//! Orphaned heaps\nstatic heap_t* _memory_orphan_heaps;\n#if RPMALLOC_FIRST_CLASS_HEAPS\n//! Orphaned heaps (first class heaps)\nstatic heap_t* _memory_first_class_orphan_heaps;\n#endif\n#if ENABLE_STATISTICS\n//! Allocations counter\nstatic atomic64_t _allocation_counter;\n//! Deallocations counter\nstatic atomic64_t _deallocation_counter;\n//! Active heap count\nstatic atomic32_t _memory_active_heaps;\n//! Number of currently mapped memory pages\nstatic atomic32_t _mapped_pages;\n//! Peak number of concurrently mapped memory pages\nstatic int32_t _mapped_pages_peak;\n//! Number of mapped master spans\nstatic atomic32_t _master_spans;\n//! Number of unmapped dangling master spans\nstatic atomic32_t _unmapped_master_spans;\n//! Running counter of total number of mapped memory pages since start\nstatic atomic32_t _mapped_total;\n//! Running counter of total number of unmapped memory pages since start\nstatic atomic32_t _unmapped_total;\n//! Number of currently mapped memory pages in OS calls\nstatic atomic32_t _mapped_pages_os;\n//! Number of currently allocated pages in huge allocations\nstatic atomic32_t _huge_pages_current;\n//! Peak number of currently allocated pages in huge allocations\nstatic int32_t _huge_pages_peak;\n#endif\n\n////////////\n///\n/// Thread local heap and ID\n///\n//////\n\n//! Current thread heap\n#if ((defined(__APPLE__) || defined(__HAIKU__)) && ENABLE_PRELOAD) || defined(__TINYC__)\nstatic pthread_key_t _memory_thread_heap;\n#else\n#  ifdef _MSC_VER\n#    define _Thread_local __declspec(thread)\n#    define TLS_MODEL\n#  else\n#    if defined(__ANDROID__) && __ANDROID_API__ >= 29 && defined(__NDK_MAJOR__) && __NDK_MAJOR__ >= 26\n#      define TLS_MODEL __attribute__((tls_model(\"local-dynamic\")))\n#    elif !defined(__HAIKU__)\n#      define TLS_MODEL __attribute__((tls_model(\"initial-exec\")))\n#    else\n#      define TLS_MODEL\n#    endif\n#    if !defined(__clang__) && defined(__GNUC__)\n#      define _Thread_local __thread\n#    endif\n#  endif\nstatic _Thread_local heap_t* _memory_thread_heap TLS_MODEL;\n#endif\n\nstatic inline heap_t*\nget_thread_heap_raw(void) {\n#if (defined(__APPLE__) || defined(__HAIKU__)) && ENABLE_PRELOAD\n\treturn pthread_getspecific(_memory_thread_heap);\n#else\n\treturn _memory_thread_heap;\n#endif\n}\n\n//! Get the current thread heap\nstatic inline heap_t*\nget_thread_heap(void) {\n\theap_t* heap = get_thread_heap_raw();\n#if ENABLE_PRELOAD\n\tif (EXPECTED(heap != 0))\n\t\treturn heap;\n\trpmalloc_initialize();\n\treturn get_thread_heap_raw();\n#else\n\treturn heap;\n#endif\n}\n\n//! Fast thread ID\nstatic inline uintptr_t\nget_thread_id(void) {\n#if defined(_WIN32)\n\treturn (uintptr_t)((void*)NtCurrentTeb());\n#elif (defined(__GNUC__) || defined(__clang__)) && !defined(__CYGWIN__)\n\tuintptr_t tid;\n#  if defined(__i386__)\n\t__asm__(\"movl %%gs:0, %0\" : \"=r\" (tid) : : );\n#  elif defined(__x86_64__)\n#    if defined(__MACH__)\n\t__asm__(\"movq %%gs:0, %0\" : \"=r\" (tid) : : );\n#    else\n\t__asm__(\"movq %%fs:0, %0\" : \"=r\" (tid) : : );\n#    endif\n#  elif defined(__arm__)\n\t__asm__ volatile (\"mrc p15, 0, %0, c13, c0, 3\" : \"=r\" (tid));\n#  elif defined(__aarch64__)\n#    if defined(__MACH__)\n\t// tpidr_el0 likely unused, always return 0 on iOS\n\t__asm__ volatile (\"mrs %0, tpidrro_el0\" : \"=r\" (tid));\n#    else\n\t__asm__ volatile (\"mrs %0, tpidr_el0\" : \"=r\" (tid));\n#    endif\n#  else\n\ttid = (uintptr_t)((void*)get_thread_heap_raw());\n#  endif\n\treturn tid;\n#else\n\treturn (uintptr_t)((void*)get_thread_heap_raw());\n#endif\n}\n\n//! Set the current thread heap\nstatic void\nset_thread_heap(heap_t* heap) {\n#if ((defined(__APPLE__) || defined(__HAIKU__)) && ENABLE_PRELOAD) || defined(__TINYC__)\n\tpthread_setspecific(_memory_thread_heap, heap);\n#else\n\t_memory_thread_heap = heap;\n#endif\n\tif (heap)\n\t\theap->owner_thread = get_thread_id();\n}\n\n//! Set main thread ID\nextern void\nrpmalloc_set_main_thread(void);\n\nvoid\nrpmalloc_set_main_thread(void) {\n\t_rpmalloc_main_thread_id = get_thread_id();\n}\n\nstatic void\n_rpmalloc_spin(void) {\n#if defined(_MSC_VER) && !(defined(_M_ARM) || defined(_M_ARM64))\n\t_mm_pause();\n#elif defined(__x86_64__) || defined(__i386__)\n\t__asm__ volatile(\"pause\" ::: \"memory\");\n#elif defined(__aarch64__) || (defined(__arm__) && __ARM_ARCH >= 7)\n\t__asm__ volatile(\"yield\" ::: \"memory\");\n#elif defined(__powerpc__) || defined(__powerpc64__)\n        // No idea if ever been compiled in such archs but ... as precaution\n\t__asm__ volatile(\"or 27,27,27\");\n#elif defined(__sparc__)\n\t__asm__ volatile(\"rd %ccr, %g0 \\n\\trd %ccr, %g0 \\n\\trd %ccr, %g0\");\n#else\n\tstd::this_thread::yield();\n#endif\n}\n\n#if defined(_WIN32) && (!defined(BUILD_DYNAMIC_LINK) || !BUILD_DYNAMIC_LINK)\nstatic void NTAPI\n_rpmalloc_thread_destructor(void* value) {\n#if ENABLE_OVERRIDE\n\t// If this is called on main thread it means rpmalloc_finalize\n\t// has not been called and shutdown is forced (through _exit) or unclean\n\tif (get_thread_id() == _rpmalloc_main_thread_id)\n\t\treturn;\n#endif\n\tif (value)\n\t\trpmalloc_thread_finalize(1);\n}\n#endif\n\n\n////////////\n///\n/// Low level memory map/unmap\n///\n//////\n\nstatic void\n_rpmalloc_set_name(void* address, size_t size) {\n#if defined(__linux__) || defined(__ANDROID__)\n\tconst char *name = _memory_huge_pages ? _memory_config.huge_page_name : _memory_config.page_name;\n\tif (address == MAP_FAILED || !name)\n\t\treturn;\n\t// If the kernel does not support CONFIG_ANON_VMA_NAME or if the call fails\n\t// (e.g. invalid name) it is a no-op basically.\n\t(void)prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, (uintptr_t)address, size, (uintptr_t)name);\n#else\n\t(void)sizeof(size);\n\t(void)sizeof(address);\n#endif\n}\n\n\n//! Map more virtual memory\n//  size is number of bytes to map\n//  offset receives the offset in bytes from start of mapped region\n//  returns address to start of mapped region to use\nstatic void*\n_rpmalloc_mmap(size_t size, size_t* offset) {\n\trpmalloc_assert(!(size % _memory_page_size), \"Invalid mmap size\");\n\trpmalloc_assert(size >= _memory_page_size, \"Invalid mmap size\");\n\tvoid* address = _memory_config.memory_map(size, offset);\n\tif (EXPECTED(address != 0)) {\n\t\t_rpmalloc_stat_add_peak(&_mapped_pages, (size >> _memory_page_size_shift), _mapped_pages_peak);\n\t\t_rpmalloc_stat_add(&_mapped_total, (size >> _memory_page_size_shift));\n\t}\n\treturn address;\n}\n\n//! Unmap virtual memory\n//  address is the memory address to unmap, as returned from _memory_map\n//  size is the number of bytes to unmap, which might be less than full region for a partial unmap\n//  offset is the offset in bytes to the actual mapped region, as set by _memory_map\n//  release is set to 0 for partial unmap, or size of entire range for a full unmap\nstatic void\n_rpmalloc_unmap(void* address, size_t size, size_t offset, size_t release) {\n\trpmalloc_assert(!release || (release >= size), \"Invalid unmap size\");\n\trpmalloc_assert(!release || (release >= _memory_page_size), \"Invalid unmap size\");\n\tif (release) {\n\t\trpmalloc_assert(!(release % _memory_page_size), \"Invalid unmap size\");\n\t\t_rpmalloc_stat_sub(&_mapped_pages, (release >> _memory_page_size_shift));\n\t\t_rpmalloc_stat_add(&_unmapped_total, (release >> _memory_page_size_shift));\n\t}\n\t_memory_config.memory_unmap(address, size, offset, release);\n}\n\n//! Default implementation to map new pages to virtual memory\nstatic void*\n_rpmalloc_mmap_os(size_t size, size_t* offset) {\n\t//Either size is a heap (a single page) or a (multiple) span - we only need to align spans, and only if larger than map granularity\n\tsize_t padding = ((size >= _memory_span_size) && (_memory_span_size > _memory_map_granularity)) ? _memory_span_size : 0;\n\trpmalloc_assert(size >= _memory_page_size, \"Invalid mmap size\");\n#if PLATFORM_WINDOWS\n\t//Ok to MEM_COMMIT - according to MSDN, \"actual physical pages are not allocated unless/until the virtual addresses are actually accessed\"\n\tvoid* ptr = VirtualAlloc(0, size + padding, (_memory_huge_pages ? MEM_LARGE_PAGES : 0) | MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);\n\tif (!ptr) {\n\t\tif (_memory_config.map_fail_callback) {\n\t\t\tif (_memory_config.map_fail_callback(size + padding))\n\t\t\t\treturn _rpmalloc_mmap_os(size, offset);\n\t\t} else {\n\t\t\trpmalloc_assert(ptr, \"Failed to map virtual memory block\");\n\t\t}\n\t\treturn 0;\n\t}\n#else\n\tint flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_UNINITIALIZED;\n#  if defined(__APPLE__) && !TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR\n\tint fd = (int)VM_MAKE_TAG(240U);\n\tif (_memory_huge_pages)\n\t\tfd |= VM_FLAGS_SUPERPAGE_SIZE_2MB;\n\tvoid* ptr = mmap(0, size + padding, PROT_READ | PROT_WRITE, flags, fd, 0);\n#  elif defined(MAP_HUGETLB)\n\tvoid* ptr = mmap(0, size + padding, PROT_READ | PROT_WRITE | PROT_MAX(PROT_READ | PROT_WRITE), (_memory_huge_pages ? MAP_HUGETLB : 0) | flags, -1, 0);\n#    if defined(MADV_HUGEPAGE)\n\t// In some configurations, huge pages allocations might fail thus\n\t// we fallback to normal allocations and promote the region as transparent huge page\n\tif ((ptr == MAP_FAILED || !ptr) && _memory_huge_pages) {\n\t\tptr = mmap(0, size + padding, PROT_READ | PROT_WRITE, flags, -1, 0);\n\t\tif (ptr && ptr != MAP_FAILED) {\n\t\t\tint prm = madvise(ptr, size + padding, MADV_HUGEPAGE);\n\t\t\t(void)prm;\n\t\t\trpmalloc_assert((prm == 0), \"Failed to promote the page to THP\");\n\t\t}\n\t}\n#    endif\n\t_rpmalloc_set_name(ptr, size + padding);\n#  elif defined(MAP_ALIGNED)\n\tconst size_t align = (sizeof(size_t) * 8) - (size_t)(__builtin_clzl(size - 1));\n\tvoid* ptr = mmap(0, size + padding, PROT_READ | PROT_WRITE, (_memory_huge_pages ? MAP_ALIGNED(align) : 0) | flags, -1, 0);\n#  elif defined(MAP_ALIGN)\n\tcaddr_t base = (_memory_huge_pages ? (caddr_t)(4 << 20) : 0);\n\tvoid* ptr = mmap(base, size + padding, PROT_READ | PROT_WRITE, (_memory_huge_pages ? MAP_ALIGN : 0) | flags, -1, 0);\n#  else\n\tvoid* ptr = mmap(0, size + padding, PROT_READ | PROT_WRITE, flags, -1, 0);\n#  endif\n\tif ((ptr == MAP_FAILED) || !ptr) {\n\t\tif (_memory_config.map_fail_callback) {\n\t\t\tif (_memory_config.map_fail_callback(size + padding))\n\t\t\t\treturn _rpmalloc_mmap_os(size, offset);\n\t\t} else if (errno != ENOMEM) {\n\t\t\trpmalloc_assert((ptr != MAP_FAILED) && ptr, \"Failed to map virtual memory block\");\n\t\t}\n\t\treturn 0;\n\t}\n#endif\n\t_rpmalloc_stat_add(&_mapped_pages_os, (int32_t)((size + padding) >> _memory_page_size_shift));\n\tif (padding) {\n\t\tsize_t final_padding = padding - ((uintptr_t)ptr & ~_memory_span_mask);\n\t\trpmalloc_assert(final_padding <= _memory_span_size, \"Internal failure in padding\");\n\t\trpmalloc_assert(final_padding <= padding, \"Internal failure in padding\");\n\t\trpmalloc_assert(!(final_padding % 8), \"Internal failure in padding\");\n\t\tptr = pointer_offset(ptr, final_padding);\n\t\t*offset = final_padding >> 3;\n\t}\n\trpmalloc_assert((size < _memory_span_size) || !((uintptr_t)ptr & ~_memory_span_mask), \"Internal failure in padding\");\n\treturn ptr;\n}\n\n//! Default implementation to unmap pages from virtual memory\nstatic void\n_rpmalloc_unmap_os(void* address, size_t size, size_t offset, size_t release) {\n\trpmalloc_assert(release || (offset == 0), \"Invalid unmap size\");\n\trpmalloc_assert(!release || (release >= _memory_page_size), \"Invalid unmap size\");\n\trpmalloc_assert(size >= _memory_page_size, \"Invalid unmap size\");\n\tif (release && offset) {\n\t\toffset <<= 3;\n\t\taddress = pointer_offset(address, -(int32_t)offset);\n\t\tif ((release >= _memory_span_size) && (_memory_span_size > _memory_map_granularity)) {\n\t\t\t//Padding is always one span size\n\t\t\trelease += _memory_span_size;\n\t\t}\n\t}\n#if !DISABLE_UNMAP\n#if PLATFORM_WINDOWS\n\tif (!VirtualFree(address, release ? 0 : size, release ? MEM_RELEASE : MEM_DECOMMIT)) {\n\t\trpmalloc_assert(0, \"Failed to unmap virtual memory block\");\n\t}\n#else\n\tif (release) {\n\t\tif (munmap(address, release)) {\n\t\t\trpmalloc_assert(0, \"Failed to unmap virtual memory block\");\n\t\t}\n\t} else {\n#if defined(MADV_FREE_REUSABLE)\n\t\tint ret;\n\t\twhile ((ret = madvise(address, size, MADV_FREE_REUSABLE)) == -1 && (errno == EAGAIN))\n\t\t\terrno = 0;\n\t\tif ((ret == -1) && (errno != 0)) {\n#elif defined(MADV_DONTNEED)\n\t\tif (madvise(address, size, MADV_DONTNEED)) {\n#elif defined(MADV_PAGEOUT)\n\t\tif (madvise(address, size, MADV_PAGEOUT)) {\n#elif defined(MADV_FREE)\n\t\tif (madvise(address, size, MADV_FREE)) {\n#else\n\t\tif (posix_madvise(address, size, POSIX_MADV_DONTNEED)) {\n#endif\n\t\t\trpmalloc_assert(0, \"Failed to madvise virtual memory block as free\");\n\t\t}\n\t}\n#endif\n#endif\n\tif (release)\n\t\t_rpmalloc_stat_sub(&_mapped_pages_os, release >> _memory_page_size_shift);\n}\n\nstatic void\n_rpmalloc_span_mark_as_subspan_unless_master(span_t* master, span_t* subspan, size_t span_count);\n\n//! Use global reserved spans to fulfill a memory map request (reserve size must be checked by caller)\nstatic span_t*\n_rpmalloc_global_get_reserved_spans(size_t span_count) {\n\tspan_t* span = _memory_global_reserve;\n\t_rpmalloc_span_mark_as_subspan_unless_master(_memory_global_reserve_master, span, span_count);\n\t_memory_global_reserve_count -= span_count;\n\tif (_memory_global_reserve_count)\n\t\t_memory_global_reserve = (span_t*)pointer_offset(span, span_count << _memory_span_size_shift);\n\telse\n\t\t_memory_global_reserve = 0;\n\treturn span;\n}\n\n//! Store the given spans as global reserve (must only be called from within new heap allocation, not thread safe)\nstatic void\n_rpmalloc_global_set_reserved_spans(span_t* master, span_t* reserve, size_t reserve_span_count) {\n\t_memory_global_reserve_master = master;\n\t_memory_global_reserve_count = reserve_span_count;\n\t_memory_global_reserve = reserve;\n}\n\n\n////////////\n///\n/// Span linked list management\n///\n//////\n\n//! Add a span to double linked list at the head\nstatic void\n_rpmalloc_span_double_link_list_add(span_t** head, span_t* span) {\n\tif (*head)\n\t\t(*head)->prev = span;\n\tspan->next = *head;\n\t*head = span;\n}\n\n//! Pop head span from double linked list\nstatic void\n_rpmalloc_span_double_link_list_pop_head(span_t** head, span_t* span) {\n\trpmalloc_assert(*head == span, \"Linked list corrupted\");\n\tspan = *head;\n\t*head = span->next;\n}\n\n//! Remove a span from double linked list\nstatic void\n_rpmalloc_span_double_link_list_remove(span_t** head, span_t* span) {\n\trpmalloc_assert(*head, \"Linked list corrupted\");\n\tif (*head == span) {\n\t\t*head = span->next;\n\t} else {\n\t\tspan_t* next_span = span->next;\n\t\tspan_t* prev_span = span->prev;\n\t\tprev_span->next = next_span;\n\t\tif (EXPECTED(next_span != 0))\n\t\t\tnext_span->prev = prev_span;\n\t}\n}\n\n\n////////////\n///\n/// Span control\n///\n//////\n\nstatic void\n_rpmalloc_heap_cache_insert(heap_t* heap, span_t* span);\n\nstatic void\n_rpmalloc_heap_finalize(heap_t* heap);\n\nstatic void\n_rpmalloc_heap_set_reserved_spans(heap_t* heap, span_t* master, span_t* reserve, size_t reserve_span_count);\n\n//! Declare the span to be a subspan and store distance from master span and span count\nstatic void\n_rpmalloc_span_mark_as_subspan_unless_master(span_t* master, span_t* subspan, size_t span_count) {\n\trpmalloc_assert((subspan != master) || (subspan->flags & SPAN_FLAG_MASTER), \"Span master pointer and/or flag mismatch\");\n\tif (subspan != master) {\n\t\tsubspan->flags = SPAN_FLAG_SUBSPAN;\n\t\tsubspan->offset_from_master = (uint32_t)((uintptr_t)pointer_diff(subspan, master) >> _memory_span_size_shift);\n\t\tsubspan->align_offset = 0;\n\t}\n\tsubspan->span_count = (uint32_t)span_count;\n}\n\n//! Use reserved spans to fulfill a memory map request (reserve size must be checked by caller)\nstatic span_t*\n_rpmalloc_span_map_from_reserve(heap_t* heap, size_t span_count) {\n\t//Update the heap span reserve\n\tspan_t* span = heap->span_reserve;\n\theap->span_reserve = (span_t*)pointer_offset(span, span_count * _memory_span_size);\n\theap->spans_reserved -= (uint32_t)span_count;\n\n\t_rpmalloc_span_mark_as_subspan_unless_master(heap->span_reserve_master, span, span_count);\n\tif (span_count <= LARGE_CLASS_COUNT)\n\t\t_rpmalloc_stat_inc(&heap->span_use[span_count - 1].spans_from_reserved);\n\n\treturn span;\n}\n\n//! Get the aligned number of spans to map in based on wanted count, configured mapping granularity and the page size\nstatic size_t\n_rpmalloc_span_align_count(size_t span_count) {\n\tsize_t request_count = (span_count > _memory_span_map_count) ? span_count : _memory_span_map_count;\n\tif ((_memory_page_size > _memory_span_size) && ((request_count * _memory_span_size) % _memory_page_size))\n\t\trequest_count += _memory_span_map_count - (request_count % _memory_span_map_count);\n\treturn request_count;\n}\n\n//! Setup a newly mapped span\nstatic void\n_rpmalloc_span_initialize(span_t* span, size_t total_span_count, size_t span_count, size_t align_offset) {\n\tspan->total_spans = (uint32_t)total_span_count;\n\tspan->span_count = (uint32_t)span_count;\n\tspan->align_offset = (uint32_t)align_offset;\n\tspan->flags = SPAN_FLAG_MASTER;\n\tatomic_store32(&span->remaining_spans, (int32_t)total_span_count);\n}\n\nstatic void\n_rpmalloc_span_unmap(span_t* span);\n\n//! Map an aligned set of spans, taking configured mapping granularity and the page size into account\nstatic span_t*\n_rpmalloc_span_map_aligned_count(heap_t* heap, size_t span_count) {\n\t//If we already have some, but not enough, reserved spans, release those to heap cache and map a new\n\t//full set of spans. Otherwise we would waste memory if page size > span size (huge pages)\n\tsize_t aligned_span_count = _rpmalloc_span_align_count(span_count);\n\tsize_t align_offset = 0;\n\tspan_t* span = (span_t*)_rpmalloc_mmap(aligned_span_count * _memory_span_size, &align_offset);\n\tif (!span)\n\t\treturn 0;\n\t_rpmalloc_span_initialize(span, aligned_span_count, span_count, align_offset);\n\t_rpmalloc_stat_inc(&_master_spans);\n\tif (span_count <= LARGE_CLASS_COUNT)\n\t\t_rpmalloc_stat_inc(&heap->span_use[span_count - 1].spans_map_calls);\n\tif (aligned_span_count > span_count) {\n\t\tspan_t* reserved_spans = (span_t*)pointer_offset(span, span_count * _memory_span_size);\n\t\tsize_t reserved_count = aligned_span_count - span_count;\n\t\tif (heap->spans_reserved) {\n\t\t\t_rpmalloc_span_mark_as_subspan_unless_master(heap->span_reserve_master, heap->span_reserve, heap->spans_reserved);\n\t\t\t_rpmalloc_heap_cache_insert(heap, heap->span_reserve);\n\t\t}\n\t\tif (reserved_count > _memory_heap_reserve_count) {\n\t\t\t// If huge pages or eager spam map count, the global reserve spin lock is held by caller, _rpmalloc_span_map\n\t\t\trpmalloc_assert(atomic_load32(&_memory_global_lock) == 1, \"Global spin lock not held as expected\");\n\t\t\tsize_t remain_count = reserved_count - _memory_heap_reserve_count;\n\t\t\treserved_count = _memory_heap_reserve_count;\n\t\t\tspan_t* remain_span = (span_t*)pointer_offset(reserved_spans, reserved_count * _memory_span_size);\n\t\t\tif (_memory_global_reserve) {\n\t\t\t\t_rpmalloc_span_mark_as_subspan_unless_master(_memory_global_reserve_master, _memory_global_reserve, _memory_global_reserve_count);\n\t\t\t\t_rpmalloc_span_unmap(_memory_global_reserve);\n\t\t\t}\n\t\t\t_rpmalloc_global_set_reserved_spans(span, remain_span, remain_count);\n\t\t}\n\t\t_rpmalloc_heap_set_reserved_spans(heap, span, reserved_spans, reserved_count);\n\t}\n\treturn span;\n}\n\n//! Map in memory pages for the given number of spans (or use previously reserved pages)\nstatic span_t*\n_rpmalloc_span_map(heap_t* heap, size_t span_count) {\n\tif (span_count <= heap->spans_reserved)\n\t\treturn _rpmalloc_span_map_from_reserve(heap, span_count);\n\tspan_t* span = 0;\n\tint use_global_reserve = (_memory_page_size > _memory_span_size) || (_memory_span_map_count > _memory_heap_reserve_count);\n\tif (use_global_reserve) {\n\t\t// If huge pages, make sure only one thread maps more memory to avoid bloat\n\t\twhile (!atomic_cas32_acquire(&_memory_global_lock, 1, 0))\n\t\t\t_rpmalloc_spin();\n\t\tif (_memory_global_reserve_count >= span_count) {\n\t\t\tsize_t reserve_count = (!heap->spans_reserved ? _memory_heap_reserve_count : span_count);\n\t\t\tif (_memory_global_reserve_count < reserve_count)\n\t\t\t\treserve_count = _memory_global_reserve_count;\n\t\t\tspan = _rpmalloc_global_get_reserved_spans(reserve_count);\n\t\t\tif (span) {\n\t\t\t\tif (reserve_count > span_count) {\n\t\t\t\t\tspan_t* reserved_span = (span_t*)pointer_offset(span, span_count << _memory_span_size_shift);\n\t\t\t\t\t_rpmalloc_heap_set_reserved_spans(heap, _memory_global_reserve_master, reserved_span, reserve_count - span_count);\n\t\t\t\t}\n\t\t\t\t// Already marked as subspan in _rpmalloc_global_get_reserved_spans\n\t\t\t\tspan->span_count = (uint32_t)span_count;\n\t\t\t}\n\t\t}\n\t}\n\tif (!span)\n\t\tspan = _rpmalloc_span_map_aligned_count(heap, span_count);\n\tif (use_global_reserve)\n\t\tatomic_store32_release(&_memory_global_lock, 0);\n\treturn span;\n}\n\n//! Unmap memory pages for the given number of spans (or mark as unused if no partial unmappings)\nstatic void\n_rpmalloc_span_unmap(span_t* span) {\n\trpmalloc_assert((span->flags & SPAN_FLAG_MASTER) || (span->flags & SPAN_FLAG_SUBSPAN), \"Span flag corrupted\");\n\trpmalloc_assert(!(span->flags & SPAN_FLAG_MASTER) || !(span->flags & SPAN_FLAG_SUBSPAN), \"Span flag corrupted\");\n\n\tint is_master = !!(span->flags & SPAN_FLAG_MASTER);\n\tspan_t* master = is_master ? span : ((span_t*)pointer_offset(span, -(intptr_t)((uintptr_t)span->offset_from_master * _memory_span_size)));\n\trpmalloc_assert(is_master || (span->flags & SPAN_FLAG_SUBSPAN), \"Span flag corrupted\");\n\trpmalloc_assert(master->flags & SPAN_FLAG_MASTER, \"Span flag corrupted\");\n\n\tsize_t span_count = span->span_count;\n\tif (!is_master) {\n\t\t//Directly unmap subspans (unless huge pages, in which case we defer and unmap entire page range with master)\n\t\trpmalloc_assert(span->align_offset == 0, \"Span align offset corrupted\");\n\t\tif (_memory_span_size >= _memory_page_size)\n\t\t\t_rpmalloc_unmap(span, span_count * _memory_span_size, 0, 0);\n\t} else {\n\t\t//Special double flag to denote an unmapped master\n\t\t//It must be kept in memory since span header must be used\n\t\tspan->flags |= SPAN_FLAG_MASTER | SPAN_FLAG_SUBSPAN | SPAN_FLAG_UNMAPPED_MASTER;\n\t\t_rpmalloc_stat_add(&_unmapped_master_spans, 1);\n\t}\n\n\tif (atomic_add32(&master->remaining_spans, -(int32_t)span_count) <= 0) {\n\t\t//Everything unmapped, unmap the master span with release flag to unmap the entire range of the super span\n\t\trpmalloc_assert(!!(master->flags & SPAN_FLAG_MASTER) && !!(master->flags & SPAN_FLAG_SUBSPAN), \"Span flag corrupted\");\n\t\tsize_t unmap_count = master->span_count;\n\t\tif (_memory_span_size < _memory_page_size)\n\t\t\tunmap_count = master->total_spans;\n\t\t_rpmalloc_stat_sub(&_master_spans, 1);\n\t\t_rpmalloc_stat_sub(&_unmapped_master_spans, 1);\n\t\t_rpmalloc_unmap(master, unmap_count * _memory_span_size, master->align_offset, (size_t)master->total_spans * _memory_span_size);\n\t}\n}\n\n//! Move the span (used for small or medium allocations) to the heap thread cache\nstatic void\n_rpmalloc_span_release_to_cache(heap_t* heap, span_t* span) {\n\trpmalloc_assert(heap == span->heap, \"Span heap pointer corrupted\");\n\trpmalloc_assert(span->size_class < SIZE_CLASS_COUNT, \"Invalid span size class\");\n\trpmalloc_assert(span->span_count == 1, \"Invalid span count\");\n#if ENABLE_ADAPTIVE_THREAD_CACHE || ENABLE_STATISTICS\n\tatomic_decr32(&heap->span_use[0].current);\n#endif\n\t_rpmalloc_stat_dec(&heap->size_class_use[span->size_class].spans_current);\n\tif (!heap->finalize) {\n\t\t_rpmalloc_stat_inc(&heap->span_use[0].spans_to_cache);\n\t\t_rpmalloc_stat_inc(&heap->size_class_use[span->size_class].spans_to_cache);\n\t\tif (heap->size_class[span->size_class].cache)\n\t\t\t_rpmalloc_heap_cache_insert(heap, heap->size_class[span->size_class].cache);\n\t\theap->size_class[span->size_class].cache = span;\n\t} else {\n\t\t_rpmalloc_span_unmap(span);\n\t}\n}\n\n//! Initialize a (partial) free list up to next system memory page, while reserving the first block\n//! as allocated, returning number of blocks in list\nstatic uint32_t\nfree_list_partial_init(void** list, void** first_block, void* page_start, void* block_start, uint32_t block_count, uint32_t block_size) {\n\trpmalloc_assert(block_count, \"Internal failure\");\n\t*first_block = block_start;\n\tif (block_count > 1) {\n\t\tvoid* free_block = pointer_offset(block_start, block_size);\n\t\tvoid* block_end = pointer_offset(block_start, (size_t)block_size * block_count);\n\t\t//If block size is less than half a memory page, bound init to next memory page boundary\n\t\tif (block_size < (_memory_page_size >> 1)) {\n\t\t\tvoid* page_end = pointer_offset(page_start, _memory_page_size);\n\t\t\tif (page_end < block_end)\n\t\t\t\tblock_end = page_end;\n\t\t}\n\t\t*list = free_block;\n\t\tblock_count = 2;\n\t\tvoid* next_block = pointer_offset(free_block, block_size);\n\t\twhile (next_block < block_end) {\n\t\t\t*((void**)free_block) = next_block;\n\t\t\tfree_block = next_block;\n\t\t\t++block_count;\n\t\t\tnext_block = pointer_offset(next_block, block_size);\n\t\t}\n\t\t*((void**)free_block) = 0;\n\t} else {\n\t\t*list = 0;\n\t}\n\treturn block_count;\n}\n\n//! Initialize an unused span (from cache or mapped) to be new active span, putting the initial free list in heap class free list\nstatic void*\n_rpmalloc_span_initialize_new(heap_t* heap, heap_size_class_t* heap_size_class, span_t* span, uint32_t class_idx) {\n\trpmalloc_assert(span->span_count == 1, \"Internal failure\");\n\tsize_class_t* size_class = _memory_size_class + class_idx;\n\tspan->size_class = class_idx;\n\tspan->heap = heap;\n\tspan->flags &= ~SPAN_FLAG_ALIGNED_BLOCKS;\n\tspan->block_size = size_class->block_size;\n\tspan->block_count = size_class->block_count;\n\tspan->free_list = 0;\n\tspan->list_size = 0;\n\tatomic_store_ptr_release(&span->free_list_deferred, 0);\n\n\t//Setup free list. Only initialize one system page worth of free blocks in list\n\tvoid* block;\n\tspan->free_list_limit = free_list_partial_init(&heap_size_class->free_list, &block, \n\t\tspan, pointer_offset(span, SPAN_HEADER_SIZE), size_class->block_count, size_class->block_size);\n\t//Link span as partial if there remains blocks to be initialized as free list, or full if fully initialized\n\tif (span->free_list_limit < span->block_count) {\n\t\t_rpmalloc_span_double_link_list_add(&heap_size_class->partial_span, span);\n\t\tspan->used_count = span->free_list_limit;\n\t} else {\n#if RPMALLOC_FIRST_CLASS_HEAPS\n\t\t_rpmalloc_span_double_link_list_add(&heap->full_span[class_idx], span);\n#endif\n\t\t++heap->full_span_count;\n\t\tspan->used_count = span->block_count;\n\t}\n\treturn block;\n}\n\nstatic void\n_rpmalloc_span_extract_free_list_deferred(span_t* span) {\n\t// We need acquire semantics on the CAS operation since we are interested in the list size\n\t// Refer to _rpmalloc_deallocate_defer_small_or_medium for further comments on this dependency\n\tdo {\n\t\tspan->free_list = atomic_exchange_ptr_acquire(&span->free_list_deferred, INVALID_POINTER);\n\t} while (span->free_list == INVALID_POINTER);\n\tspan->used_count -= span->list_size;\n\tspan->list_size = 0;\n\tatomic_store_ptr_release(&span->free_list_deferred, 0);\n}\n\nstatic int\n_rpmalloc_span_is_fully_utilized(span_t* span) {\n\trpmalloc_assert(span->free_list_limit <= span->block_count, \"Span free list corrupted\");\n\treturn !span->free_list && (span->free_list_limit >= span->block_count);\n}\n\nstatic int\n_rpmalloc_span_finalize(heap_t* heap, size_t iclass, span_t* span, span_t** list_head) {\n\tvoid* free_list = heap->size_class[iclass].free_list;\n\tspan_t* class_span = (span_t*)((uintptr_t)free_list & _memory_span_mask);\n\tif (span == class_span) {\n\t\t// Adopt the heap class free list back into the span free list\n\t\tvoid* block = span->free_list;\n\t\tvoid* last_block = 0;\n\t\twhile (block) {\n\t\t\tlast_block = block;\n\t\t\tblock = *((void**)block);\n\t\t}\n\t\tuint32_t free_count = 0;\n\t\tblock = free_list;\n\t\twhile (block) {\n\t\t\t++free_count;\n\t\t\tblock = *((void**)block);\n\t\t}\n\t\tif (last_block) {\n\t\t\t*((void**)last_block) = free_list;\n\t\t} else {\n\t\t\tspan->free_list = free_list;\n\t\t}\n\t\theap->size_class[iclass].free_list = 0;\n\t\tspan->used_count -= free_count;\n\t}\n\t//If this assert triggers you have memory leaks\n\trpmalloc_assert(span->list_size == span->used_count, \"Memory leak detected\");\n\tif (span->list_size == span->used_count) {\n\t\t_rpmalloc_stat_dec(&heap->span_use[0].current);\n\t\t_rpmalloc_stat_dec(&heap->size_class_use[iclass].spans_current);\n\t\t// This function only used for spans in double linked lists\n\t\tif (list_head)\n\t\t\t_rpmalloc_span_double_link_list_remove(list_head, span);\n\t\t_rpmalloc_span_unmap(span);\n\t\treturn 1;\n\t}\n\treturn 0;\n}\n\n\n////////////\n///\n/// Global cache\n///\n//////\n\n#if ENABLE_GLOBAL_CACHE\n\n//! Finalize a global cache\nstatic void\n_rpmalloc_global_cache_finalize(global_cache_t* cache) {\n\twhile (!atomic_cas32_acquire(&cache->lock, 1, 0))\n\t\t_rpmalloc_spin();\n\n\tfor (size_t ispan = 0; ispan < cache->count; ++ispan)\n\t\t_rpmalloc_span_unmap(cache->span[ispan]);\n\tcache->count = 0;\n\n\twhile (cache->overflow) {\n\t\tspan_t* span = cache->overflow;\n\t\tcache->overflow = span->next;\n\t\t_rpmalloc_span_unmap(span);\n\t}\n\n\tatomic_store32_release(&cache->lock, 0);\n}\n\nstatic void\n_rpmalloc_global_cache_insert_spans(span_t** span, size_t span_count, size_t count) {\n\tconst size_t cache_limit = (span_count == 1) ? \n\t\tGLOBAL_CACHE_MULTIPLIER * MAX_THREAD_SPAN_CACHE :\n\t\tGLOBAL_CACHE_MULTIPLIER * (MAX_THREAD_SPAN_LARGE_CACHE - (span_count >> 1));\n\n\tglobal_cache_t* cache = &_memory_span_cache[span_count - 1];\n\n\tsize_t insert_count = count;\n\twhile (!atomic_cas32_acquire(&cache->lock, 1, 0))\n\t\t_rpmalloc_spin();\n\n#if ENABLE_STATISTICS\n\tcache->insert_count += count;\n#endif\n\tif ((cache->count + insert_count) > cache_limit)\n\t\tinsert_count = cache_limit - cache->count;\n\n\tmemcpy(cache->span + cache->count, span, sizeof(span_t*) * insert_count);\n\tcache->count += (uint32_t)insert_count;\n\n#if ENABLE_UNLIMITED_CACHE\n\twhile (insert_count < count) {\n#else\n\t// Enable unlimited cache if huge pages, or we will leak since it is unlikely that an entire huge page\n\t// will be unmapped, and we're unable to partially decommit a huge page\n\twhile ((_memory_page_size > _memory_span_size) && (insert_count < count)) {\n#endif\t\t\n\t\tspan_t* current_span = span[insert_count++];\n\t\tcurrent_span->next = cache->overflow;\n\t\tcache->overflow = current_span;\n\t}\n\tatomic_store32_release(&cache->lock, 0);\n\n\tspan_t* keep = 0;\n\tfor (size_t ispan = insert_count; ispan < count; ++ispan) {\n\t\tspan_t* current_span = span[ispan];\n\t\t// Keep master spans that has remaining subspans to avoid dangling them\n\t\tif ((current_span->flags & SPAN_FLAG_MASTER) &&\n\t\t    (atomic_load32(&current_span->remaining_spans) > (int32_t)current_span->span_count)) {\n\t\t\tcurrent_span->next = keep;\n\t\t\tkeep = current_span;\n\t\t} else {\n\t\t\t_rpmalloc_span_unmap(current_span);\n\t\t}\n\t}\n\n\tif (keep) {\n\t\twhile (!atomic_cas32_acquire(&cache->lock, 1, 0))\n\t\t\t_rpmalloc_spin();\n\n\t\tsize_t islot = 0;\n\t\twhile (keep) {\n\t\t\tfor (; islot < cache->count; ++islot) {\n\t\t\t\tspan_t* current_span = cache->span[islot];\n\t\t\t\tif (!(current_span->flags & SPAN_FLAG_MASTER) || ((current_span->flags & SPAN_FLAG_MASTER) &&\n\t\t\t\t    (atomic_load32(&current_span->remaining_spans) <= (int32_t)current_span->span_count))) {\n\t\t\t\t\t_rpmalloc_span_unmap(current_span);\n\t\t\t\t\tcache->span[islot] = keep;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (islot == cache->count)\n\t\t\t\tbreak;\n\t\t\tkeep = keep->next;\n\t\t}\n\n\t\tif (keep) {\n\t\t\tspan_t* tail = keep;\n\t\t\twhile (tail->next)\n\t\t\t\ttail = tail->next;\n\t\t\ttail->next = cache->overflow;\n\t\t\tcache->overflow = keep;\n\t\t}\n\n\t\tatomic_store32_release(&cache->lock, 0);\n\t}\n}\n\nstatic size_t\n_rpmalloc_global_cache_extract_spans(span_t** span, size_t span_count, size_t count) {\n\tglobal_cache_t* cache = &_memory_span_cache[span_count - 1];\n\n\tsize_t extract_count = 0;\n\twhile (!atomic_cas32_acquire(&cache->lock, 1, 0))\n\t\t_rpmalloc_spin();\n\n#if ENABLE_STATISTICS\n\tcache->extract_count += count;\n#endif\n\tsize_t want = count - extract_count;\n\tif (want > cache->count)\n\t\twant = cache->count;\n\n\tmemcpy(span + extract_count, cache->span + (cache->count - want), sizeof(span_t*) * want);\n\tcache->count -= (uint32_t)want;\n\textract_count += want;\n\n\twhile ((extract_count < count) && cache->overflow) {\n\t\tspan_t* current_span = cache->overflow;\n\t\tspan[extract_count++] = current_span;\n\t\tcache->overflow = current_span->next;\n\t}\n\n#if ENABLE_ASSERTS\n\tfor (size_t ispan = 0; ispan < extract_count; ++ispan) {\n\t\tassert(span[ispan]->span_count == span_count);\n\t}\n#endif\n\n\tatomic_store32_release(&cache->lock, 0);\n\n\treturn extract_count;\n}\n\n#endif\n\n////////////\n///\n/// Heap control\n///\n//////\n\nstatic void _rpmalloc_deallocate_huge(span_t*);\n\n//! Store the given spans as reserve in the given heap\nstatic void\n_rpmalloc_heap_set_reserved_spans(heap_t* heap, span_t* master, span_t* reserve, size_t reserve_span_count) {\n\theap->span_reserve_master = master;\n\theap->span_reserve = reserve;\n\theap->spans_reserved = (uint32_t)reserve_span_count;\n}\n\n//! Adopt the deferred span cache list, optionally extracting the first single span for immediate re-use\nstatic void\n_rpmalloc_heap_cache_adopt_deferred(heap_t* heap, span_t** single_span) {\n\tspan_t* span = (span_t*)((void*)atomic_exchange_ptr_acquire(&heap->span_free_deferred, 0));\n\twhile (span) {\n\t\tspan_t* next_span = (span_t*)span->free_list;\n\t\trpmalloc_assert(span->heap == heap, \"Span heap pointer corrupted\");\n\t\tif (EXPECTED(span->size_class < SIZE_CLASS_COUNT)) {\n\t\t\trpmalloc_assert(heap->full_span_count, \"Heap span counter corrupted\");\n\t\t\t--heap->full_span_count;\n\t\t\t_rpmalloc_stat_dec(&heap->span_use[0].spans_deferred);\n#if RPMALLOC_FIRST_CLASS_HEAPS\n\t\t\t_rpmalloc_span_double_link_list_remove(&heap->full_span[span->size_class], span);\n#endif\n\t\t\t_rpmalloc_stat_dec(&heap->span_use[0].current);\n\t\t\t_rpmalloc_stat_dec(&heap->size_class_use[span->size_class].spans_current);\n\t\t\tif (single_span && !*single_span)\n\t\t\t\t*single_span = span;\n\t\t\telse\n\t\t\t\t_rpmalloc_heap_cache_insert(heap, span);\n\t\t} else {\n\t\t\tif (span->size_class == SIZE_CLASS_HUGE) {\n\t\t\t\t_rpmalloc_deallocate_huge(span);\n\t\t\t} else {\n\t\t\t\trpmalloc_assert(span->size_class == SIZE_CLASS_LARGE, \"Span size class invalid\");\n\t\t\t\trpmalloc_assert(heap->full_span_count, \"Heap span counter corrupted\");\n\t\t\t\t--heap->full_span_count;\n#if RPMALLOC_FIRST_CLASS_HEAPS\n\t\t\t\t_rpmalloc_span_double_link_list_remove(&heap->large_huge_span, span);\n#endif\n\t\t\t\tuint32_t idx = span->span_count - 1;\n\t\t\t\t_rpmalloc_stat_dec(&heap->span_use[idx].spans_deferred);\n\t\t\t\t_rpmalloc_stat_dec(&heap->span_use[idx].current);\n\t\t\t\tif (!idx && single_span && !*single_span)\n\t\t\t\t\t*single_span = span;\n\t\t\t\telse\n\t\t\t\t\t_rpmalloc_heap_cache_insert(heap, span);\n\t\t\t}\n\t\t}\n\t\tspan = next_span;\n\t}\n}\n\nstatic void\n_rpmalloc_heap_unmap(heap_t* heap) {\n\tif (!heap->master_heap) {\n\t\tif ((heap->finalize > 1) && !atomic_load32(&heap->child_count)) {\n\t\t\tspan_t* span = (span_t*)((uintptr_t)heap & _memory_span_mask);\n\t\t\t_rpmalloc_span_unmap(span);\n\t\t}\n\t} else {\n\t\tif (atomic_decr32(&heap->master_heap->child_count) == 0) {\n\t\t\t_rpmalloc_heap_unmap(heap->master_heap);\n\t\t}\n\t}\n}\n\nstatic void\n_rpmalloc_heap_global_finalize(heap_t* heap) {\n\tif (heap->finalize++ > 1) {\n\t\t--heap->finalize;\n\t\treturn;\n\t}\n\n\t_rpmalloc_heap_finalize(heap);\n\n#if ENABLE_THREAD_CACHE\n\tfor (size_t iclass = 0; iclass < LARGE_CLASS_COUNT; ++iclass) {\n\t\tspan_cache_t* span_cache;\n\t\tif (!iclass)\n\t\t\tspan_cache = &heap->span_cache;\n\t\telse\n\t\t\tspan_cache = (span_cache_t*)(heap->span_large_cache + (iclass - 1));\n\t\tfor (size_t ispan = 0; ispan < span_cache->count; ++ispan)\n\t\t\t_rpmalloc_span_unmap(span_cache->span[ispan]);\n\t\tspan_cache->count = 0;\n\t}\n#endif\n\n\tif (heap->full_span_count) {\n\t\t--heap->finalize;\n\t\treturn;\n\t}\n\n\tfor (size_t iclass = 0; iclass < SIZE_CLASS_COUNT; ++iclass) {\n\t\tif (heap->size_class[iclass].free_list || heap->size_class[iclass].partial_span) {\n\t\t\t--heap->finalize;\n\t\t\treturn;\n\t\t}\n\t}\n\t//Heap is now completely free, unmap and remove from heap list\n\tsize_t list_idx = (size_t)heap->id % HEAP_ARRAY_SIZE;\n\theap_t* list_heap = _memory_heaps[list_idx];\n\tif (list_heap == heap) {\n\t\t_memory_heaps[list_idx] = heap->next_heap;\n\t} else {\n\t\twhile (list_heap->next_heap != heap)\n\t\t\tlist_heap = list_heap->next_heap;\n\t\tlist_heap->next_heap = heap->next_heap;\n\t}\n\n\t_rpmalloc_heap_unmap(heap);\n}\n\n//! Insert a single span into thread heap cache, releasing to global cache if overflow\nstatic void\n_rpmalloc_heap_cache_insert(heap_t* heap, span_t* span) {\n\tif (UNEXPECTED(heap->finalize != 0)) {\n\t\t_rpmalloc_span_unmap(span);\n\t\t_rpmalloc_heap_global_finalize(heap);\n\t\treturn;\n\t}\n#if ENABLE_THREAD_CACHE\n\tsize_t span_count = span->span_count;\n\t_rpmalloc_stat_inc(&heap->span_use[span_count - 1].spans_to_cache);\n\tif (span_count == 1) {\n\t\tspan_cache_t* span_cache = &heap->span_cache;\n\t\tspan_cache->span[span_cache->count++] = span;\n\t\tif (span_cache->count == MAX_THREAD_SPAN_CACHE) {\n\t\t\tconst size_t remain_count = MAX_THREAD_SPAN_CACHE - THREAD_SPAN_CACHE_TRANSFER;\n#if ENABLE_GLOBAL_CACHE\n\t\t\t_rpmalloc_stat_add64(&heap->thread_to_global, THREAD_SPAN_CACHE_TRANSFER * _memory_span_size);\n\t\t\t_rpmalloc_stat_add(&heap->span_use[span_count - 1].spans_to_global, THREAD_SPAN_CACHE_TRANSFER);\n\t\t\t_rpmalloc_global_cache_insert_spans(span_cache->span + remain_count, span_count, THREAD_SPAN_CACHE_TRANSFER);\n#else\n\t\t\tfor (size_t ispan = 0; ispan < THREAD_SPAN_CACHE_TRANSFER; ++ispan)\n\t\t\t\t_rpmalloc_span_unmap(span_cache->span[remain_count + ispan]);\n#endif\n\t\t\tspan_cache->count = remain_count;\n\t\t}\n\t} else {\n\t\tsize_t cache_idx = span_count - 2;\n\t\tspan_large_cache_t* span_cache = heap->span_large_cache + cache_idx;\n\t\tspan_cache->span[span_cache->count++] = span;\n\t\tconst size_t cache_limit = (MAX_THREAD_SPAN_LARGE_CACHE - (span_count >> 1));\n\t\tif (span_cache->count == cache_limit) {\n\t\t\tconst size_t transfer_limit = 2 + (cache_limit >> 2);\n\t\t\tconst size_t transfer_count = (THREAD_SPAN_LARGE_CACHE_TRANSFER <= transfer_limit ? THREAD_SPAN_LARGE_CACHE_TRANSFER : transfer_limit);\n\t\t\tconst size_t remain_count = cache_limit - transfer_count;\n#if ENABLE_GLOBAL_CACHE\n\t\t\t_rpmalloc_stat_add64(&heap->thread_to_global, transfer_count * span_count * _memory_span_size);\n\t\t\t_rpmalloc_stat_add(&heap->span_use[span_count - 1].spans_to_global, transfer_count);\n\t\t\t_rpmalloc_global_cache_insert_spans(span_cache->span + remain_count, span_count, transfer_count);\n#else\n\t\t\tfor (size_t ispan = 0; ispan < transfer_count; ++ispan)\n\t\t\t\t_rpmalloc_span_unmap(span_cache->span[remain_count + ispan]);\n#endif\n\t\t\tspan_cache->count = remain_count;\n\t\t}\n\t}\n#else\n\t(void)sizeof(heap);\n\t_rpmalloc_span_unmap(span);\n#endif\n}\n\n//! Extract the given number of spans from the different cache levels\nstatic span_t*\n_rpmalloc_heap_thread_cache_extract(heap_t* heap, size_t span_count) {\n\tspan_t* span = 0;\n#if ENABLE_THREAD_CACHE\n\tspan_cache_t* span_cache;\n\tif (span_count == 1)\n\t\tspan_cache = &heap->span_cache;\n\telse\n\t\tspan_cache = (span_cache_t*)(heap->span_large_cache + (span_count - 2));\n\tif (span_cache->count) {\n\t\t_rpmalloc_stat_inc(&heap->span_use[span_count - 1].spans_from_cache);\n\t\treturn span_cache->span[--span_cache->count];\n\t}\n#endif\n\treturn span;\n}\n\nstatic span_t*\n_rpmalloc_heap_thread_cache_deferred_extract(heap_t* heap, size_t span_count) {\n\tspan_t* span = 0;\n\tif (span_count == 1) {\n\t\t_rpmalloc_heap_cache_adopt_deferred(heap, &span);\n\t} else {\n\t\t_rpmalloc_heap_cache_adopt_deferred(heap, 0);\n\t\tspan = _rpmalloc_heap_thread_cache_extract(heap, span_count);\n\t}\n\treturn span;\n}\n\nstatic span_t*\n_rpmalloc_heap_reserved_extract(heap_t* heap, size_t span_count) {\n\tif (heap->spans_reserved >= span_count)\n\t\treturn _rpmalloc_span_map(heap, span_count);\n\treturn 0;\n}\n\n//! Extract a span from the global cache\nstatic span_t*\n_rpmalloc_heap_global_cache_extract(heap_t* heap, size_t span_count) {\n#if ENABLE_GLOBAL_CACHE\n#if ENABLE_THREAD_CACHE\n\tspan_cache_t* span_cache;\n\tsize_t wanted_count;\n\tif (span_count == 1) {\n\t\tspan_cache = &heap->span_cache;\n\t\twanted_count = THREAD_SPAN_CACHE_TRANSFER;\n\t} else {\n\t\tspan_cache = (span_cache_t*)(heap->span_large_cache + (span_count - 2));\n\t\twanted_count = THREAD_SPAN_LARGE_CACHE_TRANSFER;\n\t}\n\tspan_cache->count = _rpmalloc_global_cache_extract_spans(span_cache->span, span_count, wanted_count);\n\tif (span_cache->count) {\n\t\t_rpmalloc_stat_add64(&heap->global_to_thread, span_count * span_cache->count * _memory_span_size);\n\t\t_rpmalloc_stat_add(&heap->span_use[span_count - 1].spans_from_global, span_cache->count);\n\t\treturn span_cache->span[--span_cache->count];\n\t}\n#else\n\tspan_t* span = 0;\n\tsize_t count = _rpmalloc_global_cache_extract_spans(&span, span_count, 1);\n\tif (count) {\n\t\t_rpmalloc_stat_add64(&heap->global_to_thread, span_count * count * _memory_span_size);\n\t\t_rpmalloc_stat_add(&heap->span_use[span_count - 1].spans_from_global, count);\n\t\treturn span;\n\t}\n#endif\n#endif\n\t(void)sizeof(heap);\n\t(void)sizeof(span_count);\n\treturn 0;\n}\n\nstatic void\n_rpmalloc_inc_span_statistics(heap_t* heap, size_t span_count, uint32_t class_idx) {\n\t(void)sizeof(heap);\n\t(void)sizeof(span_count);\n\t(void)sizeof(class_idx);\n#if ENABLE_ADAPTIVE_THREAD_CACHE || ENABLE_STATISTICS\n\tuint32_t idx = (uint32_t)span_count - 1;\n\tuint32_t current_count = (uint32_t)atomic_incr32(&heap->span_use[idx].current);\n\tif (current_count > (uint32_t)atomic_load32(&heap->span_use[idx].high))\n\t\tatomic_store32(&heap->span_use[idx].high, (int32_t)current_count);\n\t_rpmalloc_stat_add_peak(&heap->size_class_use[class_idx].spans_current, 1, heap->size_class_use[class_idx].spans_peak);\n#endif\n}\n\n//! Get a span from one of the cache levels (thread cache, reserved, global cache) or fallback to mapping more memory\nstatic span_t*\n_rpmalloc_heap_extract_new_span(heap_t* heap, heap_size_class_t* heap_size_class, size_t span_count, uint32_t class_idx) {\n\tspan_t* span;\n#if ENABLE_THREAD_CACHE\n\tif (heap_size_class && heap_size_class->cache) {\n\t\tspan = heap_size_class->cache;\n\t\theap_size_class->cache = (heap->span_cache.count ? heap->span_cache.span[--heap->span_cache.count] : 0);\n\t\t_rpmalloc_inc_span_statistics(heap, span_count, class_idx);\n\t\treturn span;\n\t}\n#endif\n\t(void)sizeof(class_idx);\n\t// Allow 50% overhead to increase cache hits\n\tsize_t base_span_count = span_count;\n\tsize_t limit_span_count = (span_count > 2) ? (span_count + (span_count >> 1)) : span_count;\n\tif (limit_span_count > LARGE_CLASS_COUNT)\n\t\tlimit_span_count = LARGE_CLASS_COUNT;\n\tdo {\n\t\tspan = _rpmalloc_heap_thread_cache_extract(heap, span_count);\n\t\tif (EXPECTED(span != 0)) {\n\t\t\t_rpmalloc_stat_inc(&heap->size_class_use[class_idx].spans_from_cache);\n\t\t\t_rpmalloc_inc_span_statistics(heap, span_count, class_idx);\n\t\t\treturn span;\n\t\t}\n\t\tspan = _rpmalloc_heap_thread_cache_deferred_extract(heap, span_count);\n\t\tif (EXPECTED(span != 0)) {\n\t\t\t_rpmalloc_stat_inc(&heap->size_class_use[class_idx].spans_from_cache);\n\t\t\t_rpmalloc_inc_span_statistics(heap, span_count, class_idx);\n\t\t\treturn span;\n\t\t}\n\t\tspan = _rpmalloc_heap_reserved_extract(heap, span_count);\n\t\tif (EXPECTED(span != 0)) {\n\t\t\t_rpmalloc_stat_inc(&heap->size_class_use[class_idx].spans_from_reserved);\n\t\t\t_rpmalloc_inc_span_statistics(heap, span_count, class_idx);\n\t\t\treturn span;\n\t\t}\n\t\tspan = _rpmalloc_heap_global_cache_extract(heap, span_count);\n\t\tif (EXPECTED(span != 0)) {\n\t\t\t_rpmalloc_stat_inc(&heap->size_class_use[class_idx].spans_from_cache);\n\t\t\t_rpmalloc_inc_span_statistics(heap, span_count, class_idx);\n\t\t\treturn span;\n\t\t}\n\t\t++span_count;\n\t} while (span_count <= limit_span_count);\n\t//Final fallback, map in more virtual memory\n\tspan = _rpmalloc_span_map(heap, base_span_count);\n\t_rpmalloc_inc_span_statistics(heap, base_span_count, class_idx);\n\t_rpmalloc_stat_inc(&heap->size_class_use[class_idx].spans_map_calls);\n\treturn span;\n}\n\nstatic void\n_rpmalloc_heap_initialize(heap_t* heap) {\n\tmemset((void*)heap, 0, sizeof(heap_t));\n\t//Get a new heap ID\n\theap->id = 1 + atomic_incr32(&_memory_heap_id);\n\n\t//Link in heap in heap ID map\n\tsize_t list_idx = (size_t)heap->id % HEAP_ARRAY_SIZE;\n\theap->next_heap = _memory_heaps[list_idx];\n\t_memory_heaps[list_idx] = heap;\n}\n\nstatic void\n_rpmalloc_heap_orphan(heap_t* heap, int first_class) {\n\theap->owner_thread = (uintptr_t)-1;\n#if RPMALLOC_FIRST_CLASS_HEAPS\n\theap_t** heap_list = (first_class ? &_memory_first_class_orphan_heaps : &_memory_orphan_heaps);\n#else\n\t(void)sizeof(first_class);\n\theap_t** heap_list = &_memory_orphan_heaps;\n#endif\n\theap->next_orphan = *heap_list;\n\t*heap_list = heap;\n}\n\n//! Allocate a new heap from newly mapped memory pages\nstatic heap_t*\n_rpmalloc_heap_allocate_new(void) {\n\t// Map in pages for a 16 heaps. If page size is greater than required size for this, map a page and\n\t// use first part for heaps and remaining part for spans for allocations. Adds a lot of complexity,\n\t// but saves a lot of memory on systems where page size > 64 spans (4MiB)\n\tsize_t heap_size = sizeof(heap_t);\n\tsize_t aligned_heap_size = 16 * ((heap_size + 15) / 16);\n\tsize_t request_heap_count = 16;\n\tsize_t heap_span_count = ((aligned_heap_size * request_heap_count) + sizeof(span_t) + _memory_span_size - 1) / _memory_span_size;\n\tsize_t block_size = _memory_span_size * heap_span_count;\n\tsize_t span_count = heap_span_count;\n\tspan_t* span = 0;\n\t// If there are global reserved spans, use these first\n\tif (_memory_global_reserve_count >= heap_span_count) {\n\t\tspan = _rpmalloc_global_get_reserved_spans(heap_span_count);\n\t}\n\tif (!span) {\n\t\tif (_memory_page_size > block_size) {\n\t\t\tspan_count = _memory_page_size / _memory_span_size;\n\t\t\tblock_size = _memory_page_size;\n\t\t\t// If using huge pages, make sure to grab enough heaps to avoid reallocating a huge page just to serve new heaps\n\t\t\tsize_t possible_heap_count = (block_size - sizeof(span_t)) / aligned_heap_size;\n\t\t\tif (possible_heap_count >= (request_heap_count * 16))\n\t\t\t\trequest_heap_count *= 16;\n\t\t\telse if (possible_heap_count < request_heap_count)\n\t\t\t\trequest_heap_count = possible_heap_count;\n\t\t\theap_span_count = ((aligned_heap_size * request_heap_count) + sizeof(span_t) + _memory_span_size - 1) / _memory_span_size;\n\t\t}\n\n\t\tsize_t align_offset = 0;\n\t\tspan = (span_t*)_rpmalloc_mmap(block_size, &align_offset);\n\t\tif (!span)\n\t\t\treturn 0;\n\n\t\t// Master span will contain the heaps\n\t\t_rpmalloc_stat_inc(&_master_spans);\n\t\t_rpmalloc_span_initialize(span, span_count, heap_span_count, align_offset);\n\t}\n\n\tsize_t remain_size = _memory_span_size - sizeof(span_t);\n\theap_t* heap = (heap_t*)pointer_offset(span, sizeof(span_t));\n\t_rpmalloc_heap_initialize(heap);\n\n\t// Put extra heaps as orphans\n\tsize_t num_heaps = remain_size / aligned_heap_size;\n\tif (num_heaps < request_heap_count)\n\t\tnum_heaps = request_heap_count;\n\tatomic_store32(&heap->child_count, (int32_t)num_heaps - 1);\n\theap_t* extra_heap = (heap_t*)pointer_offset(heap, aligned_heap_size);\n\twhile (num_heaps > 1) {\n\t\t_rpmalloc_heap_initialize(extra_heap);\n\t\textra_heap->master_heap = heap;\n\t\t_rpmalloc_heap_orphan(extra_heap, 1);\n\t\textra_heap = (heap_t*)pointer_offset(extra_heap, aligned_heap_size);\n\t\t--num_heaps;\n\t}\n\n\tif (span_count > heap_span_count) {\n\t\t// Cap reserved spans\n\t\tsize_t remain_count = span_count - heap_span_count;\n\t\tsize_t reserve_count = (remain_count > _memory_heap_reserve_count ? _memory_heap_reserve_count : remain_count);\n\t\tspan_t* remain_span = (span_t*)pointer_offset(span, heap_span_count * _memory_span_size);\n\t\t_rpmalloc_heap_set_reserved_spans(heap, span, remain_span, reserve_count);\n\n\t\tif (remain_count > reserve_count) {\n\t\t\t// Set to global reserved spans\n\t\t\tremain_span = (span_t*)pointer_offset(remain_span, reserve_count * _memory_span_size);\n\t\t\treserve_count = remain_count - reserve_count;\n\t\t\t_rpmalloc_global_set_reserved_spans(span, remain_span, reserve_count);\n\t\t}\n\t}\n\n\treturn heap;\n}\n\nstatic heap_t*\n_rpmalloc_heap_extract_orphan(heap_t** heap_list) {\n\theap_t* heap = *heap_list;\n\t*heap_list = (heap ? heap->next_orphan : 0);\n\treturn heap;\n}\n\n//! Allocate a new heap, potentially reusing a previously orphaned heap\nstatic heap_t*\n_rpmalloc_heap_allocate(int first_class) {\n\theap_t* heap = 0;\n\twhile (!atomic_cas32_acquire(&_memory_global_lock, 1, 0))\n\t\t_rpmalloc_spin();\n\tif (first_class == 0)\n\t\theap = _rpmalloc_heap_extract_orphan(&_memory_orphan_heaps);\n#if RPMALLOC_FIRST_CLASS_HEAPS\n\tif (!heap)\n\t\theap = _rpmalloc_heap_extract_orphan(&_memory_first_class_orphan_heaps);\n#endif\n\tif (!heap)\n\t\theap = _rpmalloc_heap_allocate_new();\n\tatomic_store32_release(&_memory_global_lock, 0);\n\t_rpmalloc_heap_cache_adopt_deferred(heap, 0);\n\treturn heap;\n}\n\nextern thread_local bool RpThreadShutdown;\n\nstatic void\n_rpmalloc_heap_release(void* heapptr, int first_class, int release_cache) {\n\theap_t* heap = (heap_t*)heapptr;\n\tif (!heap)\n\t\treturn;\n\tRpThreadShutdown = true;\n\t//Release thread cache spans back to global cache\n\t_rpmalloc_heap_cache_adopt_deferred(heap, 0);\n\tif (release_cache  || heap->finalize) {\n#if ENABLE_THREAD_CACHE\n\t\tfor (size_t iclass = 0; iclass < LARGE_CLASS_COUNT; ++iclass) {\n\t\t\tspan_cache_t* span_cache;\n\t\t\tif (!iclass)\n\t\t\t\tspan_cache = &heap->span_cache;\n\t\t\telse\n\t\t\t\tspan_cache = (span_cache_t*)(heap->span_large_cache + (iclass - 1));\n\t\t\tif (!span_cache->count)\n\t\t\t\tcontinue;\n#if ENABLE_GLOBAL_CACHE\n\t\t\tif (heap->finalize) {\n\t\t\t\tfor (size_t ispan = 0; ispan < span_cache->count; ++ispan)\n\t\t\t\t\t_rpmalloc_span_unmap(span_cache->span[ispan]);\n\t\t\t} else {\n\t\t\t\t_rpmalloc_stat_add64(&heap->thread_to_global, span_cache->count * (iclass + 1) * _memory_span_size);\n\t\t\t\t_rpmalloc_stat_add(&heap->span_use[iclass].spans_to_global, span_cache->count);\n\t\t\t\t_rpmalloc_global_cache_insert_spans(span_cache->span, iclass + 1, span_cache->count);\n\t\t\t}\n#else\n\t\t\tfor (size_t ispan = 0; ispan < span_cache->count; ++ispan)\n\t\t\t\t_rpmalloc_span_unmap(span_cache->span[ispan]);\n#endif\n\t\t\tspan_cache->count = 0;\n\t\t}\n#endif\n\t}\n\n\tif (get_thread_heap_raw() == heap)\n\t\tset_thread_heap(0);\n\n#if ENABLE_STATISTICS\n\tatomic_decr32(&_memory_active_heaps);\n\trpmalloc_assert(atomic_load32(&_memory_active_heaps) >= 0, \"Still active heaps during finalization\");\n#endif\n\n\t// If we are forcibly terminating with _exit the state of the\n\t// lock atomic is unknown and it's best to just go ahead and exit\n\tif (get_thread_id() != _rpmalloc_main_thread_id) {\n\t\twhile (!atomic_cas32_acquire(&_memory_global_lock, 1, 0))\n\t\t\t_rpmalloc_spin();\n\t}\n\t_rpmalloc_heap_orphan(heap, first_class);\n\tatomic_store32_release(&_memory_global_lock, 0);\n}\n\nstatic void\n_rpmalloc_heap_release_raw(void* heapptr, int release_cache) {\n\t_rpmalloc_heap_release(heapptr, 0, release_cache);\n}\n\nstatic void\n_rpmalloc_heap_release_raw_fc(void* heapptr) {\n\t_rpmalloc_heap_release_raw(heapptr, 1);\n}\n\nstatic void\n_rpmalloc_heap_finalize(heap_t* heap) {\n\tif (heap->spans_reserved) {\n\t\tspan_t* span = _rpmalloc_span_map(heap, heap->spans_reserved);\n\t\t_rpmalloc_span_unmap(span);\n\t\theap->spans_reserved = 0;\n\t}\n\n\t_rpmalloc_heap_cache_adopt_deferred(heap, 0);\n\n\tfor (size_t iclass = 0; iclass < SIZE_CLASS_COUNT; ++iclass) {\n\t\tif (heap->size_class[iclass].cache)\n\t\t\t_rpmalloc_span_unmap(heap->size_class[iclass].cache);\n\t\theap->size_class[iclass].cache = 0;\n\t\tspan_t* span = heap->size_class[iclass].partial_span;\n\t\twhile (span) {\n\t\t\tspan_t* next = span->next;\n\t\t\t_rpmalloc_span_finalize(heap, iclass, span, &heap->size_class[iclass].partial_span);\n\t\t\tspan = next;\n\t\t}\n\t\t// If class still has a free list it must be a full span\n\t\tif (heap->size_class[iclass].free_list) {\n\t\t\tspan_t* class_span = (span_t*)((uintptr_t)heap->size_class[iclass].free_list & _memory_span_mask);\n\t\t\tspan_t** list = 0;\n#if RPMALLOC_FIRST_CLASS_HEAPS\n\t\t\tlist = &heap->full_span[iclass];\n#endif\n\t\t\t--heap->full_span_count;\n\t\t\tif (!_rpmalloc_span_finalize(heap, iclass, class_span, list)) {\n\t\t\t\tif (list)\n\t\t\t\t\t_rpmalloc_span_double_link_list_remove(list, class_span);\n\t\t\t\t_rpmalloc_span_double_link_list_add(&heap->size_class[iclass].partial_span, class_span);\n\t\t\t}\n\t\t}\n\t}\n\n#if ENABLE_THREAD_CACHE\n\tfor (size_t iclass = 0; iclass < LARGE_CLASS_COUNT; ++iclass) {\n\t\tspan_cache_t* span_cache;\n\t\tif (!iclass)\n\t\t\tspan_cache = &heap->span_cache;\n\t\telse\n\t\t\tspan_cache = (span_cache_t*)(heap->span_large_cache + (iclass - 1));\n\t\tfor (size_t ispan = 0; ispan < span_cache->count; ++ispan)\n\t\t\t_rpmalloc_span_unmap(span_cache->span[ispan]);\n\t\tspan_cache->count = 0;\n\t}\n#endif\n\trpmalloc_assert(!atomic_load_ptr(&heap->span_free_deferred), \"Heaps still active during finalization\");\n}\n\n\n////////////\n///\n/// Allocation entry points\n///\n//////\n\n//! Pop first block from a free list\nstatic void*\nfree_list_pop(void** list) {\n\tvoid* block = *list;\n\t*list = *((void**)block);\n\treturn block;\n}\n\n//! Allocate a small/medium sized memory block from the given heap\nstatic void*\n_rpmalloc_allocate_from_heap_fallback(heap_t* heap, heap_size_class_t* heap_size_class, uint32_t class_idx) {\n\tspan_t* span = heap_size_class->partial_span;\n\tif (EXPECTED(span != 0)) {\n\t\trpmalloc_assert(span->block_count == _memory_size_class[span->size_class].block_count, \"Span block count corrupted\");\n\t\trpmalloc_assert(!_rpmalloc_span_is_fully_utilized(span), \"Internal failure\");\n\t\tvoid* block;\n\t\tif (span->free_list) {\n\t\t\t//Span local free list is not empty, swap to size class free list\n\t\t\tblock = free_list_pop(&span->free_list);\n\t\t\theap_size_class->free_list = span->free_list;\n\t\t\tspan->free_list = 0;\n\t\t} else {\n\t\t\t//If the span did not fully initialize free list, link up another page worth of blocks\t\t\t\n\t\t\tvoid* block_start = pointer_offset(span, SPAN_HEADER_SIZE + ((size_t)span->free_list_limit * span->block_size));\n\t\t\tspan->free_list_limit += free_list_partial_init(&heap_size_class->free_list, &block,\n\t\t\t\t(void*)((uintptr_t)block_start & ~(_memory_page_size - 1)), block_start,\n\t\t\t\tspan->block_count - span->free_list_limit, span->block_size);\n\t\t}\n\t\trpmalloc_assert(span->free_list_limit <= span->block_count, \"Span block count corrupted\");\n\t\tspan->used_count = span->free_list_limit;\n\n\t\t//Swap in deferred free list if present\n\t\tif (atomic_load_ptr(&span->free_list_deferred))\n\t\t\t_rpmalloc_span_extract_free_list_deferred(span);\n\n\t\t//If span is still not fully utilized keep it in partial list and early return block\n\t\tif (!_rpmalloc_span_is_fully_utilized(span))\n\t\t\treturn block;\n\n\t\t//The span is fully utilized, unlink from partial list and add to fully utilized list\n\t\t_rpmalloc_span_double_link_list_pop_head(&heap_size_class->partial_span, span);\n#if RPMALLOC_FIRST_CLASS_HEAPS\n\t\t_rpmalloc_span_double_link_list_add(&heap->full_span[class_idx], span);\n#endif\n\t\t++heap->full_span_count;\n\t\treturn block;\n\t}\n\n\t//Find a span in one of the cache levels\n\tspan = _rpmalloc_heap_extract_new_span(heap, heap_size_class, 1, class_idx);\n\tif (EXPECTED(span != 0)) {\n\t\t//Mark span as owned by this heap and set base data, return first block\n\t\treturn _rpmalloc_span_initialize_new(heap, heap_size_class, span, class_idx);\n\t}\n\n\treturn 0;\n}\n\n//! Allocate a small sized memory block from the given heap\nstatic void*\n_rpmalloc_allocate_small(heap_t* heap, size_t size) {\n\trpmalloc_assert(heap, \"No thread heap\");\n\t//Small sizes have unique size classes\n\tconst uint32_t class_idx = (uint32_t)((size + (SMALL_GRANULARITY - 1)) >> SMALL_GRANULARITY_SHIFT);\n\theap_size_class_t* heap_size_class = heap->size_class + class_idx;\n\t_rpmalloc_stat_inc_alloc(heap, class_idx);\n\tif (EXPECTED(heap_size_class->free_list != 0))\n\t\treturn free_list_pop(&heap_size_class->free_list);\n\treturn _rpmalloc_allocate_from_heap_fallback(heap, heap_size_class, class_idx);\n}\n\n//! Allocate a medium sized memory block from the given heap\nstatic void*\n_rpmalloc_allocate_medium(heap_t* heap, size_t size) {\n\trpmalloc_assert(heap, \"No thread heap\");\n\t//Calculate the size class index and do a dependent lookup of the final class index (in case of merged classes)\n\tconst uint32_t base_idx = (uint32_t)(SMALL_CLASS_COUNT + ((size - (SMALL_SIZE_LIMIT + 1)) >> MEDIUM_GRANULARITY_SHIFT));\n\tconst uint32_t class_idx = _memory_size_class[base_idx].class_idx;\n\theap_size_class_t* heap_size_class = heap->size_class + class_idx;\n\t_rpmalloc_stat_inc_alloc(heap, class_idx);\n\tif (EXPECTED(heap_size_class->free_list != 0))\n\t\treturn free_list_pop(&heap_size_class->free_list);\n\treturn _rpmalloc_allocate_from_heap_fallback(heap, heap_size_class, class_idx);\n}\n\n//! Allocate a large sized memory block from the given heap\nstatic void*\n_rpmalloc_allocate_large(heap_t* heap, size_t size) {\n\trpmalloc_assert(heap, \"No thread heap\");\n\t//Calculate number of needed max sized spans (including header)\n\t//Since this function is never called if size > LARGE_SIZE_LIMIT\n\t//the span_count is guaranteed to be <= LARGE_CLASS_COUNT\n\tsize += SPAN_HEADER_SIZE;\n\tsize_t span_count = size >> _memory_span_size_shift;\n\tif (size & (_memory_span_size - 1))\n\t\t++span_count;\n\n\t//Find a span in one of the cache levels\n\tspan_t* span = _rpmalloc_heap_extract_new_span(heap, 0, span_count, SIZE_CLASS_LARGE);\n\tif (!span)\n\t\treturn span;\n\n\t//Mark span as owned by this heap and set base data\n\trpmalloc_assert(span->span_count >= span_count, \"Internal failure\");\n\tspan->size_class = SIZE_CLASS_LARGE;\n\tspan->heap = heap;\n\n#if RPMALLOC_FIRST_CLASS_HEAPS\n\t_rpmalloc_span_double_link_list_add(&heap->large_huge_span, span);\n#endif\n\t++heap->full_span_count;\n\n\treturn pointer_offset(span, SPAN_HEADER_SIZE);\n}\n\n//! Allocate a huge block by mapping memory pages directly\nstatic void*\n_rpmalloc_allocate_huge(heap_t* heap, size_t size) {\n\trpmalloc_assert(heap, \"No thread heap\");\n\t_rpmalloc_heap_cache_adopt_deferred(heap, 0);\n\tsize += SPAN_HEADER_SIZE;\n\tsize_t num_pages = size >> _memory_page_size_shift;\n\tif (size & (_memory_page_size - 1))\n\t\t++num_pages;\n\tsize_t align_offset = 0;\n\tspan_t* span = (span_t*)_rpmalloc_mmap(num_pages * _memory_page_size, &align_offset);\n\tif (!span)\n\t\treturn span;\n\n\t//Store page count in span_count\n\tspan->size_class = SIZE_CLASS_HUGE;\n\tspan->span_count = (uint32_t)num_pages;\n\tspan->align_offset = (uint32_t)align_offset;\n\tspan->heap = heap;\n\t_rpmalloc_stat_add_peak(&_huge_pages_current, num_pages, _huge_pages_peak);\n\n#if RPMALLOC_FIRST_CLASS_HEAPS\n\t_rpmalloc_span_double_link_list_add(&heap->large_huge_span, span);\n#endif\n\t++heap->full_span_count;\n\n\treturn pointer_offset(span, SPAN_HEADER_SIZE);\n}\n\n//! Allocate a block of the given size\nstatic void*\n_rpmalloc_allocate(heap_t* heap, size_t size) {\n\t_rpmalloc_stat_add64(&_allocation_counter, 1);\n\tif (EXPECTED(size <= SMALL_SIZE_LIMIT))\n\t\treturn _rpmalloc_allocate_small(heap, size);\n\telse if (size <= _memory_medium_size_limit)\n\t\treturn _rpmalloc_allocate_medium(heap, size);\n\telse if (size <= LARGE_SIZE_LIMIT)\n\t\treturn _rpmalloc_allocate_large(heap, size);\n\treturn _rpmalloc_allocate_huge(heap, size);\n}\n\nstatic void*\n_rpmalloc_aligned_allocate(heap_t* heap, size_t alignment, size_t size) {\n\tif (alignment <= SMALL_GRANULARITY)\n\t\treturn _rpmalloc_allocate(heap, size);\n\n#if ENABLE_VALIDATE_ARGS\n\tif ((size + alignment) < size) {\n\t\terrno = EINVAL;\n\t\treturn 0;\n\t}\n\tif (alignment & (alignment - 1)) {\n\t\terrno = EINVAL;\n\t\treturn 0;\n\t}\n#endif\n\n\tif ((alignment <= SPAN_HEADER_SIZE) && (size < _memory_medium_size_limit)) {\n\t\t// If alignment is less or equal to span header size (which is power of two),\n\t\t// and size aligned to span header size multiples is less than size + alignment,\n\t\t// then use natural alignment of blocks to provide alignment\n\t\tsize_t multiple_size = size ? (size + (SPAN_HEADER_SIZE - 1)) & ~(uintptr_t)(SPAN_HEADER_SIZE - 1) : SPAN_HEADER_SIZE;\n\t\trpmalloc_assert(!(multiple_size % SPAN_HEADER_SIZE), \"Failed alignment calculation\");\n\t\tif (multiple_size <= (size + alignment))\n\t\t\treturn _rpmalloc_allocate(heap, multiple_size);\n\t}\n\n\tvoid* ptr = 0;\n\tsize_t align_mask = alignment - 1;\n\tif (alignment <= _memory_page_size) {\n\t\tptr = _rpmalloc_allocate(heap, size + alignment);\n\t\tif ((uintptr_t)ptr & align_mask) {\n\t\t\tptr = (void*)(((uintptr_t)ptr & ~(uintptr_t)align_mask) + alignment);\n\t\t\t//Mark as having aligned blocks\n\t\t\tspan_t* span = (span_t*)((uintptr_t)ptr & _memory_span_mask);\n\t\t\tspan->flags |= SPAN_FLAG_ALIGNED_BLOCKS;\n\t\t}\n\t\treturn ptr;\n\t}\n\n\t// Fallback to mapping new pages for this request. Since pointers passed\n\t// to rpfree must be able to reach the start of the span by bitmasking of\n\t// the address with the span size, the returned aligned pointer from this\n\t// function must be with a span size of the start of the mapped area.\n\t// In worst case this requires us to loop and map pages until we get a\n\t// suitable memory address. It also means we can never align to span size\n\t// or greater, since the span header will push alignment more than one\n\t// span size away from span start (thus causing pointer mask to give us\n\t// an invalid span start on free)\n\tif (alignment & align_mask) {\n\t\terrno = EINVAL;\n\t\treturn 0;\n\t}\n\tif (alignment >= _memory_span_size) {\n\t\terrno = EINVAL;\n\t\treturn 0;\n\t}\n\n\tsize_t extra_pages = alignment / _memory_page_size;\n\n\t// Since each span has a header, we will at least need one extra memory page\n\tsize_t num_pages = 1 + (size / _memory_page_size);\n\tif (size & (_memory_page_size - 1))\n\t\t++num_pages;\n\n\tif (extra_pages > num_pages)\n\t\tnum_pages = 1 + extra_pages;\n\n\tsize_t original_pages = num_pages;\n\tsize_t limit_pages = (_memory_span_size / _memory_page_size) * 2;\n\tif (limit_pages < (original_pages * 2))\n\t\tlimit_pages = original_pages * 2;\n\n\tsize_t mapped_size, align_offset;\n\tspan_t* span;\n\nretry:\n\talign_offset = 0;\n\tmapped_size = num_pages * _memory_page_size;\n\n\tspan = (span_t*)_rpmalloc_mmap(mapped_size, &align_offset);\n\tif (!span) {\n\t\terrno = ENOMEM;\n\t\treturn 0;\n\t}\n\tptr = pointer_offset(span, SPAN_HEADER_SIZE);\n\n\tif ((uintptr_t)ptr & align_mask)\n\t\tptr = (void*)(((uintptr_t)ptr & ~(uintptr_t)align_mask) + alignment);\n\n\tif (((size_t)pointer_diff(ptr, span) >= _memory_span_size) ||\n\t    (pointer_offset(ptr, size) > pointer_offset(span, mapped_size)) ||\n\t    (((uintptr_t)ptr & _memory_span_mask) != (uintptr_t)span)) {\n\t\t_rpmalloc_unmap(span, mapped_size, align_offset, mapped_size);\n\t\t++num_pages;\n\t\tif (num_pages > limit_pages) {\n\t\t\terrno = EINVAL;\n\t\t\treturn 0;\n\t\t}\n\t\tgoto retry;\n\t}\n\n\t//Store page count in span_count\n\tspan->size_class = SIZE_CLASS_HUGE;\n\tspan->span_count = (uint32_t)num_pages;\n\tspan->align_offset = (uint32_t)align_offset;\n\tspan->heap = heap;\n\t_rpmalloc_stat_add_peak(&_huge_pages_current, num_pages, _huge_pages_peak);\n\n#if RPMALLOC_FIRST_CLASS_HEAPS\n\t_rpmalloc_span_double_link_list_add(&heap->large_huge_span, span);\n#endif\n\t++heap->full_span_count;\n\n\t_rpmalloc_stat_add64(&_allocation_counter, 1);\n\n\treturn ptr;\n}\n\n\n////////////\n///\n/// Deallocation entry points\n///\n//////\n\n//! Deallocate the given small/medium memory block in the current thread local heap\nstatic void\n_rpmalloc_deallocate_direct_small_or_medium(span_t* span, void* block) {\n\theap_t* heap = span->heap;\n\trpmalloc_assert(heap->owner_thread == get_thread_id() || !heap->owner_thread || heap->finalize, \"Internal failure\");\n\t//Add block to free list\n\tif (UNEXPECTED(_rpmalloc_span_is_fully_utilized(span))) {\n\t\tspan->used_count = span->block_count;\n#if RPMALLOC_FIRST_CLASS_HEAPS\n\t\t_rpmalloc_span_double_link_list_remove(&heap->full_span[span->size_class], span);\n#endif\n\t\t_rpmalloc_span_double_link_list_add(&heap->size_class[span->size_class].partial_span, span);\n\t\t--heap->full_span_count;\n\t}\n\t*((void**)block) = span->free_list;\n\t--span->used_count;\n\tspan->free_list = block;\n\tif (UNEXPECTED(span->used_count == span->list_size)) {\n\t\t// If there are no used blocks it is guaranteed that no other external thread is accessing the span\n\t\tif (span->used_count) {\n\t\t\t// Make sure we have synchronized the deferred list and list size by using acquire semantics\n\t\t\t// and guarantee that no external thread is accessing span concurrently\n\t\t\tvoid* free_list;\n\t\t\tdo {\n\t\t\t\tfree_list = atomic_exchange_ptr_acquire(&span->free_list_deferred, INVALID_POINTER);\n\t\t\t} while (free_list == INVALID_POINTER);\n\t\t\tatomic_store_ptr_release(&span->free_list_deferred, free_list);\n\t\t}\n\t\t_rpmalloc_span_double_link_list_remove(&heap->size_class[span->size_class].partial_span, span);\n\t\t_rpmalloc_span_release_to_cache(heap, span);\n\t}\n}\n\nstatic void\n_rpmalloc_deallocate_defer_free_span(heap_t* heap, span_t* span) {\n\tif (span->size_class != SIZE_CLASS_HUGE)\n\t\t_rpmalloc_stat_inc(&heap->span_use[span->span_count - 1].spans_deferred);\n\t//This list does not need ABA protection, no mutable side state\n\tdo {\n\t\tspan->free_list = (void*)atomic_load_ptr(&heap->span_free_deferred);\n\t} while (!atomic_cas_ptr(&heap->span_free_deferred, span, span->free_list));\n}\n\n//! Put the block in the deferred free list of the owning span\nstatic void\n_rpmalloc_deallocate_defer_small_or_medium(span_t* span, void* block) {\n\t// The memory ordering here is a bit tricky, to avoid having to ABA protect\n\t// the deferred free list to avoid desynchronization of list and list size\n\t// we need to have acquire semantics on successful CAS of the pointer to\n\t// guarantee the list_size variable validity + release semantics on pointer store\n\tvoid* free_list;\n\tdo {\n\t\tfree_list = atomic_exchange_ptr_acquire(&span->free_list_deferred, INVALID_POINTER);\n\t} while (free_list == INVALID_POINTER);\n\t*((void**)block) = free_list;\n\tuint32_t free_count = ++span->list_size;\n\tint all_deferred_free = (free_count == span->block_count);\n\tatomic_store_ptr_release(&span->free_list_deferred, block);\n\tif (all_deferred_free) {\n\t\t// Span was completely freed by this block. Due to the INVALID_POINTER spin lock\n\t\t// no other thread can reach this state simultaneously on this span.\n\t\t// Safe to move to owner heap deferred cache\n\t\t_rpmalloc_deallocate_defer_free_span(span->heap, span);\n\t}\n}\n\nstatic void\n_rpmalloc_deallocate_small_or_medium(span_t* span, void* p) {\n\t_rpmalloc_stat_inc_free(span->heap, span->size_class);\n\tif (span->flags & SPAN_FLAG_ALIGNED_BLOCKS) {\n\t\t//Realign pointer to block start\n\t\tvoid* blocks_start = pointer_offset(span, SPAN_HEADER_SIZE);\n\t\tuint32_t block_offset = (uint32_t)pointer_diff(p, blocks_start);\n\t\tp = pointer_offset(p, -(int32_t)(block_offset % span->block_size));\n\t}\n\t//Check if block belongs to this heap or if deallocation should be deferred\n#if RPMALLOC_FIRST_CLASS_HEAPS\n\tint defer = (span->heap->owner_thread && (span->heap->owner_thread != get_thread_id()) && !span->heap->finalize);\n#else\n\tint defer = ((span->heap->owner_thread != get_thread_id()) && !span->heap->finalize);\n#endif\n\tif (!defer)\n\t\t_rpmalloc_deallocate_direct_small_or_medium(span, p);\n\telse\n\t\t_rpmalloc_deallocate_defer_small_or_medium(span, p);\n}\n\n//! Deallocate the given large memory block to the current heap\nstatic void\n_rpmalloc_deallocate_large(span_t* span) {\n\trpmalloc_assert(span->size_class == SIZE_CLASS_LARGE, \"Bad span size class\");\n\trpmalloc_assert(!(span->flags & SPAN_FLAG_MASTER) || !(span->flags & SPAN_FLAG_SUBSPAN), \"Span flag corrupted\");\n\trpmalloc_assert((span->flags & SPAN_FLAG_MASTER) || (span->flags & SPAN_FLAG_SUBSPAN), \"Span flag corrupted\");\n\t//We must always defer (unless finalizing) if from another heap since we cannot touch the list or counters of another heap\n#if RPMALLOC_FIRST_CLASS_HEAPS\n\tint defer = (span->heap->owner_thread && (span->heap->owner_thread != get_thread_id()) && !span->heap->finalize);\n#else\n\tint defer = ((span->heap->owner_thread != get_thread_id()) && !span->heap->finalize);\n#endif\n\tif (defer) {\n\t\t_rpmalloc_deallocate_defer_free_span(span->heap, span);\n\t\treturn;\n\t}\n\trpmalloc_assert(span->heap->full_span_count, \"Heap span counter corrupted\");\n\t--span->heap->full_span_count;\n#if RPMALLOC_FIRST_CLASS_HEAPS\n\t_rpmalloc_span_double_link_list_remove(&span->heap->large_huge_span, span);\n#endif\n#if ENABLE_ADAPTIVE_THREAD_CACHE || ENABLE_STATISTICS\n\t//Decrease counter\n\tsize_t idx = span->span_count - 1;\n\tatomic_decr32(&span->heap->span_use[idx].current);\n#endif\n\theap_t* heap = span->heap;\n\trpmalloc_assert(heap, \"No thread heap\");\n#if ENABLE_THREAD_CACHE\n\tconst int set_as_reserved = ((span->span_count > 1) && (heap->span_cache.count == 0) && !heap->finalize && !heap->spans_reserved);\n#else\n\tconst int set_as_reserved = ((span->span_count > 1) && !heap->finalize && !heap->spans_reserved);\n#endif\n\tif (set_as_reserved) {\n\t\theap->span_reserve = span;\n\t\theap->spans_reserved = span->span_count;\n\t\tif (span->flags & SPAN_FLAG_MASTER) {\n\t\t\theap->span_reserve_master = span;\n\t\t} else { //SPAN_FLAG_SUBSPAN\n\t\t\tspan_t* master = (span_t*)pointer_offset(span, -(intptr_t)((size_t)span->offset_from_master * _memory_span_size));\n\t\t\theap->span_reserve_master = master;\n\t\t\trpmalloc_assert(master->flags & SPAN_FLAG_MASTER, \"Span flag corrupted\");\n\t\t\trpmalloc_assert(atomic_load32(&master->remaining_spans) >= (int32_t)span->span_count, \"Master span count corrupted\");\n\t\t}\n\t\t_rpmalloc_stat_inc(&heap->span_use[idx].spans_to_reserved);\n\t} else {\n\t\t//Insert into cache list\n\t\t_rpmalloc_heap_cache_insert(heap, span);\n\t}\n}\n\n//! Deallocate the given huge span\nstatic void\n_rpmalloc_deallocate_huge(span_t* span) {\n\trpmalloc_assert(span->heap, \"No span heap\");\n#if RPMALLOC_FIRST_CLASS_HEAPS\n\tint defer = (span->heap->owner_thread && (span->heap->owner_thread != get_thread_id()) && !span->heap->finalize);\n#else\n\tint defer = ((span->heap->owner_thread != get_thread_id()) && !span->heap->finalize);\n#endif\n\tif (defer) {\n\t\t_rpmalloc_deallocate_defer_free_span(span->heap, span);\n\t\treturn;\n\t}\n\trpmalloc_assert(span->heap->full_span_count, \"Heap span counter corrupted\");\n\t--span->heap->full_span_count;\n#if RPMALLOC_FIRST_CLASS_HEAPS\n\t_rpmalloc_span_double_link_list_remove(&span->heap->large_huge_span, span);\n#endif\n\n\t//Oversized allocation, page count is stored in span_count\n\tsize_t num_pages = span->span_count;\n\t_rpmalloc_unmap(span, num_pages * _memory_page_size, span->align_offset, num_pages * _memory_page_size);\n\t_rpmalloc_stat_sub(&_huge_pages_current, num_pages);\n}\n\n//! Deallocate the given block\nstatic void\n_rpmalloc_deallocate(void* p) {\n\t_rpmalloc_stat_add64(&_deallocation_counter, 1);\n\t//Grab the span (always at start of span, using span alignment)\n\tspan_t* span = (span_t*)((uintptr_t)p & _memory_span_mask);\n\tif (UNEXPECTED(!span))\n\t\treturn;\n\tif (EXPECTED(span->size_class < SIZE_CLASS_COUNT))\n\t\t_rpmalloc_deallocate_small_or_medium(span, p);\n\telse if (span->size_class == SIZE_CLASS_LARGE)\n\t\t_rpmalloc_deallocate_large(span);\n\telse\n\t\t_rpmalloc_deallocate_huge(span);\n}\n\n////////////\n///\n/// Reallocation entry points\n///\n//////\n\nstatic size_t\n_rpmalloc_usable_size(void* p);\n\n//! Reallocate the given block to the given size\nstatic void*\n_rpmalloc_reallocate(heap_t* heap, void* p, size_t size, size_t oldsize, unsigned int flags) {\n\tif (p) {\n\t\t//Grab the span using guaranteed span alignment\n\t\tspan_t* span = (span_t*)((uintptr_t)p & _memory_span_mask);\n\t\tif (EXPECTED(span->size_class < SIZE_CLASS_COUNT)) {\n\t\t\t//Small/medium sized block\n\t\t\trpmalloc_assert(span->span_count == 1, \"Span counter corrupted\");\n\t\t\tvoid* blocks_start = pointer_offset(span, SPAN_HEADER_SIZE);\n\t\t\tuint32_t block_offset = (uint32_t)pointer_diff(p, blocks_start);\n\t\t\tuint32_t block_idx = block_offset / span->block_size;\n\t\t\tvoid* block = pointer_offset(blocks_start, (size_t)block_idx * span->block_size);\n\t\t\tif (!oldsize)\n\t\t\t\toldsize = (size_t)((ptrdiff_t)span->block_size - pointer_diff(p, block));\n\t\t\tif ((size_t)span->block_size >= size) {\n\t\t\t\t//Still fits in block, never mind trying to save memory, but preserve data if alignment changed\n\t\t\t\tif ((p != block) && !(flags & RPMALLOC_NO_PRESERVE))\n\t\t\t\t\tmemmove(block, p, oldsize);\n\t\t\t\treturn block;\n\t\t\t}\n\t\t} else if (span->size_class == SIZE_CLASS_LARGE) {\n\t\t\t//Large block\n\t\t\tsize_t total_size = size + SPAN_HEADER_SIZE;\n\t\t\tsize_t num_spans = total_size >> _memory_span_size_shift;\n\t\t\tif (total_size & (_memory_span_mask - 1))\n\t\t\t\t++num_spans;\n\t\t\tsize_t current_spans = span->span_count;\n\t\t\tvoid* block = pointer_offset(span, SPAN_HEADER_SIZE);\n\t\t\tif (!oldsize)\n\t\t\t\toldsize = (current_spans * _memory_span_size) - (size_t)pointer_diff(p, block) - SPAN_HEADER_SIZE;\n\t\t\tif ((current_spans >= num_spans) && (total_size >= (oldsize / 2))) {\n\t\t\t\t//Still fits in block, never mind trying to save memory, but preserve data if alignment changed\n\t\t\t\tif ((p != block) && !(flags & RPMALLOC_NO_PRESERVE))\n\t\t\t\t\tmemmove(block, p, oldsize);\n\t\t\t\treturn block;\n\t\t\t}\n\t\t} else {\n\t\t\t//Oversized block\n\t\t\tsize_t total_size = size + SPAN_HEADER_SIZE;\n\t\t\tsize_t num_pages = total_size >> _memory_page_size_shift;\n\t\t\tif (total_size & (_memory_page_size - 1))\n\t\t\t\t++num_pages;\n\t\t\t//Page count is stored in span_count\n\t\t\tsize_t current_pages = span->span_count;\n\t\t\tvoid* block = pointer_offset(span, SPAN_HEADER_SIZE);\n\t\t\tif (!oldsize)\n\t\t\t\toldsize = (current_pages * _memory_page_size) - (size_t)pointer_diff(p, block) - SPAN_HEADER_SIZE;\n\t\t\tif ((current_pages >= num_pages) && (num_pages >= (current_pages / 2))) {\n\t\t\t\t//Still fits in block, never mind trying to save memory, but preserve data if alignment changed\n\t\t\t\tif ((p != block) && !(flags & RPMALLOC_NO_PRESERVE))\n\t\t\t\t\tmemmove(block, p, oldsize);\n\t\t\t\treturn block;\n\t\t\t}\n\t\t}\n\t} else {\n\t\toldsize = 0;\n\t}\n\n\tif (!!(flags & RPMALLOC_GROW_OR_FAIL))\n\t\treturn 0;\n\n\t//Size is greater than block size, need to allocate a new block and deallocate the old\n\t//Avoid hysteresis by overallocating if increase is small (below 37%)\n\tsize_t lower_bound = oldsize + (oldsize >> 2) + (oldsize >> 3);\n\tsize_t new_size = (size > lower_bound) ? size : ((size > oldsize) ? lower_bound : size);\n\tvoid* block = _rpmalloc_allocate(heap, new_size);\n\tif (p && block) {\n\t\tif (!(flags & RPMALLOC_NO_PRESERVE))\n\t\t\tmemcpy(block, p, oldsize < new_size ? oldsize : new_size);\n\t\t_rpmalloc_deallocate(p);\n\t}\n\n\treturn block;\n}\n\nstatic void*\n_rpmalloc_aligned_reallocate(heap_t* heap, void* ptr, size_t alignment, size_t size, size_t oldsize,\n                           unsigned int flags) {\n\tif (alignment <= SMALL_GRANULARITY)\n\t\treturn _rpmalloc_reallocate(heap, ptr, size, oldsize, flags);\n\n\tint no_alloc = !!(flags & RPMALLOC_GROW_OR_FAIL);\n\tsize_t usablesize = (ptr ? _rpmalloc_usable_size(ptr) : 0);\n\tif ((usablesize >= size) && !((uintptr_t)ptr & (alignment - 1))) {\n\t\tif (no_alloc || (size >= (usablesize / 2)))\n\t\t\treturn ptr;\n\t}\n\t// Aligned alloc marks span as having aligned blocks\n\tvoid* block = (!no_alloc ? _rpmalloc_aligned_allocate(heap, alignment, size) : 0);\n\tif (EXPECTED(block != 0)) {\n\t\tif (!(flags & RPMALLOC_NO_PRESERVE) && ptr) {\n\t\t\tif (!oldsize)\n\t\t\t\toldsize = usablesize;\n\t\t\tmemcpy(block, ptr, oldsize < size ? oldsize : size);\n\t\t}\n\t\t_rpmalloc_deallocate(ptr);\n\t}\n\treturn block;\n}\n\n\n////////////\n///\n/// Initialization, finalization and utility\n///\n//////\n\n//! Get the usable size of the given block\nstatic size_t\n_rpmalloc_usable_size(void* p) {\n\t//Grab the span using guaranteed span alignment\n\tspan_t* span = (span_t*)((uintptr_t)p & _memory_span_mask);\n\tif (span->size_class < SIZE_CLASS_COUNT) {\n\t\t//Small/medium block\n\t\tvoid* blocks_start = pointer_offset(span, SPAN_HEADER_SIZE);\n\t\treturn span->block_size - ((size_t)pointer_diff(p, blocks_start) % span->block_size);\n\t}\n\tif (span->size_class == SIZE_CLASS_LARGE) {\n\t\t//Large block\n\t\tsize_t current_spans = span->span_count;\n\t\treturn (current_spans * _memory_span_size) - (size_t)pointer_diff(p, span);\n\t}\n\t//Oversized block, page count is stored in span_count\n\tsize_t current_pages = span->span_count;\n\treturn (current_pages * _memory_page_size) - (size_t)pointer_diff(p, span);\n}\n\n//! Adjust and optimize the size class properties for the given class\nstatic void\n_rpmalloc_adjust_size_class(size_t iclass) {\n\tsize_t block_size = _memory_size_class[iclass].block_size;\n\tsize_t block_count = (_memory_span_size - SPAN_HEADER_SIZE) / block_size;\n\n\t_memory_size_class[iclass].block_count = (uint16_t)block_count;\n\t_memory_size_class[iclass].class_idx = (uint16_t)iclass;\n\n\t//Check if previous size classes can be merged\n\tif (iclass >= SMALL_CLASS_COUNT) {\n\t\tsize_t prevclass = iclass;\n\t\twhile (prevclass > 0) {\n\t\t\t--prevclass;\n\t\t\t//A class can be merged if number of pages and number of blocks are equal\n\t\t\tif (_memory_size_class[prevclass].block_count == _memory_size_class[iclass].block_count)\n\t\t\t\tmemcpy(_memory_size_class + prevclass, _memory_size_class + iclass, sizeof(_memory_size_class[iclass]));\n\t\t\telse\n\t\t\t\tbreak;\n\t\t}\n\t}\n}\n\n//! Initialize the allocator and setup global data\nTRACY_API int\nrpmalloc_initialize(void) {\n\tif (_rpmalloc_initialized) {\n\t\trpmalloc_thread_initialize();\n\t\treturn 0;\n\t}\n\treturn rpmalloc_initialize_config(0);\n}\n\nint\nrpmalloc_initialize_config(const rpmalloc_config_t* config) {\n\tif (_rpmalloc_initialized) {\n\t\trpmalloc_thread_initialize();\n\t\treturn 0;\n\t}\n\t_rpmalloc_initialized = 1;\n\n\tif (config)\n\t\tmemcpy(&_memory_config, config, sizeof(rpmalloc_config_t));\n\telse\n\t\tmemset(&_memory_config, 0, sizeof(rpmalloc_config_t));\n\n\tif (!_memory_config.memory_map || !_memory_config.memory_unmap) {\n\t\t_memory_config.memory_map = _rpmalloc_mmap_os;\n\t\t_memory_config.memory_unmap = _rpmalloc_unmap_os;\n\t}\n\n#if PLATFORM_WINDOWS\n\tSYSTEM_INFO system_info;\n\tmemset(&system_info, 0, sizeof(system_info));\n\tGetSystemInfo(&system_info);\n\t_memory_map_granularity = system_info.dwAllocationGranularity;\n#else\n\t_memory_map_granularity = (size_t)sysconf(_SC_PAGESIZE);\n#endif\n\n#if RPMALLOC_CONFIGURABLE\n\t_memory_page_size = _memory_config.page_size;\n#else\n\t_memory_page_size = 0;\n#endif\n\t_memory_huge_pages = 0;\n\tif (!_memory_page_size) {\n#if PLATFORM_WINDOWS\n\t\t_memory_page_size = system_info.dwPageSize;\n#else\n\t\t_memory_page_size = _memory_map_granularity;\n\t\tif (_memory_config.enable_huge_pages) {\n#if defined(__linux__)\n\t\t\tsize_t huge_page_size = 0;\n\t\t\tFILE* meminfo = fopen(\"/proc/meminfo\", \"r\");\n\t\t\tif (meminfo) {\n\t\t\t\tchar line[128];\n\t\t\t\twhile (!huge_page_size && fgets(line, sizeof(line) - 1, meminfo)) {\n\t\t\t\t\tline[sizeof(line) - 1] = 0;\n\t\t\t\t\tif (strstr(line, \"Hugepagesize:\"))\n\t\t\t\t\t\thuge_page_size = (size_t)strtol(line + 13, 0, 10) * 1024;\n\t\t\t\t}\n\t\t\t\tfclose(meminfo);\n\t\t\t}\n\t\t\tif (huge_page_size) {\n\t\t\t\t_memory_huge_pages = 1;\n\t\t\t\t_memory_page_size = huge_page_size;\n\t\t\t\t_memory_map_granularity = huge_page_size;\n\t\t\t}\n#elif defined(__FreeBSD__)\n\t\t\tint rc;\n\t\t\tsize_t sz = sizeof(rc);\n\n\t\t\tif (sysctlbyname(\"vm.pmap.pg_ps_enabled\", &rc, &sz, NULL, 0) == 0 && rc == 1) {\n\t\t\t\t_memory_huge_pages = 1;\n\t\t\t\t_memory_page_size = 2 * 1024 * 1024;\n\t\t\t\t_memory_map_granularity = _memory_page_size;\n\t\t\t}\n#elif defined(__APPLE__) || defined(__NetBSD__)\n\t\t\t_memory_huge_pages = 1;\n\t\t\t_memory_page_size = 2 * 1024 * 1024;\n\t\t\t_memory_map_granularity = _memory_page_size;\n#endif\n\t\t}\n#endif\n\t} else {\n\t\tif (_memory_config.enable_huge_pages)\n\t\t\t_memory_huge_pages = 1;\n\t}\n\n#if PLATFORM_WINDOWS && !defined TRACY_GDK\n\tif (_memory_config.enable_huge_pages) {\n\t\tHANDLE token = 0;\n\t\tsize_t large_page_minimum = GetLargePageMinimum();\n\t\tif (large_page_minimum)\n\t\t\tOpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token);\n\t\tif (token) {\n\t\t\tLUID luid;\n\t\t\tif (LookupPrivilegeValue(0, SE_LOCK_MEMORY_NAME, &luid)) {\n\t\t\t\tTOKEN_PRIVILEGES token_privileges;\n\t\t\t\tmemset(&token_privileges, 0, sizeof(token_privileges));\n\t\t\t\ttoken_privileges.PrivilegeCount = 1;\n\t\t\t\ttoken_privileges.Privileges[0].Luid = luid;\n\t\t\t\ttoken_privileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;\n\t\t\t\tif (AdjustTokenPrivileges(token, FALSE, &token_privileges, 0, 0, 0)) {\n\t\t\t\t\tif (GetLastError() == ERROR_SUCCESS)\n\t\t\t\t\t\t_memory_huge_pages = 1;\n\t\t\t\t}\n\t\t\t}\n\t\t\tCloseHandle(token);\n\t\t}\n\t\tif (_memory_huge_pages) {\n\t\t\tif (large_page_minimum > _memory_page_size)\n\t\t\t\t_memory_page_size = large_page_minimum;\n\t\t\tif (large_page_minimum > _memory_map_granularity)\n\t\t\t\t_memory_map_granularity = large_page_minimum;\n\t\t}\n\t}\n#endif\n\n\tsize_t min_span_size = 256;\n\tsize_t max_page_size;\n#if UINTPTR_MAX > 0xFFFFFFFF\n\tmax_page_size = 4096ULL * 1024ULL * 1024ULL;\n#else\n\tmax_page_size = 4 * 1024 * 1024;\n#endif\n\tif (_memory_page_size < min_span_size)\n\t\t_memory_page_size = min_span_size;\n\tif (_memory_page_size > max_page_size)\n\t\t_memory_page_size = max_page_size;\n\t_memory_page_size_shift = 0;\n\tsize_t page_size_bit = _memory_page_size;\n\twhile (page_size_bit != 1) {\n\t\t++_memory_page_size_shift;\n\t\tpage_size_bit >>= 1;\n\t}\n\t_memory_page_size = ((size_t)1 << _memory_page_size_shift);\n\n#if RPMALLOC_CONFIGURABLE\n\tif (!_memory_config.span_size) {\n\t\t_memory_span_size = _memory_default_span_size;\n\t\t_memory_span_size_shift = _memory_default_span_size_shift;\n\t\t_memory_span_mask = _memory_default_span_mask;\n\t} else {\n\t\tsize_t span_size = _memory_config.span_size;\n\t\tif (span_size > (256 * 1024))\n\t\t\tspan_size = (256 * 1024);\n\t\t_memory_span_size = 4096;\n\t\t_memory_span_size_shift = 12;\n\t\twhile (_memory_span_size < span_size) {\n\t\t\t_memory_span_size <<= 1;\n\t\t\t++_memory_span_size_shift;\n\t\t}\n\t\t_memory_span_mask = ~(uintptr_t)(_memory_span_size - 1);\n\t}\n#endif\n\n\t_memory_span_map_count = ( _memory_config.span_map_count ? _memory_config.span_map_count : DEFAULT_SPAN_MAP_COUNT);\n\tif ((_memory_span_size * _memory_span_map_count) < _memory_page_size)\n\t\t_memory_span_map_count = (_memory_page_size / _memory_span_size);\n\tif ((_memory_page_size >= _memory_span_size) && ((_memory_span_map_count * _memory_span_size) % _memory_page_size))\n\t\t_memory_span_map_count = (_memory_page_size / _memory_span_size);\n\t_memory_heap_reserve_count = (_memory_span_map_count > DEFAULT_SPAN_MAP_COUNT) ? DEFAULT_SPAN_MAP_COUNT : _memory_span_map_count;\n\n\t_memory_config.page_size = _memory_page_size;\n\t_memory_config.span_size = _memory_span_size;\n\t_memory_config.span_map_count = _memory_span_map_count;\n\t_memory_config.enable_huge_pages = _memory_huge_pages;\n\n#if ((defined(__APPLE__) || defined(__HAIKU__)) && ENABLE_PRELOAD) || defined(__TINYC__)\n\tif (pthread_key_create(&_memory_thread_heap, _rpmalloc_heap_release_raw_fc))\n\t\treturn -1;\n#endif\n#if defined(_WIN32) && (!defined(BUILD_DYNAMIC_LINK) || !BUILD_DYNAMIC_LINK)\n\tfls_key = FlsAlloc(&_rpmalloc_thread_destructor);\n#endif\n\n\t//Setup all small and medium size classes\n\tsize_t iclass = 0;\n\t_memory_size_class[iclass].block_size = SMALL_GRANULARITY;\n\t_rpmalloc_adjust_size_class(iclass);\n\tfor (iclass = 1; iclass < SMALL_CLASS_COUNT; ++iclass) {\n\t\tsize_t size = iclass * SMALL_GRANULARITY;\n\t\t_memory_size_class[iclass].block_size = (uint32_t)size;\n\t\t_rpmalloc_adjust_size_class(iclass);\n\t}\n\t//At least two blocks per span, then fall back to large allocations\n\t_memory_medium_size_limit = (_memory_span_size - SPAN_HEADER_SIZE) >> 1;\n\tif (_memory_medium_size_limit > MEDIUM_SIZE_LIMIT)\n\t\t_memory_medium_size_limit = MEDIUM_SIZE_LIMIT;\n\tfor (iclass = 0; iclass < MEDIUM_CLASS_COUNT; ++iclass) {\n\t\tsize_t size = SMALL_SIZE_LIMIT + ((iclass + 1) * MEDIUM_GRANULARITY);\n\t\tif (size > _memory_medium_size_limit)\n\t\t\tbreak;\n\t\t_memory_size_class[SMALL_CLASS_COUNT + iclass].block_size = (uint32_t)size;\n\t\t_rpmalloc_adjust_size_class(SMALL_CLASS_COUNT + iclass);\n\t}\n\n\t_memory_orphan_heaps = 0;\n#if RPMALLOC_FIRST_CLASS_HEAPS\n\t_memory_first_class_orphan_heaps = 0;\n#endif\n#if ENABLE_STATISTICS\n\tatomic_store32(&_memory_active_heaps, 0);\n\tatomic_store32(&_mapped_pages, 0);\n\t_mapped_pages_peak = 0;\n\tatomic_store32(&_master_spans, 0);\n\tatomic_store32(&_mapped_total, 0);\n\tatomic_store32(&_unmapped_total, 0);\n\tatomic_store32(&_mapped_pages_os, 0);\n\tatomic_store32(&_huge_pages_current, 0);\n\t_huge_pages_peak = 0;\n#endif\n\tmemset(_memory_heaps, 0, sizeof(_memory_heaps));\n\tatomic_store32_release(&_memory_global_lock, 0);\n\n\t//Initialize this thread\n\trpmalloc_thread_initialize();\n\treturn 0;\n}\n\n//! Finalize the allocator\nTRACY_API void\nrpmalloc_finalize(void) {\n\trpmalloc_thread_finalize(1);\n\t//rpmalloc_dump_statistics(stdout);\n\n\tif (_memory_global_reserve) {\n\t\tatomic_add32(&_memory_global_reserve_master->remaining_spans, -(int32_t)_memory_global_reserve_count);\n\t\t_memory_global_reserve_master = 0;\n\t\t_memory_global_reserve_count = 0;\n\t\t_memory_global_reserve = 0;\n\t}\n\tatomic_store32_release(&_memory_global_lock, 0);\t\n\n\t//Free all thread caches and fully free spans\n\tfor (size_t list_idx = 0; list_idx < HEAP_ARRAY_SIZE; ++list_idx) {\n\t\theap_t* heap = _memory_heaps[list_idx];\n\t\twhile (heap) {\n\t\t\theap_t* next_heap = heap->next_heap;\n\t\t\theap->finalize = 1;\n\t\t\t_rpmalloc_heap_global_finalize(heap);\n\t\t\theap = next_heap;\n\t\t}\n\t}\n\n#if ENABLE_GLOBAL_CACHE\n\t//Free global caches\n\tfor (size_t iclass = 0; iclass < LARGE_CLASS_COUNT; ++iclass)\n\t\t_rpmalloc_global_cache_finalize(&_memory_span_cache[iclass]);\n#endif\n\n#if (defined(__APPLE__) || defined(__HAIKU__)) && ENABLE_PRELOAD\n\tpthread_key_delete(_memory_thread_heap);\n#endif\n#if defined(_WIN32) && (!defined(BUILD_DYNAMIC_LINK) || !BUILD_DYNAMIC_LINK)\n\tFlsFree(fls_key);\n\tfls_key = 0;\n#endif\n#if ENABLE_STATISTICS\n\t//If you hit these asserts you probably have memory leaks (perhaps global scope data doing dynamic allocations) or double frees in your code\n\trpmalloc_assert(atomic_load32(&_mapped_pages) == 0, \"Memory leak detected\");\n\trpmalloc_assert(atomic_load32(&_mapped_pages_os) == 0, \"Memory leak detected\");\n#endif\n\n\t_rpmalloc_initialized = 0;\n}\n\n//! Initialize thread, assign heap\nTRACY_API void\nrpmalloc_thread_initialize(void) {\n\tif (!get_thread_heap_raw()) {\n\t\theap_t* heap = _rpmalloc_heap_allocate(0);\n\t\tif (heap) {\n\t\t\t_rpmalloc_stat_inc(&_memory_active_heaps);\n\t\t\tset_thread_heap(heap);\n#if defined(_WIN32) && (!defined(BUILD_DYNAMIC_LINK) || !BUILD_DYNAMIC_LINK)\n\t\t\tFlsSetValue(fls_key, heap);\n#endif\n\t\t}\n\t}\n}\n\n//! Finalize thread, orphan heap\nTRACY_API void\nrpmalloc_thread_finalize(int release_caches) {\n\theap_t* heap = get_thread_heap_raw();\n\tif (heap)\n\t\t_rpmalloc_heap_release_raw(heap, release_caches);\n\tset_thread_heap(0);\n#if defined(_WIN32) && (!defined(BUILD_DYNAMIC_LINK) || !BUILD_DYNAMIC_LINK)\n\tFlsSetValue(fls_key, 0);\n#endif\n}\n\nint\nrpmalloc_is_thread_initialized(void) {\n\treturn (get_thread_heap_raw() != 0) ? 1 : 0;\n}\n\nconst rpmalloc_config_t*\nrpmalloc_config(void) {\n\treturn &_memory_config;\n}\n\n// Extern interface\n\nTRACY_API RPMALLOC_ALLOCATOR void*\nrpmalloc(size_t size) {\n#if ENABLE_VALIDATE_ARGS\n\tif (size >= MAX_ALLOC_SIZE) {\n\t\terrno = EINVAL;\n\t\treturn 0;\n\t}\n#endif\n\theap_t* heap = get_thread_heap();\n\treturn _rpmalloc_allocate(heap, size);\n}\n\nTRACY_API void\nrpfree(void* ptr) {\n\t_rpmalloc_deallocate(ptr);\n}\n\nextern inline RPMALLOC_ALLOCATOR void*\nrpcalloc(size_t num, size_t size) {\n\tsize_t total;\n#if ENABLE_VALIDATE_ARGS\n#if PLATFORM_WINDOWS\n\tint err = SizeTMult(num, size, &total);\n\tif ((err != S_OK) || (total >= MAX_ALLOC_SIZE)) {\n\t\terrno = EINVAL;\n\t\treturn 0;\n\t}\n#else\n\tint err = __builtin_umull_overflow(num, size, &total);\n\tif (err || (total >= MAX_ALLOC_SIZE)) {\n\t\terrno = EINVAL;\n\t\treturn 0;\n\t}\n#endif\n#else\n\ttotal = num * size;\n#endif\n\theap_t* heap = get_thread_heap();\n\tvoid* block = _rpmalloc_allocate(heap, total);\n\tif (block)\n\t\tmemset(block, 0, total);\n\treturn block;\n}\n\nTRACY_API RPMALLOC_ALLOCATOR void*\nrprealloc(void* ptr, size_t size) {\n#if ENABLE_VALIDATE_ARGS\n\tif (size >= MAX_ALLOC_SIZE) {\n\t\terrno = EINVAL;\n\t\treturn ptr;\n\t}\n#endif\n\theap_t* heap = get_thread_heap();\n\treturn _rpmalloc_reallocate(heap, ptr, size, 0, 0);\n}\n\nextern RPMALLOC_ALLOCATOR void*\nrpaligned_realloc(void* ptr, size_t alignment, size_t size, size_t oldsize,\n                  unsigned int flags) {\n#if ENABLE_VALIDATE_ARGS\n\tif ((size + alignment < size) || (alignment > _memory_page_size)) {\n\t\terrno = EINVAL;\n\t\treturn 0;\n\t}\n#endif\n\theap_t* heap = get_thread_heap();\n\treturn _rpmalloc_aligned_reallocate(heap, ptr, alignment, size, oldsize, flags);\n}\n\nextern RPMALLOC_ALLOCATOR void*\nrpaligned_alloc(size_t alignment, size_t size) {\n\theap_t* heap = get_thread_heap();\n\treturn _rpmalloc_aligned_allocate(heap, alignment, size);\n}\n\nextern inline RPMALLOC_ALLOCATOR void*\nrpaligned_calloc(size_t alignment, size_t num, size_t size) {\n\tsize_t total;\n#if ENABLE_VALIDATE_ARGS\n#if PLATFORM_WINDOWS\n\tint err = SizeTMult(num, size, &total);\n\tif ((err != S_OK) || (total >= MAX_ALLOC_SIZE)) {\n\t\terrno = EINVAL;\n\t\treturn 0;\n\t}\n#else\n\tint err = __builtin_umull_overflow(num, size, &total);\n\tif (err || (total >= MAX_ALLOC_SIZE)) {\n\t\terrno = EINVAL;\n\t\treturn 0;\n\t}\n#endif\n#else\n\ttotal = num * size;\n#endif\n\tvoid* block = rpaligned_alloc(alignment, total);\n\tif (block)\n\t\tmemset(block, 0, total);\n\treturn block;\n}\n\nextern inline RPMALLOC_ALLOCATOR void*\nrpmemalign(size_t alignment, size_t size) {\n\treturn rpaligned_alloc(alignment, size);\n}\n\nextern inline int\nrpposix_memalign(void **memptr, size_t alignment, size_t size) {\n\tif (memptr)\n\t\t*memptr = rpaligned_alloc(alignment, size);\n\telse\n\t\treturn EINVAL;\n\treturn *memptr ? 0 : ENOMEM;\n}\n\nextern inline size_t\nrpmalloc_usable_size(void* ptr) {\n\treturn (ptr ? _rpmalloc_usable_size(ptr) : 0);\n}\n\nextern inline void\nrpmalloc_thread_collect(void) {\n}\n\nvoid\nrpmalloc_thread_statistics(rpmalloc_thread_statistics_t* stats) {\n\tmemset(stats, 0, sizeof(rpmalloc_thread_statistics_t));\n\theap_t* heap = get_thread_heap_raw();\n\tif (!heap)\n\t\treturn;\n\n\tfor (size_t iclass = 0; iclass < SIZE_CLASS_COUNT; ++iclass) {\n\t\tsize_class_t* size_class = _memory_size_class + iclass;\n\t\tspan_t* span = heap->size_class[iclass].partial_span;\n\t\twhile (span) {\n\t\t\tsize_t free_count = span->list_size;\n\t\t\tsize_t block_count = size_class->block_count;\n\t\t\tif (span->free_list_limit < block_count)\n\t\t\t\tblock_count = span->free_list_limit;\n\t\t\tfree_count += (block_count - span->used_count);\n\t\t\tstats->sizecache = free_count * size_class->block_size;\n\t\t\tspan = span->next;\n\t\t}\n\t}\n\n#if ENABLE_THREAD_CACHE\n\tfor (size_t iclass = 0; iclass < LARGE_CLASS_COUNT; ++iclass) {\n\t\tspan_cache_t* span_cache;\n\t\tif (!iclass)\n\t\t\tspan_cache = &heap->span_cache;\n\t\telse\n\t\t\tspan_cache = (span_cache_t*)(heap->span_large_cache + (iclass - 1));\n\t\tstats->spancache = span_cache->count * (iclass + 1) * _memory_span_size;\n\t}\n#endif\n\n\tspan_t* deferred = (span_t*)atomic_load_ptr(&heap->span_free_deferred);\n\twhile (deferred) {\n\t\tif (deferred->size_class != SIZE_CLASS_HUGE)\n\t\t\tstats->spancache = (size_t)deferred->span_count * _memory_span_size;\n\t\tdeferred = (span_t*)deferred->free_list;\n\t}\n\n#if ENABLE_STATISTICS\n\tstats->thread_to_global = (size_t)atomic_load64(&heap->thread_to_global);\n\tstats->global_to_thread = (size_t)atomic_load64(&heap->global_to_thread);\n\n\tfor (size_t iclass = 0; iclass < LARGE_CLASS_COUNT; ++iclass) {\n\t\tstats->span_use[iclass].current = (size_t)atomic_load32(&heap->span_use[iclass].current);\n\t\tstats->span_use[iclass].peak = (size_t)atomic_load32(&heap->span_use[iclass].high);\n\t\tstats->span_use[iclass].to_global = (size_t)atomic_load32(&heap->span_use[iclass].spans_to_global);\n\t\tstats->span_use[iclass].from_global = (size_t)atomic_load32(&heap->span_use[iclass].spans_from_global);\n\t\tstats->span_use[iclass].to_cache = (size_t)atomic_load32(&heap->span_use[iclass].spans_to_cache);\n\t\tstats->span_use[iclass].from_cache = (size_t)atomic_load32(&heap->span_use[iclass].spans_from_cache);\n\t\tstats->span_use[iclass].to_reserved = (size_t)atomic_load32(&heap->span_use[iclass].spans_to_reserved);\n\t\tstats->span_use[iclass].from_reserved = (size_t)atomic_load32(&heap->span_use[iclass].spans_from_reserved);\n\t\tstats->span_use[iclass].map_calls = (size_t)atomic_load32(&heap->span_use[iclass].spans_map_calls);\n\t}\n\tfor (size_t iclass = 0; iclass < SIZE_CLASS_COUNT; ++iclass) {\n\t\tstats->size_use[iclass].alloc_current = (size_t)atomic_load32(&heap->size_class_use[iclass].alloc_current);\n\t\tstats->size_use[iclass].alloc_peak = (size_t)heap->size_class_use[iclass].alloc_peak;\n\t\tstats->size_use[iclass].alloc_total = (size_t)atomic_load32(&heap->size_class_use[iclass].alloc_total);\n\t\tstats->size_use[iclass].free_total = (size_t)atomic_load32(&heap->size_class_use[iclass].free_total);\n\t\tstats->size_use[iclass].spans_to_cache = (size_t)atomic_load32(&heap->size_class_use[iclass].spans_to_cache);\n\t\tstats->size_use[iclass].spans_from_cache = (size_t)atomic_load32(&heap->size_class_use[iclass].spans_from_cache);\n\t\tstats->size_use[iclass].spans_from_reserved = (size_t)atomic_load32(&heap->size_class_use[iclass].spans_from_reserved);\n\t\tstats->size_use[iclass].map_calls = (size_t)atomic_load32(&heap->size_class_use[iclass].spans_map_calls);\n\t}\n#endif\n}\n\nvoid\nrpmalloc_global_statistics(rpmalloc_global_statistics_t* stats) {\n\tmemset(stats, 0, sizeof(rpmalloc_global_statistics_t));\n#if ENABLE_STATISTICS\n\tstats->mapped = (size_t)atomic_load32(&_mapped_pages) * _memory_page_size;\n\tstats->mapped_peak = (size_t)_mapped_pages_peak * _memory_page_size;\n\tstats->mapped_total = (size_t)atomic_load32(&_mapped_total) * _memory_page_size;\n\tstats->unmapped_total = (size_t)atomic_load32(&_unmapped_total) * _memory_page_size;\n\tstats->huge_alloc = (size_t)atomic_load32(&_huge_pages_current) * _memory_page_size;\n\tstats->huge_alloc_peak = (size_t)_huge_pages_peak * _memory_page_size;\n#endif\n#if ENABLE_GLOBAL_CACHE\n\tfor (size_t iclass = 0; iclass < LARGE_CLASS_COUNT; ++iclass)\n\t\tstats->cached += _memory_span_cache[iclass].count * (iclass + 1) * _memory_span_size;\n#endif\n}\n\n#if ENABLE_STATISTICS\n\nstatic void\n_memory_heap_dump_statistics(heap_t* heap, void* file) {\n\tfprintf(file, \"Heap %d stats:\\n\", heap->id);\n\tfprintf(file, \"Class   CurAlloc  PeakAlloc   TotAlloc    TotFree  BlkSize BlkCount SpansCur SpansPeak  PeakAllocMiB  ToCacheMiB FromCacheMiB FromReserveMiB MmapCalls\\n\");\n\tfor (size_t iclass = 0; iclass < SIZE_CLASS_COUNT; ++iclass) {\n\t\tif (!atomic_load32(&heap->size_class_use[iclass].alloc_total))\n\t\t\tcontinue;\n\t\tfprintf(file, \"%3u:  %10u %10u %10u %10u %8u %8u %8d %9d %13zu %11zu %12zu %14zu %9u\\n\", (uint32_t)iclass,\n\t\t\tatomic_load32(&heap->size_class_use[iclass].alloc_current),\n\t\t\theap->size_class_use[iclass].alloc_peak,\n\t\t\tatomic_load32(&heap->size_class_use[iclass].alloc_total),\n\t\t\tatomic_load32(&heap->size_class_use[iclass].free_total),\n\t\t\t_memory_size_class[iclass].block_size,\n\t\t\t_memory_size_class[iclass].block_count,\n\t\t\tatomic_load32(&heap->size_class_use[iclass].spans_current),\n\t\t\theap->size_class_use[iclass].spans_peak,\n\t\t\t((size_t)heap->size_class_use[iclass].alloc_peak * (size_t)_memory_size_class[iclass].block_size) / (size_t)(1024 * 1024),\n\t\t\t((size_t)atomic_load32(&heap->size_class_use[iclass].spans_to_cache) * _memory_span_size) / (size_t)(1024 * 1024),\n\t\t\t((size_t)atomic_load32(&heap->size_class_use[iclass].spans_from_cache) * _memory_span_size) / (size_t)(1024 * 1024),\n\t\t\t((size_t)atomic_load32(&heap->size_class_use[iclass].spans_from_reserved) * _memory_span_size) / (size_t)(1024 * 1024),\n\t\t\tatomic_load32(&heap->size_class_use[iclass].spans_map_calls));\n\t}\n\tfprintf(file, \"Spans  Current     Peak Deferred  PeakMiB  Cached  ToCacheMiB FromCacheMiB ToReserveMiB FromReserveMiB ToGlobalMiB FromGlobalMiB  MmapCalls\\n\");\n\tfor (size_t iclass = 0; iclass < LARGE_CLASS_COUNT; ++iclass) {\n\t\tif (!atomic_load32(&heap->span_use[iclass].high) && !atomic_load32(&heap->span_use[iclass].spans_map_calls))\n\t\t\tcontinue;\n\t\tfprintf(file, \"%4u: %8d %8u %8u %8zu %7u %11zu %12zu %12zu %14zu %11zu %13zu %10u\\n\", (uint32_t)(iclass + 1),\n\t\t\tatomic_load32(&heap->span_use[iclass].current),\n\t\t\tatomic_load32(&heap->span_use[iclass].high),\n\t\t\tatomic_load32(&heap->span_use[iclass].spans_deferred),\n\t\t\t((size_t)atomic_load32(&heap->span_use[iclass].high) * (size_t)_memory_span_size * (iclass + 1)) / (size_t)(1024 * 1024),\n#if ENABLE_THREAD_CACHE\n\t\t\t(unsigned int)(!iclass ? heap->span_cache.count : heap->span_large_cache[iclass - 1].count),\n\t\t\t((size_t)atomic_load32(&heap->span_use[iclass].spans_to_cache) * (iclass + 1) * _memory_span_size) / (size_t)(1024 * 1024),\n\t\t\t((size_t)atomic_load32(&heap->span_use[iclass].spans_from_cache) * (iclass + 1) * _memory_span_size) / (size_t)(1024 * 1024),\n#else\n\t\t\t0, (size_t)0, (size_t)0,\n#endif\n\t\t\t((size_t)atomic_load32(&heap->span_use[iclass].spans_to_reserved) * (iclass + 1) * _memory_span_size) / (size_t)(1024 * 1024),\n\t\t\t((size_t)atomic_load32(&heap->span_use[iclass].spans_from_reserved) * (iclass + 1) * _memory_span_size) / (size_t)(1024 * 1024),\n\t\t\t((size_t)atomic_load32(&heap->span_use[iclass].spans_to_global) * (size_t)_memory_span_size * (iclass + 1)) / (size_t)(1024 * 1024),\n\t\t\t((size_t)atomic_load32(&heap->span_use[iclass].spans_from_global) * (size_t)_memory_span_size * (iclass + 1)) / (size_t)(1024 * 1024),\n\t\t\tatomic_load32(&heap->span_use[iclass].spans_map_calls));\n\t}\n\tfprintf(file, \"Full spans: %zu\\n\", heap->full_span_count);\n\tfprintf(file, \"ThreadToGlobalMiB GlobalToThreadMiB\\n\");\n\tfprintf(file, \"%17zu %17zu\\n\", (size_t)atomic_load64(&heap->thread_to_global) / (size_t)(1024 * 1024), (size_t)atomic_load64(&heap->global_to_thread) / (size_t)(1024 * 1024));\n}\n\n#endif\n\nvoid\nrpmalloc_dump_statistics(void* file) {\n#if ENABLE_STATISTICS\n\tfor (size_t list_idx = 0; list_idx < HEAP_ARRAY_SIZE; ++list_idx) {\n\t\theap_t* heap = _memory_heaps[list_idx];\n\t\twhile (heap) {\n\t\t\tint need_dump = 0;\n\t\t\tfor (size_t iclass = 0; !need_dump && (iclass < SIZE_CLASS_COUNT); ++iclass) {\n\t\t\t\tif (!atomic_load32(&heap->size_class_use[iclass].alloc_total)) {\n\t\t\t\t\trpmalloc_assert(!atomic_load32(&heap->size_class_use[iclass].free_total), \"Heap statistics counter mismatch\");\n\t\t\t\t\trpmalloc_assert(!atomic_load32(&heap->size_class_use[iclass].spans_map_calls), \"Heap statistics counter mismatch\");\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tneed_dump = 1;\n\t\t\t}\n\t\t\tfor (size_t iclass = 0; !need_dump && (iclass < LARGE_CLASS_COUNT); ++iclass) {\n\t\t\t\tif (!atomic_load32(&heap->span_use[iclass].high) && !atomic_load32(&heap->span_use[iclass].spans_map_calls))\n\t\t\t\t\tcontinue;\n\t\t\t\tneed_dump = 1;\n\t\t\t}\n\t\t\tif (need_dump)\n\t\t\t\t_memory_heap_dump_statistics(heap, file);\n\t\t\theap = heap->next_heap;\n\t\t}\n\t}\n\tfprintf(file, \"Global stats:\\n\");\n\tsize_t huge_current = (size_t)atomic_load32(&_huge_pages_current) * _memory_page_size;\n\tsize_t huge_peak = (size_t)_huge_pages_peak * _memory_page_size;\n\tfprintf(file, \"HugeCurrentMiB HugePeakMiB\\n\");\n\tfprintf(file, \"%14zu %11zu\\n\", huge_current / (size_t)(1024 * 1024), huge_peak / (size_t)(1024 * 1024));\n\n\tfprintf(file, \"GlobalCacheMiB\\n\");\n\tfor (size_t iclass = 0; iclass < LARGE_CLASS_COUNT; ++iclass) {\n\t\tglobal_cache_t* cache = _memory_span_cache + iclass;\n\t\tsize_t global_cache = (size_t)cache->count * iclass * _memory_span_size;\n\n\t\tsize_t global_overflow_cache = 0;\n\t\tspan_t* span = cache->overflow;\n\t\twhile (span) {\n\t\t\tglobal_overflow_cache += iclass * _memory_span_size;\n\t\t\tspan = span->next;\n\t\t}\n\t\tif (global_cache || global_overflow_cache || cache->insert_count || cache->extract_count)\n\t\t\tfprintf(file, \"%4zu: %8zuMiB (%8zuMiB overflow) %14zu insert %14zu extract\\n\", iclass + 1, global_cache / (size_t)(1024 * 1024), global_overflow_cache / (size_t)(1024 * 1024), cache->insert_count, cache->extract_count);\n\t}\n\n\tsize_t mapped = (size_t)atomic_load32(&_mapped_pages) * _memory_page_size;\n\tsize_t mapped_os = (size_t)atomic_load32(&_mapped_pages_os) * _memory_page_size;\n\tsize_t mapped_peak = (size_t)_mapped_pages_peak * _memory_page_size;\n\tsize_t mapped_total = (size_t)atomic_load32(&_mapped_total) * _memory_page_size;\n\tsize_t unmapped_total = (size_t)atomic_load32(&_unmapped_total) * _memory_page_size;\n\tfprintf(file, \"MappedMiB MappedOSMiB MappedPeakMiB MappedTotalMiB UnmappedTotalMiB\\n\");\n\tfprintf(file, \"%9zu %11zu %13zu %14zu %16zu\\n\",\n\t\tmapped / (size_t)(1024 * 1024),\n\t\tmapped_os / (size_t)(1024 * 1024),\n\t\tmapped_peak / (size_t)(1024 * 1024),\n\t\tmapped_total / (size_t)(1024 * 1024),\n\t\tunmapped_total / (size_t)(1024 * 1024));\n\n\tfprintf(file, \"\\n\");\n#if 0\n\tint64_t allocated = atomic_load64(&_allocation_counter);\n\tint64_t deallocated = atomic_load64(&_deallocation_counter);\n\tfprintf(file, \"Allocation count: %lli\\n\", allocated);\n\tfprintf(file, \"Deallocation count: %lli\\n\", deallocated);\n\tfprintf(file, \"Current allocations: %lli\\n\", (allocated - deallocated));\n\tfprintf(file, \"Master spans: %d\\n\", atomic_load32(&_master_spans));\n\tfprintf(file, \"Dangling master spans: %d\\n\", atomic_load32(&_unmapped_master_spans));\n#endif\n#endif\n\t(void)sizeof(file);\n}\n\n#if RPMALLOC_FIRST_CLASS_HEAPS\n\nextern inline rpmalloc_heap_t*\nrpmalloc_heap_acquire(void) {\n\t// Must be a pristine heap from newly mapped memory pages, or else memory blocks\n\t// could already be allocated from the heap which would (wrongly) be released when\n\t// heap is cleared with rpmalloc_heap_free_all(). Also heaps guaranteed to be\n\t// pristine from the dedicated orphan list can be used.\n\theap_t* heap = _rpmalloc_heap_allocate(1);\n\theap->owner_thread = 0;\n\t_rpmalloc_stat_inc(&_memory_active_heaps);\n\treturn heap;\n}\n\nextern inline void\nrpmalloc_heap_release(rpmalloc_heap_t* heap) {\n\tif (heap)\n\t\t_rpmalloc_heap_release(heap, 1, 1);\n}\n\nextern inline RPMALLOC_ALLOCATOR void*\nrpmalloc_heap_alloc(rpmalloc_heap_t* heap, size_t size) {\n#if ENABLE_VALIDATE_ARGS\n\tif (size >= MAX_ALLOC_SIZE) {\n\t\terrno = EINVAL;\n\t\treturn 0;\n\t}\n#endif\n\treturn _rpmalloc_allocate(heap, size);\n}\n\nextern inline RPMALLOC_ALLOCATOR void*\nrpmalloc_heap_aligned_alloc(rpmalloc_heap_t* heap, size_t alignment, size_t size) {\n#if ENABLE_VALIDATE_ARGS\n\tif (size >= MAX_ALLOC_SIZE) {\n\t\terrno = EINVAL;\n\t\treturn 0;\n\t}\n#endif\n\treturn _rpmalloc_aligned_allocate(heap, alignment, size);\n}\n\nextern inline RPMALLOC_ALLOCATOR void*\nrpmalloc_heap_calloc(rpmalloc_heap_t* heap, size_t num, size_t size) {\n\treturn rpmalloc_heap_aligned_calloc(heap, 0, num, size);\n}\n\nextern inline RPMALLOC_ALLOCATOR void*\nrpmalloc_heap_aligned_calloc(rpmalloc_heap_t* heap, size_t alignment, size_t num, size_t size) {\n\tsize_t total;\n#if ENABLE_VALIDATE_ARGS\n#if PLATFORM_WINDOWS\n\tint err = SizeTMult(num, size, &total);\n\tif ((err != S_OK) || (total >= MAX_ALLOC_SIZE)) {\n\t\terrno = EINVAL;\n\t\treturn 0;\n\t}\n#else\n\tint err = __builtin_umull_overflow(num, size, &total);\n\tif (err || (total >= MAX_ALLOC_SIZE)) {\n\t\terrno = EINVAL;\n\t\treturn 0;\n\t}\n#endif\n#else\n\ttotal = num * size;\n#endif\n\tvoid* block = _rpmalloc_aligned_allocate(heap, alignment, total);\n\tif (block)\n\t\tmemset(block, 0, total);\n\treturn block;\n}\n\nextern inline RPMALLOC_ALLOCATOR void*\nrpmalloc_heap_realloc(rpmalloc_heap_t* heap, void* ptr, size_t size, unsigned int flags) {\n#if ENABLE_VALIDATE_ARGS\n\tif (size >= MAX_ALLOC_SIZE) {\n\t\terrno = EINVAL;\n\t\treturn ptr;\n\t}\n#endif\n\treturn _rpmalloc_reallocate(heap, ptr, size, 0, flags);\n}\n\nextern inline RPMALLOC_ALLOCATOR void*\nrpmalloc_heap_aligned_realloc(rpmalloc_heap_t* heap, void* ptr, size_t alignment, size_t size, unsigned int flags) {\n#if ENABLE_VALIDATE_ARGS\n\tif ((size + alignment < size) || (alignment > _memory_page_size)) {\n\t\terrno = EINVAL;\n\t\treturn 0;\n\t}\n#endif\n\treturn _rpmalloc_aligned_reallocate(heap, ptr, alignment, size, 0, flags);\t\n}\n\nextern inline void\nrpmalloc_heap_free(rpmalloc_heap_t* heap, void* ptr) {\n\t(void)sizeof(heap);\n\t_rpmalloc_deallocate(ptr);\n}\n\nextern inline void\nrpmalloc_heap_free_all(rpmalloc_heap_t* heap) {\n\tspan_t* span;\n\tspan_t* next_span;\n\n\t_rpmalloc_heap_cache_adopt_deferred(heap, 0);\n\n\tfor (size_t iclass = 0; iclass < SIZE_CLASS_COUNT; ++iclass) {\n\t\tspan = heap->size_class[iclass].partial_span;\n\t\twhile (span) {\n\t\t\tnext_span = span->next;\n\t\t\t_rpmalloc_heap_cache_insert(heap, span);\n\t\t\tspan = next_span;\n\t\t}\n\t\theap->size_class[iclass].partial_span = 0;\n\t\tspan = heap->full_span[iclass];\n\t\twhile (span) {\n\t\t\tnext_span = span->next;\n\t\t\t_rpmalloc_heap_cache_insert(heap, span);\n\t\t\tspan = next_span;\n\t\t}\n\t}\n\tmemset(heap->size_class, 0, sizeof(heap->size_class));\n\tmemset(heap->full_span, 0, sizeof(heap->full_span));\n\n\tspan = heap->large_huge_span;\n\twhile (span) {\n\t\tnext_span = span->next;\n\t\tif (UNEXPECTED(span->size_class == SIZE_CLASS_HUGE))\n\t\t\t_rpmalloc_deallocate_huge(span);\n\t\telse\n\t\t\t_rpmalloc_heap_cache_insert(heap, span);\n\t\tspan = next_span;\n\t}\n\theap->large_huge_span = 0;\n\theap->full_span_count = 0;\n\n#if ENABLE_THREAD_CACHE\n\tfor (size_t iclass = 0; iclass < LARGE_CLASS_COUNT; ++iclass) {\n\t\tspan_cache_t* span_cache;\n\t\tif (!iclass)\n\t\t\tspan_cache = &heap->span_cache;\n\t\telse\n\t\t\tspan_cache = (span_cache_t*)(heap->span_large_cache + (iclass - 1));\n\t\tif (!span_cache->count)\n\t\t\tcontinue;\n#if ENABLE_GLOBAL_CACHE\n\t\t_rpmalloc_stat_add64(&heap->thread_to_global, span_cache->count * (iclass + 1) * _memory_span_size);\n\t\t_rpmalloc_stat_add(&heap->span_use[iclass].spans_to_global, span_cache->count);\n\t\t_rpmalloc_global_cache_insert_spans(span_cache->span, iclass + 1, span_cache->count);\n#else\n\t\tfor (size_t ispan = 0; ispan < span_cache->count; ++ispan)\n\t\t\t_rpmalloc_span_unmap(span_cache->span[ispan]);\n#endif\n\t\tspan_cache->count = 0;\n\t}\n#endif\n\n#if ENABLE_STATISTICS\n\tfor (size_t iclass = 0; iclass < SIZE_CLASS_COUNT; ++iclass) {\n\t\tatomic_store32(&heap->size_class_use[iclass].alloc_current, 0);\n\t\tatomic_store32(&heap->size_class_use[iclass].spans_current, 0);\n\t}\n\tfor (size_t iclass = 0; iclass < LARGE_CLASS_COUNT; ++iclass) {\n\t\tatomic_store32(&heap->span_use[iclass].current, 0);\n\t}\n#endif\n}\n\nextern inline void\nrpmalloc_heap_thread_set_current(rpmalloc_heap_t* heap) {\n\theap_t* prev_heap = get_thread_heap_raw();\n\tif (prev_heap != heap) {\n\t\tset_thread_heap(heap);\n\t\tif (prev_heap)\n\t\t\trpmalloc_heap_release(prev_heap);\n\t}\n}\n\n#endif\n\n}\n\n#endif\n"
  },
  {
    "path": "tracy-client-sys/tracy/client/tracy_rpmalloc.hpp",
    "content": "/* rpmalloc.h  -  Memory allocator  -  Public Domain  -  2016 Mattias Jansson\n *\n * This library provides a cross-platform lock free thread caching malloc implementation in C11.\n * The latest source code is always available at\n *\n * https://github.com/mjansson/rpmalloc\n *\n * This library is put in the public domain; you can redistribute it and/or modify it without any restrictions.\n *\n */\n\n#pragma once\n\n#include <stddef.h>\n#include \"../common/TracyApi.h\"\n\nnamespace tracy\n{\n\n#if defined(__clang__) || defined(__GNUC__)\n# define RPMALLOC_EXPORT __attribute__((visibility(\"default\")))\n# define RPMALLOC_ALLOCATOR \n# if (defined(__clang_major__) && (__clang_major__ < 4)) || (defined(__GNUC__) && defined(ENABLE_PRELOAD) && ENABLE_PRELOAD)\n# define RPMALLOC_ATTRIB_MALLOC\n# define RPMALLOC_ATTRIB_ALLOC_SIZE(size)\n# define RPMALLOC_ATTRIB_ALLOC_SIZE2(count, size)\n# else\n# define RPMALLOC_ATTRIB_MALLOC __attribute__((__malloc__))\n# define RPMALLOC_ATTRIB_ALLOC_SIZE(size) __attribute__((alloc_size(size)))\n# define RPMALLOC_ATTRIB_ALLOC_SIZE2(count, size)  __attribute__((alloc_size(count, size)))\n# endif\n# define RPMALLOC_CDECL\n#elif defined(_MSC_VER)\n# define RPMALLOC_EXPORT\n# define RPMALLOC_ALLOCATOR __declspec(allocator) __declspec(restrict)\n# define RPMALLOC_ATTRIB_MALLOC\n# define RPMALLOC_ATTRIB_ALLOC_SIZE(size)\n# define RPMALLOC_ATTRIB_ALLOC_SIZE2(count,size)\n# define RPMALLOC_CDECL __cdecl\n#else\n# define RPMALLOC_EXPORT\n# define RPMALLOC_ALLOCATOR\n# define RPMALLOC_ATTRIB_MALLOC\n# define RPMALLOC_ATTRIB_ALLOC_SIZE(size)\n# define RPMALLOC_ATTRIB_ALLOC_SIZE2(count,size)\n# define RPMALLOC_CDECL\n#endif\n\n//! Define RPMALLOC_CONFIGURABLE to enable configuring sizes. Will introduce\n//  a very small overhead due to some size calculations not being compile time constants\n#ifndef RPMALLOC_CONFIGURABLE\n#define RPMALLOC_CONFIGURABLE 0\n#endif\n\n//! Define RPMALLOC_FIRST_CLASS_HEAPS to enable heap based API (rpmalloc_heap_* functions).\n//  Will introduce a very small overhead to track fully allocated spans in heaps\n#ifndef RPMALLOC_FIRST_CLASS_HEAPS\n#define RPMALLOC_FIRST_CLASS_HEAPS 0\n#endif\n\n//! Flag to rpaligned_realloc to not preserve content in reallocation\n#define RPMALLOC_NO_PRESERVE    1\n//! Flag to rpaligned_realloc to fail and return null pointer if grow cannot be done in-place,\n//  in which case the original pointer is still valid (just like a call to realloc which failes to allocate\n//  a new block).\n#define RPMALLOC_GROW_OR_FAIL   2\n\ntypedef struct rpmalloc_global_statistics_t {\n\t//! Current amount of virtual memory mapped, all of which might not have been committed (only if ENABLE_STATISTICS=1)\n\tsize_t mapped;\n\t//! Peak amount of virtual memory mapped, all of which might not have been committed (only if ENABLE_STATISTICS=1)\n\tsize_t mapped_peak;\n\t//! Current amount of memory in global caches for small and medium sizes (<32KiB)\n\tsize_t cached;\n\t//! Current amount of memory allocated in huge allocations, i.e larger than LARGE_SIZE_LIMIT which is 2MiB by default (only if ENABLE_STATISTICS=1)\n\tsize_t huge_alloc;\n\t//! Peak amount of memory allocated in huge allocations, i.e larger than LARGE_SIZE_LIMIT which is 2MiB by default (only if ENABLE_STATISTICS=1)\n\tsize_t huge_alloc_peak;\n\t//! Total amount of memory mapped since initialization (only if ENABLE_STATISTICS=1)\n\tsize_t mapped_total;\n\t//! Total amount of memory unmapped since initialization  (only if ENABLE_STATISTICS=1)\n\tsize_t unmapped_total;\n} rpmalloc_global_statistics_t;\n\ntypedef struct rpmalloc_thread_statistics_t {\n\t//! Current number of bytes available in thread size class caches for small and medium sizes (<32KiB)\n\tsize_t sizecache;\n\t//! Current number of bytes available in thread span caches for small and medium sizes (<32KiB)\n\tsize_t spancache;\n\t//! Total number of bytes transitioned from thread cache to global cache (only if ENABLE_STATISTICS=1)\n\tsize_t thread_to_global;\n\t//! Total number of bytes transitioned from global cache to thread cache (only if ENABLE_STATISTICS=1)\n\tsize_t global_to_thread;\n\t//! Per span count statistics (only if ENABLE_STATISTICS=1)\n\tstruct {\n\t\t//! Currently used number of spans\n\t\tsize_t current;\n\t\t//! High water mark of spans used\n\t\tsize_t peak;\n\t\t//! Number of spans transitioned to global cache\n\t\tsize_t to_global;\n\t\t//! Number of spans transitioned from global cache\n\t\tsize_t from_global;\n\t\t//! Number of spans transitioned to thread cache\n\t\tsize_t to_cache;\n\t\t//! Number of spans transitioned from thread cache\n\t\tsize_t from_cache;\n\t\t//! Number of spans transitioned to reserved state\n\t\tsize_t to_reserved;\n\t\t//! Number of spans transitioned from reserved state\n\t\tsize_t from_reserved;\n\t\t//! Number of raw memory map calls (not hitting the reserve spans but resulting in actual OS mmap calls)\n\t\tsize_t map_calls;\n\t} span_use[64];\n\t//! Per size class statistics (only if ENABLE_STATISTICS=1)\n\tstruct {\n\t\t//! Current number of allocations\n\t\tsize_t alloc_current;\n\t\t//! Peak number of allocations\n\t\tsize_t alloc_peak;\n\t\t//! Total number of allocations\n\t\tsize_t alloc_total;\n\t\t//! Total number of frees\n\t\tsize_t free_total;\n\t\t//! Number of spans transitioned to cache\n\t\tsize_t spans_to_cache;\n\t\t//! Number of spans transitioned from cache\n\t\tsize_t spans_from_cache;\n\t\t//! Number of spans transitioned from reserved state\n\t\tsize_t spans_from_reserved;\n\t\t//! Number of raw memory map calls (not hitting the reserve spans but resulting in actual OS mmap calls)\n\t\tsize_t map_calls;\n\t} size_use[128];\n} rpmalloc_thread_statistics_t;\n\ntypedef struct rpmalloc_config_t {\n\t//! Map memory pages for the given number of bytes. The returned address MUST be\n\t//  aligned to the rpmalloc span size, which will always be a power of two.\n\t//  Optionally the function can store an alignment offset in the offset variable\n\t//  in case it performs alignment and the returned pointer is offset from the\n\t//  actual start of the memory region due to this alignment. The alignment offset\n\t//  will be passed to the memory unmap function. The alignment offset MUST NOT be\n\t//  larger than 65535 (storable in an uint16_t), if it is you must use natural\n\t//  alignment to shift it into 16 bits. If you set a memory_map function, you\n\t//  must also set a memory_unmap function or else the default implementation will\n\t//  be used for both. This function must be thread safe, it can be called by\n\t//  multiple threads simultaneously.\n\tvoid* (*memory_map)(size_t size, size_t* offset);\n\t//! Unmap the memory pages starting at address and spanning the given number of bytes.\n\t//  If release is set to non-zero, the unmap is for an entire span range as returned by\n\t//  a previous call to memory_map and that the entire range should be released. The\n\t//  release argument holds the size of the entire span range. If release is set to 0,\n\t//  the unmap is a partial decommit of a subset of the mapped memory range.\n\t//  If you set a memory_unmap function, you must also set a memory_map function or\n\t//  else the default implementation will be used for both. This function must be thread\n\t//  safe, it can be called by multiple threads simultaneously.\n\tvoid (*memory_unmap)(void* address, size_t size, size_t offset, size_t release);\n\t//! Called when an assert fails, if asserts are enabled. Will use the standard assert()\n\t//  if this is not set.\n\tvoid (*error_callback)(const char* message);\n\t//! Called when a call to map memory pages fails (out of memory). If this callback is\n\t//  not set or returns zero the library will return a null pointer in the allocation\n\t//  call. If this callback returns non-zero the map call will be retried. The argument\n\t//  passed is the number of bytes that was requested in the map call. Only used if\n\t//  the default system memory map function is used (memory_map callback is not set).\n\tint (*map_fail_callback)(size_t size);\n\t//! Size of memory pages. The page size MUST be a power of two. All memory mapping\n\t//  requests to memory_map will be made with size set to a multiple of the page size.\n\t//  Used if RPMALLOC_CONFIGURABLE is defined to 1, otherwise system page size is used.\n\tsize_t page_size;\n\t//! Size of a span of memory blocks. MUST be a power of two, and in [4096,262144]\n\t//  range (unless 0 - set to 0 to use the default span size). Used if RPMALLOC_CONFIGURABLE\n\t//  is defined to 1.\n\tsize_t span_size;\n\t//! Number of spans to map at each request to map new virtual memory blocks. This can\n\t//  be used to minimize the system call overhead at the cost of virtual memory address\n\t//  space. The extra mapped pages will not be written until actually used, so physical\n\t//  committed memory should not be affected in the default implementation. Will be\n\t//  aligned to a multiple of spans that match memory page size in case of huge pages.\n\tsize_t span_map_count;\n\t//! Enable use of large/huge pages. If this flag is set to non-zero and page size is\n\t//  zero, the allocator will try to enable huge pages and auto detect the configuration.\n\t//  If this is set to non-zero and page_size is also non-zero, the allocator will\n\t//  assume huge pages have been configured and enabled prior to initializing the\n\t//  allocator.\n\t//  For Windows, see https://docs.microsoft.com/en-us/windows/desktop/memory/large-page-support\n\t//  For Linux, see https://www.kernel.org/doc/Documentation/vm/hugetlbpage.txt\n\tint enable_huge_pages;\n\t//! Respectively allocated pages and huge allocated pages names for systems\n\t//  supporting it to be able to distinguish among anonymous regions.\n\tconst char *page_name;\n\tconst char *huge_page_name;\n} rpmalloc_config_t;\n\n//! Initialize allocator with default configuration\nTRACY_API int\nrpmalloc_initialize(void);\n\n//! Initialize allocator with given configuration\nRPMALLOC_EXPORT int\nrpmalloc_initialize_config(const rpmalloc_config_t* config);\n\n//! Get allocator configuration\nRPMALLOC_EXPORT const rpmalloc_config_t*\nrpmalloc_config(void);\n\n//! Finalize allocator\nTRACY_API void\nrpmalloc_finalize(void);\n\n//! Initialize allocator for calling thread\nTRACY_API void\nrpmalloc_thread_initialize(void);\n\n//! Finalize allocator for calling thread\nTRACY_API void\nrpmalloc_thread_finalize(int release_caches);\n\n//! Perform deferred deallocations pending for the calling thread heap\nRPMALLOC_EXPORT void\nrpmalloc_thread_collect(void);\n\n//! Query if allocator is initialized for calling thread\nRPMALLOC_EXPORT int\nrpmalloc_is_thread_initialized(void);\n\n//! Get per-thread statistics\nRPMALLOC_EXPORT void\nrpmalloc_thread_statistics(rpmalloc_thread_statistics_t* stats);\n\n//! Get global statistics\nRPMALLOC_EXPORT void\nrpmalloc_global_statistics(rpmalloc_global_statistics_t* stats);\n\n//! Dump all statistics in human readable format to file (should be a FILE*)\nRPMALLOC_EXPORT void\nrpmalloc_dump_statistics(void* file);\n\n//! Allocate a memory block of at least the given size\nTRACY_API RPMALLOC_ALLOCATOR void*\nrpmalloc(size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(1);\n\n//! Free the given memory block\nTRACY_API void\nrpfree(void* ptr);\n\n//! Allocate a memory block of at least the given size and zero initialize it\nRPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*\nrpcalloc(size_t num, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE2(1, 2);\n\n//! Reallocate the given block to at least the given size\nTRACY_API RPMALLOC_ALLOCATOR void*\nrprealloc(void* ptr, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(2);\n\n//! Reallocate the given block to at least the given size and alignment,\n//  with optional control flags (see RPMALLOC_NO_PRESERVE).\n//  Alignment must be a power of two and a multiple of sizeof(void*),\n//  and should ideally be less than memory page size. A caveat of rpmalloc\n//  internals is that this must also be strictly less than the span size (default 64KiB)\nRPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*\nrpaligned_realloc(void* ptr, size_t alignment, size_t size, size_t oldsize, unsigned int flags) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(3);\n\n//! Allocate a memory block of at least the given size and alignment.\n//  Alignment must be a power of two and a multiple of sizeof(void*),\n//  and should ideally be less than memory page size. A caveat of rpmalloc\n//  internals is that this must also be strictly less than the span size (default 64KiB)\nRPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*\nrpaligned_alloc(size_t alignment, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(2);\n\n//! Allocate a memory block of at least the given size and alignment, and zero initialize it.\n//  Alignment must be a power of two and a multiple of sizeof(void*),\n//  and should ideally be less than memory page size. A caveat of rpmalloc\n//  internals is that this must also be strictly less than the span size (default 64KiB)\nRPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*\nrpaligned_calloc(size_t alignment, size_t num, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE2(2, 3);\n\n//! Allocate a memory block of at least the given size and alignment.\n//  Alignment must be a power of two and a multiple of sizeof(void*),\n//  and should ideally be less than memory page size. A caveat of rpmalloc\n//  internals is that this must also be strictly less than the span size (default 64KiB)\nRPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*\nrpmemalign(size_t alignment, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(2);\n\n//! Allocate a memory block of at least the given size and alignment.\n//  Alignment must be a power of two and a multiple of sizeof(void*),\n//  and should ideally be less than memory page size. A caveat of rpmalloc\n//  internals is that this must also be strictly less than the span size (default 64KiB)\nRPMALLOC_EXPORT int\nrpposix_memalign(void** memptr, size_t alignment, size_t size);\n\n//! Query the usable size of the given memory block (from given pointer to the end of block)\nRPMALLOC_EXPORT size_t\nrpmalloc_usable_size(void* ptr);\n\n#if RPMALLOC_FIRST_CLASS_HEAPS\n\n//! Heap type\ntypedef struct heap_t rpmalloc_heap_t;\n\n//! Acquire a new heap. Will reuse existing released heaps or allocate memory for a new heap\n//  if none available. Heap API is implemented with the strict assumption that only one single\n//  thread will call heap functions for a given heap at any given time, no functions are thread safe.\nRPMALLOC_EXPORT rpmalloc_heap_t*\nrpmalloc_heap_acquire(void);\n\n//! Release a heap (does NOT free the memory allocated by the heap, use rpmalloc_heap_free_all before destroying the heap).\n//  Releasing a heap will enable it to be reused by other threads. Safe to pass a null pointer.\nRPMALLOC_EXPORT void\nrpmalloc_heap_release(rpmalloc_heap_t* heap);\n\n//! Allocate a memory block of at least the given size using the given heap.\nRPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*\nrpmalloc_heap_alloc(rpmalloc_heap_t* heap, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(2);\n\n//! Allocate a memory block of at least the given size using the given heap. The returned\n//  block will have the requested alignment. Alignment must be a power of two and a multiple of sizeof(void*),\n//  and should ideally be less than memory page size. A caveat of rpmalloc\n//  internals is that this must also be strictly less than the span size (default 64KiB).\nRPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*\nrpmalloc_heap_aligned_alloc(rpmalloc_heap_t* heap, size_t alignment, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(3);\n\n//! Allocate a memory block of at least the given size using the given heap and zero initialize it.\nRPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*\nrpmalloc_heap_calloc(rpmalloc_heap_t* heap, size_t num, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE2(2, 3);\n\n//! Allocate a memory block of at least the given size using the given heap and zero initialize it. The returned\n//  block will have the requested alignment. Alignment must either be zero, or a power of two and a multiple of sizeof(void*),\n//  and should ideally be less than memory page size. A caveat of rpmalloc\n//  internals is that this must also be strictly less than the span size (default 64KiB).\nRPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*\nrpmalloc_heap_aligned_calloc(rpmalloc_heap_t* heap, size_t alignment, size_t num, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE2(2, 3);\n\n//! Reallocate the given block to at least the given size. The memory block MUST be allocated\n//  by the same heap given to this function.\nRPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*\nrpmalloc_heap_realloc(rpmalloc_heap_t* heap, void* ptr, size_t size, unsigned int flags) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(3);\n\n//! Reallocate the given block to at least the given size. The memory block MUST be allocated\n//  by the same heap given to this function. The returned block will have the requested alignment.\n//  Alignment must be either zero, or a power of two and a multiple of sizeof(void*), and should ideally be\n//  less than memory page size. A caveat of rpmalloc internals is that this must also be strictly less than\n//  the span size (default 64KiB).\nRPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*\nrpmalloc_heap_aligned_realloc(rpmalloc_heap_t* heap, void* ptr, size_t alignment, size_t size, unsigned int flags) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(4);\n\n//! Free the given memory block from the given heap. The memory block MUST be allocated\n//  by the same heap given to this function.\nRPMALLOC_EXPORT void\nrpmalloc_heap_free(rpmalloc_heap_t* heap, void* ptr);\n\n//! Free all memory allocated by the heap\nRPMALLOC_EXPORT void\nrpmalloc_heap_free_all(rpmalloc_heap_t* heap);\n\n//! Set the given heap as the current heap for the calling thread. A heap MUST only be current heap\n//  for a single thread, a heap can never be shared between multiple threads. The previous\n//  current heap for the calling thread is released to be reused by other threads.\nRPMALLOC_EXPORT void\nrpmalloc_heap_thread_set_current(rpmalloc_heap_t* heap);\n\n#endif\n\n}\n"
  },
  {
    "path": "tracy-client-sys/tracy/common/TracyAlign.hpp",
    "content": "#ifndef __TRACYALIGN_HPP__\n#define __TRACYALIGN_HPP__\n\n#include <string.h>\n\n#include \"TracyForceInline.hpp\"\n\nnamespace tracy\n{\n\ntemplate<typename T>\ntracy_force_inline T MemRead( const void* ptr )\n{\n    T val;\n    memcpy( &val, ptr, sizeof( T ) );\n    return val;\n}\n\ntemplate<typename T>\ntracy_force_inline void MemWrite( void* ptr, T val )\n{\n    memcpy( ptr, &val, sizeof( T ) );\n}\n\n}\n\n#endif\n"
  },
  {
    "path": "tracy-client-sys/tracy/common/TracyAlloc.hpp",
    "content": "#ifndef __TRACYALLOC_HPP__\n#define __TRACYALLOC_HPP__\n\n#include <stdlib.h>\n\n#if defined TRACY_ENABLE && !defined __EMSCRIPTEN__\n#  include \"TracyApi.h\"\n#  include \"TracyForceInline.hpp\"\n#  include \"../client/tracy_rpmalloc.hpp\"\n#  define TRACY_USE_RPMALLOC\n#endif\n\nnamespace tracy\n{\n\n#ifdef TRACY_USE_RPMALLOC\nTRACY_API void InitRpmalloc();\n#else\nstatic inline void InitRpmalloc() {}\n#endif\n\nstatic inline void* tracy_malloc( size_t size )\n{\n#ifdef TRACY_USE_RPMALLOC\n    InitRpmalloc();\n    return rpmalloc( size );\n#else\n    return malloc( size );\n#endif\n}\n\nstatic inline void* tracy_malloc_fast( size_t size )\n{\n#ifdef TRACY_USE_RPMALLOC\n    return rpmalloc( size );\n#else\n    return malloc( size );\n#endif\n}\n\nstatic inline void tracy_free( void* ptr )\n{\n#ifdef TRACY_USE_RPMALLOC\n    InitRpmalloc();\n    rpfree( ptr );\n#else\n    free( ptr );\n#endif\n}\n\nstatic inline void tracy_free_fast( void* ptr )\n{\n#ifdef TRACY_USE_RPMALLOC\n    rpfree( ptr );\n#else\n    free( ptr );\n#endif\n}\n\nstatic inline void* tracy_realloc( void* ptr, size_t size )\n{\n#ifdef TRACY_USE_RPMALLOC\n    InitRpmalloc();\n    return rprealloc( ptr, size );\n#else\n    return realloc( ptr, size );\n#endif\n}\n\n}\n\n#endif\n"
  },
  {
    "path": "tracy-client-sys/tracy/common/TracyApi.h",
    "content": "#ifndef __TRACYAPI_H__\n#define __TRACYAPI_H__\n\n#if defined _WIN32\n#  if defined TRACY_EXPORTS\n#    define TRACY_API __declspec(dllexport)\n#  elif defined TRACY_IMPORTS\n#    define TRACY_API __declspec(dllimport)\n#  else\n#    define TRACY_API\n#  endif\n#else\n#  define TRACY_API __attribute__((visibility(\"default\")))\n#endif\n\n#endif    // __TRACYAPI_H__\n"
  },
  {
    "path": "tracy-client-sys/tracy/common/TracyColor.hpp",
    "content": "#ifndef __TRACYCOLOR_HPP__\n#define __TRACYCOLOR_HPP__\n\nnamespace tracy\n{\nstruct Color\n{\nenum ColorType\n{\n    Snow = 0xfffafa,\n    GhostWhite = 0xf8f8ff,\n    WhiteSmoke = 0xf5f5f5,\n    Gainsboro = 0xdcdcdc,\n    FloralWhite = 0xfffaf0,\n    OldLace = 0xfdf5e6,\n    Linen = 0xfaf0e6,\n    AntiqueWhite = 0xfaebd7,\n    PapayaWhip = 0xffefd5,\n    BlanchedAlmond = 0xffebcd,\n    Bisque = 0xffe4c4,\n    PeachPuff = 0xffdab9,\n    NavajoWhite = 0xffdead,\n    Moccasin = 0xffe4b5,\n    Cornsilk = 0xfff8dc,\n    Ivory = 0xfffff0,\n    LemonChiffon = 0xfffacd,\n    Seashell = 0xfff5ee,\n    Honeydew = 0xf0fff0,\n    MintCream = 0xf5fffa,\n    Azure = 0xf0ffff,\n    AliceBlue = 0xf0f8ff,\n    Lavender = 0xe6e6fa,\n    LavenderBlush = 0xfff0f5,\n    MistyRose = 0xffe4e1,\n    White = 0xffffff,\n    Black = 0x000000,\n    DarkSlateGray = 0x2f4f4f,\n    DarkSlateGrey = 0x2f4f4f,\n    DimGray = 0x696969,\n    DimGrey = 0x696969,\n    SlateGray = 0x708090,\n    SlateGrey = 0x708090,\n    LightSlateGray = 0x778899,\n    LightSlateGrey = 0x778899,\n    Gray = 0xbebebe,\n    Grey = 0xbebebe,\n    X11Gray = 0xbebebe,\n    X11Grey = 0xbebebe,\n    WebGray = 0x808080,\n    WebGrey = 0x808080,\n    LightGrey = 0xd3d3d3,\n    LightGray = 0xd3d3d3,\n    MidnightBlue = 0x191970,\n    Navy = 0x000080,\n    NavyBlue = 0x000080,\n    CornflowerBlue = 0x6495ed,\n    DarkSlateBlue = 0x483d8b,\n    SlateBlue = 0x6a5acd,\n    MediumSlateBlue = 0x7b68ee,\n    LightSlateBlue = 0x8470ff,\n    MediumBlue = 0x0000cd,\n    RoyalBlue = 0x4169e1,\n    Blue = 0x0000ff,\n    DodgerBlue = 0x1e90ff,\n    DeepSkyBlue = 0x00bfff,\n    SkyBlue = 0x87ceeb,\n    LightSkyBlue = 0x87cefa,\n    SteelBlue = 0x4682b4,\n    LightSteelBlue = 0xb0c4de,\n    LightBlue = 0xadd8e6,\n    PowderBlue = 0xb0e0e6,\n    PaleTurquoise = 0xafeeee,\n    DarkTurquoise = 0x00ced1,\n    MediumTurquoise = 0x48d1cc,\n    Turquoise = 0x40e0d0,\n    Cyan = 0x00ffff,\n    Aqua = 0x00ffff,\n    LightCyan = 0xe0ffff,\n    CadetBlue = 0x5f9ea0,\n    MediumAquamarine = 0x66cdaa,\n    Aquamarine = 0x7fffd4,\n    DarkGreen = 0x006400,\n    DarkOliveGreen = 0x556b2f,\n    DarkSeaGreen = 0x8fbc8f,\n    SeaGreen = 0x2e8b57,\n    MediumSeaGreen = 0x3cb371,\n    LightSeaGreen = 0x20b2aa,\n    PaleGreen = 0x98fb98,\n    SpringGreen = 0x00ff7f,\n    LawnGreen = 0x7cfc00,\n    Green = 0x00ff00,\n    Lime = 0x00ff00,\n    X11Green = 0x00ff00,\n    WebGreen = 0x008000,\n    Chartreuse = 0x7fff00,\n    MediumSpringGreen = 0x00fa9a,\n    GreenYellow = 0xadff2f,\n    LimeGreen = 0x32cd32,\n    YellowGreen = 0x9acd32,\n    ForestGreen = 0x228b22,\n    OliveDrab = 0x6b8e23,\n    DarkKhaki = 0xbdb76b,\n    Khaki = 0xf0e68c,\n    PaleGoldenrod = 0xeee8aa,\n    LightGoldenrodYellow = 0xfafad2,\n    LightYellow = 0xffffe0,\n    Yellow = 0xffff00,\n    Gold = 0xffd700,\n    LightGoldenrod = 0xeedd82,\n    Goldenrod = 0xdaa520,\n    DarkGoldenrod = 0xb8860b,\n    RosyBrown = 0xbc8f8f,\n    IndianRed = 0xcd5c5c,\n    SaddleBrown = 0x8b4513,\n    Sienna = 0xa0522d,\n    Peru = 0xcd853f,\n    Burlywood = 0xdeb887,\n    Beige = 0xf5f5dc,\n    Wheat = 0xf5deb3,\n    SandyBrown = 0xf4a460,\n    Tan = 0xd2b48c,\n    Chocolate = 0xd2691e,\n    Firebrick = 0xb22222,\n    Brown = 0xa52a2a,\n    DarkSalmon = 0xe9967a,\n    Salmon = 0xfa8072,\n    LightSalmon = 0xffa07a,\n    Orange = 0xffa500,\n    DarkOrange = 0xff8c00,\n    Coral = 0xff7f50,\n    LightCoral = 0xf08080,\n    Tomato = 0xff6347,\n    OrangeRed = 0xff4500,\n    Red = 0xff0000,\n    HotPink = 0xff69b4,\n    DeepPink = 0xff1493,\n    Pink = 0xffc0cb,\n    LightPink = 0xffb6c1,\n    PaleVioletRed = 0xdb7093,\n    Maroon = 0xb03060,\n    X11Maroon = 0xb03060,\n    WebMaroon = 0x800000,\n    MediumVioletRed = 0xc71585,\n    VioletRed = 0xd02090,\n    Magenta = 0xff00ff,\n    Fuchsia = 0xff00ff,\n    Violet = 0xee82ee,\n    Plum = 0xdda0dd,\n    Orchid = 0xda70d6,\n    MediumOrchid = 0xba55d3,\n    DarkOrchid = 0x9932cc,\n    DarkViolet = 0x9400d3,\n    BlueViolet = 0x8a2be2,\n    Purple = 0xa020f0,\n    X11Purple = 0xa020f0,\n    WebPurple = 0x800080,\n    MediumPurple = 0x9370db,\n    Thistle = 0xd8bfd8,\n    Snow1 = 0xfffafa,\n    Snow2 = 0xeee9e9,\n    Snow3 = 0xcdc9c9,\n    Snow4 = 0x8b8989,\n    Seashell1 = 0xfff5ee,\n    Seashell2 = 0xeee5de,\n    Seashell3 = 0xcdc5bf,\n    Seashell4 = 0x8b8682,\n    AntiqueWhite1 = 0xffefdb,\n    AntiqueWhite2 = 0xeedfcc,\n    AntiqueWhite3 = 0xcdc0b0,\n    AntiqueWhite4 = 0x8b8378,\n    Bisque1 = 0xffe4c4,\n    Bisque2 = 0xeed5b7,\n    Bisque3 = 0xcdb79e,\n    Bisque4 = 0x8b7d6b,\n    PeachPuff1 = 0xffdab9,\n    PeachPuff2 = 0xeecbad,\n    PeachPuff3 = 0xcdaf95,\n    PeachPuff4 = 0x8b7765,\n    NavajoWhite1 = 0xffdead,\n    NavajoWhite2 = 0xeecfa1,\n    NavajoWhite3 = 0xcdb38b,\n    NavajoWhite4 = 0x8b795e,\n    LemonChiffon1 = 0xfffacd,\n    LemonChiffon2 = 0xeee9bf,\n    LemonChiffon3 = 0xcdc9a5,\n    LemonChiffon4 = 0x8b8970,\n    Cornsilk1 = 0xfff8dc,\n    Cornsilk2 = 0xeee8cd,\n    Cornsilk3 = 0xcdc8b1,\n    Cornsilk4 = 0x8b8878,\n    Ivory1 = 0xfffff0,\n    Ivory2 = 0xeeeee0,\n    Ivory3 = 0xcdcdc1,\n    Ivory4 = 0x8b8b83,\n    Honeydew1 = 0xf0fff0,\n    Honeydew2 = 0xe0eee0,\n    Honeydew3 = 0xc1cdc1,\n    Honeydew4 = 0x838b83,\n    LavenderBlush1 = 0xfff0f5,\n    LavenderBlush2 = 0xeee0e5,\n    LavenderBlush3 = 0xcdc1c5,\n    LavenderBlush4 = 0x8b8386,\n    MistyRose1 = 0xffe4e1,\n    MistyRose2 = 0xeed5d2,\n    MistyRose3 = 0xcdb7b5,\n    MistyRose4 = 0x8b7d7b,\n    Azure1 = 0xf0ffff,\n    Azure2 = 0xe0eeee,\n    Azure3 = 0xc1cdcd,\n    Azure4 = 0x838b8b,\n    SlateBlue1 = 0x836fff,\n    SlateBlue2 = 0x7a67ee,\n    SlateBlue3 = 0x6959cd,\n    SlateBlue4 = 0x473c8b,\n    RoyalBlue1 = 0x4876ff,\n    RoyalBlue2 = 0x436eee,\n    RoyalBlue3 = 0x3a5fcd,\n    RoyalBlue4 = 0x27408b,\n    Blue1 = 0x0000ff,\n    Blue2 = 0x0000ee,\n    Blue3 = 0x0000cd,\n    Blue4 = 0x00008b,\n    DodgerBlue1 = 0x1e90ff,\n    DodgerBlue2 = 0x1c86ee,\n    DodgerBlue3 = 0x1874cd,\n    DodgerBlue4 = 0x104e8b,\n    SteelBlue1 = 0x63b8ff,\n    SteelBlue2 = 0x5cacee,\n    SteelBlue3 = 0x4f94cd,\n    SteelBlue4 = 0x36648b,\n    DeepSkyBlue1 = 0x00bfff,\n    DeepSkyBlue2 = 0x00b2ee,\n    DeepSkyBlue3 = 0x009acd,\n    DeepSkyBlue4 = 0x00688b,\n    SkyBlue1 = 0x87ceff,\n    SkyBlue2 = 0x7ec0ee,\n    SkyBlue3 = 0x6ca6cd,\n    SkyBlue4 = 0x4a708b,\n    LightSkyBlue1 = 0xb0e2ff,\n    LightSkyBlue2 = 0xa4d3ee,\n    LightSkyBlue3 = 0x8db6cd,\n    LightSkyBlue4 = 0x607b8b,\n    SlateGray1 = 0xc6e2ff,\n    SlateGray2 = 0xb9d3ee,\n    SlateGray3 = 0x9fb6cd,\n    SlateGray4 = 0x6c7b8b,\n    LightSteelBlue1 = 0xcae1ff,\n    LightSteelBlue2 = 0xbcd2ee,\n    LightSteelBlue3 = 0xa2b5cd,\n    LightSteelBlue4 = 0x6e7b8b,\n    LightBlue1 = 0xbfefff,\n    LightBlue2 = 0xb2dfee,\n    LightBlue3 = 0x9ac0cd,\n    LightBlue4 = 0x68838b,\n    LightCyan1 = 0xe0ffff,\n    LightCyan2 = 0xd1eeee,\n    LightCyan3 = 0xb4cdcd,\n    LightCyan4 = 0x7a8b8b,\n    PaleTurquoise1 = 0xbbffff,\n    PaleTurquoise2 = 0xaeeeee,\n    PaleTurquoise3 = 0x96cdcd,\n    PaleTurquoise4 = 0x668b8b,\n    CadetBlue1 = 0x98f5ff,\n    CadetBlue2 = 0x8ee5ee,\n    CadetBlue3 = 0x7ac5cd,\n    CadetBlue4 = 0x53868b,\n    Turquoise1 = 0x00f5ff,\n    Turquoise2 = 0x00e5ee,\n    Turquoise3 = 0x00c5cd,\n    Turquoise4 = 0x00868b,\n    Cyan1 = 0x00ffff,\n    Cyan2 = 0x00eeee,\n    Cyan3 = 0x00cdcd,\n    Cyan4 = 0x008b8b,\n    DarkSlateGray1 = 0x97ffff,\n    DarkSlateGray2 = 0x8deeee,\n    DarkSlateGray3 = 0x79cdcd,\n    DarkSlateGray4 = 0x528b8b,\n    Aquamarine1 = 0x7fffd4,\n    Aquamarine2 = 0x76eec6,\n    Aquamarine3 = 0x66cdaa,\n    Aquamarine4 = 0x458b74,\n    DarkSeaGreen1 = 0xc1ffc1,\n    DarkSeaGreen2 = 0xb4eeb4,\n    DarkSeaGreen3 = 0x9bcd9b,\n    DarkSeaGreen4 = 0x698b69,\n    SeaGreen1 = 0x54ff9f,\n    SeaGreen2 = 0x4eee94,\n    SeaGreen3 = 0x43cd80,\n    SeaGreen4 = 0x2e8b57,\n    PaleGreen1 = 0x9aff9a,\n    PaleGreen2 = 0x90ee90,\n    PaleGreen3 = 0x7ccd7c,\n    PaleGreen4 = 0x548b54,\n    SpringGreen1 = 0x00ff7f,\n    SpringGreen2 = 0x00ee76,\n    SpringGreen3 = 0x00cd66,\n    SpringGreen4 = 0x008b45,\n    Green1 = 0x00ff00,\n    Green2 = 0x00ee00,\n    Green3 = 0x00cd00,\n    Green4 = 0x008b00,\n    Chartreuse1 = 0x7fff00,\n    Chartreuse2 = 0x76ee00,\n    Chartreuse3 = 0x66cd00,\n    Chartreuse4 = 0x458b00,\n    OliveDrab1 = 0xc0ff3e,\n    OliveDrab2 = 0xb3ee3a,\n    OliveDrab3 = 0x9acd32,\n    OliveDrab4 = 0x698b22,\n    DarkOliveGreen1 = 0xcaff70,\n    DarkOliveGreen2 = 0xbcee68,\n    DarkOliveGreen3 = 0xa2cd5a,\n    DarkOliveGreen4 = 0x6e8b3d,\n    Khaki1 = 0xfff68f,\n    Khaki2 = 0xeee685,\n    Khaki3 = 0xcdc673,\n    Khaki4 = 0x8b864e,\n    LightGoldenrod1 = 0xffec8b,\n    LightGoldenrod2 = 0xeedc82,\n    LightGoldenrod3 = 0xcdbe70,\n    LightGoldenrod4 = 0x8b814c,\n    LightYellow1 = 0xffffe0,\n    LightYellow2 = 0xeeeed1,\n    LightYellow3 = 0xcdcdb4,\n    LightYellow4 = 0x8b8b7a,\n    Yellow1 = 0xffff00,\n    Yellow2 = 0xeeee00,\n    Yellow3 = 0xcdcd00,\n    Yellow4 = 0x8b8b00,\n    Gold1 = 0xffd700,\n    Gold2 = 0xeec900,\n    Gold3 = 0xcdad00,\n    Gold4 = 0x8b7500,\n    Goldenrod1 = 0xffc125,\n    Goldenrod2 = 0xeeb422,\n    Goldenrod3 = 0xcd9b1d,\n    Goldenrod4 = 0x8b6914,\n    DarkGoldenrod1 = 0xffb90f,\n    DarkGoldenrod2 = 0xeead0e,\n    DarkGoldenrod3 = 0xcd950c,\n    DarkGoldenrod4 = 0x8b6508,\n    RosyBrown1 = 0xffc1c1,\n    RosyBrown2 = 0xeeb4b4,\n    RosyBrown3 = 0xcd9b9b,\n    RosyBrown4 = 0x8b6969,\n    IndianRed1 = 0xff6a6a,\n    IndianRed2 = 0xee6363,\n    IndianRed3 = 0xcd5555,\n    IndianRed4 = 0x8b3a3a,\n    Sienna1 = 0xff8247,\n    Sienna2 = 0xee7942,\n    Sienna3 = 0xcd6839,\n    Sienna4 = 0x8b4726,\n    Burlywood1 = 0xffd39b,\n    Burlywood2 = 0xeec591,\n    Burlywood3 = 0xcdaa7d,\n    Burlywood4 = 0x8b7355,\n    Wheat1 = 0xffe7ba,\n    Wheat2 = 0xeed8ae,\n    Wheat3 = 0xcdba96,\n    Wheat4 = 0x8b7e66,\n    Tan1 = 0xffa54f,\n    Tan2 = 0xee9a49,\n    Tan3 = 0xcd853f,\n    Tan4 = 0x8b5a2b,\n    Chocolate1 = 0xff7f24,\n    Chocolate2 = 0xee7621,\n    Chocolate3 = 0xcd661d,\n    Chocolate4 = 0x8b4513,\n    Firebrick1 = 0xff3030,\n    Firebrick2 = 0xee2c2c,\n    Firebrick3 = 0xcd2626,\n    Firebrick4 = 0x8b1a1a,\n    Brown1 = 0xff4040,\n    Brown2 = 0xee3b3b,\n    Brown3 = 0xcd3333,\n    Brown4 = 0x8b2323,\n    Salmon1 = 0xff8c69,\n    Salmon2 = 0xee8262,\n    Salmon3 = 0xcd7054,\n    Salmon4 = 0x8b4c39,\n    LightSalmon1 = 0xffa07a,\n    LightSalmon2 = 0xee9572,\n    LightSalmon3 = 0xcd8162,\n    LightSalmon4 = 0x8b5742,\n    Orange1 = 0xffa500,\n    Orange2 = 0xee9a00,\n    Orange3 = 0xcd8500,\n    Orange4 = 0x8b5a00,\n    DarkOrange1 = 0xff7f00,\n    DarkOrange2 = 0xee7600,\n    DarkOrange3 = 0xcd6600,\n    DarkOrange4 = 0x8b4500,\n    Coral1 = 0xff7256,\n    Coral2 = 0xee6a50,\n    Coral3 = 0xcd5b45,\n    Coral4 = 0x8b3e2f,\n    Tomato1 = 0xff6347,\n    Tomato2 = 0xee5c42,\n    Tomato3 = 0xcd4f39,\n    Tomato4 = 0x8b3626,\n    OrangeRed1 = 0xff4500,\n    OrangeRed2 = 0xee4000,\n    OrangeRed3 = 0xcd3700,\n    OrangeRed4 = 0x8b2500,\n    Red1 = 0xff0000,\n    Red2 = 0xee0000,\n    Red3 = 0xcd0000,\n    Red4 = 0x8b0000,\n    DeepPink1 = 0xff1493,\n    DeepPink2 = 0xee1289,\n    DeepPink3 = 0xcd1076,\n    DeepPink4 = 0x8b0a50,\n    HotPink1 = 0xff6eb4,\n    HotPink2 = 0xee6aa7,\n    HotPink3 = 0xcd6090,\n    HotPink4 = 0x8b3a62,\n    Pink1 = 0xffb5c5,\n    Pink2 = 0xeea9b8,\n    Pink3 = 0xcd919e,\n    Pink4 = 0x8b636c,\n    LightPink1 = 0xffaeb9,\n    LightPink2 = 0xeea2ad,\n    LightPink3 = 0xcd8c95,\n    LightPink4 = 0x8b5f65,\n    PaleVioletRed1 = 0xff82ab,\n    PaleVioletRed2 = 0xee799f,\n    PaleVioletRed3 = 0xcd6889,\n    PaleVioletRed4 = 0x8b475d,\n    Maroon1 = 0xff34b3,\n    Maroon2 = 0xee30a7,\n    Maroon3 = 0xcd2990,\n    Maroon4 = 0x8b1c62,\n    VioletRed1 = 0xff3e96,\n    VioletRed2 = 0xee3a8c,\n    VioletRed3 = 0xcd3278,\n    VioletRed4 = 0x8b2252,\n    Magenta1 = 0xff00ff,\n    Magenta2 = 0xee00ee,\n    Magenta3 = 0xcd00cd,\n    Magenta4 = 0x8b008b,\n    Orchid1 = 0xff83fa,\n    Orchid2 = 0xee7ae9,\n    Orchid3 = 0xcd69c9,\n    Orchid4 = 0x8b4789,\n    Plum1 = 0xffbbff,\n    Plum2 = 0xeeaeee,\n    Plum3 = 0xcd96cd,\n    Plum4 = 0x8b668b,\n    MediumOrchid1 = 0xe066ff,\n    MediumOrchid2 = 0xd15fee,\n    MediumOrchid3 = 0xb452cd,\n    MediumOrchid4 = 0x7a378b,\n    DarkOrchid1 = 0xbf3eff,\n    DarkOrchid2 = 0xb23aee,\n    DarkOrchid3 = 0x9a32cd,\n    DarkOrchid4 = 0x68228b,\n    Purple1 = 0x9b30ff,\n    Purple2 = 0x912cee,\n    Purple3 = 0x7d26cd,\n    Purple4 = 0x551a8b,\n    MediumPurple1 = 0xab82ff,\n    MediumPurple2 = 0x9f79ee,\n    MediumPurple3 = 0x8968cd,\n    MediumPurple4 = 0x5d478b,\n    Thistle1 = 0xffe1ff,\n    Thistle2 = 0xeed2ee,\n    Thistle3 = 0xcdb5cd,\n    Thistle4 = 0x8b7b8b,\n    Gray0 = 0x000000,\n    Grey0 = 0x000000,\n    Gray1 = 0x030303,\n    Grey1 = 0x030303,\n    Gray2 = 0x050505,\n    Grey2 = 0x050505,\n    Gray3 = 0x080808,\n    Grey3 = 0x080808,\n    Gray4 = 0x0a0a0a,\n    Grey4 = 0x0a0a0a,\n    Gray5 = 0x0d0d0d,\n    Grey5 = 0x0d0d0d,\n    Gray6 = 0x0f0f0f,\n    Grey6 = 0x0f0f0f,\n    Gray7 = 0x121212,\n    Grey7 = 0x121212,\n    Gray8 = 0x141414,\n    Grey8 = 0x141414,\n    Gray9 = 0x171717,\n    Grey9 = 0x171717,\n    Gray10 = 0x1a1a1a,\n    Grey10 = 0x1a1a1a,\n    Gray11 = 0x1c1c1c,\n    Grey11 = 0x1c1c1c,\n    Gray12 = 0x1f1f1f,\n    Grey12 = 0x1f1f1f,\n    Gray13 = 0x212121,\n    Grey13 = 0x212121,\n    Gray14 = 0x242424,\n    Grey14 = 0x242424,\n    Gray15 = 0x262626,\n    Grey15 = 0x262626,\n    Gray16 = 0x292929,\n    Grey16 = 0x292929,\n    Gray17 = 0x2b2b2b,\n    Grey17 = 0x2b2b2b,\n    Gray18 = 0x2e2e2e,\n    Grey18 = 0x2e2e2e,\n    Gray19 = 0x303030,\n    Grey19 = 0x303030,\n    Gray20 = 0x333333,\n    Grey20 = 0x333333,\n    Gray21 = 0x363636,\n    Grey21 = 0x363636,\n    Gray22 = 0x383838,\n    Grey22 = 0x383838,\n    Gray23 = 0x3b3b3b,\n    Grey23 = 0x3b3b3b,\n    Gray24 = 0x3d3d3d,\n    Grey24 = 0x3d3d3d,\n    Gray25 = 0x404040,\n    Grey25 = 0x404040,\n    Gray26 = 0x424242,\n    Grey26 = 0x424242,\n    Gray27 = 0x454545,\n    Grey27 = 0x454545,\n    Gray28 = 0x474747,\n    Grey28 = 0x474747,\n    Gray29 = 0x4a4a4a,\n    Grey29 = 0x4a4a4a,\n    Gray30 = 0x4d4d4d,\n    Grey30 = 0x4d4d4d,\n    Gray31 = 0x4f4f4f,\n    Grey31 = 0x4f4f4f,\n    Gray32 = 0x525252,\n    Grey32 = 0x525252,\n    Gray33 = 0x545454,\n    Grey33 = 0x545454,\n    Gray34 = 0x575757,\n    Grey34 = 0x575757,\n    Gray35 = 0x595959,\n    Grey35 = 0x595959,\n    Gray36 = 0x5c5c5c,\n    Grey36 = 0x5c5c5c,\n    Gray37 = 0x5e5e5e,\n    Grey37 = 0x5e5e5e,\n    Gray38 = 0x616161,\n    Grey38 = 0x616161,\n    Gray39 = 0x636363,\n    Grey39 = 0x636363,\n    Gray40 = 0x666666,\n    Grey40 = 0x666666,\n    Gray41 = 0x696969,\n    Grey41 = 0x696969,\n    Gray42 = 0x6b6b6b,\n    Grey42 = 0x6b6b6b,\n    Gray43 = 0x6e6e6e,\n    Grey43 = 0x6e6e6e,\n    Gray44 = 0x707070,\n    Grey44 = 0x707070,\n    Gray45 = 0x737373,\n    Grey45 = 0x737373,\n    Gray46 = 0x757575,\n    Grey46 = 0x757575,\n    Gray47 = 0x787878,\n    Grey47 = 0x787878,\n    Gray48 = 0x7a7a7a,\n    Grey48 = 0x7a7a7a,\n    Gray49 = 0x7d7d7d,\n    Grey49 = 0x7d7d7d,\n    Gray50 = 0x7f7f7f,\n    Grey50 = 0x7f7f7f,\n    Gray51 = 0x828282,\n    Grey51 = 0x828282,\n    Gray52 = 0x858585,\n    Grey52 = 0x858585,\n    Gray53 = 0x878787,\n    Grey53 = 0x878787,\n    Gray54 = 0x8a8a8a,\n    Grey54 = 0x8a8a8a,\n    Gray55 = 0x8c8c8c,\n    Grey55 = 0x8c8c8c,\n    Gray56 = 0x8f8f8f,\n    Grey56 = 0x8f8f8f,\n    Gray57 = 0x919191,\n    Grey57 = 0x919191,\n    Gray58 = 0x949494,\n    Grey58 = 0x949494,\n    Gray59 = 0x969696,\n    Grey59 = 0x969696,\n    Gray60 = 0x999999,\n    Grey60 = 0x999999,\n    Gray61 = 0x9c9c9c,\n    Grey61 = 0x9c9c9c,\n    Gray62 = 0x9e9e9e,\n    Grey62 = 0x9e9e9e,\n    Gray63 = 0xa1a1a1,\n    Grey63 = 0xa1a1a1,\n    Gray64 = 0xa3a3a3,\n    Grey64 = 0xa3a3a3,\n    Gray65 = 0xa6a6a6,\n    Grey65 = 0xa6a6a6,\n    Gray66 = 0xa8a8a8,\n    Grey66 = 0xa8a8a8,\n    Gray67 = 0xababab,\n    Grey67 = 0xababab,\n    Gray68 = 0xadadad,\n    Grey68 = 0xadadad,\n    Gray69 = 0xb0b0b0,\n    Grey69 = 0xb0b0b0,\n    Gray70 = 0xb3b3b3,\n    Grey70 = 0xb3b3b3,\n    Gray71 = 0xb5b5b5,\n    Grey71 = 0xb5b5b5,\n    Gray72 = 0xb8b8b8,\n    Grey72 = 0xb8b8b8,\n    Gray73 = 0xbababa,\n    Grey73 = 0xbababa,\n    Gray74 = 0xbdbdbd,\n    Grey74 = 0xbdbdbd,\n    Gray75 = 0xbfbfbf,\n    Grey75 = 0xbfbfbf,\n    Gray76 = 0xc2c2c2,\n    Grey76 = 0xc2c2c2,\n    Gray77 = 0xc4c4c4,\n    Grey77 = 0xc4c4c4,\n    Gray78 = 0xc7c7c7,\n    Grey78 = 0xc7c7c7,\n    Gray79 = 0xc9c9c9,\n    Grey79 = 0xc9c9c9,\n    Gray80 = 0xcccccc,\n    Grey80 = 0xcccccc,\n    Gray81 = 0xcfcfcf,\n    Grey81 = 0xcfcfcf,\n    Gray82 = 0xd1d1d1,\n    Grey82 = 0xd1d1d1,\n    Gray83 = 0xd4d4d4,\n    Grey83 = 0xd4d4d4,\n    Gray84 = 0xd6d6d6,\n    Grey84 = 0xd6d6d6,\n    Gray85 = 0xd9d9d9,\n    Grey85 = 0xd9d9d9,\n    Gray86 = 0xdbdbdb,\n    Grey86 = 0xdbdbdb,\n    Gray87 = 0xdedede,\n    Grey87 = 0xdedede,\n    Gray88 = 0xe0e0e0,\n    Grey88 = 0xe0e0e0,\n    Gray89 = 0xe3e3e3,\n    Grey89 = 0xe3e3e3,\n    Gray90 = 0xe5e5e5,\n    Grey90 = 0xe5e5e5,\n    Gray91 = 0xe8e8e8,\n    Grey91 = 0xe8e8e8,\n    Gray92 = 0xebebeb,\n    Grey92 = 0xebebeb,\n    Gray93 = 0xededed,\n    Grey93 = 0xededed,\n    Gray94 = 0xf0f0f0,\n    Grey94 = 0xf0f0f0,\n    Gray95 = 0xf2f2f2,\n    Grey95 = 0xf2f2f2,\n    Gray96 = 0xf5f5f5,\n    Grey96 = 0xf5f5f5,\n    Gray97 = 0xf7f7f7,\n    Grey97 = 0xf7f7f7,\n    Gray98 = 0xfafafa,\n    Grey98 = 0xfafafa,\n    Gray99 = 0xfcfcfc,\n    Grey99 = 0xfcfcfc,\n    Gray100 = 0xffffff,\n    Grey100 = 0xffffff,\n    DarkGrey = 0xa9a9a9,\n    DarkGray = 0xa9a9a9,\n    DarkBlue = 0x00008b,\n    DarkCyan = 0x008b8b,\n    DarkMagenta = 0x8b008b,\n    DarkRed = 0x8b0000,\n    LightGreen = 0x90ee90,\n    Crimson = 0xdc143c,\n    Indigo = 0x4b0082,\n    Olive = 0x808000,\n    RebeccaPurple = 0x663399,\n    Silver = 0xc0c0c0,\n    Teal = 0x008080,\n};\n};\n}\n\n#endif\n"
  },
  {
    "path": "tracy-client-sys/tracy/common/TracyForceInline.hpp",
    "content": "#ifndef __TRACYFORCEINLINE_HPP__\n#define __TRACYFORCEINLINE_HPP__\n\n#if defined(__GNUC__)\n#  define tracy_force_inline __attribute__((always_inline)) inline\n#elif defined(_MSC_VER)\n#  define tracy_force_inline __forceinline\n#else\n#  define tracy_force_inline inline\n#endif\n\n#if defined(__GNUC__)\n#  define tracy_no_inline __attribute__((noinline))\n#elif defined(_MSC_VER)\n#  define tracy_no_inline __declspec(noinline)\n#else\n#  define tracy_no_inline\n#endif\n\n#endif\n"
  },
  {
    "path": "tracy-client-sys/tracy/common/TracyMutex.hpp",
    "content": "#ifndef __TRACYMUTEX_HPP__\n#define __TRACYMUTEX_HPP__\n\n#if defined _MSC_VER\n\n#  include <shared_mutex>\n\nnamespace tracy\n{\nusing TracyMutex = std::shared_mutex;\n}\n\n#else\n\n#include <mutex>\n\nnamespace tracy\n{\nusing TracyMutex = std::mutex;\n}\n\n#endif\n\n#endif\n"
  },
  {
    "path": "tracy-client-sys/tracy/common/TracyProtocol.hpp",
    "content": "#ifndef __TRACYPROTOCOL_HPP__\n#define __TRACYPROTOCOL_HPP__\n\n#include <limits>\n#include <stdint.h>\n\nnamespace tracy\n{\n\nconstexpr unsigned Lz4CompressBound( unsigned isize ) { return isize + ( isize / 255 ) + 16; }\n\nenum : uint32_t { ProtocolVersion = 76 };\nenum : uint16_t { BroadcastVersion = 3 };\n\nusing lz4sz_t = uint32_t;\n\nenum { TargetFrameSize = 256 * 1024 };\nenum { LZ4Size = Lz4CompressBound( TargetFrameSize ) };\nstatic_assert( LZ4Size <= (std::numeric_limits<lz4sz_t>::max)(), \"LZ4Size greater than lz4sz_t\" );\nstatic_assert( TargetFrameSize * 2 >= 64 * 1024, \"Not enough space for LZ4 stream buffer\" );\n\nenum { HandshakeShibbolethSize = 8 };\nstatic const char HandshakeShibboleth[HandshakeShibbolethSize] = { 'T', 'r', 'a', 'c', 'y', 'P', 'r', 'f' };\n\nenum HandshakeStatus : uint8_t\n{\n    HandshakePending,\n    HandshakeWelcome,\n    HandshakeProtocolMismatch,\n    HandshakeNotAvailable,\n    HandshakeDropped\n};\n\nenum { WelcomeMessageProgramNameSize = 64 };\nenum { WelcomeMessageHostInfoSize = 1024 };\n\n#pragma pack( push, 1 )\n\n// Must increase left query space after handling!\nenum ServerQuery : uint8_t\n{\n    ServerQueryTerminate,\n    ServerQueryString,\n    ServerQueryThreadString,\n    ServerQuerySourceLocation,\n    ServerQueryPlotName,\n    ServerQueryFrameName,\n    ServerQueryParameter,\n    ServerQueryFiberName,\n    ServerQueryExternalName,\n    // Items above are high priority. Split order must be preserved. See IsQueryPrio().\n    ServerQueryDisconnect,\n    ServerQueryCallstackFrame,\n    ServerQuerySymbol,\n    ServerQuerySymbolCode,\n    ServerQuerySourceCode,\n    ServerQueryDataTransfer,\n    ServerQueryDataTransferPart\n};\n\nstruct ServerQueryPacket\n{\n    ServerQuery type;\n    uint64_t ptr;\n    uint32_t extra;\n};\n\nenum { ServerQueryPacketSize = sizeof( ServerQueryPacket ) };\n\n\nenum CpuArchitecture : uint8_t\n{\n    CpuArchUnknown,\n    CpuArchX86,\n    CpuArchX64,\n    CpuArchArm32,\n    CpuArchArm64\n};\n\n\nstruct WelcomeFlag\n{\n    enum _t : uint8_t\n    {\n        OnDemand        = 1 << 0,\n        IgnoreMemFaults = 1 << 1,\n        CodeTransfer    = 1 << 2,\n        CombineSamples  = 1 << 3,\n        IdentifySamples = 1 << 4,\n    };\n};\n\nstruct WelcomeMessage\n{\n    double timerMul;\n    int64_t initBegin;\n    int64_t initEnd;\n    uint64_t resolution;\n    uint64_t epoch;\n    uint64_t exectime;\n    uint64_t pid;\n    int64_t samplingPeriod;\n    uint8_t flags;\n    uint8_t cpuArch;\n    char cpuManufacturer[12];\n    uint32_t cpuId;\n    char programName[WelcomeMessageProgramNameSize];\n    char hostInfo[WelcomeMessageHostInfoSize];\n};\n\nenum { WelcomeMessageSize = sizeof( WelcomeMessage ) };\n\n\nstruct OnDemandPayloadMessage\n{\n    uint64_t frames;\n    uint64_t currentTime;\n};\n\nenum { OnDemandPayloadMessageSize = sizeof( OnDemandPayloadMessage ) };\n\n\nstruct BroadcastMessage\n{\n    uint16_t broadcastVersion;\n    uint16_t listenPort;\n    uint32_t protocolVersion;\n    uint64_t pid;\n    int32_t activeTime;        // in seconds\n    char programName[WelcomeMessageProgramNameSize];\n};\n\nstruct BroadcastMessage_v2\n{\n    uint16_t broadcastVersion;\n    uint16_t listenPort;\n    uint32_t protocolVersion;\n    int32_t activeTime;\n    char programName[WelcomeMessageProgramNameSize];\n};\n\nstruct BroadcastMessage_v1\n{\n    uint32_t broadcastVersion;\n    uint32_t protocolVersion;\n    uint32_t listenPort;\n    uint32_t activeTime;\n    char programName[WelcomeMessageProgramNameSize];\n};\n\nstruct BroadcastMessage_v0\n{\n    uint32_t broadcastVersion;\n    uint32_t protocolVersion;\n    uint32_t activeTime;\n    char programName[WelcomeMessageProgramNameSize];\n};\n\nenum { BroadcastMessageSize = sizeof( BroadcastMessage ) };\nenum { BroadcastMessageSize_v2 = sizeof( BroadcastMessage_v2 ) };\nenum { BroadcastMessageSize_v1 = sizeof( BroadcastMessage_v1 ) };\nenum { BroadcastMessageSize_v0 = sizeof( BroadcastMessage_v0 ) };\n\n#pragma pack( pop )\n\n}\n\n#endif\n"
  },
  {
    "path": "tracy-client-sys/tracy/common/TracyQueue.hpp",
    "content": "#ifndef __TRACYQUEUE_HPP__\n#define __TRACYQUEUE_HPP__\n\n#include <stddef.h>\n#include <stdint.h>\n\nnamespace tracy\n{\n\nenum class QueueType : uint8_t\n{\n    ZoneText,\n    ZoneName,\n    Message,\n    MessageColor,\n    MessageCallstack,\n    MessageColorCallstack,\n    MessageAppInfo,\n    ZoneBeginAllocSrcLoc,\n    ZoneBeginAllocSrcLocCallstack,\n    CallstackSerial,\n    Callstack,\n    CallstackAlloc,\n    CallstackSample,\n    CallstackSampleContextSwitch,\n    FrameImage,\n    ZoneBegin,\n    ZoneBeginCallstack,\n    ZoneEnd,\n    LockWait,\n    LockObtain,\n    LockRelease,\n    LockSharedWait,\n    LockSharedObtain,\n    LockSharedRelease,\n    LockName,\n    MemAlloc,\n    MemAllocNamed,\n    MemFree,\n    MemFreeNamed,\n    MemAllocCallstack,\n    MemAllocCallstackNamed,\n    MemFreeCallstack,\n    MemFreeCallstackNamed,\n    MemDiscard,\n    MemDiscardCallstack,\n    GpuZoneBegin,\n    GpuZoneBeginCallstack,\n    GpuZoneBeginAllocSrcLoc,\n    GpuZoneBeginAllocSrcLocCallstack,\n    GpuZoneEnd,\n    GpuZoneBeginSerial,\n    GpuZoneBeginCallstackSerial,\n    GpuZoneBeginAllocSrcLocSerial,\n    GpuZoneBeginAllocSrcLocCallstackSerial,\n    GpuZoneEndSerial,\n    PlotDataInt,\n    PlotDataFloat,\n    PlotDataDouble,\n    ContextSwitch,\n    ThreadWakeup,\n    GpuTime,\n    GpuContextName,\n    GpuAnnotationName,\n    CallstackFrameSize,\n    SymbolInformation,\n    ExternalNameMetadata,\n    SymbolCodeMetadata,\n    SourceCodeMetadata,\n    FiberEnter,\n    FiberLeave,\n    Terminate,\n    KeepAlive,\n    ThreadContext,\n    GpuCalibration,\n    GpuTimeSync,\n    Crash,\n    CrashReport,\n    ZoneValidation,\n    ZoneColor,\n    ZoneValue,\n    FrameMarkMsg,\n    FrameMarkMsgStart,\n    FrameMarkMsgEnd,\n    FrameVsync,\n    SourceLocation,\n    LockAnnounce,\n    LockTerminate,\n    LockMark,\n    MessageLiteral,\n    MessageLiteralColor,\n    MessageLiteralCallstack,\n    MessageLiteralColorCallstack,\n    GpuNewContext,\n    CallstackFrame,\n    SysTimeReport,\n    SysPowerReport,\n    TidToPid,\n    HwSampleCpuCycle,\n    HwSampleInstructionRetired,\n    HwSampleCacheReference,\n    HwSampleCacheMiss,\n    HwSampleBranchRetired,\n    HwSampleBranchMiss,\n    PlotConfig,\n    ParamSetup,\n    AckServerQueryNoop,\n    AckSourceCodeNotAvailable,\n    AckSymbolCodeNotAvailable,\n    CpuTopology,\n    SingleStringData,\n    SecondStringData,\n    MemNamePayload,\n    ThreadGroupHint,\n    GpuZoneAnnotation,\n    StringData,\n    ThreadName,\n    PlotName,\n    SourceLocationPayload,\n    CallstackPayload,\n    CallstackAllocPayload,\n    FrameName,\n    FrameImageData,\n    ExternalName,\n    ExternalThreadName,\n    SymbolCode,\n    SourceCode,\n    FiberName,\n    NUM_TYPES\n};\n\n#pragma pack( push, 1 )\n\nstruct QueueThreadContext\n{\n    uint32_t thread;\n};\n\nstruct QueueZoneBeginLean\n{\n    int64_t time;\n};\n\nstruct QueueZoneBegin : public QueueZoneBeginLean\n{\n    uint64_t srcloc;    // ptr\n};\n\nstruct QueueZoneBeginThread : public QueueZoneBegin\n{\n    uint32_t thread;\n};\n\nstruct QueueZoneEnd\n{\n    int64_t time;\n};\n\nstruct QueueZoneEndThread : public QueueZoneEnd\n{\n    uint32_t thread;\n};\n\nstruct QueueZoneValidation\n{\n    uint32_t id;\n};\n\nstruct QueueZoneValidationThread : public QueueZoneValidation\n{\n    uint32_t thread;\n};\n\nstruct QueueZoneColor\n{\n    uint8_t b;\n    uint8_t g;\n    uint8_t r;\n};\n\nstruct QueueZoneColorThread : public QueueZoneColor\n{\n    uint32_t thread;\n};\n\nstruct QueueZoneValue\n{\n    uint64_t value;\n};\n\nstruct QueueZoneValueThread : public QueueZoneValue\n{\n    uint32_t thread;\n};\n\nstruct QueueStringTransfer\n{\n    uint64_t ptr;\n};\n\nstruct QueueFrameMark\n{\n    int64_t time;\n    uint64_t name;      // ptr\n};\n\nstruct QueueFrameVsync\n{\n    int64_t time;\n    uint32_t id;\n};\n\nstruct QueueFrameImage\n{\n    uint32_t frame;\n    uint16_t w;\n    uint16_t h;\n    uint8_t flip;\n};\n\nstruct QueueFrameImageFat : public QueueFrameImage\n{\n    uint64_t image;     // ptr\n};\n\nstruct QueueSourceLocation\n{\n    uint64_t name;\n    uint64_t function;  // ptr\n    uint64_t file;      // ptr\n    uint32_t line;\n    uint8_t b;\n    uint8_t g;\n    uint8_t r;\n};\n\nstruct QueueZoneTextFat\n{\n    uint64_t text;      // ptr\n    uint16_t size;\n};\n\nstruct QueueZoneTextFatThread : public QueueZoneTextFat\n{\n    uint32_t thread;\n};\n\nenum class LockType : uint8_t\n{\n    Lockable,\n    SharedLockable\n};\n\nstruct QueueLockAnnounce\n{\n    uint32_t id;\n    int64_t time;\n    uint64_t lckloc;    // ptr\n    LockType type;\n};\n\nstruct QueueFiberEnter\n{\n    int64_t time;\n    uint64_t fiber;     // ptr\n    uint32_t thread;\n    int32_t groupHint;\n};\n\nstruct QueueFiberLeave\n{\n    int64_t time;\n    uint32_t thread;\n};\n\nstruct QueueLockTerminate\n{\n    uint32_t id;\n    int64_t time;\n};\n\nstruct QueueLockWait\n{\n    uint32_t thread;\n    uint32_t id;\n    int64_t time;\n};\n\nstruct QueueLockObtain\n{\n    uint32_t thread;\n    uint32_t id;\n    int64_t time;\n};\n\nstruct QueueLockRelease\n{\n    uint32_t id;\n    int64_t time;\n};\n\nstruct QueueLockReleaseShared : public QueueLockRelease\n{\n    uint32_t thread;\n};\n\nstruct QueueLockMark\n{\n    uint32_t thread;\n    uint32_t id;\n    uint64_t srcloc;    // ptr\n};\n\nstruct QueueLockName\n{\n    uint32_t id;\n};\n\nstruct QueueLockNameFat : public QueueLockName\n{\n    uint64_t name;      // ptr\n    uint16_t size;\n};\n\nstruct QueuePlotDataBase\n{\n    uint64_t name;      // ptr\n    int64_t time;\n};\n\nstruct QueuePlotDataInt : public QueuePlotDataBase\n{\n    int64_t val;\n};\n\nstruct QueuePlotDataFloat : public QueuePlotDataBase\n{\n    float val;\n};\n\nstruct QueuePlotDataDouble : public QueuePlotDataBase\n{\n    double val;\n};\n\nstruct QueueMessage\n{\n    int64_t time;\n};\n\nstruct QueueMessageColor : public QueueMessage\n{\n    uint8_t b;\n    uint8_t g;\n    uint8_t r;\n};\n\nstruct QueueMessageLiteral : public QueueMessage\n{\n    uint64_t text;      // ptr\n};\n\nstruct QueueMessageLiteralThread : public QueueMessageLiteral\n{\n    uint32_t thread;\n};\n\nstruct QueueMessageColorLiteral : public QueueMessageColor\n{\n    uint64_t text;      // ptr\n};\n\nstruct QueueMessageColorLiteralThread : public QueueMessageColorLiteral\n{\n    uint32_t thread;\n};\n\nstruct QueueMessageFat : public QueueMessage\n{\n    uint64_t text;      // ptr\n    uint16_t size;\n};\n\nstruct QueueMessageFatThread : public QueueMessageFat\n{\n    uint32_t thread;\n};\n\nstruct QueueMessageColorFat : public QueueMessageColor\n{\n    uint64_t text;      // ptr\n    uint16_t size;\n};\n\nstruct QueueMessageColorFatThread : public QueueMessageColorFat\n{\n    uint32_t thread;\n};\n\n// Don't change order, only add new entries at the end, this is also used on trace dumps!\nenum class GpuContextType : uint8_t\n{\n    Invalid,\n    OpenGl,\n    Vulkan,\n    OpenCL,\n    Direct3D12,\n    Direct3D11,\n    Metal,\n    Custom,\n    CUDA,\n    Rocprof\n};\n\nenum GpuContextFlags : uint8_t\n{\n    GpuContextCalibration   = 1 << 0\n};\n\nstruct QueueGpuNewContext\n{\n    int64_t cpuTime;\n    int64_t gpuTime;\n    uint32_t thread;\n    float period;\n    uint8_t context;\n    GpuContextFlags flags;\n    GpuContextType type;\n};\n\nstruct QueueGpuZoneBeginLean\n{\n    int64_t cpuTime;\n    uint32_t thread;\n    uint16_t queryId;\n    uint8_t context;\n};\n\nstruct QueueGpuZoneBegin : public QueueGpuZoneBeginLean\n{\n    uint64_t srcloc;\n};\n\nstruct QueueGpuZoneEnd\n{\n    int64_t cpuTime;\n    uint32_t thread;\n    uint16_t queryId;\n    uint8_t context;\n};\n\nstruct QueueGpuZoneAnnotation\n{\n    int64_t noteId;\n    double value;\n    uint32_t thread;\n    uint16_t queryId;\n    uint8_t context;\n};\n\nstruct QueueGpuTime\n{\n    int64_t gpuTime;\n    uint16_t queryId;\n    uint8_t context;\n};\n\nstruct QueueGpuCalibration\n{\n    int64_t gpuTime;\n    int64_t cpuTime;\n    int64_t cpuDelta;\n    uint8_t context;\n};\n\nstruct QueueGpuTimeSync\n{\n    int64_t gpuTime;\n    int64_t cpuTime;\n    uint8_t context;\n};\n\nstruct QueueGpuContextName\n{\n    uint8_t context;\n};\n\nstruct QueueGpuContextNameFat : public QueueGpuContextName\n{\n    uint64_t ptr;\n    uint16_t size;\n};\n\nstruct QueueGpuAnnotationName\n{\n    int64_t noteId;\n    uint8_t context;\n};\n\nstruct QueueGpuAnnotationNameFat : public QueueGpuAnnotationName\n{\n    uint64_t ptr;\n    uint16_t size;\n};\n\nstruct QueueMemNamePayload\n{\n    uint64_t name;\n};\n\nstruct QueueThreadGroupHint\n{\n    uint32_t thread;\n    int32_t groupHint;\n};\n\nstruct QueueMemAlloc\n{\n    int64_t time;\n    uint32_t thread;\n    uint64_t ptr;\n    char size[6];\n};\n\nstruct QueueMemFree\n{\n    int64_t time;\n    uint32_t thread;\n    uint64_t ptr;\n};\n\nstruct QueueMemDiscard\n{\n    int64_t time;\n    uint32_t thread;\n    uint64_t name;\n};\n\nstruct QueueCallstackFat\n{\n    uint64_t ptr;\n};\n\nstruct QueueCallstackFatThread : public QueueCallstackFat\n{\n    uint32_t thread;\n};\n\nstruct QueueCallstackAllocFat\n{\n    uint64_t ptr;\n    uint64_t nativePtr;\n};\n\nstruct QueueCallstackAllocFatThread : public QueueCallstackAllocFat\n{\n    uint32_t thread;\n};\n\nstruct QueueCallstackSample\n{\n    int64_t time;\n    uint32_t thread;\n};\n\nstruct QueueCallstackSampleFat : public QueueCallstackSample\n{\n    uint64_t ptr;\n};\n\nstruct QueueCallstackFrameSize\n{\n    uint64_t ptr;\n    uint8_t size;\n};\n\nstruct QueueCallstackFrameSizeFat : public QueueCallstackFrameSize\n{\n    uint64_t data;\n    uint64_t imageName;\n};\n\nstruct QueueCallstackFrame\n{\n    uint32_t line;\n    uint64_t symAddr;\n    uint32_t symLen;\n};\n\nstruct QueueSymbolInformation\n{\n    uint32_t line;\n    uint64_t symAddr;\n};\n\nstruct QueueSymbolInformationFat : public QueueSymbolInformation\n{\n    uint64_t fileString;\n    uint8_t needFree;\n};\n\nstruct QueueCrashReport\n{\n    int64_t time;\n    uint64_t text;      // ptr\n};\n\nstruct QueueCrashReportThread\n{\n    uint32_t thread;\n};\n\nstruct QueueSysTime\n{\n    int64_t time;\n    float sysTime;\n};\n\nstruct QueueSysPower\n{\n    int64_t time;\n    uint64_t delta;\n    uint64_t name;  // ptr\n};\n\nstruct QueueContextSwitch\n{\n    int64_t time;\n    uint32_t oldThread;\n    uint32_t newThread;\n    uint8_t cpu;\n    uint8_t oldThreadWaitReason;\n    uint8_t oldThreadState;\n    uint8_t previousCState;\n    int8_t newThreadPriority;\n    int8_t oldThreadPriority;\n};\n\nstruct QueueThreadWakeup\n{\n    int64_t time;\n    uint32_t thread;\n    uint8_t cpu;\n    int8_t adjustReason;\n    int8_t adjustIncrement;\n};\n\nstruct QueueTidToPid\n{\n    uint64_t tid;\n    uint64_t pid;\n};\n\nstruct QueueHwSample\n{\n    uint64_t ip;\n    int64_t time;\n};\n\nenum class PlotFormatType : uint8_t\n{\n    Number,\n    Memory,\n    Percentage\n};\n\nstruct QueuePlotConfig\n{\n    uint64_t name;      // ptr\n    uint8_t type;\n    uint8_t step;\n    uint8_t fill;\n    uint32_t color;\n};\n\nstruct QueueParamSetup\n{\n    uint32_t idx;\n    uint64_t name;      // ptr\n    uint8_t isBool;\n    int32_t val;\n};\n\nstruct QueueSourceCodeNotAvailable\n{\n    uint32_t id;\n};\n\nstruct QueueCpuTopology\n{\n    uint32_t package;\n    uint32_t die;\n    uint32_t core;\n    uint32_t thread;\n};\n\nstruct QueueExternalNameMetadata\n{\n    uint64_t thread;\n    uint64_t name;\n    uint64_t threadName;\n};\n\nstruct QueueSymbolCodeMetadata\n{\n    uint64_t symbol;\n    uint64_t ptr;\n    uint32_t size;\n};\n\nstruct QueueSourceCodeMetadata\n{\n    uint64_t ptr;\n    uint32_t size;\n    uint32_t id;\n};\n\nstruct QueueHeader\n{\n    union\n    {\n        QueueType type;\n        uint8_t idx;\n    };\n};\n\nstruct QueueItem\n{\n    QueueHeader hdr;\n    union\n    {\n        QueueThreadContext threadCtx;\n        QueueZoneBegin zoneBegin;\n        QueueZoneBeginLean zoneBeginLean;\n        QueueZoneBeginThread zoneBeginThread;\n        QueueZoneEnd zoneEnd;\n        QueueZoneEndThread zoneEndThread;\n        QueueZoneValidation zoneValidation;\n        QueueZoneValidationThread zoneValidationThread;\n        QueueZoneColor zoneColor;\n        QueueZoneColorThread zoneColorThread;\n        QueueZoneValue zoneValue;\n        QueueZoneValueThread zoneValueThread;\n        QueueStringTransfer stringTransfer;\n        QueueFrameMark frameMark;\n        QueueFrameVsync frameVsync;\n        QueueFrameImage frameImage;\n        QueueFrameImageFat frameImageFat;\n        QueueSourceLocation srcloc;\n        QueueZoneTextFat zoneTextFat;\n        QueueZoneTextFatThread zoneTextFatThread;\n        QueueLockAnnounce lockAnnounce;\n        QueueLockTerminate lockTerminate;\n        QueueLockWait lockWait;\n        QueueLockObtain lockObtain;\n        QueueLockRelease lockRelease;\n        QueueLockReleaseShared lockReleaseShared;\n        QueueLockMark lockMark;\n        QueueLockName lockName;\n        QueueLockNameFat lockNameFat;\n        QueuePlotDataInt plotDataInt;\n        QueuePlotDataFloat plotDataFloat;\n        QueuePlotDataDouble plotDataDouble;\n        QueueMessage message;\n        QueueMessageColor messageColor;\n        QueueMessageLiteral messageLiteral;\n        QueueMessageLiteralThread messageLiteralThread;\n        QueueMessageColorLiteral messageColorLiteral;\n        QueueMessageColorLiteralThread messageColorLiteralThread;\n        QueueMessageFat messageFat;\n        QueueMessageFatThread messageFatThread;\n        QueueMessageColorFat messageColorFat;\n        QueueMessageColorFatThread messageColorFatThread;\n        QueueGpuNewContext gpuNewContext;\n        QueueGpuZoneBegin gpuZoneBegin;\n        QueueGpuZoneBeginLean gpuZoneBeginLean;\n        QueueGpuZoneEnd gpuZoneEnd;\n        QueueGpuTime gpuTime;\n        QueueGpuCalibration gpuCalibration;\n        QueueGpuTimeSync gpuTimeSync;\n        QueueGpuContextName gpuContextName;\n        QueueGpuContextNameFat gpuContextNameFat;\n        QueueGpuAnnotationName gpuAnnotationName;\n        QueueGpuAnnotationNameFat gpuAnnotationNameFat;\n        QueueMemAlloc memAlloc;\n        QueueMemFree memFree;\n        QueueMemDiscard memDiscard;\n        QueueMemNamePayload memName;\n        QueueThreadGroupHint threadGroupHint;\n        QueueCallstackFat callstackFat;\n        QueueCallstackFatThread callstackFatThread;\n        QueueCallstackAllocFat callstackAllocFat;\n        QueueCallstackAllocFatThread callstackAllocFatThread;\n        QueueCallstackSample callstackSample;\n        QueueCallstackSampleFat callstackSampleFat;\n        QueueCallstackFrameSize callstackFrameSize;\n        QueueCallstackFrameSizeFat callstackFrameSizeFat;\n        QueueCallstackFrame callstackFrame;\n        QueueSymbolInformation symbolInformation;\n        QueueSymbolInformationFat symbolInformationFat;\n        QueueCrashReport crashReport;\n        QueueCrashReportThread crashReportThread;\n        QueueSysTime sysTime;\n        QueueSysPower sysPower;\n        QueueContextSwitch contextSwitch;\n        QueueThreadWakeup threadWakeup;\n        QueueTidToPid tidToPid;\n        QueueHwSample hwSample;\n        QueuePlotConfig plotConfig;\n        QueueParamSetup paramSetup;\n        QueueCpuTopology cpuTopology;\n        QueueExternalNameMetadata externalNameMetadata;\n        QueueSymbolCodeMetadata symbolCodeMetadata;\n        QueueSourceCodeMetadata sourceCodeMetadata;\n        QueueSourceCodeNotAvailable sourceCodeNotAvailable;\n        QueueFiberEnter fiberEnter;\n        QueueFiberLeave fiberLeave;\n        QueueGpuZoneAnnotation zoneAnnotation;\n    };\n};\n#pragma pack( pop )\n\n\nenum { QueueItemSize = sizeof( QueueItem ) };\n\nstatic constexpr size_t QueueDataSize[] = {\n    sizeof( QueueHeader ),                                  // zone text\n    sizeof( QueueHeader ),                                  // zone name\n    sizeof( QueueHeader ) + sizeof( QueueMessage ),\n    sizeof( QueueHeader ) + sizeof( QueueMessageColor ),\n    sizeof( QueueHeader ) + sizeof( QueueMessage ),         // callstack\n    sizeof( QueueHeader ) + sizeof( QueueMessageColor ),    // callstack\n    sizeof( QueueHeader ) + sizeof( QueueMessage ),         // app info\n    sizeof( QueueHeader ) + sizeof( QueueZoneBeginLean ),   // allocated source location\n    sizeof( QueueHeader ) + sizeof( QueueZoneBeginLean ),   // allocated source location, callstack\n    sizeof( QueueHeader ),                                  // callstack memory\n    sizeof( QueueHeader ),                                  // callstack\n    sizeof( QueueHeader ),                                  // callstack alloc\n    sizeof( QueueHeader ) + sizeof( QueueCallstackSample ),\n    sizeof( QueueHeader ) + sizeof( QueueCallstackSample ), // context switch\n    sizeof( QueueHeader ) + sizeof( QueueFrameImage ),\n    sizeof( QueueHeader ) + sizeof( QueueZoneBegin ),\n    sizeof( QueueHeader ) + sizeof( QueueZoneBegin ),       // callstack\n    sizeof( QueueHeader ) + sizeof( QueueZoneEnd ),\n    sizeof( QueueHeader ) + sizeof( QueueLockWait ),\n    sizeof( QueueHeader ) + sizeof( QueueLockObtain ),\n    sizeof( QueueHeader ) + sizeof( QueueLockRelease ),\n    sizeof( QueueHeader ) + sizeof( QueueLockWait ),        // shared\n    sizeof( QueueHeader ) + sizeof( QueueLockObtain ),      // shared\n    sizeof( QueueHeader ) + sizeof( QueueLockReleaseShared ),\n    sizeof( QueueHeader ) + sizeof( QueueLockName ),\n    sizeof( QueueHeader ) + sizeof( QueueMemAlloc ),\n    sizeof( QueueHeader ) + sizeof( QueueMemAlloc ),        // named\n    sizeof( QueueHeader ) + sizeof( QueueMemFree ),\n    sizeof( QueueHeader ) + sizeof( QueueMemFree ),         // named\n    sizeof( QueueHeader ) + sizeof( QueueMemAlloc ),        // callstack\n    sizeof( QueueHeader ) + sizeof( QueueMemAlloc ),        // callstack, named\n    sizeof( QueueHeader ) + sizeof( QueueMemFree ),         // callstack\n    sizeof( QueueHeader ) + sizeof( QueueMemFree ),         // callstack, named\n    sizeof( QueueHeader ) + sizeof( QueueMemDiscard ),\n    sizeof( QueueHeader ) + sizeof( QueueMemDiscard ),      // callstack\n    sizeof( QueueHeader ) + sizeof( QueueGpuZoneBegin ),\n    sizeof( QueueHeader ) + sizeof( QueueGpuZoneBegin ),    // callstack\n    sizeof( QueueHeader ) + sizeof( QueueGpuZoneBeginLean ),// allocated source location\n    sizeof( QueueHeader ) + sizeof( QueueGpuZoneBeginLean ),// allocated source location, callstack\n    sizeof( QueueHeader ) + sizeof( QueueGpuZoneEnd ),\n    sizeof( QueueHeader ) + sizeof( QueueGpuZoneBegin ),    // serial\n    sizeof( QueueHeader ) + sizeof( QueueGpuZoneBegin ),    // serial, callstack\n    sizeof( QueueHeader ) + sizeof( QueueGpuZoneBeginLean ),// serial, allocated source location\n    sizeof( QueueHeader ) + sizeof( QueueGpuZoneBeginLean ),// serial, allocated source location, callstack\n    sizeof( QueueHeader ) + sizeof( QueueGpuZoneEnd ),      // serial\n    sizeof( QueueHeader ) + sizeof( QueuePlotDataInt ),\n    sizeof( QueueHeader ) + sizeof( QueuePlotDataFloat ),\n    sizeof( QueueHeader ) + sizeof( QueuePlotDataDouble ),\n    sizeof( QueueHeader ) + sizeof( QueueContextSwitch ),\n    sizeof( QueueHeader ) + sizeof( QueueThreadWakeup ),\n    sizeof( QueueHeader ) + sizeof( QueueGpuTime ),\n    sizeof( QueueHeader ) + sizeof( QueueGpuContextName ),\n    sizeof( QueueHeader ) + sizeof( QueueGpuAnnotationName ),\n    sizeof( QueueHeader ) + sizeof( QueueCallstackFrameSize ),\n    sizeof( QueueHeader ) + sizeof( QueueSymbolInformation ),\n    sizeof( QueueHeader ),                                  // ExternalNameMetadata - not for wire transfer\n    sizeof( QueueHeader ),                                  // SymbolCodeMetadata - not for wire transfer\n    sizeof( QueueHeader ),                                  // SourceCodeMetadata - not for wire transfer\n    sizeof( QueueHeader ) + sizeof( QueueFiberEnter ),\n    sizeof( QueueHeader ) + sizeof( QueueFiberLeave ),\n    // above items must be first\n    sizeof( QueueHeader ),                                  // terminate\n    sizeof( QueueHeader ),                                  // keep alive\n    sizeof( QueueHeader ) + sizeof( QueueThreadContext ),\n    sizeof( QueueHeader ) + sizeof( QueueGpuCalibration ),\n    sizeof( QueueHeader ) + sizeof( QueueGpuTimeSync ),\n    sizeof( QueueHeader ),                                  // crash\n    sizeof( QueueHeader ) + sizeof( QueueCrashReport ),\n    sizeof( QueueHeader ) + sizeof( QueueZoneValidation ),\n    sizeof( QueueHeader ) + sizeof( QueueZoneColor ),\n    sizeof( QueueHeader ) + sizeof( QueueZoneValue ),\n    sizeof( QueueHeader ) + sizeof( QueueFrameMark ),       // continuous frames\n    sizeof( QueueHeader ) + sizeof( QueueFrameMark ),       // start\n    sizeof( QueueHeader ) + sizeof( QueueFrameMark ),       // end\n    sizeof( QueueHeader ) + sizeof( QueueFrameVsync ),\n    sizeof( QueueHeader ) + sizeof( QueueSourceLocation ),\n    sizeof( QueueHeader ) + sizeof( QueueLockAnnounce ),\n    sizeof( QueueHeader ) + sizeof( QueueLockTerminate ),\n    sizeof( QueueHeader ) + sizeof( QueueLockMark ),\n    sizeof( QueueHeader ) + sizeof( QueueMessageLiteral ),\n    sizeof( QueueHeader ) + sizeof( QueueMessageColorLiteral ),\n    sizeof( QueueHeader ) + sizeof( QueueMessageLiteral ),  // callstack\n    sizeof( QueueHeader ) + sizeof( QueueMessageColorLiteral ), // callstack\n    sizeof( QueueHeader ) + sizeof( QueueGpuNewContext ),\n    sizeof( QueueHeader ) + sizeof( QueueCallstackFrame ),\n    sizeof( QueueHeader ) + sizeof( QueueSysTime ),\n    sizeof( QueueHeader ) + sizeof( QueueSysPower ),\n    sizeof( QueueHeader ) + sizeof( QueueTidToPid ),\n    sizeof( QueueHeader ) + sizeof( QueueHwSample ),        // cpu cycle\n    sizeof( QueueHeader ) + sizeof( QueueHwSample ),        // instruction retired\n    sizeof( QueueHeader ) + sizeof( QueueHwSample ),        // cache reference\n    sizeof( QueueHeader ) + sizeof( QueueHwSample ),        // cache miss\n    sizeof( QueueHeader ) + sizeof( QueueHwSample ),        // branch retired\n    sizeof( QueueHeader ) + sizeof( QueueHwSample ),        // branch miss\n    sizeof( QueueHeader ) + sizeof( QueuePlotConfig ),\n    sizeof( QueueHeader ) + sizeof( QueueParamSetup ),\n    sizeof( QueueHeader ),                                  // server query acknowledgement\n    sizeof( QueueHeader ) + sizeof( QueueSourceCodeNotAvailable ),\n    sizeof( QueueHeader ),                                  // symbol code not available\n    sizeof( QueueHeader ) + sizeof( QueueCpuTopology ),\n    sizeof( QueueHeader ),                                  // single string data\n    sizeof( QueueHeader ),                                  // second string data\n    sizeof( QueueHeader ) + sizeof( QueueMemNamePayload ),\n    sizeof( QueueHeader ) + sizeof( QueueThreadGroupHint ),\n    sizeof( QueueHeader ) + sizeof( QueueGpuZoneAnnotation ), // GPU zone annotation\n    // keep all QueueStringTransfer below\n    sizeof( QueueHeader ) + sizeof( QueueStringTransfer ),  // string data\n    sizeof( QueueHeader ) + sizeof( QueueStringTransfer ),  // thread name\n    sizeof( QueueHeader ) + sizeof( QueueStringTransfer ),  // plot name\n    sizeof( QueueHeader ) + sizeof( QueueStringTransfer ),  // allocated source location payload\n    sizeof( QueueHeader ) + sizeof( QueueStringTransfer ),  // callstack payload\n    sizeof( QueueHeader ) + sizeof( QueueStringTransfer ),  // callstack alloc payload\n    sizeof( QueueHeader ) + sizeof( QueueStringTransfer ),  // frame name\n    sizeof( QueueHeader ) + sizeof( QueueStringTransfer ),  // frame image data\n    sizeof( QueueHeader ) + sizeof( QueueStringTransfer ),  // external name\n    sizeof( QueueHeader ) + sizeof( QueueStringTransfer ),  // external thread name\n    sizeof( QueueHeader ) + sizeof( QueueStringTransfer ),  // symbol code\n    sizeof( QueueHeader ) + sizeof( QueueStringTransfer ),  // source code\n    sizeof( QueueHeader ) + sizeof( QueueStringTransfer ),  // fiber name\n};\n\nstatic_assert( QueueItemSize == 32, \"Queue item size not 32 bytes\" );\nstatic_assert( sizeof( QueueDataSize ) / sizeof( size_t ) == (uint8_t)QueueType::NUM_TYPES, \"QueueDataSize mismatch\" );\nstatic_assert( sizeof( void* ) <= sizeof( uint64_t ), \"Pointer size > 8 bytes\" );\nstatic_assert( sizeof( void* ) == sizeof( uintptr_t ), \"Pointer size != uintptr_t\" );\n\n}\n\n#endif\n"
  },
  {
    "path": "tracy-client-sys/tracy/common/TracySocket.cpp",
    "content": "#include <assert.h>\n#include <inttypes.h>\n#include <new>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <sys/types.h>\n\n#include \"TracyAlloc.hpp\"\n#include \"TracySocket.hpp\"\n#include \"TracySystem.hpp\"\n\n#ifdef _WIN32\n#  ifndef NOMINMAX\n#    define NOMINMAX\n#  endif\n#  include <winsock2.h>\n#  include <ws2tcpip.h>\n#  ifdef _MSC_VER\n#    pragma warning(disable:4244)\n#    pragma warning(disable:4267)\n#  endif\n#  define poll WSAPoll\n#  ifdef _MSC_VER\n#    pragma comment(lib, \"ws2_32.lib\")\n#  endif\n#else\n#  include <arpa/inet.h>\n#  include <sys/socket.h>\n#  include <sys/param.h>\n#  include <errno.h>\n#  include <fcntl.h>\n#  include <netinet/in.h>\n#  include <netdb.h>\n#  include <unistd.h>\n#  include <poll.h>\n#endif\n\n#ifndef MSG_NOSIGNAL\n#  define MSG_NOSIGNAL 0\n#endif\n\nnamespace tracy\n{\n\n#ifdef _WIN32\ntypedef SOCKET socket_t;\n#else\ntypedef int socket_t;\n#endif\n\n#ifdef _WIN32\nstruct __wsinit\n{\n    __wsinit()\n    {\n        WSADATA wsaData;\n        if( WSAStartup( MAKEWORD( 2, 2 ), &wsaData ) != 0 )\n        {\n            fprintf( stderr, \"Cannot init winsock.\\n\" );\n            exit( 1 );\n        }\n    }\n};\n\nvoid InitWinSock()\n{\n    static __wsinit init;\n}\n#endif\n\n\nenum { BufSize = 128 * 1024 };\n\nSocket::Socket()\n    : m_buf( (char*)tracy_malloc( BufSize ) )\n    , m_bufPtr( nullptr )\n    , m_sock( -1 )\n    , m_bufLeft( 0 )\n    , m_ptr( nullptr )\n{\n#ifdef _WIN32\n    InitWinSock();\n#endif\n}\n\nSocket::Socket( int sock )\n    : m_buf( (char*)tracy_malloc( BufSize ) )\n    , m_bufPtr( nullptr )\n    , m_sock( sock )\n    , m_bufLeft( 0 )\n    , m_ptr( nullptr )\n{\n}\n\nSocket::~Socket()\n{\n    tracy_free( m_buf );\n    if( m_sock.load( std::memory_order_relaxed ) != -1 )\n    {\n        Close();\n    }\n    if( m_ptr )\n    {\n        freeaddrinfo( m_res );\n#ifdef _WIN32\n        closesocket( m_connSock );\n#else\n        close( m_connSock );\n#endif\n    }\n}\n\nbool Socket::Connect( const char* addr, uint16_t port )\n{\n    assert( !IsValid() );\n\n    if( m_ptr )\n    {\n        const auto c = connect( m_connSock, m_ptr->ai_addr, m_ptr->ai_addrlen );\n        if( c == -1 )\n        {\n#if defined _WIN32\n            const auto err = WSAGetLastError();\n            if( err == WSAEALREADY || err == WSAEINPROGRESS ) return false;\n            if( err != WSAEISCONN )\n            {\n                freeaddrinfo( m_res );\n                closesocket( m_connSock );\n                m_ptr = nullptr;\n                return false;\n            }\n#else\n            const auto err = errno;\n            if( err == EALREADY || err == EINPROGRESS ) return false;\n            if( err != EISCONN )\n            {\n                freeaddrinfo( m_res );\n                close( m_connSock );\n                m_ptr = nullptr;\n                return false;\n            }\n#endif\n        }\n\n#if defined _WIN32\n        u_long nonblocking = 0;\n        ioctlsocket( m_connSock, FIONBIO, &nonblocking );\n#else\n        int flags = fcntl( m_connSock, F_GETFL, 0 );\n        fcntl( m_connSock, F_SETFL, flags & ~O_NONBLOCK );\n#endif\n        m_sock.store( m_connSock, std::memory_order_relaxed );\n        freeaddrinfo( m_res );\n        m_ptr = nullptr;\n        return true;\n    }\n\n    struct addrinfo hints;\n    struct addrinfo *res, *ptr;\n\n    memset( &hints, 0, sizeof( hints ) );\n    hints.ai_family = AF_UNSPEC;\n    hints.ai_socktype = SOCK_STREAM;\n\n    char portbuf[32];\n    sprintf( portbuf, \"%\" PRIu16, port );\n\n    if( getaddrinfo( addr, portbuf, &hints, &res ) != 0 ) return false;\n    int sock = 0;\n    for( ptr = res; ptr; ptr = ptr->ai_next )\n    {\n        if( ( sock = socket( ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol ) ) == -1 ) continue;\n#if defined __APPLE__\n        int val = 1;\n        setsockopt( sock, SOL_SOCKET, SO_NOSIGPIPE, &val, sizeof( val ) );\n#endif\n#if defined _WIN32\n        u_long nonblocking = 1;\n        ioctlsocket( sock, FIONBIO, &nonblocking );\n#else\n        int flags = fcntl( sock, F_GETFL, 0 );\n        fcntl( sock, F_SETFL, flags | O_NONBLOCK );\n#endif\n        if( connect( sock, ptr->ai_addr, ptr->ai_addrlen ) == 0 )\n        {\n            break;\n        }\n        else\n        {\n#if defined _WIN32\n            const auto err = WSAGetLastError();\n            if( err != WSAEWOULDBLOCK )\n            {\n                closesocket( sock );\n                continue;\n            }\n#else\n            if( errno != EINPROGRESS )\n            {\n                close( sock );\n                continue;\n            }\n#endif\n        }\n        m_res = res;\n        m_ptr = ptr;\n        m_connSock = sock;\n        return false;\n    }\n    freeaddrinfo( res );\n    if( !ptr ) return false;\n\n#if defined _WIN32\n    u_long nonblocking = 0;\n    ioctlsocket( sock, FIONBIO, &nonblocking );\n#else\n    int flags = fcntl( sock, F_GETFL, 0 );\n    fcntl( sock, F_SETFL, flags & ~O_NONBLOCK );\n#endif\n\n    m_sock.store( sock, std::memory_order_relaxed );\n    return true;\n}\n\nbool Socket::ConnectBlocking( const char* addr, uint16_t port )\n{\n    assert( !IsValid() );\n    assert( !m_ptr );\n\n    struct addrinfo hints;\n    struct addrinfo *res, *ptr;\n\n    memset( &hints, 0, sizeof( hints ) );\n    hints.ai_family = AF_UNSPEC;\n    hints.ai_socktype = SOCK_STREAM;\n\n    char portbuf[32];\n    sprintf( portbuf, \"%\" PRIu16, port );\n\n    if( getaddrinfo( addr, portbuf, &hints, &res ) != 0 ) return false;\n    int sock = 0;\n    for( ptr = res; ptr; ptr = ptr->ai_next )\n    {\n        if( ( sock = socket( ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol ) ) == -1 ) continue;\n#if defined __APPLE__\n        int val = 1;\n        setsockopt( sock, SOL_SOCKET, SO_NOSIGPIPE, &val, sizeof( val ) );\n#endif\n        if( connect( sock, ptr->ai_addr, ptr->ai_addrlen ) == -1 )\n        {\n#ifdef _WIN32\n            closesocket( sock );\n#else\n            close( sock );\n#endif\n            continue;\n        }\n        break;\n    }\n    freeaddrinfo( res );\n    if( !ptr ) return false;\n\n    m_sock.store( sock, std::memory_order_relaxed );\n    return true;\n}\n\nvoid Socket::Close()\n{\n    const auto sock = m_sock.load( std::memory_order_relaxed );\n    assert( sock != -1 );\n#ifdef _WIN32\n    closesocket( sock );\n#else\n    close( sock );\n#endif\n    m_sock.store( -1, std::memory_order_relaxed );\n}\n\nint Socket::Send( const void* _buf, int len )\n{\n    const auto sock = m_sock.load( std::memory_order_relaxed );\n    auto buf = (const char*)_buf;\n    assert( sock != -1 );\n    auto start = buf;\n    while( len > 0 )\n    {\n        auto ret = send( sock, buf, len, MSG_NOSIGNAL );\n        if( ret == -1 ) return -1;\n        len -= ret;\n        buf += ret;\n    }\n    return int( buf - start );\n}\n\nint Socket::GetSendBufSize()\n{\n    const auto sock = m_sock.load( std::memory_order_relaxed );\n    int bufSize;\n#if defined _WIN32\n    int sz = sizeof( bufSize );\n    getsockopt( sock, SOL_SOCKET, SO_SNDBUF, (char*)&bufSize, &sz );\n#else\n    socklen_t sz = sizeof( bufSize );\n    getsockopt( sock, SOL_SOCKET, SO_SNDBUF, &bufSize, &sz );\n#endif\n    return bufSize;\n}\n\nint Socket::RecvBuffered( void* buf, int len, int timeout )\n{\n    if( len <= m_bufLeft )\n    {\n        memcpy( buf, m_bufPtr, len );\n        m_bufPtr += len;\n        m_bufLeft -= len;\n        return len;\n    }\n\n    if( m_bufLeft > 0 )\n    {\n        memcpy( buf, m_bufPtr, m_bufLeft );\n        const auto ret = m_bufLeft;\n        m_bufLeft = 0;\n        return ret;\n    }\n\n    if( len >= BufSize ) return Recv( buf, len, timeout );\n\n    m_bufLeft = Recv( m_buf, BufSize, timeout );\n    if( m_bufLeft <= 0 ) return m_bufLeft;\n\n    const auto sz = len < m_bufLeft ? len : m_bufLeft;\n    memcpy( buf, m_buf, sz );\n    m_bufPtr = m_buf + sz;\n    m_bufLeft -= sz;\n    return sz;\n}\n\nint Socket::Recv( void* _buf, int len, int timeout )\n{\n    const auto sock = m_sock.load( std::memory_order_relaxed );\n    auto buf = (char*)_buf;\n\n    struct pollfd fd;\n    fd.fd = (socket_t)sock;\n    fd.events = POLLIN;\n\n    if( poll( &fd, 1, timeout ) > 0 )\n    {\n        return recv( sock, buf, len, 0 );\n    }\n    else\n    {\n        return -1;\n    }\n}\n\nint Socket::ReadUpTo( void* _buf, int len )\n{\n    const auto sock = m_sock.load( std::memory_order_relaxed );\n    auto buf = (char*)_buf;\n\n    int rd = 0;\n    while( len > 0 )\n    {\n        const auto res = recv( sock, buf, len, 0 );\n        if( res == 0 ) break;\n        if( res == -1 ) return -1;\n        len -= res;\n        rd += res;\n        buf += res;\n    }\n    return rd;\n}\n\nbool Socket::Read( void* buf, int len, int timeout )\n{\n    auto cbuf = (char*)buf;\n    while( len > 0 )\n    {\n        if( !ReadImpl( cbuf, len, timeout ) ) return false;\n    }\n    return true;\n}\n\nbool Socket::ReadImpl( char*& buf, int& len, int timeout )\n{\n    const auto sz = RecvBuffered( buf, len, timeout );\n    switch( sz )\n    {\n    case 0:\n        return false;\n    case -1:\n#ifdef _WIN32\n    {\n        auto err = WSAGetLastError();\n        if( err == WSAECONNABORTED || err == WSAECONNRESET ) return false;\n    }\n#endif\n    break;\n    default:\n        len -= sz;\n        buf += sz;\n        break;\n    }\n    return true;\n}\n\nbool Socket::ReadRaw( void* _buf, int len, int timeout )\n{\n    auto buf = (char*)_buf;\n    while( len > 0 )\n    {\n        const auto sz = Recv( buf, len, timeout );\n        if( sz <= 0 ) return false;\n        len -= sz;\n        buf += sz;\n    }\n    return true;\n}\n\nbool Socket::HasData()\n{\n    const auto sock = m_sock.load( std::memory_order_relaxed );\n    if( m_bufLeft > 0 ) return true;\n\n    struct pollfd fd;\n    fd.fd = (socket_t)sock;\n    fd.events = POLLIN;\n\n    return poll( &fd, 1, 0 ) > 0;\n}\n\nbool Socket::IsValid() const\n{\n    return m_sock.load( std::memory_order_relaxed ) >= 0;\n}\n\n\nListenSocket::ListenSocket()\n    : m_sock( -1 )\n{\n#ifdef _WIN32\n    InitWinSock();\n#endif\n}\n\nListenSocket::~ListenSocket()\n{\n    if( m_sock != -1 ) Close();\n}\n\nstatic int addrinfo_and_socket_for_family( uint16_t port, int ai_family, struct addrinfo** res )\n{\n    struct addrinfo hints;\n    memset( &hints, 0, sizeof( hints ) );\n    hints.ai_family = ai_family;\n    hints.ai_socktype = SOCK_STREAM;\n#ifndef TRACY_ONLY_LOCALHOST\n    const char* onlyLocalhost = GetEnvVar( \"TRACY_ONLY_LOCALHOST\" );\n    if( !onlyLocalhost || onlyLocalhost[0] != '1' )\n    {\n        hints.ai_flags = AI_PASSIVE;\n    }\n#endif\n    char portbuf[32];\n    sprintf( portbuf, \"%\" PRIu16, port );\n    if( getaddrinfo( nullptr, portbuf, &hints, res ) != 0 ) return -1;\n    int sock = socket( (*res)->ai_family, (*res)->ai_socktype, (*res)->ai_protocol );\n    if (sock == -1) freeaddrinfo( *res );\n    return sock;\n}\n\nbool ListenSocket::Listen( uint16_t port, int backlog )\n{\n    assert( m_sock == -1 );\n\n    struct addrinfo* res = nullptr;\n\n#if !defined TRACY_ONLY_IPV4 && !defined TRACY_ONLY_LOCALHOST\n    const char* onlyIPv4 = GetEnvVar( \"TRACY_ONLY_IPV4\" );\n    if( !onlyIPv4 || onlyIPv4[0] != '1' )\n    {\n        m_sock = addrinfo_and_socket_for_family( port, AF_INET6, &res );\n    }\n#endif\n    if (m_sock == -1)\n    {\n        // IPV6 protocol may not be available/is disabled. Try to create a socket\n        // with the IPV4 protocol\n        m_sock = addrinfo_and_socket_for_family( port, AF_INET, &res );\n        if( m_sock == -1 ) return false;\n    }\n#if defined _WIN32\n    unsigned long val = 0;\n    setsockopt( m_sock, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&val, sizeof( val ) );\n#elif defined BSD\n    int val = 0;\n    setsockopt( m_sock, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&val, sizeof( val ) );\n    val = 1;\n    setsockopt( m_sock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof( val ) );\n#else\n    int val = 1;\n    setsockopt( m_sock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof( val ) );\n#endif\n    if( bind( m_sock, res->ai_addr, res->ai_addrlen ) == -1 ) { freeaddrinfo( res ); Close(); return false; }\n    if( listen( m_sock, backlog ) == -1 ) { freeaddrinfo( res ); Close(); return false; }\n    freeaddrinfo( res );\n    return true;\n}\n\nSocket* ListenSocket::Accept()\n{\n    struct sockaddr_storage remote;\n    socklen_t sz = sizeof( remote );\n\n    struct pollfd fd;\n    fd.fd = (socket_t)m_sock;\n    fd.events = POLLIN;\n\n    if( poll( &fd, 1, 10 ) > 0 )\n    {\n        int sock = accept( m_sock, (sockaddr*)&remote, &sz);\n        if( sock == -1 ) return nullptr;\n\n#if defined __APPLE__\n        int val = 1;\n        setsockopt( sock, SOL_SOCKET, SO_NOSIGPIPE, &val, sizeof( val ) );\n#endif\n\n        auto ptr = (Socket*)tracy_malloc( sizeof( Socket ) );\n        new(ptr) Socket( sock );\n        return ptr;\n    }\n    else\n    {\n        return nullptr;\n    }\n}\n\nvoid ListenSocket::Close()\n{\n    assert( m_sock != -1 );\n#ifdef _WIN32\n    closesocket( m_sock );\n#else\n    close( m_sock );\n#endif\n    m_sock = -1;\n}\n\nUdpBroadcast::UdpBroadcast()\n    : m_sock( -1 )\n{\n#ifdef _WIN32\n    InitWinSock();\n#endif\n}\n\nUdpBroadcast::~UdpBroadcast()\n{\n    if( m_sock != -1 ) Close();\n}\n\nbool UdpBroadcast::Open( const char* addr, uint16_t port )\n{\n    assert( m_sock == -1 );\n\n    struct addrinfo hints;\n    struct addrinfo *res, *ptr;\n\n    memset( &hints, 0, sizeof( hints ) );\n    hints.ai_family = AF_INET;\n    hints.ai_socktype = SOCK_DGRAM;\n\n    char portbuf[32];\n    sprintf( portbuf, \"%\" PRIu16, port );\n\n    if( getaddrinfo( addr, portbuf, &hints, &res ) != 0 ) return false;\n    int sock = 0;\n    for( ptr = res; ptr; ptr = ptr->ai_next )\n    {\n        if( ( sock = socket( ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol ) ) == -1 ) continue;\n#if defined __APPLE__\n        int val = 1;\n        setsockopt( sock, SOL_SOCKET, SO_NOSIGPIPE, &val, sizeof( val ) );\n#endif\n#if defined _WIN32\n        unsigned long broadcast = 1;\n        if( setsockopt( sock, SOL_SOCKET, SO_BROADCAST, (const char*)&broadcast, sizeof( broadcast ) ) == -1 )\n#else\n        int broadcast = 1;\n        if( setsockopt( sock, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof( broadcast ) ) == -1 )\n#endif\n        {\n#ifdef _WIN32\n            closesocket( sock );\n#else\n            close( sock );\n#endif\n            continue;\n        }\n        break;\n    }\n    freeaddrinfo( res );\n    if( !ptr ) return false;\n\n    m_sock = sock;\n    inet_pton( AF_INET, addr, &m_addr );\n    return true;\n}\n\nvoid UdpBroadcast::Close()\n{\n    assert( m_sock != -1 );\n#ifdef _WIN32\n    closesocket( m_sock );\n#else\n    close( m_sock );\n#endif\n    m_sock = -1;\n}\n\nint UdpBroadcast::Send( uint16_t port, const void* data, int len )\n{\n    assert( m_sock != -1 );\n    struct sockaddr_in addr;\n    addr.sin_family = AF_INET;\n    addr.sin_port = htons( port );\n    addr.sin_addr.s_addr = m_addr;\n    return sendto( m_sock, (const char*)data, len, MSG_NOSIGNAL, (sockaddr*)&addr, sizeof( addr ) );\n}\n\nIpAddress::IpAddress()\n    : m_number( 0 )\n{\n    *m_text = '\\0';\n}\n\nIpAddress::~IpAddress()\n{\n}\n\nvoid IpAddress::Set( const struct sockaddr& addr )\n{\n#if defined _WIN32 && ( !defined NTDDI_WIN10 || NTDDI_VERSION < NTDDI_WIN10 )\n    struct sockaddr_in tmp;\n    memcpy( &tmp, &addr, sizeof( tmp ) );\n    auto ai = &tmp;\n#else\n    auto ai = (const struct sockaddr_in*)&addr;\n#endif\n    inet_ntop( AF_INET, &ai->sin_addr, m_text, 17 );\n    m_number = ai->sin_addr.s_addr;\n}\n\nUdpListen::UdpListen()\n    : m_sock( -1 )\n{\n#ifdef _WIN32\n    InitWinSock();\n#endif\n}\n\nUdpListen::~UdpListen()\n{\n    if( m_sock != -1 ) Close();\n}\n\nbool UdpListen::Listen( uint16_t port )\n{\n    assert( m_sock == -1 );\n\n    int sock;\n    if( ( sock = socket( AF_INET, SOCK_DGRAM, 0 ) ) == -1 ) return false;\n\n#if defined __APPLE__\n    int val = 1;\n    setsockopt( sock, SOL_SOCKET, SO_NOSIGPIPE, &val, sizeof( val ) );\n#endif\n#if defined _WIN32\n    unsigned long reuse = 1;\n    setsockopt( sock, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse, sizeof( reuse ) );\n#else\n    int reuse = 1;\n    setsockopt( sock, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof( reuse ) );\n#endif\n#if defined _WIN32\n    unsigned long broadcast = 1;\n    if( setsockopt( sock, SOL_SOCKET, SO_BROADCAST, (const char*)&broadcast, sizeof( broadcast ) ) == -1 )\n#else\n    int broadcast = 1;\n    if( setsockopt( sock, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof( broadcast ) ) == -1 )\n#endif\n    {\n#ifdef _WIN32\n        closesocket( sock );\n#else\n        close( sock );\n#endif\n        return false;\n    }\n\n    struct sockaddr_in addr;\n    addr.sin_family = AF_INET;\n    addr.sin_port = htons( port );\n    addr.sin_addr.s_addr = INADDR_ANY;\n\n    if( bind( sock, (sockaddr*)&addr, sizeof( addr ) ) == -1 )\n    {\n#ifdef _WIN32\n        closesocket( sock );\n#else\n        close( sock );\n#endif\n        return false;\n    }\n\n    m_sock = sock;\n    return true;\n}\n\nvoid UdpListen::Close()\n{\n    assert( m_sock != -1 );\n#ifdef _WIN32\n    closesocket( m_sock );\n#else\n    close( m_sock );\n#endif\n    m_sock = -1;\n}\n\nconst char* UdpListen::Read( size_t& len, IpAddress& addr, int timeout )\n{\n    static char buf[2048];\n\n    struct pollfd fd;\n    fd.fd = (socket_t)m_sock;\n    fd.events = POLLIN;\n    if( poll( &fd, 1, timeout ) <= 0 ) return nullptr;\n\n    sockaddr sa;\n    socklen_t salen = sizeof( struct sockaddr );\n    len = (size_t)recvfrom( m_sock, buf, 2048, 0, &sa, &salen );\n    addr.Set( sa );\n\n    return buf;\n}\n\n}\n"
  },
  {
    "path": "tracy-client-sys/tracy/common/TracySocket.hpp",
    "content": "#ifndef __TRACYSOCKET_HPP__\n#define __TRACYSOCKET_HPP__\n\n#include <atomic>\n#include <stddef.h>\n#include <stdint.h>\n\nstruct addrinfo;\nstruct sockaddr;\n\nnamespace tracy\n{\n\n#ifdef _WIN32\nvoid InitWinSock();\n#endif\n\nclass Socket\n{\npublic:\n    Socket();\n    Socket( int sock );\n    ~Socket();\n\n    bool Connect( const char* addr, uint16_t port );\n    bool ConnectBlocking( const char* addr, uint16_t port );\n    void Close();\n\n    int Send( const void* buf, int len );\n    int GetSendBufSize();\n\n    int ReadUpTo( void* buf, int len );\n    bool Read( void* buf, int len, int timeout );\n\n    template<typename ShouldExit>\n    bool Read( void* buf, int len, int timeout, ShouldExit exitCb )\n    {\n        auto cbuf = (char*)buf;\n        while( len > 0 )\n        {\n            if( exitCb() ) return false;\n            if( !ReadImpl( cbuf, len, timeout ) ) return false;\n        }\n        return true;\n    }\n\n    bool ReadRaw( void* buf, int len, int timeout );\n    bool HasData();\n    bool IsValid() const;\n\n    Socket( const Socket& ) = delete;\n    Socket( Socket&& ) = delete;\n    Socket& operator=( const Socket& ) = delete;\n    Socket& operator=( Socket&& ) = delete;\n\nprivate:\n    int RecvBuffered( void* buf, int len, int timeout );\n    int Recv( void* buf, int len, int timeout );\n\n    bool ReadImpl( char*& buf, int& len, int timeout );\n\n    char* m_buf;\n    char* m_bufPtr;\n    std::atomic<int> m_sock;\n    int m_bufLeft;\n\n    struct addrinfo *m_res;\n    struct addrinfo *m_ptr;\n    int m_connSock;\n};\n\nclass ListenSocket\n{\npublic:\n    ListenSocket();\n    ~ListenSocket();\n\n    bool Listen( uint16_t port, int backlog );\n    Socket* Accept();\n    void Close();\n\n    ListenSocket( const ListenSocket& ) = delete;\n    ListenSocket( ListenSocket&& ) = delete;\n    ListenSocket& operator=( const ListenSocket& ) = delete;\n    ListenSocket& operator=( ListenSocket&& ) = delete;\n\nprivate:\n    int m_sock;\n};\n\nclass UdpBroadcast\n{\npublic:\n    UdpBroadcast();\n    ~UdpBroadcast();\n\n    bool Open( const char* addr, uint16_t port );\n    void Close();\n\n    int Send( uint16_t port, const void* data, int len );\n\n    UdpBroadcast( const UdpBroadcast& ) = delete;\n    UdpBroadcast( UdpBroadcast&& ) = delete;\n    UdpBroadcast& operator=( const UdpBroadcast& ) = delete;\n    UdpBroadcast& operator=( UdpBroadcast&& ) = delete;\n\nprivate:\n    int m_sock;\n    uint32_t m_addr;\n};\n\nclass IpAddress\n{\npublic:\n    IpAddress();\n    ~IpAddress();\n\n    void Set( const struct sockaddr& addr );\n\n    uint32_t GetNumber() const { return m_number; }\n    const char* GetText() const { return m_text; }\n\n    IpAddress( const IpAddress& ) = delete;\n    IpAddress( IpAddress&& ) = delete;\n    IpAddress& operator=( const IpAddress& ) = delete;\n    IpAddress& operator=( IpAddress&& ) = delete;\n\nprivate:\n    uint32_t m_number;\n    char m_text[17];\n};\n\nclass UdpListen\n{\npublic:\n    UdpListen();\n    ~UdpListen();\n\n    bool Listen( uint16_t port );\n    void Close();\n\n    const char* Read( size_t& len, IpAddress& addr, int timeout );\n\n    UdpListen( const UdpListen& ) = delete;\n    UdpListen( UdpListen&& ) = delete;\n    UdpListen& operator=( const UdpListen& ) = delete;\n    UdpListen& operator=( UdpListen&& ) = delete;\n\nprivate:\n    int m_sock;\n};\n\n}\n\n#endif\n"
  },
  {
    "path": "tracy-client-sys/tracy/common/TracyStackFrames.cpp",
    "content": "#include \"TracyStackFrames.hpp\"\n\nnamespace tracy\n{\n\nconst char* s_tracyStackFrames_[] = {\n    \"tracy::Callstack\",\n    \"tracy::Callstack(int)\",\n    \"tracy::GpuCtxScope::{ctor}\",\n    \"tracy::Profiler::SendCallstack\",\n    \"tracy::Profiler::SendCallstack(int)\",\n    \"tracy::Profiler::SendCallstack(int, unsigned long)\",\n    \"tracy::Profiler::MemAllocCallstack\",\n    \"tracy::Profiler::MemAllocCallstack(void const*, unsigned long, int)\",\n    \"tracy::Profiler::MemFreeCallstack\",\n    \"tracy::Profiler::MemFreeCallstack(void const*, int)\",\n    \"tracy::ScopedZone::{ctor}\",\n    \"tracy::ScopedZone::ScopedZone(tracy::SourceLocationData const*, int, bool)\",\n    \"tracy::Profiler::Message\",\n    nullptr\n};\n\nconst char** s_tracyStackFrames = s_tracyStackFrames_;\n\nconst StringMatch s_tracySkipSubframes_[] = {\n    { \"/include/arm_neon.h\", 19 },\n    { \"/include/adxintrin.h\", 20 },\n    { \"/include/ammintrin.h\", 20 },\n    { \"/include/amxbf16intrin.h\", 24 },\n    { \"/include/amxint8intrin.h\", 24 },\n    { \"/include/amxtileintrin.h\", 24 },\n    { \"/include/avx2intrin.h\", 21 },\n    { \"/include/avx5124fmapsintrin.h\", 29 },\n    { \"/include/avx5124vnniwintrin.h\", 29 },\n    { \"/include/avx512bf16intrin.h\", 27 },\n    { \"/include/avx512bf16vlintrin.h\", 29 },\n    { \"/include/avx512bitalgintrin.h\", 29 },\n    { \"/include/avx512bwintrin.h\", 25 },\n    { \"/include/avx512cdintrin.h\", 25 },\n    { \"/include/avx512dqintrin.h\", 25 },\n    { \"/include/avx512erintrin.h\", 25 },\n    { \"/include/avx512fintrin.h\", 24 },\n    { \"/include/avx512ifmaintrin.h\", 27 },\n    { \"/include/avx512ifmavlintrin.h\", 29 },\n    { \"/include/avx512pfintrin.h\", 25 },\n    { \"/include/avx512vbmi2intrin.h\", 28 },\n    { \"/include/avx512vbmi2vlintrin.h\", 30 },\n    { \"/include/avx512vbmiintrin.h\", 27 },\n    { \"/include/avx512vbmivlintrin.h\", 29 },\n    { \"/include/avx512vlbwintrin.h\", 27 },\n    { \"/include/avx512vldqintrin.h\", 27 },\n    { \"/include/avx512vlintrin.h\", 25 },\n    { \"/include/avx512vnniintrin.h\", 27 },\n    { \"/include/avx512vnnivlintrin.h\", 29 },\n    { \"/include/avx512vp2intersectintrin.h\", 35 },\n    { \"/include/avx512vp2intersectvlintrin.h\", 37 },\n    { \"/include/avx512vpopcntdqintrin.h\", 32 },\n    { \"/include/avx512vpopcntdqvlintrin.h\", 34 },\n    { \"/include/avxintrin.h\", 20 },\n    { \"/include/avxvnniintrin.h\", 24 },\n    { \"/include/bmi2intrin.h\", 21 },\n    { \"/include/bmiintrin.h\", 20 },\n    { \"/include/bmmintrin.h\", 20 },\n    { \"/include/cetintrin.h\", 20 },\n    { \"/include/cldemoteintrin.h\", 25 },\n    { \"/include/clflushoptintrin.h\", 27 },\n    { \"/include/clwbintrin.h\", 21 },\n    { \"/include/clzerointrin.h\", 23 },\n    { \"/include/emmintrin.h\", 20 },\n    { \"/include/enqcmdintrin.h\", 23 },\n    { \"/include/f16cintrin.h\", 21 },\n    { \"/include/fma4intrin.h\", 21 },\n    { \"/include/fmaintrin.h\", 20 },\n    { \"/include/fxsrintrin.h\", 21 },\n    { \"/include/gfniintrin.h\", 21 },\n    { \"/include/hresetintrin.h\", 23 },\n    { \"/include/ia32intrin.h\", 21 },\n    { \"/include/immintrin.h\", 20 },\n    { \"/include/keylockerintrin.h\", 26 },\n    { \"/include/lwpintrin.h\", 20 },\n    { \"/include/lzcntintrin.h\", 22 },\n    { \"/include/mmintrin.h\", 19 },\n    { \"/include/movdirintrin.h\", 23 },\n    { \"/include/mwaitxintrin.h\", 23 },\n    { \"/include/nmmintrin.h\", 20 },\n    { \"/include/pconfigintrin.h\", 24 },\n    { \"/include/pkuintrin.h\", 20 },\n    { \"/include/pmmintrin.h\", 20 },\n    { \"/include/popcntintrin.h\", 23 },\n    { \"/include/prfchwintrin.h\", 23 },\n    { \"/include/rdseedintrin.h\", 23 },\n    { \"/include/rtmintrin.h\", 20 },\n    { \"/include/serializeintrin.h\", 26 },\n    { \"/include/sgxintrin.h\", 20 },\n    { \"/include/shaintrin.h\", 20 },\n    { \"/include/smmintrin.h\", 20 },\n    { \"/include/tbmintrin.h\", 20 },\n    { \"/include/tmmintrin.h\", 20 },\n    { \"/include/tsxldtrkintrin.h\", 25 },\n    { \"/include/uintrintrin.h\", 22 },\n    { \"/include/vaesintrin.h\", 21 },\n    { \"/include/vpclmulqdqintrin.h\", 27 },\n    { \"/include/waitpkgintrin.h\", 24 },\n    { \"/include/wbnoinvdintrin.h\", 25 },\n    { \"/include/wmmintrin.h\", 20 },\n    { \"/include/x86gprintrin.h\", 23 },\n    { \"/include/x86intrin.h\", 20 },\n    { \"/include/xmmintrin.h\", 20 },\n    { \"/include/xopintrin.h\", 20 },\n    { \"/include/xsavecintrin.h\", 23 },\n    { \"/include/xsaveintrin.h\", 22 },\n    { \"/include/xsaveoptintrin.h\", 25 },\n    { \"/include/xsavesintrin.h\", 23 },\n    { \"/include/xtestintrin.h\", 22 },\n    { \"/bits/atomic_base.h\", 19 },\n    { \"/atomic\", 7 },\n    {}\n};\n\nconst StringMatch* s_tracySkipSubframes = s_tracySkipSubframes_;\n\n}\n"
  },
  {
    "path": "tracy-client-sys/tracy/common/TracyStackFrames.hpp",
    "content": "#ifndef __TRACYSTACKFRAMES_HPP__\n#define __TRACYSTACKFRAMES_HPP__\n\n#include <stddef.h>\n\nnamespace tracy\n{\n\nstruct StringMatch\n{\n    const char* str;\n    size_t len;\n};\n\nextern const char** s_tracyStackFrames;\nextern const StringMatch* s_tracySkipSubframes;\n\nstatic constexpr int s_tracySkipSubframesMinLen = 7;\n\n}\n\n#endif\n"
  },
  {
    "path": "tracy-client-sys/tracy/common/TracySystem.cpp",
    "content": "#ifdef _MSC_VER\n#  pragma warning(disable:4996)\n#endif\n#if defined _WIN32\n#  ifndef WIN32_LEAN_AND_MEAN\n#    define WIN32_LEAN_AND_MEAN\n#  endif\n#  ifndef NOMINMAX\n#    define NOMINMAX\n#  endif\n#  include <windows.h>\n#  include <malloc.h>\n#  include \"TracyWinFamily.hpp\"\n#else\n#  include <pthread.h>\n#  include <string.h>\n#  include <unistd.h>\n#endif\n\n#ifdef __linux__\n#  ifdef __ANDROID__\n#    include <sys/types.h>\n#  else\n#    include <sys/syscall.h>\n#  endif\n#  include <fcntl.h>\n#elif defined __FreeBSD__\n#  include <sys/thr.h>\n#elif defined __NetBSD__\n#  include <lwp.h>\n#elif defined __DragonFly__\n#  include <sys/lwp.h>\n#elif defined __QNX__\n#  include <process.h>\n#  include <sys/neutrino.h>\n#endif\n\n#ifdef __MINGW32__\n#  define __STDC_FORMAT_MACROS\n#endif\n#include <inttypes.h>\n#include <stdio.h>\n#include <stdlib.h>\n\n#include \"TracySystem.hpp\"\n\n#if defined _WIN32\nextern \"C\" typedef HRESULT (WINAPI *t_SetThreadDescription)( HANDLE, PCWSTR );\nextern \"C\" typedef HRESULT (WINAPI *t_GetThreadDescription)( HANDLE, PWSTR* );\n#endif\n\n#ifdef TRACY_ENABLE\n#  include <atomic>\n#  include \"TracyAlloc.hpp\"\n#endif\n\nnamespace tracy\n{\n\nnamespace detail\n{\n\nTRACY_API uint32_t GetThreadHandleImpl()\n{\n#if defined _WIN32\n    static_assert( sizeof( decltype( GetCurrentThreadId() ) ) <= sizeof( uint32_t ), \"Thread handle too big to fit in protocol\" );\n    return uint32_t( GetCurrentThreadId() );\n#elif defined __APPLE__\n    uint64_t id;\n    pthread_threadid_np( pthread_self(), &id );\n    return uint32_t( id );\n#elif defined __ANDROID__\n    return (uint32_t)gettid();\n#elif defined __linux__\n    return (uint32_t)syscall( SYS_gettid );\n#elif defined __FreeBSD__\n    long id;\n    thr_self( &id );\n    return id;\n#elif defined __NetBSD__\n    return _lwp_self();\n#elif defined __DragonFly__\n    return lwp_gettid();\n#elif defined __OpenBSD__\n    return getthrid();\n#elif defined __QNX__\n    return (uint32_t) gettid();\n#elif defined __EMSCRIPTEN__\n    // Not supported, but let it compile.\n    return 0;\n#else\n    // To add support for a platform, retrieve and return the kernel thread identifier here.\n    //\n    // Note that pthread_t (as for example returned by pthread_self()) is *not* a kernel\n    // thread identifier. It is a pointer to a library-allocated data structure instead.\n    // Such pointers will be reused heavily, making the pthread_t non-unique. Additionally\n    // a 64-bit pointer cannot be reliably truncated to 32 bits.\n    #error \"Unsupported platform!\"\n#endif\n\n}\n\n}\n\n#ifdef TRACY_ENABLE\nstd::atomic<ThreadNameData*>& GetThreadNameData();\n#endif\n\n#if defined _MSC_VER && !defined __clang__\n#  pragma pack( push, 8 )\nstruct THREADNAME_INFO\n{\n    DWORD dwType;\n    LPCSTR szName;\n    DWORD dwThreadID;\n    DWORD dwFlags;\n};\n#  pragma pack( pop )\n\nvoid ThreadNameMsvcMagic( const THREADNAME_INFO& info )\n{\n    __try\n    {\n        RaiseException( 0x406D1388, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info );\n    }\n    __except(EXCEPTION_EXECUTE_HANDLER)\n    {\n    }\n}\n#endif\n\nTRACY_API void SetThreadName( const char* name )\n{\n    SetThreadNameWithHint( name, 0 );\n}\n\nTRACY_API void SetThreadNameWithHint( const char* name, int32_t groupHint )\n{\n#if defined _WIN32\n#  if defined TRACY_WIN32_NO_DESKTOP\n    static auto _SetThreadDescription = &::SetThreadDescription;\n#  else\n    static auto _SetThreadDescription = (t_SetThreadDescription)GetProcAddress( GetModuleHandleA( \"kernel32.dll\" ), \"SetThreadDescription\" );\n#  endif\n    if( _SetThreadDescription )\n    {\n        wchar_t buf[256];\n        mbstowcs( buf, name, 256 );\n        _SetThreadDescription( GetCurrentThread(), buf );\n    }\n    else\n    {\n#  if defined _MSC_VER && !defined __clang__\n        THREADNAME_INFO info;\n        info.dwType = 0x1000;\n        info.szName = name;\n        info.dwThreadID = GetCurrentThreadId();\n        info.dwFlags = 0;\n        ThreadNameMsvcMagic( info );\n#  endif\n    }\n#elif defined _GNU_SOURCE && !defined __EMSCRIPTEN__\n    {\n        const auto sz = strlen( name );\n        if( sz <= 15 )\n        {\n#if defined __APPLE__\n            pthread_setname_np( name );\n#else\n            pthread_setname_np( pthread_self(), name );\n#endif\n        }\n        else\n        {\n            char buf[16];\n            memcpy( buf, name, 15 );\n            buf[15] = '\\0';\n#if defined __APPLE__\n            pthread_setname_np( buf );\n#else\n            pthread_setname_np( pthread_self(), buf );\n#endif\n        }\n    }\n#elif defined __QNX__\n    {\n        const auto sz = strlen( name );\n        if( sz <= _NTO_THREAD_NAME_MAX )\n        {\n            pthread_setname_np( pthread_self(), name );\n        }\n        else\n        {\n            char buf[_NTO_THREAD_NAME_MAX + 1];\n            memcpy( buf, name, _NTO_THREAD_NAME_MAX );\n            buf[_NTO_THREAD_NAME_MAX] = '\\0';\n            pthread_setname_np( pthread_self(), buf );\n        }\n    };\n#endif\n#ifdef TRACY_ENABLE\n    {\n        const auto sz = strlen( name );\n        char* buf = (char*)tracy_malloc( sz+1 );\n        memcpy( buf, name, sz );\n        buf[sz] = '\\0';\n        auto data = (ThreadNameData*)tracy_malloc_fast( sizeof( ThreadNameData ) );\n        data->id = detail::GetThreadHandleImpl();\n        data->groupHint = groupHint;\n        data->name = buf;\n        data->next = GetThreadNameData().load( std::memory_order_relaxed );\n        while( !GetThreadNameData().compare_exchange_weak( data->next, data, std::memory_order_release, std::memory_order_relaxed ) ) {}\n    }\n#endif\n}\n\n#ifdef TRACY_ENABLE\nThreadNameData* GetThreadNameData( uint32_t id )\n{\n    auto ptr = GetThreadNameData().load( std::memory_order_relaxed );\n    while( ptr )\n    {\n        if( ptr->id == id )\n        {\n            return ptr;\n        }\n        ptr = ptr->next;\n    }\n    return nullptr;\n}\n#endif\n\nTRACY_API const char* GetThreadName( uint32_t id )\n{\n    static char buf[256];\n#ifdef TRACY_ENABLE\n    auto ptr = GetThreadNameData().load( std::memory_order_relaxed );\n    while( ptr )\n    {\n        if( ptr->id == id )\n        {\n            return ptr->name;\n        }\n        ptr = ptr->next;\n    }\n#endif\n\n#if defined _WIN32\n# if defined TRACY_WIN32_NO_DESKTOP\n   static auto _GetThreadDescription = &::GetThreadDescription;\n# else\n   static auto _GetThreadDescription = (t_GetThreadDescription)GetProcAddress( GetModuleHandleA( \"kernel32.dll\" ), \"GetThreadDescription\" );\n# endif\n    if( _GetThreadDescription )\n    {\n        auto hnd = OpenThread( THREAD_QUERY_LIMITED_INFORMATION, FALSE, (DWORD)id );\n        if( hnd != 0 )\n        {\n            PWSTR tmp;\n            if( SUCCEEDED( _GetThreadDescription( hnd, &tmp ) ) )\n            {\n                auto ret = wcstombs( buf, tmp, 256 );\n                CloseHandle( hnd );\n                LocalFree( tmp );\n                if( ret != static_cast<size_t>( -1 ) )\n                {\n                    return buf;\n                }\n            }\n        }\n    }\n#elif defined __linux__\n  int cs, fd;\n  char path[32];\n  snprintf( path, sizeof( path ), \"/proc/self/task/%d/comm\", id );\n  sprintf( buf, \"%\" PRIu32, id );\n# ifndef __ANDROID__\n   pthread_setcancelstate( PTHREAD_CANCEL_DISABLE, &cs );\n# endif\n  if ( ( fd = open( path, O_RDONLY ) ) > 0) {\n      int len = read( fd, buf, 255 );\n      if( len > 0 )\n      {\n          buf[len] = 0;\n          if( len > 1 && buf[len-1] == '\\n' )\n          {\n              buf[len-1] = 0;\n          }\n      }\n      close( fd );\n  }\n# ifndef __ANDROID__\n   pthread_setcancelstate( cs, 0 );\n# endif\n  return buf;\n#elif defined __QNX__\n    static char qnxNameBuf[_NTO_THREAD_NAME_MAX + 1] = {0};\n    if (pthread_getname_np(static_cast<int>(id), qnxNameBuf, _NTO_THREAD_NAME_MAX) == 0) {\n        return qnxNameBuf;\n    };\n#endif\n\n  sprintf( buf, \"%\" PRIu32, id );\n  return buf;\n}\n\nTRACY_API const char* GetEnvVar( const char* name )\n{\n#if defined _WIN32\n    // unfortunately getenv() on Windows is just fundamentally broken.  It caches the entire\n    // environment block once on startup, then never refreshes it again.  If any environment\n    // strings are added or modified after startup of the CRT, those changes will not be\n    // seen by getenv().  This removes the possibility of an app using this SDK from\n    // programmatically setting any of the behaviour controlling envvars here.\n    //\n    // To work around this, we'll instead go directly to the Win32 environment strings APIs\n    // to get the current value.\n    static char buffer[1024];\n    DWORD const kBufferSize = DWORD(sizeof(buffer) / sizeof(buffer[0]));\n    DWORD count = GetEnvironmentVariableA(name, buffer, kBufferSize);\n\n    if( count == 0 )\n        return nullptr;\n\n    if( count >= kBufferSize )\n    {\n        char* buf = reinterpret_cast<char*>(_alloca(count + 1));\n        count = GetEnvironmentVariableA(name, buf, count + 1);\n        memcpy(buffer, buf, kBufferSize);\n        buffer[kBufferSize - 1] = 0;\n    }\n\n    return buffer;\n#else\n    return getenv(name);\n#endif\n}\n\n}\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nTRACY_API void ___tracy_set_thread_name( const char* name ) { tracy::SetThreadName( name ); }\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "tracy-client-sys/tracy/common/TracySystem.hpp",
    "content": "#ifndef __TRACYSYSTEM_HPP__\n#define __TRACYSYSTEM_HPP__\n\n#include <stdint.h>\n\n#include \"TracyApi.h\"\n\nnamespace tracy\n{\n\nnamespace detail\n{\nTRACY_API uint32_t GetThreadHandleImpl();\n}\n\n#ifdef TRACY_ENABLE\nstruct ThreadNameData\n{\n    uint32_t id;\n    int32_t groupHint;\n    const char* name;\n    ThreadNameData* next;\n};\n\nThreadNameData* GetThreadNameData( uint32_t id );\n\nTRACY_API uint32_t GetThreadHandle();\n#else\nstatic inline uint32_t GetThreadHandle()\n{\n    return detail::GetThreadHandleImpl();\n}\n#endif\n\nTRACY_API void SetThreadName( const char* name );\nTRACY_API void SetThreadNameWithHint( const char* name, int32_t groupHint );\nTRACY_API const char* GetThreadName( uint32_t id );\n\nTRACY_API const char* GetEnvVar( const char* name );\n\n}\n\n#endif\n"
  },
  {
    "path": "tracy-client-sys/tracy/common/TracyVersion.hpp",
    "content": "#ifndef __TRACYVERSION_HPP__\n#define __TRACYVERSION_HPP__\n\nnamespace tracy\n{\nnamespace Version\n{\nenum { Major = 0 };\nenum { Minor = 13 };\nenum { Patch = 1 };\n}\n}\n\n#endif\n"
  },
  {
    "path": "tracy-client-sys/tracy/common/TracyWinFamily.hpp",
    "content": "#ifndef __TRACYWINFAMILY_HPP__\n#define __TRACYWINFAMILY_HPP__\n\n#ifdef _WIN32\n#  include <winapifamily.h>\n#  if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)\n#    define TRACY_WIN32_NO_DESKTOP\n#    if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_GAMES)\n#      define TRACY_GDK\n#    elif WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)\n#      define TRACY_UWP\n#    endif\n#  endif\n#endif\n\n#endif\n"
  },
  {
    "path": "tracy-client-sys/tracy/common/TracyYield.hpp",
    "content": "#ifndef __TRACYYIELD_HPP__\n#define __TRACYYIELD_HPP__\n\n#if defined __SSE2__ || defined _M_AMD64 || (defined _M_IX86_FP && _M_IX86_FP == 2)\n#  include <emmintrin.h>\n#else\n#  include <thread>\n#endif\n\n#include \"TracyForceInline.hpp\"\n\nnamespace tracy\n{\n\nstatic tracy_force_inline void YieldThread()\n{\n#if defined __SSE2__ || defined _M_AMD64 || (defined _M_IX86_FP && _M_IX86_FP == 2)\n    _mm_pause();\n#elif defined __aarch64__\n    asm volatile( \"isb\" : : );\n#else\n    std::this_thread::yield();\n#endif\n}\n\n}\n\n#endif\n"
  },
  {
    "path": "tracy-client-sys/tracy/common/tracy_lz4.cpp",
    "content": "/*\n   LZ4 - Fast LZ compression algorithm\n   Copyright (C) 2011-2020, Yann Collet.\n\n   BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)\n\n   Redistribution and use in source and binary forms, with or without\n   modification, are permitted provided that the following conditions are\n   met:\n\n       * Redistributions of source code must retain the above copyright\n   notice, this list of conditions and the following disclaimer.\n       * Redistributions in binary form must reproduce the above\n   copyright notice, this list of conditions and the following disclaimer\n   in the documentation and/or other materials provided with the\n   distribution.\n\n   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n   \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n   You can contact the author at :\n    - LZ4 homepage : http://www.lz4.org\n    - LZ4 source repository : https://github.com/lz4/lz4\n*/\n\n/*-************************************\n*  Tuning parameters\n**************************************/\n/*\n * LZ4_HEAPMODE :\n * Select how default compression functions will allocate memory for their hash table,\n * in memory stack (0:default, fastest), or in memory heap (1:requires malloc()).\n */\n#ifndef LZ4_HEAPMODE\n#  define LZ4_HEAPMODE 0\n#endif\n\n/*\n * LZ4_ACCELERATION_DEFAULT :\n * Select \"acceleration\" for LZ4_compress_fast() when parameter value <= 0\n */\n#define LZ4_ACCELERATION_DEFAULT 1\n/*\n * LZ4_ACCELERATION_MAX :\n * Any \"acceleration\" value higher than this threshold\n * get treated as LZ4_ACCELERATION_MAX instead (fix #876)\n */\n#define LZ4_ACCELERATION_MAX 65537\n\n\n/*-************************************\n*  CPU Feature Detection\n**************************************/\n/* LZ4_FORCE_MEMORY_ACCESS\n * By default, access to unaligned memory is controlled by `memcpy()`, which is safe and portable.\n * Unfortunately, on some target/compiler combinations, the generated assembly is sub-optimal.\n * The below switch allow to select different access method for improved performance.\n * Method 0 (default) : use `memcpy()`. Safe and portable.\n * Method 1 : `__packed` statement. It depends on compiler extension (ie, not portable).\n *            This method is safe if your compiler supports it, and *generally* as fast or faster than `memcpy`.\n * Method 2 : direct access. This method is portable but violate C standard.\n *            It can generate buggy code on targets which assembly generation depends on alignment.\n *            But in some circumstances, it's the only known way to get the most performance (ie GCC + ARMv6)\n * See https://fastcompression.blogspot.fr/2015/08/accessing-unaligned-memory.html for details.\n * Prefer these methods in priority order (0 > 1 > 2)\n */\n#ifndef LZ4_FORCE_MEMORY_ACCESS   /* can be defined externally */\n#  if defined(__GNUC__) && \\\n  ( defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) \\\n  || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) )\n#    define LZ4_FORCE_MEMORY_ACCESS 2\n#  elif (defined(__INTEL_COMPILER) && !defined(_WIN32)) || defined(__GNUC__)\n#    define LZ4_FORCE_MEMORY_ACCESS 1\n#  endif\n#endif\n\n/*\n * LZ4_FORCE_SW_BITCOUNT\n * Define this parameter if your target system or compiler does not support hardware bit count\n */\n#if defined(_MSC_VER) && defined(_WIN32_WCE)   /* Visual Studio for WinCE doesn't support Hardware bit count */\n#  undef  LZ4_FORCE_SW_BITCOUNT  /* avoid double def */\n#  define LZ4_FORCE_SW_BITCOUNT\n#endif\n\n\n\n/*-************************************\n*  Dependency\n**************************************/\n/*\n * LZ4_SRC_INCLUDED:\n * Amalgamation flag, whether lz4.c is included\n */\n#ifndef LZ4_SRC_INCLUDED\n#  define LZ4_SRC_INCLUDED 1\n#endif\n\n#ifndef LZ4_STATIC_LINKING_ONLY\n#define LZ4_STATIC_LINKING_ONLY\n#endif\n\n#ifndef LZ4_DISABLE_DEPRECATE_WARNINGS\n#define LZ4_DISABLE_DEPRECATE_WARNINGS /* due to LZ4_decompress_safe_withPrefix64k */\n#endif\n\n#define LZ4_STATIC_LINKING_ONLY  /* LZ4_DISTANCE_MAX */\n#include \"tracy_lz4.hpp\"\n/* see also \"memory routines\" below */\n\n\n/*-************************************\n*  Compiler Options\n**************************************/\n#if defined(_MSC_VER) && (_MSC_VER >= 1400)  /* Visual Studio 2005+ */\n#  include <intrin.h>               /* only present in VS2005+ */\n#  pragma warning(disable : 4127)   /* disable: C4127: conditional expression is constant */\n#  pragma warning(disable : 6237)   /* disable: C6237: conditional expression is always 0 */\n#endif  /* _MSC_VER */\n\n#ifndef LZ4_FORCE_INLINE\n#  if defined (_MSC_VER) && !defined (__clang__)    /* MSVC */\n#    define LZ4_FORCE_INLINE static __forceinline\n#  else\n#    if defined (__cplusplus) || defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L   /* C99 */\n#      if defined (__GNUC__) || defined (__clang__)\n#        define LZ4_FORCE_INLINE static inline __attribute__((always_inline))\n#      else\n#        define LZ4_FORCE_INLINE static inline\n#      endif\n#    else\n#      define LZ4_FORCE_INLINE static\n#    endif /* __STDC_VERSION__ */\n#  endif  /* _MSC_VER */\n#endif /* LZ4_FORCE_INLINE */\n\n/* LZ4_FORCE_O2 and LZ4_FORCE_INLINE\n * gcc on ppc64le generates an unrolled SIMDized loop for LZ4_wildCopy8,\n * together with a simple 8-byte copy loop as a fall-back path.\n * However, this optimization hurts the decompression speed by >30%,\n * because the execution does not go to the optimized loop\n * for typical compressible data, and all of the preamble checks\n * before going to the fall-back path become useless overhead.\n * This optimization happens only with the -O3 flag, and -O2 generates\n * a simple 8-byte copy loop.\n * With gcc on ppc64le, all of the LZ4_decompress_* and LZ4_wildCopy8\n * functions are annotated with __attribute__((optimize(\"O2\"))),\n * and also LZ4_wildCopy8 is forcibly inlined, so that the O2 attribute\n * of LZ4_wildCopy8 does not affect the compression speed.\n */\n#if defined(__PPC64__) && defined(__LITTLE_ENDIAN__) && defined(__GNUC__) && !defined(__clang__)\n#  define LZ4_FORCE_O2  __attribute__((optimize(\"O2\")))\n#  undef LZ4_FORCE_INLINE\n#  define LZ4_FORCE_INLINE  static __inline __attribute__((optimize(\"O2\"),always_inline))\n#else\n#  define LZ4_FORCE_O2\n#endif\n\n#if (defined(__GNUC__) && (__GNUC__ >= 3)) || (defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 800)) || defined(__clang__)\n#  define expect(expr,value)    (__builtin_expect ((expr),(value)) )\n#else\n#  define expect(expr,value)    (expr)\n#endif\n\n#ifndef likely\n#define likely(expr)     expect((expr) != 0, 1)\n#endif\n#ifndef unlikely\n#define unlikely(expr)   expect((expr) != 0, 0)\n#endif\n\n/* Should the alignment test prove unreliable, for some reason,\n * it can be disabled by setting LZ4_ALIGN_TEST to 0 */\n#ifndef LZ4_ALIGN_TEST  /* can be externally provided */\n# define LZ4_ALIGN_TEST 1\n#endif\n\n\n/*-************************************\n*  Memory routines\n**************************************/\n\n/*! LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION :\n *  Disable relatively high-level LZ4/HC functions that use dynamic memory\n *  allocation functions (malloc(), calloc(), free()).\n *\n *  Note that this is a compile-time switch. And since it disables\n *  public/stable LZ4 v1 API functions, we don't recommend using this\n *  symbol to generate a library for distribution.\n *\n *  The following public functions are removed when this symbol is defined.\n *  - lz4   : LZ4_createStream, LZ4_freeStream,\n *            LZ4_createStreamDecode, LZ4_freeStreamDecode, LZ4_create (deprecated)\n *  - lz4hc : LZ4_createStreamHC, LZ4_freeStreamHC,\n *            LZ4_createHC (deprecated), LZ4_freeHC  (deprecated)\n *  - lz4frame, lz4file : All LZ4F_* functions\n */\n#if defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION)\n#  define ALLOC(s)          lz4_error_memory_allocation_is_disabled\n#  define ALLOC_AND_ZERO(s) lz4_error_memory_allocation_is_disabled\n#  define FREEMEM(p)        lz4_error_memory_allocation_is_disabled\n#elif defined(LZ4_USER_MEMORY_FUNCTIONS)\n/* memory management functions can be customized by user project.\n * Below functions must exist somewhere in the Project\n * and be available at link time */\nvoid* LZ4_malloc(size_t s);\nvoid* LZ4_calloc(size_t n, size_t s);\nvoid  LZ4_free(void* p);\n# define ALLOC(s)          LZ4_malloc(s)\n# define ALLOC_AND_ZERO(s) LZ4_calloc(1,s)\n# define FREEMEM(p)        LZ4_free(p)\n#else\n# include <stdlib.h>   /* malloc, calloc, free */\n# define ALLOC(s)          malloc(s)\n# define ALLOC_AND_ZERO(s) calloc(1,s)\n# define FREEMEM(p)        free(p)\n#endif\n\n#if ! LZ4_FREESTANDING\n#  include <string.h>   /* memset, memcpy */\n#endif\n#if !defined(LZ4_memset)\n#  define LZ4_memset(p,v,s) memset((p),(v),(s))\n#endif\n#define MEM_INIT(p,v,s)   LZ4_memset((p),(v),(s))\n\n\n/*-************************************\n*  Common Constants\n**************************************/\n#define MINMATCH 4\n\n#define WILDCOPYLENGTH 8\n#define LASTLITERALS   5   /* see ../doc/lz4_Block_format.md#parsing-restrictions */\n#define MFLIMIT       12   /* see ../doc/lz4_Block_format.md#parsing-restrictions */\n#define MATCH_SAFEGUARD_DISTANCE  ((2*WILDCOPYLENGTH) - MINMATCH)   /* ensure it's possible to write 2 x wildcopyLength without overflowing output buffer */\n#define FASTLOOP_SAFE_DISTANCE 64\nstatic const int LZ4_minLength = (MFLIMIT+1);\n\n#define KB *(1 <<10)\n#define MB *(1 <<20)\n#define GB *(1U<<30)\n\n#define LZ4_DISTANCE_ABSOLUTE_MAX 65535\n#if (LZ4_DISTANCE_MAX > LZ4_DISTANCE_ABSOLUTE_MAX)   /* max supported by LZ4 format */\n#  error \"LZ4_DISTANCE_MAX is too big : must be <= 65535\"\n#endif\n\n#define ML_BITS  4\n#define ML_MASK  ((1U<<ML_BITS)-1)\n#define RUN_BITS (8-ML_BITS)\n#define RUN_MASK ((1U<<RUN_BITS)-1)\n\n\n/*-************************************\n*  Error detection\n**************************************/\n#if defined(LZ4_DEBUG) && (LZ4_DEBUG>=1)\n#  include <assert.h>\n#else\n#  ifndef assert\n#    define assert(condition) ((void)0)\n#  endif\n#endif\n\n#define LZ4_STATIC_ASSERT(c)   { enum { LZ4_static_assert = 1/(int)(!!(c)) }; }   /* use after variable declarations */\n\n#if defined(LZ4_DEBUG) && (LZ4_DEBUG>=2)\n#  include <stdio.h>\n   static int g_debuglog_enable = 1;\n#  define DEBUGLOG(l, ...) {                          \\\n        if ((g_debuglog_enable) && (l<=LZ4_DEBUG)) {  \\\n            fprintf(stderr, __FILE__ \": \");           \\\n            fprintf(stderr, __VA_ARGS__);             \\\n            fprintf(stderr, \" \\n\");                   \\\n    }   }\n#else\n#  define DEBUGLOG(l, ...) {}    /* disabled */\n#endif\n\nstatic int LZ4_isAligned(const void* ptr, size_t alignment)\n{\n    return ((size_t)ptr & (alignment -1)) == 0;\n}\n\n\n/*-************************************\n*  Types\n**************************************/\n#include <limits.h>\n#if defined(__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */)\n# include <stdint.h>\n  typedef  uint8_t BYTE;\n  typedef uint16_t U16;\n  typedef uint32_t U32;\n  typedef  int32_t S32;\n  typedef uint64_t U64;\n  typedef uintptr_t uptrval;\n#else\n# if UINT_MAX != 4294967295UL\n#   error \"LZ4 code (when not C++ or C99) assumes that sizeof(int) == 4\"\n# endif\n  typedef unsigned char       BYTE;\n  typedef unsigned short      U16;\n  typedef unsigned int        U32;\n  typedef   signed int        S32;\n  typedef unsigned long long  U64;\n  typedef size_t              uptrval;   /* generally true, except OpenVMS-64 */\n#endif\n\n#if defined(__x86_64__)\n  typedef U64    reg_t;   /* 64-bits in x32 mode */\n#else\n  typedef size_t reg_t;   /* 32-bits in x32 mode */\n#endif\n\ntypedef enum {\n    notLimited = 0,\n    limitedOutput = 1,\n    fillOutput = 2\n} limitedOutput_directive;\n\nnamespace tracy\n{\n\n/*-************************************\n*  Reading and writing into memory\n**************************************/\n\n/**\n * LZ4 relies on memcpy with a constant size being inlined. In freestanding\n * environments, the compiler can't assume the implementation of memcpy() is\n * standard compliant, so it can't apply its specialized memcpy() inlining\n * logic. When possible, use __builtin_memcpy() to tell the compiler to analyze\n * memcpy() as if it were standard compliant, so it can inline it in freestanding\n * environments. This is needed when decompressing the Linux Kernel, for example.\n */\n#if !defined(LZ4_memcpy)\n#  if defined(__GNUC__) && (__GNUC__ >= 4)\n#    define LZ4_memcpy(dst, src, size) __builtin_memcpy(dst, src, size)\n#  else\n#    define LZ4_memcpy(dst, src, size) memcpy(dst, src, size)\n#  endif\n#endif\n\n#if !defined(LZ4_memmove)\n#  if defined(__GNUC__) && (__GNUC__ >= 4)\n#    define LZ4_memmove __builtin_memmove\n#  else\n#    define LZ4_memmove memmove\n#  endif\n#endif\n\nstatic unsigned LZ4_isLittleEndian(void)\n{\n    const union { U32 u; BYTE c[4]; } one = { 1 };   /* don't use static : performance detrimental */\n    return one.c[0];\n}\n\n\n#if defined(LZ4_FORCE_MEMORY_ACCESS) && (LZ4_FORCE_MEMORY_ACCESS==2)\n/* lie to the compiler about data alignment; use with caution */\n\nstatic U16 LZ4_read16(const void* memPtr) { return *(const U16*) memPtr; }\nstatic U32 LZ4_read32(const void* memPtr) { return *(const U32*) memPtr; }\nstatic reg_t LZ4_read_ARCH(const void* memPtr) { return *(const reg_t*) memPtr; }\n\nstatic void LZ4_write16(void* memPtr, U16 value) { *(U16*)memPtr = value; }\nstatic void LZ4_write32(void* memPtr, U32 value) { *(U32*)memPtr = value; }\n\n#elif defined(LZ4_FORCE_MEMORY_ACCESS) && (LZ4_FORCE_MEMORY_ACCESS==1)\n\n/* __pack instructions are safer, but compiler specific, hence potentially problematic for some compilers */\n/* currently only defined for gcc and icc */\ntypedef union { U16 u16; U32 u32; reg_t uArch; } __attribute__((packed)) LZ4_unalign;\n\nstatic U16 LZ4_read16(const void* ptr) { return ((const LZ4_unalign*)ptr)->u16; }\nstatic U32 LZ4_read32(const void* ptr) { return ((const LZ4_unalign*)ptr)->u32; }\nstatic reg_t LZ4_read_ARCH(const void* ptr) { return ((const LZ4_unalign*)ptr)->uArch; }\n\nstatic void LZ4_write16(void* memPtr, U16 value) { ((LZ4_unalign*)memPtr)->u16 = value; }\nstatic void LZ4_write32(void* memPtr, U32 value) { ((LZ4_unalign*)memPtr)->u32 = value; }\n\n#else  /* safe and portable access using memcpy() */\n\nstatic U16 LZ4_read16(const void* memPtr)\n{\n    U16 val; LZ4_memcpy(&val, memPtr, sizeof(val)); return val;\n}\n\nstatic U32 LZ4_read32(const void* memPtr)\n{\n    U32 val; LZ4_memcpy(&val, memPtr, sizeof(val)); return val;\n}\n\nstatic reg_t LZ4_read_ARCH(const void* memPtr)\n{\n    reg_t val; LZ4_memcpy(&val, memPtr, sizeof(val)); return val;\n}\n\nstatic void LZ4_write16(void* memPtr, U16 value)\n{\n    LZ4_memcpy(memPtr, &value, sizeof(value));\n}\n\nstatic void LZ4_write32(void* memPtr, U32 value)\n{\n    LZ4_memcpy(memPtr, &value, sizeof(value));\n}\n\n#endif /* LZ4_FORCE_MEMORY_ACCESS */\n\n\nstatic U16 LZ4_readLE16(const void* memPtr)\n{\n    if (LZ4_isLittleEndian()) {\n        return LZ4_read16(memPtr);\n    } else {\n        const BYTE* p = (const BYTE*)memPtr;\n        return (U16)((U16)p[0] + (p[1]<<8));\n    }\n}\n\nstatic void LZ4_writeLE16(void* memPtr, U16 value)\n{\n    if (LZ4_isLittleEndian()) {\n        LZ4_write16(memPtr, value);\n    } else {\n        BYTE* p = (BYTE*)memPtr;\n        p[0] = (BYTE) value;\n        p[1] = (BYTE)(value>>8);\n    }\n}\n\n/* customized variant of memcpy, which can overwrite up to 8 bytes beyond dstEnd */\nLZ4_FORCE_INLINE\nvoid LZ4_wildCopy8(void* dstPtr, const void* srcPtr, void* dstEnd)\n{\n    BYTE* d = (BYTE*)dstPtr;\n    const BYTE* s = (const BYTE*)srcPtr;\n    BYTE* const e = (BYTE*)dstEnd;\n\n    do { LZ4_memcpy(d,s,8); d+=8; s+=8; } while (d<e);\n}\n\nstatic const unsigned inc32table[8] = {0, 1, 2,  1,  0,  4, 4, 4};\nstatic const int      dec64table[8] = {0, 0, 0, -1, -4,  1, 2, 3};\n\n\n#ifndef LZ4_FAST_DEC_LOOP\n#  if defined __i386__ || defined _M_IX86 || defined __x86_64__ || defined _M_X64\n#    define LZ4_FAST_DEC_LOOP 1\n#  elif defined(__aarch64__) && defined(__APPLE__)\n#    define LZ4_FAST_DEC_LOOP 1\n#  elif defined(__aarch64__) && !defined(__clang__)\n     /* On non-Apple aarch64, we disable this optimization for clang because\n      * on certain mobile chipsets, performance is reduced with clang. For\n      * more information refer to https://github.com/lz4/lz4/pull/707 */\n#    define LZ4_FAST_DEC_LOOP 1\n#  else\n#    define LZ4_FAST_DEC_LOOP 0\n#  endif\n#endif\n\n#if LZ4_FAST_DEC_LOOP\n\nLZ4_FORCE_INLINE void\nLZ4_memcpy_using_offset_base(BYTE* dstPtr, const BYTE* srcPtr, BYTE* dstEnd, const size_t offset)\n{\n    assert(srcPtr + offset == dstPtr);\n    if (offset < 8) {\n        LZ4_write32(dstPtr, 0);   /* silence an msan warning when offset==0 */\n        dstPtr[0] = srcPtr[0];\n        dstPtr[1] = srcPtr[1];\n        dstPtr[2] = srcPtr[2];\n        dstPtr[3] = srcPtr[3];\n        srcPtr += inc32table[offset];\n        LZ4_memcpy(dstPtr+4, srcPtr, 4);\n        srcPtr -= dec64table[offset];\n        dstPtr += 8;\n    } else {\n        LZ4_memcpy(dstPtr, srcPtr, 8);\n        dstPtr += 8;\n        srcPtr += 8;\n    }\n\n    LZ4_wildCopy8(dstPtr, srcPtr, dstEnd);\n}\n\n/* customized variant of memcpy, which can overwrite up to 32 bytes beyond dstEnd\n * this version copies two times 16 bytes (instead of one time 32 bytes)\n * because it must be compatible with offsets >= 16. */\nLZ4_FORCE_INLINE void\nLZ4_wildCopy32(void* dstPtr, const void* srcPtr, void* dstEnd)\n{\n    BYTE* d = (BYTE*)dstPtr;\n    const BYTE* s = (const BYTE*)srcPtr;\n    BYTE* const e = (BYTE*)dstEnd;\n\n    do { LZ4_memcpy(d,s,16); LZ4_memcpy(d+16,s+16,16); d+=32; s+=32; } while (d<e);\n}\n\n/* LZ4_memcpy_using_offset()  presumes :\n * - dstEnd >= dstPtr + MINMATCH\n * - there is at least 8 bytes available to write after dstEnd */\nLZ4_FORCE_INLINE void\nLZ4_memcpy_using_offset(BYTE* dstPtr, const BYTE* srcPtr, BYTE* dstEnd, const size_t offset)\n{\n    BYTE v[8];\n\n    assert(dstEnd >= dstPtr + MINMATCH);\n\n    switch(offset) {\n    case 1:\n        MEM_INIT(v, *srcPtr, 8);\n        break;\n    case 2:\n        LZ4_memcpy(v, srcPtr, 2);\n        LZ4_memcpy(&v[2], srcPtr, 2);\n#if defined(_MSC_VER) && (_MSC_VER <= 1933) /* MSVC 2022 ver 17.3 or earlier */\n#  pragma warning(push)\n#  pragma warning(disable : 6385) /* warning C6385: Reading invalid data from 'v'. */\n#endif\n        LZ4_memcpy(&v[4], v, 4);\n#if defined(_MSC_VER) && (_MSC_VER <= 1933) /* MSVC 2022 ver 17.3 or earlier */\n#  pragma warning(pop)\n#endif\n        break;\n    case 4:\n        LZ4_memcpy(v, srcPtr, 4);\n        LZ4_memcpy(&v[4], srcPtr, 4);\n        break;\n    default:\n        LZ4_memcpy_using_offset_base(dstPtr, srcPtr, dstEnd, offset);\n        return;\n    }\n\n    LZ4_memcpy(dstPtr, v, 8);\n    dstPtr += 8;\n    while (dstPtr < dstEnd) {\n        LZ4_memcpy(dstPtr, v, 8);\n        dstPtr += 8;\n    }\n}\n#endif\n\n\n/*-************************************\n*  Common functions\n**************************************/\nLZ4_FORCE_INLINE unsigned LZ4_NbCommonBytes (reg_t val)\n{\n    assert(val != 0);\n    if (LZ4_isLittleEndian()) {\n        if (sizeof(val) == 8) {\n#       if defined(_MSC_VER) && (_MSC_VER >= 1800) && (defined(_M_AMD64) && !defined(_M_ARM64EC)) && !defined(LZ4_FORCE_SW_BITCOUNT)\n/*-*************************************************************************************************\n* ARM64EC is a Microsoft-designed ARM64 ABI compatible with AMD64 applications on ARM64 Windows 11.\n* The ARM64EC ABI does not support AVX/AVX2/AVX512 instructions, nor their relevant intrinsics\n* including _tzcnt_u64. Therefore, we need to neuter the _tzcnt_u64 code path for ARM64EC.\n****************************************************************************************************/\n#         if defined(__clang__) && (__clang_major__ < 10)\n            /* Avoid undefined clang-cl intrinsics issue.\n             * See https://github.com/lz4/lz4/pull/1017 for details. */\n            return (unsigned)__builtin_ia32_tzcnt_u64(val) >> 3;\n#         else\n            /* x64 CPUS without BMI support interpret `TZCNT` as `REP BSF` */\n            return (unsigned)_tzcnt_u64(val) >> 3;\n#         endif\n#       elif defined(_MSC_VER) && defined(_WIN64) && !defined(LZ4_FORCE_SW_BITCOUNT)\n            unsigned long r = 0;\n            _BitScanForward64(&r, (U64)val);\n            return (unsigned)r >> 3;\n#       elif (defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 3) || \\\n                            ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 4))))) && \\\n                                        !defined(LZ4_FORCE_SW_BITCOUNT)\n            return (unsigned)__builtin_ctzll((U64)val) >> 3;\n#       else\n            const U64 m = 0x0101010101010101ULL;\n            val ^= val - 1;\n            return (unsigned)(((U64)((val & (m - 1)) * m)) >> 56);\n#       endif\n        } else /* 32 bits */ {\n#       if defined(_MSC_VER) && (_MSC_VER >= 1400) && !defined(LZ4_FORCE_SW_BITCOUNT)\n            unsigned long r;\n            _BitScanForward(&r, (U32)val);\n            return (unsigned)r >> 3;\n#       elif (defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 3) || \\\n                            ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 4))))) && \\\n                        !defined(__TINYC__) && !defined(LZ4_FORCE_SW_BITCOUNT)\n            return (unsigned)__builtin_ctz((U32)val) >> 3;\n#       else\n            const U32 m = 0x01010101;\n            return (unsigned)((((val - 1) ^ val) & (m - 1)) * m) >> 24;\n#       endif\n        }\n    } else   /* Big Endian CPU */ {\n        if (sizeof(val)==8) {\n#       if (defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 3) || \\\n                            ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 4))))) && \\\n                        !defined(__TINYC__) && !defined(LZ4_FORCE_SW_BITCOUNT)\n            return (unsigned)__builtin_clzll((U64)val) >> 3;\n#       else\n#if 1\n            /* this method is probably faster,\n             * but adds a 128 bytes lookup table */\n            static const unsigned char ctz7_tab[128] = {\n                7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,\n                4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,\n                5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,\n                4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,\n                6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,\n                4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,\n                5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,\n                4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,\n            };\n            U64 const mask = 0x0101010101010101ULL;\n            U64 const t = (((val >> 8) - mask) | val) & mask;\n            return ctz7_tab[(t * 0x0080402010080402ULL) >> 57];\n#else\n            /* this method doesn't consume memory space like the previous one,\n             * but it contains several branches,\n             * that may end up slowing execution */\n            static const U32 by32 = sizeof(val)*4;  /* 32 on 64 bits (goal), 16 on 32 bits.\n            Just to avoid some static analyzer complaining about shift by 32 on 32-bits target.\n            Note that this code path is never triggered in 32-bits mode. */\n            unsigned r;\n            if (!(val>>by32)) { r=4; } else { r=0; val>>=by32; }\n            if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; }\n            r += (!val);\n            return r;\n#endif\n#       endif\n        } else /* 32 bits */ {\n#       if (defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 3) || \\\n                            ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 4))))) && \\\n                                        !defined(LZ4_FORCE_SW_BITCOUNT)\n            return (unsigned)__builtin_clz((U32)val) >> 3;\n#       else\n            val >>= 8;\n            val = ((((val + 0x00FFFF00) | 0x00FFFFFF) + val) |\n              (val + 0x00FF0000)) >> 24;\n            return (unsigned)val ^ 3;\n#       endif\n        }\n    }\n}\n\n\n#define STEPSIZE sizeof(reg_t)\nLZ4_FORCE_INLINE\nunsigned LZ4_count(const BYTE* pIn, const BYTE* pMatch, const BYTE* pInLimit)\n{\n    const BYTE* const pStart = pIn;\n\n    if (likely(pIn < pInLimit-(STEPSIZE-1))) {\n        reg_t const diff = LZ4_read_ARCH(pMatch) ^ LZ4_read_ARCH(pIn);\n        if (!diff) {\n            pIn+=STEPSIZE; pMatch+=STEPSIZE;\n        } else {\n            return LZ4_NbCommonBytes(diff);\n    }   }\n\n    while (likely(pIn < pInLimit-(STEPSIZE-1))) {\n        reg_t const diff = LZ4_read_ARCH(pMatch) ^ LZ4_read_ARCH(pIn);\n        if (!diff) { pIn+=STEPSIZE; pMatch+=STEPSIZE; continue; }\n        pIn += LZ4_NbCommonBytes(diff);\n        return (unsigned)(pIn - pStart);\n    }\n\n    if ((STEPSIZE==8) && (pIn<(pInLimit-3)) && (LZ4_read32(pMatch) == LZ4_read32(pIn))) { pIn+=4; pMatch+=4; }\n    if ((pIn<(pInLimit-1)) && (LZ4_read16(pMatch) == LZ4_read16(pIn))) { pIn+=2; pMatch+=2; }\n    if ((pIn<pInLimit) && (*pMatch == *pIn)) pIn++;\n    return (unsigned)(pIn - pStart);\n}\n\n\n#ifndef LZ4_COMMONDEFS_ONLY\n/*-************************************\n*  Local Constants\n**************************************/\nstatic const int LZ4_64Klimit = ((64 KB) + (MFLIMIT-1));\nstatic const U32 LZ4_skipTrigger = 6;  /* Increase this value ==> compression run slower on incompressible data */\n\n\n/*-************************************\n*  Local Structures and types\n**************************************/\ntypedef enum { clearedTable = 0, byPtr, byU32, byU16 } tableType_t;\n\n/**\n * This enum distinguishes several different modes of accessing previous\n * content in the stream.\n *\n * - noDict        : There is no preceding content.\n * - withPrefix64k : Table entries up to ctx->dictSize before the current blob\n *                   blob being compressed are valid and refer to the preceding\n *                   content (of length ctx->dictSize), which is available\n *                   contiguously preceding in memory the content currently\n *                   being compressed.\n * - usingExtDict  : Like withPrefix64k, but the preceding content is somewhere\n *                   else in memory, starting at ctx->dictionary with length\n *                   ctx->dictSize.\n * - usingDictCtx  : Everything concerning the preceding content is\n *                   in a separate context, pointed to by ctx->dictCtx.\n *                   ctx->dictionary, ctx->dictSize, and table entries\n *                   in the current context that refer to positions\n *                   preceding the beginning of the current compression are\n *                   ignored. Instead, ctx->dictCtx->dictionary and ctx->dictCtx\n *                   ->dictSize describe the location and size of the preceding\n *                   content, and matches are found by looking in the ctx\n *                   ->dictCtx->hashTable.\n */\ntypedef enum { noDict = 0, withPrefix64k, usingExtDict, usingDictCtx } dict_directive;\ntypedef enum { noDictIssue = 0, dictSmall } dictIssue_directive;\n\n\n/*-************************************\n*  Local Utils\n**************************************/\nint LZ4_versionNumber (void) { return LZ4_VERSION_NUMBER; }\nconst char* LZ4_versionString(void) { return LZ4_VERSION_STRING; }\nint LZ4_compressBound(int isize)  { return LZ4_COMPRESSBOUND(isize); }\nint LZ4_sizeofState(void) { return sizeof(LZ4_stream_t); }\n\n\n/*-****************************************\n*  Internal Definitions, used only in Tests\n*******************************************/\n\nint LZ4_compress_forceExtDict (LZ4_stream_t* LZ4_dict, const char* source, char* dest, int srcSize);\n\nint LZ4_decompress_safe_forceExtDict(const char* source, char* dest,\n                                     int compressedSize, int maxOutputSize,\n                                     const void* dictStart, size_t dictSize);\nint LZ4_decompress_safe_partial_forceExtDict(const char* source, char* dest,\n                                     int compressedSize, int targetOutputSize, int dstCapacity,\n                                     const void* dictStart, size_t dictSize);\n\n/*-******************************\n*  Compression functions\n********************************/\nLZ4_FORCE_INLINE U32 LZ4_hash4(U32 sequence, tableType_t const tableType)\n{\n    if (tableType == byU16)\n        return ((sequence * 2654435761U) >> ((MINMATCH*8)-(LZ4_HASHLOG+1)));\n    else\n        return ((sequence * 2654435761U) >> ((MINMATCH*8)-LZ4_HASHLOG));\n}\n\nLZ4_FORCE_INLINE U32 LZ4_hash5(U64 sequence, tableType_t const tableType)\n{\n    const U32 hashLog = (tableType == byU16) ? LZ4_HASHLOG+1 : LZ4_HASHLOG;\n    if (LZ4_isLittleEndian()) {\n        const U64 prime5bytes = 889523592379ULL;\n        return (U32)(((sequence << 24) * prime5bytes) >> (64 - hashLog));\n    } else {\n        const U64 prime8bytes = 11400714785074694791ULL;\n        return (U32)(((sequence >> 24) * prime8bytes) >> (64 - hashLog));\n    }\n}\n\nLZ4_FORCE_INLINE U32 LZ4_hashPosition(const void* const p, tableType_t const tableType)\n{\n    if ((sizeof(reg_t)==8) && (tableType != byU16)) return LZ4_hash5(LZ4_read_ARCH(p), tableType);\n    return LZ4_hash4(LZ4_read32(p), tableType);\n}\n\nLZ4_FORCE_INLINE void LZ4_clearHash(U32 h, void* tableBase, tableType_t const tableType)\n{\n    switch (tableType)\n    {\n    default: /* fallthrough */\n    case clearedTable: { /* illegal! */ assert(0); return; }\n    case byPtr: { const BYTE** hashTable = (const BYTE**)tableBase; hashTable[h] = NULL; return; }\n    case byU32: { U32* hashTable = (U32*) tableBase; hashTable[h] = 0; return; }\n    case byU16: { U16* hashTable = (U16*) tableBase; hashTable[h] = 0; return; }\n    }\n}\n\nLZ4_FORCE_INLINE void LZ4_putIndexOnHash(U32 idx, U32 h, void* tableBase, tableType_t const tableType)\n{\n    switch (tableType)\n    {\n    default: /* fallthrough */\n    case clearedTable: /* fallthrough */\n    case byPtr: { /* illegal! */ assert(0); return; }\n    case byU32: { U32* hashTable = (U32*) tableBase; hashTable[h] = idx; return; }\n    case byU16: { U16* hashTable = (U16*) tableBase; assert(idx < 65536); hashTable[h] = (U16)idx; return; }\n    }\n}\n\nLZ4_FORCE_INLINE void LZ4_putPositionOnHash(const BYTE* p, U32 h,\n                                  void* tableBase, tableType_t const tableType,\n                            const BYTE* srcBase)\n{\n    switch (tableType)\n    {\n    case clearedTable: { /* illegal! */ assert(0); return; }\n    case byPtr: { const BYTE** hashTable = (const BYTE**)tableBase; hashTable[h] = p; return; }\n    case byU32: { U32* hashTable = (U32*) tableBase; hashTable[h] = (U32)(p-srcBase); return; }\n    case byU16: { U16* hashTable = (U16*) tableBase; hashTable[h] = (U16)(p-srcBase); return; }\n    }\n}\n\nLZ4_FORCE_INLINE void LZ4_putPosition(const BYTE* p, void* tableBase, tableType_t tableType, const BYTE* srcBase)\n{\n    U32 const h = LZ4_hashPosition(p, tableType);\n    LZ4_putPositionOnHash(p, h, tableBase, tableType, srcBase);\n}\n\n/* LZ4_getIndexOnHash() :\n * Index of match position registered in hash table.\n * hash position must be calculated by using base+index, or dictBase+index.\n * Assumption 1 : only valid if tableType == byU32 or byU16.\n * Assumption 2 : h is presumed valid (within limits of hash table)\n */\nLZ4_FORCE_INLINE U32 LZ4_getIndexOnHash(U32 h, const void* tableBase, tableType_t tableType)\n{\n    LZ4_STATIC_ASSERT(LZ4_MEMORY_USAGE > 2);\n    if (tableType == byU32) {\n        const U32* const hashTable = (const U32*) tableBase;\n        assert(h < (1U << (LZ4_MEMORY_USAGE-2)));\n        return hashTable[h];\n    }\n    if (tableType == byU16) {\n        const U16* const hashTable = (const U16*) tableBase;\n        assert(h < (1U << (LZ4_MEMORY_USAGE-1)));\n        return hashTable[h];\n    }\n    assert(0); return 0;  /* forbidden case */\n}\n\nstatic const BYTE* LZ4_getPositionOnHash(U32 h, const void* tableBase, tableType_t tableType, const BYTE* srcBase)\n{\n    if (tableType == byPtr) { const BYTE* const* hashTable = (const BYTE* const*) tableBase; return hashTable[h]; }\n    if (tableType == byU32) { const U32* const hashTable = (const U32*) tableBase; return hashTable[h] + srcBase; }\n    { const U16* const hashTable = (const U16*) tableBase; return hashTable[h] + srcBase; }   /* default, to ensure a return */\n}\n\nLZ4_FORCE_INLINE const BYTE*\nLZ4_getPosition(const BYTE* p,\n                const void* tableBase, tableType_t tableType,\n                const BYTE* srcBase)\n{\n    U32 const h = LZ4_hashPosition(p, tableType);\n    return LZ4_getPositionOnHash(h, tableBase, tableType, srcBase);\n}\n\nLZ4_FORCE_INLINE void\nLZ4_prepareTable(LZ4_stream_t_internal* const cctx,\n           const int inputSize,\n           const tableType_t tableType) {\n    /* If the table hasn't been used, it's guaranteed to be zeroed out, and is\n     * therefore safe to use no matter what mode we're in. Otherwise, we figure\n     * out if it's safe to leave as is or whether it needs to be reset.\n     */\n    if ((tableType_t)cctx->tableType != clearedTable) {\n        assert(inputSize >= 0);\n        if ((tableType_t)cctx->tableType != tableType\n          || ((tableType == byU16) && cctx->currentOffset + (unsigned)inputSize >= 0xFFFFU)\n          || ((tableType == byU32) && cctx->currentOffset > 1 GB)\n          || tableType == byPtr\n          || inputSize >= 4 KB)\n        {\n            DEBUGLOG(4, \"LZ4_prepareTable: Resetting table in %p\", cctx);\n            MEM_INIT(cctx->hashTable, 0, LZ4_HASHTABLESIZE);\n            cctx->currentOffset = 0;\n            cctx->tableType = (U32)clearedTable;\n        } else {\n            DEBUGLOG(4, \"LZ4_prepareTable: Re-use hash table (no reset)\");\n        }\n    }\n\n    /* Adding a gap, so all previous entries are > LZ4_DISTANCE_MAX back,\n     * is faster than compressing without a gap.\n     * However, compressing with currentOffset == 0 is faster still,\n     * so we preserve that case.\n     */\n    if (cctx->currentOffset != 0 && tableType == byU32) {\n        DEBUGLOG(5, \"LZ4_prepareTable: adding 64KB to currentOffset\");\n        cctx->currentOffset += 64 KB;\n    }\n\n    /* Finally, clear history */\n    cctx->dictCtx = NULL;\n    cctx->dictionary = NULL;\n    cctx->dictSize = 0;\n}\n\n/** LZ4_compress_generic() :\n *  inlined, to ensure branches are decided at compilation time.\n *  Presumed already validated at this stage:\n *  - source != NULL\n *  - inputSize > 0\n */\nLZ4_FORCE_INLINE int LZ4_compress_generic_validated(\n                 LZ4_stream_t_internal* const cctx,\n                 const char* const source,\n                 char* const dest,\n                 const int inputSize,\n                 int*  inputConsumed, /* only written when outputDirective == fillOutput */\n                 const int maxOutputSize,\n                 const limitedOutput_directive outputDirective,\n                 const tableType_t tableType,\n                 const dict_directive dictDirective,\n                 const dictIssue_directive dictIssue,\n                 const int acceleration)\n{\n    int result;\n    const BYTE* ip = (const BYTE*) source;\n\n    U32 const startIndex = cctx->currentOffset;\n    const BYTE* base = (const BYTE*) source - startIndex;\n    const BYTE* lowLimit;\n\n    const LZ4_stream_t_internal* dictCtx = (const LZ4_stream_t_internal*) cctx->dictCtx;\n    const BYTE* const dictionary =\n        dictDirective == usingDictCtx ? dictCtx->dictionary : cctx->dictionary;\n    const U32 dictSize =\n        dictDirective == usingDictCtx ? dictCtx->dictSize : cctx->dictSize;\n    const U32 dictDelta = (dictDirective == usingDictCtx) ? startIndex - dictCtx->currentOffset : 0;   /* make indexes in dictCtx comparable with index in current context */\n\n    int const maybe_extMem = (dictDirective == usingExtDict) || (dictDirective == usingDictCtx);\n    U32 const prefixIdxLimit = startIndex - dictSize;   /* used when dictDirective == dictSmall */\n    const BYTE* const dictEnd = dictionary ? dictionary + dictSize : dictionary;\n    const BYTE* anchor = (const BYTE*) source;\n    const BYTE* const iend = ip + inputSize;\n    const BYTE* const mflimitPlusOne = iend - MFLIMIT + 1;\n    const BYTE* const matchlimit = iend - LASTLITERALS;\n\n    /* the dictCtx currentOffset is indexed on the start of the dictionary,\n     * while a dictionary in the current context precedes the currentOffset */\n    const BYTE* dictBase = (dictionary == NULL) ? NULL :\n                           (dictDirective == usingDictCtx) ?\n                            dictionary + dictSize - dictCtx->currentOffset :\n                            dictionary + dictSize - startIndex;\n\n    BYTE* op = (BYTE*) dest;\n    BYTE* const olimit = op + maxOutputSize;\n\n    U32 offset = 0;\n    U32 forwardH;\n\n    DEBUGLOG(5, \"LZ4_compress_generic_validated: srcSize=%i, tableType=%u\", inputSize, tableType);\n    assert(ip != NULL);\n    /* If init conditions are not met, we don't have to mark stream\n     * as having dirty context, since no action was taken yet */\n    if (outputDirective == fillOutput && maxOutputSize < 1) { return 0; } /* Impossible to store anything */\n    if ((tableType == byU16) && (inputSize>=LZ4_64Klimit)) { return 0; }  /* Size too large (not within 64K limit) */\n    if (tableType==byPtr) assert(dictDirective==noDict);      /* only supported use case with byPtr */\n    assert(acceleration >= 1);\n\n    lowLimit = (const BYTE*)source - (dictDirective == withPrefix64k ? dictSize : 0);\n\n    /* Update context state */\n    if (dictDirective == usingDictCtx) {\n        /* Subsequent linked blocks can't use the dictionary. */\n        /* Instead, they use the block we just compressed. */\n        cctx->dictCtx = NULL;\n        cctx->dictSize = (U32)inputSize;\n    } else {\n        cctx->dictSize += (U32)inputSize;\n    }\n    cctx->currentOffset += (U32)inputSize;\n    cctx->tableType = (U32)tableType;\n\n    if (inputSize<LZ4_minLength) goto _last_literals;        /* Input too small, no compression (all literals) */\n\n    /* First Byte */\n    LZ4_putPosition(ip, cctx->hashTable, tableType, base);\n    ip++; forwardH = LZ4_hashPosition(ip, tableType);\n\n    /* Main Loop */\n    for ( ; ; ) {\n        const BYTE* match;\n        BYTE* token;\n        const BYTE* filledIp;\n\n        /* Find a match */\n        if (tableType == byPtr) {\n            const BYTE* forwardIp = ip;\n            int step = 1;\n            int searchMatchNb = acceleration << LZ4_skipTrigger;\n            do {\n                U32 const h = forwardH;\n                ip = forwardIp;\n                forwardIp += step;\n                step = (searchMatchNb++ >> LZ4_skipTrigger);\n\n                if (unlikely(forwardIp > mflimitPlusOne)) goto _last_literals;\n                assert(ip < mflimitPlusOne);\n\n                match = LZ4_getPositionOnHash(h, cctx->hashTable, tableType, base);\n                forwardH = LZ4_hashPosition(forwardIp, tableType);\n                LZ4_putPositionOnHash(ip, h, cctx->hashTable, tableType, base);\n\n            } while ( (match+LZ4_DISTANCE_MAX < ip)\n                   || (LZ4_read32(match) != LZ4_read32(ip)) );\n\n        } else {   /* byU32, byU16 */\n\n            const BYTE* forwardIp = ip;\n            int step = 1;\n            int searchMatchNb = acceleration << LZ4_skipTrigger;\n            do {\n                U32 const h = forwardH;\n                U32 const current = (U32)(forwardIp - base);\n                U32 matchIndex = LZ4_getIndexOnHash(h, cctx->hashTable, tableType);\n                assert(matchIndex <= current);\n                assert(forwardIp - base < (ptrdiff_t)(2 GB - 1));\n                ip = forwardIp;\n                forwardIp += step;\n                step = (searchMatchNb++ >> LZ4_skipTrigger);\n\n                if (unlikely(forwardIp > mflimitPlusOne)) goto _last_literals;\n                assert(ip < mflimitPlusOne);\n\n                if (dictDirective == usingDictCtx) {\n                    if (matchIndex < startIndex) {\n                        /* there was no match, try the dictionary */\n                        assert(tableType == byU32);\n                        matchIndex = LZ4_getIndexOnHash(h, dictCtx->hashTable, byU32);\n                        match = dictBase + matchIndex;\n                        matchIndex += dictDelta;   /* make dictCtx index comparable with current context */\n                        lowLimit = dictionary;\n                    } else {\n                        match = base + matchIndex;\n                        lowLimit = (const BYTE*)source;\n                    }\n                } else if (dictDirective == usingExtDict) {\n                    if (matchIndex < startIndex) {\n                        DEBUGLOG(7, \"extDict candidate: matchIndex=%5u  <  startIndex=%5u\", matchIndex, startIndex);\n                        assert(startIndex - matchIndex >= MINMATCH);\n                        assert(dictBase);\n                        match = dictBase + matchIndex;\n                        lowLimit = dictionary;\n                    } else {\n                        match = base + matchIndex;\n                        lowLimit = (const BYTE*)source;\n                    }\n                } else {   /* single continuous memory segment */\n                    match = base + matchIndex;\n                }\n                forwardH = LZ4_hashPosition(forwardIp, tableType);\n                LZ4_putIndexOnHash(current, h, cctx->hashTable, tableType);\n\n                DEBUGLOG(7, \"candidate at pos=%u  (offset=%u \\n\", matchIndex, current - matchIndex);\n                if ((dictIssue == dictSmall) && (matchIndex < prefixIdxLimit)) { continue; }    /* match outside of valid area */\n                assert(matchIndex < current);\n                if ( ((tableType != byU16) || (LZ4_DISTANCE_MAX < LZ4_DISTANCE_ABSOLUTE_MAX))\n                  && (matchIndex+LZ4_DISTANCE_MAX < current)) {\n                    continue;\n                } /* too far */\n                assert((current - matchIndex) <= LZ4_DISTANCE_MAX);  /* match now expected within distance */\n\n                if (LZ4_read32(match) == LZ4_read32(ip)) {\n                    if (maybe_extMem) offset = current - matchIndex;\n                    break;   /* match found */\n                }\n\n            } while(1);\n        }\n\n        /* Catch up */\n        filledIp = ip;\n        while (((ip>anchor) & (match > lowLimit)) && (unlikely(ip[-1]==match[-1]))) { ip--; match--; }\n\n        /* Encode Literals */\n        {   unsigned const litLength = (unsigned)(ip - anchor);\n            token = op++;\n            if ((outputDirective == limitedOutput) &&  /* Check output buffer overflow */\n                (unlikely(op + litLength + (2 + 1 + LASTLITERALS) + (litLength/255) > olimit)) ) {\n                return 0;   /* cannot compress within `dst` budget. Stored indexes in hash table are nonetheless fine */\n            }\n            if ((outputDirective == fillOutput) &&\n                (unlikely(op + (litLength+240)/255 /* litlen */ + litLength /* literals */ + 2 /* offset */ + 1 /* token */ + MFLIMIT - MINMATCH /* min last literals so last match is <= end - MFLIMIT */ > olimit))) {\n                op--;\n                goto _last_literals;\n            }\n            if (litLength >= RUN_MASK) {\n                int len = (int)(litLength - RUN_MASK);\n                *token = (RUN_MASK<<ML_BITS);\n                for(; len >= 255 ; len-=255) *op++ = 255;\n                *op++ = (BYTE)len;\n            }\n            else *token = (BYTE)(litLength<<ML_BITS);\n\n            /* Copy Literals */\n            LZ4_wildCopy8(op, anchor, op+litLength);\n            op+=litLength;\n            DEBUGLOG(6, \"seq.start:%i, literals=%u, match.start:%i\",\n                        (int)(anchor-(const BYTE*)source), litLength, (int)(ip-(const BYTE*)source));\n        }\n\n_next_match:\n        /* at this stage, the following variables must be correctly set :\n         * - ip : at start of LZ operation\n         * - match : at start of previous pattern occurrence; can be within current prefix, or within extDict\n         * - offset : if maybe_ext_memSegment==1 (constant)\n         * - lowLimit : must be == dictionary to mean \"match is within extDict\"; must be == source otherwise\n         * - token and *token : position to write 4-bits for match length; higher 4-bits for literal length supposed already written\n         */\n\n        if ((outputDirective == fillOutput) &&\n            (op + 2 /* offset */ + 1 /* token */ + MFLIMIT - MINMATCH /* min last literals so last match is <= end - MFLIMIT */ > olimit)) {\n            /* the match was too close to the end, rewind and go to last literals */\n            op = token;\n            goto _last_literals;\n        }\n\n        /* Encode Offset */\n        if (maybe_extMem) {   /* static test */\n            DEBUGLOG(6, \"             with offset=%u  (ext if > %i)\", offset, (int)(ip - (const BYTE*)source));\n            assert(offset <= LZ4_DISTANCE_MAX && offset > 0);\n            LZ4_writeLE16(op, (U16)offset); op+=2;\n        } else  {\n            DEBUGLOG(6, \"             with offset=%u  (same segment)\", (U32)(ip - match));\n            assert(ip-match <= LZ4_DISTANCE_MAX);\n            LZ4_writeLE16(op, (U16)(ip - match)); op+=2;\n        }\n\n        /* Encode MatchLength */\n        {   unsigned matchCode;\n\n            if ( (dictDirective==usingExtDict || dictDirective==usingDictCtx)\n              && (lowLimit==dictionary) /* match within extDict */ ) {\n                const BYTE* limit = ip + (dictEnd-match);\n                assert(dictEnd > match);\n                if (limit > matchlimit) limit = matchlimit;\n                matchCode = LZ4_count(ip+MINMATCH, match+MINMATCH, limit);\n                ip += (size_t)matchCode + MINMATCH;\n                if (ip==limit) {\n                    unsigned const more = LZ4_count(limit, (const BYTE*)source, matchlimit);\n                    matchCode += more;\n                    ip += more;\n                }\n                DEBUGLOG(6, \"             with matchLength=%u starting in extDict\", matchCode+MINMATCH);\n            } else {\n                matchCode = LZ4_count(ip+MINMATCH, match+MINMATCH, matchlimit);\n                ip += (size_t)matchCode + MINMATCH;\n                DEBUGLOG(6, \"             with matchLength=%u\", matchCode+MINMATCH);\n            }\n\n            if ((outputDirective) &&    /* Check output buffer overflow */\n                (unlikely(op + (1 + LASTLITERALS) + (matchCode+240)/255 > olimit)) ) {\n                if (outputDirective == fillOutput) {\n                    /* Match description too long : reduce it */\n                    U32 newMatchCode = 15 /* in token */ - 1 /* to avoid needing a zero byte */ + ((U32)(olimit - op) - 1 - LASTLITERALS) * 255;\n                    ip -= matchCode - newMatchCode;\n                    assert(newMatchCode < matchCode);\n                    matchCode = newMatchCode;\n                    if (unlikely(ip <= filledIp)) {\n                        /* We have already filled up to filledIp so if ip ends up less than filledIp\n                         * we have positions in the hash table beyond the current position. This is\n                         * a problem if we reuse the hash table. So we have to remove these positions\n                         * from the hash table.\n                         */\n                        const BYTE* ptr;\n                        DEBUGLOG(5, \"Clearing %u positions\", (U32)(filledIp - ip));\n                        for (ptr = ip; ptr <= filledIp; ++ptr) {\n                            U32 const h = LZ4_hashPosition(ptr, tableType);\n                            LZ4_clearHash(h, cctx->hashTable, tableType);\n                        }\n                    }\n                } else {\n                    assert(outputDirective == limitedOutput);\n                    return 0;   /* cannot compress within `dst` budget. Stored indexes in hash table are nonetheless fine */\n                }\n            }\n            if (matchCode >= ML_MASK) {\n                *token += ML_MASK;\n                matchCode -= ML_MASK;\n                LZ4_write32(op, 0xFFFFFFFF);\n                while (matchCode >= 4*255) {\n                    op+=4;\n                    LZ4_write32(op, 0xFFFFFFFF);\n                    matchCode -= 4*255;\n                }\n                op += matchCode / 255;\n                *op++ = (BYTE)(matchCode % 255);\n            } else\n                *token += (BYTE)(matchCode);\n        }\n        /* Ensure we have enough space for the last literals. */\n        assert(!(outputDirective == fillOutput && op + 1 + LASTLITERALS > olimit));\n\n        anchor = ip;\n\n        /* Test end of chunk */\n        if (ip >= mflimitPlusOne) break;\n\n        /* Fill table */\n        LZ4_putPosition(ip-2, cctx->hashTable, tableType, base);\n\n        /* Test next position */\n        if (tableType == byPtr) {\n\n            match = LZ4_getPosition(ip, cctx->hashTable, tableType, base);\n            LZ4_putPosition(ip, cctx->hashTable, tableType, base);\n            if ( (match+LZ4_DISTANCE_MAX >= ip)\n              && (LZ4_read32(match) == LZ4_read32(ip)) )\n            { token=op++; *token=0; goto _next_match; }\n\n        } else {   /* byU32, byU16 */\n\n            U32 const h = LZ4_hashPosition(ip, tableType);\n            U32 const current = (U32)(ip-base);\n            U32 matchIndex = LZ4_getIndexOnHash(h, cctx->hashTable, tableType);\n            assert(matchIndex < current);\n            if (dictDirective == usingDictCtx) {\n                if (matchIndex < startIndex) {\n                    /* there was no match, try the dictionary */\n                    matchIndex = LZ4_getIndexOnHash(h, dictCtx->hashTable, byU32);\n                    match = dictBase + matchIndex;\n                    lowLimit = dictionary;   /* required for match length counter */\n                    matchIndex += dictDelta;\n                } else {\n                    match = base + matchIndex;\n                    lowLimit = (const BYTE*)source;  /* required for match length counter */\n                }\n            } else if (dictDirective==usingExtDict) {\n                if (matchIndex < startIndex) {\n                    assert(dictBase);\n                    match = dictBase + matchIndex;\n                    lowLimit = dictionary;   /* required for match length counter */\n                } else {\n                    match = base + matchIndex;\n                    lowLimit = (const BYTE*)source;   /* required for match length counter */\n                }\n            } else {   /* single memory segment */\n                match = base + matchIndex;\n            }\n            LZ4_putIndexOnHash(current, h, cctx->hashTable, tableType);\n            assert(matchIndex < current);\n            if ( ((dictIssue==dictSmall) ? (matchIndex >= prefixIdxLimit) : 1)\n              && (((tableType==byU16) && (LZ4_DISTANCE_MAX == LZ4_DISTANCE_ABSOLUTE_MAX)) ? 1 : (matchIndex+LZ4_DISTANCE_MAX >= current))\n              && (LZ4_read32(match) == LZ4_read32(ip)) ) {\n                token=op++;\n                *token=0;\n                if (maybe_extMem) offset = current - matchIndex;\n                DEBUGLOG(6, \"seq.start:%i, literals=%u, match.start:%i\",\n                            (int)(anchor-(const BYTE*)source), 0, (int)(ip-(const BYTE*)source));\n                goto _next_match;\n            }\n        }\n\n        /* Prepare next loop */\n        forwardH = LZ4_hashPosition(++ip, tableType);\n\n    }\n\n_last_literals:\n    /* Encode Last Literals */\n    {   size_t lastRun = (size_t)(iend - anchor);\n        if ( (outputDirective) &&  /* Check output buffer overflow */\n            (op + lastRun + 1 + ((lastRun+255-RUN_MASK)/255) > olimit)) {\n            if (outputDirective == fillOutput) {\n                /* adapt lastRun to fill 'dst' */\n                assert(olimit >= op);\n                lastRun  = (size_t)(olimit-op) - 1/*token*/;\n                lastRun -= (lastRun + 256 - RUN_MASK) / 256;  /*additional length tokens*/\n            } else {\n                assert(outputDirective == limitedOutput);\n                return 0;   /* cannot compress within `dst` budget. Stored indexes in hash table are nonetheless fine */\n            }\n        }\n        DEBUGLOG(6, \"Final literal run : %i literals\", (int)lastRun);\n        if (lastRun >= RUN_MASK) {\n            size_t accumulator = lastRun - RUN_MASK;\n            *op++ = RUN_MASK << ML_BITS;\n            for(; accumulator >= 255 ; accumulator-=255) *op++ = 255;\n            *op++ = (BYTE) accumulator;\n        } else {\n            *op++ = (BYTE)(lastRun<<ML_BITS);\n        }\n        LZ4_memcpy(op, anchor, lastRun);\n        ip = anchor + lastRun;\n        op += lastRun;\n    }\n\n    if (outputDirective == fillOutput) {\n        *inputConsumed = (int) (((const char*)ip)-source);\n    }\n    result = (int)(((char*)op) - dest);\n    assert(result > 0);\n    DEBUGLOG(5, \"LZ4_compress_generic: compressed %i bytes into %i bytes\", inputSize, result);\n    return result;\n}\n\n/** LZ4_compress_generic() :\n *  inlined, to ensure branches are decided at compilation time;\n *  takes care of src == (NULL, 0)\n *  and forward the rest to LZ4_compress_generic_validated */\nLZ4_FORCE_INLINE int LZ4_compress_generic(\n                 LZ4_stream_t_internal* const cctx,\n                 const char* const src,\n                 char* const dst,\n                 const int srcSize,\n                 int *inputConsumed, /* only written when outputDirective == fillOutput */\n                 const int dstCapacity,\n                 const limitedOutput_directive outputDirective,\n                 const tableType_t tableType,\n                 const dict_directive dictDirective,\n                 const dictIssue_directive dictIssue,\n                 const int acceleration)\n{\n    DEBUGLOG(5, \"LZ4_compress_generic: srcSize=%i, dstCapacity=%i\",\n                srcSize, dstCapacity);\n\n    if ((U32)srcSize > (U32)LZ4_MAX_INPUT_SIZE) { return 0; }  /* Unsupported srcSize, too large (or negative) */\n    if (srcSize == 0) {   /* src == NULL supported if srcSize == 0 */\n        if (outputDirective != notLimited && dstCapacity <= 0) return 0;  /* no output, can't write anything */\n        DEBUGLOG(5, \"Generating an empty block\");\n        assert(outputDirective == notLimited || dstCapacity >= 1);\n        assert(dst != NULL);\n        dst[0] = 0;\n        if (outputDirective == fillOutput) {\n            assert (inputConsumed != NULL);\n            *inputConsumed = 0;\n        }\n        return 1;\n    }\n    assert(src != NULL);\n\n    return LZ4_compress_generic_validated(cctx, src, dst, srcSize,\n                inputConsumed, /* only written into if outputDirective == fillOutput */\n                dstCapacity, outputDirective,\n                tableType, dictDirective, dictIssue, acceleration);\n}\n\n\nint LZ4_compress_fast_extState(void* state, const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration)\n{\n    LZ4_stream_t_internal* const ctx = & LZ4_initStream(state, sizeof(LZ4_stream_t)) -> internal_donotuse;\n    assert(ctx != NULL);\n    if (acceleration < 1) acceleration = LZ4_ACCELERATION_DEFAULT;\n    if (acceleration > LZ4_ACCELERATION_MAX) acceleration = LZ4_ACCELERATION_MAX;\n    if (maxOutputSize >= LZ4_compressBound(inputSize)) {\n        if (inputSize < LZ4_64Klimit) {\n            return LZ4_compress_generic(ctx, source, dest, inputSize, NULL, 0, notLimited, byU16, noDict, noDictIssue, acceleration);\n        } else {\n            const tableType_t tableType = ((sizeof(void*)==4) && ((uptrval)source > LZ4_DISTANCE_MAX)) ? byPtr : byU32;\n            return LZ4_compress_generic(ctx, source, dest, inputSize, NULL, 0, notLimited, tableType, noDict, noDictIssue, acceleration);\n        }\n    } else {\n        if (inputSize < LZ4_64Klimit) {\n            return LZ4_compress_generic(ctx, source, dest, inputSize, NULL, maxOutputSize, limitedOutput, byU16, noDict, noDictIssue, acceleration);\n        } else {\n            const tableType_t tableType = ((sizeof(void*)==4) && ((uptrval)source > LZ4_DISTANCE_MAX)) ? byPtr : byU32;\n            return LZ4_compress_generic(ctx, source, dest, inputSize, NULL, maxOutputSize, limitedOutput, tableType, noDict, noDictIssue, acceleration);\n        }\n    }\n}\n\n/**\n * LZ4_compress_fast_extState_fastReset() :\n * A variant of LZ4_compress_fast_extState().\n *\n * Using this variant avoids an expensive initialization step. It is only safe\n * to call if the state buffer is known to be correctly initialized already\n * (see comment in lz4.h on LZ4_resetStream_fast() for a definition of\n * \"correctly initialized\").\n */\nint LZ4_compress_fast_extState_fastReset(void* state, const char* src, char* dst, int srcSize, int dstCapacity, int acceleration)\n{\n    LZ4_stream_t_internal* ctx = &((LZ4_stream_t*)state)->internal_donotuse;\n    if (acceleration < 1) acceleration = LZ4_ACCELERATION_DEFAULT;\n    if (acceleration > LZ4_ACCELERATION_MAX) acceleration = LZ4_ACCELERATION_MAX;\n\n    if (dstCapacity >= LZ4_compressBound(srcSize)) {\n        if (srcSize < LZ4_64Klimit) {\n            const tableType_t tableType = byU16;\n            LZ4_prepareTable(ctx, srcSize, tableType);\n            if (ctx->currentOffset) {\n                return LZ4_compress_generic(ctx, src, dst, srcSize, NULL, 0, notLimited, tableType, noDict, dictSmall, acceleration);\n            } else {\n                return LZ4_compress_generic(ctx, src, dst, srcSize, NULL, 0, notLimited, tableType, noDict, noDictIssue, acceleration);\n            }\n        } else {\n            const tableType_t tableType = ((sizeof(void*)==4) && ((uptrval)src > LZ4_DISTANCE_MAX)) ? byPtr : byU32;\n            LZ4_prepareTable(ctx, srcSize, tableType);\n            return LZ4_compress_generic(ctx, src, dst, srcSize, NULL, 0, notLimited, tableType, noDict, noDictIssue, acceleration);\n        }\n    } else {\n        if (srcSize < LZ4_64Klimit) {\n            const tableType_t tableType = byU16;\n            LZ4_prepareTable(ctx, srcSize, tableType);\n            if (ctx->currentOffset) {\n                return LZ4_compress_generic(ctx, src, dst, srcSize, NULL, dstCapacity, limitedOutput, tableType, noDict, dictSmall, acceleration);\n            } else {\n                return LZ4_compress_generic(ctx, src, dst, srcSize, NULL, dstCapacity, limitedOutput, tableType, noDict, noDictIssue, acceleration);\n            }\n        } else {\n            const tableType_t tableType = ((sizeof(void*)==4) && ((uptrval)src > LZ4_DISTANCE_MAX)) ? byPtr : byU32;\n            LZ4_prepareTable(ctx, srcSize, tableType);\n            return LZ4_compress_generic(ctx, src, dst, srcSize, NULL, dstCapacity, limitedOutput, tableType, noDict, noDictIssue, acceleration);\n        }\n    }\n}\n\n\nint LZ4_compress_fast(const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration)\n{\n    int result;\n#if (LZ4_HEAPMODE)\n    LZ4_stream_t* ctxPtr = (LZ4_stream_t*)ALLOC(sizeof(LZ4_stream_t));   /* malloc-calloc always properly aligned */\n    if (ctxPtr == NULL) return 0;\n#else\n    LZ4_stream_t ctx;\n    LZ4_stream_t* const ctxPtr = &ctx;\n#endif\n    result = LZ4_compress_fast_extState(ctxPtr, source, dest, inputSize, maxOutputSize, acceleration);\n\n#if (LZ4_HEAPMODE)\n    FREEMEM(ctxPtr);\n#endif\n    return result;\n}\n\n\nint LZ4_compress_default(const char* src, char* dst, int srcSize, int maxOutputSize)\n{\n    return LZ4_compress_fast(src, dst, srcSize, maxOutputSize, 1);\n}\n\n\n/* Note!: This function leaves the stream in an unclean/broken state!\n * It is not safe to subsequently use the same state with a _fastReset() or\n * _continue() call without resetting it. */\nstatic int LZ4_compress_destSize_extState (LZ4_stream_t* state, const char* src, char* dst, int* srcSizePtr, int targetDstSize)\n{\n    void* const s = LZ4_initStream(state, sizeof (*state));\n    assert(s != NULL); (void)s;\n\n    if (targetDstSize >= LZ4_compressBound(*srcSizePtr)) {  /* compression success is guaranteed */\n        return LZ4_compress_fast_extState(state, src, dst, *srcSizePtr, targetDstSize, 1);\n    } else {\n        if (*srcSizePtr < LZ4_64Klimit) {\n            return LZ4_compress_generic(&state->internal_donotuse, src, dst, *srcSizePtr, srcSizePtr, targetDstSize, fillOutput, byU16, noDict, noDictIssue, 1);\n        } else {\n            tableType_t const addrMode = ((sizeof(void*)==4) && ((uptrval)src > LZ4_DISTANCE_MAX)) ? byPtr : byU32;\n            return LZ4_compress_generic(&state->internal_donotuse, src, dst, *srcSizePtr, srcSizePtr, targetDstSize, fillOutput, addrMode, noDict, noDictIssue, 1);\n    }   }\n}\n\n\nint LZ4_compress_destSize(const char* src, char* dst, int* srcSizePtr, int targetDstSize)\n{\n#if (LZ4_HEAPMODE)\n    LZ4_stream_t* ctx = (LZ4_stream_t*)ALLOC(sizeof(LZ4_stream_t));   /* malloc-calloc always properly aligned */\n    if (ctx == NULL) return 0;\n#else\n    LZ4_stream_t ctxBody;\n    LZ4_stream_t* ctx = &ctxBody;\n#endif\n\n    int result = LZ4_compress_destSize_extState(ctx, src, dst, srcSizePtr, targetDstSize);\n\n#if (LZ4_HEAPMODE)\n    FREEMEM(ctx);\n#endif\n    return result;\n}\n\n\n\n/*-******************************\n*  Streaming functions\n********************************/\n\n#if !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION)\nLZ4_stream_t* LZ4_createStream(void)\n{\n    LZ4_stream_t* const lz4s = (LZ4_stream_t*)ALLOC(sizeof(LZ4_stream_t));\n    LZ4_STATIC_ASSERT(sizeof(LZ4_stream_t) >= sizeof(LZ4_stream_t_internal));\n    DEBUGLOG(4, \"LZ4_createStream %p\", lz4s);\n    if (lz4s == NULL) return NULL;\n    LZ4_initStream(lz4s, sizeof(*lz4s));\n    return lz4s;\n}\n#endif\n\nstatic size_t LZ4_stream_t_alignment(void)\n{\n#if LZ4_ALIGN_TEST\n    typedef struct { char c; LZ4_stream_t t; } t_a;\n    return sizeof(t_a) - sizeof(LZ4_stream_t);\n#else\n    return 1;  /* effectively disabled */\n#endif\n}\n\nLZ4_stream_t* LZ4_initStream (void* buffer, size_t size)\n{\n    DEBUGLOG(5, \"LZ4_initStream\");\n    if (buffer == NULL) { return NULL; }\n    if (size < sizeof(LZ4_stream_t)) { return NULL; }\n    if (!LZ4_isAligned(buffer, LZ4_stream_t_alignment())) return NULL;\n    MEM_INIT(buffer, 0, sizeof(LZ4_stream_t_internal));\n    return (LZ4_stream_t*)buffer;\n}\n\n/* resetStream is now deprecated,\n * prefer initStream() which is more general */\nvoid LZ4_resetStream (LZ4_stream_t* LZ4_stream)\n{\n    DEBUGLOG(5, \"LZ4_resetStream (ctx:%p)\", LZ4_stream);\n    MEM_INIT(LZ4_stream, 0, sizeof(LZ4_stream_t_internal));\n}\n\nvoid LZ4_resetStream_fast(LZ4_stream_t* ctx) {\n    LZ4_prepareTable(&(ctx->internal_donotuse), 0, byU32);\n}\n\n#if !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION)\nint LZ4_freeStream (LZ4_stream_t* LZ4_stream)\n{\n    if (!LZ4_stream) return 0;   /* support free on NULL */\n    DEBUGLOG(5, \"LZ4_freeStream %p\", LZ4_stream);\n    FREEMEM(LZ4_stream);\n    return (0);\n}\n#endif\n\n\n#define HASH_UNIT sizeof(reg_t)\nint LZ4_loadDict (LZ4_stream_t* LZ4_dict, const char* dictionary, int dictSize)\n{\n    LZ4_stream_t_internal* dict = &LZ4_dict->internal_donotuse;\n    const tableType_t tableType = byU32;\n    const BYTE* p = (const BYTE*)dictionary;\n    const BYTE* const dictEnd = p + dictSize;\n    const BYTE* base;\n\n    DEBUGLOG(4, \"LZ4_loadDict (%i bytes from %p into %p)\", dictSize, dictionary, LZ4_dict);\n\n    /* It's necessary to reset the context,\n     * and not just continue it with prepareTable()\n     * to avoid any risk of generating overflowing matchIndex\n     * when compressing using this dictionary */\n    LZ4_resetStream(LZ4_dict);\n\n    /* We always increment the offset by 64 KB, since, if the dict is longer,\n     * we truncate it to the last 64k, and if it's shorter, we still want to\n     * advance by a whole window length so we can provide the guarantee that\n     * there are only valid offsets in the window, which allows an optimization\n     * in LZ4_compress_fast_continue() where it uses noDictIssue even when the\n     * dictionary isn't a full 64k. */\n    dict->currentOffset += 64 KB;\n\n    if (dictSize < (int)HASH_UNIT) {\n        return 0;\n    }\n\n    if ((dictEnd - p) > 64 KB) p = dictEnd - 64 KB;\n    base = dictEnd - dict->currentOffset;\n    dict->dictionary = p;\n    dict->dictSize = (U32)(dictEnd - p);\n    dict->tableType = (U32)tableType;\n\n    while (p <= dictEnd-HASH_UNIT) {\n        LZ4_putPosition(p, dict->hashTable, tableType, base);\n        p+=3;\n    }\n\n    return (int)dict->dictSize;\n}\n\nvoid LZ4_attach_dictionary(LZ4_stream_t* workingStream, const LZ4_stream_t* dictionaryStream)\n{\n    const LZ4_stream_t_internal* dictCtx = (dictionaryStream == NULL) ? NULL :\n        &(dictionaryStream->internal_donotuse);\n\n    DEBUGLOG(4, \"LZ4_attach_dictionary (%p, %p, size %u)\",\n             workingStream, dictionaryStream,\n             dictCtx != NULL ? dictCtx->dictSize : 0);\n\n    if (dictCtx != NULL) {\n        /* If the current offset is zero, we will never look in the\n         * external dictionary context, since there is no value a table\n         * entry can take that indicate a miss. In that case, we need\n         * to bump the offset to something non-zero.\n         */\n        if (workingStream->internal_donotuse.currentOffset == 0) {\n            workingStream->internal_donotuse.currentOffset = 64 KB;\n        }\n\n        /* Don't actually attach an empty dictionary.\n         */\n        if (dictCtx->dictSize == 0) {\n            dictCtx = NULL;\n        }\n    }\n    workingStream->internal_donotuse.dictCtx = dictCtx;\n}\n\n\nstatic void LZ4_renormDictT(LZ4_stream_t_internal* LZ4_dict, int nextSize)\n{\n    assert(nextSize >= 0);\n    if (LZ4_dict->currentOffset + (unsigned)nextSize > 0x80000000) {   /* potential ptrdiff_t overflow (32-bits mode) */\n        /* rescale hash table */\n        U32 const delta = LZ4_dict->currentOffset - 64 KB;\n        const BYTE* dictEnd = LZ4_dict->dictionary + LZ4_dict->dictSize;\n        int i;\n        DEBUGLOG(4, \"LZ4_renormDictT\");\n        for (i=0; i<LZ4_HASH_SIZE_U32; i++) {\n            if (LZ4_dict->hashTable[i] < delta) LZ4_dict->hashTable[i]=0;\n            else LZ4_dict->hashTable[i] -= delta;\n        }\n        LZ4_dict->currentOffset = 64 KB;\n        if (LZ4_dict->dictSize > 64 KB) LZ4_dict->dictSize = 64 KB;\n        LZ4_dict->dictionary = dictEnd - LZ4_dict->dictSize;\n    }\n}\n\n\nint LZ4_compress_fast_continue (LZ4_stream_t* LZ4_stream,\n                                const char* source, char* dest,\n                                int inputSize, int maxOutputSize,\n                                int acceleration)\n{\n    const tableType_t tableType = byU32;\n    LZ4_stream_t_internal* const streamPtr = &LZ4_stream->internal_donotuse;\n    const char* dictEnd = streamPtr->dictSize ? (const char*)streamPtr->dictionary + streamPtr->dictSize : NULL;\n\n    DEBUGLOG(5, \"LZ4_compress_fast_continue (inputSize=%i, dictSize=%u)\", inputSize, streamPtr->dictSize);\n\n    LZ4_renormDictT(streamPtr, inputSize);   /* fix index overflow */\n    if (acceleration < 1) acceleration = LZ4_ACCELERATION_DEFAULT;\n    if (acceleration > LZ4_ACCELERATION_MAX) acceleration = LZ4_ACCELERATION_MAX;\n\n    /* invalidate tiny dictionaries */\n    if ( (streamPtr->dictSize < 4)     /* tiny dictionary : not enough for a hash */\n      && (dictEnd != source)           /* prefix mode */\n      && (inputSize > 0)               /* tolerance : don't lose history, in case next invocation would use prefix mode */\n      && (streamPtr->dictCtx == NULL)  /* usingDictCtx */\n      ) {\n        DEBUGLOG(5, \"LZ4_compress_fast_continue: dictSize(%u) at addr:%p is too small\", streamPtr->dictSize, streamPtr->dictionary);\n        /* remove dictionary existence from history, to employ faster prefix mode */\n        streamPtr->dictSize = 0;\n        streamPtr->dictionary = (const BYTE*)source;\n        dictEnd = source;\n    }\n\n    /* Check overlapping input/dictionary space */\n    {   const char* const sourceEnd = source + inputSize;\n        if ((sourceEnd > (const char*)streamPtr->dictionary) && (sourceEnd < dictEnd)) {\n            streamPtr->dictSize = (U32)(dictEnd - sourceEnd);\n            if (streamPtr->dictSize > 64 KB) streamPtr->dictSize = 64 KB;\n            if (streamPtr->dictSize < 4) streamPtr->dictSize = 0;\n            streamPtr->dictionary = (const BYTE*)dictEnd - streamPtr->dictSize;\n        }\n    }\n\n    /* prefix mode : source data follows dictionary */\n    if (dictEnd == source) {\n        if ((streamPtr->dictSize < 64 KB) && (streamPtr->dictSize < streamPtr->currentOffset))\n            return LZ4_compress_generic(streamPtr, source, dest, inputSize, NULL, maxOutputSize, limitedOutput, tableType, withPrefix64k, dictSmall, acceleration);\n        else\n            return LZ4_compress_generic(streamPtr, source, dest, inputSize, NULL, maxOutputSize, limitedOutput, tableType, withPrefix64k, noDictIssue, acceleration);\n    }\n\n    /* external dictionary mode */\n    {   int result;\n        if (streamPtr->dictCtx) {\n            /* We depend here on the fact that dictCtx'es (produced by\n             * LZ4_loadDict) guarantee that their tables contain no references\n             * to offsets between dictCtx->currentOffset - 64 KB and\n             * dictCtx->currentOffset - dictCtx->dictSize. This makes it safe\n             * to use noDictIssue even when the dict isn't a full 64 KB.\n             */\n            if (inputSize > 4 KB) {\n                /* For compressing large blobs, it is faster to pay the setup\n                 * cost to copy the dictionary's tables into the active context,\n                 * so that the compression loop is only looking into one table.\n                 */\n                LZ4_memcpy(streamPtr, streamPtr->dictCtx, sizeof(*streamPtr));\n                result = LZ4_compress_generic(streamPtr, source, dest, inputSize, NULL, maxOutputSize, limitedOutput, tableType, usingExtDict, noDictIssue, acceleration);\n            } else {\n                result = LZ4_compress_generic(streamPtr, source, dest, inputSize, NULL, maxOutputSize, limitedOutput, tableType, usingDictCtx, noDictIssue, acceleration);\n            }\n        } else {  /* small data <= 4 KB */\n            if ((streamPtr->dictSize < 64 KB) && (streamPtr->dictSize < streamPtr->currentOffset)) {\n                result = LZ4_compress_generic(streamPtr, source, dest, inputSize, NULL, maxOutputSize, limitedOutput, tableType, usingExtDict, dictSmall, acceleration);\n            } else {\n                result = LZ4_compress_generic(streamPtr, source, dest, inputSize, NULL, maxOutputSize, limitedOutput, tableType, usingExtDict, noDictIssue, acceleration);\n            }\n        }\n        streamPtr->dictionary = (const BYTE*)source;\n        streamPtr->dictSize = (U32)inputSize;\n        return result;\n    }\n}\n\n\n/* Hidden debug function, to force-test external dictionary mode */\nint LZ4_compress_forceExtDict (LZ4_stream_t* LZ4_dict, const char* source, char* dest, int srcSize)\n{\n    LZ4_stream_t_internal* streamPtr = &LZ4_dict->internal_donotuse;\n    int result;\n\n    LZ4_renormDictT(streamPtr, srcSize);\n\n    if ((streamPtr->dictSize < 64 KB) && (streamPtr->dictSize < streamPtr->currentOffset)) {\n        result = LZ4_compress_generic(streamPtr, source, dest, srcSize, NULL, 0, notLimited, byU32, usingExtDict, dictSmall, 1);\n    } else {\n        result = LZ4_compress_generic(streamPtr, source, dest, srcSize, NULL, 0, notLimited, byU32, usingExtDict, noDictIssue, 1);\n    }\n\n    streamPtr->dictionary = (const BYTE*)source;\n    streamPtr->dictSize = (U32)srcSize;\n\n    return result;\n}\n\n\n/*! LZ4_saveDict() :\n *  If previously compressed data block is not guaranteed to remain available at its memory location,\n *  save it into a safer place (char* safeBuffer).\n *  Note : no need to call LZ4_loadDict() afterwards, dictionary is immediately usable,\n *         one can therefore call LZ4_compress_fast_continue() right after.\n * @return : saved dictionary size in bytes (necessarily <= dictSize), or 0 if error.\n */\nint LZ4_saveDict (LZ4_stream_t* LZ4_dict, char* safeBuffer, int dictSize)\n{\n    LZ4_stream_t_internal* const dict = &LZ4_dict->internal_donotuse;\n\n    DEBUGLOG(5, \"LZ4_saveDict : dictSize=%i, safeBuffer=%p\", dictSize, safeBuffer);\n\n    if ((U32)dictSize > 64 KB) { dictSize = 64 KB; } /* useless to define a dictionary > 64 KB */\n    if ((U32)dictSize > dict->dictSize) { dictSize = (int)dict->dictSize; }\n\n    if (safeBuffer == NULL) assert(dictSize == 0);\n    if (dictSize > 0) {\n        const BYTE* const previousDictEnd = dict->dictionary + dict->dictSize;\n        assert(dict->dictionary);\n        LZ4_memmove(safeBuffer, previousDictEnd - dictSize, (size_t)dictSize);\n    }\n\n    dict->dictionary = (const BYTE*)safeBuffer;\n    dict->dictSize = (U32)dictSize;\n\n    return dictSize;\n}\n\n\n\n/*-*******************************\n *  Decompression functions\n ********************************/\n\ntypedef enum { decode_full_block = 0, partial_decode = 1 } earlyEnd_directive;\n\n#undef MIN\n#define MIN(a,b)    ( (a) < (b) ? (a) : (b) )\n\n\n/* variant for decompress_unsafe()\n * does not know end of input\n * presumes input is well formed\n * note : will consume at least one byte */\nsize_t read_long_length_no_check(const BYTE** pp)\n{\n    size_t b, l = 0;\n    do { b = **pp; (*pp)++; l += b; } while (b==255);\n    DEBUGLOG(6, \"read_long_length_no_check: +length=%zu using %zu input bytes\", l, l/255 + 1)\n    return l;\n}\n\n/* core decoder variant for LZ4_decompress_fast*()\n * for legacy support only : these entry points are deprecated.\n * - Presumes input is correctly formed (no defense vs malformed inputs)\n * - Does not know input size (presume input buffer is \"large enough\")\n * - Decompress a full block (only)\n * @return : nb of bytes read from input.\n * Note : this variant is not optimized for speed, just for maintenance.\n *        the goal is to remove support of decompress_fast*() variants by v2.0\n**/\nLZ4_FORCE_INLINE int\nLZ4_decompress_unsafe_generic(\n                 const BYTE* const istart,\n                 BYTE* const ostart,\n                 int decompressedSize,\n\n                 size_t prefixSize,\n                 const BYTE* const dictStart,  /* only if dict==usingExtDict */\n                 const size_t dictSize         /* note: =0 if dictStart==NULL */\n                 )\n{\n    const BYTE* ip = istart;\n    BYTE* op = (BYTE*)ostart;\n    BYTE* const oend = ostart + decompressedSize;\n    const BYTE* const prefixStart = ostart - prefixSize;\n\n    DEBUGLOG(5, \"LZ4_decompress_unsafe_generic\");\n    if (dictStart == NULL) assert(dictSize == 0);\n\n    while (1) {\n        /* start new sequence */\n        unsigned token = *ip++;\n\n        /* literals */\n        {   size_t ll = token >> ML_BITS;\n            if (ll==15) {\n                /* long literal length */\n                ll += read_long_length_no_check(&ip);\n            }\n            if ((size_t)(oend-op) < ll) return -1; /* output buffer overflow */\n            LZ4_memmove(op, ip, ll); /* support in-place decompression */\n            op += ll;\n            ip += ll;\n            if ((size_t)(oend-op) < MFLIMIT) {\n                if (op==oend) break;  /* end of block */\n                DEBUGLOG(5, \"invalid: literals end at distance %zi from end of block\", oend-op);\n                /* incorrect end of block :\n                 * last match must start at least MFLIMIT==12 bytes before end of output block */\n                return -1;\n        }   }\n\n        /* match */\n        {   size_t ml = token & 15;\n            size_t const offset = LZ4_readLE16(ip);\n            ip+=2;\n\n            if (ml==15) {\n                /* long literal length */\n                ml += read_long_length_no_check(&ip);\n            }\n            ml += MINMATCH;\n\n            if ((size_t)(oend-op) < ml) return -1; /* output buffer overflow */\n\n            {   const BYTE* match = op - offset;\n\n                /* out of range */\n                if (offset > (size_t)(op - prefixStart) + dictSize) {\n                    DEBUGLOG(6, \"offset out of range\");\n                    return -1;\n                }\n\n                /* check special case : extDict */\n                if (offset > (size_t)(op - prefixStart)) {\n                    /* extDict scenario */\n                    const BYTE* const dictEnd = dictStart + dictSize;\n                    const BYTE* extMatch = dictEnd - (offset - (size_t)(op-prefixStart));\n                    size_t const extml = (size_t)(dictEnd - extMatch);\n                    if (extml > ml) {\n                        /* match entirely within extDict */\n                        LZ4_memmove(op, extMatch, ml);\n                        op += ml;\n                        ml = 0;\n                    } else {\n                        /* match split between extDict & prefix */\n                        LZ4_memmove(op, extMatch, extml);\n                        op += extml;\n                        ml -= extml;\n                    }\n                    match = prefixStart;\n                }\n\n                /* match copy - slow variant, supporting overlap copy */\n                {   size_t u;\n                    for (u=0; u<ml; u++) {\n                        op[u] = match[u];\n            }   }   }\n            op += ml;\n            if ((size_t)(oend-op) < LASTLITERALS) {\n                DEBUGLOG(5, \"invalid: match ends at distance %zi from end of block\", oend-op);\n                /* incorrect end of block :\n                 * last match must stop at least LASTLITERALS==5 bytes before end of output block */\n                return -1;\n            }\n        } /* match */\n    } /* main loop */\n    return (int)(ip - istart);\n}\n\n\n/* Read the variable-length literal or match length.\n *\n * @ip : input pointer\n * @ilimit : position after which if length is not decoded, the input is necessarily corrupted.\n * @initial_check - check ip >= ipmax before start of loop.  Returns initial_error if so.\n * @error (output) - error code.  Must be set to 0 before call.\n**/\ntypedef size_t Rvl_t;\nstatic const Rvl_t rvl_error = (Rvl_t)(-1);\nLZ4_FORCE_INLINE Rvl_t\nread_variable_length(const BYTE** ip, const BYTE* ilimit,\n                     int initial_check)\n{\n    Rvl_t s, length = 0;\n    assert(ip != NULL);\n    assert(*ip !=  NULL);\n    assert(ilimit != NULL);\n    if (initial_check && unlikely((*ip) >= ilimit)) {    /* read limit reached */\n        return rvl_error;\n    }\n    do {\n        s = **ip;\n        (*ip)++;\n        length += s;\n        if (unlikely((*ip) > ilimit)) {    /* read limit reached */\n            return rvl_error;\n        }\n        /* accumulator overflow detection (32-bit mode only) */\n        if ((sizeof(length)<8) && unlikely(length > ((Rvl_t)(-1)/2)) ) {\n            return rvl_error;\n        }\n    } while (s==255);\n\n    return length;\n}\n\n/*! LZ4_decompress_generic() :\n *  This generic decompression function covers all use cases.\n *  It shall be instantiated several times, using different sets of directives.\n *  Note that it is important for performance that this function really get inlined,\n *  in order to remove useless branches during compilation optimization.\n */\nLZ4_FORCE_INLINE int\nLZ4_decompress_generic(\n                 const char* const src,\n                 char* const dst,\n                 int srcSize,\n                 int outputSize,         /* If endOnInput==endOnInputSize, this value is `dstCapacity` */\n\n                 earlyEnd_directive partialDecoding,  /* full, partial */\n                 dict_directive dict,                 /* noDict, withPrefix64k, usingExtDict */\n                 const BYTE* const lowPrefix,  /* always <= dst, == dst when no prefix */\n                 const BYTE* const dictStart,  /* only if dict==usingExtDict */\n                 const size_t dictSize         /* note : = 0 if noDict */\n                 )\n{\n    if ((src == NULL) || (outputSize < 0)) { return -1; }\n\n    {   const BYTE* ip = (const BYTE*) src;\n        const BYTE* const iend = ip + srcSize;\n\n        BYTE* op = (BYTE*) dst;\n        BYTE* const oend = op + outputSize;\n        BYTE* cpy;\n\n        const BYTE* const dictEnd = (dictStart == NULL) ? NULL : dictStart + dictSize;\n\n        const int checkOffset = (dictSize < (int)(64 KB));\n\n\n        /* Set up the \"end\" pointers for the shortcut. */\n        const BYTE* const shortiend = iend - 14 /*maxLL*/ - 2 /*offset*/;\n        const BYTE* const shortoend = oend - 14 /*maxLL*/ - 18 /*maxML*/;\n\n        const BYTE* match;\n        size_t offset;\n        unsigned token;\n        size_t length;\n\n\n        DEBUGLOG(5, \"LZ4_decompress_generic (srcSize:%i, dstSize:%i)\", srcSize, outputSize);\n\n        /* Special cases */\n        assert(lowPrefix <= op);\n        if (unlikely(outputSize==0)) {\n            /* Empty output buffer */\n            if (partialDecoding) return 0;\n            return ((srcSize==1) && (*ip==0)) ? 0 : -1;\n        }\n        if (unlikely(srcSize==0)) { return -1; }\n\n    /* LZ4_FAST_DEC_LOOP:\n     * designed for modern OoO performance cpus,\n     * where copying reliably 32-bytes is preferable to an unpredictable branch.\n     * note : fast loop may show a regression for some client arm chips. */\n#if LZ4_FAST_DEC_LOOP\n        if ((oend - op) < FASTLOOP_SAFE_DISTANCE) {\n            DEBUGLOG(6, \"skip fast decode loop\");\n            goto safe_decode;\n        }\n\n        /* Fast loop : decode sequences as long as output < oend-FASTLOOP_SAFE_DISTANCE */\n        while (1) {\n            /* Main fastloop assertion: We can always wildcopy FASTLOOP_SAFE_DISTANCE */\n            assert(oend - op >= FASTLOOP_SAFE_DISTANCE);\n            assert(ip < iend);\n            token = *ip++;\n            length = token >> ML_BITS;  /* literal length */\n\n            /* decode literal length */\n            if (length == RUN_MASK) {\n                size_t const addl = read_variable_length(&ip, iend-RUN_MASK, 1);\n                if (addl == rvl_error) { goto _output_error; }\n                length += addl;\n                if (unlikely((uptrval)(op)+length<(uptrval)(op))) { goto _output_error; } /* overflow detection */\n                if (unlikely((uptrval)(ip)+length<(uptrval)(ip))) { goto _output_error; } /* overflow detection */\n\n                /* copy literals */\n                cpy = op+length;\n                LZ4_STATIC_ASSERT(MFLIMIT >= WILDCOPYLENGTH);\n                if ((cpy>oend-32) || (ip+length>iend-32)) { goto safe_literal_copy; }\n                LZ4_wildCopy32(op, ip, cpy);\n                ip += length; op = cpy;\n            } else {\n                cpy = op+length;\n                DEBUGLOG(7, \"copy %u bytes in a 16-bytes stripe\", (unsigned)length);\n                /* We don't need to check oend, since we check it once for each loop below */\n                if (ip > iend-(16 + 1/*max lit + offset + nextToken*/)) { goto safe_literal_copy; }\n                /* Literals can only be <= 14, but hope compilers optimize better when copy by a register size */\n                LZ4_memcpy(op, ip, 16);\n                ip += length; op = cpy;\n            }\n\n            /* get offset */\n            offset = LZ4_readLE16(ip); ip+=2;\n            match = op - offset;\n            assert(match <= op);  /* overflow check */\n\n            /* get matchlength */\n            length = token & ML_MASK;\n\n            if (length == ML_MASK) {\n                size_t const addl = read_variable_length(&ip, iend - LASTLITERALS + 1, 0);\n                if (addl == rvl_error) { goto _output_error; }\n                length += addl;\n                length += MINMATCH;\n                if (unlikely((uptrval)(op)+length<(uptrval)op)) { goto _output_error; } /* overflow detection */\n                if ((checkOffset) && (unlikely(match + dictSize < lowPrefix))) { goto _output_error; } /* Error : offset outside buffers */\n                if (op + length >= oend - FASTLOOP_SAFE_DISTANCE) {\n                    goto safe_match_copy;\n                }\n            } else {\n                length += MINMATCH;\n                if (op + length >= oend - FASTLOOP_SAFE_DISTANCE) {\n                    goto safe_match_copy;\n                }\n\n                /* Fastpath check: skip LZ4_wildCopy32 when true */\n                if ((dict == withPrefix64k) || (match >= lowPrefix)) {\n                    if (offset >= 8) {\n                        assert(match >= lowPrefix);\n                        assert(match <= op);\n                        assert(op + 18 <= oend);\n\n                        LZ4_memcpy(op, match, 8);\n                        LZ4_memcpy(op+8, match+8, 8);\n                        LZ4_memcpy(op+16, match+16, 2);\n                        op += length;\n                        continue;\n            }   }   }\n\n            if (checkOffset && (unlikely(match + dictSize < lowPrefix))) { goto _output_error; } /* Error : offset outside buffers */\n            /* match starting within external dictionary */\n            if ((dict==usingExtDict) && (match < lowPrefix)) {\n                assert(dictEnd != NULL);\n                if (unlikely(op+length > oend-LASTLITERALS)) {\n                    if (partialDecoding) {\n                        DEBUGLOG(7, \"partialDecoding: dictionary match, close to dstEnd\");\n                        length = MIN(length, (size_t)(oend-op));\n                    } else {\n                        goto _output_error;  /* end-of-block condition violated */\n                }   }\n\n                if (length <= (size_t)(lowPrefix-match)) {\n                    /* match fits entirely within external dictionary : just copy */\n                    LZ4_memmove(op, dictEnd - (lowPrefix-match), length);\n                    op += length;\n                } else {\n                    /* match stretches into both external dictionary and current block */\n                    size_t const copySize = (size_t)(lowPrefix - match);\n                    size_t const restSize = length - copySize;\n                    LZ4_memcpy(op, dictEnd - copySize, copySize);\n                    op += copySize;\n                    if (restSize > (size_t)(op - lowPrefix)) {  /* overlap copy */\n                        BYTE* const endOfMatch = op + restSize;\n                        const BYTE* copyFrom = lowPrefix;\n                        while (op < endOfMatch) { *op++ = *copyFrom++; }\n                    } else {\n                        LZ4_memcpy(op, lowPrefix, restSize);\n                        op += restSize;\n                }   }\n                continue;\n            }\n\n            /* copy match within block */\n            cpy = op + length;\n\n            assert((op <= oend) && (oend-op >= 32));\n            if (unlikely(offset<16)) {\n                LZ4_memcpy_using_offset(op, match, cpy, offset);\n            } else {\n                LZ4_wildCopy32(op, match, cpy);\n            }\n\n            op = cpy;   /* wildcopy correction */\n        }\n    safe_decode:\n#endif\n\n        /* Main Loop : decode remaining sequences where output < FASTLOOP_SAFE_DISTANCE */\n        while (1) {\n            assert(ip < iend);\n            token = *ip++;\n            length = token >> ML_BITS;  /* literal length */\n\n            /* A two-stage shortcut for the most common case:\n             * 1) If the literal length is 0..14, and there is enough space,\n             * enter the shortcut and copy 16 bytes on behalf of the literals\n             * (in the fast mode, only 8 bytes can be safely copied this way).\n             * 2) Further if the match length is 4..18, copy 18 bytes in a similar\n             * manner; but we ensure that there's enough space in the output for\n             * those 18 bytes earlier, upon entering the shortcut (in other words,\n             * there is a combined check for both stages).\n             */\n            if ( (length != RUN_MASK)\n                /* strictly \"less than\" on input, to re-enter the loop with at least one byte */\n              && likely((ip < shortiend) & (op <= shortoend)) ) {\n                /* Copy the literals */\n                LZ4_memcpy(op, ip, 16);\n                op += length; ip += length;\n\n                /* The second stage: prepare for match copying, decode full info.\n                 * If it doesn't work out, the info won't be wasted. */\n                length = token & ML_MASK; /* match length */\n                offset = LZ4_readLE16(ip); ip += 2;\n                match = op - offset;\n                assert(match <= op); /* check overflow */\n\n                /* Do not deal with overlapping matches. */\n                if ( (length != ML_MASK)\n                  && (offset >= 8)\n                  && (dict==withPrefix64k || match >= lowPrefix) ) {\n                    /* Copy the match. */\n                    LZ4_memcpy(op + 0, match + 0, 8);\n                    LZ4_memcpy(op + 8, match + 8, 8);\n                    LZ4_memcpy(op +16, match +16, 2);\n                    op += length + MINMATCH;\n                    /* Both stages worked, load the next token. */\n                    continue;\n                }\n\n                /* The second stage didn't work out, but the info is ready.\n                 * Propel it right to the point of match copying. */\n                goto _copy_match;\n            }\n\n            /* decode literal length */\n            if (length == RUN_MASK) {\n                size_t const addl = read_variable_length(&ip, iend-RUN_MASK, 1);\n                if (addl == rvl_error) { goto _output_error; }\n                length += addl;\n                if (unlikely((uptrval)(op)+length<(uptrval)(op))) { goto _output_error; } /* overflow detection */\n                if (unlikely((uptrval)(ip)+length<(uptrval)(ip))) { goto _output_error; } /* overflow detection */\n            }\n\n            /* copy literals */\n            cpy = op+length;\n#if LZ4_FAST_DEC_LOOP\n        safe_literal_copy:\n#endif\n            LZ4_STATIC_ASSERT(MFLIMIT >= WILDCOPYLENGTH);\n            if ((cpy>oend-MFLIMIT) || (ip+length>iend-(2+1+LASTLITERALS))) {\n                /* We've either hit the input parsing restriction or the output parsing restriction.\n                 * In the normal scenario, decoding a full block, it must be the last sequence,\n                 * otherwise it's an error (invalid input or dimensions).\n                 * In partialDecoding scenario, it's necessary to ensure there is no buffer overflow.\n                 */\n                if (partialDecoding) {\n                    /* Since we are partial decoding we may be in this block because of the output parsing\n                     * restriction, which is not valid since the output buffer is allowed to be undersized.\n                     */\n                    DEBUGLOG(7, \"partialDecoding: copying literals, close to input or output end\")\n                    DEBUGLOG(7, \"partialDecoding: literal length = %u\", (unsigned)length);\n                    DEBUGLOG(7, \"partialDecoding: remaining space in dstBuffer : %i\", (int)(oend - op));\n                    DEBUGLOG(7, \"partialDecoding: remaining space in srcBuffer : %i\", (int)(iend - ip));\n                    /* Finishing in the middle of a literals segment,\n                     * due to lack of input.\n                     */\n                    if (ip+length > iend) {\n                        length = (size_t)(iend-ip);\n                        cpy = op + length;\n                    }\n                    /* Finishing in the middle of a literals segment,\n                     * due to lack of output space.\n                     */\n                    if (cpy > oend) {\n                        cpy = oend;\n                        assert(op<=oend);\n                        length = (size_t)(oend-op);\n                    }\n                } else {\n                     /* We must be on the last sequence (or invalid) because of the parsing limitations\n                      * so check that we exactly consume the input and don't overrun the output buffer.\n                      */\n                    if ((ip+length != iend) || (cpy > oend)) {\n                        DEBUGLOG(6, \"should have been last run of literals\")\n                        DEBUGLOG(6, \"ip(%p) + length(%i) = %p != iend (%p)\", ip, (int)length, ip+length, iend);\n                        DEBUGLOG(6, \"or cpy(%p) > oend(%p)\", cpy, oend);\n                        goto _output_error;\n                    }\n                }\n                LZ4_memmove(op, ip, length);  /* supports overlapping memory regions, for in-place decompression scenarios */\n                ip += length;\n                op += length;\n                /* Necessarily EOF when !partialDecoding.\n                 * When partialDecoding, it is EOF if we've either\n                 * filled the output buffer or\n                 * can't proceed with reading an offset for following match.\n                 */\n                if (!partialDecoding || (cpy == oend) || (ip >= (iend-2))) {\n                    break;\n                }\n            } else {\n                LZ4_wildCopy8(op, ip, cpy);   /* can overwrite up to 8 bytes beyond cpy */\n                ip += length; op = cpy;\n            }\n\n            /* get offset */\n            offset = LZ4_readLE16(ip); ip+=2;\n            match = op - offset;\n\n            /* get matchlength */\n            length = token & ML_MASK;\n\n    _copy_match:\n            if (length == ML_MASK) {\n                size_t const addl = read_variable_length(&ip, iend - LASTLITERALS + 1, 0);\n                if (addl == rvl_error) { goto _output_error; }\n                length += addl;\n                if (unlikely((uptrval)(op)+length<(uptrval)op)) goto _output_error;   /* overflow detection */\n            }\n            length += MINMATCH;\n\n#if LZ4_FAST_DEC_LOOP\n        safe_match_copy:\n#endif\n            if ((checkOffset) && (unlikely(match + dictSize < lowPrefix))) goto _output_error;   /* Error : offset outside buffers */\n            /* match starting within external dictionary */\n            if ((dict==usingExtDict) && (match < lowPrefix)) {\n                assert(dictEnd != NULL);\n                if (unlikely(op+length > oend-LASTLITERALS)) {\n                    if (partialDecoding) length = MIN(length, (size_t)(oend-op));\n                    else goto _output_error;   /* doesn't respect parsing restriction */\n                }\n\n                if (length <= (size_t)(lowPrefix-match)) {\n                    /* match fits entirely within external dictionary : just copy */\n                    LZ4_memmove(op, dictEnd - (lowPrefix-match), length);\n                    op += length;\n                } else {\n                    /* match stretches into both external dictionary and current block */\n                    size_t const copySize = (size_t)(lowPrefix - match);\n                    size_t const restSize = length - copySize;\n                    LZ4_memcpy(op, dictEnd - copySize, copySize);\n                    op += copySize;\n                    if (restSize > (size_t)(op - lowPrefix)) {  /* overlap copy */\n                        BYTE* const endOfMatch = op + restSize;\n                        const BYTE* copyFrom = lowPrefix;\n                        while (op < endOfMatch) *op++ = *copyFrom++;\n                    } else {\n                        LZ4_memcpy(op, lowPrefix, restSize);\n                        op += restSize;\n                }   }\n                continue;\n            }\n            assert(match >= lowPrefix);\n\n            /* copy match within block */\n            cpy = op + length;\n\n            /* partialDecoding : may end anywhere within the block */\n            assert(op<=oend);\n            if (partialDecoding && (cpy > oend-MATCH_SAFEGUARD_DISTANCE)) {\n                size_t const mlen = MIN(length, (size_t)(oend-op));\n                const BYTE* const matchEnd = match + mlen;\n                BYTE* const copyEnd = op + mlen;\n                if (matchEnd > op) {   /* overlap copy */\n                    while (op < copyEnd) { *op++ = *match++; }\n                } else {\n                    LZ4_memcpy(op, match, mlen);\n                }\n                op = copyEnd;\n                if (op == oend) { break; }\n                continue;\n            }\n\n            if (unlikely(offset<8)) {\n                LZ4_write32(op, 0);   /* silence msan warning when offset==0 */\n                op[0] = match[0];\n                op[1] = match[1];\n                op[2] = match[2];\n                op[3] = match[3];\n                match += inc32table[offset];\n                LZ4_memcpy(op+4, match, 4);\n                match -= dec64table[offset];\n            } else {\n                LZ4_memcpy(op, match, 8);\n                match += 8;\n            }\n            op += 8;\n\n            if (unlikely(cpy > oend-MATCH_SAFEGUARD_DISTANCE)) {\n                BYTE* const oCopyLimit = oend - (WILDCOPYLENGTH-1);\n                if (cpy > oend-LASTLITERALS) { goto _output_error; } /* Error : last LASTLITERALS bytes must be literals (uncompressed) */\n                if (op < oCopyLimit) {\n                    LZ4_wildCopy8(op, match, oCopyLimit);\n                    match += oCopyLimit - op;\n                    op = oCopyLimit;\n                }\n                while (op < cpy) { *op++ = *match++; }\n            } else {\n                LZ4_memcpy(op, match, 8);\n                if (length > 16)  { LZ4_wildCopy8(op+8, match+8, cpy); }\n            }\n            op = cpy;   /* wildcopy correction */\n        }\n\n        /* end of decoding */\n        DEBUGLOG(5, \"decoded %i bytes\", (int) (((char*)op)-dst));\n        return (int) (((char*)op)-dst);     /* Nb of output bytes decoded */\n\n        /* Overflow error detected */\n    _output_error:\n        return (int) (-(((const char*)ip)-src))-1;\n    }\n}\n\n\n/*===== Instantiate the API decoding functions. =====*/\n\nLZ4_FORCE_O2\nint LZ4_decompress_safe(const char* source, char* dest, int compressedSize, int maxDecompressedSize)\n{\n    return LZ4_decompress_generic(source, dest, compressedSize, maxDecompressedSize,\n                                  decode_full_block, noDict,\n                                  (BYTE*)dest, NULL, 0);\n}\n\nLZ4_FORCE_O2\nint LZ4_decompress_safe_partial(const char* src, char* dst, int compressedSize, int targetOutputSize, int dstCapacity)\n{\n    dstCapacity = MIN(targetOutputSize, dstCapacity);\n    return LZ4_decompress_generic(src, dst, compressedSize, dstCapacity,\n                                  partial_decode,\n                                  noDict, (BYTE*)dst, NULL, 0);\n}\n\nLZ4_FORCE_O2\nint LZ4_decompress_fast(const char* source, char* dest, int originalSize)\n{\n    DEBUGLOG(5, \"LZ4_decompress_fast\");\n    return LZ4_decompress_unsafe_generic(\n                (const BYTE*)source, (BYTE*)dest, originalSize,\n                0, NULL, 0);\n}\n\n/*===== Instantiate a few more decoding cases, used more than once. =====*/\n\nLZ4_FORCE_O2 /* Exported, an obsolete API function. */\nint LZ4_decompress_safe_withPrefix64k(const char* source, char* dest, int compressedSize, int maxOutputSize)\n{\n    return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize,\n                                  decode_full_block, withPrefix64k,\n                                  (BYTE*)dest - 64 KB, NULL, 0);\n}\n\nLZ4_FORCE_O2\nstatic int LZ4_decompress_safe_partial_withPrefix64k(const char* source, char* dest, int compressedSize, int targetOutputSize, int dstCapacity)\n{\n    dstCapacity = MIN(targetOutputSize, dstCapacity);\n    return LZ4_decompress_generic(source, dest, compressedSize, dstCapacity,\n                                  partial_decode, withPrefix64k,\n                                  (BYTE*)dest - 64 KB, NULL, 0);\n}\n\n/* Another obsolete API function, paired with the previous one. */\nint LZ4_decompress_fast_withPrefix64k(const char* source, char* dest, int originalSize)\n{\n    return LZ4_decompress_unsafe_generic(\n                (const BYTE*)source, (BYTE*)dest, originalSize,\n                64 KB, NULL, 0);\n}\n\nLZ4_FORCE_O2\nstatic int LZ4_decompress_safe_withSmallPrefix(const char* source, char* dest, int compressedSize, int maxOutputSize,\n                                               size_t prefixSize)\n{\n    return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize,\n                                  decode_full_block, noDict,\n                                  (BYTE*)dest-prefixSize, NULL, 0);\n}\n\nLZ4_FORCE_O2\nstatic int LZ4_decompress_safe_partial_withSmallPrefix(const char* source, char* dest, int compressedSize, int targetOutputSize, int dstCapacity,\n                                               size_t prefixSize)\n{\n    dstCapacity = MIN(targetOutputSize, dstCapacity);\n    return LZ4_decompress_generic(source, dest, compressedSize, dstCapacity,\n                                  partial_decode, noDict,\n                                  (BYTE*)dest-prefixSize, NULL, 0);\n}\n\nLZ4_FORCE_O2\nint LZ4_decompress_safe_forceExtDict(const char* source, char* dest,\n                                     int compressedSize, int maxOutputSize,\n                                     const void* dictStart, size_t dictSize)\n{\n    return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize,\n                                  decode_full_block, usingExtDict,\n                                  (BYTE*)dest, (const BYTE*)dictStart, dictSize);\n}\n\nLZ4_FORCE_O2\nint LZ4_decompress_safe_partial_forceExtDict(const char* source, char* dest,\n                                     int compressedSize, int targetOutputSize, int dstCapacity,\n                                     const void* dictStart, size_t dictSize)\n{\n    dstCapacity = MIN(targetOutputSize, dstCapacity);\n    return LZ4_decompress_generic(source, dest, compressedSize, dstCapacity,\n                                  partial_decode, usingExtDict,\n                                  (BYTE*)dest, (const BYTE*)dictStart, dictSize);\n}\n\nLZ4_FORCE_O2\nstatic int LZ4_decompress_fast_extDict(const char* source, char* dest, int originalSize,\n                                       const void* dictStart, size_t dictSize)\n{\n    return LZ4_decompress_unsafe_generic(\n                (const BYTE*)source, (BYTE*)dest, originalSize,\n                0, (const BYTE*)dictStart, dictSize);\n}\n\n/* The \"double dictionary\" mode, for use with e.g. ring buffers: the first part\n * of the dictionary is passed as prefix, and the second via dictStart + dictSize.\n * These routines are used only once, in LZ4_decompress_*_continue().\n */\nLZ4_FORCE_INLINE\nint LZ4_decompress_safe_doubleDict(const char* source, char* dest, int compressedSize, int maxOutputSize,\n                                   size_t prefixSize, const void* dictStart, size_t dictSize)\n{\n    return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize,\n                                  decode_full_block, usingExtDict,\n                                  (BYTE*)dest-prefixSize, (const BYTE*)dictStart, dictSize);\n}\n\n/*===== streaming decompression functions =====*/\n\n#if !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION)\nLZ4_streamDecode_t* LZ4_createStreamDecode(void)\n{\n    LZ4_STATIC_ASSERT(sizeof(LZ4_streamDecode_t) >= sizeof(LZ4_streamDecode_t_internal));\n    return (LZ4_streamDecode_t*) ALLOC_AND_ZERO(sizeof(LZ4_streamDecode_t));\n}\n\nint LZ4_freeStreamDecode (LZ4_streamDecode_t* LZ4_stream)\n{\n    if (LZ4_stream == NULL) { return 0; }  /* support free on NULL */\n    FREEMEM(LZ4_stream);\n    return 0;\n}\n#endif\n\n/*! LZ4_setStreamDecode() :\n *  Use this function to instruct where to find the dictionary.\n *  This function is not necessary if previous data is still available where it was decoded.\n *  Loading a size of 0 is allowed (same effect as no dictionary).\n * @return : 1 if OK, 0 if error\n */\nint LZ4_setStreamDecode (LZ4_streamDecode_t* LZ4_streamDecode, const char* dictionary, int dictSize)\n{\n    LZ4_streamDecode_t_internal* lz4sd = &LZ4_streamDecode->internal_donotuse;\n    lz4sd->prefixSize = (size_t)dictSize;\n    if (dictSize) {\n        assert(dictionary != NULL);\n        lz4sd->prefixEnd = (const BYTE*) dictionary + dictSize;\n    } else {\n        lz4sd->prefixEnd = (const BYTE*) dictionary;\n    }\n    lz4sd->externalDict = NULL;\n    lz4sd->extDictSize  = 0;\n    return 1;\n}\n\n/*! LZ4_decoderRingBufferSize() :\n *  when setting a ring buffer for streaming decompression (optional scenario),\n *  provides the minimum size of this ring buffer\n *  to be compatible with any source respecting maxBlockSize condition.\n *  Note : in a ring buffer scenario,\n *  blocks are presumed decompressed next to each other.\n *  When not enough space remains for next block (remainingSize < maxBlockSize),\n *  decoding resumes from beginning of ring buffer.\n * @return : minimum ring buffer size,\n *           or 0 if there is an error (invalid maxBlockSize).\n */\nint LZ4_decoderRingBufferSize(int maxBlockSize)\n{\n    if (maxBlockSize < 0) return 0;\n    if (maxBlockSize > LZ4_MAX_INPUT_SIZE) return 0;\n    if (maxBlockSize < 16) maxBlockSize = 16;\n    return LZ4_DECODER_RING_BUFFER_SIZE(maxBlockSize);\n}\n\n/*\n*_continue() :\n    These decoding functions allow decompression of multiple blocks in \"streaming\" mode.\n    Previously decoded blocks must still be available at the memory position where they were decoded.\n    If it's not possible, save the relevant part of decoded data into a safe buffer,\n    and indicate where it stands using LZ4_setStreamDecode()\n*/\nLZ4_FORCE_O2\nint LZ4_decompress_safe_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int compressedSize, int maxOutputSize)\n{\n    LZ4_streamDecode_t_internal* lz4sd = &LZ4_streamDecode->internal_donotuse;\n    int result;\n\n    if (lz4sd->prefixSize == 0) {\n        /* The first call, no dictionary yet. */\n        assert(lz4sd->extDictSize == 0);\n        result = LZ4_decompress_safe(source, dest, compressedSize, maxOutputSize);\n        if (result <= 0) return result;\n        lz4sd->prefixSize = (size_t)result;\n        lz4sd->prefixEnd = (BYTE*)dest + result;\n    } else if (lz4sd->prefixEnd == (BYTE*)dest) {\n        /* They're rolling the current segment. */\n        if (lz4sd->prefixSize >= 64 KB - 1)\n            result = LZ4_decompress_safe_withPrefix64k(source, dest, compressedSize, maxOutputSize);\n        else if (lz4sd->extDictSize == 0)\n            result = LZ4_decompress_safe_withSmallPrefix(source, dest, compressedSize, maxOutputSize,\n                                                         lz4sd->prefixSize);\n        else\n            result = LZ4_decompress_safe_doubleDict(source, dest, compressedSize, maxOutputSize,\n                                                    lz4sd->prefixSize, lz4sd->externalDict, lz4sd->extDictSize);\n        if (result <= 0) return result;\n        lz4sd->prefixSize += (size_t)result;\n        lz4sd->prefixEnd  += result;\n    } else {\n        /* The buffer wraps around, or they're switching to another buffer. */\n        lz4sd->extDictSize = lz4sd->prefixSize;\n        lz4sd->externalDict = lz4sd->prefixEnd - lz4sd->extDictSize;\n        result = LZ4_decompress_safe_forceExtDict(source, dest, compressedSize, maxOutputSize,\n                                                  lz4sd->externalDict, lz4sd->extDictSize);\n        if (result <= 0) return result;\n        lz4sd->prefixSize = (size_t)result;\n        lz4sd->prefixEnd  = (BYTE*)dest + result;\n    }\n\n    return result;\n}\n\nLZ4_FORCE_O2 int\nLZ4_decompress_fast_continue (LZ4_streamDecode_t* LZ4_streamDecode,\n                        const char* source, char* dest, int originalSize)\n{\n    LZ4_streamDecode_t_internal* const lz4sd =\n        (assert(LZ4_streamDecode!=NULL), &LZ4_streamDecode->internal_donotuse);\n    int result;\n\n    DEBUGLOG(5, \"LZ4_decompress_fast_continue (toDecodeSize=%i)\", originalSize);\n    assert(originalSize >= 0);\n\n    if (lz4sd->prefixSize == 0) {\n        DEBUGLOG(5, \"first invocation : no prefix nor extDict\");\n        assert(lz4sd->extDictSize == 0);\n        result = LZ4_decompress_fast(source, dest, originalSize);\n        if (result <= 0) return result;\n        lz4sd->prefixSize = (size_t)originalSize;\n        lz4sd->prefixEnd = (BYTE*)dest + originalSize;\n    } else if (lz4sd->prefixEnd == (BYTE*)dest) {\n        DEBUGLOG(5, \"continue using existing prefix\");\n        result = LZ4_decompress_unsafe_generic(\n                        (const BYTE*)source, (BYTE*)dest, originalSize,\n                        lz4sd->prefixSize,\n                        lz4sd->externalDict, lz4sd->extDictSize);\n        if (result <= 0) return result;\n        lz4sd->prefixSize += (size_t)originalSize;\n        lz4sd->prefixEnd  += originalSize;\n    } else {\n        DEBUGLOG(5, \"prefix becomes extDict\");\n        lz4sd->extDictSize = lz4sd->prefixSize;\n        lz4sd->externalDict = lz4sd->prefixEnd - lz4sd->extDictSize;\n        result = LZ4_decompress_fast_extDict(source, dest, originalSize,\n                                             lz4sd->externalDict, lz4sd->extDictSize);\n        if (result <= 0) return result;\n        lz4sd->prefixSize = (size_t)originalSize;\n        lz4sd->prefixEnd  = (BYTE*)dest + originalSize;\n    }\n\n    return result;\n}\n\n\n/*\nAdvanced decoding functions :\n*_usingDict() :\n    These decoding functions work the same as \"_continue\" ones,\n    the dictionary must be explicitly provided within parameters\n*/\n\nint LZ4_decompress_safe_usingDict(const char* source, char* dest, int compressedSize, int maxOutputSize, const char* dictStart, int dictSize)\n{\n    if (dictSize==0)\n        return LZ4_decompress_safe(source, dest, compressedSize, maxOutputSize);\n    if (dictStart+dictSize == dest) {\n        if (dictSize >= 64 KB - 1) {\n            return LZ4_decompress_safe_withPrefix64k(source, dest, compressedSize, maxOutputSize);\n        }\n        assert(dictSize >= 0);\n        return LZ4_decompress_safe_withSmallPrefix(source, dest, compressedSize, maxOutputSize, (size_t)dictSize);\n    }\n    assert(dictSize >= 0);\n    return LZ4_decompress_safe_forceExtDict(source, dest, compressedSize, maxOutputSize, dictStart, (size_t)dictSize);\n}\n\nint LZ4_decompress_safe_partial_usingDict(const char* source, char* dest, int compressedSize, int targetOutputSize, int dstCapacity, const char* dictStart, int dictSize)\n{\n    if (dictSize==0)\n        return LZ4_decompress_safe_partial(source, dest, compressedSize, targetOutputSize, dstCapacity);\n    if (dictStart+dictSize == dest) {\n        if (dictSize >= 64 KB - 1) {\n            return LZ4_decompress_safe_partial_withPrefix64k(source, dest, compressedSize, targetOutputSize, dstCapacity);\n        }\n        assert(dictSize >= 0);\n        return LZ4_decompress_safe_partial_withSmallPrefix(source, dest, compressedSize, targetOutputSize, dstCapacity, (size_t)dictSize);\n    }\n    assert(dictSize >= 0);\n    return LZ4_decompress_safe_partial_forceExtDict(source, dest, compressedSize, targetOutputSize, dstCapacity, dictStart, (size_t)dictSize);\n}\n\nint LZ4_decompress_fast_usingDict(const char* source, char* dest, int originalSize, const char* dictStart, int dictSize)\n{\n    if (dictSize==0 || dictStart+dictSize == dest)\n        return LZ4_decompress_unsafe_generic(\n                        (const BYTE*)source, (BYTE*)dest, originalSize,\n                        (size_t)dictSize, NULL, 0);\n    assert(dictSize >= 0);\n    return LZ4_decompress_fast_extDict(source, dest, originalSize, dictStart, (size_t)dictSize);\n}\n\n\n/*=*************************************************\n*  Obsolete Functions\n***************************************************/\n/* obsolete compression functions */\nint LZ4_compress_limitedOutput(const char* source, char* dest, int inputSize, int maxOutputSize)\n{\n    return LZ4_compress_default(source, dest, inputSize, maxOutputSize);\n}\nint LZ4_compress(const char* src, char* dest, int srcSize)\n{\n    return LZ4_compress_default(src, dest, srcSize, LZ4_compressBound(srcSize));\n}\nint LZ4_compress_limitedOutput_withState (void* state, const char* src, char* dst, int srcSize, int dstSize)\n{\n    return LZ4_compress_fast_extState(state, src, dst, srcSize, dstSize, 1);\n}\nint LZ4_compress_withState (void* state, const char* src, char* dst, int srcSize)\n{\n    return LZ4_compress_fast_extState(state, src, dst, srcSize, LZ4_compressBound(srcSize), 1);\n}\nint LZ4_compress_limitedOutput_continue (LZ4_stream_t* LZ4_stream, const char* src, char* dst, int srcSize, int dstCapacity)\n{\n    return LZ4_compress_fast_continue(LZ4_stream, src, dst, srcSize, dstCapacity, 1);\n}\nint LZ4_compress_continue (LZ4_stream_t* LZ4_stream, const char* source, char* dest, int inputSize)\n{\n    return LZ4_compress_fast_continue(LZ4_stream, source, dest, inputSize, LZ4_compressBound(inputSize), 1);\n}\n\n/*\nThese decompression functions are deprecated and should no longer be used.\nThey are only provided here for compatibility with older user programs.\n- LZ4_uncompress is totally equivalent to LZ4_decompress_fast\n- LZ4_uncompress_unknownOutputSize is totally equivalent to LZ4_decompress_safe\n*/\nint LZ4_uncompress (const char* source, char* dest, int outputSize)\n{\n    return LZ4_decompress_fast(source, dest, outputSize);\n}\nint LZ4_uncompress_unknownOutputSize (const char* source, char* dest, int isize, int maxOutputSize)\n{\n    return LZ4_decompress_safe(source, dest, isize, maxOutputSize);\n}\n\n/* Obsolete Streaming functions */\n\nint LZ4_sizeofStreamState(void) { return sizeof(LZ4_stream_t); }\n\nint LZ4_resetStreamState(void* state, char* inputBuffer)\n{\n    (void)inputBuffer;\n    LZ4_resetStream((LZ4_stream_t*)state);\n    return 0;\n}\n\n#if !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION)\nvoid* LZ4_create (char* inputBuffer)\n{\n    (void)inputBuffer;\n    return LZ4_createStream();\n}\n#endif\n\nchar* LZ4_slideInputBuffer (void* state)\n{\n    /* avoid const char * -> char * conversion warning */\n    return (char *)(uptrval)((LZ4_stream_t*)state)->internal_donotuse.dictionary;\n}\n\n#endif   /* LZ4_COMMONDEFS_ONLY */\n\n}\n"
  },
  {
    "path": "tracy-client-sys/tracy/common/tracy_lz4.hpp",
    "content": "/*\n *  LZ4 - Fast LZ compression algorithm\n *  Header File\n *  Copyright (C) 2011-2020, Yann Collet.\n\n   BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)\n\n   Redistribution and use in source and binary forms, with or without\n   modification, are permitted provided that the following conditions are\n   met:\n\n       * Redistributions of source code must retain the above copyright\n   notice, this list of conditions and the following disclaimer.\n       * Redistributions in binary form must reproduce the above\n   copyright notice, this list of conditions and the following disclaimer\n   in the documentation and/or other materials provided with the\n   distribution.\n\n   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n   \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n   You can contact the author at :\n    - LZ4 homepage : http://www.lz4.org\n    - LZ4 source repository : https://github.com/lz4/lz4\n*/\n\n#ifndef TRACY_LZ4_H_2983827168210\n#define TRACY_LZ4_H_2983827168210\n\n/* --- Dependency --- */\n#include <stddef.h>   /* size_t */\n#include <stdint.h>\n\n\n/**\n  Introduction\n\n  LZ4 is lossless compression algorithm, providing compression speed >500 MB/s per core,\n  scalable with multi-cores CPU. It features an extremely fast decoder, with speed in\n  multiple GB/s per core, typically reaching RAM speed limits on multi-core systems.\n\n  The LZ4 compression library provides in-memory compression and decompression functions.\n  It gives full buffer control to user.\n  Compression can be done in:\n    - a single step (described as Simple Functions)\n    - a single step, reusing a context (described in Advanced Functions)\n    - unbounded multiple steps (described as Streaming compression)\n\n  lz4.h generates and decodes LZ4-compressed blocks (doc/lz4_Block_format.md).\n  Decompressing such a compressed block requires additional metadata.\n  Exact metadata depends on exact decompression function.\n  For the typical case of LZ4_decompress_safe(),\n  metadata includes block's compressed size, and maximum bound of decompressed size.\n  Each application is free to encode and pass such metadata in whichever way it wants.\n\n  lz4.h only handle blocks, it can not generate Frames.\n\n  Blocks are different from Frames (doc/lz4_Frame_format.md).\n  Frames bundle both blocks and metadata in a specified manner.\n  Embedding metadata is required for compressed data to be self-contained and portable.\n  Frame format is delivered through a companion API, declared in lz4frame.h.\n  The `lz4` CLI can only manage frames.\n*/\n\n/*^***************************************************************\n*  Export parameters\n*****************************************************************/\n/*\n*  LZ4_DLL_EXPORT :\n*  Enable exporting of functions when building a Windows DLL\n*  LZ4LIB_VISIBILITY :\n*  Control library symbols visibility.\n*/\n#ifndef LZ4LIB_VISIBILITY\n#  if defined(__GNUC__) && (__GNUC__ >= 4)\n#    define LZ4LIB_VISIBILITY __attribute__ ((visibility (\"default\")))\n#  else\n#    define LZ4LIB_VISIBILITY\n#  endif\n#endif\n#if defined(LZ4_DLL_EXPORT) && (LZ4_DLL_EXPORT==1)\n#  define LZ4LIB_API __declspec(dllexport) LZ4LIB_VISIBILITY\n#elif defined(LZ4_DLL_IMPORT) && (LZ4_DLL_IMPORT==1)\n#  define LZ4LIB_API __declspec(dllimport) LZ4LIB_VISIBILITY /* It isn't required but allows to generate better code, saving a function pointer load from the IAT and an indirect jump.*/\n#else\n#  define LZ4LIB_API LZ4LIB_VISIBILITY\n#endif\n\n/*! LZ4_FREESTANDING :\n *  When this macro is set to 1, it enables \"freestanding mode\" that is\n *  suitable for typical freestanding environment which doesn't support\n *  standard C library.\n *\n *  - LZ4_FREESTANDING is a compile-time switch.\n *  - It requires the following macros to be defined:\n *    LZ4_memcpy, LZ4_memmove, LZ4_memset.\n *  - It only enables LZ4/HC functions which don't use heap.\n *    All LZ4F_* functions are not supported.\n *  - See tests/freestanding.c to check its basic setup.\n */\n#if defined(LZ4_FREESTANDING) && (LZ4_FREESTANDING == 1)\n#  define LZ4_HEAPMODE 0\n#  define LZ4HC_HEAPMODE 0\n#  define LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION 1\n#  if !defined(LZ4_memcpy)\n#    error \"LZ4_FREESTANDING requires macro 'LZ4_memcpy'.\"\n#  endif\n#  if !defined(LZ4_memset)\n#    error \"LZ4_FREESTANDING requires macro 'LZ4_memset'.\"\n#  endif\n#  if !defined(LZ4_memmove)\n#    error \"LZ4_FREESTANDING requires macro 'LZ4_memmove'.\"\n#  endif\n#elif ! defined(LZ4_FREESTANDING)\n#  define LZ4_FREESTANDING 0\n#endif\n\n\n/*------   Version   ------*/\n#define LZ4_VERSION_MAJOR    1    /* for breaking interface changes  */\n#define LZ4_VERSION_MINOR    9    /* for new (non-breaking) interface capabilities */\n#define LZ4_VERSION_RELEASE  4    /* for tweaks, bug-fixes, or development */\n\n#define LZ4_VERSION_NUMBER (LZ4_VERSION_MAJOR *100*100 + LZ4_VERSION_MINOR *100 + LZ4_VERSION_RELEASE)\n\n#define LZ4_LIB_VERSION LZ4_VERSION_MAJOR.LZ4_VERSION_MINOR.LZ4_VERSION_RELEASE\n#define LZ4_QUOTE(str) #str\n#define LZ4_EXPAND_AND_QUOTE(str) LZ4_QUOTE(str)\n#define LZ4_VERSION_STRING LZ4_EXPAND_AND_QUOTE(LZ4_LIB_VERSION)  /* requires v1.7.3+ */\n\nnamespace tracy\n{\n\nLZ4LIB_API int LZ4_versionNumber (void);  /**< library version number; useful to check dll version; requires v1.3.0+ */\nLZ4LIB_API const char* LZ4_versionString (void);   /**< library version string; useful to check dll version; requires v1.7.5+ */\n\n\n/*-************************************\n*  Tuning parameter\n**************************************/\n#define LZ4_MEMORY_USAGE_MIN 10\n#define LZ4_MEMORY_USAGE_DEFAULT 14\n#define LZ4_MEMORY_USAGE_MAX 20\n\n/*!\n * LZ4_MEMORY_USAGE :\n * Memory usage formula : N->2^N Bytes (examples : 10 -> 1KB; 12 -> 4KB ; 16 -> 64KB; 20 -> 1MB; )\n * Increasing memory usage improves compression ratio, at the cost of speed.\n * Reduced memory usage may improve speed at the cost of ratio, thanks to better cache locality.\n * Default value is 14, for 16KB, which nicely fits into Intel x86 L1 cache\n */\n#ifndef LZ4_MEMORY_USAGE\n# define LZ4_MEMORY_USAGE LZ4_MEMORY_USAGE_DEFAULT\n#endif\n\n#if (LZ4_MEMORY_USAGE < LZ4_MEMORY_USAGE_MIN)\n#  error \"LZ4_MEMORY_USAGE is too small !\"\n#endif\n\n#if (LZ4_MEMORY_USAGE > LZ4_MEMORY_USAGE_MAX)\n#  error \"LZ4_MEMORY_USAGE is too large !\"\n#endif\n\n/*-************************************\n*  Simple Functions\n**************************************/\n/*! LZ4_compress_default() :\n *  Compresses 'srcSize' bytes from buffer 'src'\n *  into already allocated 'dst' buffer of size 'dstCapacity'.\n *  Compression is guaranteed to succeed if 'dstCapacity' >= LZ4_compressBound(srcSize).\n *  It also runs faster, so it's a recommended setting.\n *  If the function cannot compress 'src' into a more limited 'dst' budget,\n *  compression stops *immediately*, and the function result is zero.\n *  In which case, 'dst' content is undefined (invalid).\n *      srcSize : max supported value is LZ4_MAX_INPUT_SIZE.\n *      dstCapacity : size of buffer 'dst' (which must be already allocated)\n *     @return  : the number of bytes written into buffer 'dst' (necessarily <= dstCapacity)\n *                or 0 if compression fails\n * Note : This function is protected against buffer overflow scenarios (never writes outside 'dst' buffer, nor read outside 'source' buffer).\n */\nLZ4LIB_API int LZ4_compress_default(const char* src, char* dst, int srcSize, int dstCapacity);\n\n/*! LZ4_decompress_safe() :\n *  compressedSize : is the exact complete size of the compressed block.\n *  dstCapacity : is the size of destination buffer (which must be already allocated), presumed an upper bound of decompressed size.\n * @return : the number of bytes decompressed into destination buffer (necessarily <= dstCapacity)\n *           If destination buffer is not large enough, decoding will stop and output an error code (negative value).\n *           If the source stream is detected malformed, the function will stop decoding and return a negative result.\n * Note 1 : This function is protected against malicious data packets :\n *          it will never writes outside 'dst' buffer, nor read outside 'source' buffer,\n *          even if the compressed block is maliciously modified to order the decoder to do these actions.\n *          In such case, the decoder stops immediately, and considers the compressed block malformed.\n * Note 2 : compressedSize and dstCapacity must be provided to the function, the compressed block does not contain them.\n *          The implementation is free to send / store / derive this information in whichever way is most beneficial.\n *          If there is a need for a different format which bundles together both compressed data and its metadata, consider looking at lz4frame.h instead.\n */\nLZ4LIB_API int LZ4_decompress_safe (const char* src, char* dst, int compressedSize, int dstCapacity);\n\n\n/*-************************************\n*  Advanced Functions\n**************************************/\n#define LZ4_MAX_INPUT_SIZE        0x7E000000   /* 2 113 929 216 bytes */\n#define LZ4_COMPRESSBOUND(isize)  ((unsigned)(isize) > (unsigned)LZ4_MAX_INPUT_SIZE ? 0 : (isize) + ((isize)/255) + 16)\n\n/*! LZ4_compressBound() :\n    Provides the maximum size that LZ4 compression may output in a \"worst case\" scenario (input data not compressible)\n    This function is primarily useful for memory allocation purposes (destination buffer size).\n    Macro LZ4_COMPRESSBOUND() is also provided for compilation-time evaluation (stack memory allocation for example).\n    Note that LZ4_compress_default() compresses faster when dstCapacity is >= LZ4_compressBound(srcSize)\n        inputSize  : max supported value is LZ4_MAX_INPUT_SIZE\n        return : maximum output size in a \"worst case\" scenario\n              or 0, if input size is incorrect (too large or negative)\n*/\nLZ4LIB_API int LZ4_compressBound(int inputSize);\n\n/*! LZ4_compress_fast() :\n    Same as LZ4_compress_default(), but allows selection of \"acceleration\" factor.\n    The larger the acceleration value, the faster the algorithm, but also the lesser the compression.\n    It's a trade-off. It can be fine tuned, with each successive value providing roughly +~3% to speed.\n    An acceleration value of \"1\" is the same as regular LZ4_compress_default()\n    Values <= 0 will be replaced by LZ4_ACCELERATION_DEFAULT (currently == 1, see lz4.c).\n    Values > LZ4_ACCELERATION_MAX will be replaced by LZ4_ACCELERATION_MAX (currently == 65537, see lz4.c).\n*/\nLZ4LIB_API int LZ4_compress_fast (const char* src, char* dst, int srcSize, int dstCapacity, int acceleration);\n\n\n/*! LZ4_compress_fast_extState() :\n *  Same as LZ4_compress_fast(), using an externally allocated memory space for its state.\n *  Use LZ4_sizeofState() to know how much memory must be allocated,\n *  and allocate it on 8-bytes boundaries (using `malloc()` typically).\n *  Then, provide this buffer as `void* state` to compression function.\n */\nLZ4LIB_API int LZ4_sizeofState(void);\nLZ4LIB_API int LZ4_compress_fast_extState (void* state, const char* src, char* dst, int srcSize, int dstCapacity, int acceleration);\n\n\n/*! LZ4_compress_destSize() :\n *  Reverse the logic : compresses as much data as possible from 'src' buffer\n *  into already allocated buffer 'dst', of size >= 'targetDestSize'.\n *  This function either compresses the entire 'src' content into 'dst' if it's large enough,\n *  or fill 'dst' buffer completely with as much data as possible from 'src'.\n *  note: acceleration parameter is fixed to \"default\".\n *\n * *srcSizePtr : will be modified to indicate how many bytes where read from 'src' to fill 'dst'.\n *               New value is necessarily <= input value.\n * @return : Nb bytes written into 'dst' (necessarily <= targetDestSize)\n *           or 0 if compression fails.\n *\n * Note : from v1.8.2 to v1.9.1, this function had a bug (fixed un v1.9.2+):\n *        the produced compressed content could, in specific circumstances,\n *        require to be decompressed into a destination buffer larger\n *        by at least 1 byte than the content to decompress.\n *        If an application uses `LZ4_compress_destSize()`,\n *        it's highly recommended to update liblz4 to v1.9.2 or better.\n *        If this can't be done or ensured,\n *        the receiving decompression function should provide\n *        a dstCapacity which is > decompressedSize, by at least 1 byte.\n *        See https://github.com/lz4/lz4/issues/859 for details\n */\nLZ4LIB_API int LZ4_compress_destSize (const char* src, char* dst, int* srcSizePtr, int targetDstSize);\n\n\n/*! LZ4_decompress_safe_partial() :\n *  Decompress an LZ4 compressed block, of size 'srcSize' at position 'src',\n *  into destination buffer 'dst' of size 'dstCapacity'.\n *  Up to 'targetOutputSize' bytes will be decoded.\n *  The function stops decoding on reaching this objective.\n *  This can be useful to boost performance\n *  whenever only the beginning of a block is required.\n *\n * @return : the number of bytes decoded in `dst` (necessarily <= targetOutputSize)\n *           If source stream is detected malformed, function returns a negative result.\n *\n *  Note 1 : @return can be < targetOutputSize, if compressed block contains less data.\n *\n *  Note 2 : targetOutputSize must be <= dstCapacity\n *\n *  Note 3 : this function effectively stops decoding on reaching targetOutputSize,\n *           so dstCapacity is kind of redundant.\n *           This is because in older versions of this function,\n *           decoding operation would still write complete sequences.\n *           Therefore, there was no guarantee that it would stop writing at exactly targetOutputSize,\n *           it could write more bytes, though only up to dstCapacity.\n *           Some \"margin\" used to be required for this operation to work properly.\n *           Thankfully, this is no longer necessary.\n *           The function nonetheless keeps the same signature, in an effort to preserve API compatibility.\n *\n *  Note 4 : If srcSize is the exact size of the block,\n *           then targetOutputSize can be any value,\n *           including larger than the block's decompressed size.\n *           The function will, at most, generate block's decompressed size.\n *\n *  Note 5 : If srcSize is _larger_ than block's compressed size,\n *           then targetOutputSize **MUST** be <= block's decompressed size.\n *           Otherwise, *silent corruption will occur*.\n */\nLZ4LIB_API int LZ4_decompress_safe_partial (const char* src, char* dst, int srcSize, int targetOutputSize, int dstCapacity);\n\n\n/*-*********************************************\n*  Streaming Compression Functions\n***********************************************/\ntypedef union LZ4_stream_u LZ4_stream_t;  /* incomplete type (defined later) */\n\n/**\n Note about RC_INVOKED\n\n - RC_INVOKED is predefined symbol of rc.exe (the resource compiler which is part of MSVC/Visual Studio).\n   https://docs.microsoft.com/en-us/windows/win32/menurc/predefined-macros\n\n - Since rc.exe is a legacy compiler, it truncates long symbol (> 30 chars)\n   and reports warning \"RC4011: identifier truncated\".\n\n - To eliminate the warning, we surround long preprocessor symbol with\n   \"#if !defined(RC_INVOKED) ... #endif\" block that means\n   \"skip this block when rc.exe is trying to read it\".\n*/\n#if !defined(RC_INVOKED) /* https://docs.microsoft.com/en-us/windows/win32/menurc/predefined-macros */\n#if !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION)\nLZ4LIB_API LZ4_stream_t* LZ4_createStream(void);\nLZ4LIB_API int           LZ4_freeStream (LZ4_stream_t* streamPtr);\n#endif /* !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION) */\n#endif\n\n/*! LZ4_resetStream_fast() : v1.9.0+\n *  Use this to prepare an LZ4_stream_t for a new chain of dependent blocks\n *  (e.g., LZ4_compress_fast_continue()).\n *\n *  An LZ4_stream_t must be initialized once before usage.\n *  This is automatically done when created by LZ4_createStream().\n *  However, should the LZ4_stream_t be simply declared on stack (for example),\n *  it's necessary to initialize it first, using LZ4_initStream().\n *\n *  After init, start any new stream with LZ4_resetStream_fast().\n *  A same LZ4_stream_t can be re-used multiple times consecutively\n *  and compress multiple streams,\n *  provided that it starts each new stream with LZ4_resetStream_fast().\n *\n *  LZ4_resetStream_fast() is much faster than LZ4_initStream(),\n *  but is not compatible with memory regions containing garbage data.\n *\n *  Note: it's only useful to call LZ4_resetStream_fast()\n *        in the context of streaming compression.\n *        The *extState* functions perform their own resets.\n *        Invoking LZ4_resetStream_fast() before is redundant, and even counterproductive.\n */\nLZ4LIB_API void LZ4_resetStream_fast (LZ4_stream_t* streamPtr);\n\n/*! LZ4_loadDict() :\n *  Use this function to reference a static dictionary into LZ4_stream_t.\n *  The dictionary must remain available during compression.\n *  LZ4_loadDict() triggers a reset, so any previous data will be forgotten.\n *  The same dictionary will have to be loaded on decompression side for successful decoding.\n *  Dictionary are useful for better compression of small data (KB range).\n *  While LZ4 accept any input as dictionary,\n *  results are generally better when using Zstandard's Dictionary Builder.\n *  Loading a size of 0 is allowed, and is the same as reset.\n * @return : loaded dictionary size, in bytes (necessarily <= 64 KB)\n */\nLZ4LIB_API int LZ4_loadDict (LZ4_stream_t* streamPtr, const char* dictionary, int dictSize);\n\n/*! LZ4_compress_fast_continue() :\n *  Compress 'src' content using data from previously compressed blocks, for better compression ratio.\n * 'dst' buffer must be already allocated.\n *  If dstCapacity >= LZ4_compressBound(srcSize), compression is guaranteed to succeed, and runs faster.\n *\n * @return : size of compressed block\n *           or 0 if there is an error (typically, cannot fit into 'dst').\n *\n *  Note 1 : Each invocation to LZ4_compress_fast_continue() generates a new block.\n *           Each block has precise boundaries.\n *           Each block must be decompressed separately, calling LZ4_decompress_*() with relevant metadata.\n *           It's not possible to append blocks together and expect a single invocation of LZ4_decompress_*() to decompress them together.\n *\n *  Note 2 : The previous 64KB of source data is __assumed__ to remain present, unmodified, at same address in memory !\n *\n *  Note 3 : When input is structured as a double-buffer, each buffer can have any size, including < 64 KB.\n *           Make sure that buffers are separated, by at least one byte.\n *           This construction ensures that each block only depends on previous block.\n *\n *  Note 4 : If input buffer is a ring-buffer, it can have any size, including < 64 KB.\n *\n *  Note 5 : After an error, the stream status is undefined (invalid), it can only be reset or freed.\n */\nLZ4LIB_API int LZ4_compress_fast_continue (LZ4_stream_t* streamPtr, const char* src, char* dst, int srcSize, int dstCapacity, int acceleration);\n\n/*! LZ4_saveDict() :\n *  If last 64KB data cannot be guaranteed to remain available at its current memory location,\n *  save it into a safer place (char* safeBuffer).\n *  This is schematically equivalent to a memcpy() followed by LZ4_loadDict(),\n *  but is much faster, because LZ4_saveDict() doesn't need to rebuild tables.\n * @return : saved dictionary size in bytes (necessarily <= maxDictSize), or 0 if error.\n */\nLZ4LIB_API int LZ4_saveDict (LZ4_stream_t* streamPtr, char* safeBuffer, int maxDictSize);\n\n\n/*-**********************************************\n*  Streaming Decompression Functions\n*  Bufferless synchronous API\n************************************************/\ntypedef union LZ4_streamDecode_u LZ4_streamDecode_t;   /* tracking context */\n\n/*! LZ4_createStreamDecode() and LZ4_freeStreamDecode() :\n *  creation / destruction of streaming decompression tracking context.\n *  A tracking context can be re-used multiple times.\n */\n#if !defined(RC_INVOKED) /* https://docs.microsoft.com/en-us/windows/win32/menurc/predefined-macros */\n#if !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION)\nLZ4LIB_API LZ4_streamDecode_t* LZ4_createStreamDecode(void);\nLZ4LIB_API int                 LZ4_freeStreamDecode (LZ4_streamDecode_t* LZ4_stream);\n#endif /* !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION) */\n#endif\n\n/*! LZ4_setStreamDecode() :\n *  An LZ4_streamDecode_t context can be allocated once and re-used multiple times.\n *  Use this function to start decompression of a new stream of blocks.\n *  A dictionary can optionally be set. Use NULL or size 0 for a reset order.\n *  Dictionary is presumed stable : it must remain accessible and unmodified during next decompression.\n * @return : 1 if OK, 0 if error\n */\nLZ4LIB_API int LZ4_setStreamDecode (LZ4_streamDecode_t* LZ4_streamDecode, const char* dictionary, int dictSize);\n\n/*! LZ4_decoderRingBufferSize() : v1.8.2+\n *  Note : in a ring buffer scenario (optional),\n *  blocks are presumed decompressed next to each other\n *  up to the moment there is not enough remaining space for next block (remainingSize < maxBlockSize),\n *  at which stage it resumes from beginning of ring buffer.\n *  When setting such a ring buffer for streaming decompression,\n *  provides the minimum size of this ring buffer\n *  to be compatible with any source respecting maxBlockSize condition.\n * @return : minimum ring buffer size,\n *           or 0 if there is an error (invalid maxBlockSize).\n */\nLZ4LIB_API int LZ4_decoderRingBufferSize(int maxBlockSize);\n#define LZ4_DECODER_RING_BUFFER_SIZE(maxBlockSize) (65536 + 14 + (maxBlockSize))  /* for static allocation; maxBlockSize presumed valid */\n\n/*! LZ4_decompress_*_continue() :\n *  These decoding functions allow decompression of consecutive blocks in \"streaming\" mode.\n *  A block is an unsplittable entity, it must be presented entirely to a decompression function.\n *  Decompression functions only accepts one block at a time.\n *  The last 64KB of previously decoded data *must* remain available and unmodified at the memory position where they were decoded.\n *  If less than 64KB of data has been decoded, all the data must be present.\n *\n *  Special : if decompression side sets a ring buffer, it must respect one of the following conditions :\n *  - Decompression buffer size is _at least_ LZ4_decoderRingBufferSize(maxBlockSize).\n *    maxBlockSize is the maximum size of any single block. It can have any value > 16 bytes.\n *    In which case, encoding and decoding buffers do not need to be synchronized.\n *    Actually, data can be produced by any source compliant with LZ4 format specification, and respecting maxBlockSize.\n *  - Synchronized mode :\n *    Decompression buffer size is _exactly_ the same as compression buffer size,\n *    and follows exactly same update rule (block boundaries at same positions),\n *    and decoding function is provided with exact decompressed size of each block (exception for last block of the stream),\n *    _then_ decoding & encoding ring buffer can have any size, including small ones ( < 64 KB).\n *  - Decompression buffer is larger than encoding buffer, by a minimum of maxBlockSize more bytes.\n *    In which case, encoding and decoding buffers do not need to be synchronized,\n *    and encoding ring buffer can have any size, including small ones ( < 64 KB).\n *\n *  Whenever these conditions are not possible,\n *  save the last 64KB of decoded data into a safe buffer where it can't be modified during decompression,\n *  then indicate where this data is saved using LZ4_setStreamDecode(), before decompressing next block.\n*/\nLZ4LIB_API int\nLZ4_decompress_safe_continue (LZ4_streamDecode_t* LZ4_streamDecode,\n                        const char* src, char* dst,\n                        int srcSize, int dstCapacity);\n\n\n/*! LZ4_decompress_*_usingDict() :\n *  These decoding functions work the same as\n *  a combination of LZ4_setStreamDecode() followed by LZ4_decompress_*_continue()\n *  They are stand-alone, and don't need an LZ4_streamDecode_t structure.\n *  Dictionary is presumed stable : it must remain accessible and unmodified during decompression.\n *  Performance tip : Decompression speed can be substantially increased\n *                    when dst == dictStart + dictSize.\n */\nLZ4LIB_API int\nLZ4_decompress_safe_usingDict(const char* src, char* dst,\n                              int srcSize, int dstCapacity,\n                              const char* dictStart, int dictSize);\n\nLZ4LIB_API int\nLZ4_decompress_safe_partial_usingDict(const char* src, char* dst,\n                                      int compressedSize,\n                                      int targetOutputSize, int maxOutputSize,\n                                      const char* dictStart, int dictSize);\n\n}\n\n#endif /* LZ4_H_2983827168210 */\n\n\n/*^*************************************\n * !!!!!!   STATIC LINKING ONLY   !!!!!!\n ***************************************/\n\n/*-****************************************************************************\n * Experimental section\n *\n * Symbols declared in this section must be considered unstable. Their\n * signatures or semantics may change, or they may be removed altogether in the\n * future. They are therefore only safe to depend on when the caller is\n * statically linked against the library.\n *\n * To protect against unsafe usage, not only are the declarations guarded,\n * the definitions are hidden by default\n * when building LZ4 as a shared/dynamic library.\n *\n * In order to access these declarations,\n * define LZ4_STATIC_LINKING_ONLY in your application\n * before including LZ4's headers.\n *\n * In order to make their implementations accessible dynamically, you must\n * define LZ4_PUBLISH_STATIC_FUNCTIONS when building the LZ4 library.\n ******************************************************************************/\n\n#ifdef LZ4_STATIC_LINKING_ONLY\n\n#ifndef TRACY_LZ4_STATIC_3504398509\n#define TRACY_LZ4_STATIC_3504398509\n\n#ifdef LZ4_PUBLISH_STATIC_FUNCTIONS\n#define LZ4LIB_STATIC_API LZ4LIB_API\n#else\n#define LZ4LIB_STATIC_API\n#endif\n\nnamespace tracy\n{\n\n/*! LZ4_compress_fast_extState_fastReset() :\n *  A variant of LZ4_compress_fast_extState().\n *\n *  Using this variant avoids an expensive initialization step.\n *  It is only safe to call if the state buffer is known to be correctly initialized already\n *  (see above comment on LZ4_resetStream_fast() for a definition of \"correctly initialized\").\n *  From a high level, the difference is that\n *  this function initializes the provided state with a call to something like LZ4_resetStream_fast()\n *  while LZ4_compress_fast_extState() starts with a call to LZ4_resetStream().\n */\nLZ4LIB_STATIC_API int LZ4_compress_fast_extState_fastReset (void* state, const char* src, char* dst, int srcSize, int dstCapacity, int acceleration);\n\n/*! LZ4_attach_dictionary() :\n *  This is an experimental API that allows\n *  efficient use of a static dictionary many times.\n *\n *  Rather than re-loading the dictionary buffer into a working context before\n *  each compression, or copying a pre-loaded dictionary's LZ4_stream_t into a\n *  working LZ4_stream_t, this function introduces a no-copy setup mechanism,\n *  in which the working stream references the dictionary stream in-place.\n *\n *  Several assumptions are made about the state of the dictionary stream.\n *  Currently, only streams which have been prepared by LZ4_loadDict() should\n *  be expected to work.\n *\n *  Alternatively, the provided dictionaryStream may be NULL,\n *  in which case any existing dictionary stream is unset.\n *\n *  If a dictionary is provided, it replaces any pre-existing stream history.\n *  The dictionary contents are the only history that can be referenced and\n *  logically immediately precede the data compressed in the first subsequent\n *  compression call.\n *\n *  The dictionary will only remain attached to the working stream through the\n *  first compression call, at the end of which it is cleared. The dictionary\n *  stream (and source buffer) must remain in-place / accessible / unchanged\n *  through the completion of the first compression call on the stream.\n */\nLZ4LIB_STATIC_API void\nLZ4_attach_dictionary(LZ4_stream_t* workingStream,\n                const LZ4_stream_t* dictionaryStream);\n\n\n/*! In-place compression and decompression\n *\n * It's possible to have input and output sharing the same buffer,\n * for highly constrained memory environments.\n * In both cases, it requires input to lay at the end of the buffer,\n * and decompression to start at beginning of the buffer.\n * Buffer size must feature some margin, hence be larger than final size.\n *\n * |<------------------------buffer--------------------------------->|\n *                             |<-----------compressed data--------->|\n * |<-----------decompressed size------------------>|\n *                                                  |<----margin---->|\n *\n * This technique is more useful for decompression,\n * since decompressed size is typically larger,\n * and margin is short.\n *\n * In-place decompression will work inside any buffer\n * which size is >= LZ4_DECOMPRESS_INPLACE_BUFFER_SIZE(decompressedSize).\n * This presumes that decompressedSize > compressedSize.\n * Otherwise, it means compression actually expanded data,\n * and it would be more efficient to store such data with a flag indicating it's not compressed.\n * This can happen when data is not compressible (already compressed, or encrypted).\n *\n * For in-place compression, margin is larger, as it must be able to cope with both\n * history preservation, requiring input data to remain unmodified up to LZ4_DISTANCE_MAX,\n * and data expansion, which can happen when input is not compressible.\n * As a consequence, buffer size requirements are much higher,\n * and memory savings offered by in-place compression are more limited.\n *\n * There are ways to limit this cost for compression :\n * - Reduce history size, by modifying LZ4_DISTANCE_MAX.\n *   Note that it is a compile-time constant, so all compressions will apply this limit.\n *   Lower values will reduce compression ratio, except when input_size < LZ4_DISTANCE_MAX,\n *   so it's a reasonable trick when inputs are known to be small.\n * - Require the compressor to deliver a \"maximum compressed size\".\n *   This is the `dstCapacity` parameter in `LZ4_compress*()`.\n *   When this size is < LZ4_COMPRESSBOUND(inputSize), then compression can fail,\n *   in which case, the return code will be 0 (zero).\n *   The caller must be ready for these cases to happen,\n *   and typically design a backup scheme to send data uncompressed.\n * The combination of both techniques can significantly reduce\n * the amount of margin required for in-place compression.\n *\n * In-place compression can work in any buffer\n * which size is >= (maxCompressedSize)\n * with maxCompressedSize == LZ4_COMPRESSBOUND(srcSize) for guaranteed compression success.\n * LZ4_COMPRESS_INPLACE_BUFFER_SIZE() depends on both maxCompressedSize and LZ4_DISTANCE_MAX,\n * so it's possible to reduce memory requirements by playing with them.\n */\n\n#define LZ4_DECOMPRESS_INPLACE_MARGIN(compressedSize)          (((compressedSize) >> 8) + 32)\n#define LZ4_DECOMPRESS_INPLACE_BUFFER_SIZE(decompressedSize)   ((decompressedSize) + LZ4_DECOMPRESS_INPLACE_MARGIN(decompressedSize))  /**< note: presumes that compressedSize < decompressedSize. note2: margin is overestimated a bit, since it could use compressedSize instead */\n\n#ifndef LZ4_DISTANCE_MAX   /* history window size; can be user-defined at compile time */\n#  define LZ4_DISTANCE_MAX 65535   /* set to maximum value by default */\n#endif\n\n#define LZ4_COMPRESS_INPLACE_MARGIN                           (LZ4_DISTANCE_MAX + 32)   /* LZ4_DISTANCE_MAX can be safely replaced by srcSize when it's smaller */\n#define LZ4_COMPRESS_INPLACE_BUFFER_SIZE(maxCompressedSize)   ((maxCompressedSize) + LZ4_COMPRESS_INPLACE_MARGIN)  /**< maxCompressedSize is generally LZ4_COMPRESSBOUND(inputSize), but can be set to any lower value, with the risk that compression can fail (return code 0(zero)) */\n\n}\n\n#endif   /* LZ4_STATIC_3504398509 */\n#endif   /* LZ4_STATIC_LINKING_ONLY */\n\n\n\n#ifndef TRACY_LZ4_H_98237428734687\n#define TRACY_LZ4_H_98237428734687\n\nnamespace tracy\n{\n\n/*-************************************************************\n *  Private Definitions\n **************************************************************\n * Do not use these definitions directly.\n * They are only exposed to allow static allocation of `LZ4_stream_t` and `LZ4_streamDecode_t`.\n * Accessing members will expose user code to API and/or ABI break in future versions of the library.\n **************************************************************/\n#define LZ4_HASHLOG   (LZ4_MEMORY_USAGE-2)\n#define LZ4_HASHTABLESIZE (1 << LZ4_MEMORY_USAGE)\n#define LZ4_HASH_SIZE_U32 (1 << LZ4_HASHLOG)       /* required as macro for static allocation */\n\n#if defined(__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */)\n  typedef  int8_t  LZ4_i8;\n  typedef uint8_t  LZ4_byte;\n  typedef uint16_t LZ4_u16;\n  typedef uint32_t LZ4_u32;\n#else\n  typedef   signed char  LZ4_i8;\n  typedef unsigned char  LZ4_byte;\n  typedef unsigned short LZ4_u16;\n  typedef unsigned int   LZ4_u32;\n#endif\n\n/*! LZ4_stream_t :\n *  Never ever use below internal definitions directly !\n *  These definitions are not API/ABI safe, and may change in future versions.\n *  If you need static allocation, declare or allocate an LZ4_stream_t object.\n**/\n\ntypedef struct LZ4_stream_t_internal LZ4_stream_t_internal;\nstruct LZ4_stream_t_internal {\n    LZ4_u32 hashTable[LZ4_HASH_SIZE_U32];\n    const LZ4_byte* dictionary;\n    const LZ4_stream_t_internal* dictCtx;\n    LZ4_u32 currentOffset;\n    LZ4_u32 tableType;\n    LZ4_u32 dictSize;\n    /* Implicit padding to ensure structure is aligned */\n};\n\n#define LZ4_STREAM_MINSIZE  ((1UL << LZ4_MEMORY_USAGE) + 32)  /* static size, for inter-version compatibility */\nunion LZ4_stream_u {\n    char minStateSize[LZ4_STREAM_MINSIZE];\n    LZ4_stream_t_internal internal_donotuse;\n}; /* previously typedef'd to LZ4_stream_t */\n\n\n/*! LZ4_initStream() : v1.9.0+\n *  An LZ4_stream_t structure must be initialized at least once.\n *  This is automatically done when invoking LZ4_createStream(),\n *  but it's not when the structure is simply declared on stack (for example).\n *\n *  Use LZ4_initStream() to properly initialize a newly declared LZ4_stream_t.\n *  It can also initialize any arbitrary buffer of sufficient size,\n *  and will @return a pointer of proper type upon initialization.\n *\n *  Note : initialization fails if size and alignment conditions are not respected.\n *         In which case, the function will @return NULL.\n *  Note2: An LZ4_stream_t structure guarantees correct alignment and size.\n *  Note3: Before v1.9.0, use LZ4_resetStream() instead\n**/\nLZ4LIB_API LZ4_stream_t* LZ4_initStream (void* buffer, size_t size);\n\n\n/*! LZ4_streamDecode_t :\n *  Never ever use below internal definitions directly !\n *  These definitions are not API/ABI safe, and may change in future versions.\n *  If you need static allocation, declare or allocate an LZ4_streamDecode_t object.\n**/\ntypedef struct {\n    const LZ4_byte* externalDict;\n    const LZ4_byte* prefixEnd;\n    size_t extDictSize;\n    size_t prefixSize;\n} LZ4_streamDecode_t_internal;\n\n#define LZ4_STREAMDECODE_MINSIZE 32\nunion LZ4_streamDecode_u {\n    char minStateSize[LZ4_STREAMDECODE_MINSIZE];\n    LZ4_streamDecode_t_internal internal_donotuse;\n} ;   /* previously typedef'd to LZ4_streamDecode_t */\n\n\n\n/*-************************************\n*  Obsolete Functions\n**************************************/\n\n/*! Deprecation warnings\n *\n *  Deprecated functions make the compiler generate a warning when invoked.\n *  This is meant to invite users to update their source code.\n *  Should deprecation warnings be a problem, it is generally possible to disable them,\n *  typically with -Wno-deprecated-declarations for gcc\n *  or _CRT_SECURE_NO_WARNINGS in Visual.\n *\n *  Another method is to define LZ4_DISABLE_DEPRECATE_WARNINGS\n *  before including the header file.\n */\n#ifdef LZ4_DISABLE_DEPRECATE_WARNINGS\n#  define LZ4_DEPRECATED(message)   /* disable deprecation warnings */\n#else\n#  if defined (__cplusplus) && (__cplusplus >= 201402) /* C++14 or greater */\n#    define LZ4_DEPRECATED(message) [[deprecated(message)]]\n#  elif defined(_MSC_VER)\n#    define LZ4_DEPRECATED(message) __declspec(deprecated(message))\n#  elif defined(__clang__) || (defined(__GNUC__) && (__GNUC__ * 10 + __GNUC_MINOR__ >= 45))\n#    define LZ4_DEPRECATED(message) __attribute__((deprecated(message)))\n#  elif defined(__GNUC__) && (__GNUC__ * 10 + __GNUC_MINOR__ >= 31)\n#    define LZ4_DEPRECATED(message) __attribute__((deprecated))\n#  else\n#    pragma message(\"WARNING: LZ4_DEPRECATED needs custom implementation for this compiler\")\n#    define LZ4_DEPRECATED(message)   /* disabled */\n#  endif\n#endif /* LZ4_DISABLE_DEPRECATE_WARNINGS */\n\n/*! Obsolete compression functions (since v1.7.3) */\nLZ4_DEPRECATED(\"use LZ4_compress_default() instead\")       LZ4LIB_API int LZ4_compress               (const char* src, char* dest, int srcSize);\nLZ4_DEPRECATED(\"use LZ4_compress_default() instead\")       LZ4LIB_API int LZ4_compress_limitedOutput (const char* src, char* dest, int srcSize, int maxOutputSize);\nLZ4_DEPRECATED(\"use LZ4_compress_fast_extState() instead\") LZ4LIB_API int LZ4_compress_withState               (void* state, const char* source, char* dest, int inputSize);\nLZ4_DEPRECATED(\"use LZ4_compress_fast_extState() instead\") LZ4LIB_API int LZ4_compress_limitedOutput_withState (void* state, const char* source, char* dest, int inputSize, int maxOutputSize);\nLZ4_DEPRECATED(\"use LZ4_compress_fast_continue() instead\") LZ4LIB_API int LZ4_compress_continue                (LZ4_stream_t* LZ4_streamPtr, const char* source, char* dest, int inputSize);\nLZ4_DEPRECATED(\"use LZ4_compress_fast_continue() instead\") LZ4LIB_API int LZ4_compress_limitedOutput_continue  (LZ4_stream_t* LZ4_streamPtr, const char* source, char* dest, int inputSize, int maxOutputSize);\n\n/*! Obsolete decompression functions (since v1.8.0) */\nLZ4_DEPRECATED(\"use LZ4_decompress_fast() instead\") LZ4LIB_API int LZ4_uncompress (const char* source, char* dest, int outputSize);\nLZ4_DEPRECATED(\"use LZ4_decompress_safe() instead\") LZ4LIB_API int LZ4_uncompress_unknownOutputSize (const char* source, char* dest, int isize, int maxOutputSize);\n\n/* Obsolete streaming functions (since v1.7.0)\n * degraded functionality; do not use!\n *\n * In order to perform streaming compression, these functions depended on data\n * that is no longer tracked in the state. They have been preserved as well as\n * possible: using them will still produce a correct output. However, they don't\n * actually retain any history between compression calls. The compression ratio\n * achieved will therefore be no better than compressing each chunk\n * independently.\n */\nLZ4_DEPRECATED(\"Use LZ4_createStream() instead\") LZ4LIB_API void* LZ4_create (char* inputBuffer);\nLZ4_DEPRECATED(\"Use LZ4_createStream() instead\") LZ4LIB_API int   LZ4_sizeofStreamState(void);\nLZ4_DEPRECATED(\"Use LZ4_resetStream() instead\")  LZ4LIB_API int   LZ4_resetStreamState(void* state, char* inputBuffer);\nLZ4_DEPRECATED(\"Use LZ4_saveDict() instead\")     LZ4LIB_API char* LZ4_slideInputBuffer (void* state);\n\n/*! Obsolete streaming decoding functions (since v1.7.0) */\nLZ4_DEPRECATED(\"use LZ4_decompress_safe_usingDict() instead\") LZ4LIB_API int LZ4_decompress_safe_withPrefix64k (const char* src, char* dst, int compressedSize, int maxDstSize);\nLZ4_DEPRECATED(\"use LZ4_decompress_fast_usingDict() instead\") LZ4LIB_API int LZ4_decompress_fast_withPrefix64k (const char* src, char* dst, int originalSize);\n\n/*! Obsolete LZ4_decompress_fast variants (since v1.9.0) :\n *  These functions used to be faster than LZ4_decompress_safe(),\n *  but this is no longer the case. They are now slower.\n *  This is because LZ4_decompress_fast() doesn't know the input size,\n *  and therefore must progress more cautiously into the input buffer to not read beyond the end of block.\n *  On top of that `LZ4_decompress_fast()` is not protected vs malformed or malicious inputs, making it a security liability.\n *  As a consequence, LZ4_decompress_fast() is strongly discouraged, and deprecated.\n *\n *  The last remaining LZ4_decompress_fast() specificity is that\n *  it can decompress a block without knowing its compressed size.\n *  Such functionality can be achieved in a more secure manner\n *  by employing LZ4_decompress_safe_partial().\n *\n *  Parameters:\n *  originalSize : is the uncompressed size to regenerate.\n *                 `dst` must be already allocated, its size must be >= 'originalSize' bytes.\n * @return : number of bytes read from source buffer (== compressed size).\n *           The function expects to finish at block's end exactly.\n *           If the source stream is detected malformed, the function stops decoding and returns a negative result.\n *  note : LZ4_decompress_fast*() requires originalSize. Thanks to this information, it never writes past the output buffer.\n *         However, since it doesn't know its 'src' size, it may read an unknown amount of input, past input buffer bounds.\n *         Also, since match offsets are not validated, match reads from 'src' may underflow too.\n *         These issues never happen if input (compressed) data is correct.\n *         But they may happen if input data is invalid (error or intentional tampering).\n *         As a consequence, use these functions in trusted environments with trusted data **only**.\n */\nLZ4_DEPRECATED(\"This function is deprecated and unsafe. Consider using LZ4_decompress_safe() instead\")\nLZ4LIB_API int LZ4_decompress_fast (const char* src, char* dst, int originalSize);\nLZ4_DEPRECATED(\"This function is deprecated and unsafe. Consider using LZ4_decompress_safe_continue() instead\")\nLZ4LIB_API int LZ4_decompress_fast_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* src, char* dst, int originalSize);\nLZ4_DEPRECATED(\"This function is deprecated and unsafe. Consider using LZ4_decompress_safe_usingDict() instead\")\nLZ4LIB_API int LZ4_decompress_fast_usingDict (const char* src, char* dst, int originalSize, const char* dictStart, int dictSize);\n\n/*! LZ4_resetStream() :\n *  An LZ4_stream_t structure must be initialized at least once.\n *  This is done with LZ4_initStream(), or LZ4_resetStream().\n *  Consider switching to LZ4_initStream(),\n *  invoking LZ4_resetStream() will trigger deprecation warnings in the future.\n */\nLZ4LIB_API void LZ4_resetStream (LZ4_stream_t* streamPtr);\n\n}\n\n#endif /* LZ4_H_98237428734687 */\n"
  },
  {
    "path": "tracy-client-sys/tracy/common/tracy_lz4hc.cpp",
    "content": "/*\n    LZ4 HC - High Compression Mode of LZ4\n    Copyright (C) 2011-2020, Yann Collet.\n\n    BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)\n\n    Redistribution and use in source and binary forms, with or without\n    modification, are permitted provided that the following conditions are\n    met:\n\n    * Redistributions of source code must retain the above copyright\n    notice, this list of conditions and the following disclaimer.\n    * Redistributions in binary form must reproduce the above\n    copyright notice, this list of conditions and the following disclaimer\n    in the documentation and/or other materials provided with the\n    distribution.\n\n    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n    \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n    A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n    OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n    You can contact the author at :\n       - LZ4 source repository : https://github.com/lz4/lz4\n       - LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c\n*/\n/* note : lz4hc is not an independent module, it requires lz4.h/lz4.c for proper compilation */\n\n\n/* *************************************\n*  Tuning Parameter\n***************************************/\n\n/*! HEAPMODE :\n *  Select how default compression function will allocate workplace memory,\n *  in stack (0:fastest), or in heap (1:requires malloc()).\n *  Since workplace is rather large, heap mode is recommended.\n**/\n#ifndef LZ4HC_HEAPMODE\n#  define LZ4HC_HEAPMODE 1\n#endif\n\n\n/*===    Dependency    ===*/\n#define LZ4_HC_STATIC_LINKING_ONLY\n#include \"tracy_lz4hc.hpp\"\n\n\n/*===   Common definitions   ===*/\n#if defined(__GNUC__)\n#  pragma GCC diagnostic ignored \"-Wunused-function\"\n#endif\n#if defined (__clang__)\n#  pragma clang diagnostic ignored \"-Wunused-function\"\n#endif\n\n#define LZ4_COMMONDEFS_ONLY\n#ifndef LZ4_SRC_INCLUDED\n#include \"tracy_lz4.cpp\"   /* LZ4_count, constants, mem */\n#endif\n\n\n/*===   Enums   ===*/\ntypedef enum { noDictCtx, usingDictCtxHc } dictCtx_directive;\n\n\n/*===   Constants   ===*/\n#define OPTIMAL_ML (int)((ML_MASK-1)+MINMATCH)\n#define LZ4_OPT_NUM   (1<<12)\n\n\n/*===   Macros   ===*/\n#define MIN(a,b)   ( (a) < (b) ? (a) : (b) )\n#define MAX(a,b)   ( (a) > (b) ? (a) : (b) )\n#define HASH_FUNCTION(i)         (((i) * 2654435761U) >> ((MINMATCH*8)-LZ4HC_HASH_LOG))\n#define DELTANEXTMAXD(p)         chainTable[(p) & LZ4HC_MAXD_MASK]    /* flexible, LZ4HC_MAXD dependent */\n#define DELTANEXTU16(table, pos) table[(U16)(pos)]   /* faster */\n/* Make fields passed to, and updated by LZ4HC_encodeSequence explicit */\n#define UPDATABLE(ip, op, anchor) &ip, &op, &anchor\n\nnamespace tracy\n{\n\nstatic U32 LZ4HC_hashPtr(const void* ptr) { return HASH_FUNCTION(LZ4_read32(ptr)); }\n\n\n/**************************************\n*  HC Compression\n**************************************/\nstatic void LZ4HC_clearTables (LZ4HC_CCtx_internal* hc4)\n{\n    MEM_INIT(hc4->hashTable, 0, sizeof(hc4->hashTable));\n    MEM_INIT(hc4->chainTable, 0xFF, sizeof(hc4->chainTable));\n}\n\nstatic void LZ4HC_init_internal (LZ4HC_CCtx_internal* hc4, const BYTE* start)\n{\n    size_t const bufferSize = (size_t)(hc4->end - hc4->prefixStart);\n    size_t newStartingOffset = bufferSize + hc4->dictLimit;\n    assert(newStartingOffset >= bufferSize);  /* check overflow */\n    if (newStartingOffset > 1 GB) {\n        LZ4HC_clearTables(hc4);\n        newStartingOffset = 0;\n    }\n    newStartingOffset += 64 KB;\n    hc4->nextToUpdate = (U32)newStartingOffset;\n    hc4->prefixStart = start;\n    hc4->end = start;\n    hc4->dictStart = start;\n    hc4->dictLimit = (U32)newStartingOffset;\n    hc4->lowLimit = (U32)newStartingOffset;\n}\n\n\n/* Update chains up to ip (excluded) */\nLZ4_FORCE_INLINE void LZ4HC_Insert (LZ4HC_CCtx_internal* hc4, const BYTE* ip)\n{\n    U16* const chainTable = hc4->chainTable;\n    U32* const hashTable  = hc4->hashTable;\n    const BYTE* const prefixPtr = hc4->prefixStart;\n    U32 const prefixIdx = hc4->dictLimit;\n    U32 const target = (U32)(ip - prefixPtr) + prefixIdx;\n    U32 idx = hc4->nextToUpdate;\n    assert(ip >= prefixPtr);\n    assert(target >= prefixIdx);\n\n    while (idx < target) {\n        U32 const h = LZ4HC_hashPtr(prefixPtr+idx-prefixIdx);\n        size_t delta = idx - hashTable[h];\n        if (delta>LZ4_DISTANCE_MAX) delta = LZ4_DISTANCE_MAX;\n        DELTANEXTU16(chainTable, idx) = (U16)delta;\n        hashTable[h] = idx;\n        idx++;\n    }\n\n    hc4->nextToUpdate = target;\n}\n\n/** LZ4HC_countBack() :\n * @return : negative value, nb of common bytes before ip/match */\nLZ4_FORCE_INLINE\nint LZ4HC_countBack(const BYTE* const ip, const BYTE* const match,\n                    const BYTE* const iMin, const BYTE* const mMin)\n{\n    int back = 0;\n    int const min = (int)MAX(iMin - ip, mMin - match);\n    assert(min <= 0);\n    assert(ip >= iMin); assert((size_t)(ip-iMin) < (1U<<31));\n    assert(match >= mMin); assert((size_t)(match - mMin) < (1U<<31));\n    while ( (back > min)\n         && (ip[back-1] == match[back-1]) )\n            back--;\n    return back;\n}\n\n#if defined(_MSC_VER)\n#  define LZ4HC_rotl32(x,r) _rotl(x,r)\n#else\n#  define LZ4HC_rotl32(x,r) ((x << r) | (x >> (32 - r)))\n#endif\n\n\nstatic U32 LZ4HC_rotatePattern(size_t const rotate, U32 const pattern)\n{\n    size_t const bitsToRotate = (rotate & (sizeof(pattern) - 1)) << 3;\n    if (bitsToRotate == 0) return pattern;\n    return LZ4HC_rotl32(pattern, (int)bitsToRotate);\n}\n\n/* LZ4HC_countPattern() :\n * pattern32 must be a sample of repetitive pattern of length 1, 2 or 4 (but not 3!) */\nstatic unsigned\nLZ4HC_countPattern(const BYTE* ip, const BYTE* const iEnd, U32 const pattern32)\n{\n    const BYTE* const iStart = ip;\n    reg_t const pattern = (sizeof(pattern)==8) ?\n        (reg_t)pattern32 + (((reg_t)pattern32) << (sizeof(pattern)*4)) : pattern32;\n\n    while (likely(ip < iEnd-(sizeof(pattern)-1))) {\n        reg_t const diff = LZ4_read_ARCH(ip) ^ pattern;\n        if (!diff) { ip+=sizeof(pattern); continue; }\n        ip += LZ4_NbCommonBytes(diff);\n        return (unsigned)(ip - iStart);\n    }\n\n    if (LZ4_isLittleEndian()) {\n        reg_t patternByte = pattern;\n        while ((ip<iEnd) && (*ip == (BYTE)patternByte)) {\n            ip++; patternByte >>= 8;\n        }\n    } else {  /* big endian */\n        U32 bitOffset = (sizeof(pattern)*8) - 8;\n        while (ip < iEnd) {\n            BYTE const byte = (BYTE)(pattern >> bitOffset);\n            if (*ip != byte) break;\n            ip ++; bitOffset -= 8;\n    }   }\n\n    return (unsigned)(ip - iStart);\n}\n\n/* LZ4HC_reverseCountPattern() :\n * pattern must be a sample of repetitive pattern of length 1, 2 or 4 (but not 3!)\n * read using natural platform endianness */\nstatic unsigned\nLZ4HC_reverseCountPattern(const BYTE* ip, const BYTE* const iLow, U32 pattern)\n{\n    const BYTE* const iStart = ip;\n\n    while (likely(ip >= iLow+4)) {\n        if (LZ4_read32(ip-4) != pattern) break;\n        ip -= 4;\n    }\n    {   const BYTE* bytePtr = (const BYTE*)(&pattern) + 3; /* works for any endianness */\n        while (likely(ip>iLow)) {\n            if (ip[-1] != *bytePtr) break;\n            ip--; bytePtr--;\n    }   }\n    return (unsigned)(iStart - ip);\n}\n\n/* LZ4HC_protectDictEnd() :\n * Checks if the match is in the last 3 bytes of the dictionary, so reading the\n * 4 byte MINMATCH would overflow.\n * @returns true if the match index is okay.\n */\nstatic int LZ4HC_protectDictEnd(U32 const dictLimit, U32 const matchIndex)\n{\n    return ((U32)((dictLimit - 1) - matchIndex) >= 3);\n}\n\ntypedef enum { rep_untested, rep_not, rep_confirmed } repeat_state_e;\ntypedef enum { favorCompressionRatio=0, favorDecompressionSpeed } HCfavor_e;\n\nLZ4_FORCE_INLINE int\nLZ4HC_InsertAndGetWiderMatch (\n        LZ4HC_CCtx_internal* const hc4,\n        const BYTE* const ip,\n        const BYTE* const iLowLimit, const BYTE* const iHighLimit,\n        int longest,\n        const BYTE** matchpos,\n        const BYTE** startpos,\n        const int maxNbAttempts,\n        const int patternAnalysis, const int chainSwap,\n        const dictCtx_directive dict,\n        const HCfavor_e favorDecSpeed)\n{\n    U16* const chainTable = hc4->chainTable;\n    U32* const HashTable = hc4->hashTable;\n    const LZ4HC_CCtx_internal * const dictCtx = hc4->dictCtx;\n    const BYTE* const prefixPtr = hc4->prefixStart;\n    const U32 prefixIdx = hc4->dictLimit;\n    const U32 ipIndex = (U32)(ip - prefixPtr) + prefixIdx;\n    const int withinStartDistance = (hc4->lowLimit + (LZ4_DISTANCE_MAX + 1) > ipIndex);\n    const U32 lowestMatchIndex = (withinStartDistance) ? hc4->lowLimit : ipIndex - LZ4_DISTANCE_MAX;\n    const BYTE* const dictStart = hc4->dictStart;\n    const U32 dictIdx = hc4->lowLimit;\n    const BYTE* const dictEnd = dictStart + prefixIdx - dictIdx;\n    int const lookBackLength = (int)(ip-iLowLimit);\n    int nbAttempts = maxNbAttempts;\n    U32 matchChainPos = 0;\n    U32 const pattern = LZ4_read32(ip);\n    U32 matchIndex;\n    repeat_state_e repeat = rep_untested;\n    size_t srcPatternLength = 0;\n\n    DEBUGLOG(7, \"LZ4HC_InsertAndGetWiderMatch\");\n    /* First Match */\n    LZ4HC_Insert(hc4, ip);\n    matchIndex = HashTable[LZ4HC_hashPtr(ip)];\n    DEBUGLOG(7, \"First match at index %u / %u (lowestMatchIndex)\",\n                matchIndex, lowestMatchIndex);\n\n    while ((matchIndex>=lowestMatchIndex) && (nbAttempts>0)) {\n        int matchLength=0;\n        nbAttempts--;\n        assert(matchIndex < ipIndex);\n        if (favorDecSpeed && (ipIndex - matchIndex < 8)) {\n            /* do nothing */\n        } else if (matchIndex >= prefixIdx) {   /* within current Prefix */\n            const BYTE* const matchPtr = prefixPtr + matchIndex - prefixIdx;\n            assert(matchPtr < ip);\n            assert(longest >= 1);\n            if (LZ4_read16(iLowLimit + longest - 1) == LZ4_read16(matchPtr - lookBackLength + longest - 1)) {\n                if (LZ4_read32(matchPtr) == pattern) {\n                    int const back = lookBackLength ? LZ4HC_countBack(ip, matchPtr, iLowLimit, prefixPtr) : 0;\n                    matchLength = MINMATCH + (int)LZ4_count(ip+MINMATCH, matchPtr+MINMATCH, iHighLimit);\n                    matchLength -= back;\n                    if (matchLength > longest) {\n                        longest = matchLength;\n                        *matchpos = matchPtr + back;\n                        *startpos = ip + back;\n            }   }   }\n        } else {   /* lowestMatchIndex <= matchIndex < dictLimit */\n            const BYTE* const matchPtr = dictStart + (matchIndex - dictIdx);\n            assert(matchIndex >= dictIdx);\n            if ( likely(matchIndex <= prefixIdx - 4)\n              && (LZ4_read32(matchPtr) == pattern) ) {\n                int back = 0;\n                const BYTE* vLimit = ip + (prefixIdx - matchIndex);\n                if (vLimit > iHighLimit) vLimit = iHighLimit;\n                matchLength = (int)LZ4_count(ip+MINMATCH, matchPtr+MINMATCH, vLimit) + MINMATCH;\n                if ((ip+matchLength == vLimit) && (vLimit < iHighLimit))\n                    matchLength += LZ4_count(ip+matchLength, prefixPtr, iHighLimit);\n                back = lookBackLength ? LZ4HC_countBack(ip, matchPtr, iLowLimit, dictStart) : 0;\n                matchLength -= back;\n                if (matchLength > longest) {\n                    longest = matchLength;\n                    *matchpos = prefixPtr - prefixIdx + matchIndex + back;   /* virtual pos, relative to ip, to retrieve offset */\n                    *startpos = ip + back;\n        }   }   }\n\n        if (chainSwap && matchLength==longest) {   /* better match => select a better chain */\n            assert(lookBackLength==0);   /* search forward only */\n            if (matchIndex + (U32)longest <= ipIndex) {\n                int const kTrigger = 4;\n                U32 distanceToNextMatch = 1;\n                int const end = longest - MINMATCH + 1;\n                int step = 1;\n                int accel = 1 << kTrigger;\n                int pos;\n                for (pos = 0; pos < end; pos += step) {\n                    U32 const candidateDist = DELTANEXTU16(chainTable, matchIndex + (U32)pos);\n                    step = (accel++ >> kTrigger);\n                    if (candidateDist > distanceToNextMatch) {\n                        distanceToNextMatch = candidateDist;\n                        matchChainPos = (U32)pos;\n                        accel = 1 << kTrigger;\n                }   }\n                if (distanceToNextMatch > 1) {\n                    if (distanceToNextMatch > matchIndex) break;   /* avoid overflow */\n                    matchIndex -= distanceToNextMatch;\n                    continue;\n        }   }   }\n\n        {   U32 const distNextMatch = DELTANEXTU16(chainTable, matchIndex);\n            if (patternAnalysis && distNextMatch==1 && matchChainPos==0) {\n                U32 const matchCandidateIdx = matchIndex-1;\n                /* may be a repeated pattern */\n                if (repeat == rep_untested) {\n                    if ( ((pattern & 0xFFFF) == (pattern >> 16))\n                      &  ((pattern & 0xFF)   == (pattern >> 24)) ) {\n                        repeat = rep_confirmed;\n                        srcPatternLength = LZ4HC_countPattern(ip+sizeof(pattern), iHighLimit, pattern) + sizeof(pattern);\n                    } else {\n                        repeat = rep_not;\n                }   }\n                if ( (repeat == rep_confirmed) && (matchCandidateIdx >= lowestMatchIndex)\n                  && LZ4HC_protectDictEnd(prefixIdx, matchCandidateIdx) ) {\n                    const int extDict = matchCandidateIdx < prefixIdx;\n                    const BYTE* const matchPtr = (extDict ? dictStart - dictIdx : prefixPtr - prefixIdx) + matchCandidateIdx;\n                    if (LZ4_read32(matchPtr) == pattern) {  /* good candidate */\n                        const BYTE* const iLimit = extDict ? dictEnd : iHighLimit;\n                        size_t forwardPatternLength = LZ4HC_countPattern(matchPtr+sizeof(pattern), iLimit, pattern) + sizeof(pattern);\n                        if (extDict && matchPtr + forwardPatternLength == iLimit) {\n                            U32 const rotatedPattern = LZ4HC_rotatePattern(forwardPatternLength, pattern);\n                            forwardPatternLength += LZ4HC_countPattern(prefixPtr, iHighLimit, rotatedPattern);\n                        }\n                        {   const BYTE* const lowestMatchPtr = extDict ? dictStart : prefixPtr;\n                            size_t backLength = LZ4HC_reverseCountPattern(matchPtr, lowestMatchPtr, pattern);\n                            size_t currentSegmentLength;\n                            if (!extDict\n                              && matchPtr - backLength == prefixPtr\n                              && dictIdx < prefixIdx) {\n                                U32 const rotatedPattern = LZ4HC_rotatePattern((U32)(-(int)backLength), pattern);\n                                backLength += LZ4HC_reverseCountPattern(dictEnd, dictStart, rotatedPattern);\n                            }\n                            /* Limit backLength not go further than lowestMatchIndex */\n                            backLength = matchCandidateIdx - MAX(matchCandidateIdx - (U32)backLength, lowestMatchIndex);\n                            assert(matchCandidateIdx - backLength >= lowestMatchIndex);\n                            currentSegmentLength = backLength + forwardPatternLength;\n                            /* Adjust to end of pattern if the source pattern fits, otherwise the beginning of the pattern */\n                            if ( (currentSegmentLength >= srcPatternLength)   /* current pattern segment large enough to contain full srcPatternLength */\n                              && (forwardPatternLength <= srcPatternLength) ) { /* haven't reached this position yet */\n                                U32 const newMatchIndex = matchCandidateIdx + (U32)forwardPatternLength - (U32)srcPatternLength;  /* best position, full pattern, might be followed by more match */\n                                if (LZ4HC_protectDictEnd(prefixIdx, newMatchIndex))\n                                    matchIndex = newMatchIndex;\n                                else {\n                                    /* Can only happen if started in the prefix */\n                                    assert(newMatchIndex >= prefixIdx - 3 && newMatchIndex < prefixIdx && !extDict);\n                                    matchIndex = prefixIdx;\n                                }\n                            } else {\n                                U32 const newMatchIndex = matchCandidateIdx - (U32)backLength;   /* farthest position in current segment, will find a match of length currentSegmentLength + maybe some back */\n                                if (!LZ4HC_protectDictEnd(prefixIdx, newMatchIndex)) {\n                                    assert(newMatchIndex >= prefixIdx - 3 && newMatchIndex < prefixIdx && !extDict);\n                                    matchIndex = prefixIdx;\n                                } else {\n                                    matchIndex = newMatchIndex;\n                                    if (lookBackLength==0) {  /* no back possible */\n                                        size_t const maxML = MIN(currentSegmentLength, srcPatternLength);\n                                        if ((size_t)longest < maxML) {\n                                            assert(prefixPtr - prefixIdx + matchIndex != ip);\n                                            if ((size_t)(ip - prefixPtr) + prefixIdx - matchIndex > LZ4_DISTANCE_MAX) break;\n                                            assert(maxML < 2 GB);\n                                            longest = (int)maxML;\n                                            *matchpos = prefixPtr - prefixIdx + matchIndex;   /* virtual pos, relative to ip, to retrieve offset */\n                                            *startpos = ip;\n                                        }\n                                        {   U32 const distToNextPattern = DELTANEXTU16(chainTable, matchIndex);\n                                            if (distToNextPattern > matchIndex) break;  /* avoid overflow */\n                                            matchIndex -= distToNextPattern;\n                        }   }   }   }   }\n                        continue;\n                }   }\n        }   }   /* PA optimization */\n\n        /* follow current chain */\n        matchIndex -= DELTANEXTU16(chainTable, matchIndex + matchChainPos);\n\n    }  /* while ((matchIndex>=lowestMatchIndex) && (nbAttempts)) */\n\n    if ( dict == usingDictCtxHc\n      && nbAttempts > 0\n      && ipIndex - lowestMatchIndex < LZ4_DISTANCE_MAX) {\n        size_t const dictEndOffset = (size_t)(dictCtx->end - dictCtx->prefixStart) + dictCtx->dictLimit;\n        U32 dictMatchIndex = dictCtx->hashTable[LZ4HC_hashPtr(ip)];\n        assert(dictEndOffset <= 1 GB);\n        matchIndex = dictMatchIndex + lowestMatchIndex - (U32)dictEndOffset;\n        while (ipIndex - matchIndex <= LZ4_DISTANCE_MAX && nbAttempts--) {\n            const BYTE* const matchPtr = dictCtx->prefixStart - dictCtx->dictLimit + dictMatchIndex;\n\n            if (LZ4_read32(matchPtr) == pattern) {\n                int mlt;\n                int back = 0;\n                const BYTE* vLimit = ip + (dictEndOffset - dictMatchIndex);\n                if (vLimit > iHighLimit) vLimit = iHighLimit;\n                mlt = (int)LZ4_count(ip+MINMATCH, matchPtr+MINMATCH, vLimit) + MINMATCH;\n                back = lookBackLength ? LZ4HC_countBack(ip, matchPtr, iLowLimit, dictCtx->prefixStart) : 0;\n                mlt -= back;\n                if (mlt > longest) {\n                    longest = mlt;\n                    *matchpos = prefixPtr - prefixIdx + matchIndex + back;\n                    *startpos = ip + back;\n            }   }\n\n            {   U32 const nextOffset = DELTANEXTU16(dictCtx->chainTable, dictMatchIndex);\n                dictMatchIndex -= nextOffset;\n                matchIndex -= nextOffset;\n    }   }   }\n\n    return longest;\n}\n\nLZ4_FORCE_INLINE int\nLZ4HC_InsertAndFindBestMatch(LZ4HC_CCtx_internal* const hc4,   /* Index table will be updated */\n                       const BYTE* const ip, const BYTE* const iLimit,\n                       const BYTE** matchpos,\n                       const int maxNbAttempts,\n                       const int patternAnalysis,\n                       const dictCtx_directive dict)\n{\n    const BYTE* uselessPtr = ip;\n    /* note : LZ4HC_InsertAndGetWiderMatch() is able to modify the starting position of a match (*startpos),\n     * but this won't be the case here, as we define iLowLimit==ip,\n     * so LZ4HC_InsertAndGetWiderMatch() won't be allowed to search past ip */\n    return LZ4HC_InsertAndGetWiderMatch(hc4, ip, ip, iLimit, MINMATCH-1, matchpos, &uselessPtr, maxNbAttempts, patternAnalysis, 0 /*chainSwap*/, dict, favorCompressionRatio);\n}\n\n/* LZ4HC_encodeSequence() :\n * @return : 0 if ok,\n *           1 if buffer issue detected */\nLZ4_FORCE_INLINE int LZ4HC_encodeSequence (\n    const BYTE** _ip,\n    BYTE** _op,\n    const BYTE** _anchor,\n    int matchLength,\n    const BYTE* const match,\n    limitedOutput_directive limit,\n    BYTE* oend)\n{\n#define ip      (*_ip)\n#define op      (*_op)\n#define anchor  (*_anchor)\n\n    size_t length;\n    BYTE* const token = op++;\n\n#if defined(LZ4_DEBUG) && (LZ4_DEBUG >= 6)\n    static const BYTE* start = NULL;\n    static U32 totalCost = 0;\n    U32 const pos = (start==NULL) ? 0 : (U32)(anchor - start);\n    U32 const ll = (U32)(ip - anchor);\n    U32 const llAdd = (ll>=15) ? ((ll-15) / 255) + 1 : 0;\n    U32 const mlAdd = (matchLength>=19) ? ((matchLength-19) / 255) + 1 : 0;\n    U32 const cost = 1 + llAdd + ll + 2 + mlAdd;\n    if (start==NULL) start = anchor;  /* only works for single segment */\n    /* g_debuglog_enable = (pos >= 2228) & (pos <= 2262); */\n    DEBUGLOG(6, \"pos:%7u -- literals:%4u, match:%4i, offset:%5u, cost:%4u + %5u\",\n                pos,\n                (U32)(ip - anchor), matchLength, (U32)(ip-match),\n                cost, totalCost);\n    totalCost += cost;\n#endif\n\n    /* Encode Literal length */\n    length = (size_t)(ip - anchor);\n    LZ4_STATIC_ASSERT(notLimited == 0);\n    /* Check output limit */\n    if (limit && ((op + (length / 255) + length + (2 + 1 + LASTLITERALS)) > oend)) {\n        DEBUGLOG(6, \"Not enough room to write %i literals (%i bytes remaining)\",\n                (int)length, (int)(oend - op));\n        return 1;\n    }\n    if (length >= RUN_MASK) {\n        size_t len = length - RUN_MASK;\n        *token = (RUN_MASK << ML_BITS);\n        for(; len >= 255 ; len -= 255) *op++ = 255;\n        *op++ = (BYTE)len;\n    } else {\n        *token = (BYTE)(length << ML_BITS);\n    }\n\n    /* Copy Literals */\n    LZ4_wildCopy8(op, anchor, op + length);\n    op += length;\n\n    /* Encode Offset */\n    assert( (ip - match) <= LZ4_DISTANCE_MAX );   /* note : consider providing offset as a value, rather than as a pointer difference */\n    LZ4_writeLE16(op, (U16)(ip - match)); op += 2;\n\n    /* Encode MatchLength */\n    assert(matchLength >= MINMATCH);\n    length = (size_t)matchLength - MINMATCH;\n    if (limit && (op + (length / 255) + (1 + LASTLITERALS) > oend)) {\n        DEBUGLOG(6, \"Not enough room to write match length\");\n        return 1;   /* Check output limit */\n    }\n    if (length >= ML_MASK) {\n        *token += ML_MASK;\n        length -= ML_MASK;\n        for(; length >= 510 ; length -= 510) { *op++ = 255; *op++ = 255; }\n        if (length >= 255) { length -= 255; *op++ = 255; }\n        *op++ = (BYTE)length;\n    } else {\n        *token += (BYTE)(length);\n    }\n\n    /* Prepare next loop */\n    ip += matchLength;\n    anchor = ip;\n\n    return 0;\n}\n#undef ip\n#undef op\n#undef anchor\n\nLZ4_FORCE_INLINE int LZ4HC_compress_hashChain (\n    LZ4HC_CCtx_internal* const ctx,\n    const char* const source,\n    char* const dest,\n    int* srcSizePtr,\n    int const maxOutputSize,\n    int maxNbAttempts,\n    const limitedOutput_directive limit,\n    const dictCtx_directive dict\n    )\n{\n    const int inputSize = *srcSizePtr;\n    const int patternAnalysis = (maxNbAttempts > 128);   /* levels 9+ */\n\n    const BYTE* ip = (const BYTE*) source;\n    const BYTE* anchor = ip;\n    const BYTE* const iend = ip + inputSize;\n    const BYTE* const mflimit = iend - MFLIMIT;\n    const BYTE* const matchlimit = (iend - LASTLITERALS);\n\n    BYTE* optr = (BYTE*) dest;\n    BYTE* op = (BYTE*) dest;\n    BYTE* oend = op + maxOutputSize;\n\n    int   ml0, ml, ml2, ml3;\n    const BYTE* start0;\n    const BYTE* ref0;\n    const BYTE* ref = NULL;\n    const BYTE* start2 = NULL;\n    const BYTE* ref2 = NULL;\n    const BYTE* start3 = NULL;\n    const BYTE* ref3 = NULL;\n\n    /* init */\n    *srcSizePtr = 0;\n    if (limit == fillOutput) oend -= LASTLITERALS;                  /* Hack for support LZ4 format restriction */\n    if (inputSize < LZ4_minLength) goto _last_literals;             /* Input too small, no compression (all literals) */\n\n    /* Main Loop */\n    while (ip <= mflimit) {\n        ml = LZ4HC_InsertAndFindBestMatch(ctx, ip, matchlimit, &ref, maxNbAttempts, patternAnalysis, dict);\n        if (ml<MINMATCH) { ip++; continue; }\n\n        /* saved, in case we would skip too much */\n        start0 = ip; ref0 = ref; ml0 = ml;\n\n_Search2:\n        if (ip+ml <= mflimit) {\n            ml2 = LZ4HC_InsertAndGetWiderMatch(ctx,\n                            ip + ml - 2, ip + 0, matchlimit, ml, &ref2, &start2,\n                            maxNbAttempts, patternAnalysis, 0, dict, favorCompressionRatio);\n        } else {\n            ml2 = ml;\n        }\n\n        if (ml2 == ml) { /* No better match => encode ML1 */\n            optr = op;\n            if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml, ref, limit, oend)) goto _dest_overflow;\n            continue;\n        }\n\n        if (start0 < ip) {   /* first match was skipped at least once */\n            if (start2 < ip + ml0) {  /* squeezing ML1 between ML0(original ML1) and ML2 */\n                ip = start0; ref = ref0; ml = ml0;  /* restore initial ML1 */\n        }   }\n\n        /* Here, start0==ip */\n        if ((start2 - ip) < 3) {  /* First Match too small : removed */\n            ml = ml2;\n            ip = start2;\n            ref =ref2;\n            goto _Search2;\n        }\n\n_Search3:\n        /* At this stage, we have :\n        *  ml2 > ml1, and\n        *  ip1+3 <= ip2 (usually < ip1+ml1) */\n        if ((start2 - ip) < OPTIMAL_ML) {\n            int correction;\n            int new_ml = ml;\n            if (new_ml > OPTIMAL_ML) new_ml = OPTIMAL_ML;\n            if (ip+new_ml > start2 + ml2 - MINMATCH) new_ml = (int)(start2 - ip) + ml2 - MINMATCH;\n            correction = new_ml - (int)(start2 - ip);\n            if (correction > 0) {\n                start2 += correction;\n                ref2 += correction;\n                ml2 -= correction;\n            }\n        }\n        /* Now, we have start2 = ip+new_ml, with new_ml = min(ml, OPTIMAL_ML=18) */\n\n        if (start2 + ml2 <= mflimit) {\n            ml3 = LZ4HC_InsertAndGetWiderMatch(ctx,\n                            start2 + ml2 - 3, start2, matchlimit, ml2, &ref3, &start3,\n                            maxNbAttempts, patternAnalysis, 0, dict, favorCompressionRatio);\n        } else {\n            ml3 = ml2;\n        }\n\n        if (ml3 == ml2) {  /* No better match => encode ML1 and ML2 */\n            /* ip & ref are known; Now for ml */\n            if (start2 < ip+ml)  ml = (int)(start2 - ip);\n            /* Now, encode 2 sequences */\n            optr = op;\n            if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml, ref, limit, oend)) goto _dest_overflow;\n            ip = start2;\n            optr = op;\n            if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml2, ref2, limit, oend)) {\n                ml  = ml2;\n                ref = ref2;\n                goto _dest_overflow;\n            }\n            continue;\n        }\n\n        if (start3 < ip+ml+3) {  /* Not enough space for match 2 : remove it */\n            if (start3 >= (ip+ml)) {  /* can write Seq1 immediately ==> Seq2 is removed, so Seq3 becomes Seq1 */\n                if (start2 < ip+ml) {\n                    int correction = (int)(ip+ml - start2);\n                    start2 += correction;\n                    ref2 += correction;\n                    ml2 -= correction;\n                    if (ml2 < MINMATCH) {\n                        start2 = start3;\n                        ref2 = ref3;\n                        ml2 = ml3;\n                    }\n                }\n\n                optr = op;\n                if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml, ref, limit, oend)) goto _dest_overflow;\n                ip  = start3;\n                ref = ref3;\n                ml  = ml3;\n\n                start0 = start2;\n                ref0 = ref2;\n                ml0 = ml2;\n                goto _Search2;\n            }\n\n            start2 = start3;\n            ref2 = ref3;\n            ml2 = ml3;\n            goto _Search3;\n        }\n\n        /*\n        * OK, now we have 3 ascending matches;\n        * let's write the first one ML1.\n        * ip & ref are known; Now decide ml.\n        */\n        if (start2 < ip+ml) {\n            if ((start2 - ip) < OPTIMAL_ML) {\n                int correction;\n                if (ml > OPTIMAL_ML) ml = OPTIMAL_ML;\n                if (ip + ml > start2 + ml2 - MINMATCH) ml = (int)(start2 - ip) + ml2 - MINMATCH;\n                correction = ml - (int)(start2 - ip);\n                if (correction > 0) {\n                    start2 += correction;\n                    ref2 += correction;\n                    ml2 -= correction;\n                }\n            } else {\n                ml = (int)(start2 - ip);\n            }\n        }\n        optr = op;\n        if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml, ref, limit, oend)) goto _dest_overflow;\n\n        /* ML2 becomes ML1 */\n        ip = start2; ref = ref2; ml = ml2;\n\n        /* ML3 becomes ML2 */\n        start2 = start3; ref2 = ref3; ml2 = ml3;\n\n        /* let's find a new ML3 */\n        goto _Search3;\n    }\n\n_last_literals:\n    /* Encode Last Literals */\n    {   size_t lastRunSize = (size_t)(iend - anchor);  /* literals */\n        size_t llAdd = (lastRunSize + 255 - RUN_MASK) / 255;\n        size_t const totalSize = 1 + llAdd + lastRunSize;\n        if (limit == fillOutput) oend += LASTLITERALS;  /* restore correct value */\n        if (limit && (op + totalSize > oend)) {\n            if (limit == limitedOutput) return 0;\n            /* adapt lastRunSize to fill 'dest' */\n            lastRunSize  = (size_t)(oend - op) - 1 /*token*/;\n            llAdd = (lastRunSize + 256 - RUN_MASK) / 256;\n            lastRunSize -= llAdd;\n        }\n        DEBUGLOG(6, \"Final literal run : %i literals\", (int)lastRunSize);\n        ip = anchor + lastRunSize;  /* can be != iend if limit==fillOutput */\n\n        if (lastRunSize >= RUN_MASK) {\n            size_t accumulator = lastRunSize - RUN_MASK;\n            *op++ = (RUN_MASK << ML_BITS);\n            for(; accumulator >= 255 ; accumulator -= 255) *op++ = 255;\n            *op++ = (BYTE) accumulator;\n        } else {\n            *op++ = (BYTE)(lastRunSize << ML_BITS);\n        }\n        LZ4_memcpy(op, anchor, lastRunSize);\n        op += lastRunSize;\n    }\n\n    /* End */\n    *srcSizePtr = (int) (((const char*)ip) - source);\n    return (int) (((char*)op)-dest);\n\n_dest_overflow:\n    if (limit == fillOutput) {\n        /* Assumption : ip, anchor, ml and ref must be set correctly */\n        size_t const ll = (size_t)(ip - anchor);\n        size_t const ll_addbytes = (ll + 240) / 255;\n        size_t const ll_totalCost = 1 + ll_addbytes + ll;\n        BYTE* const maxLitPos = oend - 3; /* 2 for offset, 1 for token */\n        DEBUGLOG(6, \"Last sequence overflowing\");\n        op = optr;  /* restore correct out pointer */\n        if (op + ll_totalCost <= maxLitPos) {\n            /* ll validated; now adjust match length */\n            size_t const bytesLeftForMl = (size_t)(maxLitPos - (op+ll_totalCost));\n            size_t const maxMlSize = MINMATCH + (ML_MASK-1) + (bytesLeftForMl * 255);\n            assert(maxMlSize < INT_MAX); assert(ml >= 0);\n            if ((size_t)ml > maxMlSize) ml = (int)maxMlSize;\n            if ((oend + LASTLITERALS) - (op + ll_totalCost + 2) - 1 + ml >= MFLIMIT) {\n                LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml, ref, notLimited, oend);\n        }   }\n        goto _last_literals;\n    }\n    /* compression failed */\n    return 0;\n}\n\n\nstatic int LZ4HC_compress_optimal( LZ4HC_CCtx_internal* ctx,\n    const char* const source, char* dst,\n    int* srcSizePtr, int dstCapacity,\n    int const nbSearches, size_t sufficient_len,\n    const limitedOutput_directive limit, int const fullUpdate,\n    const dictCtx_directive dict,\n    const HCfavor_e favorDecSpeed);\n\n\nLZ4_FORCE_INLINE int LZ4HC_compress_generic_internal (\n    LZ4HC_CCtx_internal* const ctx,\n    const char* const src,\n    char* const dst,\n    int* const srcSizePtr,\n    int const dstCapacity,\n    int cLevel,\n    const limitedOutput_directive limit,\n    const dictCtx_directive dict\n    )\n{\n    typedef enum { lz4hc, lz4opt } lz4hc_strat_e;\n    typedef struct {\n        lz4hc_strat_e strat;\n        int nbSearches;\n        U32 targetLength;\n    } cParams_t;\n    static const cParams_t clTable[LZ4HC_CLEVEL_MAX+1] = {\n        { lz4hc,     2, 16 },  /* 0, unused */\n        { lz4hc,     2, 16 },  /* 1, unused */\n        { lz4hc,     2, 16 },  /* 2, unused */\n        { lz4hc,     4, 16 },  /* 3 */\n        { lz4hc,     8, 16 },  /* 4 */\n        { lz4hc,    16, 16 },  /* 5 */\n        { lz4hc,    32, 16 },  /* 6 */\n        { lz4hc,    64, 16 },  /* 7 */\n        { lz4hc,   128, 16 },  /* 8 */\n        { lz4hc,   256, 16 },  /* 9 */\n        { lz4opt,   96, 64 },  /*10==LZ4HC_CLEVEL_OPT_MIN*/\n        { lz4opt,  512,128 },  /*11 */\n        { lz4opt,16384,LZ4_OPT_NUM },  /* 12==LZ4HC_CLEVEL_MAX */\n    };\n\n    DEBUGLOG(4, \"LZ4HC_compress_generic(ctx=%p, src=%p, srcSize=%d, limit=%d)\",\n                ctx, src, *srcSizePtr, limit);\n\n    if (limit == fillOutput && dstCapacity < 1) return 0;   /* Impossible to store anything */\n    if ((U32)*srcSizePtr > (U32)LZ4_MAX_INPUT_SIZE) return 0;    /* Unsupported input size (too large or negative) */\n\n    ctx->end += *srcSizePtr;\n    if (cLevel < 1) cLevel = LZ4HC_CLEVEL_DEFAULT;   /* note : convention is different from lz4frame, maybe something to review */\n    cLevel = MIN(LZ4HC_CLEVEL_MAX, cLevel);\n    {   cParams_t const cParam = clTable[cLevel];\n        HCfavor_e const favor = ctx->favorDecSpeed ? favorDecompressionSpeed : favorCompressionRatio;\n        int result;\n\n        if (cParam.strat == lz4hc) {\n            result = LZ4HC_compress_hashChain(ctx,\n                                src, dst, srcSizePtr, dstCapacity,\n                                cParam.nbSearches, limit, dict);\n        } else {\n            assert(cParam.strat == lz4opt);\n            result = LZ4HC_compress_optimal(ctx,\n                                src, dst, srcSizePtr, dstCapacity,\n                                cParam.nbSearches, cParam.targetLength, limit,\n                                cLevel == LZ4HC_CLEVEL_MAX,   /* ultra mode */\n                                dict, favor);\n        }\n        if (result <= 0) ctx->dirty = 1;\n        return result;\n    }\n}\n\nstatic void LZ4HC_setExternalDict(LZ4HC_CCtx_internal* ctxPtr, const BYTE* newBlock);\n\nstatic int\nLZ4HC_compress_generic_noDictCtx (\n        LZ4HC_CCtx_internal* const ctx,\n        const char* const src,\n        char* const dst,\n        int* const srcSizePtr,\n        int const dstCapacity,\n        int cLevel,\n        limitedOutput_directive limit\n        )\n{\n    assert(ctx->dictCtx == NULL);\n    return LZ4HC_compress_generic_internal(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit, noDictCtx);\n}\n\nstatic int\nLZ4HC_compress_generic_dictCtx (\n        LZ4HC_CCtx_internal* const ctx,\n        const char* const src,\n        char* const dst,\n        int* const srcSizePtr,\n        int const dstCapacity,\n        int cLevel,\n        limitedOutput_directive limit\n        )\n{\n    const size_t position = (size_t)(ctx->end - ctx->prefixStart) + (ctx->dictLimit - ctx->lowLimit);\n    assert(ctx->dictCtx != NULL);\n    if (position >= 64 KB) {\n        ctx->dictCtx = NULL;\n        return LZ4HC_compress_generic_noDictCtx(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit);\n    } else if (position == 0 && *srcSizePtr > 4 KB) {\n        LZ4_memcpy(ctx, ctx->dictCtx, sizeof(LZ4HC_CCtx_internal));\n        LZ4HC_setExternalDict(ctx, (const BYTE *)src);\n        ctx->compressionLevel = (short)cLevel;\n        return LZ4HC_compress_generic_noDictCtx(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit);\n    } else {\n        return LZ4HC_compress_generic_internal(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit, usingDictCtxHc);\n    }\n}\n\nstatic int\nLZ4HC_compress_generic (\n        LZ4HC_CCtx_internal* const ctx,\n        const char* const src,\n        char* const dst,\n        int* const srcSizePtr,\n        int const dstCapacity,\n        int cLevel,\n        limitedOutput_directive limit\n        )\n{\n    if (ctx->dictCtx == NULL) {\n        return LZ4HC_compress_generic_noDictCtx(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit);\n    } else {\n        return LZ4HC_compress_generic_dictCtx(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit);\n    }\n}\n\n\nint LZ4_sizeofStateHC(void) { return (int)sizeof(LZ4_streamHC_t); }\n\nstatic size_t LZ4_streamHC_t_alignment(void)\n{\n#if LZ4_ALIGN_TEST\n    typedef struct { char c; LZ4_streamHC_t t; } t_a;\n    return sizeof(t_a) - sizeof(LZ4_streamHC_t);\n#else\n    return 1;  /* effectively disabled */\n#endif\n}\n\n/* state is presumed correctly initialized,\n * in which case its size and alignment have already been validate */\nint LZ4_compress_HC_extStateHC_fastReset (void* state, const char* src, char* dst, int srcSize, int dstCapacity, int compressionLevel)\n{\n    LZ4HC_CCtx_internal* const ctx = &((LZ4_streamHC_t*)state)->internal_donotuse;\n    if (!LZ4_isAligned(state, LZ4_streamHC_t_alignment())) return 0;\n    LZ4_resetStreamHC_fast((LZ4_streamHC_t*)state, compressionLevel);\n    LZ4HC_init_internal (ctx, (const BYTE*)src);\n    if (dstCapacity < LZ4_compressBound(srcSize))\n        return LZ4HC_compress_generic (ctx, src, dst, &srcSize, dstCapacity, compressionLevel, limitedOutput);\n    else\n        return LZ4HC_compress_generic (ctx, src, dst, &srcSize, dstCapacity, compressionLevel, notLimited);\n}\n\nint LZ4_compress_HC_extStateHC (void* state, const char* src, char* dst, int srcSize, int dstCapacity, int compressionLevel)\n{\n    LZ4_streamHC_t* const ctx = LZ4_initStreamHC(state, sizeof(*ctx));\n    if (ctx==NULL) return 0;   /* init failure */\n    return LZ4_compress_HC_extStateHC_fastReset(state, src, dst, srcSize, dstCapacity, compressionLevel);\n}\n\nint LZ4_compress_HC(const char* src, char* dst, int srcSize, int dstCapacity, int compressionLevel)\n{\n    int cSize;\n#if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1\n    LZ4_streamHC_t* const statePtr = (LZ4_streamHC_t*)ALLOC(sizeof(LZ4_streamHC_t));\n    if (statePtr==NULL) return 0;\n#else\n    LZ4_streamHC_t state;\n    LZ4_streamHC_t* const statePtr = &state;\n#endif\n    cSize = LZ4_compress_HC_extStateHC(statePtr, src, dst, srcSize, dstCapacity, compressionLevel);\n#if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1\n    FREEMEM(statePtr);\n#endif\n    return cSize;\n}\n\n/* state is presumed sized correctly (>= sizeof(LZ4_streamHC_t)) */\nint LZ4_compress_HC_destSize(void* state, const char* source, char* dest, int* sourceSizePtr, int targetDestSize, int cLevel)\n{\n    LZ4_streamHC_t* const ctx = LZ4_initStreamHC(state, sizeof(*ctx));\n    if (ctx==NULL) return 0;   /* init failure */\n    LZ4HC_init_internal(&ctx->internal_donotuse, (const BYTE*) source);\n    LZ4_setCompressionLevel(ctx, cLevel);\n    return LZ4HC_compress_generic(&ctx->internal_donotuse, source, dest, sourceSizePtr, targetDestSize, cLevel, fillOutput);\n}\n\n\n\n/**************************************\n*  Streaming Functions\n**************************************/\n/* allocation */\n#if !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION)\nLZ4_streamHC_t* LZ4_createStreamHC(void)\n{\n    LZ4_streamHC_t* const state =\n        (LZ4_streamHC_t*)ALLOC_AND_ZERO(sizeof(LZ4_streamHC_t));\n    if (state == NULL) return NULL;\n    LZ4_setCompressionLevel(state, LZ4HC_CLEVEL_DEFAULT);\n    return state;\n}\n\nint LZ4_freeStreamHC (LZ4_streamHC_t* LZ4_streamHCPtr)\n{\n    DEBUGLOG(4, \"LZ4_freeStreamHC(%p)\", LZ4_streamHCPtr);\n    if (!LZ4_streamHCPtr) return 0;  /* support free on NULL */\n    FREEMEM(LZ4_streamHCPtr);\n    return 0;\n}\n#endif\n\n\nLZ4_streamHC_t* LZ4_initStreamHC (void* buffer, size_t size)\n{\n    LZ4_streamHC_t* const LZ4_streamHCPtr = (LZ4_streamHC_t*)buffer;\n    DEBUGLOG(4, \"LZ4_initStreamHC(%p, %u)\", buffer, (unsigned)size);\n    /* check conditions */\n    if (buffer == NULL) return NULL;\n    if (size < sizeof(LZ4_streamHC_t)) return NULL;\n    if (!LZ4_isAligned(buffer, LZ4_streamHC_t_alignment())) return NULL;\n    /* init */\n    { LZ4HC_CCtx_internal* const hcstate = &(LZ4_streamHCPtr->internal_donotuse);\n      MEM_INIT(hcstate, 0, sizeof(*hcstate)); }\n    LZ4_setCompressionLevel(LZ4_streamHCPtr, LZ4HC_CLEVEL_DEFAULT);\n    return LZ4_streamHCPtr;\n}\n\n/* just a stub */\nvoid LZ4_resetStreamHC (LZ4_streamHC_t* LZ4_streamHCPtr, int compressionLevel)\n{\n    LZ4_initStreamHC(LZ4_streamHCPtr, sizeof(*LZ4_streamHCPtr));\n    LZ4_setCompressionLevel(LZ4_streamHCPtr, compressionLevel);\n}\n\nvoid LZ4_resetStreamHC_fast (LZ4_streamHC_t* LZ4_streamHCPtr, int compressionLevel)\n{\n    DEBUGLOG(4, \"LZ4_resetStreamHC_fast(%p, %d)\", LZ4_streamHCPtr, compressionLevel);\n    if (LZ4_streamHCPtr->internal_donotuse.dirty) {\n        LZ4_initStreamHC(LZ4_streamHCPtr, sizeof(*LZ4_streamHCPtr));\n    } else {\n        /* preserve end - prefixStart : can trigger clearTable's threshold */\n        if (LZ4_streamHCPtr->internal_donotuse.end != NULL) {\n            LZ4_streamHCPtr->internal_donotuse.end -= (uptrval)LZ4_streamHCPtr->internal_donotuse.prefixStart;\n        } else {\n            assert(LZ4_streamHCPtr->internal_donotuse.prefixStart == NULL);\n        }\n        LZ4_streamHCPtr->internal_donotuse.prefixStart = NULL;\n        LZ4_streamHCPtr->internal_donotuse.dictCtx = NULL;\n    }\n    LZ4_setCompressionLevel(LZ4_streamHCPtr, compressionLevel);\n}\n\nvoid LZ4_setCompressionLevel(LZ4_streamHC_t* LZ4_streamHCPtr, int compressionLevel)\n{\n    DEBUGLOG(5, \"LZ4_setCompressionLevel(%p, %d)\", LZ4_streamHCPtr, compressionLevel);\n    if (compressionLevel < 1) compressionLevel = LZ4HC_CLEVEL_DEFAULT;\n    if (compressionLevel > LZ4HC_CLEVEL_MAX) compressionLevel = LZ4HC_CLEVEL_MAX;\n    LZ4_streamHCPtr->internal_donotuse.compressionLevel = (short)compressionLevel;\n}\n\nvoid LZ4_favorDecompressionSpeed(LZ4_streamHC_t* LZ4_streamHCPtr, int favor)\n{\n    LZ4_streamHCPtr->internal_donotuse.favorDecSpeed = (favor!=0);\n}\n\n/* LZ4_loadDictHC() :\n * LZ4_streamHCPtr is presumed properly initialized */\nint LZ4_loadDictHC (LZ4_streamHC_t* LZ4_streamHCPtr,\n              const char* dictionary, int dictSize)\n{\n    LZ4HC_CCtx_internal* const ctxPtr = &LZ4_streamHCPtr->internal_donotuse;\n    DEBUGLOG(4, \"LZ4_loadDictHC(ctx:%p, dict:%p, dictSize:%d)\", LZ4_streamHCPtr, dictionary, dictSize);\n    assert(LZ4_streamHCPtr != NULL);\n    if (dictSize > 64 KB) {\n        dictionary += (size_t)dictSize - 64 KB;\n        dictSize = 64 KB;\n    }\n    /* need a full initialization, there are bad side-effects when using resetFast() */\n    {   int const cLevel = ctxPtr->compressionLevel;\n        LZ4_initStreamHC(LZ4_streamHCPtr, sizeof(*LZ4_streamHCPtr));\n        LZ4_setCompressionLevel(LZ4_streamHCPtr, cLevel);\n    }\n    LZ4HC_init_internal (ctxPtr, (const BYTE*)dictionary);\n    ctxPtr->end = (const BYTE*)dictionary + dictSize;\n    if (dictSize >= 4) LZ4HC_Insert (ctxPtr, ctxPtr->end-3);\n    return dictSize;\n}\n\nvoid LZ4_attach_HC_dictionary(LZ4_streamHC_t *working_stream, const LZ4_streamHC_t *dictionary_stream) {\n    working_stream->internal_donotuse.dictCtx = dictionary_stream != NULL ? &(dictionary_stream->internal_donotuse) : NULL;\n}\n\n/* compression */\n\nstatic void LZ4HC_setExternalDict(LZ4HC_CCtx_internal* ctxPtr, const BYTE* newBlock)\n{\n    DEBUGLOG(4, \"LZ4HC_setExternalDict(%p, %p)\", ctxPtr, newBlock);\n    if (ctxPtr->end >= ctxPtr->prefixStart + 4)\n        LZ4HC_Insert (ctxPtr, ctxPtr->end-3);   /* Referencing remaining dictionary content */\n\n    /* Only one memory segment for extDict, so any previous extDict is lost at this stage */\n    ctxPtr->lowLimit  = ctxPtr->dictLimit;\n    ctxPtr->dictStart  = ctxPtr->prefixStart;\n    ctxPtr->dictLimit += (U32)(ctxPtr->end - ctxPtr->prefixStart);\n    ctxPtr->prefixStart = newBlock;\n    ctxPtr->end  = newBlock;\n    ctxPtr->nextToUpdate = ctxPtr->dictLimit;   /* match referencing will resume from there */\n\n    /* cannot reference an extDict and a dictCtx at the same time */\n    ctxPtr->dictCtx = NULL;\n}\n\nstatic int\nLZ4_compressHC_continue_generic (LZ4_streamHC_t* LZ4_streamHCPtr,\n                                 const char* src, char* dst,\n                                 int* srcSizePtr, int dstCapacity,\n                                 limitedOutput_directive limit)\n{\n    LZ4HC_CCtx_internal* const ctxPtr = &LZ4_streamHCPtr->internal_donotuse;\n    DEBUGLOG(5, \"LZ4_compressHC_continue_generic(ctx=%p, src=%p, srcSize=%d, limit=%d)\",\n                LZ4_streamHCPtr, src, *srcSizePtr, limit);\n    assert(ctxPtr != NULL);\n    /* auto-init if forgotten */\n    if (ctxPtr->prefixStart == NULL) LZ4HC_init_internal (ctxPtr, (const BYTE*) src);\n\n    /* Check overflow */\n    if ((size_t)(ctxPtr->end - ctxPtr->prefixStart) + ctxPtr->dictLimit > 2 GB) {\n        size_t dictSize = (size_t)(ctxPtr->end - ctxPtr->prefixStart);\n        if (dictSize > 64 KB) dictSize = 64 KB;\n        LZ4_loadDictHC(LZ4_streamHCPtr, (const char*)(ctxPtr->end) - dictSize, (int)dictSize);\n    }\n\n    /* Check if blocks follow each other */\n    if ((const BYTE*)src != ctxPtr->end)\n        LZ4HC_setExternalDict(ctxPtr, (const BYTE*)src);\n\n    /* Check overlapping input/dictionary space */\n    {   const BYTE* sourceEnd = (const BYTE*) src + *srcSizePtr;\n        const BYTE* const dictBegin = ctxPtr->dictStart;\n        const BYTE* const dictEnd   = ctxPtr->dictStart + (ctxPtr->dictLimit - ctxPtr->lowLimit);\n        if ((sourceEnd > dictBegin) && ((const BYTE*)src < dictEnd)) {\n            if (sourceEnd > dictEnd) sourceEnd = dictEnd;\n            ctxPtr->lowLimit += (U32)(sourceEnd - ctxPtr->dictStart);\n            ctxPtr->dictStart += (U32)(sourceEnd - ctxPtr->dictStart);\n            if (ctxPtr->dictLimit - ctxPtr->lowLimit < 4) {\n                ctxPtr->lowLimit = ctxPtr->dictLimit;\n                ctxPtr->dictStart = ctxPtr->prefixStart;\n    }   }   }\n\n    return LZ4HC_compress_generic (ctxPtr, src, dst, srcSizePtr, dstCapacity, ctxPtr->compressionLevel, limit);\n}\n\nint LZ4_compress_HC_continue (LZ4_streamHC_t* LZ4_streamHCPtr, const char* src, char* dst, int srcSize, int dstCapacity)\n{\n    if (dstCapacity < LZ4_compressBound(srcSize))\n        return LZ4_compressHC_continue_generic (LZ4_streamHCPtr, src, dst, &srcSize, dstCapacity, limitedOutput);\n    else\n        return LZ4_compressHC_continue_generic (LZ4_streamHCPtr, src, dst, &srcSize, dstCapacity, notLimited);\n}\n\nint LZ4_compress_HC_continue_destSize (LZ4_streamHC_t* LZ4_streamHCPtr, const char* src, char* dst, int* srcSizePtr, int targetDestSize)\n{\n    return LZ4_compressHC_continue_generic(LZ4_streamHCPtr, src, dst, srcSizePtr, targetDestSize, fillOutput);\n}\n\n\n\n/* LZ4_saveDictHC :\n * save history content\n * into a user-provided buffer\n * which is then used to continue compression\n */\nint LZ4_saveDictHC (LZ4_streamHC_t* LZ4_streamHCPtr, char* safeBuffer, int dictSize)\n{\n    LZ4HC_CCtx_internal* const streamPtr = &LZ4_streamHCPtr->internal_donotuse;\n    int const prefixSize = (int)(streamPtr->end - streamPtr->prefixStart);\n    DEBUGLOG(5, \"LZ4_saveDictHC(%p, %p, %d)\", LZ4_streamHCPtr, safeBuffer, dictSize);\n    assert(prefixSize >= 0);\n    if (dictSize > 64 KB) dictSize = 64 KB;\n    if (dictSize < 4) dictSize = 0;\n    if (dictSize > prefixSize) dictSize = prefixSize;\n    if (safeBuffer == NULL) assert(dictSize == 0);\n    if (dictSize > 0)\n        LZ4_memmove(safeBuffer, streamPtr->end - dictSize, dictSize);\n    {   U32 const endIndex = (U32)(streamPtr->end - streamPtr->prefixStart) + streamPtr->dictLimit;\n        streamPtr->end = (const BYTE*)safeBuffer + dictSize;\n        streamPtr->prefixStart = streamPtr->end - dictSize;\n        streamPtr->dictLimit = endIndex - (U32)dictSize;\n        streamPtr->lowLimit = endIndex - (U32)dictSize;\n        streamPtr->dictStart = streamPtr->prefixStart;\n        if (streamPtr->nextToUpdate < streamPtr->dictLimit)\n            streamPtr->nextToUpdate = streamPtr->dictLimit;\n    }\n    return dictSize;\n}\n\n\n/***************************************************\n*  Deprecated Functions\n***************************************************/\n\n/* These functions currently generate deprecation warnings */\n\n/* Wrappers for deprecated compression functions */\nint LZ4_compressHC(const char* src, char* dst, int srcSize) { return LZ4_compress_HC (src, dst, srcSize, LZ4_compressBound(srcSize), 0); }\nint LZ4_compressHC_limitedOutput(const char* src, char* dst, int srcSize, int maxDstSize) { return LZ4_compress_HC(src, dst, srcSize, maxDstSize, 0); }\nint LZ4_compressHC2(const char* src, char* dst, int srcSize, int cLevel) { return LZ4_compress_HC (src, dst, srcSize, LZ4_compressBound(srcSize), cLevel); }\nint LZ4_compressHC2_limitedOutput(const char* src, char* dst, int srcSize, int maxDstSize, int cLevel) { return LZ4_compress_HC(src, dst, srcSize, maxDstSize, cLevel); }\nint LZ4_compressHC_withStateHC (void* state, const char* src, char* dst, int srcSize) { return LZ4_compress_HC_extStateHC (state, src, dst, srcSize, LZ4_compressBound(srcSize), 0); }\nint LZ4_compressHC_limitedOutput_withStateHC (void* state, const char* src, char* dst, int srcSize, int maxDstSize) { return LZ4_compress_HC_extStateHC (state, src, dst, srcSize, maxDstSize, 0); }\nint LZ4_compressHC2_withStateHC (void* state, const char* src, char* dst, int srcSize, int cLevel) { return LZ4_compress_HC_extStateHC(state, src, dst, srcSize, LZ4_compressBound(srcSize), cLevel); }\nint LZ4_compressHC2_limitedOutput_withStateHC (void* state, const char* src, char* dst, int srcSize, int maxDstSize, int cLevel) { return LZ4_compress_HC_extStateHC(state, src, dst, srcSize, maxDstSize, cLevel); }\nint LZ4_compressHC_continue (LZ4_streamHC_t* ctx, const char* src, char* dst, int srcSize) { return LZ4_compress_HC_continue (ctx, src, dst, srcSize, LZ4_compressBound(srcSize)); }\nint LZ4_compressHC_limitedOutput_continue (LZ4_streamHC_t* ctx, const char* src, char* dst, int srcSize, int maxDstSize) { return LZ4_compress_HC_continue (ctx, src, dst, srcSize, maxDstSize); }\n\n\n/* Deprecated streaming functions */\nint LZ4_sizeofStreamStateHC(void) { return sizeof(LZ4_streamHC_t); }\n\n/* state is presumed correctly sized, aka >= sizeof(LZ4_streamHC_t)\n * @return : 0 on success, !=0 if error */\nint LZ4_resetStreamStateHC(void* state, char* inputBuffer)\n{\n    LZ4_streamHC_t* const hc4 = LZ4_initStreamHC(state, sizeof(*hc4));\n    if (hc4 == NULL) return 1;   /* init failed */\n    LZ4HC_init_internal (&hc4->internal_donotuse, (const BYTE*)inputBuffer);\n    return 0;\n}\n\n#if !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION)\nvoid* LZ4_createHC (const char* inputBuffer)\n{\n    LZ4_streamHC_t* const hc4 = LZ4_createStreamHC();\n    if (hc4 == NULL) return NULL;   /* not enough memory */\n    LZ4HC_init_internal (&hc4->internal_donotuse, (const BYTE*)inputBuffer);\n    return hc4;\n}\n\nint LZ4_freeHC (void* LZ4HC_Data)\n{\n    if (!LZ4HC_Data) return 0;  /* support free on NULL */\n    FREEMEM(LZ4HC_Data);\n    return 0;\n}\n#endif\n\nint LZ4_compressHC2_continue (void* LZ4HC_Data, const char* src, char* dst, int srcSize, int cLevel)\n{\n    return LZ4HC_compress_generic (&((LZ4_streamHC_t*)LZ4HC_Data)->internal_donotuse, src, dst, &srcSize, 0, cLevel, notLimited);\n}\n\nint LZ4_compressHC2_limitedOutput_continue (void* LZ4HC_Data, const char* src, char* dst, int srcSize, int dstCapacity, int cLevel)\n{\n    return LZ4HC_compress_generic (&((LZ4_streamHC_t*)LZ4HC_Data)->internal_donotuse, src, dst, &srcSize, dstCapacity, cLevel, limitedOutput);\n}\n\nchar* LZ4_slideInputBufferHC(void* LZ4HC_Data)\n{\n    LZ4_streamHC_t* const ctx = (LZ4_streamHC_t*)LZ4HC_Data;\n    const BYTE* bufferStart = ctx->internal_donotuse.prefixStart - ctx->internal_donotuse.dictLimit + ctx->internal_donotuse.lowLimit;\n    LZ4_resetStreamHC_fast(ctx, ctx->internal_donotuse.compressionLevel);\n    /* avoid const char * -> char * conversion warning :( */\n    return (char*)(uptrval)bufferStart;\n}\n\n\n/* ================================================\n *  LZ4 Optimal parser (levels [LZ4HC_CLEVEL_OPT_MIN - LZ4HC_CLEVEL_MAX])\n * ===============================================*/\ntypedef struct {\n    int price;\n    int off;\n    int mlen;\n    int litlen;\n} LZ4HC_optimal_t;\n\n/* price in bytes */\nLZ4_FORCE_INLINE int LZ4HC_literalsPrice(int const litlen)\n{\n    int price = litlen;\n    assert(litlen >= 0);\n    if (litlen >= (int)RUN_MASK)\n        price += 1 + ((litlen-(int)RUN_MASK) / 255);\n    return price;\n}\n\n\n/* requires mlen >= MINMATCH */\nLZ4_FORCE_INLINE int LZ4HC_sequencePrice(int litlen, int mlen)\n{\n    int price = 1 + 2 ; /* token + 16-bit offset */\n    assert(litlen >= 0);\n    assert(mlen >= MINMATCH);\n\n    price += LZ4HC_literalsPrice(litlen);\n\n    if (mlen >= (int)(ML_MASK+MINMATCH))\n        price += 1 + ((mlen-(int)(ML_MASK+MINMATCH)) / 255);\n\n    return price;\n}\n\n\ntypedef struct {\n    int off;\n    int len;\n} LZ4HC_match_t;\n\nLZ4_FORCE_INLINE LZ4HC_match_t\nLZ4HC_FindLongerMatch(LZ4HC_CCtx_internal* const ctx,\n                      const BYTE* ip, const BYTE* const iHighLimit,\n                      int minLen, int nbSearches,\n                      const dictCtx_directive dict,\n                      const HCfavor_e favorDecSpeed)\n{\n    LZ4HC_match_t match = { 0 , 0 };\n    const BYTE* matchPtr = NULL;\n    /* note : LZ4HC_InsertAndGetWiderMatch() is able to modify the starting position of a match (*startpos),\n     * but this won't be the case here, as we define iLowLimit==ip,\n     * so LZ4HC_InsertAndGetWiderMatch() won't be allowed to search past ip */\n    int matchLength = LZ4HC_InsertAndGetWiderMatch(ctx, ip, ip, iHighLimit, minLen, &matchPtr, &ip, nbSearches, 1 /*patternAnalysis*/, 1 /*chainSwap*/, dict, favorDecSpeed);\n    if (matchLength <= minLen) return match;\n    if (favorDecSpeed) {\n        if ((matchLength>18) & (matchLength<=36)) matchLength=18;   /* favor shortcut */\n    }\n    match.len = matchLength;\n    match.off = (int)(ip-matchPtr);\n    return match;\n}\n\n\nstatic int LZ4HC_compress_optimal ( LZ4HC_CCtx_internal* ctx,\n                                    const char* const source,\n                                    char* dst,\n                                    int* srcSizePtr,\n                                    int dstCapacity,\n                                    int const nbSearches,\n                                    size_t sufficient_len,\n                                    const limitedOutput_directive limit,\n                                    int const fullUpdate,\n                                    const dictCtx_directive dict,\n                                    const HCfavor_e favorDecSpeed)\n{\n    int retval = 0;\n#define TRAILING_LITERALS 3\n#if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1\n    LZ4HC_optimal_t* const opt = (LZ4HC_optimal_t*)ALLOC(sizeof(LZ4HC_optimal_t) * (LZ4_OPT_NUM + TRAILING_LITERALS));\n#else\n    LZ4HC_optimal_t opt[LZ4_OPT_NUM + TRAILING_LITERALS];   /* ~64 KB, which is a bit large for stack... */\n#endif\n\n    const BYTE* ip = (const BYTE*) source;\n    const BYTE* anchor = ip;\n    const BYTE* const iend = ip + *srcSizePtr;\n    const BYTE* const mflimit = iend - MFLIMIT;\n    const BYTE* const matchlimit = iend - LASTLITERALS;\n    BYTE* op = (BYTE*) dst;\n    BYTE* opSaved = (BYTE*) dst;\n    BYTE* oend = op + dstCapacity;\n    int ovml = MINMATCH;  /* overflow - last sequence */\n    const BYTE* ovref = NULL;\n\n    /* init */\n#if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1\n    if (opt == NULL) goto _return_label;\n#endif\n    DEBUGLOG(5, \"LZ4HC_compress_optimal(dst=%p, dstCapa=%u)\", dst, (unsigned)dstCapacity);\n    *srcSizePtr = 0;\n    if (limit == fillOutput) oend -= LASTLITERALS;   /* Hack for support LZ4 format restriction */\n    if (sufficient_len >= LZ4_OPT_NUM) sufficient_len = LZ4_OPT_NUM-1;\n\n    /* Main Loop */\n    while (ip <= mflimit) {\n         int const llen = (int)(ip - anchor);\n         int best_mlen, best_off;\n         int cur, last_match_pos = 0;\n\n         LZ4HC_match_t const firstMatch = LZ4HC_FindLongerMatch(ctx, ip, matchlimit, MINMATCH-1, nbSearches, dict, favorDecSpeed);\n         if (firstMatch.len==0) { ip++; continue; }\n\n         if ((size_t)firstMatch.len > sufficient_len) {\n             /* good enough solution : immediate encoding */\n             int const firstML = firstMatch.len;\n             const BYTE* const matchPos = ip - firstMatch.off;\n             opSaved = op;\n             if ( LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), firstML, matchPos, limit, oend) ) {  /* updates ip, op and anchor */\n                 ovml = firstML;\n                 ovref = matchPos;\n                 goto _dest_overflow;\n             }\n             continue;\n         }\n\n         /* set prices for first positions (literals) */\n         {   int rPos;\n             for (rPos = 0 ; rPos < MINMATCH ; rPos++) {\n                 int const cost = LZ4HC_literalsPrice(llen + rPos);\n                 opt[rPos].mlen = 1;\n                 opt[rPos].off = 0;\n                 opt[rPos].litlen = llen + rPos;\n                 opt[rPos].price = cost;\n                 DEBUGLOG(7, \"rPos:%3i => price:%3i (litlen=%i) -- initial setup\",\n                             rPos, cost, opt[rPos].litlen);\n         }   }\n         /* set prices using initial match */\n         {   int mlen = MINMATCH;\n             int const matchML = firstMatch.len;   /* necessarily < sufficient_len < LZ4_OPT_NUM */\n             int const offset = firstMatch.off;\n             assert(matchML < LZ4_OPT_NUM);\n             for ( ; mlen <= matchML ; mlen++) {\n                 int const cost = LZ4HC_sequencePrice(llen, mlen);\n                 opt[mlen].mlen = mlen;\n                 opt[mlen].off = offset;\n                 opt[mlen].litlen = llen;\n                 opt[mlen].price = cost;\n                 DEBUGLOG(7, \"rPos:%3i => price:%3i (matchlen=%i) -- initial setup\",\n                             mlen, cost, mlen);\n         }   }\n         last_match_pos = firstMatch.len;\n         {   int addLit;\n             for (addLit = 1; addLit <= TRAILING_LITERALS; addLit ++) {\n                 opt[last_match_pos+addLit].mlen = 1; /* literal */\n                 opt[last_match_pos+addLit].off = 0;\n                 opt[last_match_pos+addLit].litlen = addLit;\n                 opt[last_match_pos+addLit].price = opt[last_match_pos].price + LZ4HC_literalsPrice(addLit);\n                 DEBUGLOG(7, \"rPos:%3i => price:%3i (litlen=%i) -- initial setup\",\n                             last_match_pos+addLit, opt[last_match_pos+addLit].price, addLit);\n         }   }\n\n         /* check further positions */\n         for (cur = 1; cur < last_match_pos; cur++) {\n             const BYTE* const curPtr = ip + cur;\n             LZ4HC_match_t newMatch;\n\n             if (curPtr > mflimit) break;\n             DEBUGLOG(7, \"rPos:%u[%u] vs [%u]%u\",\n                     cur, opt[cur].price, opt[cur+1].price, cur+1);\n             if (fullUpdate) {\n                 /* not useful to search here if next position has same (or lower) cost */\n                 if ( (opt[cur+1].price <= opt[cur].price)\n                   /* in some cases, next position has same cost, but cost rises sharply after, so a small match would still be beneficial */\n                   && (opt[cur+MINMATCH].price < opt[cur].price + 3/*min seq price*/) )\n                     continue;\n             } else {\n                 /* not useful to search here if next position has same (or lower) cost */\n                 if (opt[cur+1].price <= opt[cur].price) continue;\n             }\n\n             DEBUGLOG(7, \"search at rPos:%u\", cur);\n             if (fullUpdate)\n                 newMatch = LZ4HC_FindLongerMatch(ctx, curPtr, matchlimit, MINMATCH-1, nbSearches, dict, favorDecSpeed);\n             else\n                 /* only test matches of minimum length; slightly faster, but misses a few bytes */\n                 newMatch = LZ4HC_FindLongerMatch(ctx, curPtr, matchlimit, last_match_pos - cur, nbSearches, dict, favorDecSpeed);\n             if (!newMatch.len) continue;\n\n             if ( ((size_t)newMatch.len > sufficient_len)\n               || (newMatch.len + cur >= LZ4_OPT_NUM) ) {\n                 /* immediate encoding */\n                 best_mlen = newMatch.len;\n                 best_off = newMatch.off;\n                 last_match_pos = cur + 1;\n                 goto encode;\n             }\n\n             /* before match : set price with literals at beginning */\n             {   int const baseLitlen = opt[cur].litlen;\n                 int litlen;\n                 for (litlen = 1; litlen < MINMATCH; litlen++) {\n                     int const price = opt[cur].price - LZ4HC_literalsPrice(baseLitlen) + LZ4HC_literalsPrice(baseLitlen+litlen);\n                     int const pos = cur + litlen;\n                     if (price < opt[pos].price) {\n                         opt[pos].mlen = 1; /* literal */\n                         opt[pos].off = 0;\n                         opt[pos].litlen = baseLitlen+litlen;\n                         opt[pos].price = price;\n                         DEBUGLOG(7, \"rPos:%3i => price:%3i (litlen=%i)\",\n                                     pos, price, opt[pos].litlen);\n             }   }   }\n\n             /* set prices using match at position = cur */\n             {   int const matchML = newMatch.len;\n                 int ml = MINMATCH;\n\n                 assert(cur + newMatch.len < LZ4_OPT_NUM);\n                 for ( ; ml <= matchML ; ml++) {\n                     int const pos = cur + ml;\n                     int const offset = newMatch.off;\n                     int price;\n                     int ll;\n                     DEBUGLOG(7, \"testing price rPos %i (last_match_pos=%i)\",\n                                 pos, last_match_pos);\n                     if (opt[cur].mlen == 1) {\n                         ll = opt[cur].litlen;\n                         price = ((cur > ll) ? opt[cur - ll].price : 0)\n                               + LZ4HC_sequencePrice(ll, ml);\n                     } else {\n                         ll = 0;\n                         price = opt[cur].price + LZ4HC_sequencePrice(0, ml);\n                     }\n\n                    assert((U32)favorDecSpeed <= 1);\n                     if (pos > last_match_pos+TRAILING_LITERALS\n                      || price <= opt[pos].price - (int)favorDecSpeed) {\n                         DEBUGLOG(7, \"rPos:%3i => price:%3i (matchlen=%i)\",\n                                     pos, price, ml);\n                         assert(pos < LZ4_OPT_NUM);\n                         if ( (ml == matchML)  /* last pos of last match */\n                           && (last_match_pos < pos) )\n                             last_match_pos = pos;\n                         opt[pos].mlen = ml;\n                         opt[pos].off = offset;\n                         opt[pos].litlen = ll;\n                         opt[pos].price = price;\n             }   }   }\n             /* complete following positions with literals */\n             {   int addLit;\n                 for (addLit = 1; addLit <= TRAILING_LITERALS; addLit ++) {\n                     opt[last_match_pos+addLit].mlen = 1; /* literal */\n                     opt[last_match_pos+addLit].off = 0;\n                     opt[last_match_pos+addLit].litlen = addLit;\n                     opt[last_match_pos+addLit].price = opt[last_match_pos].price + LZ4HC_literalsPrice(addLit);\n                     DEBUGLOG(7, \"rPos:%3i => price:%3i (litlen=%i)\", last_match_pos+addLit, opt[last_match_pos+addLit].price, addLit);\n             }   }\n         }  /* for (cur = 1; cur <= last_match_pos; cur++) */\n\n         assert(last_match_pos < LZ4_OPT_NUM + TRAILING_LITERALS);\n         best_mlen = opt[last_match_pos].mlen;\n         best_off = opt[last_match_pos].off;\n         cur = last_match_pos - best_mlen;\n\nencode: /* cur, last_match_pos, best_mlen, best_off must be set */\n         assert(cur < LZ4_OPT_NUM);\n         assert(last_match_pos >= 1);  /* == 1 when only one candidate */\n         DEBUGLOG(6, \"reverse traversal, looking for shortest path (last_match_pos=%i)\", last_match_pos);\n         {   int candidate_pos = cur;\n             int selected_matchLength = best_mlen;\n             int selected_offset = best_off;\n             while (1) {  /* from end to beginning */\n                 int const next_matchLength = opt[candidate_pos].mlen;  /* can be 1, means literal */\n                 int const next_offset = opt[candidate_pos].off;\n                 DEBUGLOG(7, \"pos %i: sequence length %i\", candidate_pos, selected_matchLength);\n                 opt[candidate_pos].mlen = selected_matchLength;\n                 opt[candidate_pos].off = selected_offset;\n                 selected_matchLength = next_matchLength;\n                 selected_offset = next_offset;\n                 if (next_matchLength > candidate_pos) break; /* last match elected, first match to encode */\n                 assert(next_matchLength > 0);  /* can be 1, means literal */\n                 candidate_pos -= next_matchLength;\n         }   }\n\n         /* encode all recorded sequences in order */\n         {   int rPos = 0;  /* relative position (to ip) */\n             while (rPos < last_match_pos) {\n                 int const ml = opt[rPos].mlen;\n                 int const offset = opt[rPos].off;\n                 if (ml == 1) { ip++; rPos++; continue; }  /* literal; note: can end up with several literals, in which case, skip them */\n                 rPos += ml;\n                 assert(ml >= MINMATCH);\n                 assert((offset >= 1) && (offset <= LZ4_DISTANCE_MAX));\n                 opSaved = op;\n                 if ( LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml, ip - offset, limit, oend) ) {  /* updates ip, op and anchor */\n                     ovml = ml;\n                     ovref = ip - offset;\n                     goto _dest_overflow;\n         }   }   }\n     }  /* while (ip <= mflimit) */\n\n_last_literals:\n     /* Encode Last Literals */\n     {   size_t lastRunSize = (size_t)(iend - anchor);  /* literals */\n         size_t llAdd = (lastRunSize + 255 - RUN_MASK) / 255;\n         size_t const totalSize = 1 + llAdd + lastRunSize;\n         if (limit == fillOutput) oend += LASTLITERALS;  /* restore correct value */\n         if (limit && (op + totalSize > oend)) {\n             if (limit == limitedOutput) { /* Check output limit */\n                retval = 0;\n                goto _return_label;\n             }\n             /* adapt lastRunSize to fill 'dst' */\n             lastRunSize  = (size_t)(oend - op) - 1 /*token*/;\n             llAdd = (lastRunSize + 256 - RUN_MASK) / 256;\n             lastRunSize -= llAdd;\n         }\n         DEBUGLOG(6, \"Final literal run : %i literals\", (int)lastRunSize);\n         ip = anchor + lastRunSize; /* can be != iend if limit==fillOutput */\n\n         if (lastRunSize >= RUN_MASK) {\n             size_t accumulator = lastRunSize - RUN_MASK;\n             *op++ = (RUN_MASK << ML_BITS);\n             for(; accumulator >= 255 ; accumulator -= 255) *op++ = 255;\n             *op++ = (BYTE) accumulator;\n         } else {\n             *op++ = (BYTE)(lastRunSize << ML_BITS);\n         }\n         LZ4_memcpy(op, anchor, lastRunSize);\n         op += lastRunSize;\n     }\n\n     /* End */\n     *srcSizePtr = (int) (((const char*)ip) - source);\n     retval = (int) ((char*)op-dst);\n     goto _return_label;\n\n_dest_overflow:\nif (limit == fillOutput) {\n     /* Assumption : ip, anchor, ovml and ovref must be set correctly */\n     size_t const ll = (size_t)(ip - anchor);\n     size_t const ll_addbytes = (ll + 240) / 255;\n     size_t const ll_totalCost = 1 + ll_addbytes + ll;\n     BYTE* const maxLitPos = oend - 3; /* 2 for offset, 1 for token */\n     DEBUGLOG(6, \"Last sequence overflowing (only %i bytes remaining)\", (int)(oend-1-opSaved));\n     op = opSaved;  /* restore correct out pointer */\n     if (op + ll_totalCost <= maxLitPos) {\n         /* ll validated; now adjust match length */\n         size_t const bytesLeftForMl = (size_t)(maxLitPos - (op+ll_totalCost));\n         size_t const maxMlSize = MINMATCH + (ML_MASK-1) + (bytesLeftForMl * 255);\n         assert(maxMlSize < INT_MAX); assert(ovml >= 0);\n         if ((size_t)ovml > maxMlSize) ovml = (int)maxMlSize;\n         if ((oend + LASTLITERALS) - (op + ll_totalCost + 2) - 1 + ovml >= MFLIMIT) {\n             DEBUGLOG(6, \"Space to end : %i + ml (%i)\", (int)((oend + LASTLITERALS) - (op + ll_totalCost + 2) - 1), ovml);\n             DEBUGLOG(6, \"Before : ip = %p, anchor = %p\", ip, anchor);\n             LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ovml, ovref, notLimited, oend);\n             DEBUGLOG(6, \"After : ip = %p, anchor = %p\", ip, anchor);\n     }   }\n     goto _last_literals;\n}\n_return_label:\n#if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1\n     FREEMEM(opt);\n#endif\n     return retval;\n}\n\n}\n"
  },
  {
    "path": "tracy-client-sys/tracy/common/tracy_lz4hc.hpp",
    "content": "/*\n   LZ4 HC - High Compression Mode of LZ4\n   Header File\n   Copyright (C) 2011-2020, Yann Collet.\n   BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)\n\n   Redistribution and use in source and binary forms, with or without\n   modification, are permitted provided that the following conditions are\n   met:\n\n       * Redistributions of source code must retain the above copyright\n   notice, this list of conditions and the following disclaimer.\n       * Redistributions in binary form must reproduce the above\n   copyright notice, this list of conditions and the following disclaimer\n   in the documentation and/or other materials provided with the\n   distribution.\n\n   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n   \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n   You can contact the author at :\n   - LZ4 source repository : https://github.com/lz4/lz4\n   - LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c\n*/\n#ifndef TRACY_LZ4_HC_H_19834876238432\n#define TRACY_LZ4_HC_H_19834876238432\n\n/* --- Dependency --- */\n/* note : lz4hc requires lz4.h/lz4.c for compilation */\n#include \"tracy_lz4.hpp\"   /* stddef, LZ4LIB_API, LZ4_DEPRECATED */\n\n\n/* --- Useful constants --- */\n#define LZ4HC_CLEVEL_MIN         3\n#define LZ4HC_CLEVEL_DEFAULT     9\n#define LZ4HC_CLEVEL_OPT_MIN    10\n#define LZ4HC_CLEVEL_MAX        12\n\nnamespace tracy\n{\n\n/*-************************************\n *  Block Compression\n **************************************/\n/*! LZ4_compress_HC() :\n *  Compress data from `src` into `dst`, using the powerful but slower \"HC\" algorithm.\n * `dst` must be already allocated.\n *  Compression is guaranteed to succeed if `dstCapacity >= LZ4_compressBound(srcSize)` (see \"lz4.h\")\n *  Max supported `srcSize` value is LZ4_MAX_INPUT_SIZE (see \"lz4.h\")\n * `compressionLevel` : any value between 1 and LZ4HC_CLEVEL_MAX will work.\n *                      Values > LZ4HC_CLEVEL_MAX behave the same as LZ4HC_CLEVEL_MAX.\n * @return : the number of bytes written into 'dst'\n *           or 0 if compression fails.\n */\nLZ4LIB_API int LZ4_compress_HC (const char* src, char* dst, int srcSize, int dstCapacity, int compressionLevel);\n\n\n/* Note :\n *   Decompression functions are provided within \"lz4.h\" (BSD license)\n */\n\n\n/*! LZ4_compress_HC_extStateHC() :\n *  Same as LZ4_compress_HC(), but using an externally allocated memory segment for `state`.\n * `state` size is provided by LZ4_sizeofStateHC().\n *  Memory segment must be aligned on 8-bytes boundaries (which a normal malloc() should do properly).\n */\nLZ4LIB_API int LZ4_sizeofStateHC(void);\nLZ4LIB_API int LZ4_compress_HC_extStateHC(void* stateHC, const char* src, char* dst, int srcSize, int maxDstSize, int compressionLevel);\n\n\n/*! LZ4_compress_HC_destSize() : v1.9.0+\n *  Will compress as much data as possible from `src`\n *  to fit into `targetDstSize` budget.\n *  Result is provided in 2 parts :\n * @return : the number of bytes written into 'dst' (necessarily <= targetDstSize)\n *           or 0 if compression fails.\n * `srcSizePtr` : on success, *srcSizePtr is updated to indicate how much bytes were read from `src`\n */\nLZ4LIB_API int LZ4_compress_HC_destSize(void* stateHC,\n                                  const char* src, char* dst,\n                                        int* srcSizePtr, int targetDstSize,\n                                        int compressionLevel);\n\n\n/*-************************************\n *  Streaming Compression\n *  Bufferless synchronous API\n **************************************/\n typedef union LZ4_streamHC_u LZ4_streamHC_t;   /* incomplete type (defined later) */\n\n/*! LZ4_createStreamHC() and LZ4_freeStreamHC() :\n *  These functions create and release memory for LZ4 HC streaming state.\n *  Newly created states are automatically initialized.\n *  A same state can be used multiple times consecutively,\n *  starting with LZ4_resetStreamHC_fast() to start a new stream of blocks.\n */\nLZ4LIB_API LZ4_streamHC_t* LZ4_createStreamHC(void);\nLZ4LIB_API int             LZ4_freeStreamHC (LZ4_streamHC_t* streamHCPtr);\n\n/*\n  These functions compress data in successive blocks of any size,\n  using previous blocks as dictionary, to improve compression ratio.\n  One key assumption is that previous blocks (up to 64 KB) remain read-accessible while compressing next blocks.\n  There is an exception for ring buffers, which can be smaller than 64 KB.\n  Ring-buffer scenario is automatically detected and handled within LZ4_compress_HC_continue().\n\n  Before starting compression, state must be allocated and properly initialized.\n  LZ4_createStreamHC() does both, though compression level is set to LZ4HC_CLEVEL_DEFAULT.\n\n  Selecting the compression level can be done with LZ4_resetStreamHC_fast() (starts a new stream)\n  or LZ4_setCompressionLevel() (anytime, between blocks in the same stream) (experimental).\n  LZ4_resetStreamHC_fast() only works on states which have been properly initialized at least once,\n  which is automatically the case when state is created using LZ4_createStreamHC().\n\n  After reset, a first \"fictional block\" can be designated as initial dictionary,\n  using LZ4_loadDictHC() (Optional).\n\n  Invoke LZ4_compress_HC_continue() to compress each successive block.\n  The number of blocks is unlimited.\n  Previous input blocks, including initial dictionary when present,\n  must remain accessible and unmodified during compression.\n\n  It's allowed to update compression level anytime between blocks,\n  using LZ4_setCompressionLevel() (experimental).\n\n  'dst' buffer should be sized to handle worst case scenarios\n  (see LZ4_compressBound(), it ensures compression success).\n  In case of failure, the API does not guarantee recovery,\n  so the state _must_ be reset.\n  To ensure compression success\n  whenever `dst` buffer size cannot be made >= LZ4_compressBound(),\n  consider using LZ4_compress_HC_continue_destSize().\n\n  Whenever previous input blocks can't be preserved unmodified in-place during compression of next blocks,\n  it's possible to copy the last blocks into a more stable memory space, using LZ4_saveDictHC().\n  Return value of LZ4_saveDictHC() is the size of dictionary effectively saved into 'safeBuffer' (<= 64 KB)\n\n  After completing a streaming compression,\n  it's possible to start a new stream of blocks, using the same LZ4_streamHC_t state,\n  just by resetting it, using LZ4_resetStreamHC_fast().\n*/\n\nLZ4LIB_API void LZ4_resetStreamHC_fast(LZ4_streamHC_t* streamHCPtr, int compressionLevel);   /* v1.9.0+ */\nLZ4LIB_API int  LZ4_loadDictHC (LZ4_streamHC_t* streamHCPtr, const char* dictionary, int dictSize);\n\nLZ4LIB_API int LZ4_compress_HC_continue (LZ4_streamHC_t* streamHCPtr,\n                                   const char* src, char* dst,\n                                         int srcSize, int maxDstSize);\n\n/*! LZ4_compress_HC_continue_destSize() : v1.9.0+\n *  Similar to LZ4_compress_HC_continue(),\n *  but will read as much data as possible from `src`\n *  to fit into `targetDstSize` budget.\n *  Result is provided into 2 parts :\n * @return : the number of bytes written into 'dst' (necessarily <= targetDstSize)\n *           or 0 if compression fails.\n * `srcSizePtr` : on success, *srcSizePtr will be updated to indicate how much bytes were read from `src`.\n *           Note that this function may not consume the entire input.\n */\nLZ4LIB_API int LZ4_compress_HC_continue_destSize(LZ4_streamHC_t* LZ4_streamHCPtr,\n                                           const char* src, char* dst,\n                                                 int* srcSizePtr, int targetDstSize);\n\nLZ4LIB_API int LZ4_saveDictHC (LZ4_streamHC_t* streamHCPtr, char* safeBuffer, int maxDictSize);\n\n\n\n/*^**********************************************\n * !!!!!!   STATIC LINKING ONLY   !!!!!!\n ***********************************************/\n\n/*-******************************************************************\n * PRIVATE DEFINITIONS :\n * Do not use these definitions directly.\n * They are merely exposed to allow static allocation of `LZ4_streamHC_t`.\n * Declare an `LZ4_streamHC_t` directly, rather than any type below.\n * Even then, only do so in the context of static linking, as definitions may change between versions.\n ********************************************************************/\n\n#define LZ4HC_DICTIONARY_LOGSIZE 16\n#define LZ4HC_MAXD (1<<LZ4HC_DICTIONARY_LOGSIZE)\n#define LZ4HC_MAXD_MASK (LZ4HC_MAXD - 1)\n\n#define LZ4HC_HASH_LOG 15\n#define LZ4HC_HASHTABLESIZE (1 << LZ4HC_HASH_LOG)\n#define LZ4HC_HASH_MASK (LZ4HC_HASHTABLESIZE - 1)\n\n\n/* Never ever use these definitions directly !\n * Declare or allocate an LZ4_streamHC_t instead.\n**/\ntypedef struct LZ4HC_CCtx_internal LZ4HC_CCtx_internal;\nstruct LZ4HC_CCtx_internal\n{\n    LZ4_u32   hashTable[LZ4HC_HASHTABLESIZE];\n    LZ4_u16   chainTable[LZ4HC_MAXD];\n    const LZ4_byte* end;       /* next block here to continue on current prefix */\n    const LZ4_byte* prefixStart;  /* Indexes relative to this position */\n    const LZ4_byte* dictStart; /* alternate reference for extDict */\n    LZ4_u32   dictLimit;       /* below that point, need extDict */\n    LZ4_u32   lowLimit;        /* below that point, no more dict */\n    LZ4_u32   nextToUpdate;    /* index from which to continue dictionary update */\n    short     compressionLevel;\n    LZ4_i8    favorDecSpeed;   /* favor decompression speed if this flag set,\n                                  otherwise, favor compression ratio */\n    LZ4_i8    dirty;           /* stream has to be fully reset if this flag is set */\n    const LZ4HC_CCtx_internal* dictCtx;\n};\n\n#define LZ4_STREAMHC_MINSIZE  262200  /* static size, for inter-version compatibility */\nunion LZ4_streamHC_u {\n    char minStateSize[LZ4_STREAMHC_MINSIZE];\n    LZ4HC_CCtx_internal internal_donotuse;\n}; /* previously typedef'd to LZ4_streamHC_t */\n\n/* LZ4_streamHC_t :\n * This structure allows static allocation of LZ4 HC streaming state.\n * This can be used to allocate statically on stack, or as part of a larger structure.\n *\n * Such state **must** be initialized using LZ4_initStreamHC() before first use.\n *\n * Note that invoking LZ4_initStreamHC() is not required when\n * the state was created using LZ4_createStreamHC() (which is recommended).\n * Using the normal builder, a newly created state is automatically initialized.\n *\n * Static allocation shall only be used in combination with static linking.\n */\n\n/* LZ4_initStreamHC() : v1.9.0+\n * Required before first use of a statically allocated LZ4_streamHC_t.\n * Before v1.9.0 : use LZ4_resetStreamHC() instead\n */\nLZ4LIB_API LZ4_streamHC_t* LZ4_initStreamHC(void* buffer, size_t size);\n\n\n/*-************************************\n*  Deprecated Functions\n**************************************/\n/* see lz4.h LZ4_DISABLE_DEPRECATE_WARNINGS to turn off deprecation warnings */\n\n/* deprecated compression functions */\nLZ4_DEPRECATED(\"use LZ4_compress_HC() instead\") LZ4LIB_API int LZ4_compressHC               (const char* source, char* dest, int inputSize);\nLZ4_DEPRECATED(\"use LZ4_compress_HC() instead\") LZ4LIB_API int LZ4_compressHC_limitedOutput (const char* source, char* dest, int inputSize, int maxOutputSize);\nLZ4_DEPRECATED(\"use LZ4_compress_HC() instead\") LZ4LIB_API int LZ4_compressHC2              (const char* source, char* dest, int inputSize, int compressionLevel);\nLZ4_DEPRECATED(\"use LZ4_compress_HC() instead\") LZ4LIB_API int LZ4_compressHC2_limitedOutput(const char* source, char* dest, int inputSize, int maxOutputSize, int compressionLevel);\nLZ4_DEPRECATED(\"use LZ4_compress_HC_extStateHC() instead\") LZ4LIB_API int LZ4_compressHC_withStateHC               (void* state, const char* source, char* dest, int inputSize);\nLZ4_DEPRECATED(\"use LZ4_compress_HC_extStateHC() instead\") LZ4LIB_API int LZ4_compressHC_limitedOutput_withStateHC (void* state, const char* source, char* dest, int inputSize, int maxOutputSize);\nLZ4_DEPRECATED(\"use LZ4_compress_HC_extStateHC() instead\") LZ4LIB_API int LZ4_compressHC2_withStateHC              (void* state, const char* source, char* dest, int inputSize, int compressionLevel);\nLZ4_DEPRECATED(\"use LZ4_compress_HC_extStateHC() instead\") LZ4LIB_API int LZ4_compressHC2_limitedOutput_withStateHC(void* state, const char* source, char* dest, int inputSize, int maxOutputSize, int compressionLevel);\nLZ4_DEPRECATED(\"use LZ4_compress_HC_continue() instead\") LZ4LIB_API int LZ4_compressHC_continue               (LZ4_streamHC_t* LZ4_streamHCPtr, const char* source, char* dest, int inputSize);\nLZ4_DEPRECATED(\"use LZ4_compress_HC_continue() instead\") LZ4LIB_API int LZ4_compressHC_limitedOutput_continue (LZ4_streamHC_t* LZ4_streamHCPtr, const char* source, char* dest, int inputSize, int maxOutputSize);\n\n/* Obsolete streaming functions; degraded functionality; do not use!\n *\n * In order to perform streaming compression, these functions depended on data\n * that is no longer tracked in the state. They have been preserved as well as\n * possible: using them will still produce a correct output. However, use of\n * LZ4_slideInputBufferHC() will truncate the history of the stream, rather\n * than preserve a window-sized chunk of history.\n */\n#if !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION)\nLZ4_DEPRECATED(\"use LZ4_createStreamHC() instead\") LZ4LIB_API void* LZ4_createHC (const char* inputBuffer);\nLZ4_DEPRECATED(\"use LZ4_freeStreamHC() instead\") LZ4LIB_API   int   LZ4_freeHC (void* LZ4HC_Data);\n#endif\nLZ4_DEPRECATED(\"use LZ4_saveDictHC() instead\") LZ4LIB_API     char* LZ4_slideInputBufferHC (void* LZ4HC_Data);\nLZ4_DEPRECATED(\"use LZ4_compress_HC_continue() instead\") LZ4LIB_API int LZ4_compressHC2_continue               (void* LZ4HC_Data, const char* source, char* dest, int inputSize, int compressionLevel);\nLZ4_DEPRECATED(\"use LZ4_compress_HC_continue() instead\") LZ4LIB_API int LZ4_compressHC2_limitedOutput_continue (void* LZ4HC_Data, const char* source, char* dest, int inputSize, int maxOutputSize, int compressionLevel);\nLZ4_DEPRECATED(\"use LZ4_createStreamHC() instead\") LZ4LIB_API int   LZ4_sizeofStreamStateHC(void);\nLZ4_DEPRECATED(\"use LZ4_initStreamHC() instead\") LZ4LIB_API  int   LZ4_resetStreamStateHC(void* state, char* inputBuffer);\n\n\n/* LZ4_resetStreamHC() is now replaced by LZ4_initStreamHC().\n * The intention is to emphasize the difference with LZ4_resetStreamHC_fast(),\n * which is now the recommended function to start a new stream of blocks,\n * but cannot be used to initialize a memory segment containing arbitrary garbage data.\n *\n * It is recommended to switch to LZ4_initStreamHC().\n * LZ4_resetStreamHC() will generate deprecation warnings in a future version.\n */\nLZ4LIB_API void LZ4_resetStreamHC (LZ4_streamHC_t* streamHCPtr, int compressionLevel);\n\n}\n\n#endif /* LZ4_HC_H_19834876238432 */\n\n\n/*-**************************************************\n * !!!!!     STATIC LINKING ONLY     !!!!!\n * Following definitions are considered experimental.\n * They should not be linked from DLL,\n * as there is no guarantee of API stability yet.\n * Prototypes will be promoted to \"stable\" status\n * after successful usage in real-life scenarios.\n ***************************************************/\n#ifdef LZ4_HC_STATIC_LINKING_ONLY   /* protection macro */\n#ifndef TRACY_LZ4_HC_SLO_098092834\n#define TRACY_LZ4_HC_SLO_098092834\n\n#define LZ4_STATIC_LINKING_ONLY   /* LZ4LIB_STATIC_API */\n#include \"tracy_lz4.hpp\"\n\nnamespace tracy\n{\n\n/*! LZ4_setCompressionLevel() : v1.8.0+ (experimental)\n *  It's possible to change compression level\n *  between successive invocations of LZ4_compress_HC_continue*()\n *  for dynamic adaptation.\n */\nLZ4LIB_STATIC_API void LZ4_setCompressionLevel(\n    LZ4_streamHC_t* LZ4_streamHCPtr, int compressionLevel);\n\n/*! LZ4_favorDecompressionSpeed() : v1.8.2+ (experimental)\n *  Opt. Parser will favor decompression speed over compression ratio.\n *  Only applicable to levels >= LZ4HC_CLEVEL_OPT_MIN.\n */\nLZ4LIB_STATIC_API void LZ4_favorDecompressionSpeed(\n    LZ4_streamHC_t* LZ4_streamHCPtr, int favor);\n\n/*! LZ4_resetStreamHC_fast() : v1.9.0+\n *  When an LZ4_streamHC_t is known to be in a internally coherent state,\n *  it can often be prepared for a new compression with almost no work, only\n *  sometimes falling back to the full, expensive reset that is always required\n *  when the stream is in an indeterminate state (i.e., the reset performed by\n *  LZ4_resetStreamHC()).\n *\n *  LZ4_streamHCs are guaranteed to be in a valid state when:\n *  - returned from LZ4_createStreamHC()\n *  - reset by LZ4_resetStreamHC()\n *  - memset(stream, 0, sizeof(LZ4_streamHC_t))\n *  - the stream was in a valid state and was reset by LZ4_resetStreamHC_fast()\n *  - the stream was in a valid state and was then used in any compression call\n *    that returned success\n *  - the stream was in an indeterminate state and was used in a compression\n *    call that fully reset the state (LZ4_compress_HC_extStateHC()) and that\n *    returned success\n *\n *  Note:\n *  A stream that was last used in a compression call that returned an error\n *  may be passed to this function. However, it will be fully reset, which will\n *  clear any existing history and settings from the context.\n */\nLZ4LIB_STATIC_API void LZ4_resetStreamHC_fast(\n    LZ4_streamHC_t* LZ4_streamHCPtr, int compressionLevel);\n\n/*! LZ4_compress_HC_extStateHC_fastReset() :\n *  A variant of LZ4_compress_HC_extStateHC().\n *\n *  Using this variant avoids an expensive initialization step. It is only safe\n *  to call if the state buffer is known to be correctly initialized already\n *  (see above comment on LZ4_resetStreamHC_fast() for a definition of\n *  \"correctly initialized\"). From a high level, the difference is that this\n *  function initializes the provided state with a call to\n *  LZ4_resetStreamHC_fast() while LZ4_compress_HC_extStateHC() starts with a\n *  call to LZ4_resetStreamHC().\n */\nLZ4LIB_STATIC_API int LZ4_compress_HC_extStateHC_fastReset (\n    void* state,\n    const char* src, char* dst,\n    int srcSize, int dstCapacity,\n    int compressionLevel);\n\n/*! LZ4_attach_HC_dictionary() :\n *  This is an experimental API that allows for the efficient use of a\n *  static dictionary many times.\n *\n *  Rather than re-loading the dictionary buffer into a working context before\n *  each compression, or copying a pre-loaded dictionary's LZ4_streamHC_t into a\n *  working LZ4_streamHC_t, this function introduces a no-copy setup mechanism,\n *  in which the working stream references the dictionary stream in-place.\n *\n *  Several assumptions are made about the state of the dictionary stream.\n *  Currently, only streams which have been prepared by LZ4_loadDictHC() should\n *  be expected to work.\n *\n *  Alternatively, the provided dictionary stream pointer may be NULL, in which\n *  case any existing dictionary stream is unset.\n *\n *  A dictionary should only be attached to a stream without any history (i.e.,\n *  a stream that has just been reset).\n *\n *  The dictionary will remain attached to the working stream only for the\n *  current stream session. Calls to LZ4_resetStreamHC(_fast) will remove the\n *  dictionary context association from the working stream. The dictionary\n *  stream (and source buffer) must remain in-place / accessible / unchanged\n *  through the lifetime of the stream session.\n */\nLZ4LIB_STATIC_API void LZ4_attach_HC_dictionary(\n          LZ4_streamHC_t *working_stream,\n    const LZ4_streamHC_t *dictionary_stream);\n\n}\n\n#endif   /* LZ4_HC_SLO_098092834 */\n#endif   /* LZ4_HC_STATIC_LINKING_ONLY */\n"
  },
  {
    "path": "tracy-client-sys/tracy/libbacktrace/LICENSE",
    "content": "# Copyright (C) 2012-2016 Free Software Foundation, Inc.\n\n# Redistribution and use in source and binary forms, with or without\n# modification, are permitted provided that the following conditions are\n# met:\n\n#     (1) Redistributions of source code must retain the above copyright\n#     notice, this list of conditions and the following disclaimer. \n\n#     (2) Redistributions in binary form must reproduce the above copyright\n#     notice, this list of conditions and the following disclaimer in\n#     the documentation and/or other materials provided with the\n#     distribution.  \n    \n#     (3) The name of the author may not be used to\n#     endorse or promote products derived from this software without\n#     specific prior written permission.\n\n# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\n# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n# DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,\n# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\n# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\n# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\n# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n# POSSIBILITY OF SUCH DAMAGE.\n"
  },
  {
    "path": "tracy-client-sys/tracy/libbacktrace/alloc.cpp",
    "content": "/* alloc.c -- Memory allocation without mmap.\n   Copyright (C) 2012-2021 Free Software Foundation, Inc.\n   Written by Ian Lance Taylor, Google.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n    (1) Redistributions of source code must retain the above copyright\n    notice, this list of conditions and the following disclaimer.\n\n    (2) Redistributions in binary form must reproduce the above copyright\n    notice, this list of conditions and the following disclaimer in\n    the documentation and/or other materials provided with the\n    distribution.\n\n    (3) The name of the author may not be used to\n    endorse or promote products derived from this software without\n    specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\nIMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\nWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,\nINDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\nHOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\nSTRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\nIN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGE.  */\n\n#include \"config.h\"\n\n#include <errno.h>\n#include <stdlib.h>\n#include <sys/types.h>\n\n#include \"backtrace.hpp\"\n#include \"internal.hpp\"\n\n#include \"../common/TracyAlloc.hpp\"\n\nnamespace tracy\n{\n\n/* Allocation routines to use on systems that do not support anonymous\n   mmap.  This implementation just uses malloc, which means that the\n   backtrace functions may not be safely invoked from a signal\n   handler.  */\n\n/* Allocate memory like malloc.  If ERROR_CALLBACK is NULL, don't\n   report an error.  */\n\nvoid *\nbacktrace_alloc (struct backtrace_state *state ATTRIBUTE_UNUSED,\n\t\t size_t size, backtrace_error_callback error_callback,\n\t\t void *data)\n{\n  void *ret;\n\n  ret = tracy_malloc (size);\n  if (ret == NULL)\n    {\n      if (error_callback)\n\terror_callback (data, \"malloc\", errno);\n    }\n  return ret;\n}\n\n/* Free memory.  */\n\nvoid\nbacktrace_free (struct backtrace_state *state ATTRIBUTE_UNUSED,\n\t\tvoid *p, size_t size ATTRIBUTE_UNUSED,\n\t\tbacktrace_error_callback error_callback ATTRIBUTE_UNUSED,\n\t\tvoid *data ATTRIBUTE_UNUSED)\n{\n  tracy_free (p);\n}\n\n/* Grow VEC by SIZE bytes.  */\n\nvoid *\nbacktrace_vector_grow (struct backtrace_state *state ATTRIBUTE_UNUSED,\n\t\t       size_t size, backtrace_error_callback error_callback,\n\t\t       void *data, struct backtrace_vector *vec)\n{\n  void *ret;\n\n  if (size > vec->alc)\n    {\n      size_t alc;\n      void *base;\n\n      if (vec->size == 0)\n\talc = 32 * size;\n      else if (vec->size >= 4096)\n\talc = vec->size + 4096;\n      else\n\talc = 2 * vec->size;\n\n      if (alc < vec->size + size)\n\talc = vec->size + size;\n\n      base = tracy_realloc (vec->base, alc);\n      if (base == NULL)\n\t{\n\t  error_callback (data, \"realloc\", errno);\n\t  return NULL;\n\t}\n\n      vec->base = base;\n      vec->alc = alc - vec->size;\n    }\n\n  ret = (char *) vec->base + vec->size;\n  vec->size += size;\n  vec->alc -= size;\n  return ret;\n}\n\n/* Finish the current allocation on VEC.  */\n\nvoid *\nbacktrace_vector_finish (struct backtrace_state *state,\n\t\t\t struct backtrace_vector *vec,\n\t\t\t backtrace_error_callback error_callback,\n\t\t\t void *data)\n{\n  void *ret;\n\n  /* With this allocator we call realloc in backtrace_vector_grow,\n     which means we can't easily reuse the memory here.  So just\n     release it.  */\n  if (!backtrace_vector_release (state, vec, error_callback, data))\n    return NULL;\n  ret = vec->base;\n  vec->base = NULL;\n  vec->size = 0;\n  vec->alc = 0;\n  return ret;\n}\n\n/* Release any extra space allocated for VEC.  */\n\nint\nbacktrace_vector_release (struct backtrace_state *state ATTRIBUTE_UNUSED,\n\t\t\t  struct backtrace_vector *vec,\n\t\t\t  backtrace_error_callback error_callback,\n\t\t\t  void *data)\n{\n  vec->alc = 0;\n\n  if (vec->size == 0)\n    {\n      /* As of C17, realloc with size 0 is marked as an obsolescent feature, use\n\t free instead.  */\n      tracy_free (vec->base);\n      vec->base = NULL;\n      return 1;\n    }\n\n  vec->base = tracy_realloc (vec->base, vec->size);\n  if (vec->base == NULL)\n    {\n      error_callback (data, \"realloc\", errno);\n      return 0;\n    }\n\n  return 1;\n}\n\n}\n"
  },
  {
    "path": "tracy-client-sys/tracy/libbacktrace/backtrace.hpp",
    "content": "/* backtrace.h -- Public header file for stack backtrace library.\n   Copyright (C) 2012-2021 Free Software Foundation, Inc.\n   Written by Ian Lance Taylor, Google.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n    (1) Redistributions of source code must retain the above copyright\n    notice, this list of conditions and the following disclaimer.\n\n    (2) Redistributions in binary form must reproduce the above copyright\n    notice, this list of conditions and the following disclaimer in\n    the documentation and/or other materials provided with the\n    distribution.\n\n    (3) The name of the author may not be used to\n    endorse or promote products derived from this software without\n    specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\nIMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\nWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,\nINDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\nHOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\nSTRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\nIN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGE.  */\n\n#ifndef BACKTRACE_H\n#define BACKTRACE_H\n\n#include <stddef.h>\n#include <stdint.h>\n#include <stdio.h>\n\nnamespace tracy\n{\n\n/* The backtrace state.  This struct is intentionally not defined in\n   the public interface.  */\n\nstruct backtrace_state;\n\n/* The type of the error callback argument to backtrace functions.\n   This function, if not NULL, will be called for certain error cases.\n   The DATA argument is passed to the function that calls this one.\n   The MSG argument is an error message.  The ERRNUM argument, if\n   greater than 0, holds an errno value.  The MSG buffer may become\n   invalid after this function returns.\n\n   As a special case, the ERRNUM argument will be passed as -1 if no\n   debug info can be found for the executable, or if the debug info\n   exists but has an unsupported version, but the function requires\n   debug info (e.g., backtrace_full, backtrace_pcinfo).  The MSG in\n   this case will be something along the lines of \"no debug info\".\n   Similarly, ERRNUM will be passed as -1 if there is no symbol table,\n   but the function requires a symbol table (e.g., backtrace_syminfo).\n   This may be used as a signal that some other approach should be\n   tried.  */\n\ntypedef void (*backtrace_error_callback) (void *data, const char *msg,\n\t\t\t\t\t  int errnum);\n\n/* Create state information for the backtrace routines.  This must be\n   called before any of the other routines, and its return value must\n   be passed to all of the other routines.  FILENAME is the path name\n   of the executable file; if it is NULL the library will try\n   system-specific path names.  If not NULL, FILENAME must point to a\n   permanent buffer.  If THREADED is non-zero the state may be\n   accessed by multiple threads simultaneously, and the library will\n   use appropriate atomic operations.  If THREADED is zero the state\n   may only be accessed by one thread at a time.  This returns a state\n   pointer on success, NULL on error.  If an error occurs, this will\n   call the ERROR_CALLBACK routine.\n\n   Calling this function allocates resources that cannot be freed.\n   There is no backtrace_free_state function.  The state is used to\n   cache information that is expensive to recompute.  Programs are\n   expected to call this function at most once and to save the return\n   value for all later calls to backtrace functions.  */\n\nextern struct backtrace_state *backtrace_create_state (\n    const char *filename, int threaded,\n    backtrace_error_callback error_callback, void *data);\n\n/* The type of the callback argument to the backtrace_full function.\n   DATA is the argument passed to backtrace_full.  PC is the program\n   counter.  FILENAME is the name of the file containing PC, or NULL\n   if not available.  LINENO is the line number in FILENAME containing\n   PC, or 0 if not available.  FUNCTION is the name of the function\n   containing PC, or NULL if not available.  This should return 0 to\n   continuing tracing.  The FILENAME and FUNCTION buffers may become\n   invalid after this function returns.  */\n\ntypedef int (*backtrace_full_callback) (void *data, uintptr_t pc, uintptr_t lowaddr,\n\t\t\t\t\tconst char *filename, int lineno,\n\t\t\t\t\tconst char *function);\n\n/* Get a full stack backtrace.  SKIP is the number of frames to skip;\n   passing 0 will start the trace with the function calling\n   backtrace_full.  DATA is passed to the callback routine.  If any\n   call to CALLBACK returns a non-zero value, the stack backtrace\n   stops, and backtrace returns that value; this may be used to limit\n   the number of stack frames desired.  If all calls to CALLBACK\n   return 0, backtrace returns 0.  The backtrace_full function will\n   make at least one call to either CALLBACK or ERROR_CALLBACK.  This\n   function requires debug info for the executable.  */\n\nextern int backtrace_full (struct backtrace_state *state, int skip,\n\t\t\t   backtrace_full_callback callback,\n\t\t\t   backtrace_error_callback error_callback,\n\t\t\t   void *data);\n\n/* The type of the callback argument to the backtrace_simple function.\n   DATA is the argument passed to simple_backtrace.  PC is the program\n   counter.  This should return 0 to continue tracing.  */\n\ntypedef int (*backtrace_simple_callback) (void *data, uintptr_t pc);\n\n/* Get a simple backtrace.  SKIP is the number of frames to skip, as\n   in backtrace.  DATA is passed to the callback routine.  If any call\n   to CALLBACK returns a non-zero value, the stack backtrace stops,\n   and backtrace_simple returns that value.  Otherwise\n   backtrace_simple returns 0.  The backtrace_simple function will\n   make at least one call to either CALLBACK or ERROR_CALLBACK.  This\n   function does not require any debug info for the executable.  */\n\nextern int backtrace_simple (struct backtrace_state *state, int skip,\n\t\t\t     backtrace_simple_callback callback,\n\t\t\t     backtrace_error_callback error_callback,\n\t\t\t     void *data);\n\n/* Print the current backtrace in a user readable format to a FILE.\n   SKIP is the number of frames to skip, as in backtrace_full.  Any\n   error messages are printed to stderr.  This function requires debug\n   info for the executable.  */\n\nextern void backtrace_print (struct backtrace_state *state, int skip, FILE *);\n\n/* Given PC, a program counter in the current program, call the\n   callback function with filename, line number, and function name\n   information.  This will normally call the callback function exactly\n   once.  However, if the PC happens to describe an inlined call, and\n   the debugging information contains the necessary information, then\n   this may call the callback function multiple times.  This will make\n   at least one call to either CALLBACK or ERROR_CALLBACK.  This\n   returns the first non-zero value returned by CALLBACK, or 0.  */\n\nextern int backtrace_pcinfo (struct backtrace_state *state, uintptr_t pc,\n\t\t\t     backtrace_full_callback callback,\n\t\t\t     backtrace_error_callback error_callback,\n\t\t\t     void *data);\n\n/* The type of the callback argument to backtrace_syminfo.  DATA and\n   PC are the arguments passed to backtrace_syminfo.  SYMNAME is the\n   name of the symbol for the corresponding code.  SYMVAL is the\n   value and SYMSIZE is the size of the symbol.  SYMNAME will be NULL\n   if no error occurred but the symbol could not be found.  */\n\ntypedef void (*backtrace_syminfo_callback) (void *data, uintptr_t pc,\n\t\t\t\t\t    const char *symname,\n\t\t\t\t\t    uintptr_t symval,\n\t\t\t\t\t    uintptr_t symsize);\n\n/* Given ADDR, an address or program counter in the current program,\n   call the callback information with the symbol name and value\n   describing the function or variable in which ADDR may be found.\n   This will call either CALLBACK or ERROR_CALLBACK exactly once.\n   This returns 1 on success, 0 on failure.  This function requires\n   the symbol table but does not require the debug info.  Note that if\n   the symbol table is present but ADDR could not be found in the\n   table, CALLBACK will be called with a NULL SYMNAME argument.\n   Returns 1 on success, 0 on error.  */\n\nextern int backtrace_syminfo (struct backtrace_state *state, uintptr_t addr,\n\t\t\t      backtrace_syminfo_callback callback,\n\t\t\t      backtrace_error_callback error_callback,\n\t\t\t      void *data);\n\n}\n\n#endif\n"
  },
  {
    "path": "tracy-client-sys/tracy/libbacktrace/config.h",
    "content": "#include <limits.h>\n#if defined(__linux__) && !defined(__GLIBC__) && !defined(__WORDSIZE)\n// include __WORDSIZE headers for musl\n#  include <bits/reg.h>\n#endif\n#if __WORDSIZE == 64\n#  define BACKTRACE_ELF_SIZE 64\n#else\n#  define BACKTRACE_ELF_SIZE 32\n#endif\n\n#define HAVE_DLFCN_H 1\n#define HAVE_FCNTL 1\n#define HAVE_INTTYPES_H 1\n#define HAVE_LSTAT 1\n#define HAVE_READLINK 1\n#define HAVE_DL_ITERATE_PHDR 1\n#define HAVE_ATOMIC_FUNCTIONS 1\n#define HAVE_DECL_STRNLEN 1\n\n#ifdef __APPLE__\n#  define HAVE_MACH_O_DYLD_H 1\n#elif defined BSD\n#  define HAVE_KERN_PROC 1\n#  define HAVE_KERN_PROC_ARGS 1\n#endif\n"
  },
  {
    "path": "tracy-client-sys/tracy/libbacktrace/dwarf.cpp",
    "content": "/* dwarf.c -- Get file/line information from DWARF for backtraces.\n   Copyright (C) 2012-2021 Free Software Foundation, Inc.\n   Written by Ian Lance Taylor, Google.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n    (1) Redistributions of source code must retain the above copyright\n    notice, this list of conditions and the following disclaimer.\n\n    (2) Redistributions in binary form must reproduce the above copyright\n    notice, this list of conditions and the following disclaimer in\n    the documentation and/or other materials provided with the\n    distribution.\n\n    (3) The name of the author may not be used to\n    endorse or promote products derived from this software without\n    specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\nIMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\nWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,\nINDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\nHOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\nSTRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\nIN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGE.  */\n\n#include \"config.h\"\n\n#include <errno.h>\n#include <stdlib.h>\n#include <string.h>\n#include <sys/types.h>\n\n#include \"filenames.hpp\"\n\n#include \"backtrace.hpp\"\n#include \"internal.hpp\"\n\nnamespace tracy\n{\n\n/* DWARF constants.  */\n\nenum dwarf_tag {\n  DW_TAG_entry_point = 0x3,\n  DW_TAG_compile_unit = 0x11,\n  DW_TAG_inlined_subroutine = 0x1d,\n  DW_TAG_subprogram = 0x2e,\n  DW_TAG_skeleton_unit = 0x4a,\n};\n\nenum dwarf_form {\n  DW_FORM_addr = 0x01,\n  DW_FORM_block2 = 0x03,\n  DW_FORM_block4 = 0x04,\n  DW_FORM_data2 = 0x05,\n  DW_FORM_data4 = 0x06,\n  DW_FORM_data8 = 0x07,\n  DW_FORM_string = 0x08,\n  DW_FORM_block = 0x09,\n  DW_FORM_block1 = 0x0a,\n  DW_FORM_data1 = 0x0b,\n  DW_FORM_flag = 0x0c,\n  DW_FORM_sdata = 0x0d,\n  DW_FORM_strp = 0x0e,\n  DW_FORM_udata = 0x0f,\n  DW_FORM_ref_addr = 0x10,\n  DW_FORM_ref1 = 0x11,\n  DW_FORM_ref2 = 0x12,\n  DW_FORM_ref4 = 0x13,\n  DW_FORM_ref8 = 0x14,\n  DW_FORM_ref_udata = 0x15,\n  DW_FORM_indirect = 0x16,\n  DW_FORM_sec_offset = 0x17,\n  DW_FORM_exprloc = 0x18,\n  DW_FORM_flag_present = 0x19,\n  DW_FORM_ref_sig8 = 0x20,\n  DW_FORM_strx = 0x1a,\n  DW_FORM_addrx = 0x1b,\n  DW_FORM_ref_sup4 = 0x1c,\n  DW_FORM_strp_sup = 0x1d,\n  DW_FORM_data16 = 0x1e,\n  DW_FORM_line_strp = 0x1f,\n  DW_FORM_implicit_const = 0x21,\n  DW_FORM_loclistx = 0x22,\n  DW_FORM_rnglistx = 0x23,\n  DW_FORM_ref_sup8 = 0x24,\n  DW_FORM_strx1 = 0x25,\n  DW_FORM_strx2 = 0x26,\n  DW_FORM_strx3 = 0x27,\n  DW_FORM_strx4 = 0x28,\n  DW_FORM_addrx1 = 0x29,\n  DW_FORM_addrx2 = 0x2a,\n  DW_FORM_addrx3 = 0x2b,\n  DW_FORM_addrx4 = 0x2c,\n  DW_FORM_GNU_addr_index = 0x1f01,\n  DW_FORM_GNU_str_index = 0x1f02,\n  DW_FORM_GNU_ref_alt = 0x1f20,\n  DW_FORM_GNU_strp_alt = 0x1f21\n};\n\nenum dwarf_attribute {\n  DW_AT_sibling = 0x01,\n  DW_AT_location = 0x02,\n  DW_AT_name = 0x03,\n  DW_AT_ordering = 0x09,\n  DW_AT_subscr_data = 0x0a,\n  DW_AT_byte_size = 0x0b,\n  DW_AT_bit_offset = 0x0c,\n  DW_AT_bit_size = 0x0d,\n  DW_AT_element_list = 0x0f,\n  DW_AT_stmt_list = 0x10,\n  DW_AT_low_pc = 0x11,\n  DW_AT_high_pc = 0x12,\n  DW_AT_language = 0x13,\n  DW_AT_member = 0x14,\n  DW_AT_discr = 0x15,\n  DW_AT_discr_value = 0x16,\n  DW_AT_visibility = 0x17,\n  DW_AT_import = 0x18,\n  DW_AT_string_length = 0x19,\n  DW_AT_common_reference = 0x1a,\n  DW_AT_comp_dir = 0x1b,\n  DW_AT_const_value = 0x1c,\n  DW_AT_containing_type = 0x1d,\n  DW_AT_default_value = 0x1e,\n  DW_AT_inline = 0x20,\n  DW_AT_is_optional = 0x21,\n  DW_AT_lower_bound = 0x22,\n  DW_AT_producer = 0x25,\n  DW_AT_prototyped = 0x27,\n  DW_AT_return_addr = 0x2a,\n  DW_AT_start_scope = 0x2c,\n  DW_AT_bit_stride = 0x2e,\n  DW_AT_upper_bound = 0x2f,\n  DW_AT_abstract_origin = 0x31,\n  DW_AT_accessibility = 0x32,\n  DW_AT_address_class = 0x33,\n  DW_AT_artificial = 0x34,\n  DW_AT_base_types = 0x35,\n  DW_AT_calling_convention = 0x36,\n  DW_AT_count = 0x37,\n  DW_AT_data_member_location = 0x38,\n  DW_AT_decl_column = 0x39,\n  DW_AT_decl_file = 0x3a,\n  DW_AT_decl_line = 0x3b,\n  DW_AT_declaration = 0x3c,\n  DW_AT_discr_list = 0x3d,\n  DW_AT_encoding = 0x3e,\n  DW_AT_external = 0x3f,\n  DW_AT_frame_base = 0x40,\n  DW_AT_friend = 0x41,\n  DW_AT_identifier_case = 0x42,\n  DW_AT_macro_info = 0x43,\n  DW_AT_namelist_items = 0x44,\n  DW_AT_priority = 0x45,\n  DW_AT_segment = 0x46,\n  DW_AT_specification = 0x47,\n  DW_AT_static_link = 0x48,\n  DW_AT_type = 0x49,\n  DW_AT_use_location = 0x4a,\n  DW_AT_variable_parameter = 0x4b,\n  DW_AT_virtuality = 0x4c,\n  DW_AT_vtable_elem_location = 0x4d,\n  DW_AT_allocated = 0x4e,\n  DW_AT_associated = 0x4f,\n  DW_AT_data_location = 0x50,\n  DW_AT_byte_stride = 0x51,\n  DW_AT_entry_pc = 0x52,\n  DW_AT_use_UTF8 = 0x53,\n  DW_AT_extension = 0x54,\n  DW_AT_ranges = 0x55,\n  DW_AT_trampoline = 0x56,\n  DW_AT_call_column = 0x57,\n  DW_AT_call_file = 0x58,\n  DW_AT_call_line = 0x59,\n  DW_AT_description = 0x5a,\n  DW_AT_binary_scale = 0x5b,\n  DW_AT_decimal_scale = 0x5c,\n  DW_AT_small = 0x5d,\n  DW_AT_decimal_sign = 0x5e,\n  DW_AT_digit_count = 0x5f,\n  DW_AT_picture_string = 0x60,\n  DW_AT_mutable = 0x61,\n  DW_AT_threads_scaled = 0x62,\n  DW_AT_explicit = 0x63,\n  DW_AT_object_pointer = 0x64,\n  DW_AT_endianity = 0x65,\n  DW_AT_elemental = 0x66,\n  DW_AT_pure = 0x67,\n  DW_AT_recursive = 0x68,\n  DW_AT_signature = 0x69,\n  DW_AT_main_subprogram = 0x6a,\n  DW_AT_data_bit_offset = 0x6b,\n  DW_AT_const_expr = 0x6c,\n  DW_AT_enum_class = 0x6d,\n  DW_AT_linkage_name = 0x6e,\n  DW_AT_string_length_bit_size = 0x6f,\n  DW_AT_string_length_byte_size = 0x70,\n  DW_AT_rank = 0x71,\n  DW_AT_str_offsets_base = 0x72,\n  DW_AT_addr_base = 0x73,\n  DW_AT_rnglists_base = 0x74,\n  DW_AT_dwo_name = 0x76,\n  DW_AT_reference = 0x77,\n  DW_AT_rvalue_reference = 0x78,\n  DW_AT_macros = 0x79,\n  DW_AT_call_all_calls = 0x7a,\n  DW_AT_call_all_source_calls = 0x7b,\n  DW_AT_call_all_tail_calls = 0x7c,\n  DW_AT_call_return_pc = 0x7d,\n  DW_AT_call_value = 0x7e,\n  DW_AT_call_origin = 0x7f,\n  DW_AT_call_parameter = 0x80,\n  DW_AT_call_pc = 0x81,\n  DW_AT_call_tail_call = 0x82,\n  DW_AT_call_target = 0x83,\n  DW_AT_call_target_clobbered = 0x84,\n  DW_AT_call_data_location = 0x85,\n  DW_AT_call_data_value = 0x86,\n  DW_AT_noreturn = 0x87,\n  DW_AT_alignment = 0x88,\n  DW_AT_export_symbols = 0x89,\n  DW_AT_deleted = 0x8a,\n  DW_AT_defaulted = 0x8b,\n  DW_AT_loclists_base = 0x8c,\n  DW_AT_lo_user = 0x2000,\n  DW_AT_hi_user = 0x3fff,\n  DW_AT_MIPS_fde = 0x2001,\n  DW_AT_MIPS_loop_begin = 0x2002,\n  DW_AT_MIPS_tail_loop_begin = 0x2003,\n  DW_AT_MIPS_epilog_begin = 0x2004,\n  DW_AT_MIPS_loop_unroll_factor = 0x2005,\n  DW_AT_MIPS_software_pipeline_depth = 0x2006,\n  DW_AT_MIPS_linkage_name = 0x2007,\n  DW_AT_MIPS_stride = 0x2008,\n  DW_AT_MIPS_abstract_name = 0x2009,\n  DW_AT_MIPS_clone_origin = 0x200a,\n  DW_AT_MIPS_has_inlines = 0x200b,\n  DW_AT_HP_block_index = 0x2000,\n  DW_AT_HP_unmodifiable = 0x2001,\n  DW_AT_HP_prologue = 0x2005,\n  DW_AT_HP_epilogue = 0x2008,\n  DW_AT_HP_actuals_stmt_list = 0x2010,\n  DW_AT_HP_proc_per_section = 0x2011,\n  DW_AT_HP_raw_data_ptr = 0x2012,\n  DW_AT_HP_pass_by_reference = 0x2013,\n  DW_AT_HP_opt_level = 0x2014,\n  DW_AT_HP_prof_version_id = 0x2015,\n  DW_AT_HP_opt_flags = 0x2016,\n  DW_AT_HP_cold_region_low_pc = 0x2017,\n  DW_AT_HP_cold_region_high_pc = 0x2018,\n  DW_AT_HP_all_variables_modifiable = 0x2019,\n  DW_AT_HP_linkage_name = 0x201a,\n  DW_AT_HP_prof_flags = 0x201b,\n  DW_AT_HP_unit_name = 0x201f,\n  DW_AT_HP_unit_size = 0x2020,\n  DW_AT_HP_widened_byte_size = 0x2021,\n  DW_AT_HP_definition_points = 0x2022,\n  DW_AT_HP_default_location = 0x2023,\n  DW_AT_HP_is_result_param = 0x2029,\n  DW_AT_sf_names = 0x2101,\n  DW_AT_src_info = 0x2102,\n  DW_AT_mac_info = 0x2103,\n  DW_AT_src_coords = 0x2104,\n  DW_AT_body_begin = 0x2105,\n  DW_AT_body_end = 0x2106,\n  DW_AT_GNU_vector = 0x2107,\n  DW_AT_GNU_guarded_by = 0x2108,\n  DW_AT_GNU_pt_guarded_by = 0x2109,\n  DW_AT_GNU_guarded = 0x210a,\n  DW_AT_GNU_pt_guarded = 0x210b,\n  DW_AT_GNU_locks_excluded = 0x210c,\n  DW_AT_GNU_exclusive_locks_required = 0x210d,\n  DW_AT_GNU_shared_locks_required = 0x210e,\n  DW_AT_GNU_odr_signature = 0x210f,\n  DW_AT_GNU_template_name = 0x2110,\n  DW_AT_GNU_call_site_value = 0x2111,\n  DW_AT_GNU_call_site_data_value = 0x2112,\n  DW_AT_GNU_call_site_target = 0x2113,\n  DW_AT_GNU_call_site_target_clobbered = 0x2114,\n  DW_AT_GNU_tail_call = 0x2115,\n  DW_AT_GNU_all_tail_call_sites = 0x2116,\n  DW_AT_GNU_all_call_sites = 0x2117,\n  DW_AT_GNU_all_source_call_sites = 0x2118,\n  DW_AT_GNU_macros = 0x2119,\n  DW_AT_GNU_deleted = 0x211a,\n  DW_AT_GNU_dwo_name = 0x2130,\n  DW_AT_GNU_dwo_id = 0x2131,\n  DW_AT_GNU_ranges_base = 0x2132,\n  DW_AT_GNU_addr_base = 0x2133,\n  DW_AT_GNU_pubnames = 0x2134,\n  DW_AT_GNU_pubtypes = 0x2135,\n  DW_AT_GNU_discriminator = 0x2136,\n  DW_AT_GNU_locviews = 0x2137,\n  DW_AT_GNU_entry_view = 0x2138,\n  DW_AT_VMS_rtnbeg_pd_address = 0x2201,\n  DW_AT_use_GNAT_descriptive_type = 0x2301,\n  DW_AT_GNAT_descriptive_type = 0x2302,\n  DW_AT_GNU_numerator = 0x2303,\n  DW_AT_GNU_denominator = 0x2304,\n  DW_AT_GNU_bias = 0x2305,\n  DW_AT_upc_threads_scaled = 0x3210,\n  DW_AT_PGI_lbase = 0x3a00,\n  DW_AT_PGI_soffset = 0x3a01,\n  DW_AT_PGI_lstride = 0x3a02,\n  DW_AT_APPLE_optimized = 0x3fe1,\n  DW_AT_APPLE_flags = 0x3fe2,\n  DW_AT_APPLE_isa = 0x3fe3,\n  DW_AT_APPLE_block = 0x3fe4,\n  DW_AT_APPLE_major_runtime_vers = 0x3fe5,\n  DW_AT_APPLE_runtime_class = 0x3fe6,\n  DW_AT_APPLE_omit_frame_ptr = 0x3fe7,\n  DW_AT_APPLE_property_name = 0x3fe8,\n  DW_AT_APPLE_property_getter = 0x3fe9,\n  DW_AT_APPLE_property_setter = 0x3fea,\n  DW_AT_APPLE_property_attribute = 0x3feb,\n  DW_AT_APPLE_objc_complete_type = 0x3fec,\n  DW_AT_APPLE_property = 0x3fed\n};\n\nenum dwarf_line_number_op {\n  DW_LNS_extended_op = 0x0,\n  DW_LNS_copy = 0x1,\n  DW_LNS_advance_pc = 0x2,\n  DW_LNS_advance_line = 0x3,\n  DW_LNS_set_file = 0x4,\n  DW_LNS_set_column = 0x5,\n  DW_LNS_negate_stmt = 0x6,\n  DW_LNS_set_basic_block = 0x7,\n  DW_LNS_const_add_pc = 0x8,\n  DW_LNS_fixed_advance_pc = 0x9,\n  DW_LNS_set_prologue_end = 0xa,\n  DW_LNS_set_epilogue_begin = 0xb,\n  DW_LNS_set_isa = 0xc,\n};\n\nenum dwarf_extended_line_number_op {\n  DW_LNE_end_sequence = 0x1,\n  DW_LNE_set_address = 0x2,\n  DW_LNE_define_file = 0x3,\n  DW_LNE_set_discriminator = 0x4,\n};\n\nenum dwarf_line_number_content_type {\n  DW_LNCT_path = 0x1,\n  DW_LNCT_directory_index = 0x2,\n  DW_LNCT_timestamp = 0x3,\n  DW_LNCT_size = 0x4,\n  DW_LNCT_MD5 = 0x5,\n  DW_LNCT_lo_user = 0x2000,\n  DW_LNCT_hi_user = 0x3fff\n};\n\nenum dwarf_range_list_entry {\n  DW_RLE_end_of_list = 0x00,\n  DW_RLE_base_addressx = 0x01,\n  DW_RLE_startx_endx = 0x02,\n  DW_RLE_startx_length = 0x03,\n  DW_RLE_offset_pair = 0x04,\n  DW_RLE_base_address = 0x05,\n  DW_RLE_start_end = 0x06,\n  DW_RLE_start_length = 0x07\n};\n\nenum dwarf_unit_type {\n  DW_UT_compile = 0x01,\n  DW_UT_type = 0x02,\n  DW_UT_partial = 0x03,\n  DW_UT_skeleton = 0x04,\n  DW_UT_split_compile = 0x05,\n  DW_UT_split_type = 0x06,\n  DW_UT_lo_user = 0x80,\n  DW_UT_hi_user = 0xff\n};\n\n#if !defined(HAVE_DECL_STRNLEN) || !HAVE_DECL_STRNLEN\n\n/* If strnlen is not declared, provide our own version.  */\n\nstatic size_t\nxstrnlen (const char *s, size_t maxlen)\n{\n  size_t i;\n\n  for (i = 0; i < maxlen; ++i)\n    if (s[i] == '\\0')\n      break;\n  return i;\n}\n\n#define strnlen xstrnlen\n\n#endif\n\n/* A buffer to read DWARF info.  */\n\nstruct dwarf_buf\n{\n  /* Buffer name for error messages.  */\n  const char *name;\n  /* Start of the buffer.  */\n  const unsigned char *start;\n  /* Next byte to read.  */\n  const unsigned char *buf;\n  /* The number of bytes remaining.  */\n  size_t left;\n  /* Whether the data is big-endian.  */\n  int is_bigendian;\n  /* Error callback routine.  */\n  backtrace_error_callback error_callback;\n  /* Data for error_callback.  */\n  void *data;\n  /* Non-zero if we've reported an underflow error.  */\n  int reported_underflow;\n};\n\n/* A single attribute in a DWARF abbreviation.  */\n\nstruct attr\n{\n  /* The attribute name.  */\n  enum dwarf_attribute name;\n  /* The attribute form.  */\n  enum dwarf_form form;\n  /* The attribute value, for DW_FORM_implicit_const.  */\n  int64_t val;\n};\n\n/* A single DWARF abbreviation.  */\n\nstruct abbrev\n{\n  /* The abbrev code--the number used to refer to the abbrev.  */\n  uint64_t code;\n  /* The entry tag.  */\n  enum dwarf_tag tag;\n  /* Non-zero if this abbrev has child entries.  */\n  int has_children;\n  /* The number of attributes.  */\n  size_t num_attrs;\n  /* The attributes.  */\n  struct attr *attrs;\n};\n\n/* The DWARF abbreviations for a compilation unit.  This structure\n   only exists while reading the compilation unit.  Most DWARF readers\n   seem to a hash table to map abbrev ID's to abbrev entries.\n   However, we primarily care about GCC, and GCC simply issues ID's in\n   numerical order starting at 1.  So we simply keep a sorted vector,\n   and try to just look up the code.  */\n\nstruct abbrevs\n{\n  /* The number of abbrevs in the vector.  */\n  size_t num_abbrevs;\n  /* The abbrevs, sorted by the code field.  */\n  struct abbrev *abbrevs;\n};\n\n/* The different kinds of attribute values.  */\n\nenum attr_val_encoding\n{\n  /* No attribute value.  */\n  ATTR_VAL_NONE,\n  /* An address.  */\n  ATTR_VAL_ADDRESS,\n  /* An index into the .debug_addr section, whose value is relative to\n     the DW_AT_addr_base attribute of the compilation unit.  */\n  ATTR_VAL_ADDRESS_INDEX,\n  /* A unsigned integer.  */\n  ATTR_VAL_UINT,\n  /* A sigd integer.  */\n  ATTR_VAL_SINT,\n  /* A string.  */\n  ATTR_VAL_STRING,\n  /* An index into the .debug_str_offsets section.  */\n  ATTR_VAL_STRING_INDEX,\n  /* An offset to other data in the containing unit.  */\n  ATTR_VAL_REF_UNIT,\n  /* An offset to other data within the .debug_info section.  */\n  ATTR_VAL_REF_INFO,\n  /* An offset to other data within the alt .debug_info section.  */\n  ATTR_VAL_REF_ALT_INFO,\n  /* An offset to data in some other section.  */\n  ATTR_VAL_REF_SECTION,\n  /* A type signature.  */\n  ATTR_VAL_REF_TYPE,\n  /* An index into the .debug_rnglists section.  */\n  ATTR_VAL_RNGLISTS_INDEX,\n  /* A block of data (not represented).  */\n  ATTR_VAL_BLOCK,\n  /* An expression (not represented).  */\n  ATTR_VAL_EXPR,\n};\n\n/* An attribute value.  */\n\nstruct attr_val\n{\n  /* How the value is stored in the field u.  */\n  enum attr_val_encoding encoding;\n  union\n  {\n    /* ATTR_VAL_ADDRESS*, ATTR_VAL_UINT, ATTR_VAL_REF*.  */\n    uint64_t uint;\n    /* ATTR_VAL_SINT.  */\n    int64_t sint;\n    /* ATTR_VAL_STRING.  */\n    const char *string;\n    /* ATTR_VAL_BLOCK not stored.  */\n  } u;\n};\n\n/* The line number program header.  */\n\nstruct line_header\n{\n  /* The version of the line number information.  */\n  int version;\n  /* Address size.  */\n  int addrsize;\n  /* The minimum instruction length.  */\n  unsigned int min_insn_len;\n  /* The maximum number of ops per instruction.  */\n  unsigned int max_ops_per_insn;\n  /* The line base for special opcodes.  */\n  int line_base;\n  /* The line range for special opcodes.  */\n  unsigned int line_range;\n  /* The opcode base--the first special opcode.  */\n  unsigned int opcode_base;\n  /* Opcode lengths, indexed by opcode - 1.  */\n  const unsigned char *opcode_lengths;\n  /* The number of directory entries.  */\n  size_t dirs_count;\n  /* The directory entries.  */\n  const char **dirs;\n  /* The number of filenames.  */\n  size_t filenames_count;\n  /* The filenames.  */\n  const char **filenames;\n};\n\n/* A format description from a line header.  */\n\nstruct line_header_format\n{\n  int lnct;\t\t/* LNCT code.  */\n  enum dwarf_form form;\t/* Form of entry data.  */\n};\n\n/* Map a single PC value to a file/line.  We will keep a vector of\n   these sorted by PC value.  Each file/line will be correct from the\n   PC up to the PC of the next entry if there is one.  We allocate one\n   extra entry at the end so that we can use bsearch.  */\n\nstruct line\n{\n  /* PC.  */\n  uintptr_t pc;\n  /* File name.  Many entries in the array are expected to point to\n     the same file name.  */\n  const char *filename;\n  /* Line number.  */\n  int lineno;\n  /* Index of the object in the original array read from the DWARF\n     section, before it has been sorted.  The index makes it possible\n     to use Quicksort and maintain stability.  */\n  int idx;\n};\n\n/* A growable vector of line number information.  This is used while\n   reading the line numbers.  */\n\nstruct line_vector\n{\n  /* Memory.  This is an array of struct line.  */\n  struct backtrace_vector vec;\n  /* Number of valid mappings.  */\n  size_t count;\n};\n\n/* A function described in the debug info.  */\n\nstruct function\n{\n  /* The name of the function.  */\n  const char *name;\n  /* If this is an inlined function, the filename of the call\n     site.  */\n  const char *caller_filename;\n  /* If this is an inlined function, the line number of the call\n     site.  */\n  int caller_lineno;\n  /* Map PC ranges to inlined functions.  */\n  struct function_addrs *function_addrs;\n  size_t function_addrs_count;\n};\n\n/* An address range for a function.  This maps a PC value to a\n   specific function.  */\n\nstruct function_addrs\n{\n  /* Range is LOW <= PC < HIGH.  */\n  uintptr_t low;\n  uintptr_t high;\n  /* Function for this address range.  */\n  struct function *function;\n};\n\n/* A growable vector of function address ranges.  */\n\nstruct function_vector\n{\n  /* Memory.  This is an array of struct function_addrs.  */\n  struct backtrace_vector vec;\n  /* Number of address ranges present.  */\n  size_t count;\n};\n\n/* A DWARF compilation unit.  This only holds the information we need\n   to map a PC to a file and line.  */\n\nstruct unit\n{\n  /* The first entry for this compilation unit.  */\n  const unsigned char *unit_data;\n  /* The length of the data for this compilation unit.  */\n  size_t unit_data_len;\n  /* The offset of UNIT_DATA from the start of the information for\n     this compilation unit.  */\n  size_t unit_data_offset;\n  /* Offset of the start of the compilation unit from the start of the\n     .debug_info section.  */\n  size_t low_offset;\n  /* Offset of the end of the compilation unit from the start of the\n     .debug_info section.  */\n  size_t high_offset;\n  /* DWARF version.  */\n  int version;\n  /* Whether unit is DWARF64.  */\n  int is_dwarf64;\n  /* Address size.  */\n  int addrsize;\n  /* Offset into line number information.  */\n  off_t lineoff;\n  /* Offset of compilation unit in .debug_str_offsets.  */\n  uint64_t str_offsets_base;\n  /* Offset of compilation unit in .debug_addr.  */\n  uint64_t addr_base;\n  /* Offset of compilation unit in .debug_rnglists.  */\n  uint64_t rnglists_base;\n  /* Primary source file.  */\n  const char *filename;\n  /* Compilation command working directory.  */\n  const char *comp_dir;\n  /* Absolute file name, only set if needed.  */\n  const char *abs_filename;\n  /* The abbreviations for this unit.  */\n  struct abbrevs abbrevs;\n\n  /* The fields above this point are read in during initialization and\n     may be accessed freely.  The fields below this point are read in\n     as needed, and therefore require care, as different threads may\n     try to initialize them simultaneously.  */\n\n  /* PC to line number mapping.  This is NULL if the values have not\n     been read.  This is (struct line *) -1 if there was an error\n     reading the values.  */\n  struct line *lines;\n  /* Number of entries in lines.  */\n  size_t lines_count;\n  /* PC ranges to function.  */\n  struct function_addrs *function_addrs;\n  size_t function_addrs_count;\n};\n\n/* An address range for a compilation unit.  This maps a PC value to a\n   specific compilation unit.  Note that we invert the representation\n   in DWARF: instead of listing the units and attaching a list of\n   ranges, we list the ranges and have each one point to the unit.\n   This lets us do a binary search to find the unit.  */\n\nstruct unit_addrs\n{\n  /* Range is LOW <= PC < HIGH.  */\n  uintptr_t low;\n  uintptr_t high;\n  /* Compilation unit for this address range.  */\n  struct unit *u;\n};\n\n/* A growable vector of compilation unit address ranges.  */\n\nstruct unit_addrs_vector\n{\n  /* Memory.  This is an array of struct unit_addrs.  */\n  struct backtrace_vector vec;\n  /* Number of address ranges present.  */\n  size_t count;\n};\n\n/* A growable vector of compilation unit pointer.  */\n\nstruct unit_vector\n{\n  struct backtrace_vector vec;\n  size_t count;\n};\n\n/* The information we need to map a PC to a file and line.  */\n\nstruct dwarf_data\n{\n  /* The data for the next file we know about.  */\n  struct dwarf_data *next;\n  /* The data for .gnu_debugaltlink.  */\n  struct dwarf_data *altlink;\n/* The base address mapping for this file.  */\n  struct libbacktrace_base_address base_address;\n  /* A sorted list of address ranges.  */\n  struct unit_addrs *addrs;\n  /* Number of address ranges in list.  */\n  size_t addrs_count;\n  /* A sorted list of units.  */\n  struct unit **units;\n  /* Number of units in the list.  */\n  size_t units_count;\n  /* The unparsed DWARF debug data.  */\n  struct dwarf_sections dwarf_sections;\n  /* Whether the data is big-endian or not.  */\n  int is_bigendian;\n  /* A vector used for function addresses.  We keep this here so that\n     we can grow the vector as we read more functions.  */\n  struct function_vector fvec;\n};\n\n/* Report an error for a DWARF buffer.  */\n\nstatic void\ndwarf_buf_error (struct dwarf_buf *buf, const char *msg, int errnum)\n{\n  char b[200];\n\n  snprintf (b, sizeof b, \"%s in %s at %d\",\n\t    msg, buf->name, (int) (buf->buf - buf->start));\n  buf->error_callback (buf->data, b, errnum);\n}\n\n/* Require at least COUNT bytes in BUF.  Return 1 if all is well, 0 on\n   error.  */\n\nstatic int\nrequire (struct dwarf_buf *buf, size_t count)\n{\n  if (buf->left >= count)\n    return 1;\n\n  if (!buf->reported_underflow)\n    {\n      dwarf_buf_error (buf, \"DWARF underflow\", 0);\n      buf->reported_underflow = 1;\n    }\n\n  return 0;\n}\n\n/* Advance COUNT bytes in BUF.  Return 1 if all is well, 0 on\n   error.  */\n\nstatic int\nadvance (struct dwarf_buf *buf, size_t count)\n{\n  if (!require (buf, count))\n    return 0;\n  buf->buf += count;\n  buf->left -= count;\n  return 1;\n}\n\n/* Read one zero-terminated string from BUF and advance past the string.  */\n\nstatic const char *\nread_string (struct dwarf_buf *buf)\n{\n  const char *p = (const char *)buf->buf;\n  size_t len = strnlen (p, buf->left);\n\n  /* - If len == left, we ran out of buffer before finding the zero terminator.\n       Generate an error by advancing len + 1.\n     - If len < left, advance by len + 1 to skip past the zero terminator.  */\n  size_t count = len + 1;\n\n  if (!advance (buf, count))\n    return NULL;\n\n  return p;\n}\n\n/* Read one byte from BUF and advance 1 byte.  */\n\nstatic unsigned char\nread_byte (struct dwarf_buf *buf)\n{\n  const unsigned char *p = buf->buf;\n\n  if (!advance (buf, 1))\n    return 0;\n  return p[0];\n}\n\n/* Read a signed char from BUF and advance 1 byte.  */\n\nstatic signed char\nread_sbyte (struct dwarf_buf *buf)\n{\n  const unsigned char *p = buf->buf;\n\n  if (!advance (buf, 1))\n    return 0;\n  return (*p ^ 0x80) - 0x80;\n}\n\n/* Read a uint16 from BUF and advance 2 bytes.  */\n\nstatic uint16_t\nread_uint16 (struct dwarf_buf *buf)\n{\n  const unsigned char *p = buf->buf;\n\n  if (!advance (buf, 2))\n    return 0;\n  if (buf->is_bigendian)\n    return ((uint16_t) p[0] << 8) | (uint16_t) p[1];\n  else\n    return ((uint16_t) p[1] << 8) | (uint16_t) p[0];\n}\n\n/* Read a 24 bit value from BUF and advance 3 bytes.  */\n\nstatic uint32_t\nread_uint24 (struct dwarf_buf *buf)\n{\n  const unsigned char *p = buf->buf;\n\n  if (!advance (buf, 3))\n    return 0;\n  if (buf->is_bigendian)\n    return (((uint32_t) p[0] << 16) | ((uint32_t) p[1] << 8)\n\t    | (uint32_t) p[2]);\n  else\n    return (((uint32_t) p[2] << 16) | ((uint32_t) p[1] << 8)\n\t    | (uint32_t) p[0]);\n}\n\n/* Read a uint32 from BUF and advance 4 bytes.  */\n\nstatic uint32_t\nread_uint32 (struct dwarf_buf *buf)\n{\n  const unsigned char *p = buf->buf;\n\n  if (!advance (buf, 4))\n    return 0;\n  if (buf->is_bigendian)\n    return (((uint32_t) p[0] << 24) | ((uint32_t) p[1] << 16)\n\t    | ((uint32_t) p[2] << 8) | (uint32_t) p[3]);\n  else\n    return (((uint32_t) p[3] << 24) | ((uint32_t) p[2] << 16)\n\t    | ((uint32_t) p[1] << 8) | (uint32_t) p[0]);\n}\n\n/* Read a uint64 from BUF and advance 8 bytes.  */\n\nstatic uint64_t\nread_uint64 (struct dwarf_buf *buf)\n{\n  const unsigned char *p = buf->buf;\n\n  if (!advance (buf, 8))\n    return 0;\n  if (buf->is_bigendian)\n    return (((uint64_t) p[0] << 56) | ((uint64_t) p[1] << 48)\n\t    | ((uint64_t) p[2] << 40) | ((uint64_t) p[3] << 32)\n\t    | ((uint64_t) p[4] << 24) | ((uint64_t) p[5] << 16)\n\t    | ((uint64_t) p[6] << 8) | (uint64_t) p[7]);\n  else\n    return (((uint64_t) p[7] << 56) | ((uint64_t) p[6] << 48)\n\t    | ((uint64_t) p[5] << 40) | ((uint64_t) p[4] << 32)\n\t    | ((uint64_t) p[3] << 24) | ((uint64_t) p[2] << 16)\n\t    | ((uint64_t) p[1] << 8) | (uint64_t) p[0]);\n}\n\n/* Read an offset from BUF and advance the appropriate number of\n   bytes.  */\n\nstatic uint64_t\nread_offset (struct dwarf_buf *buf, int is_dwarf64)\n{\n  if (is_dwarf64)\n    return read_uint64 (buf);\n  else\n    return read_uint32 (buf);\n}\n\n/* Read an address from BUF and advance the appropriate number of\n   bytes.  */\n\nstatic uint64_t\nread_address (struct dwarf_buf *buf, int addrsize)\n{\n  switch (addrsize)\n    {\n    case 1:\n      return read_byte (buf);\n    case 2:\n      return read_uint16 (buf);\n    case 4:\n      return read_uint32 (buf);\n    case 8:\n      return read_uint64 (buf);\n    default:\n      dwarf_buf_error (buf, \"unrecognized address size\", 0);\n      return 0;\n    }\n}\n\n/* Return whether a value is the highest possible address, given the\n   address size.  */\n\nstatic int\nis_highest_address (uint64_t address, int addrsize)\n{\n  switch (addrsize)\n    {\n    case 1:\n      return address == (unsigned char) -1;\n    case 2:\n      return address == (uint16_t) -1;\n    case 4:\n      return address == (uint32_t) -1;\n    case 8:\n      return address == (uint64_t) -1;\n    default:\n      return 0;\n    }\n}\n\n/* Read an unsigned LEB128 number.  */\n\nstatic uint64_t\nread_uleb128 (struct dwarf_buf *buf)\n{\n  uint64_t ret;\n  unsigned int shift;\n  int overflow;\n  unsigned char b;\n\n  ret = 0;\n  shift = 0;\n  overflow = 0;\n  do\n    {\n      const unsigned char *p;\n\n      p = buf->buf;\n      if (!advance (buf, 1))\n\treturn 0;\n      b = *p;\n      if (shift < 64)\n\tret |= ((uint64_t) (b & 0x7f)) << shift;\n      else if (!overflow)\n\t{\n\t  dwarf_buf_error (buf, \"LEB128 overflows uint64_t\", 0);\n\t  overflow = 1;\n\t}\n      shift += 7;\n    }\n  while ((b & 0x80) != 0);\n\n  return ret;\n}\n\n/* Read a signed LEB128 number.  */\n\nstatic int64_t\nread_sleb128 (struct dwarf_buf *buf)\n{\n  uint64_t val;\n  unsigned int shift;\n  int overflow;\n  unsigned char b;\n\n  val = 0;\n  shift = 0;\n  overflow = 0;\n  do\n    {\n      const unsigned char *p;\n\n      p = buf->buf;\n      if (!advance (buf, 1))\n\treturn 0;\n      b = *p;\n      if (shift < 64)\n\tval |= ((uint64_t) (b & 0x7f)) << shift;\n      else if (!overflow)\n\t{\n\t  dwarf_buf_error (buf, \"signed LEB128 overflows uint64_t\", 0);\n\t  overflow = 1;\n\t}\n      shift += 7;\n    }\n  while ((b & 0x80) != 0);\n\n  if ((b & 0x40) != 0 && shift < 64)\n    val |= ((uint64_t) -1) << shift;\n\n  return (int64_t) val;\n}\n\n/* Return the length of an LEB128 number.  */\n\nstatic size_t\nleb128_len (const unsigned char *p)\n{\n  size_t ret;\n\n  ret = 1;\n  while ((*p & 0x80) != 0)\n    {\n      ++p;\n      ++ret;\n    }\n  return ret;\n}\n\n/* Read initial_length from BUF and advance the appropriate number of bytes.  */\n\nstatic uint64_t\nread_initial_length (struct dwarf_buf *buf, int *is_dwarf64)\n{\n  uint64_t len;\n\n  len = read_uint32 (buf);\n  if (len == 0xffffffff)\n    {\n      len = read_uint64 (buf);\n      *is_dwarf64 = 1;\n    }\n  else\n    *is_dwarf64 = 0;\n\n  return len;\n}\n\n/* Free an abbreviations structure.  */\n\nstatic void\nfree_abbrevs (struct backtrace_state *state, struct abbrevs *abbrevs,\n\t      backtrace_error_callback error_callback, void *data)\n{\n  size_t i;\n\n  for (i = 0; i < abbrevs->num_abbrevs; ++i)\n    backtrace_free (state, abbrevs->abbrevs[i].attrs,\n\t\t    abbrevs->abbrevs[i].num_attrs * sizeof (struct attr),\n\t\t    error_callback, data);\n  backtrace_free (state, abbrevs->abbrevs,\n\t\t  abbrevs->num_abbrevs * sizeof (struct abbrev),\n\t\t  error_callback, data);\n  abbrevs->num_abbrevs = 0;\n  abbrevs->abbrevs = NULL;\n}\n\n/* Read an attribute value.  Returns 1 on success, 0 on failure.  If\n   the value can be represented as a uint64_t, sets *VAL and sets\n   *IS_VALID to 1.  We don't try to store the value of other attribute\n   forms, because we don't care about them.  */\n\nstatic int\nread_attribute (enum dwarf_form form, uint64_t implicit_val,\n\t\tstruct dwarf_buf *buf, int is_dwarf64, int version,\n\t\tint addrsize, const struct dwarf_sections *dwarf_sections,\n\t\tstruct dwarf_data *altlink, struct attr_val *val)\n{\n  /* Avoid warnings about val.u.FIELD may be used uninitialized if\n     this function is inlined.  The warnings aren't valid but can\n     occur because the different fields are set and used\n     conditionally.  */\n  memset (val, 0, sizeof *val);\n\n  switch (form)\n    {\n    case DW_FORM_addr:\n      val->encoding = ATTR_VAL_ADDRESS;\n      val->u.uint = read_address (buf, addrsize);\n      return 1;\n    case DW_FORM_block2:\n      val->encoding = ATTR_VAL_BLOCK;\n      return advance (buf, read_uint16 (buf));\n    case DW_FORM_block4:\n      val->encoding = ATTR_VAL_BLOCK;\n      return advance (buf, read_uint32 (buf));\n    case DW_FORM_data2:\n      val->encoding = ATTR_VAL_UINT;\n      val->u.uint = read_uint16 (buf);\n      return 1;\n    case DW_FORM_data4:\n      val->encoding = ATTR_VAL_UINT;\n      val->u.uint = read_uint32 (buf);\n      return 1;\n    case DW_FORM_data8:\n      val->encoding = ATTR_VAL_UINT;\n      val->u.uint = read_uint64 (buf);\n      return 1;\n    case DW_FORM_data16:\n      val->encoding = ATTR_VAL_BLOCK;\n      return advance (buf, 16);\n    case DW_FORM_string:\n      val->encoding = ATTR_VAL_STRING;\n      val->u.string = read_string (buf);\n      return val->u.string == NULL ? 0 : 1;\n    case DW_FORM_block:\n      val->encoding = ATTR_VAL_BLOCK;\n      return advance (buf, read_uleb128 (buf));\n    case DW_FORM_block1:\n      val->encoding = ATTR_VAL_BLOCK;\n      return advance (buf, read_byte (buf));\n    case DW_FORM_data1:\n      val->encoding = ATTR_VAL_UINT;\n      val->u.uint = read_byte (buf);\n      return 1;\n    case DW_FORM_flag:\n      val->encoding = ATTR_VAL_UINT;\n      val->u.uint = read_byte (buf);\n      return 1;\n    case DW_FORM_sdata:\n      val->encoding = ATTR_VAL_SINT;\n      val->u.sint = read_sleb128 (buf);\n      return 1;\n    case DW_FORM_strp:\n      {\n\tuint64_t offset;\n\n\toffset = read_offset (buf, is_dwarf64);\n\tif (offset >= dwarf_sections->size[DEBUG_STR])\n\t  {\n\t    dwarf_buf_error (buf, \"DW_FORM_strp out of range\", 0);\n\t    return 0;\n\t  }\n\tval->encoding = ATTR_VAL_STRING;\n\tval->u.string =\n\t  (const char *) dwarf_sections->data[DEBUG_STR] + offset;\n\treturn 1;\n      }\n    case DW_FORM_line_strp:\n      {\n\tuint64_t offset;\n\n\toffset = read_offset (buf, is_dwarf64);\n\tif (offset >= dwarf_sections->size[DEBUG_LINE_STR])\n\t  {\n\t    dwarf_buf_error (buf, \"DW_FORM_line_strp out of range\", 0);\n\t    return 0;\n\t  }\n\tval->encoding = ATTR_VAL_STRING;\n\tval->u.string =\n\t  (const char *) dwarf_sections->data[DEBUG_LINE_STR] + offset;\n\treturn 1;\n      }\n    case DW_FORM_udata:\n      val->encoding = ATTR_VAL_UINT;\n      val->u.uint = read_uleb128 (buf);\n      return 1;\n    case DW_FORM_ref_addr:\n      val->encoding = ATTR_VAL_REF_INFO;\n      if (version == 2)\n\tval->u.uint = read_address (buf, addrsize);\n      else\n\tval->u.uint = read_offset (buf, is_dwarf64);\n      return 1;\n    case DW_FORM_ref1:\n      val->encoding = ATTR_VAL_REF_UNIT;\n      val->u.uint = read_byte (buf);\n      return 1;\n    case DW_FORM_ref2:\n      val->encoding = ATTR_VAL_REF_UNIT;\n      val->u.uint = read_uint16 (buf);\n      return 1;\n    case DW_FORM_ref4:\n      val->encoding = ATTR_VAL_REF_UNIT;\n      val->u.uint = read_uint32 (buf);\n      return 1;\n    case DW_FORM_ref8:\n      val->encoding = ATTR_VAL_REF_UNIT;\n      val->u.uint = read_uint64 (buf);\n      return 1;\n    case DW_FORM_ref_udata:\n      val->encoding = ATTR_VAL_REF_UNIT;\n      val->u.uint = read_uleb128 (buf);\n      return 1;\n    case DW_FORM_indirect:\n      {\n\tuint64_t form;\n\n\tform = read_uleb128 (buf);\n\tif (form == DW_FORM_implicit_const)\n\t  {\n\t    dwarf_buf_error (buf,\n\t\t\t     \"DW_FORM_indirect to DW_FORM_implicit_const\",\n\t\t\t     0);\n\t    return 0;\n\t  }\n\treturn read_attribute ((enum dwarf_form) form, 0, buf, is_dwarf64,\n\t\t\t       version, addrsize, dwarf_sections, altlink,\n\t\t\t       val);\n      }\n    case DW_FORM_sec_offset:\n      val->encoding = ATTR_VAL_REF_SECTION;\n      val->u.uint = read_offset (buf, is_dwarf64);\n      return 1;\n    case DW_FORM_exprloc:\n      val->encoding = ATTR_VAL_EXPR;\n      return advance (buf, read_uleb128 (buf));\n    case DW_FORM_flag_present:\n      val->encoding = ATTR_VAL_UINT;\n      val->u.uint = 1;\n      return 1;\n    case DW_FORM_ref_sig8:\n      val->encoding = ATTR_VAL_REF_TYPE;\n      val->u.uint = read_uint64 (buf);\n      return 1;\n    case DW_FORM_strx: case DW_FORM_strx1: case DW_FORM_strx2:\n    case DW_FORM_strx3: case DW_FORM_strx4:\n      {\n\tuint64_t offset;\n\n\tswitch (form)\n\t  {\n\t  case DW_FORM_strx:\n\t    offset = read_uleb128 (buf);\n\t    break;\n\t  case DW_FORM_strx1:\n\t    offset = read_byte (buf);\n\t    break;\n\t  case DW_FORM_strx2:\n\t    offset = read_uint16 (buf);\n\t    break;\n\t  case DW_FORM_strx3:\n\t    offset = read_uint24 (buf);\n\t    break;\n\t  case DW_FORM_strx4:\n\t    offset = read_uint32 (buf);\n\t    break;\n\t  default:\n\t    /* This case can't happen.  */\n\t    return 0;\n\t  }\n\tval->encoding = ATTR_VAL_STRING_INDEX;\n\tval->u.uint = offset;\n\treturn 1;\n      }\n    case DW_FORM_addrx: case DW_FORM_addrx1: case DW_FORM_addrx2:\n    case DW_FORM_addrx3: case DW_FORM_addrx4:\n      {\n\tuint64_t offset;\n\n\tswitch (form)\n\t  {\n\t  case DW_FORM_addrx:\n\t    offset = read_uleb128 (buf);\n\t    break;\n\t  case DW_FORM_addrx1:\n\t    offset = read_byte (buf);\n\t    break;\n\t  case DW_FORM_addrx2:\n\t    offset = read_uint16 (buf);\n\t    break;\n\t  case DW_FORM_addrx3:\n\t    offset = read_uint24 (buf);\n\t    break;\n\t  case DW_FORM_addrx4:\n\t    offset = read_uint32 (buf);\n\t    break;\n\t  default:\n\t    /* This case can't happen.  */\n\t    return 0;\n\t  }\n\tval->encoding = ATTR_VAL_ADDRESS_INDEX;\n\tval->u.uint = offset;\n\treturn 1;\n      }\n    case DW_FORM_ref_sup4:\n      val->encoding = ATTR_VAL_REF_SECTION;\n      val->u.uint = read_uint32 (buf);\n      return 1;\n    case DW_FORM_ref_sup8:\n      val->encoding = ATTR_VAL_REF_SECTION;\n      val->u.uint = read_uint64 (buf);\n      return 1;\n    case DW_FORM_implicit_const:\n      val->encoding = ATTR_VAL_UINT;\n      val->u.uint = implicit_val;\n      return 1;\n    case DW_FORM_loclistx:\n      /* We don't distinguish this from DW_FORM_sec_offset.  It\n       * shouldn't matter since we don't care about loclists.  */\n      val->encoding = ATTR_VAL_REF_SECTION;\n      val->u.uint = read_uleb128 (buf);\n      return 1;\n    case DW_FORM_rnglistx:\n      val->encoding = ATTR_VAL_RNGLISTS_INDEX;\n      val->u.uint = read_uleb128 (buf);\n      return 1;\n    case DW_FORM_GNU_addr_index:\n      val->encoding = ATTR_VAL_REF_SECTION;\n      val->u.uint = read_uleb128 (buf);\n      return 1;\n    case DW_FORM_GNU_str_index:\n      val->encoding = ATTR_VAL_REF_SECTION;\n      val->u.uint = read_uleb128 (buf);\n      return 1;\n    case DW_FORM_GNU_ref_alt:\n      val->u.uint = read_offset (buf, is_dwarf64);\n      if (altlink == NULL)\n\t{\n\t  val->encoding = ATTR_VAL_NONE;\n\t  return 1;\n\t}\n      val->encoding = ATTR_VAL_REF_ALT_INFO;\n      return 1;\n    case DW_FORM_strp_sup: case DW_FORM_GNU_strp_alt:\n      {\n\tuint64_t offset;\n\n\toffset = read_offset (buf, is_dwarf64);\n\tif (altlink == NULL)\n\t  {\n\t    val->encoding = ATTR_VAL_NONE;\n\t    return 1;\n\t  }\n\tif (offset >= altlink->dwarf_sections.size[DEBUG_STR])\n\t  {\n\t    dwarf_buf_error (buf, \"DW_FORM_strp_sup out of range\", 0);\n\t    return 0;\n\t  }\n\tval->encoding = ATTR_VAL_STRING;\n\tval->u.string =\n\t  (const char *) altlink->dwarf_sections.data[DEBUG_STR] + offset;\n\treturn 1;\n      }\n    default:\n      dwarf_buf_error (buf, \"unrecognized DWARF form\", -1);\n      return 0;\n    }\n}\n\n/* If we can determine the value of a string attribute, set *STRING to\n   point to the string.  Return 1 on success, 0 on error.  If we don't\n   know the value, we consider that a success, and we don't change\n   *STRING.  An error is only reported for some sort of out of range\n   offset.  */\n\nstatic int\nresolve_string (const struct dwarf_sections *dwarf_sections, int is_dwarf64,\n\t\tint is_bigendian, uint64_t str_offsets_base,\n\t\tconst struct attr_val *val,\n\t\tbacktrace_error_callback error_callback, void *data,\n\t\tconst char **string)\n{\n  switch (val->encoding)\n    {\n    case ATTR_VAL_STRING:\n      *string = val->u.string;\n      return 1;\n\n    case ATTR_VAL_STRING_INDEX:\n      {\n\tuint64_t offset;\n\tstruct dwarf_buf offset_buf;\n\n\toffset = val->u.uint * (is_dwarf64 ? 8 : 4) + str_offsets_base;\n\tif (offset + (is_dwarf64 ? 8 : 4)\n\t    > dwarf_sections->size[DEBUG_STR_OFFSETS])\n\t  {\n\t    error_callback (data, \"DW_FORM_strx value out of range\", 0);\n\t    return 0;\n\t  }\n\n\toffset_buf.name = \".debug_str_offsets\";\n\toffset_buf.start = dwarf_sections->data[DEBUG_STR_OFFSETS];\n\toffset_buf.buf = dwarf_sections->data[DEBUG_STR_OFFSETS] + offset;\n\toffset_buf.left = dwarf_sections->size[DEBUG_STR_OFFSETS] - offset;\n\toffset_buf.is_bigendian = is_bigendian;\n\toffset_buf.error_callback = error_callback;\n\toffset_buf.data = data;\n\toffset_buf.reported_underflow = 0;\n\n\toffset = read_offset (&offset_buf, is_dwarf64);\n\tif (offset >= dwarf_sections->size[DEBUG_STR])\n\t  {\n\t    dwarf_buf_error (&offset_buf,\n\t\t\t\t   \"DW_FORM_strx offset out of range\",\n\t\t\t\t   0);\n\t    return 0;\n\t  }\n\t*string = (const char *) dwarf_sections->data[DEBUG_STR] + offset;\n\treturn 1;\n      }\n\n    default:\n      return 1;\n    }\n}\n\n/* Set *ADDRESS to the real address for a ATTR_VAL_ADDRESS_INDEX.\n   Return 1 on success, 0 on error.  */\n\nstatic int\nresolve_addr_index (const struct dwarf_sections *dwarf_sections,\n\t\t    uint64_t addr_base, int addrsize, int is_bigendian,\n\t\t    uint64_t addr_index,\n\t\t    backtrace_error_callback error_callback, void *data,\n\t\t    uintptr_t *address)\n{\n  uint64_t offset;\n  struct dwarf_buf addr_buf;\n\n  offset = addr_index * addrsize + addr_base;\n  if (offset + addrsize > dwarf_sections->size[DEBUG_ADDR])\n    {\n      error_callback (data, \"DW_FORM_addrx value out of range\", 0);\n      return 0;\n    }\n\n  addr_buf.name = \".debug_addr\";\n  addr_buf.start = dwarf_sections->data[DEBUG_ADDR];\n  addr_buf.buf = dwarf_sections->data[DEBUG_ADDR] + offset;\n  addr_buf.left = dwarf_sections->size[DEBUG_ADDR] - offset;\n  addr_buf.is_bigendian = is_bigendian;\n  addr_buf.error_callback = error_callback;\n  addr_buf.data = data;\n  addr_buf.reported_underflow = 0;\n\n  *address = (uintptr_t) read_address (&addr_buf, addrsize);\n  return 1;\n}\n\n/* Compare a unit offset against a unit for bsearch.  */\n\nstatic int\nunits_search (const void *vkey, const void *ventry)\n{\n  const size_t *key = (const size_t *) vkey;\n  const struct unit *entry = *((const struct unit *const *) ventry);\n  size_t offset;\n\n  offset = *key;\n  if (offset < entry->low_offset)\n    return -1;\n  else if (offset >= entry->high_offset)\n    return 1;\n  else\n    return 0;\n}\n\n/* Find a unit in PU containing OFFSET.  */\n\nstatic struct unit *\nfind_unit (struct unit **pu, size_t units_count, size_t offset)\n{\n  struct unit **u;\n  u = (struct unit**)bsearch (&offset, pu, units_count, sizeof (struct unit *), units_search);\n  return u == NULL ? NULL : *u;\n}\n\n/* Compare function_addrs for qsort.  When ranges are nested, make the\n   smallest one sort last.  */\n\nstatic int\nfunction_addrs_compare (const void *v1, const void *v2)\n{\n  const struct function_addrs *a1 = (const struct function_addrs *) v1;\n  const struct function_addrs *a2 = (const struct function_addrs *) v2;\n\n  if (a1->low < a2->low)\n    return -1;\n  if (a1->low > a2->low)\n    return 1;\n  if (a1->high < a2->high)\n    return 1;\n  if (a1->high > a2->high)\n    return -1;\n  return strcmp (a1->function->name, a2->function->name);\n}\n\n/* Compare a PC against a function_addrs for bsearch.  We always\n   allocate an entra entry at the end of the vector, so that this\n   routine can safely look at the next entry.  Note that if there are\n   multiple ranges containing PC, which one will be returned is\n   unpredictable.  We compensate for that in dwarf_fileline.  */\n\nstatic int\nfunction_addrs_search (const void *vkey, const void *ventry)\n{\n  const uintptr_t *key = (const uintptr_t *) vkey;\n  const struct function_addrs *entry = (const struct function_addrs *) ventry;\n  uintptr_t pc;\n\n  pc = *key;\n  if (pc < entry->low)\n    return -1;\n  else if (pc > (entry + 1)->low)\n    return 1;\n  else\n    return 0;\n}\n\n/* Add a new compilation unit address range to a vector.  This is\n   called via add_ranges.  Returns 1 on success, 0 on failure.  */\n\nstatic int\nadd_unit_addr (struct backtrace_state *state, void *rdata,\n\t       uintptr_t lowpc, uintptr_t highpc,\n\t       backtrace_error_callback error_callback, void *data,\n\t       void *pvec)\n{\n  struct unit *u = (struct unit *) rdata;\n  struct unit_addrs_vector *vec = (struct unit_addrs_vector *) pvec;\n  struct unit_addrs *p;\n\n  /* Try to merge with the last entry.  */\n  if (vec->count > 0)\n    {\n      p = (struct unit_addrs *) vec->vec.base + (vec->count - 1);\n      if ((lowpc == p->high || lowpc == p->high + 1)\n\t  && u == p->u)\n\t{\n\t  if (highpc > p->high)\n\t    p->high = highpc;\n\t  return 1;\n\t}\n    }\n\n  p = ((struct unit_addrs *)\n       backtrace_vector_grow (state, sizeof (struct unit_addrs),\n\t\t\t      error_callback, data, &vec->vec));\n  if (p == NULL)\n    return 0;\n\n  p->low = lowpc;\n  p->high = highpc;\n  p->u = u;\n\n  ++vec->count;\n\n  return 1;\n}\n\n/* Compare unit_addrs for qsort.  When ranges are nested, make the\n   smallest one sort last.  */\n\nstatic int\nunit_addrs_compare (const void *v1, const void *v2)\n{\n  const struct unit_addrs *a1 = (const struct unit_addrs *) v1;\n  const struct unit_addrs *a2 = (const struct unit_addrs *) v2;\n\n  if (a1->low < a2->low)\n    return -1;\n  if (a1->low > a2->low)\n    return 1;\n  if (a1->high < a2->high)\n    return 1;\n  if (a1->high > a2->high)\n    return -1;\n  if (a1->u->lineoff < a2->u->lineoff)\n    return -1;\n  if (a1->u->lineoff > a2->u->lineoff)\n    return 1;\n  return 0;\n}\n\n/* Compare a PC against a unit_addrs for bsearch.  We always allocate\n   an entry entry at the end of the vector, so that this routine can\n   safely look at the next entry.  Note that if there are multiple\n   ranges containing PC, which one will be returned is unpredictable.\n   We compensate for that in dwarf_fileline.  */\n\nstatic int\nunit_addrs_search (const void *vkey, const void *ventry)\n{\n  const uintptr_t *key = (const uintptr_t *) vkey;\n  const struct unit_addrs *entry = (const struct unit_addrs *) ventry;\n  uintptr_t pc;\n\n  pc = *key;\n  if (pc < entry->low)\n    return -1;\n  else if (pc > (entry + 1)->low)\n    return 1;\n  else\n    return 0;\n}\n\n/* Sort the line vector by PC.  We want a stable sort here to maintain\n   the order of lines for the same PC values.  Since the sequence is\n   being sorted in place, their addresses cannot be relied on to\n   maintain stability.  That is the purpose of the index member.  */\n\nstatic int\nline_compare (const void *v1, const void *v2)\n{\n  const struct line *ln1 = (const struct line *) v1;\n  const struct line *ln2 = (const struct line *) v2;\n\n  if (ln1->pc < ln2->pc)\n    return -1;\n  else if (ln1->pc > ln2->pc)\n    return 1;\n  else if (ln1->idx < ln2->idx)\n    return -1;\n  else if (ln1->idx > ln2->idx)\n    return 1;\n  else\n    return 0;\n}\n\n/* Find a PC in a line vector.  We always allocate an extra entry at\n   the end of the lines vector, so that this routine can safely look\n   at the next entry.  Note that when there are multiple mappings for\n   the same PC value, this will return the last one.  */\n\nstatic int\nline_search (const void *vkey, const void *ventry)\n{\n  const uintptr_t *key = (const uintptr_t *) vkey;\n  const struct line *entry = (const struct line *) ventry;\n  uintptr_t pc;\n\n  pc = *key;\n  if (pc < entry->pc)\n    return -1;\n  else if (pc >= (entry + 1)->pc)\n    return 1;\n  else\n    return 0;\n}\n\n/* Sort the abbrevs by the abbrev code.  This function is passed to\n   both qsort and bsearch.  */\n\nstatic int\nabbrev_compare (const void *v1, const void *v2)\n{\n  const struct abbrev *a1 = (const struct abbrev *) v1;\n  const struct abbrev *a2 = (const struct abbrev *) v2;\n\n  if (a1->code < a2->code)\n    return -1;\n  else if (a1->code > a2->code)\n    return 1;\n  else\n    {\n      /* This really shouldn't happen.  It means there are two\n\t different abbrevs with the same code, and that means we don't\n\t know which one lookup_abbrev should return.  */\n      return 0;\n    }\n}\n\n/* Read the abbreviation table for a compilation unit.  Returns 1 on\n   success, 0 on failure.  */\n\nstatic int\nread_abbrevs (struct backtrace_state *state, uint64_t abbrev_offset,\n\t      const unsigned char *dwarf_abbrev, size_t dwarf_abbrev_size,\n\t      int is_bigendian, backtrace_error_callback error_callback,\n\t      void *data, struct abbrevs *abbrevs)\n{\n  struct dwarf_buf abbrev_buf;\n  struct dwarf_buf count_buf;\n  size_t num_abbrevs;\n\n  abbrevs->num_abbrevs = 0;\n  abbrevs->abbrevs = NULL;\n\n  if (abbrev_offset >= dwarf_abbrev_size)\n    {\n      error_callback (data, \"abbrev offset out of range\", 0);\n      return 0;\n    }\n\n  abbrev_buf.name = \".debug_abbrev\";\n  abbrev_buf.start = dwarf_abbrev;\n  abbrev_buf.buf = dwarf_abbrev + abbrev_offset;\n  abbrev_buf.left = dwarf_abbrev_size - abbrev_offset;\n  abbrev_buf.is_bigendian = is_bigendian;\n  abbrev_buf.error_callback = error_callback;\n  abbrev_buf.data = data;\n  abbrev_buf.reported_underflow = 0;\n\n  /* Count the number of abbrevs in this list.  */\n\n  count_buf = abbrev_buf;\n  num_abbrevs = 0;\n  while (read_uleb128 (&count_buf) != 0)\n    {\n      if (count_buf.reported_underflow)\n\treturn 0;\n      ++num_abbrevs;\n      // Skip tag.\n      read_uleb128 (&count_buf);\n      // Skip has_children.\n      read_byte (&count_buf);\n      // Skip attributes.\n      while (read_uleb128 (&count_buf) != 0)\n\t{\n\t  uint64_t form;\n\n\t  form = read_uleb128 (&count_buf);\n\t  if ((enum dwarf_form) form == DW_FORM_implicit_const)\n\t    read_sleb128 (&count_buf);\n\t}\n      // Skip form of last attribute.\n      read_uleb128 (&count_buf);\n    }\n\n  if (count_buf.reported_underflow)\n    return 0;\n\n  if (num_abbrevs == 0)\n    return 1;\n\n  abbrevs->abbrevs = ((struct abbrev *)\n\t\t      backtrace_alloc (state,\n\t\t\t\t       num_abbrevs * sizeof (struct abbrev),\n\t\t\t\t       error_callback, data));\n  if (abbrevs->abbrevs == NULL)\n    return 0;\n  abbrevs->num_abbrevs = num_abbrevs;\n  memset (abbrevs->abbrevs, 0, num_abbrevs * sizeof (struct abbrev));\n\n  num_abbrevs = 0;\n  while (1)\n    {\n      uint64_t code;\n      struct abbrev a;\n      size_t num_attrs;\n      struct attr *attrs;\n\n      if (abbrev_buf.reported_underflow)\n\tgoto fail;\n\n      code = read_uleb128 (&abbrev_buf);\n      if (code == 0)\n\tbreak;\n\n      a.code = code;\n      a.tag = (enum dwarf_tag) read_uleb128 (&abbrev_buf);\n      a.has_children = read_byte (&abbrev_buf);\n\n      count_buf = abbrev_buf;\n      num_attrs = 0;\n      while (read_uleb128 (&count_buf) != 0)\n\t{\n\t  uint64_t form;\n\n\t  ++num_attrs;\n\t  form = read_uleb128 (&count_buf);\n\t  if ((enum dwarf_form) form == DW_FORM_implicit_const)\n\t    read_sleb128 (&count_buf);\n\t}\n\n      if (num_attrs == 0)\n\t{\n\t  attrs = NULL;\n\t  read_uleb128 (&abbrev_buf);\n\t  read_uleb128 (&abbrev_buf);\n\t}\n      else\n\t{\n\t  attrs = ((struct attr *)\n\t\t   backtrace_alloc (state, num_attrs * sizeof *attrs,\n\t\t\t\t    error_callback, data));\n\t  if (attrs == NULL)\n\t    goto fail;\n\t  num_attrs = 0;\n\t  while (1)\n\t    {\n\t      uint64_t name;\n\t      uint64_t form;\n\n\t      name = read_uleb128 (&abbrev_buf);\n\t      form = read_uleb128 (&abbrev_buf);\n\t      if (name == 0)\n\t\tbreak;\n\t      attrs[num_attrs].name = (enum dwarf_attribute) name;\n\t      attrs[num_attrs].form = (enum dwarf_form) form;\n\t      if ((enum dwarf_form) form == DW_FORM_implicit_const)\n\t\tattrs[num_attrs].val = read_sleb128 (&abbrev_buf);\n\t      else\n\t\tattrs[num_attrs].val = 0;\n\t      ++num_attrs;\n\t    }\n\t}\n\n      a.num_attrs = num_attrs;\n      a.attrs = attrs;\n\n      abbrevs->abbrevs[num_abbrevs] = a;\n      ++num_abbrevs;\n    }\n\n  backtrace_qsort (abbrevs->abbrevs, abbrevs->num_abbrevs,\n\t\t   sizeof (struct abbrev), abbrev_compare);\n\n  return 1;\n\n fail:\n  free_abbrevs (state, abbrevs, error_callback, data);\n  return 0;\n}\n\n/* Return the abbrev information for an abbrev code.  */\n\nstatic const struct abbrev *\nlookup_abbrev (struct abbrevs *abbrevs, uint64_t code,\n\t       backtrace_error_callback error_callback, void *data)\n{\n  struct abbrev key;\n  void *p;\n\n  /* With GCC, where abbrevs are simply numbered in order, we should\n     be able to just look up the entry.  */\n  if (code - 1 < abbrevs->num_abbrevs\n      && abbrevs->abbrevs[code - 1].code == code)\n    return &abbrevs->abbrevs[code - 1];\n\n  /* Otherwise we have to search.  */\n  memset (&key, 0, sizeof key);\n  key.code = code;\n  p = bsearch (&key, abbrevs->abbrevs, abbrevs->num_abbrevs,\n\t       sizeof (struct abbrev), abbrev_compare);\n  if (p == NULL)\n    {\n      error_callback (data, \"invalid abbreviation code\", 0);\n      return NULL;\n    }\n  return (const struct abbrev *) p;\n}\n\n/* This struct is used to gather address range information while\n   reading attributes.  We use this while building a mapping from\n   address ranges to compilation units and then again while mapping\n   from address ranges to function entries.  Normally either\n   lowpc/highpc is set or ranges is set.  */\n\nstruct pcrange {\n  uintptr_t lowpc;             /* The low PC value.  */\n  int have_lowpc;\t\t/* Whether a low PC value was found.  */\n  int lowpc_is_addr_index;\t/* Whether lowpc is in .debug_addr.  */\n  uintptr_t highpc;            /* The high PC value.  */\n  int have_highpc;\t\t/* Whether a high PC value was found.  */\n  int highpc_is_relative;\t/* Whether highpc is relative to lowpc.  */\n  int highpc_is_addr_index;\t/* Whether highpc is in .debug_addr.  */\n  uint64_t ranges;\t\t/* Offset in ranges section.  */\n  int have_ranges;\t\t/* Whether ranges is valid.  */\n  int ranges_is_index;\t\t/* Whether ranges is DW_FORM_rnglistx.  */\n};\n\n/* Update PCRANGE from an attribute value.  */\n\nstatic void\nupdate_pcrange (const struct attr* attr, const struct attr_val* val,\n\t\tstruct pcrange *pcrange)\n{\n  switch (attr->name)\n    {\n    case DW_AT_low_pc:\n      if (val->encoding == ATTR_VAL_ADDRESS)\n\t{\n\t  pcrange->lowpc = (uintptr_t) val->u.uint;\n\t  pcrange->have_lowpc = 1;\n\t}\n      else if (val->encoding == ATTR_VAL_ADDRESS_INDEX)\n\t{\n\t  pcrange->lowpc = (uintptr_t) val->u.uint;\n\t  pcrange->have_lowpc = 1;\n\t  pcrange->lowpc_is_addr_index = 1;\n\t}\n      break;\n\n    case DW_AT_high_pc:\n      if (val->encoding == ATTR_VAL_ADDRESS)\n\t{\n\t  pcrange->highpc = (uintptr_t) val->u.uint;\n\t  pcrange->have_highpc = 1;\n\t}\n      else if (val->encoding == ATTR_VAL_UINT)\n\t{\n\t  pcrange->highpc = (uintptr_t) val->u.uint;\n\t  pcrange->have_highpc = 1;\n\t  pcrange->highpc_is_relative = 1;\n\t}\n      else if (val->encoding == ATTR_VAL_ADDRESS_INDEX)\n\t{\n\t  pcrange->highpc = (uintptr_t) val->u.uint;\n\t  pcrange->have_highpc = 1;\n\t  pcrange->highpc_is_addr_index = 1;\n\t}\n      break;\n\n    case DW_AT_ranges:\n      if (val->encoding == ATTR_VAL_UINT\n\t  || val->encoding == ATTR_VAL_REF_SECTION)\n\t{\n\t  pcrange->ranges = val->u.uint;\n\t  pcrange->have_ranges = 1;\n\t}\n      else if (val->encoding == ATTR_VAL_RNGLISTS_INDEX)\n\t{\n\t  pcrange->ranges = val->u.uint;\n\t  pcrange->have_ranges = 1;\n\t  pcrange->ranges_is_index = 1;\n\t}\n      break;\n\n    default:\n      break;\n    }\n}\n\n/* Call ADD_RANGE for a low/high PC pair.  Returns 1 on success, 0 on\n  error.  */\n\nstatic int\nadd_low_high_range (struct backtrace_state *state,\n\t\t    const struct dwarf_sections *dwarf_sections,\n\t\t    struct libbacktrace_base_address base_address,\n\t\t    int is_bigendian, struct unit *u,\n\t\t    const struct pcrange *pcrange,\n\t\t    int (*add_range) (struct backtrace_state *state,\n\t\t\t\t      void *rdata, uintptr_t lowpc,\n\t\t\t\t      uintptr_t highpc,\n\t\t\t\t      backtrace_error_callback error_callback,\n\t\t\t\t      void *data, void *vec),\n\t\t    void *rdata,\n\t\t    backtrace_error_callback error_callback, void *data,\n\t\t    void *vec)\n{\n  uintptr_t lowpc;\n  uintptr_t highpc;\n\n  lowpc = pcrange->lowpc;\n  if (pcrange->lowpc_is_addr_index)\n    {\n      if (!resolve_addr_index (dwarf_sections, u->addr_base, u->addrsize,\n\t\t\t       is_bigendian, lowpc, error_callback, data,\n\t\t\t       &lowpc))\n\treturn 0;\n    }\n\n  highpc = pcrange->highpc;\n  if (pcrange->highpc_is_addr_index)\n    {\n      if (!resolve_addr_index (dwarf_sections, u->addr_base, u->addrsize,\n\t\t\t       is_bigendian, highpc, error_callback, data,\n\t\t\t       &highpc))\n\treturn 0;\n    }\n  if (pcrange->highpc_is_relative)\n    highpc += lowpc;\n\n  /* Add in the base address of the module when recording PC values,\n     so that we can look up the PC directly.  */\n  lowpc = libbacktrace_add_base (lowpc, base_address);\n  highpc = libbacktrace_add_base (highpc, base_address);\n\n  return add_range (state, rdata, lowpc, highpc, error_callback, data, vec);\n}\n\n/* Call ADD_RANGE for each range read from .debug_ranges, as used in\n   DWARF versions 2 through 4.  */\n\nstatic int\nadd_ranges_from_ranges (\n    struct backtrace_state *state,\n    const struct dwarf_sections *dwarf_sections,\n    struct libbacktrace_base_address base_address, int is_bigendian,\n    struct unit *u, uintptr_t base,\n    const struct pcrange *pcrange,\n    int (*add_range) (struct backtrace_state *state, void *rdata,\n\t\t      uintptr_t lowpc, uintptr_t highpc,\n\t\t      backtrace_error_callback error_callback, void *data,\n\t\t      void *vec),\n    void *rdata,\n    backtrace_error_callback error_callback, void *data,\n    void *vec)\n{\n  struct dwarf_buf ranges_buf;\n\n  if (pcrange->ranges >= dwarf_sections->size[DEBUG_RANGES])\n    {\n      error_callback (data, \"ranges offset out of range\", 0);\n      return 0;\n    }\n\n  ranges_buf.name = \".debug_ranges\";\n  ranges_buf.start = dwarf_sections->data[DEBUG_RANGES];\n  ranges_buf.buf = dwarf_sections->data[DEBUG_RANGES] + pcrange->ranges;\n  ranges_buf.left = dwarf_sections->size[DEBUG_RANGES] - pcrange->ranges;\n  ranges_buf.is_bigendian = is_bigendian;\n  ranges_buf.error_callback = error_callback;\n  ranges_buf.data = data;\n  ranges_buf.reported_underflow = 0;\n\n  while (1)\n    {\n      uint64_t low;\n      uint64_t high;\n\n      if (ranges_buf.reported_underflow)\n\treturn 0;\n\n      low = read_address (&ranges_buf, u->addrsize);\n      high = read_address (&ranges_buf, u->addrsize);\n\n      if (low == 0 && high == 0)\n\tbreak;\n\n      if (is_highest_address (low, u->addrsize))\n\tbase = (uintptr_t) high;\n      else\n\t{\n\t  uintptr_t rl, rh;\n\n\t  rl = libbacktrace_add_base ((uintptr_t) low + base, base_address);\n\t  rh = libbacktrace_add_base ((uintptr_t) high + base, base_address);\n\t  if (!add_range (state, rdata, rl, rh, error_callback, data, vec))\n\t    return 0;\n\t}\n    }\n\n  if (ranges_buf.reported_underflow)\n    return 0;\n\n  return 1;\n}\n\n/* Call ADD_RANGE for each range read from .debug_rnglists, as used in\n   DWARF version 5.  */\n\nstatic int\nadd_ranges_from_rnglists (\n    struct backtrace_state *state,\n    const struct dwarf_sections *dwarf_sections,\n    struct libbacktrace_base_address base_address, int is_bigendian,\n    struct unit *u, uintptr_t base,\n    const struct pcrange *pcrange,\n    int (*add_range) (struct backtrace_state *state, void *rdata,\n\t\t      uintptr_t lowpc, uintptr_t highpc,\n\t\t      backtrace_error_callback error_callback, void *data,\n\t\t      void *vec),\n    void *rdata,\n    backtrace_error_callback error_callback, void *data,\n    void *vec)\n{\n  uint64_t offset;\n  struct dwarf_buf rnglists_buf;\n\n  if (!pcrange->ranges_is_index)\n    offset = pcrange->ranges;\n  else\n    offset = u->rnglists_base + pcrange->ranges * (u->is_dwarf64 ? 8 : 4);\n  if (offset >= dwarf_sections->size[DEBUG_RNGLISTS])\n    {\n      error_callback (data, \"rnglists offset out of range\", 0);\n      return 0;\n    }\n\n  rnglists_buf.name = \".debug_rnglists\";\n  rnglists_buf.start = dwarf_sections->data[DEBUG_RNGLISTS];\n  rnglists_buf.buf = dwarf_sections->data[DEBUG_RNGLISTS] + offset;\n  rnglists_buf.left = dwarf_sections->size[DEBUG_RNGLISTS] - offset;\n  rnglists_buf.is_bigendian = is_bigendian;\n  rnglists_buf.error_callback = error_callback;\n  rnglists_buf.data = data;\n  rnglists_buf.reported_underflow = 0;\n\n  if (pcrange->ranges_is_index)\n    {\n      offset = read_offset (&rnglists_buf, u->is_dwarf64);\n      offset += u->rnglists_base;\n      if (offset >= dwarf_sections->size[DEBUG_RNGLISTS])\n\t{\n\t  error_callback (data, \"rnglists index offset out of range\", 0);\n\t  return 0;\n\t}\n      rnglists_buf.buf = dwarf_sections->data[DEBUG_RNGLISTS] + offset;\n      rnglists_buf.left = dwarf_sections->size[DEBUG_RNGLISTS] - offset;\n    }\n\n  while (1)\n    {\n      unsigned char rle;\n\n      rle = read_byte (&rnglists_buf);\n      if (rle == DW_RLE_end_of_list)\n\tbreak;\n      switch (rle)\n\t{\n\tcase DW_RLE_base_addressx:\n\t  {\n\t    uint64_t index;\n\n\t    index = read_uleb128 (&rnglists_buf);\n\t    if (!resolve_addr_index (dwarf_sections, u->addr_base,\n\t\t\t\t     u->addrsize, is_bigendian, index,\n\t\t\t\t     error_callback, data, &base))\n\t      return 0;\n\t  }\n\t  break;\n\n\tcase DW_RLE_startx_endx:\n\t  {\n\t    uint64_t index;\n\t    uintptr_t low;\n\t    uintptr_t high;\n\n\t    index = read_uleb128 (&rnglists_buf);\n\t    if (!resolve_addr_index (dwarf_sections, u->addr_base,\n\t\t\t\t     u->addrsize, is_bigendian, index,\n\t\t\t\t     error_callback, data, &low))\n\t      return 0;\n\t    index = read_uleb128 (&rnglists_buf);\n\t    if (!resolve_addr_index (dwarf_sections, u->addr_base,\n\t\t\t\t     u->addrsize, is_bigendian, index,\n\t\t\t\t     error_callback, data, &high))\n\t      return 0;\n\t    if (!add_range (state, rdata,\n\t\t\t    libbacktrace_add_base (low, base_address),\n\t\t\t    libbacktrace_add_base (high, base_address),\n\t\t\t    error_callback, data, vec))\n\t      return 0;\n\t  }\n\t  break;\n\n\tcase DW_RLE_startx_length:\n\t  {\n\t    uint64_t index;\n\t    uintptr_t low;\n\t    uintptr_t length;\n\n\t    index = read_uleb128 (&rnglists_buf);\n\t    if (!resolve_addr_index (dwarf_sections, u->addr_base,\n\t\t\t\t     u->addrsize, is_bigendian, index,\n\t\t\t\t     error_callback, data, &low))\n\t      return 0;\n\t    length = read_uleb128 (&rnglists_buf);\n\t    low = libbacktrace_add_base (low, base_address);\n\t    if (!add_range (state, rdata, low, low + length,\n\t\t\t    error_callback, data, vec))\n\t      return 0;\n\t  }\n\t  break;\n\n\tcase DW_RLE_offset_pair:\n\t  {\n\t    uint64_t low;\n\t    uint64_t high;\n\n\t    low = read_uleb128 (&rnglists_buf);\n\t    high = read_uleb128 (&rnglists_buf);\n\t    if (!add_range (state, rdata,\n\t\t\t    libbacktrace_add_base (low + base, base_address),\n\t\t\t    libbacktrace_add_base (high + base, base_address),\n\t\t\t    error_callback, data, vec))\n\t      return 0;\n\t  }\n\t  break;\n\n\tcase DW_RLE_base_address:\n\t  base = (uintptr_t) read_address (&rnglists_buf, u->addrsize);\n\t  break;\n\n\tcase DW_RLE_start_end:\n\t  {\n\t    uintptr_t low;\n\t    uintptr_t high;\n\n\t    low = (uintptr_t) read_address (&rnglists_buf, u->addrsize);\n\t    high = (uintptr_t) read_address (&rnglists_buf, u->addrsize);\n\t    if (!add_range (state, rdata,\n\t\t\t    libbacktrace_add_base (low, base_address),\n\t\t\t    libbacktrace_add_base (high, base_address),\n\t\t\t    error_callback, data, vec))\n\t      return 0;\n\t  }\n\t  break;\n\n\tcase DW_RLE_start_length:\n\t  {\n\t    uintptr_t low;\n\t    uintptr_t length;\n\n\t    low = (uintptr_t) read_address (&rnglists_buf, u->addrsize);\n\t    length = (uintptr_t) read_uleb128 (&rnglists_buf);\n\t    low = libbacktrace_add_base (low, base_address);\n\t    if (!add_range (state, rdata, low, low + length,\n\t\t\t    error_callback, data, vec))\n\t      return 0;\n\t  }\n\t  break;\n\n\tdefault:\n\t  dwarf_buf_error (&rnglists_buf, \"unrecognized DW_RLE value\", -1);\n\t  return 0;\n\t}\n    }\n\n  if (rnglists_buf.reported_underflow)\n    return 0;\n\n  return 1;\n}\n\n/* Call ADD_RANGE for each lowpc/highpc pair in PCRANGE.  RDATA is\n   passed to ADD_RANGE, and is either a struct unit * or a struct\n   function *.  VEC is the vector we are adding ranges to, and is\n   either a struct unit_addrs_vector * or a struct function_vector *.\n   Returns 1 on success, 0 on error.  */\n\nstatic int\nadd_ranges (struct backtrace_state *state,\n\t    const struct dwarf_sections *dwarf_sections,\n\t    struct libbacktrace_base_address base_address, int is_bigendian,\n\t    struct unit *u, uintptr_t base, const struct pcrange *pcrange,\n\t    int (*add_range) (struct backtrace_state *state, void *rdata, \n\t\t\t      uintptr_t lowpc, uintptr_t highpc,\n\t\t\t      backtrace_error_callback error_callback,\n\t\t\t      void *data, void *vec),\n\t    void *rdata,\n\t    backtrace_error_callback error_callback, void *data,\n\t    void *vec)\n{\n  if (pcrange->have_lowpc && pcrange->have_highpc)\n    return add_low_high_range (state, dwarf_sections, base_address,\n\t\t\t       is_bigendian, u, pcrange, add_range, rdata,\n\t\t\t       error_callback, data, vec);\n\n  if (!pcrange->have_ranges)\n    {\n      /* Did not find any address ranges to add.  */\n      return 1;\n    }\n\n  if (u->version < 5)\n    return add_ranges_from_ranges (state, dwarf_sections, base_address,\n\t\t\t\t   is_bigendian, u, base, pcrange, add_range,\n\t\t\t\t   rdata, error_callback, data, vec);\n  else\n    return add_ranges_from_rnglists (state, dwarf_sections, base_address,\n\t\t\t\t     is_bigendian, u, base, pcrange, add_range,\n\t\t\t\t     rdata, error_callback, data, vec);\n}\n\n/* Find the address range covered by a compilation unit, reading from\n   UNIT_BUF and adding values to U.  Returns 1 if all data could be\n   read, 0 if there is some error.  */\n\nstatic int\nfind_address_ranges (struct backtrace_state *state,\n\t\t     struct libbacktrace_base_address base_address,\n\t\t     struct dwarf_buf *unit_buf,\n\t\t     const struct dwarf_sections *dwarf_sections,\n\t\t     int is_bigendian, struct dwarf_data *altlink,\n\t\t     backtrace_error_callback error_callback, void *data,\n\t\t     struct unit *u, struct unit_addrs_vector *addrs,\n\t\t     enum dwarf_tag *unit_tag)\n{\n  while (unit_buf->left > 0)\n    {\n      uint64_t code;\n      const struct abbrev *abbrev;\n      struct pcrange pcrange;\n      struct attr_val name_val;\n      int have_name_val;\n      struct attr_val comp_dir_val;\n      int have_comp_dir_val;\n      size_t i;\n\n      code = read_uleb128 (unit_buf);\n      if (code == 0)\n\treturn 1;\n\n      abbrev = lookup_abbrev (&u->abbrevs, code, error_callback, data);\n      if (abbrev == NULL)\n\treturn 0;\n\n      if (unit_tag != NULL)\n\t*unit_tag = abbrev->tag;\n\n      memset (&pcrange, 0, sizeof pcrange);\n      memset (&name_val, 0, sizeof name_val);\n      have_name_val = 0;\n      memset (&comp_dir_val, 0, sizeof comp_dir_val);\n      have_comp_dir_val = 0;\n      for (i = 0; i < abbrev->num_attrs; ++i)\n\t{\n\t  struct attr_val val;\n\n\t  if (!read_attribute (abbrev->attrs[i].form, abbrev->attrs[i].val,\n\t\t\t       unit_buf, u->is_dwarf64, u->version,\n\t\t\t       u->addrsize, dwarf_sections, altlink, &val))\n\t    return 0;\n\n\t  switch (abbrev->attrs[i].name)\n\t    {\n\t    case DW_AT_low_pc: case DW_AT_high_pc: case DW_AT_ranges:\n\t      update_pcrange (&abbrev->attrs[i], &val, &pcrange);\n\t      break;\n\n\t    case DW_AT_stmt_list:\n\t      if ((abbrev->tag == DW_TAG_compile_unit\n\t\t   || abbrev->tag == DW_TAG_skeleton_unit)\n\t\t  && (val.encoding == ATTR_VAL_UINT\n\t\t      || val.encoding == ATTR_VAL_REF_SECTION))\n\t\tu->lineoff = val.u.uint;\n\t      break;\n\n\t    case DW_AT_name:\n\t      if (abbrev->tag == DW_TAG_compile_unit\n\t\t  || abbrev->tag == DW_TAG_skeleton_unit)\n\t\t{\n\t\t  name_val = val;\n\t\t  have_name_val = 1;\n\t\t}\n\t      break;\n\n\t    case DW_AT_comp_dir:\n\t      if (abbrev->tag == DW_TAG_compile_unit\n\t\t  || abbrev->tag == DW_TAG_skeleton_unit)\n\t\t{\n\t\t  comp_dir_val = val;\n\t\t  have_comp_dir_val = 1;\n\t\t}\n\t      break;\n\n\t    case DW_AT_str_offsets_base:\n\t      if ((abbrev->tag == DW_TAG_compile_unit\n\t\t   || abbrev->tag == DW_TAG_skeleton_unit)\n\t\t  && val.encoding == ATTR_VAL_REF_SECTION)\n\t\tu->str_offsets_base = val.u.uint;\n\t      break;\n\n\t    case DW_AT_addr_base:\n\t      if ((abbrev->tag == DW_TAG_compile_unit\n\t\t   || abbrev->tag == DW_TAG_skeleton_unit)\n\t\t  && val.encoding == ATTR_VAL_REF_SECTION)\n\t\tu->addr_base = val.u.uint;\n\t      break;\n\n\t    case DW_AT_rnglists_base:\n\t      if ((abbrev->tag == DW_TAG_compile_unit\n\t\t   || abbrev->tag == DW_TAG_skeleton_unit)\n\t\t  && val.encoding == ATTR_VAL_REF_SECTION)\n\t\tu->rnglists_base = val.u.uint;\n\t      break;\n\n\t    default:\n\t      break;\n\t    }\n\t}\n\n      // Resolve strings after we're sure that we have seen\n      // DW_AT_str_offsets_base.\n      if (have_name_val)\n\t{\n\t  if (!resolve_string (dwarf_sections, u->is_dwarf64, is_bigendian,\n\t\t\t       u->str_offsets_base, &name_val,\n\t\t\t       error_callback, data, &u->filename))\n\t    return 0;\n\t}\n      if (have_comp_dir_val)\n\t{\n\t  if (!resolve_string (dwarf_sections, u->is_dwarf64, is_bigendian,\n\t\t\t       u->str_offsets_base, &comp_dir_val,\n\t\t\t       error_callback, data, &u->comp_dir))\n\t    return 0;\n\t}\n\n      if (abbrev->tag == DW_TAG_compile_unit\n\t  || abbrev->tag == DW_TAG_subprogram\n\t  || abbrev->tag == DW_TAG_skeleton_unit)\n\t{\n\t  if (!add_ranges (state, dwarf_sections, base_address,\n\t\t\t   is_bigendian, u, pcrange.lowpc, &pcrange,\n\t\t\t   add_unit_addr, (void *) u, error_callback, data,\n\t\t\t   (void *) addrs))\n\t    return 0;\n\n\t  /* If we found the PC range in the DW_TAG_compile_unit or\n\t     DW_TAG_skeleton_unit, we can stop now.  */\n\t  if ((abbrev->tag == DW_TAG_compile_unit\n\t       || abbrev->tag == DW_TAG_skeleton_unit)\n\t      && (pcrange.have_ranges\n\t\t  || (pcrange.have_lowpc && pcrange.have_highpc)))\n\t    return 1;\n\t}\n\n      if (abbrev->has_children)\n\t{\n\t  if (!find_address_ranges (state, base_address, unit_buf,\n\t\t\t\t    dwarf_sections, is_bigendian, altlink,\n\t\t\t\t    error_callback, data, u, addrs, NULL))\n\t    return 0;\n\t}\n    }\n\n  return 1;\n}\n\n/* Build a mapping from address ranges to the compilation units where\n   the line number information for that range can be found.  Returns 1\n   on success, 0 on failure.  */\n\nstatic int\nbuild_address_map (struct backtrace_state *state,\n\t\t   struct libbacktrace_base_address base_address,\n\t\t   const struct dwarf_sections *dwarf_sections,\n\t\t   int is_bigendian, struct dwarf_data *altlink,\n\t\t   backtrace_error_callback error_callback, void *data,\n\t\t   struct unit_addrs_vector *addrs,\n\t\t   struct unit_vector *unit_vec)\n{\n  struct dwarf_buf info;\n  struct backtrace_vector units;\n  size_t units_count;\n  size_t i;\n  struct unit **pu;\n  size_t unit_offset = 0;\n  struct unit_addrs *pa;\n\n  memset (&addrs->vec, 0, sizeof addrs->vec);\n  memset (&unit_vec->vec, 0, sizeof unit_vec->vec);\n  addrs->count = 0;\n  unit_vec->count = 0;\n\n  /* Read through the .debug_info section.  FIXME: Should we use the\n     .debug_aranges section?  gdb and addr2line don't use it, but I'm\n     not sure why.  */\n\n  info.name = \".debug_info\";\n  info.start = dwarf_sections->data[DEBUG_INFO];\n  info.buf = info.start;\n  info.left = dwarf_sections->size[DEBUG_INFO];\n  info.is_bigendian = is_bigendian;\n  info.error_callback = error_callback;\n  info.data = data;\n  info.reported_underflow = 0;\n\n  memset (&units, 0, sizeof units);\n  units_count = 0;\n\n  while (info.left > 0)\n    {\n      const unsigned char *unit_data_start;\n      uint64_t len;\n      int is_dwarf64;\n      struct dwarf_buf unit_buf;\n      int version;\n      int unit_type;\n      uint64_t abbrev_offset;\n      int addrsize;\n      struct unit *u;\n      enum dwarf_tag unit_tag;\n\n      if (info.reported_underflow)\n\tgoto fail;\n\n      unit_data_start = info.buf;\n\n      len = read_initial_length (&info, &is_dwarf64);\n      unit_buf = info;\n      unit_buf.left = len;\n\n      if (!advance (&info, len))\n\tgoto fail;\n\n      version = read_uint16 (&unit_buf);\n      if (version < 2 || version > 5)\n\t{\n\t  dwarf_buf_error (&unit_buf, \"unrecognized DWARF version\", -1);\n\t  goto fail;\n\t}\n\n      if (version < 5)\n\tunit_type = 0;\n      else\n\t{\n\t  unit_type = read_byte (&unit_buf);\n\t  if (unit_type == DW_UT_type || unit_type == DW_UT_split_type)\n\t    {\n\t      /* This unit doesn't have anything we need.  */\n\t      continue;\n\t    }\n\t}\n\n      pu = ((struct unit **)\n\t    backtrace_vector_grow (state, sizeof (struct unit *),\n\t\t\t\t   error_callback, data, &units));\n      if (pu == NULL)\n\t  goto fail;\n\n      u = ((struct unit *)\n\t   backtrace_alloc (state, sizeof *u, error_callback, data));\n      if (u == NULL)\n\tgoto fail;\n\n      *pu = u;\n      ++units_count;\n\n      if (version < 5)\n\taddrsize = 0; /* Set below.  */\n      else\n\taddrsize = read_byte (&unit_buf);\n\n      memset (&u->abbrevs, 0, sizeof u->abbrevs);\n      abbrev_offset = read_offset (&unit_buf, is_dwarf64);\n      if (!read_abbrevs (state, abbrev_offset,\n\t\t\t dwarf_sections->data[DEBUG_ABBREV],\n\t\t\t dwarf_sections->size[DEBUG_ABBREV],\n\t\t\t is_bigendian, error_callback, data, &u->abbrevs))\n\tgoto fail;\n\n      if (version < 5)\n\taddrsize = read_byte (&unit_buf);\n\n      switch (unit_type)\n\t{\n\tcase 0:\n\t  break;\n\tcase DW_UT_compile: case DW_UT_partial:\n\t  break;\n\tcase DW_UT_skeleton: case DW_UT_split_compile:\n\t  read_uint64 (&unit_buf); /* dwo_id */\n\t  break;\n\tdefault:\n\t  break;\n\t}\n\n      u->low_offset = unit_offset;\n      unit_offset += len + (is_dwarf64 ? 12 : 4);\n      u->high_offset = unit_offset;\n      u->unit_data = unit_buf.buf;\n      u->unit_data_len = unit_buf.left;\n      u->unit_data_offset = unit_buf.buf - unit_data_start;\n      u->version = version;\n      u->is_dwarf64 = is_dwarf64;\n      u->addrsize = addrsize;\n      u->filename = NULL;\n      u->comp_dir = NULL;\n      u->abs_filename = NULL;\n      u->lineoff = 0;\n      u->str_offsets_base = 0;\n      u->addr_base = 0;\n      u->rnglists_base = 0;\n\n      /* The actual line number mappings will be read as needed.  */\n      u->lines = NULL;\n      u->lines_count = 0;\n      u->function_addrs = NULL;\n      u->function_addrs_count = 0;\n\n      if (!find_address_ranges (state, base_address, &unit_buf, dwarf_sections,\n\t\t\t\tis_bigendian, altlink, error_callback, data,\n\t\t\t\tu, addrs, &unit_tag))\n\tgoto fail;\n\n      if (unit_buf.reported_underflow)\n\tgoto fail;\n    }\n  if (info.reported_underflow)\n    goto fail;\n\n  /* Add a trailing addrs entry, but don't include it in addrs->count.  */\n  pa = ((struct unit_addrs *)\n\tbacktrace_vector_grow (state, sizeof (struct unit_addrs),\n\t\t\t       error_callback, data, &addrs->vec));\n  if (pa == NULL)\n    goto fail;\n  pa->low = 0;\n  --pa->low;\n  pa->high = pa->low;\n  pa->u = NULL;\n\n  unit_vec->vec = units;\n  unit_vec->count = units_count;\n  return 1;\n\n fail:\n  if (units_count > 0)\n    {\n      pu = (struct unit **) units.base;\n      for (i = 0; i < units_count; i++)\n\t{\n\t  free_abbrevs (state, &pu[i]->abbrevs, error_callback, data);\n\t  backtrace_free (state, pu[i], sizeof **pu, error_callback, data);\n\t}\n      backtrace_vector_free (state, &units, error_callback, data);\n    }\n  if (addrs->count > 0)\n    {\n      backtrace_vector_free (state, &addrs->vec, error_callback, data);\n      addrs->count = 0;\n    }\n  return 0;\n}\n\n/* Add a new mapping to the vector of line mappings that we are\n   building.  Returns 1 on success, 0 on failure.  */\n\nstatic int\nadd_line (struct backtrace_state *state, struct dwarf_data *ddata,\n\t  uintptr_t pc, const char *filename, int lineno,\n\t  backtrace_error_callback error_callback, void *data,\n\t  struct line_vector *vec)\n{\n  struct line *ln;\n\n  /* If we are adding the same mapping, ignore it.  This can happen\n     when using discriminators.  */\n  if (vec->count > 0)\n    {\n      ln = (struct line *) vec->vec.base + (vec->count - 1);\n      if (pc == ln->pc && filename == ln->filename && lineno == ln->lineno)\n\treturn 1;\n    }\n\n  ln = ((struct line *)\n\tbacktrace_vector_grow (state, sizeof (struct line), error_callback,\n\t\t\t       data, &vec->vec));\n  if (ln == NULL)\n    return 0;\n\n  /* Add in the base address here, so that we can look up the PC\n     directly.  */\n  ln->pc = libbacktrace_add_base (pc, ddata->base_address);\n\n  ln->filename = filename;\n  ln->lineno = lineno;\n  ln->idx = vec->count;\n\n  ++vec->count;\n\n  return 1;\n}\n\n/* Free the line header information.  */\n\nstatic void\nfree_line_header (struct backtrace_state *state, struct line_header *hdr,\n\t\t  backtrace_error_callback error_callback, void *data)\n{\n  if (hdr->dirs_count != 0)\n    backtrace_free (state, hdr->dirs, hdr->dirs_count * sizeof (const char *),\n\t\t    error_callback, data);\n  backtrace_free (state, hdr->filenames,\n\t\t  hdr->filenames_count * sizeof (char *),\n\t\t  error_callback, data);\n}\n\n/* Read the directories and file names for a line header for version\n   2, setting fields in HDR.  Return 1 on success, 0 on failure.  */\n\nstatic int\nread_v2_paths (struct backtrace_state *state, struct unit *u,\n\t       struct dwarf_buf *hdr_buf, struct line_header *hdr)\n{\n  const unsigned char *p;\n  const unsigned char *pend;\n  size_t i;\n\n  /* Count the number of directory entries.  */\n  hdr->dirs_count = 0;\n  p = hdr_buf->buf;\n  pend = p + hdr_buf->left;\n  while (p < pend && *p != '\\0')\n    {\n      p += strnlen((const char *) p, pend - p) + 1;\n      ++hdr->dirs_count;\n    }\n\n  /* The index of the first entry in the list of directories is 1.  Index 0 is\n     used for the current directory of the compilation.  To simplify index\n     handling, we set entry 0 to the compilation unit directory.  */\n  ++hdr->dirs_count;\n  hdr->dirs = ((const char **)\n\t       backtrace_alloc (state,\n\t\t\t\thdr->dirs_count * sizeof (const char *),\n\t\t\t\thdr_buf->error_callback,\n\t\t\t\thdr_buf->data));\n  if (hdr->dirs == NULL)\n    return 0;\n\n  hdr->dirs[0] = u->comp_dir;\n  i = 1;\n  while (*hdr_buf->buf != '\\0')\n    {\n      if (hdr_buf->reported_underflow)\n\treturn 0;\n\n      hdr->dirs[i] = read_string (hdr_buf);\n      if (hdr->dirs[i] == NULL)\n\treturn 0;\n      ++i;\n    }\n  if (!advance (hdr_buf, 1))\n    return 0;\n\n  /* Count the number of file entries.  */\n  hdr->filenames_count = 0;\n  p = hdr_buf->buf;\n  pend = p + hdr_buf->left;\n  while (p < pend && *p != '\\0')\n    {\n      p += strnlen ((const char *) p, pend - p) + 1;\n      p += leb128_len (p);\n      p += leb128_len (p);\n      p += leb128_len (p);\n      ++hdr->filenames_count;\n    }\n\n  /* The index of the first entry in the list of file names is 1.  Index 0 is\n     used for the DW_AT_name of the compilation unit.  To simplify index\n     handling, we set entry 0 to the compilation unit file name.  */\n  ++hdr->filenames_count;\n  hdr->filenames = ((const char **)\n\t\t    backtrace_alloc (state,\n\t\t\t\t     hdr->filenames_count * sizeof (char *),\n\t\t\t\t     hdr_buf->error_callback,\n\t\t\t\t     hdr_buf->data));\n  if (hdr->filenames == NULL)\n    return 0;\n  hdr->filenames[0] = u->filename;\n  i = 1;\n  while (*hdr_buf->buf != '\\0')\n    {\n      const char *filename;\n      uint64_t dir_index;\n\n      if (hdr_buf->reported_underflow)\n\treturn 0;\n\n      filename = read_string (hdr_buf);\n      if (filename == NULL)\n\treturn 0;\n      dir_index = read_uleb128 (hdr_buf);\n      if (IS_ABSOLUTE_PATH (filename)\n\t  || (dir_index < hdr->dirs_count && hdr->dirs[dir_index] == NULL))\n\thdr->filenames[i] = filename;\n      else\n\t{\n\t  const char *dir;\n\t  size_t dir_len;\n\t  size_t filename_len;\n\t  char *s;\n\n\t  if (dir_index < hdr->dirs_count)\n\t    dir = hdr->dirs[dir_index];\n\t  else\n\t    {\n\t      dwarf_buf_error (hdr_buf,\n\t\t\t       (\"invalid directory index in \"\n\t\t\t\t\"line number program header\"),\n\t\t\t       0);\n\t      return 0;\n\t    }\n\t  dir_len = strlen (dir);\n\t  filename_len = strlen (filename);\n\t  s = ((char *) backtrace_alloc (state, dir_len + filename_len + 2,\n\t\t\t\t\t hdr_buf->error_callback,\n\t\t\t\t\t hdr_buf->data));\n\t  if (s == NULL)\n\t    return 0;\n\t  memcpy (s, dir, dir_len);\n\t  /* FIXME: If we are on a DOS-based file system, and the\n\t     directory or the file name use backslashes, then we\n\t     should use a backslash here.  */\n\t  s[dir_len] = '/';\n\t  memcpy (s + dir_len + 1, filename, filename_len + 1);\n\t  hdr->filenames[i] = s;\n\t}\n\n      /* Ignore the modification time and size.  */\n      read_uleb128 (hdr_buf);\n      read_uleb128 (hdr_buf);\n\n      ++i;\n    }\n\n  return 1;\n}\n\n/* Read a single version 5 LNCT entry for a directory or file name in a\n   line header.  Sets *STRING to the resulting name, ignoring other\n   data.  Return 1 on success, 0 on failure.  */\n\nstatic int\nread_lnct (struct backtrace_state *state, struct dwarf_data *ddata,\n\t   struct unit *u, struct dwarf_buf *hdr_buf,\n\t   const struct line_header *hdr, size_t formats_count,\n\t   const struct line_header_format *formats, const char **string)\n{\n  size_t i;\n  const char *dir;\n  const char *path;\n\n  dir = NULL;\n  path = NULL;\n  for (i = 0; i < formats_count; i++)\n    {\n      struct attr_val val;\n\n      if (!read_attribute (formats[i].form, 0, hdr_buf, u->is_dwarf64,\n\t\t\t   u->version, hdr->addrsize, &ddata->dwarf_sections,\n\t\t\t   ddata->altlink, &val))\n\treturn 0;\n      switch (formats[i].lnct)\n\t{\n\tcase DW_LNCT_path:\n\t  if (!resolve_string (&ddata->dwarf_sections, u->is_dwarf64,\n\t\t\t       ddata->is_bigendian, u->str_offsets_base,\n\t\t\t       &val, hdr_buf->error_callback, hdr_buf->data,\n\t\t\t       &path))\n\t    return 0;\n\t  break;\n\tcase DW_LNCT_directory_index:\n\t  if (val.encoding == ATTR_VAL_UINT)\n\t    {\n\t      if (val.u.uint >= hdr->dirs_count)\n\t\t{\n\t\t  dwarf_buf_error (hdr_buf,\n\t\t\t\t   (\"invalid directory index in \"\n\t\t\t\t    \"line number program header\"),\n\t\t\t\t   0);\n\t\t  return 0;\n\t\t}\n\t      dir = hdr->dirs[val.u.uint];\n\t    }\n\t  break;\n\tdefault:\n\t  /* We don't care about timestamps or sizes or hashes.  */\n\t  break;\n\t}\n    }\n\n  if (path == NULL)\n    {\n      dwarf_buf_error (hdr_buf,\n\t\t       \"missing file name in line number program header\",\n\t\t       0);\n      return 0;\n    }\n\n  if (dir == NULL)\n    *string = path;\n  else\n    {\n      size_t dir_len;\n      size_t path_len;\n      char *s;\n\n      dir_len = strlen (dir);\n      path_len = strlen (path);\n      s = (char *) backtrace_alloc (state, dir_len + path_len + 2,\n\t\t\t\t    hdr_buf->error_callback, hdr_buf->data);\n      if (s == NULL)\n\treturn 0;\n      memcpy (s, dir, dir_len);\n      /* FIXME: If we are on a DOS-based file system, and the\n\t directory or the path name use backslashes, then we should\n\t use a backslash here.  */\n      s[dir_len] = '/';\n      memcpy (s + dir_len + 1, path, path_len + 1);\n      *string = s;\n    }\n\n  return 1;\n}\n\n/* Read a set of DWARF 5 line header format entries, setting *PCOUNT\n   and *PPATHS.  Return 1 on success, 0 on failure.  */\n\nstatic int\nread_line_header_format_entries (struct backtrace_state *state,\n\t\t\t\t struct dwarf_data *ddata,\n\t\t\t\t struct unit *u,\n\t\t\t\t struct dwarf_buf *hdr_buf,\n\t\t\t\t struct line_header *hdr,\n\t\t\t\t size_t *pcount,\n\t\t\t\t const char ***ppaths)\n{\n  size_t formats_count;\n  struct line_header_format *formats;\n  size_t paths_count;\n  const char **paths;\n  size_t i;\n  int ret;\n\n  formats_count = read_byte (hdr_buf);\n  if (formats_count == 0)\n    formats = NULL;\n  else\n    {\n      formats = ((struct line_header_format *)\n\t\t backtrace_alloc (state,\n\t\t\t\t  (formats_count\n\t\t\t\t   * sizeof (struct line_header_format)),\n\t\t\t\t  hdr_buf->error_callback,\n\t\t\t\t  hdr_buf->data));\n      if (formats == NULL)\n\treturn 0;\n\n      for (i = 0; i < formats_count; i++)\n\t{\n\t  formats[i].lnct = (int) read_uleb128(hdr_buf);\n\t  formats[i].form = (enum dwarf_form) read_uleb128 (hdr_buf);\n\t}\n    }\n\n  paths_count = read_uleb128 (hdr_buf);\n  if (paths_count == 0)\n    {\n      *pcount = 0;\n      *ppaths = NULL;\n      ret = 1;\n      goto exit;\n    }\n\n  paths = ((const char **)\n\t   backtrace_alloc (state, paths_count * sizeof (const char *),\n\t\t\t    hdr_buf->error_callback, hdr_buf->data));\n  if (paths == NULL)\n    {\n      ret = 0;\n      goto exit;\n    }\n  for (i = 0; i < paths_count; i++)\n    {\n      if (!read_lnct (state, ddata, u, hdr_buf, hdr, formats_count,\n\t\t      formats, &paths[i]))\n\t{\n\t  backtrace_free (state, paths,\n\t\t\t  paths_count * sizeof (const char *),\n\t\t\t  hdr_buf->error_callback, hdr_buf->data);\n\t  ret = 0;\n\t  goto exit;\n\t}\n    }\n\n  *pcount = paths_count;\n  *ppaths = paths;\n\n  ret = 1;\n\n exit:\n  if (formats != NULL)\n    backtrace_free (state, formats,\n\t\t    formats_count * sizeof (struct line_header_format),\n\t\t    hdr_buf->error_callback, hdr_buf->data);\n\n  return  ret;\n}\n\n/* Read the line header.  Return 1 on success, 0 on failure.  */\n\nstatic int\nread_line_header (struct backtrace_state *state, struct dwarf_data *ddata,\n\t\t  struct unit *u, int is_dwarf64, struct dwarf_buf *line_buf,\n\t\t  struct line_header *hdr)\n{\n  uint64_t hdrlen;\n  struct dwarf_buf hdr_buf;\n\n  hdr->version = read_uint16 (line_buf);\n  if (hdr->version < 2 || hdr->version > 5)\n    {\n      dwarf_buf_error (line_buf, \"unsupported line number version\", -1);\n      return 0;\n    }\n\n  if (hdr->version < 5)\n    hdr->addrsize = u->addrsize;\n  else\n    {\n      hdr->addrsize = read_byte (line_buf);\n      /* We could support a non-zero segment_selector_size but I doubt\n\t we'll ever see it.  */\n      if (read_byte (line_buf) != 0)\n\t{\n\t  dwarf_buf_error (line_buf,\n\t\t\t   \"non-zero segment_selector_size not supported\",\n\t\t\t   -1);\n\t  return 0;\n\t}\n    }\n\n  hdrlen = read_offset (line_buf, is_dwarf64);\n\n  hdr_buf = *line_buf;\n  hdr_buf.left = hdrlen;\n\n  if (!advance (line_buf, hdrlen))\n    return 0;\n\n  hdr->min_insn_len = read_byte (&hdr_buf);\n  if (hdr->version < 4)\n    hdr->max_ops_per_insn = 1;\n  else\n    hdr->max_ops_per_insn = read_byte (&hdr_buf);\n\n  /* We don't care about default_is_stmt.  */\n  read_byte (&hdr_buf);\n\n  hdr->line_base = read_sbyte (&hdr_buf);\n  hdr->line_range = read_byte (&hdr_buf);\n\n  hdr->opcode_base = read_byte (&hdr_buf);\n  hdr->opcode_lengths = hdr_buf.buf;\n  if (!advance (&hdr_buf, hdr->opcode_base - 1))\n    return 0;\n\n  if (hdr->version < 5)\n    {\n      if (!read_v2_paths (state, u, &hdr_buf, hdr))\n\treturn 0;\n    }\n  else\n    {\n      if (!read_line_header_format_entries (state, ddata, u, &hdr_buf, hdr,\n\t\t\t\t\t    &hdr->dirs_count,\n\t\t\t\t\t    &hdr->dirs))\n\treturn 0;\n      if (!read_line_header_format_entries (state, ddata, u, &hdr_buf, hdr,\n\t\t\t\t\t    &hdr->filenames_count,\n\t\t\t\t\t    &hdr->filenames))\n\treturn 0;\n    }\n\n  if (hdr_buf.reported_underflow)\n    return 0;\n\n  return 1;\n}\n\n/* Read the line program, adding line mappings to VEC.  Return 1 on\n   success, 0 on failure.  */\n\nstatic int\nread_line_program (struct backtrace_state *state, struct dwarf_data *ddata,\n\t\t   const struct line_header *hdr, struct dwarf_buf *line_buf,\n\t\t   struct line_vector *vec)\n{\n  uint64_t address;\n  unsigned int op_index;\n  const char *reset_filename;\n  const char *filename;\n  int lineno;\n\n  address = 0;\n  op_index = 0;\n  if (hdr->filenames_count > 1)\n    reset_filename = hdr->filenames[1];\n  else\n    reset_filename = \"\";\n  filename = reset_filename;\n  lineno = 1;\n  while (line_buf->left > 0)\n    {\n      unsigned int op;\n\n      op = read_byte (line_buf);\n      if (op >= hdr->opcode_base)\n\t{\n\t  unsigned int advance;\n\n\t  /* Special opcode.  */\n\t  op -= hdr->opcode_base;\n\t  advance = op / hdr->line_range;\n\t  address += (hdr->min_insn_len * (op_index + advance)\n\t\t      / hdr->max_ops_per_insn);\n\t  op_index = (op_index + advance) % hdr->max_ops_per_insn;\n\t  lineno += hdr->line_base + (int) (op % hdr->line_range);\n\t  add_line (state, ddata, address, filename, lineno,\n\t\t    line_buf->error_callback, line_buf->data, vec);\n\t}\n      else if (op == DW_LNS_extended_op)\n\t{\n\t  uint64_t len;\n\n\t  len = read_uleb128 (line_buf);\n\t  op = read_byte (line_buf);\n\t  switch (op)\n\t    {\n\t    case DW_LNE_end_sequence:\n\t      /* FIXME: Should we mark the high PC here?  It seems\n\t\t that we already have that information from the\n\t\t compilation unit.  */\n\t      address = 0;\n\t      op_index = 0;\n\t      filename = reset_filename;\n\t      lineno = 1;\n\t      break;\n\t    case DW_LNE_set_address:\n\t      address = read_address (line_buf, hdr->addrsize);\n\t      break;\n\t    case DW_LNE_define_file:\n\t      {\n\t\tconst char *f;\n\t\tunsigned int dir_index;\n\n\t\tf = read_string (line_buf);\n\t\tif (f == NULL)\n\t\t  return 0;\n\t\tdir_index = read_uleb128 (line_buf);\n\t\t/* Ignore that time and length.  */\n\t\tread_uleb128 (line_buf);\n\t\tread_uleb128 (line_buf);\n\t\tif (IS_ABSOLUTE_PATH (f))\n\t\t  filename = f;\n\t\telse\n\t\t  {\n\t\t    const char *dir;\n\t\t    size_t dir_len;\n\t\t    size_t f_len;\n\t\t    char *p;\n\n\t\t    if (dir_index < hdr->dirs_count)\n\t\t      dir = hdr->dirs[dir_index];\n\t\t    else\n\t\t      {\n\t\t\tdwarf_buf_error (line_buf,\n\t\t\t\t\t (\"invalid directory index \"\n\t\t\t\t\t  \"in line number program\"),\n\t\t\t\t\t 0);\n\t\t\treturn 0;\n\t\t      }\n\t\t    dir_len = strlen (dir);\n\t\t    f_len = strlen (f);\n\t\t    p = ((char *)\n\t\t\t backtrace_alloc (state, dir_len + f_len + 2,\n\t\t\t\t\t  line_buf->error_callback,\n\t\t\t\t\t  line_buf->data));\n\t\t    if (p == NULL)\n\t\t      return 0;\n\t\t    memcpy (p, dir, dir_len);\n\t\t    /* FIXME: If we are on a DOS-based file system,\n\t\t       and the directory or the file name use\n\t\t       backslashes, then we should use a backslash\n\t\t       here.  */\n\t\t    p[dir_len] = '/';\n\t\t    memcpy (p + dir_len + 1, f, f_len + 1);\n\t\t    filename = p;\n\t\t  }\n\t      }\n\t      break;\n\t    case DW_LNE_set_discriminator:\n\t      /* We don't care about discriminators.  */\n\t      read_uleb128 (line_buf);\n\t      break;\n\t    default:\n\t      if (!advance (line_buf, len - 1))\n\t\treturn 0;\n\t      break;\n\t    }\n\t}\n      else\n\t{\n\t  switch (op)\n\t    {\n\t    case DW_LNS_copy:\n\t      add_line (state, ddata, address, filename, lineno,\n\t\t\tline_buf->error_callback, line_buf->data, vec);\n\t      break;\n\t    case DW_LNS_advance_pc:\n\t      {\n\t\tuint64_t advance;\n\n\t\tadvance = read_uleb128 (line_buf);\n\t\taddress += (hdr->min_insn_len * (op_index + advance)\n\t\t\t    / hdr->max_ops_per_insn);\n\t\top_index = (op_index + advance) % hdr->max_ops_per_insn;\n\t      }\n\t      break;\n\t    case DW_LNS_advance_line:\n\t      lineno += (int) read_sleb128 (line_buf);\n\t      break;\n\t    case DW_LNS_set_file:\n\t      {\n\t\tuint64_t fileno;\n\n\t\tfileno = read_uleb128 (line_buf);\n\t\tif (fileno >= hdr->filenames_count)\n\t\t  {\n\t\t    dwarf_buf_error (line_buf,\n\t\t\t\t     (\"invalid file number in \"\n\t\t\t\t      \"line number program\"),\n\t\t\t\t     0);\n\t\t    return 0;\n\t\t  }\n\t\tfilename = hdr->filenames[fileno];\n\t      }\n\t      break;\n\t    case DW_LNS_set_column:\n\t      read_uleb128 (line_buf);\n\t      break;\n\t    case DW_LNS_negate_stmt:\n\t      break;\n\t    case DW_LNS_set_basic_block:\n\t      break;\n\t    case DW_LNS_const_add_pc:\n\t      {\n\t\tunsigned int advance;\n\n\t\top = 255 - hdr->opcode_base;\n\t\tadvance = op / hdr->line_range;\n\t\taddress += (hdr->min_insn_len * (op_index + advance)\n\t\t\t    / hdr->max_ops_per_insn);\n\t\top_index = (op_index + advance) % hdr->max_ops_per_insn;\n\t      }\n\t      break;\n\t    case DW_LNS_fixed_advance_pc:\n\t      address += read_uint16 (line_buf);\n\t      op_index = 0;\n\t      break;\n\t    case DW_LNS_set_prologue_end:\n\t      break;\n\t    case DW_LNS_set_epilogue_begin:\n\t      break;\n\t    case DW_LNS_set_isa:\n\t      read_uleb128 (line_buf);\n\t      break;\n\t    default:\n\t      {\n\t\tunsigned int i;\n\n\t\tfor (i = hdr->opcode_lengths[op - 1]; i > 0; --i)\n\t\t  read_uleb128 (line_buf);\n\t      }\n\t      break;\n\t    }\n\t}\n    }\n\n  return 1;\n}\n\n/* Read the line number information for a compilation unit.  Returns 1\n   on success, 0 on failure.  */\n\nstatic int\nread_line_info (struct backtrace_state *state, struct dwarf_data *ddata,\n\t\tbacktrace_error_callback error_callback, void *data,\n\t\tstruct unit *u, struct line_header *hdr, struct line **lines,\n\t\tsize_t *lines_count)\n{\n  struct line_vector vec;\n  struct dwarf_buf line_buf;\n  uint64_t len;\n  int is_dwarf64;\n  struct line *ln;\n\n  memset (&vec.vec, 0, sizeof vec.vec);\n  vec.count = 0;\n\n  memset (hdr, 0, sizeof *hdr);\n\n  if (u->lineoff != (off_t) (size_t) u->lineoff\n      || (size_t) u->lineoff >= ddata->dwarf_sections.size[DEBUG_LINE])\n    {\n      error_callback (data, \"unit line offset out of range\", 0);\n      goto fail;\n    }\n\n  line_buf.name = \".debug_line\";\n  line_buf.start = ddata->dwarf_sections.data[DEBUG_LINE];\n  line_buf.buf = ddata->dwarf_sections.data[DEBUG_LINE] + u->lineoff;\n  line_buf.left = ddata->dwarf_sections.size[DEBUG_LINE] - u->lineoff;\n  line_buf.is_bigendian = ddata->is_bigendian;\n  line_buf.error_callback = error_callback;\n  line_buf.data = data;\n  line_buf.reported_underflow = 0;\n\n  len = read_initial_length (&line_buf, &is_dwarf64);\n  line_buf.left = len;\n\n  if (!read_line_header (state, ddata, u, is_dwarf64, &line_buf, hdr))\n    goto fail;\n\n  if (!read_line_program (state, ddata, hdr, &line_buf, &vec))\n    goto fail;\n\n  if (line_buf.reported_underflow)\n    goto fail;\n\n  if (vec.count == 0)\n    {\n      /* This is not a failure in the sense of a generating an error,\n\t but it is a failure in that sense that we have no useful\n\t information.  */\n      goto fail;\n    }\n\n  /* Allocate one extra entry at the end.  */\n  ln = ((struct line *)\n\tbacktrace_vector_grow (state, sizeof (struct line), error_callback,\n\t\t\t       data, &vec.vec));\n  if (ln == NULL)\n    goto fail;\n  ln->pc = (uintptr_t) -1;\n  ln->filename = NULL;\n  ln->lineno = 0;\n  ln->idx = 0;\n\n  if (!backtrace_vector_release (state, &vec.vec, error_callback, data))\n    goto fail;\n\n  ln = (struct line *) vec.vec.base;\n  backtrace_qsort (ln, vec.count, sizeof (struct line), line_compare);\n\n  *lines = ln;\n  *lines_count = vec.count;\n\n  return 1;\n\n fail:\n  backtrace_vector_free (state, &vec.vec, error_callback, data);\n  free_line_header (state, hdr, error_callback, data);\n  *lines = (struct line *) (uintptr_t) -1;\n  *lines_count = 0;\n  return 0;\n}\n\nstatic const char *read_referenced_name (struct dwarf_data *, struct unit *,\n\t\t\t\t\t uint64_t, backtrace_error_callback,\n\t\t\t\t\t void *);\n\n/* Read the name of a function from a DIE referenced by ATTR with VAL.  */\n\nstatic const char *\nread_referenced_name_from_attr (struct dwarf_data *ddata, struct unit *u,\n\t\t\t\tstruct attr *attr, struct attr_val *val,\n\t\t\t\tbacktrace_error_callback error_callback,\n\t\t\t\tvoid *data)\n{\n  switch (attr->name)\n    {\n    case DW_AT_abstract_origin:\n    case DW_AT_specification:\n      break;\n    default:\n      return NULL;\n    }\n\n  if (attr->form == DW_FORM_ref_sig8)\n    return NULL;\n\n  if (val->encoding == ATTR_VAL_REF_INFO)\n    {\n      struct unit *unit\n\t= find_unit (ddata->units, ddata->units_count,\n\t\t     val->u.uint);\n      if (unit == NULL)\n\treturn NULL;\n\n      uint64_t offset = val->u.uint - unit->low_offset;\n      return read_referenced_name (ddata, unit, offset, error_callback, data);\n    }\n\n  if (val->encoding == ATTR_VAL_UINT\n      || val->encoding == ATTR_VAL_REF_UNIT)\n    return read_referenced_name (ddata, u, val->u.uint, error_callback, data);\n\n  if (val->encoding == ATTR_VAL_REF_ALT_INFO)\n    {\n      struct unit *alt_unit\n\t= find_unit (ddata->altlink->units, ddata->altlink->units_count,\n\t\t     val->u.uint);\n      if (alt_unit == NULL)\n\treturn NULL;\n\n      uint64_t offset = val->u.uint - alt_unit->low_offset;\n      return read_referenced_name (ddata->altlink, alt_unit, offset,\n\t\t\t\t   error_callback, data);\n    }\n\n  return NULL;\n}\n\n/* Read the name of a function from a DIE referenced by a\n   DW_AT_abstract_origin or DW_AT_specification tag.  OFFSET is within\n   the same compilation unit.  */\n\nstatic const char *\nread_referenced_name (struct dwarf_data *ddata, struct unit *u,\n\t\t      uint64_t offset, backtrace_error_callback error_callback,\n\t\t      void *data)\n{\n  struct dwarf_buf unit_buf;\n  uint64_t code;\n  const struct abbrev *abbrev;\n  const char *ret;\n  size_t i;\n\n  /* OFFSET is from the start of the data for this compilation unit.\n     U->unit_data is the data, but it starts U->unit_data_offset bytes\n     from the beginning.  */\n\n  if (offset < u->unit_data_offset\n      || offset - u->unit_data_offset >= u->unit_data_len)\n    {\n      error_callback (data,\n\t\t      \"abstract origin or specification out of range\",\n\t\t      0);\n      return NULL;\n    }\n\n  offset -= u->unit_data_offset;\n\n  unit_buf.name = \".debug_info\";\n  unit_buf.start = ddata->dwarf_sections.data[DEBUG_INFO];\n  unit_buf.buf = u->unit_data + offset;\n  unit_buf.left = u->unit_data_len - offset;\n  unit_buf.is_bigendian = ddata->is_bigendian;\n  unit_buf.error_callback = error_callback;\n  unit_buf.data = data;\n  unit_buf.reported_underflow = 0;\n\n  code = read_uleb128 (&unit_buf);\n  if (code == 0)\n    {\n      dwarf_buf_error (&unit_buf,\n\t\t      \"invalid abstract origin or specification\",\n\t\t      0);\n      return NULL;\n    }\n\n  abbrev = lookup_abbrev (&u->abbrevs, code, error_callback, data);\n  if (abbrev == NULL)\n    return NULL;\n\n  ret = NULL;\n  for (i = 0; i < abbrev->num_attrs; ++i)\n    {\n      struct attr_val val;\n\n      if (!read_attribute (abbrev->attrs[i].form, abbrev->attrs[i].val,\n\t\t\t   &unit_buf, u->is_dwarf64, u->version, u->addrsize,\n\t\t\t   &ddata->dwarf_sections, ddata->altlink, &val))\n\treturn NULL;\n\n      switch (abbrev->attrs[i].name)\n\t{\n\tcase DW_AT_name:\n\t  /* Third name preference: don't override.  A name we found in some\n\t     other way, will normally be more useful -- e.g., this name is\n\t     normally not mangled.  */\n\t  if (ret != NULL)\n\t    break;\n\t  if (!resolve_string (&ddata->dwarf_sections, u->is_dwarf64,\n\t\t\t       ddata->is_bigendian, u->str_offsets_base,\n\t\t\t       &val, error_callback, data, &ret))\n\t    return NULL;\n\t  break;\n\n\tcase DW_AT_linkage_name:\n\tcase DW_AT_MIPS_linkage_name:\n\t  /* First name preference: override all.  */\n\t  {\n\t    const char *s;\n\n\t    s = NULL;\n\t    if (!resolve_string (&ddata->dwarf_sections, u->is_dwarf64,\n\t\t\t\t ddata->is_bigendian, u->str_offsets_base,\n\t\t\t\t &val, error_callback, data, &s))\n\t      return NULL;\n\t    if (s != NULL)\n\t      return s;\n\t  }\n\t  break;\n\n\tcase DW_AT_specification:\n\t  /* Second name preference: override DW_AT_name, don't override\n\t     DW_AT_linkage_name.  */\n\t  {\n\t    const char *name;\n\n\t    name = read_referenced_name_from_attr (ddata, u, &abbrev->attrs[i],\n\t\t\t\t\t\t   &val, error_callback, data);\n\t    if (name != NULL)\n\t      ret = name;\n\t  }\n\t  break;\n\n\tdefault:\n\t  break;\n\t}\n    }\n\n  return ret;\n}\n\n/* Add a range to a unit that maps to a function.  This is called via\n   add_ranges.  Returns 1 on success, 0 on error.  */\n\nstatic int\nadd_function_range (struct backtrace_state *state, void *rdata,\n\t\t    uintptr_t lowpc, uintptr_t highpc,\n\t\t    backtrace_error_callback error_callback, void *data,\n\t\t    void *pvec)\n{\n  struct function *function = (struct function *) rdata;\n  struct function_vector *vec = (struct function_vector *) pvec;\n  struct function_addrs *p;\n\n  if (vec->count > 0)\n    {\n      p = (struct function_addrs *) vec->vec.base + (vec->count - 1);\n      if ((lowpc == p->high || lowpc == p->high + 1)\n\t  && function == p->function)\n\t{\n\t  if (highpc > p->high)\n\t    p->high = highpc;\n\t  return 1;\n\t}\n    }\n\n  p = ((struct function_addrs *)\n       backtrace_vector_grow (state, sizeof (struct function_addrs),\n\t\t\t      error_callback, data, &vec->vec));\n  if (p == NULL)\n    return 0;\n\n  p->low = lowpc;\n  p->high = highpc;\n  p->function = function;\n\n  ++vec->count;\n\n  return 1;\n}\n\n/* Read one entry plus all its children.  Add function addresses to\n   VEC.  Returns 1 on success, 0 on error.  */\n\nstatic int\nread_function_entry (struct backtrace_state *state, struct dwarf_data *ddata,\n\t\t     struct unit *u, uintptr_t base, struct dwarf_buf *unit_buf,\n\t\t     const struct line_header *lhdr,\n\t\t     backtrace_error_callback error_callback, void *data,\n\t\t     struct function_vector *vec_function,\n\t\t     struct function_vector *vec_inlined)\n{\n  while (unit_buf->left > 0)\n    {\n      uint64_t code;\n      const struct abbrev *abbrev;\n      int is_function;\n      struct function *function;\n      struct function_vector *vec;\n      size_t i;\n      struct pcrange pcrange;\n      int have_linkage_name;\n\n      code = read_uleb128 (unit_buf);\n      if (code == 0)\n\treturn 1;\n\n      abbrev = lookup_abbrev (&u->abbrevs, code, error_callback, data);\n      if (abbrev == NULL)\n\treturn 0;\n\n      is_function = (abbrev->tag == DW_TAG_subprogram\n\t\t     || abbrev->tag == DW_TAG_entry_point\n\t\t     || abbrev->tag == DW_TAG_inlined_subroutine);\n\n      if (abbrev->tag == DW_TAG_inlined_subroutine)\n\tvec = vec_inlined;\n      else\n\tvec = vec_function;\n\n      function = NULL;\n      if (is_function)\n\t{\n\t  function = ((struct function *)\n\t\t      backtrace_alloc (state, sizeof *function,\n\t\t\t\t       error_callback, data));\n\t  if (function == NULL)\n\t    return 0;\n\t  memset (function, 0, sizeof *function);\n\t}\n\n      memset (&pcrange, 0, sizeof pcrange);\n      have_linkage_name = 0;\n      for (i = 0; i < abbrev->num_attrs; ++i)\n\t{\n\t  struct attr_val val;\n\n\t  if (!read_attribute (abbrev->attrs[i].form, abbrev->attrs[i].val,\n\t\t\t       unit_buf, u->is_dwarf64, u->version,\n\t\t\t       u->addrsize, &ddata->dwarf_sections,\n\t\t\t       ddata->altlink, &val))\n\t    return 0;\n\n\t  /* The compile unit sets the base address for any address\n\t     ranges in the function entries.  */\n\t  if ((abbrev->tag == DW_TAG_compile_unit\n\t       || abbrev->tag == DW_TAG_skeleton_unit)\n\t      && abbrev->attrs[i].name == DW_AT_low_pc)\n\t    {\n\t      if (val.encoding == ATTR_VAL_ADDRESS)\n\t\tbase = (uintptr_t) val.u.uint;\n\t      else if (val.encoding == ATTR_VAL_ADDRESS_INDEX)\n\t\t{\n\t\t  if (!resolve_addr_index (&ddata->dwarf_sections,\n\t\t\t\t\t   u->addr_base, u->addrsize,\n\t\t\t\t\t   ddata->is_bigendian, val.u.uint,\n\t\t\t\t\t   error_callback, data, &base))\n\t\t    return 0;\n\t\t}\n\t    }\n\n\t  if (is_function)\n\t    {\n\t      switch (abbrev->attrs[i].name)\n\t\t{\n\t\tcase DW_AT_call_file:\n\t\t  if (val.encoding == ATTR_VAL_UINT)\n\t\t    {\n\t\t      if (val.u.uint >= lhdr->filenames_count)\n\t\t\t{\n\t\t\t  dwarf_buf_error (unit_buf,\n\t\t\t\t\t   (\"invalid file number in \"\n\t\t\t\t\t    \"DW_AT_call_file attribute\"),\n\t\t\t\t\t   0);\n\t\t\t  return 0;\n\t\t\t}\n\t\t      function->caller_filename = lhdr->filenames[val.u.uint];\n\t\t    }\n\t\t  break;\n\n\t\tcase DW_AT_call_line:\n\t\t  if (val.encoding == ATTR_VAL_UINT)\n\t\t    function->caller_lineno = val.u.uint;\n\t\t  break;\n\n\t\tcase DW_AT_abstract_origin:\n\t\tcase DW_AT_specification:\n\t\t  /* Second name preference: override DW_AT_name, don't override\n\t\t     DW_AT_linkage_name.  */\n\t\t  if (have_linkage_name)\n\t\t    break;\n\t\t  {\n\t\t    const char *name;\n\n\t\t    name\n\t\t      = read_referenced_name_from_attr (ddata, u,\n\t\t\t\t\t\t\t&abbrev->attrs[i], &val,\n\t\t\t\t\t\t\terror_callback, data);\n\t\t    if (name != NULL)\n\t\t      function->name = name;\n\t\t  }\n\t\t  break;\n\n\t\tcase DW_AT_name:\n\t\t  /* Third name preference: don't override.  */\n\t\t  if (function->name != NULL)\n\t\t    break;\n\t\t  if (!resolve_string (&ddata->dwarf_sections, u->is_dwarf64,\n\t\t\t\t       ddata->is_bigendian,\n\t\t\t\t       u->str_offsets_base, &val,\n\t\t\t\t       error_callback, data, &function->name))\n\t\t    return 0;\n\t\t  break;\n\n\t\tcase DW_AT_linkage_name:\n\t\tcase DW_AT_MIPS_linkage_name:\n\t\t  /* First name preference: override all.  */\n\t\t  {\n\t\t    const char *s;\n\n\t\t    s = NULL;\n\t\t    if (!resolve_string (&ddata->dwarf_sections, u->is_dwarf64,\n\t\t\t\t\t ddata->is_bigendian,\n\t\t\t\t\t u->str_offsets_base, &val,\n\t\t\t\t\t error_callback, data, &s))\n\t\t      return 0;\n\t\t    if (s != NULL)\n\t\t      {\n\t\t\tfunction->name = s;\n\t\t\thave_linkage_name = 1;\n\t\t      }\n\t\t  }\n\t\t  break;\n\n\t\tcase DW_AT_low_pc: case DW_AT_high_pc: case DW_AT_ranges:\n\t\t  update_pcrange (&abbrev->attrs[i], &val, &pcrange);\n\t\t  break;\n\n\t\tdefault:\n\t\t  break;\n\t\t}\n\t    }\n\t}\n\n      /* If we couldn't find a name for the function, we have no use\n\t for it.  */\n      if (is_function && function->name == NULL)\n\t{\n\t  backtrace_free (state, function, sizeof *function,\n\t\t\t  error_callback, data);\n\t  is_function = 0;\n\t}\n\n      if (is_function)\n\t{\n\t  if (pcrange.have_ranges\n\t      || (pcrange.have_lowpc && pcrange.have_highpc))\n\t    {\n\t      if (!add_ranges (state, &ddata->dwarf_sections,\n\t\t\t       ddata->base_address, ddata->is_bigendian,\n\t\t\t       u, base, &pcrange, add_function_range,\n\t\t\t       (void *) function, error_callback, data,\n\t\t\t       (void *) vec))\n\t\treturn 0;\n\t    }\n\t  else\n\t    {\n\t      backtrace_free (state, function, sizeof *function,\n\t\t\t      error_callback, data);\n\t      is_function = 0;\n\t    }\n\t}\n\n      if (abbrev->has_children)\n\t{\n\t  if (!is_function)\n\t    {\n\t      if (!read_function_entry (state, ddata, u, base, unit_buf, lhdr,\n\t\t\t\t\terror_callback, data, vec_function,\n\t\t\t\t\tvec_inlined))\n\t\treturn 0;\n\t    }\n\t  else\n\t    {\n\t      struct function_vector fvec;\n\n\t      /* Gather any information for inlined functions in\n\t\t FVEC.  */\n\n\t      memset (&fvec, 0, sizeof fvec);\n\n\t      if (!read_function_entry (state, ddata, u, base, unit_buf, lhdr,\n\t\t\t\t\terror_callback, data, vec_function,\n\t\t\t\t\t&fvec))\n\t\treturn 0;\n\n\t      if (fvec.count > 0)\n\t\t{\n\t\t  struct function_addrs *p;\n\t\t  struct function_addrs *faddrs;\n\n\t\t  /* Allocate a trailing entry, but don't include it\n\t\t     in fvec.count.  */\n\t\t  p = ((struct function_addrs *)\n\t\t       backtrace_vector_grow (state,\n\t\t\t\t\t      sizeof (struct function_addrs),\n\t\t\t\t\t      error_callback, data,\n\t\t\t\t\t      &fvec.vec));\n\t\t  if (p == NULL)\n\t\t    return 0;\n\t\t  p->low = 0;\n\t\t  --p->low;\n\t\t  p->high = p->low;\n\t\t  p->function = NULL;\n\n\t\t  if (!backtrace_vector_release (state, &fvec.vec,\n\t\t\t\t\t\t error_callback, data))\n\t\t    return 0;\n\n\t\t  faddrs = (struct function_addrs *) fvec.vec.base;\n\t\t  backtrace_qsort (faddrs, fvec.count,\n\t\t\t\t   sizeof (struct function_addrs),\n\t\t\t\t   function_addrs_compare);\n\n\t\t  function->function_addrs = faddrs;\n\t\t  function->function_addrs_count = fvec.count;\n\t\t}\n\t    }\n\t}\n    }\n\n  return 1;\n}\n\n/* Read function name information for a compilation unit.  We look\n   through the whole unit looking for function tags.  */\n\nstatic void\nread_function_info (struct backtrace_state *state, struct dwarf_data *ddata,\n\t\t    const struct line_header *lhdr,\n\t\t    backtrace_error_callback error_callback, void *data,\n\t\t    struct unit *u, struct function_vector *fvec,\n\t\t    struct function_addrs **ret_addrs,\n\t\t    size_t *ret_addrs_count)\n{\n  struct function_vector lvec;\n  struct function_vector *pfvec;\n  struct dwarf_buf unit_buf;\n  struct function_addrs *p;\n  struct function_addrs *addrs;\n  size_t addrs_count;\n\n  /* Use FVEC if it is not NULL.  Otherwise use our own vector.  */\n  if (fvec != NULL)\n    pfvec = fvec;\n  else\n    {\n      memset (&lvec, 0, sizeof lvec);\n      pfvec = &lvec;\n    }\n\n  unit_buf.name = \".debug_info\";\n  unit_buf.start = ddata->dwarf_sections.data[DEBUG_INFO];\n  unit_buf.buf = u->unit_data;\n  unit_buf.left = u->unit_data_len;\n  unit_buf.is_bigendian = ddata->is_bigendian;\n  unit_buf.error_callback = error_callback;\n  unit_buf.data = data;\n  unit_buf.reported_underflow = 0;\n\n  while (unit_buf.left > 0)\n    {\n      if (!read_function_entry (state, ddata, u, 0, &unit_buf, lhdr,\n\t\t\t\terror_callback, data, pfvec, pfvec))\n\treturn;\n    }\n\n  if (pfvec->count == 0)\n    return;\n\n  /* Allocate a trailing entry, but don't include it in\n     pfvec->count.  */\n  p = ((struct function_addrs *)\n       backtrace_vector_grow (state, sizeof (struct function_addrs),\n\t\t\t      error_callback, data, &pfvec->vec));\n  if (p == NULL)\n    return;\n  p->low = 0;\n  --p->low;\n  p->high = p->low;\n  p->function = NULL;\n\n  addrs_count = pfvec->count;\n\n  if (fvec == NULL)\n    {\n      if (!backtrace_vector_release (state, &lvec.vec, error_callback, data))\n\treturn;\n      addrs = (struct function_addrs *) pfvec->vec.base;\n    }\n  else\n    {\n      /* Finish this list of addresses, but leave the remaining space in\n\t the vector available for the next function unit.  */\n      addrs = ((struct function_addrs *)\n\t       backtrace_vector_finish (state, &fvec->vec,\n\t\t\t\t\terror_callback, data));\n      if (addrs == NULL)\n\treturn;\n      fvec->count = 0;\n    }\n\n  backtrace_qsort (addrs, addrs_count, sizeof (struct function_addrs),\n\t\t   function_addrs_compare);\n\n  *ret_addrs = addrs;\n  *ret_addrs_count = addrs_count;\n}\n\n/* See if PC is inlined in FUNCTION.  If it is, print out the inlined\n   information, and update FILENAME and LINENO for the caller.\n   Returns whatever CALLBACK returns, or 0 to keep going.  */\n\nstatic int\nreport_inlined_functions (uintptr_t pc, struct function *function, const char* comp_dir,\n\t\t\t  backtrace_full_callback callback, void *data,\n\t\t\t  const char **filename, int *lineno)\n{\n  struct function_addrs *p;\n  struct function_addrs *match;\n  struct function *inlined;\n  int ret;\n\n  if (function->function_addrs_count == 0)\n    return 0;\n\n  /* Our search isn't safe if pc == -1, as that is the sentinel\n     value.  */\n  if (pc + 1 == 0)\n    return 0;\n\n  p = ((struct function_addrs *)\n       bsearch (&pc, function->function_addrs,\n\t\tfunction->function_addrs_count,\n\t\tsizeof (struct function_addrs),\n\t\tfunction_addrs_search));\n  if (p == NULL)\n    return 0;\n\n  /* Here pc >= p->low && pc < (p + 1)->low.  The function_addrs are\n     sorted by low, so if pc > p->low we are at the end of a range of\n     function_addrs with the same low value.  If pc == p->low walk\n     forward to the end of the range with that low value.  Then walk\n     backward and use the first range that includes pc.  */\n  while (pc == (p + 1)->low)\n    ++p;\n  match = NULL;\n  while (1)\n    {\n      if (pc < p->high)\n\t{\n\t  match = p;\n\t  break;\n\t}\n      if (p == function->function_addrs)\n\tbreak;\n      if ((p - 1)->low < p->low)\n\tbreak;\n      --p;\n    }\n  if (match == NULL)\n    return 0;\n\n  /* We found an inlined call.  */\n\n  inlined = match->function;\n\n  /* Report any calls inlined into this one.  */\n  ret = report_inlined_functions (pc, inlined, comp_dir, callback, data,\n\t\t\t\t  filename, lineno);\n  if (ret != 0)\n    return ret;\n\n  /* Report this inlined call.  */\n  if (*filename[0] != '/' && comp_dir)\n  {\n    char buf[1024];\n    snprintf (buf, 1024, \"%s/%s\", comp_dir, *filename);\n    ret = callback (data, pc, match->low, buf, *lineno, inlined->name);\n  }\n  else\n  {\n    ret = callback (data, pc, match->low, *filename, *lineno, inlined->name);\n  }\n  if (ret != 0)\n    return ret;\n\n  /* Our caller will report the caller of the inlined function; tell\n     it the appropriate filename and line number.  */\n  *filename = inlined->caller_filename;\n  *lineno = inlined->caller_lineno;\n\n  return 0;\n}\n\n/* Look for a PC in the DWARF mapping for one module.  On success,\n   call CALLBACK and return whatever it returns.  On error, call\n   ERROR_CALLBACK and return 0.  Sets *FOUND to 1 if the PC is found,\n   0 if not.  */\n\nstatic int\ndwarf_lookup_pc (struct backtrace_state *state, struct dwarf_data *ddata,\n\t\t uintptr_t pc, backtrace_full_callback callback,\n\t\t backtrace_error_callback error_callback, void *data,\n\t\t int *found)\n{\n  struct unit_addrs *entry;\n  int found_entry;\n  struct unit *u;\n  int new_data;\n  struct line *lines;\n  struct line *ln;\n  struct function_addrs *p;\n  struct function_addrs *fmatch;\n  struct function *function;\n  const char *filename;\n  int lineno;\n  int ret;\n\n  *found = 1;\n\n  /* Find an address range that includes PC.  Our search isn't safe if\n     PC == -1, as we use that as a sentinel value, so skip the search\n     in that case.  */\n  entry = (ddata->addrs_count == 0 || pc + 1 == 0\n\t   ? NULL\n\t   : (struct unit_addrs*)bsearch (&pc, ddata->addrs, ddata->addrs_count,\n\t\t      sizeof (struct unit_addrs), unit_addrs_search));\n\n  if (entry == NULL)\n    {\n      *found = 0;\n      return 0;\n    }\n\n  /* Here pc >= entry->low && pc < (entry + 1)->low.  The unit_addrs\n     are sorted by low, so if pc > p->low we are at the end of a range\n     of unit_addrs with the same low value.  If pc == p->low walk\n     forward to the end of the range with that low value.  Then walk\n     backward and use the first range that includes pc.  */\n  while (pc == (entry + 1)->low)\n    ++entry;\n  found_entry = 0;\n  while (1)\n    {\n      if (pc < entry->high)\n\t{\n\t  found_entry = 1;\n\t  break;\n\t}\n      if (entry == ddata->addrs)\n\tbreak;\n      if ((entry - 1)->low < entry->low)\n\tbreak;\n      --entry;\n    }\n  if (!found_entry)\n    {\n      *found = 0;\n      return 0;\n    }\n\n  /* We need the lines, lines_count, function_addrs,\n     function_addrs_count fields of u.  If they are not set, we need\n     to set them.  When running in threaded mode, we need to allow for\n     the possibility that some other thread is setting them\n     simultaneously.  */\n\n  u = entry->u;\n  lines = u->lines;\n\n  /* Skip units with no useful line number information by walking\n     backward.  Useless line number information is marked by setting\n     lines == -1.  */\n  while (entry > ddata->addrs\n\t && pc >= (entry - 1)->low\n\t && pc < (entry - 1)->high)\n    {\n      if (state->threaded)\n\tlines = (struct line *) backtrace_atomic_load_pointer (&u->lines);\n\n      if (lines != (struct line *) (uintptr_t) -1)\n\tbreak;\n\n      --entry;\n\n      u = entry->u;\n      lines = u->lines;\n    }\n\n  if (state->threaded)\n    lines = backtrace_atomic_load_pointer (&u->lines);\n\n  new_data = 0;\n  if (lines == NULL)\n    {\n      struct function_addrs *function_addrs;\n      size_t function_addrs_count;\n      struct line_header lhdr;\n      size_t count;\n\n      /* We have never read the line information for this unit.  Read\n\t it now.  */\n\n      function_addrs = NULL;\n      function_addrs_count = 0;\n      if (read_line_info (state, ddata, error_callback, data, entry->u, &lhdr,\n\t\t\t  &lines, &count))\n\t{\n\t  struct function_vector *pfvec;\n\n\t  /* If not threaded, reuse DDATA->FVEC for better memory\n\t     consumption.  */\n\t  if (state->threaded)\n\t    pfvec = NULL;\n\t  else\n\t    pfvec = &ddata->fvec;\n\t  read_function_info (state, ddata, &lhdr, error_callback, data,\n\t\t\t      entry->u, pfvec, &function_addrs,\n\t\t\t      &function_addrs_count);\n\t  free_line_header (state, &lhdr, error_callback, data);\n\t  new_data = 1;\n\t}\n\n      /* Atomically store the information we just read into the unit.\n\t If another thread is simultaneously writing, it presumably\n\t read the same information, and we don't care which one we\n\t wind up with; we just leak the other one.  We do have to\n\t write the lines field last, so that the acquire-loads above\n\t ensure that the other fields are set.  */\n\n      if (!state->threaded)\n\t{\n\t  u->lines_count = count;\n\t  u->function_addrs = function_addrs;\n\t  u->function_addrs_count = function_addrs_count;\n\t  u->lines = lines;\n\t}\n      else\n\t{\n\t  backtrace_atomic_store_size_t (&u->lines_count, count);\n\t  backtrace_atomic_store_pointer (&u->function_addrs, function_addrs);\n\t  backtrace_atomic_store_size_t (&u->function_addrs_count,\n\t\t\t\t\t function_addrs_count);\n\t  backtrace_atomic_store_pointer (&u->lines, lines);\n\t}\n    }\n\n  /* Now all fields of U have been initialized.  */\n\n  if (lines == (struct line *) (uintptr_t) -1)\n    {\n      /* If reading the line number information failed in some way,\n\t try again to see if there is a better compilation unit for\n\t this PC.  */\n      if (new_data)\n\treturn dwarf_lookup_pc (state, ddata, pc, callback, error_callback,\n\t\t\t\tdata, found);\n      return callback (data, pc, 0, NULL, 0, NULL);\n    }\n\n  /* Search for PC within this unit.  */\n\n  ln = (struct line *) bsearch (&pc, lines, entry->u->lines_count,\n\t\t\t\tsizeof (struct line), line_search);\n  if (ln == NULL)\n    {\n      /* The PC is between the low_pc and high_pc attributes of the\n\t compilation unit, but no entry in the line table covers it.\n\t This implies that the start of the compilation unit has no\n\t line number information.  */\n\n      if (entry->u->abs_filename == NULL)\n\t{\n\t  const char *filename;\n\n\t  filename = entry->u->filename;\n\t  if (filename != NULL\n\t      && !IS_ABSOLUTE_PATH (filename)\n\t      && entry->u->comp_dir != NULL)\n\t    {\n\t      size_t filename_len;\n\t      const char *dir;\n\t      size_t dir_len;\n\t      char *s;\n\n\t      filename_len = strlen (filename);\n\t      dir = entry->u->comp_dir;\n\t      dir_len = strlen (dir);\n\t      s = (char *) backtrace_alloc (state, dir_len + filename_len + 2,\n\t\t\t\t\t    error_callback, data);\n\t      if (s == NULL)\n\t\t{\n\t\t  *found = 0;\n\t\t  return 0;\n\t\t}\n\t      memcpy (s, dir, dir_len);\n\t      /* FIXME: Should use backslash if DOS file system.  */\n\t      s[dir_len] = '/';\n\t      memcpy (s + dir_len + 1, filename, filename_len + 1);\n\t      filename = s;\n\t    }\n\t  entry->u->abs_filename = filename;\n\t}\n\n      return callback (data, pc, 0, entry->u->abs_filename, 0, NULL);\n    }\n\n  /* Search for function name within this unit.  */\n\n  if (entry->u->function_addrs_count == 0)\n    return callback (data, pc, 0, ln->filename, ln->lineno, NULL);\n\n  p = ((struct function_addrs *)\n       bsearch (&pc, entry->u->function_addrs,\n\t\tentry->u->function_addrs_count,\n\t\tsizeof (struct function_addrs),\n\t\tfunction_addrs_search));\n  if (p == NULL)\n    return callback (data, pc, 0, ln->filename, ln->lineno, NULL);\n\n  /* Here pc >= p->low && pc < (p + 1)->low.  The function_addrs are\n     sorted by low, so if pc > p->low we are at the end of a range of\n     function_addrs with the same low value.  If pc == p->low walk\n     forward to the end of the range with that low value.  Then walk\n     backward and use the first range that includes pc.  */\n  while (pc == (p + 1)->low)\n    ++p;\n  fmatch = NULL;\n  while (1)\n    {\n      if (pc < p->high)\n\t{\n\t  fmatch = p;\n\t  break;\n\t}\n      if (p == entry->u->function_addrs)\n\tbreak;\n      if ((p - 1)->low < p->low)\n\tbreak;\n      --p;\n    }\n  if (fmatch == NULL)\n    return callback (data, pc, 0, ln->filename, ln->lineno, NULL);\n\n  function = fmatch->function;\n\n  filename = ln->filename;\n  lineno = ln->lineno;\n\n  ret = report_inlined_functions (pc, function, entry->u->comp_dir, callback, data,\n\t\t\t\t  &filename, &lineno);\n  if (ret != 0)\n    return ret;\n\n  if (filename[0] != '/' && entry->u->comp_dir)\n  {\n    char buf[1024];\n    snprintf (buf, 1024, \"%s/%s\", entry->u->comp_dir, filename);\n    return callback (data, pc, fmatch->low, buf, lineno, function->name);\n  }\n  else\n  {\n    return callback (data, pc, fmatch->low, filename, lineno, function->name);\n  }\n}\n\nbool dwarf_fileline_dwarf_lookup_pc_in_all_entries(struct backtrace_state *state, uintptr_t pc,\n      backtrace_full_callback callback, backtrace_error_callback error_callback, void *data,\n      int& found, int ret)\n{\n    for (struct dwarf_data* ddata = (struct dwarf_data *)state->fileline_data;\n         ddata != NULL;\n         ddata = ddata->next)\n    {\n      ret = dwarf_lookup_pc(state, ddata, pc, callback, error_callback, data, &found);\n      if (ret != 0 || found) return true;\n    }\n    return false;\n}\n\n/* Return the file/line information for a PC using the DWARF mapping\n   we built earlier.  */\n\nstatic int\ndwarf_fileline (struct backtrace_state *state, uintptr_t pc,\n\t\tbacktrace_full_callback callback,\n\t\tbacktrace_error_callback error_callback, void *data)\n{\n  struct dwarf_data *ddata;\n  int found;\n  int ret = 0;\n\n  if (!state->threaded)\n  {\n    if (dwarf_fileline_dwarf_lookup_pc_in_all_entries(state, pc, callback, error_callback, data, found, ret))\n    {\n       return ret;\n    }\n\n    // if we failed to obtain an entry in range, it can mean that the address map has been changed and new entries\n    //  have been loaded in the meantime. Request a refresh and try again.\n    if (state->request_known_address_ranges_refresh_fn)\n    {\n        int new_range_count = state->request_known_address_ranges_refresh_fn(state, pc);\n        if (new_range_count > 0)\n        {\n          if (dwarf_fileline_dwarf_lookup_pc_in_all_entries(state, pc, callback, error_callback, data, found, ret))\n          {\n            return ret;\n          }\n        }\n    }\n\n  }\n  else\n    {\n      struct dwarf_data **pp;\n\n      pp = (struct dwarf_data **) (void *) &state->fileline_data;\n      while (1)\n\t{\n\t  ddata = backtrace_atomic_load_pointer (pp);\n\t  if (ddata == NULL)\n\t    break;\n\n\t  ret = dwarf_lookup_pc (state, ddata, pc, callback, error_callback,\n\t\t\t\t data, &found);\n\t  if (ret != 0 || found)\n\t    return ret;\n\n\t  pp = &ddata->next;\n\t}\n    }\n\n  /* FIXME: See if any libraries have been dlopen'ed.  */\n\n  return callback (data, pc, 0, NULL, 0, NULL);\n}\n\n/* Initialize our data structures from the DWARF debug info for a\n   file.  Return NULL on failure.  */\n\nstatic struct dwarf_data *\nbuild_dwarf_data (struct backtrace_state *state,\n\t\t  struct libbacktrace_base_address base_address,\n\t\t  const struct dwarf_sections *dwarf_sections,\n\t\t  int is_bigendian,\n\t\t  struct dwarf_data *altlink,\n\t\t  backtrace_error_callback error_callback,\n\t\t  void *data)\n{\n  struct unit_addrs_vector addrs_vec;\n  struct unit_addrs *addrs;\n  size_t addrs_count;\n  struct unit_vector units_vec;\n  struct unit **units;\n  size_t units_count;\n  struct dwarf_data *fdata;\n\n  if (!build_address_map (state, base_address, dwarf_sections, is_bigendian,\n\t\t\t  altlink, error_callback, data, &addrs_vec,\n\t\t\t  &units_vec))\n    return NULL;\n\n  if (!backtrace_vector_release (state, &addrs_vec.vec, error_callback, data))\n    return NULL;\n  if (!backtrace_vector_release (state, &units_vec.vec, error_callback, data))\n    return NULL;\n  addrs = (struct unit_addrs *) addrs_vec.vec.base;\n  units = (struct unit **) units_vec.vec.base;\n  addrs_count = addrs_vec.count;\n  units_count = units_vec.count;\n  backtrace_qsort (addrs, addrs_count, sizeof (struct unit_addrs),\n\t\t   unit_addrs_compare);\n  /* No qsort for units required, already sorted.  */\n\n  fdata = ((struct dwarf_data *)\n\t   backtrace_alloc (state, sizeof (struct dwarf_data),\n\t\t\t    error_callback, data));\n  if (fdata == NULL)\n    return NULL;\n\n  fdata->next = NULL;\n  fdata->altlink = altlink;\n  fdata->base_address = base_address;\n  fdata->addrs = addrs;\n  fdata->addrs_count = addrs_count;\n  fdata->units = units;\n  fdata->units_count = units_count;\n  fdata->dwarf_sections = *dwarf_sections;\n  fdata->is_bigendian = is_bigendian;\n  memset (&fdata->fvec, 0, sizeof fdata->fvec);\n\n  return fdata;\n}\n\n/* Build our data structures from the DWARF sections for a module.\n   Set FILELINE_FN and STATE->FILELINE_DATA.  Return 1 on success, 0\n   on failure.  */\n\nint\nbacktrace_dwarf_add (struct backtrace_state *state,\n\t\t     struct libbacktrace_base_address base_address,\n\t\t     const struct dwarf_sections *dwarf_sections,\n\t\t     int is_bigendian,\n\t\t     struct dwarf_data *fileline_altlink,\n\t\t     backtrace_error_callback error_callback,\n\t\t     void *data, fileline *fileline_fn,\n\t\t     struct dwarf_data **fileline_entry)\n{\n  struct dwarf_data *fdata;\n\n  fdata = build_dwarf_data (state, base_address, dwarf_sections, is_bigendian,\n\t\t\t    fileline_altlink, error_callback, data);\n  if (fdata == NULL)\n    return 0;\n\n  if (fileline_entry != NULL)\n    *fileline_entry = fdata;\n\n  if (!state->threaded)\n    {\n      struct dwarf_data **pp;\n\n      for (pp = (struct dwarf_data **) (void *) &state->fileline_data;\n\t   *pp != NULL;\n\t   pp = &(*pp)->next)\n\t;\n      *pp = fdata;\n    }\n  else\n    {\n      while (1)\n\t{\n\t  struct dwarf_data **pp;\n\n\t  pp = (struct dwarf_data **) (void *) &state->fileline_data;\n\n\t  while (1)\n\t    {\n\t      struct dwarf_data *p;\n\n\t      p = backtrace_atomic_load_pointer (pp);\n\n\t      if (p == NULL)\n\t\tbreak;\n\n\t      pp = &p->next;\n\t    }\n\n\t  if (__sync_bool_compare_and_swap (pp, NULL, fdata))\n\t    break;\n\t}\n    }\n\n  *fileline_fn = dwarf_fileline;\n\n  return 1;\n}\n\n}\n"
  },
  {
    "path": "tracy-client-sys/tracy/libbacktrace/elf.cpp",
    "content": "/* elf.c -- Get debug data from an ELF file for backtraces.\n   Copyright (C) 2012-2021 Free Software Foundation, Inc.\n   Written by Ian Lance Taylor, Google.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n    (1) Redistributions of source code must retain the above copyright\n    notice, this list of conditions and the following disclaimer.\n\n    (2) Redistributions in binary form must reproduce the above copyright\n    notice, this list of conditions and the following disclaimer in\n    the documentation and/or other materials provided with the\n    distribution.\n\n    (3) The name of the author may not be used to\n    endorse or promote products derived from this software without\n    specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\nIMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\nWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,\nINDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\nHOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\nSTRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\nIN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGE.  */\n\n#include \"config.h\"\n\n#include <errno.h>\n#include <stdlib.h>\n#include <string.h>\n#include <sys/types.h>\n#include <sys/stat.h>\n#include <unistd.h>\n#include <algorithm>\n\n#ifdef HAVE_DL_ITERATE_PHDR\n#include <link.h>\n#endif\n\n#include \"backtrace.hpp\"\n#include \"internal.hpp\"\n\n#include \"../client/TracyFastVector.hpp\"\n#include \"../common/TracyAlloc.hpp\"\n\n#ifndef S_ISLNK\n #ifndef S_IFLNK\n  #define S_IFLNK 0120000\n #endif\n #ifndef S_IFMT\n  #define S_IFMT 0170000\n #endif\n #define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)\n#endif\n\n#ifndef __GNUC__\n#define __builtin_prefetch(p, r, l)\n#ifndef unlikely\n#define unlikely(x) (x)\n#endif\n#else\n#ifndef unlikely\n#define unlikely(x) __builtin_expect(!!(x), 0)\n#endif\n#endif\n\nnamespace tracy\n{\n\n#ifdef TRACY_DEBUGINFOD\nint GetDebugInfoDescriptor( const char* buildid_data, size_t buildid_size, const char* filename );\n#endif\n\n#if !defined(HAVE_DECL_STRNLEN) || !HAVE_DECL_STRNLEN\n\n/* If strnlen is not declared, provide our own version.  */\n\nstatic size_t\nxstrnlen (const char *s, size_t maxlen)\n{\n  size_t i;\n\n  for (i = 0; i < maxlen; ++i)\n    if (s[i] == '\\0')\n      break;\n  return i;\n}\n\n#define strnlen xstrnlen\n\n#endif\n\n#ifndef HAVE_LSTAT\n\n/* Dummy version of lstat for systems that don't have it.  */\n\nstatic int\nxlstat (const char *path ATTRIBUTE_UNUSED, struct stat *st ATTRIBUTE_UNUSED)\n{\n  return -1;\n}\n\n#define lstat xlstat\n\n#endif\n\n#ifndef HAVE_READLINK\n\n/* Dummy version of readlink for systems that don't have it.  */\n\nstatic ssize_t\nxreadlink (const char *path ATTRIBUTE_UNUSED, char *buf ATTRIBUTE_UNUSED,\n\t   size_t bufsz ATTRIBUTE_UNUSED)\n{\n  return -1;\n}\n\n#define readlink xreadlink\n\n#endif\n\n#ifndef HAVE_DL_ITERATE_PHDR\n\n/* Dummy version of dl_iterate_phdr for systems that don't have it.  */\n\n#define dl_phdr_info x_dl_phdr_info\n#define dl_iterate_phdr x_dl_iterate_phdr\n\nstruct dl_phdr_info\n{\n  uintptr_t dlpi_addr;\n  const char *dlpi_name;\n};\n\nstatic int\ndl_iterate_phdr (int (*callback) (struct dl_phdr_info *,\n\t\t\t\t  size_t, void *) ATTRIBUTE_UNUSED,\n\t\t void *data ATTRIBUTE_UNUSED)\n{\n  return 0;\n}\n\n#endif /* ! defined (HAVE_DL_ITERATE_PHDR) */\n\n/* The configure script must tell us whether we are 32-bit or 64-bit\n   ELF.  We could make this code test and support either possibility,\n   but there is no point.  This code only works for the currently\n   running executable, which means that we know the ELF mode at\n   configure time.  */\n\n#if BACKTRACE_ELF_SIZE != 32 && BACKTRACE_ELF_SIZE != 64\n#error \"Unknown BACKTRACE_ELF_SIZE\"\n#endif\n\n/* <link.h> might #include <elf.h> which might define our constants\n   with slightly different values.  Undefine them to be safe.  */\n\n#undef EI_NIDENT\n#undef EI_MAG0\n#undef EI_MAG1\n#undef EI_MAG2\n#undef EI_MAG3\n#undef EI_CLASS\n#undef EI_DATA\n#undef EI_VERSION\n#undef ELF_MAG0\n#undef ELF_MAG1\n#undef ELF_MAG2\n#undef ELF_MAG3\n#undef ELFCLASS32\n#undef ELFCLASS64\n#undef ELFDATA2LSB\n#undef ELFDATA2MSB\n#undef EV_CURRENT\n#undef ET_DYN\n#undef EM_PPC64\n#undef EF_PPC64_ABI\n#undef SHN_LORESERVE\n#undef SHN_XINDEX\n#undef SHN_UNDEF\n#undef SHT_PROGBITS\n#undef SHT_SYMTAB\n#undef SHT_STRTAB\n#undef SHT_DYNSYM\n#undef SHF_COMPRESSED\n#undef STT_OBJECT\n#undef STT_FUNC\n#undef NT_GNU_BUILD_ID\n#undef ELFCOMPRESS_ZLIB\n#undef ELFCOMPRESS_ZSTD\n\n/* Basic types.  */\n\ntypedef uint16_t b_elf_half;    /* Elf_Half.  */\ntypedef uint32_t b_elf_word;    /* Elf_Word.  */\ntypedef int32_t  b_elf_sword;   /* Elf_Sword.  */\n\n#if BACKTRACE_ELF_SIZE == 32\n\ntypedef uint32_t b_elf_addr;    /* Elf_Addr.  */\ntypedef uint32_t b_elf_off;     /* Elf_Off.  */\n\ntypedef uint32_t b_elf_wxword;  /* 32-bit Elf_Word, 64-bit ELF_Xword.  */\n\n#else\n\ntypedef uint64_t b_elf_addr;    /* Elf_Addr.  */\ntypedef uint64_t b_elf_off;     /* Elf_Off.  */\ntypedef uint64_t b_elf_xword;   /* Elf_Xword.  */\ntypedef int64_t  b_elf_sxword;  /* Elf_Sxword.  */\n\ntypedef uint64_t b_elf_wxword;  /* 32-bit Elf_Word, 64-bit ELF_Xword.  */\n\n#endif\n\n/* Data structures and associated constants.  */\n\n#define EI_NIDENT 16\n\ntypedef struct {\n  unsigned char\te_ident[EI_NIDENT];\t/* ELF \"magic number\" */\n  b_elf_half\te_type;\t\t\t/* Identifies object file type */\n  b_elf_half\te_machine;\t\t/* Specifies required architecture */\n  b_elf_word\te_version;\t\t/* Identifies object file version */\n  b_elf_addr\te_entry;\t\t/* Entry point virtual address */\n  b_elf_off\te_phoff;\t\t/* Program header table file offset */\n  b_elf_off\te_shoff;\t\t/* Section header table file offset */\n  b_elf_word\te_flags;\t\t/* Processor-specific flags */\n  b_elf_half\te_ehsize;\t\t/* ELF header size in bytes */\n  b_elf_half\te_phentsize;\t\t/* Program header table entry size */\n  b_elf_half\te_phnum;\t\t/* Program header table entry count */\n  b_elf_half\te_shentsize;\t\t/* Section header table entry size */\n  b_elf_half\te_shnum;\t\t/* Section header table entry count */\n  b_elf_half\te_shstrndx;\t\t/* Section header string table index */\n} b_elf_ehdr;  /* Elf_Ehdr.  */\n\n#define EI_MAG0 0\n#define EI_MAG1 1\n#define EI_MAG2 2\n#define EI_MAG3 3\n#define EI_CLASS 4\n#define EI_DATA 5\n#define EI_VERSION 6\n\n#define ELFMAG0 0x7f\n#define ELFMAG1 'E'\n#define ELFMAG2 'L'\n#define ELFMAG3 'F'\n\n#define ELFCLASS32 1\n#define ELFCLASS64 2\n\n#define ELFDATA2LSB 1\n#define ELFDATA2MSB 2\n\n#define EV_CURRENT 1\n\n#define ET_DYN 3\n\n#define EM_PPC64 21\n#define EF_PPC64_ABI 3\n\ntypedef struct {\n  b_elf_word\tsh_name;\t\t/* Section name, index in string tbl */\n  b_elf_word\tsh_type;\t\t/* Type of section */\n  b_elf_wxword\tsh_flags;\t\t/* Miscellaneous section attributes */\n  b_elf_addr\tsh_addr;\t\t/* Section virtual addr at execution */\n  b_elf_off\tsh_offset;\t\t/* Section file offset */\n  b_elf_wxword\tsh_size;\t\t/* Size of section in bytes */\n  b_elf_word\tsh_link;\t\t/* Index of another section */\n  b_elf_word\tsh_info;\t\t/* Additional section information */\n  b_elf_wxword\tsh_addralign;\t\t/* Section alignment */\n  b_elf_wxword\tsh_entsize;\t\t/* Entry size if section holds table */\n} b_elf_shdr;  /* Elf_Shdr.  */\n\n#define SHN_UNDEF\t0x0000\t\t/* Undefined section */\n#define SHN_LORESERVE\t0xFF00\t\t/* Begin range of reserved indices */\n#define SHN_XINDEX\t0xFFFF\t\t/* Section index is held elsewhere */\n\n#define SHT_PROGBITS 1\n#define SHT_SYMTAB 2\n#define SHT_STRTAB 3\n#define SHT_DYNSYM 11\n\n#define SHF_COMPRESSED 0x800\n\n#if BACKTRACE_ELF_SIZE == 32\n\ntypedef struct\n{\n  b_elf_word\tst_name;\t\t/* Symbol name, index in string tbl */\n  b_elf_addr\tst_value;\t\t/* Symbol value */\n  b_elf_word\tst_size;\t\t/* Symbol size */\n  unsigned char\tst_info;\t\t/* Symbol binding and type */\n  unsigned char\tst_other;\t\t/* Visibility and other data */\n  b_elf_half\tst_shndx;\t\t/* Symbol section index */\n} b_elf_sym;  /* Elf_Sym.  */\n\n#else /* BACKTRACE_ELF_SIZE != 32 */\n\ntypedef struct\n{\n  b_elf_word\tst_name;\t\t/* Symbol name, index in string tbl */\n  unsigned char\tst_info;\t\t/* Symbol binding and type */\n  unsigned char\tst_other;\t\t/* Visibility and other data */\n  b_elf_half\tst_shndx;\t\t/* Symbol section index */\n  b_elf_addr\tst_value;\t\t/* Symbol value */\n  b_elf_xword\tst_size;\t\t/* Symbol size */\n} b_elf_sym;  /* Elf_Sym.  */\n\n#endif /* BACKTRACE_ELF_SIZE != 32 */\n\n#define STT_OBJECT 1\n#define STT_FUNC 2\n\ntypedef struct\n{\n  uint32_t namesz;\n  uint32_t descsz;\n  uint32_t type;\n  char name[1];\n} b_elf_note;\n\n#define NT_GNU_BUILD_ID 3\n\n#if BACKTRACE_ELF_SIZE == 32\n\ntypedef struct\n{\n  b_elf_word\tch_type;\t\t/* Compresstion algorithm */\n  b_elf_word\tch_size;\t\t/* Uncompressed size */\n  b_elf_word\tch_addralign;\t\t/* Alignment for uncompressed data */\n} b_elf_chdr;  /* Elf_Chdr */\n\n#else /* BACKTRACE_ELF_SIZE != 32 */\n\ntypedef struct\n{\n  b_elf_word\tch_type;\t\t/* Compression algorithm */\n  b_elf_word\tch_reserved;\t\t/* Reserved */\n  b_elf_xword\tch_size;\t\t/* Uncompressed size */\n  b_elf_xword\tch_addralign;\t\t/* Alignment for uncompressed data */\n} b_elf_chdr;  /* Elf_Chdr */\n\n#endif /* BACKTRACE_ELF_SIZE != 32 */\n\n#define ELFCOMPRESS_ZLIB 1\n#define ELFCOMPRESS_ZSTD 2\n\n/* Names of sections, indexed by enum dwarf_section in internal.h.  */\n\nstatic const char * const dwarf_section_names[DEBUG_MAX] =\n{\n  \".debug_info\",\n  \".debug_line\",\n  \".debug_abbrev\",\n  \".debug_ranges\",\n  \".debug_str\",\n  \".debug_addr\",\n  \".debug_str_offsets\",\n  \".debug_line_str\",\n  \".debug_rnglists\"\n};\n\n/* Information we gather for the sections we care about.  */\n\nstruct debug_section_info\n{\n  /* Section file offset.  */\n  off_t offset;\n  /* Section size.  */\n  size_t size;\n  /* Section contents, after read from file.  */\n  const unsigned char *data;\n  /* Whether the SHF_COMPRESSED flag is set for the section.  */\n  int compressed;\n};\n\n/* Information we keep for an ELF symbol.  */\n\nstruct elf_symbol\n{\n  /* The name of the symbol.  */\n  const char *name;\n  /* The address of the symbol.  */\n  uintptr_t address;\n  /* The size of the symbol.  */\n  size_t size;\n};\n\n/* Information to pass to elf_syminfo.  */\n\nstruct elf_syminfo_data\n{\n  /* Symbols for the next module.  */\n  struct elf_syminfo_data *next;\n  /* The ELF symbols, sorted by address.  */\n  struct elf_symbol *symbols;\n  /* The number of symbols.  */\n  size_t count;\n};\n\n/* A view that works for either a file or memory.  */\n\nstruct elf_view\n{\n  struct backtrace_view view;\n  int release; /* If non-zero, must call backtrace_release_view.  */\n};\n\n/* Information about PowerPC64 ELFv1 .opd section.  */\n\nstruct elf_ppc64_opd_data\n{\n  /* Address of the .opd section.  */\n  b_elf_addr addr;\n  /* Section data.  */\n  const char *data;\n  /* Size of the .opd section.  */\n  size_t size;\n  /* Corresponding section view.  */\n  struct elf_view view;\n};\n\n/* Create a view of SIZE bytes from DESCRIPTOR/MEMORY at OFFSET.  */\n\nstatic int\nelf_get_view (struct backtrace_state *state, int descriptor,\n\t      const unsigned char *memory, size_t memory_size, off_t offset,\n\t      uint64_t size, backtrace_error_callback error_callback,\n\t      void *data, struct elf_view *view)\n{\n  if (memory == NULL)\n    {\n      view->release = 1;\n      return backtrace_get_view (state, descriptor, offset, size,\n\t\t\t\t error_callback, data, &view->view);\n    }\n  else\n    {\n      if ((uint64_t) offset + size > (uint64_t) memory_size)\n\t{\n\t  error_callback (data, \"out of range for in-memory file\", 0);\n\t  return 0;\n\t}\n      view->view.data = (const void *) (memory + offset);\n      view->view.base = NULL;\n      view->view.len = size;\n      view->release = 0;\n      return 1;\n    }\n}\n\n/* Release a view read by elf_get_view.  */\n\nstatic void\nelf_release_view (struct backtrace_state *state, struct elf_view *view,\n\t\t  backtrace_error_callback error_callback, void *data)\n{\n  if (view->release)\n    backtrace_release_view (state, &view->view, error_callback, data);\n}\n\n/* Compute the CRC-32 of BUF/LEN.  This uses the CRC used for\n   .gnu_debuglink files.  */\n\nstatic uint32_t\nelf_crc32 (uint32_t crc, const unsigned char *buf, size_t len)\n{\n  static const uint32_t crc32_table[256] =\n    {\n      0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419,\n      0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4,\n      0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07,\n      0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,\n      0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856,\n      0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,\n      0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,\n      0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,\n      0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,\n      0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a,\n      0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599,\n      0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,\n      0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190,\n      0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,\n      0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e,\n      0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,\n      0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed,\n      0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,\n      0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3,\n      0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,\n      0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,\n      0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5,\n      0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010,\n      0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,\n      0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17,\n      0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6,\n      0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,\n      0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,\n      0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344,\n      0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,\n      0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a,\n      0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,\n      0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1,\n      0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c,\n      0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,\n      0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,\n      0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe,\n      0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31,\n      0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c,\n      0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,\n      0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b,\n      0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,\n      0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1,\n      0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,\n      0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,\n      0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7,\n      0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66,\n      0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,\n      0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,\n      0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8,\n      0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b,\n      0x2d02ef8d\n    };\n  const unsigned char *end;\n\n  crc = ~crc;\n  for (end = buf + len; buf < end; ++ buf)\n    crc = crc32_table[(crc ^ *buf) & 0xff] ^ (crc >> 8);\n  return ~crc;\n}\n\n/* Return the CRC-32 of the entire file open at DESCRIPTOR.  */\n\nstatic uint32_t\nelf_crc32_file (struct backtrace_state *state, int descriptor,\n\t\tbacktrace_error_callback error_callback, void *data)\n{\n  struct stat st;\n  struct backtrace_view file_view;\n  uint32_t ret;\n\n  if (fstat (descriptor, &st) < 0)\n    {\n      error_callback (data, \"fstat\", errno);\n      return 0;\n    }\n\n  if (!backtrace_get_view (state, descriptor, 0, st.st_size, error_callback,\n\t\t\t   data, &file_view))\n    return 0;\n\n  ret = elf_crc32 (0, (const unsigned char *) file_view.data, st.st_size);\n\n  backtrace_release_view (state, &file_view, error_callback, data);\n\n  return ret;\n}\n\n/* A dummy callback function used when we can't find a symbol\n   table.  */\n\nstatic void\nelf_nosyms (struct backtrace_state *state ATTRIBUTE_UNUSED,\n\t    uintptr_t addr ATTRIBUTE_UNUSED,\n\t    backtrace_syminfo_callback callback ATTRIBUTE_UNUSED,\n\t    backtrace_error_callback error_callback, void *data)\n{\n  error_callback (data, \"no symbol table in ELF executable\", -1);\n}\n\n/* A callback function used when we can't find any debug info.  */\n\nstatic int\nelf_nodebug (struct backtrace_state *state, uintptr_t pc,\n\t     backtrace_full_callback callback,\n\t     backtrace_error_callback error_callback, void *data)\n{\n  if (state->syminfo_fn != NULL && state->syminfo_fn != elf_nosyms)\n    {\n      struct backtrace_call_full bdata;\n\n      /* Fetch symbol information so that we can least get the\n\t function name.  */\n\n      bdata.full_callback = callback;\n      bdata.full_error_callback = error_callback;\n      bdata.full_data = data;\n      bdata.ret = 0;\n      state->syminfo_fn (state, pc, backtrace_syminfo_to_full_callback,\n\t\t\t backtrace_syminfo_to_full_error_callback, &bdata);\n      return bdata.ret;\n    }\n\n  error_callback (data, \"no debug info in ELF executable\", -1);\n  return 0;\n}\n\n/* Compare struct elf_symbol for qsort.  */\n\nstatic int\nelf_symbol_compare (const void *v1, const void *v2)\n{\n  const struct elf_symbol *e1 = (const struct elf_symbol *) v1;\n  const struct elf_symbol *e2 = (const struct elf_symbol *) v2;\n\n  if (e1->address < e2->address)\n    return -1;\n  else if (e1->address > e2->address)\n    return 1;\n  else\n    return 0;\n}\n\n/* Compare an ADDR against an elf_symbol for bsearch.  We allocate one\n   extra entry in the array so that this can look safely at the next\n   entry.  */\n\nstatic int\nelf_symbol_search (const void *vkey, const void *ventry)\n{\n  const uintptr_t *key = (const uintptr_t *) vkey;\n  const struct elf_symbol *entry = (const struct elf_symbol *) ventry;\n  uintptr_t addr;\n\n  addr = *key;\n  if (addr < entry->address)\n    return -1;\n  else if (addr >= entry->address + entry->size)\n    return 1;\n  else\n    return 0;\n}\n\n/* Initialize the symbol table info for elf_syminfo.  */\n\nstatic int\nelf_initialize_syminfo (struct backtrace_state *state,\n\t\t\tstruct libbacktrace_base_address base_address,\n\t\t\tconst unsigned char *symtab_data, size_t symtab_size,\n\t\t\tconst unsigned char *strtab, size_t strtab_size,\n\t\t\tbacktrace_error_callback error_callback,\n\t\t\tvoid *data, struct elf_syminfo_data *sdata,\n\t\t\tstruct elf_ppc64_opd_data *opd)\n{\n  size_t sym_count;\n  const b_elf_sym *sym;\n  size_t elf_symbol_count;\n  size_t elf_symbol_size;\n  struct elf_symbol *elf_symbols;\n  size_t i;\n  unsigned int j;\n\n  sym_count = symtab_size / sizeof (b_elf_sym);\n\n  /* We only care about function symbols.  Count them.  */\n  sym = (const b_elf_sym *) symtab_data;\n  elf_symbol_count = 0;\n  for (i = 0; i < sym_count; ++i, ++sym)\n    {\n      int info;\n\n      info = sym->st_info & 0xf;\n      if ((info == STT_FUNC || info == STT_OBJECT)\n\t  && sym->st_shndx != SHN_UNDEF)\n\t++elf_symbol_count;\n    }\n\n  elf_symbol_size = elf_symbol_count * sizeof (struct elf_symbol);\n  elf_symbols = ((struct elf_symbol *)\n\t\t backtrace_alloc (state, elf_symbol_size, error_callback,\n\t\t\t\t  data));\n  if (elf_symbols == NULL)\n    return 0;\n\n  sym = (const b_elf_sym *) symtab_data;\n  j = 0;\n  for (i = 0; i < sym_count; ++i, ++sym)\n    {\n      int info;\n\n      info = sym->st_info & 0xf;\n      if (info != STT_FUNC && info != STT_OBJECT)\n\tcontinue;\n      if (sym->st_shndx == SHN_UNDEF)\n\tcontinue;\n      if (sym->st_name >= strtab_size)\n\t{\n\t  error_callback (data, \"symbol string index out of range\", 0);\n\t  backtrace_free (state, elf_symbols, elf_symbol_size, error_callback,\n\t\t\t  data);\n\t  return 0;\n\t}\n      elf_symbols[j].name = (const char *) strtab + sym->st_name;\n      /* Special case PowerPC64 ELFv1 symbols in .opd section, if the symbol\n\t is a function descriptor, read the actual code address from the\n\t descriptor.  */\n      if (opd\n\t  && sym->st_value >= opd->addr\n\t  && sym->st_value < opd->addr + opd->size)\n\telf_symbols[j].address\n\t  = *(const b_elf_addr *) (opd->data + (sym->st_value - opd->addr));\n      else\n\telf_symbols[j].address = sym->st_value;\n      elf_symbols[j].address =\n\tlibbacktrace_add_base (elf_symbols[j].address, base_address);\n      elf_symbols[j].size = sym->st_size;\n      ++j;\n    }\n\n  backtrace_qsort (elf_symbols, elf_symbol_count, sizeof (struct elf_symbol),\n\t\t   elf_symbol_compare);\n\n  sdata->next = NULL;\n  sdata->symbols = elf_symbols;\n  sdata->count = elf_symbol_count;\n\n  return 1;\n}\n\n/* Add EDATA to the list in STATE.  */\n\nstatic void\nelf_add_syminfo_data (struct backtrace_state *state,\n\t\t      struct elf_syminfo_data *edata)\n{\n  if (!state->threaded)\n    {\n      struct elf_syminfo_data **pp;\n\n      for (pp = (struct elf_syminfo_data **) (void *) &state->syminfo_data;\n\t   *pp != NULL;\n\t   pp = &(*pp)->next)\n\t;\n      *pp = edata;\n    }\n  else\n    {\n      while (1)\n\t{\n\t  struct elf_syminfo_data **pp;\n\n\t  pp = (struct elf_syminfo_data **) (void *) &state->syminfo_data;\n\n\t  while (1)\n\t    {\n\t      struct elf_syminfo_data *p;\n\n\t      p = backtrace_atomic_load_pointer (pp);\n\n\t      if (p == NULL)\n\t\tbreak;\n\n\t      pp = &p->next;\n\t    }\n\n\t  if (__sync_bool_compare_and_swap (pp, NULL, edata))\n\t    break;\n\t}\n    }\n}\n\n/* Return the symbol name and value for an ADDR.  */\n\nstatic void\nelf_syminfo (struct backtrace_state *state, uintptr_t addr,\n\t     backtrace_syminfo_callback callback,\n\t     backtrace_error_callback error_callback ATTRIBUTE_UNUSED,\n\t     void *data)\n{\n  struct elf_syminfo_data *edata;\n  struct elf_symbol *sym = NULL;\n\n  if (!state->threaded)\n    {\n      for (edata = (struct elf_syminfo_data *) state->syminfo_data;\n\t   edata != NULL;\n\t   edata = edata->next)\n\t{\n\t  sym = ((struct elf_symbol *)\n\t\t bsearch (&addr, edata->symbols, edata->count,\n\t\t\t  sizeof (struct elf_symbol), elf_symbol_search));\n\t  if (sym != NULL)\n\t    break;\n\t}\n    }\n  else\n    {\n      struct elf_syminfo_data **pp;\n\n      pp = (struct elf_syminfo_data **) (void *) &state->syminfo_data;\n      while (1)\n\t{\n\t  edata = backtrace_atomic_load_pointer (pp);\n\t  if (edata == NULL)\n\t    break;\n\n\t  sym = ((struct elf_symbol *)\n\t\t bsearch (&addr, edata->symbols, edata->count,\n\t\t\t  sizeof (struct elf_symbol), elf_symbol_search));\n\t  if (sym != NULL)\n\t    break;\n\n\t  pp = &edata->next;\n\t}\n    }\n\n  if (sym == NULL)\n    callback (data, addr, NULL, 0, 0);\n  else\n    callback (data, addr, sym->name, sym->address, sym->size);\n}\n\n/* Return whether FILENAME is a symlink.  */\n\nstatic int\nelf_is_symlink (const char *filename)\n{\n  struct stat st;\n\n  if (lstat (filename, &st) < 0)\n    return 0;\n  return S_ISLNK (st.st_mode);\n}\n\n/* Return the results of reading the symlink FILENAME in a buffer\n   allocated by backtrace_alloc.  Return the length of the buffer in\n   *LEN.  */\n\nstatic char *\nelf_readlink (struct backtrace_state *state, const char *filename,\n\t      backtrace_error_callback error_callback, void *data,\n\t      size_t *plen)\n{\n  size_t len;\n  char *buf;\n\n  len = 128;\n  while (1)\n    {\n      ssize_t rl;\n\n      buf = (char*)backtrace_alloc (state, len, error_callback, data);\n      if (buf == NULL)\n\treturn NULL;\n      rl = readlink (filename, buf, len);\n      if (rl < 0)\n\t{\n\t  backtrace_free (state, buf, len, error_callback, data);\n\t  return NULL;\n\t}\n      if ((size_t) rl < len - 1)\n\t{\n\t  buf[rl] = '\\0';\n\t  *plen = len;\n\t  return buf;\n\t}\n      backtrace_free (state, buf, len, error_callback, data);\n      len *= 2;\n    }\n}\n\n#define SYSTEM_BUILD_ID_DIR \"/usr/lib/debug/.build-id/\"\n\n/* Open a separate debug info file, using the build ID to find it.\n   Returns an open file descriptor, or -1.\n\n   The GDB manual says that the only place gdb looks for a debug file\n   when the build ID is known is in /usr/lib/debug/.build-id.  */\n\nstatic int\nelf_open_debugfile_by_buildid (struct backtrace_state *state,\n\t\t\t       const char *buildid_data, size_t buildid_size,\n             const char *filename,\n\t\t\t       backtrace_error_callback error_callback,\n\t\t\t       void *data)\n{\n  const char * const prefix = SYSTEM_BUILD_ID_DIR;\n  const size_t prefix_len = strlen (prefix);\n  const char * const suffix = \".debug\";\n  const size_t suffix_len = strlen (suffix);\n  size_t len;\n  char *bd_filename;\n  char *t;\n  size_t i;\n  int ret;\n  int does_not_exist;\n\n  len = prefix_len + buildid_size * 2 + suffix_len + 2;\n  bd_filename = (char*)backtrace_alloc (state, len, error_callback, data);\n  if (bd_filename == NULL)\n    return -1;\n\n  t = bd_filename;\n  memcpy (t, prefix, prefix_len);\n  t += prefix_len;\n  for (i = 0; i < buildid_size; i++)\n    {\n      unsigned char b;\n      unsigned char nib;\n\n      b = (unsigned char) buildid_data[i];\n      nib = (b & 0xf0) >> 4;\n      *t++ = nib < 10 ? '0' + nib : 'a' + nib - 10;\n      nib = b & 0x0f;\n      *t++ = nib < 10 ? '0' + nib : 'a' + nib - 10;\n      if (i == 0)\n\t*t++ = '/';\n    }\n  memcpy (t, suffix, suffix_len);\n  t[suffix_len] = '\\0';\n\n  ret = backtrace_open (bd_filename, error_callback, data, &does_not_exist);\n\n  backtrace_free (state, bd_filename, len, error_callback, data);\n\n  /* gdb checks that the debuginfo file has the same build ID note.\n     That seems kind of pointless to me--why would it have the right\n     name but not the right build ID?--so skipping the check.  */\n\n#ifdef TRACY_DEBUGINFOD\n  if (ret == -1)\n    return GetDebugInfoDescriptor( buildid_data, buildid_size, filename );\n  else\n    return ret;\n#else\n  return ret;\n#endif\n}\n\n/* Try to open a file whose name is PREFIX (length PREFIX_LEN)\n   concatenated with PREFIX2 (length PREFIX2_LEN) concatenated with\n   DEBUGLINK_NAME.  Returns an open file descriptor, or -1.  */\n\nstatic int\nelf_try_debugfile (struct backtrace_state *state, const char *prefix,\n\t\t   size_t prefix_len, const char *prefix2, size_t prefix2_len,\n\t\t   const char *debuglink_name,\n\t\t   backtrace_error_callback error_callback, void *data)\n{\n  size_t debuglink_len;\n  size_t try_len;\n  char *Try;\n  int does_not_exist;\n  int ret;\n\n  debuglink_len = strlen (debuglink_name);\n  try_len = prefix_len + prefix2_len + debuglink_len + 1;\n  Try = (char*)backtrace_alloc (state, try_len, error_callback, data);\n  if (Try == NULL)\n    return -1;\n\n  memcpy (Try, prefix, prefix_len);\n  memcpy (Try + prefix_len, prefix2, prefix2_len);\n  memcpy (Try + prefix_len + prefix2_len, debuglink_name, debuglink_len);\n  Try[prefix_len + prefix2_len + debuglink_len] = '\\0';\n\n  ret = backtrace_open (Try, error_callback, data, &does_not_exist);\n\n  backtrace_free (state, Try, try_len, error_callback, data);\n\n  return ret;\n}\n\n/* Find a separate debug info file, using the debuglink section data\n   to find it.  Returns an open file descriptor, or -1.  */\n\nstatic int\nelf_find_debugfile_by_debuglink (struct backtrace_state *state,\n\t\t\t\t const char *filename,\n\t\t\t\t const char *debuglink_name,\n\t\t\t\t backtrace_error_callback error_callback,\n\t\t\t\t void *data)\n{\n  int ret;\n  char *alc;\n  size_t alc_len;\n  const char *slash;\n  int ddescriptor;\n  const char *prefix;\n  size_t prefix_len;\n\n  /* Resolve symlinks in FILENAME.  Since FILENAME is fairly likely to\n     be /proc/self/exe, symlinks are common.  We don't try to resolve\n     the whole path name, just the base name.  */\n  ret = -1;\n  alc = NULL;\n  alc_len = 0;\n  while (elf_is_symlink (filename))\n    {\n      char *new_buf;\n      size_t new_len;\n\n      new_buf = elf_readlink (state, filename, error_callback, data, &new_len);\n      if (new_buf == NULL)\n\tbreak;\n\n      if (new_buf[0] == '/')\n\tfilename = new_buf;\n      else\n\t{\n\t  slash = strrchr (filename, '/');\n\t  if (slash == NULL)\n\t    filename = new_buf;\n\t  else\n\t    {\n\t      size_t clen;\n\t      char *c;\n\n\t      slash++;\n\t      clen = slash - filename + strlen (new_buf) + 1;\n\t      c = (char*)backtrace_alloc (state, clen, error_callback, data);\n\t      if (c == NULL)\n\t\tgoto done;\n\n\t      memcpy (c, filename, slash - filename);\n\t      memcpy (c + (slash - filename), new_buf, strlen (new_buf));\n\t      c[slash - filename + strlen (new_buf)] = '\\0';\n\t      backtrace_free (state, new_buf, new_len, error_callback, data);\n\t      filename = c;\n\t      new_buf = c;\n\t      new_len = clen;\n\t    }\n\t}\n\n      if (alc != NULL)\n\tbacktrace_free (state, alc, alc_len, error_callback, data);\n      alc = new_buf;\n      alc_len = new_len;\n    }\n\n  /* Look for DEBUGLINK_NAME in the same directory as FILENAME.  */\n\n  slash = strrchr (filename, '/');\n  if (slash == NULL)\n    {\n      prefix = \"\";\n      prefix_len = 0;\n    }\n  else\n    {\n      slash++;\n      prefix = filename;\n      prefix_len = slash - filename;\n    }\n\n  ddescriptor = elf_try_debugfile (state, prefix, prefix_len, \"\", 0,\n\t\t\t\t   debuglink_name, error_callback, data);\n  if (ddescriptor >= 0)\n    {\n      ret = ddescriptor;\n      goto done;\n    }\n\n  /* Look for DEBUGLINK_NAME in a .debug subdirectory of FILENAME.  */\n\n  ddescriptor = elf_try_debugfile (state, prefix, prefix_len, \".debug/\",\n\t\t\t\t   strlen (\".debug/\"), debuglink_name,\n\t\t\t\t   error_callback, data);\n  if (ddescriptor >= 0)\n    {\n      ret = ddescriptor;\n      goto done;\n    }\n\n  /* Look for DEBUGLINK_NAME in /usr/lib/debug.  */\n\n  ddescriptor = elf_try_debugfile (state, \"/usr/lib/debug/\",\n\t\t\t\t   strlen (\"/usr/lib/debug/\"), prefix,\n\t\t\t\t   prefix_len, debuglink_name,\n\t\t\t\t   error_callback, data);\n  if (ddescriptor >= 0)\n    ret = ddescriptor;\n\n done:\n  if (alc != NULL && alc_len > 0)\n    backtrace_free (state, alc, alc_len, error_callback, data);\n  return ret;\n}\n\n/* Open a separate debug info file, using the debuglink section data\n   to find it.  Returns an open file descriptor, or -1.  */\n\nstatic int\nelf_open_debugfile_by_debuglink (struct backtrace_state *state,\n\t\t\t\t const char *filename,\n\t\t\t\t const char *debuglink_name,\n\t\t\t\t uint32_t debuglink_crc,\n\t\t\t\t backtrace_error_callback error_callback,\n\t\t\t\t void *data)\n{\n  int ddescriptor;\n\n  ddescriptor = elf_find_debugfile_by_debuglink (state, filename,\n\t\t\t\t\t\t debuglink_name,\n\t\t\t\t\t\t error_callback, data);\n  if (ddescriptor < 0)\n    return -1;\n\n  if (debuglink_crc != 0)\n    {\n      uint32_t got_crc;\n\n      got_crc = elf_crc32_file (state, ddescriptor, error_callback, data);\n      if (got_crc != debuglink_crc)\n\t{\n\t  backtrace_close (ddescriptor, error_callback, data);\n\t  return -1;\n\t}\n    }\n\n  return ddescriptor;\n}\n\n/* A function useful for setting a breakpoint for an inflation failure\n   when this code is compiled with -g.  */\n\nstatic void\nelf_uncompress_failed(void)\n{\n}\n\n/* *PVAL is the current value being read from the stream, and *PBITS\n   is the number of valid bits.  Ensure that *PVAL holds at least 15\n   bits by reading additional bits from *PPIN, up to PINEND, as\n   needed.  Updates *PPIN, *PVAL and *PBITS.  Returns 1 on success, 0\n   on error.  */\n\nstatic int\nelf_fetch_bits (const unsigned char **ppin, const unsigned char *pinend,\n\t\tuint64_t *pval, unsigned int *pbits)\n{\n  unsigned int bits;\n  const unsigned char *pin;\n  uint64_t val;\n  uint32_t next;\n\n  bits = *pbits;\n  if (bits >= 15)\n    return 1;\n  pin = *ppin;\n  val = *pval;\n\n  if (unlikely (pinend - pin < 4))\n    {\n      elf_uncompress_failed ();\n      return 0;\n    }\n\n#if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) \\\n    && defined(__ORDER_BIG_ENDIAN__) \\\n    && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ \\\n        || __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)\n  /* We've ensured that PIN is aligned.  */\n  next = *(const uint32_t *)pin;\n\n#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__\n  next = __builtin_bswap32 (next);\n#endif\n#else\n  next = pin[0] | (pin[1] << 8) | (pin[2] << 16) | (pin[3] << 24);\n#endif\n\n  val |= (uint64_t)next << bits;\n  bits += 32;\n  pin += 4;\n\n  /* We will need the next four bytes soon.  */\n  __builtin_prefetch (pin, 0, 0);\n\n  *ppin = pin;\n  *pval = val;\n  *pbits = bits;\n  return 1;\n}\n\n/* This is like elf_fetch_bits, but it fetchs the bits backward, and ensures at\n   least 16 bits.  This is for zstd.  */\n\nstatic int\nelf_fetch_bits_backward (const unsigned char **ppin,\n\t\t\t const unsigned char *pinend,\n\t\t\t uint64_t *pval, unsigned int *pbits)\n{\n  unsigned int bits;\n  const unsigned char *pin;\n  uint64_t val;\n  uint32_t next;\n\n  bits = *pbits;\n  if (bits >= 16)\n    return 1;\n  pin = *ppin;\n  val = *pval;\n\n  if (unlikely (pin <= pinend))\n    return 1;\n\n  pin -= 4;\n\n#if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) \\\n  && defined(__ORDER_BIG_ENDIAN__)\t\t\t\t\\\n  && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__\t\t\t\\\n      || __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)\n  /* We've ensured that PIN is aligned.  */\n  next = *(const uint32_t *)pin;\n\n#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__\n  next = __builtin_bswap32 (next);\n#endif\n#else\n  next = pin[0] | (pin[1] << 8) | (pin[2] << 16) | (pin[3] << 24);\n#endif\n\n  val <<= 32;\n  val |= next;\n  bits += 32;\n\n  if (unlikely (pin < pinend))\n    {\n      val >>= (pinend - pin) * 8;\n      bits -= (pinend - pin) * 8;\n    }\n\n  *ppin = pin;\n  *pval = val;\n  *pbits = bits;\n  return 1;\n}\n\n/* Initialize backward fetching when the bitstream starts with a 1 bit in the\n   last byte in memory (which is the first one that we read).  This is used by\n   zstd decompression.  Returns 1 on success, 0 on error.  */\n\nstatic int\nelf_fetch_backward_init (const unsigned char **ppin,\n\t\t\t const unsigned char *pinend,\n\t\t\t uint64_t *pval, unsigned int *pbits)\n{\n  const unsigned char *pin;\n  unsigned int stream_start;\n  uint64_t val;\n  unsigned int bits;\n\n  pin = *ppin;\n  stream_start = (unsigned int)*pin;\n  if (unlikely (stream_start == 0))\n    {\n      elf_uncompress_failed ();\n      return 0;\n    }\n  val = 0;\n  bits = 0;\n\n  /* Align to a 32-bit boundary.  */\n  while ((((uintptr_t)pin) & 3) != 0)\n    {\n      val <<= 8;\n      val |= (uint64_t)*pin;\n      bits += 8;\n      --pin;\n    }\n\n  val <<= 8;\n  val |= (uint64_t)*pin;\n  bits += 8;\n\n  *ppin = pin;\n  *pval = val;\n  *pbits = bits;\n  if (!elf_fetch_bits_backward (ppin, pinend, pval, pbits))\n    return 0;\n\n  *pbits -= __builtin_clz (stream_start) - (sizeof (unsigned int) - 1) * 8 + 1;\n\n  if (!elf_fetch_bits_backward (ppin, pinend, pval, pbits))\n    return 0;\n\n  return 1;\n}\n\n/* Huffman code tables, like the rest of the zlib format, are defined\n   by RFC 1951.  We store a Huffman code table as a series of tables\n   stored sequentially in memory.  Each entry in a table is 16 bits.\n   The first, main, table has 256 entries.  It is followed by a set of\n   secondary tables of length 2 to 128 entries.  The maximum length of\n   a code sequence in the deflate format is 15 bits, so that is all we\n   need.  Each secondary table has an index, which is the offset of\n   the table in the overall memory storage.\n\n   The deflate format says that all codes of a given bit length are\n   lexicographically consecutive.  Perhaps we could have 130 values\n   that require a 15-bit code, perhaps requiring three secondary\n   tables of size 128.  I don't know if this is actually possible, but\n   it suggests that the maximum size required for secondary tables is\n   3 * 128 + 3 * 64 ... == 768.  The zlib enough program reports 660\n   as the maximum.  We permit 768, since in addition to the 256 for\n   the primary table, with two bytes per entry, and with the two\n   tables we need, that gives us a page.\n\n   A single table entry needs to store a value or (for the main table\n   only) the index and size of a secondary table.  Values range from 0\n   to 285, inclusive.  Secondary table indexes, per above, range from\n   0 to 510.  For a value we need to store the number of bits we need\n   to determine that value (one value may appear multiple times in the\n   table), which is 1 to 8.  For a secondary table we need to store\n   the number of bits used to index into the table, which is 1 to 7.\n   And of course we need 1 bit to decide whether we have a value or a\n   secondary table index.  So each entry needs 9 bits for value/table\n   index, 3 bits for size, 1 bit what it is.  For simplicity we use 16\n   bits per entry.  */\n\n/* Number of entries we allocate to for one code table.  We get a page\n   for the two code tables we need.  */\n\n#define ZLIB_HUFFMAN_TABLE_SIZE (1024)\n\n/* Bit masks and shifts for the values in the table.  */\n\n#define ZLIB_HUFFMAN_VALUE_MASK 0x01ff\n#define ZLIB_HUFFMAN_BITS_SHIFT 9\n#define ZLIB_HUFFMAN_BITS_MASK 0x7\n#define ZLIB_HUFFMAN_SECONDARY_SHIFT 12\n\n/* For working memory while inflating we need two code tables, we need\n   an array of code lengths (max value 15, so we use unsigned char),\n   and an array of unsigned shorts used while building a table.  The\n   latter two arrays must be large enough to hold the maximum number\n   of code lengths, which RFC 1951 defines as 286 + 30.  */\n\n#define ZLIB_TABLE_SIZE \\\n  (2 * ZLIB_HUFFMAN_TABLE_SIZE * sizeof (uint16_t) \\\n   + (286 + 30) * sizeof (uint16_t)\t      \\\n   + (286 + 30) * sizeof (unsigned char))\n\n#define ZLIB_TABLE_CODELEN_OFFSET \\\n  (2 * ZLIB_HUFFMAN_TABLE_SIZE * sizeof (uint16_t) \\\n   + (286 + 30) * sizeof (uint16_t))\n\n#define ZLIB_TABLE_WORK_OFFSET \\\n  (2 * ZLIB_HUFFMAN_TABLE_SIZE * sizeof (uint16_t))\n\n#ifdef BACKTRACE_GENERATE_FIXED_HUFFMAN_TABLE\n\n/* Used by the main function that generates the fixed table to learn\n   the table size.  */\nstatic size_t final_next_secondary;\n\n#endif\n\n/* Build a Huffman code table from an array of lengths in CODES of\n   length CODES_LEN.  The table is stored into *TABLE.  ZDEBUG_TABLE\n   is the same as for elf_zlib_inflate, used to find some work space.\n   Returns 1 on success, 0 on error.  */\n\nstatic int\nelf_zlib_inflate_table (unsigned char *codes, size_t codes_len,\n\t\t\tuint16_t *zdebug_table, uint16_t *table)\n{\n  uint16_t count[16];\n  uint16_t start[16];\n  uint16_t prev[16];\n  uint16_t firstcode[7];\n  uint16_t *next;\n  size_t i;\n  size_t j;\n  unsigned int code;\n  size_t next_secondary;\n\n  /* Count the number of code of each length.  Set NEXT[val] to be the\n     next value after VAL with the same bit length.  */\n\n  next = (uint16_t *) (((unsigned char *) zdebug_table)\n\t\t       + ZLIB_TABLE_WORK_OFFSET);\n\n  memset (&count[0], 0, 16 * sizeof (uint16_t));\n  for (i = 0; i < codes_len; ++i)\n    {\n      if (unlikely (codes[i] >= 16))\n\t{\n\t  elf_uncompress_failed ();\n\t  return 0;\n\t}\n\n      if (count[codes[i]] == 0)\n\t{\n\t  start[codes[i]] = i;\n\t  prev[codes[i]] = i;\n\t}\n      else\n\t{\n\t  next[prev[codes[i]]] = i;\n\t  prev[codes[i]] = i;\n\t}\n\n      ++count[codes[i]];\n    }\n\n  /* For each length, fill in the table for the codes of that\n     length.  */\n\n  memset (table, 0, ZLIB_HUFFMAN_TABLE_SIZE * sizeof (uint16_t));\n\n  /* Handle the values that do not require a secondary table.  */\n\n  code = 0;\n  for (j = 1; j <= 8; ++j)\n    {\n      unsigned int jcnt;\n      unsigned int val;\n\n      jcnt = count[j];\n      if (jcnt == 0)\n\tcontinue;\n\n      if (unlikely (jcnt > (1U << j)))\n\t{\n\t  elf_uncompress_failed ();\n\t  return 0;\n\t}\n\n      /* There are JCNT values that have this length, the values\n\t starting from START[j] continuing through NEXT[VAL].  Those\n\t values are assigned consecutive values starting at CODE.  */\n\n      val = start[j];\n      for (i = 0; i < jcnt; ++i)\n\t{\n\t  uint16_t tval;\n\t  size_t ind;\n\t  unsigned int incr;\n\n\t  /* In the compressed bit stream, the value VAL is encoded as\n\t     J bits with the value C.  */\n\n\t  if (unlikely ((val & ~ZLIB_HUFFMAN_VALUE_MASK) != 0))\n\t    {\n\t      elf_uncompress_failed ();\n\t      return 0;\n\t    }\n\n\t  tval = val | ((j - 1) << ZLIB_HUFFMAN_BITS_SHIFT);\n\n\t  /* The table lookup uses 8 bits.  If J is less than 8, we\n\t     don't know what the other bits will be.  We need to fill\n\t     in all possibilities in the table.  Since the Huffman\n\t     code is unambiguous, those entries can't be used for any\n\t     other code.  */\n\n\t  for (ind = code; ind < 0x100; ind += 1 << j)\n\t    {\n\t      if (unlikely (table[ind] != 0))\n\t\t{\n\t\t  elf_uncompress_failed ();\n\t\t  return 0;\n\t\t}\n\t      table[ind] = tval;\n\t    }\n\n\t  /* Advance to the next value with this length.  */\n\t  if (i + 1 < jcnt)\n\t    val = next[val];\n\n\t  /* The Huffman codes are stored in the bitstream with the\n\t     most significant bit first, as is required to make them\n\t     unambiguous.  The effect is that when we read them from\n\t     the bitstream we see the bit sequence in reverse order:\n\t     the most significant bit of the Huffman code is the least\n\t     significant bit of the value we read from the bitstream.\n\t     That means that to make our table lookups work, we need\n\t     to reverse the bits of CODE.  Since reversing bits is\n\t     tedious and in general requires using a table, we instead\n\t     increment CODE in reverse order.  That is, if the number\n\t     of bits we are currently using, here named J, is 3, we\n\t     count as 000, 100, 010, 110, 001, 101, 011, 111, which is\n\t     to say the numbers from 0 to 7 but with the bits\n\t     reversed.  Going to more bits, aka incrementing J,\n\t     effectively just adds more zero bits as the beginning,\n\t     and as such does not change the numeric value of CODE.\n\n\t     To increment CODE of length J in reverse order, find the\n\t     most significant zero bit and set it to one while\n\t     clearing all higher bits.  In other words, add 1 modulo\n\t     2^J, only reversed.  */\n\n\t  incr = 1U << (j - 1);\n\t  while ((code & incr) != 0)\n\t    incr >>= 1;\n\t  if (incr == 0)\n\t    code = 0;\n\t  else\n\t    {\n\t      code &= incr - 1;\n\t      code += incr;\n\t    }\n\t}\n    }\n\n  /* Handle the values that require a secondary table.  */\n\n  /* Set FIRSTCODE, the number at which the codes start, for each\n     length.  */\n\n  for (j = 9; j < 16; j++)\n    {\n      unsigned int jcnt;\n      unsigned int k;\n\n      jcnt = count[j];\n      if (jcnt == 0)\n\tcontinue;\n\n      /* There are JCNT values that have this length, the values\n\t starting from START[j].  Those values are assigned\n\t consecutive values starting at CODE.  */\n\n      firstcode[j - 9] = code;\n\n      /* Reverse add JCNT to CODE modulo 2^J.  */\n      for (k = 0; k < j; ++k)\n\t{\n\t  if ((jcnt & (1U << k)) != 0)\n\t    {\n\t      unsigned int m;\n\t      unsigned int bit;\n\n\t      bit = 1U << (j - k - 1);\n\t      for (m = 0; m < j - k; ++m, bit >>= 1)\n\t\t{\n\t\t  if ((code & bit) == 0)\n\t\t    {\n\t\t      code += bit;\n\t\t      break;\n\t\t    }\n\t\t  code &= ~bit;\n\t\t}\n\t      jcnt &= ~(1U << k);\n\t    }\n\t}\n      if (unlikely (jcnt != 0))\n\t{\n\t  elf_uncompress_failed ();\n\t  return 0;\n\t}\n    }\n\n  /* For J from 9 to 15, inclusive, we store COUNT[J] consecutive\n     values starting at START[J] with consecutive codes starting at\n     FIRSTCODE[J - 9].  In the primary table we need to point to the\n     secondary table, and the secondary table will be indexed by J - 9\n     bits.  We count down from 15 so that we install the larger\n     secondary tables first, as the smaller ones may be embedded in\n     the larger ones.  */\n\n  next_secondary = 0; /* Index of next secondary table (after primary).  */\n  for (j = 15; j >= 9; j--)\n    {\n      unsigned int jcnt;\n      unsigned int val;\n      size_t primary; /* Current primary index.  */\n      size_t secondary; /* Offset to current secondary table.  */\n      size_t secondary_bits; /* Bit size of current secondary table.  */\n\n      jcnt = count[j];\n      if (jcnt == 0)\n\tcontinue;\n\n      val = start[j];\n      code = firstcode[j - 9];\n      primary = 0x100;\n      secondary = 0;\n      secondary_bits = 0;\n      for (i = 0; i < jcnt; ++i)\n\t{\n\t  uint16_t tval;\n\t  size_t ind;\n\t  unsigned int incr;\n\n\t  if ((code & 0xff) != primary)\n\t    {\n\t      uint16_t tprimary;\n\n\t      /* Fill in a new primary table entry.  */\n\n\t      primary = code & 0xff;\n\n\t      tprimary = table[primary];\n\t      if (tprimary == 0)\n\t\t{\n\t\t  /* Start a new secondary table.  */\n\n\t\t  if (unlikely ((next_secondary & ZLIB_HUFFMAN_VALUE_MASK)\n\t\t\t\t!= next_secondary))\n\t\t    {\n\t\t      elf_uncompress_failed ();\n\t\t      return 0;\n\t\t    }\n\n\t\t  secondary = next_secondary;\n\t\t  secondary_bits = j - 8;\n\t\t  next_secondary += 1 << secondary_bits;\n\t\t  table[primary] = (secondary\n\t\t\t\t    + ((j - 8) << ZLIB_HUFFMAN_BITS_SHIFT)\n\t\t\t\t    + (1U << ZLIB_HUFFMAN_SECONDARY_SHIFT));\n\t\t}\n\t      else\n\t\t{\n\t\t  /* There is an existing entry.  It had better be a\n\t\t     secondary table with enough bits.  */\n\t\t  if (unlikely ((tprimary\n\t\t\t\t & (1U << ZLIB_HUFFMAN_SECONDARY_SHIFT))\n\t\t\t\t== 0))\n\t\t    {\n\t\t      elf_uncompress_failed ();\n\t\t      return 0;\n\t\t    }\n\t\t  secondary = tprimary & ZLIB_HUFFMAN_VALUE_MASK;\n\t\t  secondary_bits = ((tprimary >> ZLIB_HUFFMAN_BITS_SHIFT)\n\t\t\t\t    & ZLIB_HUFFMAN_BITS_MASK);\n\t\t  if (unlikely (secondary_bits < j - 8))\n\t\t    {\n\t\t      elf_uncompress_failed ();\n\t\t      return 0;\n\t\t    }\n\t\t}\n\t    }\n\n\t  /* Fill in secondary table entries.  */\n\n\t  tval = val | ((j - 8) << ZLIB_HUFFMAN_BITS_SHIFT);\n\n\t  for (ind = code >> 8;\n\t       ind < (1U << secondary_bits);\n\t       ind += 1U << (j - 8))\n\t    {\n\t      if (unlikely (table[secondary + 0x100 + ind] != 0))\n\t\t{\n\t\t  elf_uncompress_failed ();\n\t\t  return 0;\n\t\t}\n\t      table[secondary + 0x100 + ind] = tval;\n\t    }\n\n\t  if (i + 1 < jcnt)\n\t    val = next[val];\n\n\t  incr = 1U << (j - 1);\n\t  while ((code & incr) != 0)\n\t    incr >>= 1;\n\t  if (incr == 0)\n\t    code = 0;\n\t  else\n\t    {\n\t      code &= incr - 1;\n\t      code += incr;\n\t    }\n\t}\n    }\n\n#ifdef BACKTRACE_GENERATE_FIXED_HUFFMAN_TABLE\n  final_next_secondary = next_secondary;\n#endif\n\n  return 1;\n}\n\n#ifdef BACKTRACE_GENERATE_FIXED_HUFFMAN_TABLE\n\n/* Used to generate the fixed Huffman table for block type 1.  */\n\n#include <stdio.h>\n\nstatic uint16_t table[ZLIB_TABLE_SIZE];\nstatic unsigned char codes[288];\n\nint\nmain ()\n{\n  size_t i;\n\n  for (i = 0; i <= 143; ++i)\n    codes[i] = 8;\n  for (i = 144; i <= 255; ++i)\n    codes[i] = 9;\n  for (i = 256; i <= 279; ++i)\n    codes[i] = 7;\n  for (i = 280; i <= 287; ++i)\n    codes[i] = 8;\n  if (!elf_zlib_inflate_table (&codes[0], 288, &table[0], &table[0]))\n    {\n      fprintf (stderr, \"elf_zlib_inflate_table failed\\n\");\n      exit (EXIT_FAILURE);\n    }\n\n  printf (\"static const uint16_t elf_zlib_default_table[%#zx] =\\n\",\n\t  final_next_secondary + 0x100);\n  printf (\"{\\n\");\n  for (i = 0; i < final_next_secondary + 0x100; i += 8)\n    {\n      size_t j;\n\n      printf (\" \");\n      for (j = i; j < final_next_secondary + 0x100 && j < i + 8; ++j)\n\tprintf (\" %#x,\", table[j]);\n      printf (\"\\n\");\n    }\n  printf (\"};\\n\");\n  printf (\"\\n\");\n\n  for (i = 0; i < 32; ++i)\n    codes[i] = 5;\n  if (!elf_zlib_inflate_table (&codes[0], 32, &table[0], &table[0]))\n    {\n      fprintf (stderr, \"elf_zlib_inflate_table failed\\n\");\n      exit (EXIT_FAILURE);\n    }\n\n  printf (\"static const uint16_t elf_zlib_default_dist_table[%#zx] =\\n\",\n\t  final_next_secondary + 0x100);\n  printf (\"{\\n\");\n  for (i = 0; i < final_next_secondary + 0x100; i += 8)\n    {\n      size_t j;\n\n      printf (\" \");\n      for (j = i; j < final_next_secondary + 0x100 && j < i + 8; ++j)\n\tprintf (\" %#x,\", table[j]);\n      printf (\"\\n\");\n    }\n  printf (\"};\\n\");\n\n  return 0;\n}\n\n#endif\n\n/* The fixed tables generated by the #ifdef'ed out main function\n   above.  */\n\nstatic const uint16_t elf_zlib_default_table[0x170] =\n{\n  0xd00, 0xe50, 0xe10, 0xf18, 0xd10, 0xe70, 0xe30, 0x1230,\n  0xd08, 0xe60, 0xe20, 0x1210, 0xe00, 0xe80, 0xe40, 0x1250,\n  0xd04, 0xe58, 0xe18, 0x1200, 0xd14, 0xe78, 0xe38, 0x1240,\n  0xd0c, 0xe68, 0xe28, 0x1220, 0xe08, 0xe88, 0xe48, 0x1260,\n  0xd02, 0xe54, 0xe14, 0xf1c, 0xd12, 0xe74, 0xe34, 0x1238,\n  0xd0a, 0xe64, 0xe24, 0x1218, 0xe04, 0xe84, 0xe44, 0x1258,\n  0xd06, 0xe5c, 0xe1c, 0x1208, 0xd16, 0xe7c, 0xe3c, 0x1248,\n  0xd0e, 0xe6c, 0xe2c, 0x1228, 0xe0c, 0xe8c, 0xe4c, 0x1268,\n  0xd01, 0xe52, 0xe12, 0xf1a, 0xd11, 0xe72, 0xe32, 0x1234,\n  0xd09, 0xe62, 0xe22, 0x1214, 0xe02, 0xe82, 0xe42, 0x1254,\n  0xd05, 0xe5a, 0xe1a, 0x1204, 0xd15, 0xe7a, 0xe3a, 0x1244,\n  0xd0d, 0xe6a, 0xe2a, 0x1224, 0xe0a, 0xe8a, 0xe4a, 0x1264,\n  0xd03, 0xe56, 0xe16, 0xf1e, 0xd13, 0xe76, 0xe36, 0x123c,\n  0xd0b, 0xe66, 0xe26, 0x121c, 0xe06, 0xe86, 0xe46, 0x125c,\n  0xd07, 0xe5e, 0xe1e, 0x120c, 0xd17, 0xe7e, 0xe3e, 0x124c,\n  0xd0f, 0xe6e, 0xe2e, 0x122c, 0xe0e, 0xe8e, 0xe4e, 0x126c,\n  0xd00, 0xe51, 0xe11, 0xf19, 0xd10, 0xe71, 0xe31, 0x1232,\n  0xd08, 0xe61, 0xe21, 0x1212, 0xe01, 0xe81, 0xe41, 0x1252,\n  0xd04, 0xe59, 0xe19, 0x1202, 0xd14, 0xe79, 0xe39, 0x1242,\n  0xd0c, 0xe69, 0xe29, 0x1222, 0xe09, 0xe89, 0xe49, 0x1262,\n  0xd02, 0xe55, 0xe15, 0xf1d, 0xd12, 0xe75, 0xe35, 0x123a,\n  0xd0a, 0xe65, 0xe25, 0x121a, 0xe05, 0xe85, 0xe45, 0x125a,\n  0xd06, 0xe5d, 0xe1d, 0x120a, 0xd16, 0xe7d, 0xe3d, 0x124a,\n  0xd0e, 0xe6d, 0xe2d, 0x122a, 0xe0d, 0xe8d, 0xe4d, 0x126a,\n  0xd01, 0xe53, 0xe13, 0xf1b, 0xd11, 0xe73, 0xe33, 0x1236,\n  0xd09, 0xe63, 0xe23, 0x1216, 0xe03, 0xe83, 0xe43, 0x1256,\n  0xd05, 0xe5b, 0xe1b, 0x1206, 0xd15, 0xe7b, 0xe3b, 0x1246,\n  0xd0d, 0xe6b, 0xe2b, 0x1226, 0xe0b, 0xe8b, 0xe4b, 0x1266,\n  0xd03, 0xe57, 0xe17, 0xf1f, 0xd13, 0xe77, 0xe37, 0x123e,\n  0xd0b, 0xe67, 0xe27, 0x121e, 0xe07, 0xe87, 0xe47, 0x125e,\n  0xd07, 0xe5f, 0xe1f, 0x120e, 0xd17, 0xe7f, 0xe3f, 0x124e,\n  0xd0f, 0xe6f, 0xe2f, 0x122e, 0xe0f, 0xe8f, 0xe4f, 0x126e,\n  0x290, 0x291, 0x292, 0x293, 0x294, 0x295, 0x296, 0x297,\n  0x298, 0x299, 0x29a, 0x29b, 0x29c, 0x29d, 0x29e, 0x29f,\n  0x2a0, 0x2a1, 0x2a2, 0x2a3, 0x2a4, 0x2a5, 0x2a6, 0x2a7,\n  0x2a8, 0x2a9, 0x2aa, 0x2ab, 0x2ac, 0x2ad, 0x2ae, 0x2af,\n  0x2b0, 0x2b1, 0x2b2, 0x2b3, 0x2b4, 0x2b5, 0x2b6, 0x2b7,\n  0x2b8, 0x2b9, 0x2ba, 0x2bb, 0x2bc, 0x2bd, 0x2be, 0x2bf,\n  0x2c0, 0x2c1, 0x2c2, 0x2c3, 0x2c4, 0x2c5, 0x2c6, 0x2c7,\n  0x2c8, 0x2c9, 0x2ca, 0x2cb, 0x2cc, 0x2cd, 0x2ce, 0x2cf,\n  0x2d0, 0x2d1, 0x2d2, 0x2d3, 0x2d4, 0x2d5, 0x2d6, 0x2d7,\n  0x2d8, 0x2d9, 0x2da, 0x2db, 0x2dc, 0x2dd, 0x2de, 0x2df,\n  0x2e0, 0x2e1, 0x2e2, 0x2e3, 0x2e4, 0x2e5, 0x2e6, 0x2e7,\n  0x2e8, 0x2e9, 0x2ea, 0x2eb, 0x2ec, 0x2ed, 0x2ee, 0x2ef,\n  0x2f0, 0x2f1, 0x2f2, 0x2f3, 0x2f4, 0x2f5, 0x2f6, 0x2f7,\n  0x2f8, 0x2f9, 0x2fa, 0x2fb, 0x2fc, 0x2fd, 0x2fe, 0x2ff,\n};\n\nstatic const uint16_t elf_zlib_default_dist_table[0x100] =\n{\n  0x800, 0x810, 0x808, 0x818, 0x804, 0x814, 0x80c, 0x81c,\n  0x802, 0x812, 0x80a, 0x81a, 0x806, 0x816, 0x80e, 0x81e,\n  0x801, 0x811, 0x809, 0x819, 0x805, 0x815, 0x80d, 0x81d,\n  0x803, 0x813, 0x80b, 0x81b, 0x807, 0x817, 0x80f, 0x81f,\n  0x800, 0x810, 0x808, 0x818, 0x804, 0x814, 0x80c, 0x81c,\n  0x802, 0x812, 0x80a, 0x81a, 0x806, 0x816, 0x80e, 0x81e,\n  0x801, 0x811, 0x809, 0x819, 0x805, 0x815, 0x80d, 0x81d,\n  0x803, 0x813, 0x80b, 0x81b, 0x807, 0x817, 0x80f, 0x81f,\n  0x800, 0x810, 0x808, 0x818, 0x804, 0x814, 0x80c, 0x81c,\n  0x802, 0x812, 0x80a, 0x81a, 0x806, 0x816, 0x80e, 0x81e,\n  0x801, 0x811, 0x809, 0x819, 0x805, 0x815, 0x80d, 0x81d,\n  0x803, 0x813, 0x80b, 0x81b, 0x807, 0x817, 0x80f, 0x81f,\n  0x800, 0x810, 0x808, 0x818, 0x804, 0x814, 0x80c, 0x81c,\n  0x802, 0x812, 0x80a, 0x81a, 0x806, 0x816, 0x80e, 0x81e,\n  0x801, 0x811, 0x809, 0x819, 0x805, 0x815, 0x80d, 0x81d,\n  0x803, 0x813, 0x80b, 0x81b, 0x807, 0x817, 0x80f, 0x81f,\n  0x800, 0x810, 0x808, 0x818, 0x804, 0x814, 0x80c, 0x81c,\n  0x802, 0x812, 0x80a, 0x81a, 0x806, 0x816, 0x80e, 0x81e,\n  0x801, 0x811, 0x809, 0x819, 0x805, 0x815, 0x80d, 0x81d,\n  0x803, 0x813, 0x80b, 0x81b, 0x807, 0x817, 0x80f, 0x81f,\n  0x800, 0x810, 0x808, 0x818, 0x804, 0x814, 0x80c, 0x81c,\n  0x802, 0x812, 0x80a, 0x81a, 0x806, 0x816, 0x80e, 0x81e,\n  0x801, 0x811, 0x809, 0x819, 0x805, 0x815, 0x80d, 0x81d,\n  0x803, 0x813, 0x80b, 0x81b, 0x807, 0x817, 0x80f, 0x81f,\n  0x800, 0x810, 0x808, 0x818, 0x804, 0x814, 0x80c, 0x81c,\n  0x802, 0x812, 0x80a, 0x81a, 0x806, 0x816, 0x80e, 0x81e,\n  0x801, 0x811, 0x809, 0x819, 0x805, 0x815, 0x80d, 0x81d,\n  0x803, 0x813, 0x80b, 0x81b, 0x807, 0x817, 0x80f, 0x81f,\n  0x800, 0x810, 0x808, 0x818, 0x804, 0x814, 0x80c, 0x81c,\n  0x802, 0x812, 0x80a, 0x81a, 0x806, 0x816, 0x80e, 0x81e,\n  0x801, 0x811, 0x809, 0x819, 0x805, 0x815, 0x80d, 0x81d,\n  0x803, 0x813, 0x80b, 0x81b, 0x807, 0x817, 0x80f, 0x81f,\n};\n\n/* Inflate a zlib stream from PIN/SIN to POUT/SOUT.  Return 1 on\n   success, 0 on some error parsing the stream.  */\n\nstatic int\nelf_zlib_inflate (const unsigned char *pin, size_t sin, uint16_t *zdebug_table,\n\t\t  unsigned char *pout, size_t sout)\n{\n  unsigned char *porigout;\n  const unsigned char *pinend;\n  unsigned char *poutend;\n\n  /* We can apparently see multiple zlib streams concatenated\n     together, so keep going as long as there is something to read.\n     The last 4 bytes are the checksum.  */\n  porigout = pout;\n  pinend = pin + sin;\n  poutend = pout + sout;\n  while ((pinend - pin) > 4)\n    {\n      uint64_t val;\n      unsigned int bits;\n      int last;\n\n      /* Read the two byte zlib header.  */\n\n      if (unlikely ((pin[0] & 0xf) != 8)) /* 8 is zlib encoding.  */\n\t{\n\t  /* Unknown compression method.  */\n\t  elf_uncompress_failed ();\n\t  return 0;\n\t}\n      if (unlikely ((pin[0] >> 4) > 7))\n\t{\n\t  /* Window size too large.  Other than this check, we don't\n\t     care about the window size.  */\n\t  elf_uncompress_failed ();\n\t  return 0;\n\t}\n      if (unlikely ((pin[1] & 0x20) != 0))\n\t{\n\t  /* Stream expects a predefined dictionary, but we have no\n\t     dictionary.  */\n\t  elf_uncompress_failed ();\n\t  return 0;\n\t}\n      val = (pin[0] << 8) | pin[1];\n      if (unlikely (val % 31 != 0))\n\t{\n\t  /* Header check failure.  */\n\t  elf_uncompress_failed ();\n\t  return 0;\n\t}\n      pin += 2;\n\n      /* Align PIN to a 32-bit boundary.  */\n\n      val = 0;\n      bits = 0;\n      while ((((uintptr_t) pin) & 3) != 0)\n\t{\n\t  val |= (uint64_t)*pin << bits;\n\t  bits += 8;\n\t  ++pin;\n\t}\n\n      /* Read blocks until one is marked last.  */\n\n      last = 0;\n\n      while (!last)\n\t{\n\t  unsigned int type;\n\t  const uint16_t *tlit;\n\t  const uint16_t *tdist;\n\n\t  if (!elf_fetch_bits (&pin, pinend, &val, &bits))\n\t    return 0;\n\n\t  last = val & 1;\n\t  type = (val >> 1) & 3;\n\t  val >>= 3;\n\t  bits -= 3;\n\n\t  if (unlikely (type == 3))\n\t    {\n\t      /* Invalid block type.  */\n\t      elf_uncompress_failed ();\n\t      return 0;\n\t    }\n\n\t  if (type == 0)\n\t    {\n\t      uint16_t len;\n\t      uint16_t lenc;\n\n\t      /* An uncompressed block.  */\n\n\t      /* If we've read ahead more than a byte, back up.  */\n\t      while (bits >= 8)\n\t\t{\n\t\t  --pin;\n\t\t  bits -= 8;\n\t\t}\n\n\t      val = 0;\n\t      bits = 0;\n\t      if (unlikely ((pinend - pin) < 4))\n\t\t{\n\t\t  /* Missing length.  */\n\t\t  elf_uncompress_failed ();\n\t\t  return 0;\n\t\t}\n\t      len = pin[0] | (pin[1] << 8);\n\t      lenc = pin[2] | (pin[3] << 8);\n\t      pin += 4;\n\t      lenc = ~lenc;\n\t      if (unlikely (len != lenc))\n\t\t{\n\t\t  /* Corrupt data.  */\n\t\t  elf_uncompress_failed ();\n\t\t  return 0;\n\t\t}\n\t      if (unlikely (len > (unsigned int) (pinend - pin)\n\t\t\t    || len > (unsigned int) (poutend - pout)))\n\t\t{\n\t\t  /* Not enough space in buffers.  */\n\t\t  elf_uncompress_failed ();\n\t\t  return 0;\n\t\t}\n\t      memcpy (pout, pin, len);\n\t      pout += len;\n\t      pin += len;\n\n\t      /* Align PIN.  */\n\t      while ((((uintptr_t) pin) & 3) != 0)\n\t\t{\n\t\t  val |= (uint64_t)*pin << bits;\n\t\t  bits += 8;\n\t\t  ++pin;\n\t\t}\n\n\t      /* Go around to read the next block.  */\n\t      continue;\n\t    }\n\n\t  if (type == 1)\n\t    {\n\t      tlit = elf_zlib_default_table;\n\t      tdist = elf_zlib_default_dist_table;\n\t    }\n\t  else\n\t    {\n\t      unsigned int nlit;\n\t      unsigned int ndist;\n\t      unsigned int nclen;\n\t      unsigned char codebits[19];\n\t      unsigned char *plenbase;\n\t      unsigned char *plen;\n\t      unsigned char *plenend;\n\n\t      /* Read a Huffman encoding table.  The various magic\n\t\t numbers here are from RFC 1951.  */\n\n\t      if (!elf_fetch_bits (&pin, pinend, &val, &bits))\n\t\treturn 0;\n\n\t      nlit = (val & 0x1f) + 257;\n\t      val >>= 5;\n\t      ndist = (val & 0x1f) + 1;\n\t      val >>= 5;\n\t      nclen = (val & 0xf) + 4;\n\t      val >>= 4;\n\t      bits -= 14;\n\t      if (unlikely (nlit > 286 || ndist > 30))\n\t\t{\n\t\t  /* Values out of range.  */\n\t\t  elf_uncompress_failed ();\n\t\t  return 0;\n\t\t}\n\n\t      /* Read and build the table used to compress the\n\t\t literal, length, and distance codes.  */\n\n\t      memset(&codebits[0], 0, 19);\n\n\t      /* There are always at least 4 elements in the\n\t\t table.  */\n\n\t      if (!elf_fetch_bits (&pin, pinend, &val, &bits))\n\t\treturn 0;\n\n\t      codebits[16] = val & 7;\n\t      codebits[17] = (val >> 3) & 7;\n\t      codebits[18] = (val >> 6) & 7;\n\t      codebits[0] = (val >> 9) & 7;\n\t      val >>= 12;\n\t      bits -= 12;\n\n\t      if (nclen == 4)\n\t\tgoto codebitsdone;\n\n\t      codebits[8] = val & 7;\n\t      val >>= 3;\n\t      bits -= 3;\n\n\t      if (nclen == 5)\n\t\tgoto codebitsdone;\n\n\t      if (!elf_fetch_bits (&pin, pinend, &val, &bits))\n\t\treturn 0;\n\n\t      codebits[7] = val & 7;\n\t      val >>= 3;\n\t      bits -= 3;\n\n\t      if (nclen == 6)\n\t\tgoto codebitsdone;\n\n\t      codebits[9] = val & 7;\n\t      val >>= 3;\n\t      bits -= 3;\n\n\t      if (nclen == 7)\n\t\tgoto codebitsdone;\n\n\t      codebits[6] = val & 7;\n\t      val >>= 3;\n\t      bits -= 3;\n\n\t      if (nclen == 8)\n\t\tgoto codebitsdone;\n\n\t      codebits[10] = val & 7;\n\t      val >>= 3;\n\t      bits -= 3;\n\n\t      if (nclen == 9)\n\t\tgoto codebitsdone;\n\n\t      codebits[5] = val & 7;\n\t      val >>= 3;\n\t      bits -= 3;\n\n\t      if (nclen == 10)\n\t\tgoto codebitsdone;\n\n\t      if (!elf_fetch_bits (&pin, pinend, &val, &bits))\n\t\treturn 0;\n\n\t      codebits[11] = val & 7;\n\t      val >>= 3;\n\t      bits -= 3;\n\n\t      if (nclen == 11)\n\t\tgoto codebitsdone;\n\n\t      codebits[4] = val & 7;\n\t      val >>= 3;\n\t      bits -= 3;\n\n\t      if (nclen == 12)\n\t\tgoto codebitsdone;\n\n\t      codebits[12] = val & 7;\n\t      val >>= 3;\n\t      bits -= 3;\n\n\t      if (nclen == 13)\n\t\tgoto codebitsdone;\n\n\t      codebits[3] = val & 7;\n\t      val >>= 3;\n\t      bits -= 3;\n\n\t      if (nclen == 14)\n\t\tgoto codebitsdone;\n\n\t      codebits[13] = val & 7;\n\t      val >>= 3;\n\t      bits -= 3;\n\n\t      if (nclen == 15)\n\t\tgoto codebitsdone;\n\n\t      if (!elf_fetch_bits (&pin, pinend, &val, &bits))\n\t\treturn 0;\n\n\t      codebits[2] = val & 7;\n\t      val >>= 3;\n\t      bits -= 3;\n\n\t      if (nclen == 16)\n\t\tgoto codebitsdone;\n\n\t      codebits[14] = val & 7;\n\t      val >>= 3;\n\t      bits -= 3;\n\n\t      if (nclen == 17)\n\t\tgoto codebitsdone;\n\n\t      codebits[1] = val & 7;\n\t      val >>= 3;\n\t      bits -= 3;\n\n\t      if (nclen == 18)\n\t\tgoto codebitsdone;\n\n\t      codebits[15] = val & 7;\n\t      val >>= 3;\n\t      bits -= 3;\n\n\t    codebitsdone:\n\n\t      if (!elf_zlib_inflate_table (codebits, 19, zdebug_table,\n\t\t\t\t\t   zdebug_table))\n\t\treturn 0;\n\n\t      /* Read the compressed bit lengths of the literal,\n\t\t length, and distance codes.  We have allocated space\n\t\t at the end of zdebug_table to hold them.  */\n\n\t      plenbase = (((unsigned char *) zdebug_table)\n\t\t\t  + ZLIB_TABLE_CODELEN_OFFSET);\n\t      plen = plenbase;\n\t      plenend = plen + nlit + ndist;\n\t      while (plen < plenend)\n\t\t{\n\t\t  uint16_t t;\n\t\t  unsigned int b;\n\t\t  uint16_t v;\n\n\t\t  if (!elf_fetch_bits (&pin, pinend, &val, &bits))\n\t\t    return 0;\n\n\t\t  t = zdebug_table[val & 0xff];\n\n\t\t  /* The compression here uses bit lengths up to 7, so\n\t\t     a secondary table is never necessary.  */\n\t\t  if (unlikely ((t & (1U << ZLIB_HUFFMAN_SECONDARY_SHIFT))\n\t\t\t\t!= 0))\n\t\t    {\n\t\t      elf_uncompress_failed ();\n\t\t      return 0;\n\t\t    }\n\n\t\t  b = (t >> ZLIB_HUFFMAN_BITS_SHIFT) & ZLIB_HUFFMAN_BITS_MASK;\n\t\t  val >>= b + 1;\n\t\t  bits -= b + 1;\n\n\t\t  v = t & ZLIB_HUFFMAN_VALUE_MASK;\n\t\t  if (v < 16)\n\t\t    *plen++ = v;\n\t\t  else if (v == 16)\n\t\t    {\n\t\t      unsigned int c;\n\t\t      unsigned int prev;\n\n\t\t      /* Copy previous entry 3 to 6 times.  */\n\n\t\t      if (unlikely (plen == plenbase))\n\t\t\t{\n\t\t\t  elf_uncompress_failed ();\n\t\t\t  return 0;\n\t\t\t}\n\n\t\t      /* We used up to 7 bits since the last\n\t\t\t elf_fetch_bits, so we have at least 8 bits\n\t\t\t available here.  */\n\n\t\t      c = 3 + (val & 0x3);\n\t\t      val >>= 2;\n\t\t      bits -= 2;\n\t\t      if (unlikely ((unsigned int) (plenend - plen) < c))\n\t\t\t{\n\t\t\t  elf_uncompress_failed ();\n\t\t\t  return 0;\n\t\t\t}\n\n\t\t      prev = plen[-1];\n\t\t      switch (c)\n\t\t\t{\n\t\t\tcase 6:\n\t\t\t  *plen++ = prev;\n\t\t\t  ATTRIBUTE_FALLTHROUGH;\n\t\t\tcase 5:\n\t\t\t  *plen++ = prev;\n\t\t\t  ATTRIBUTE_FALLTHROUGH;\n\t\t\tcase 4:\n\t\t\t  *plen++ = prev;\n\t\t\t}\n\t\t      *plen++ = prev;\n\t\t      *plen++ = prev;\n\t\t      *plen++ = prev;\n\t\t    }\n\t\t  else if (v == 17)\n\t\t    {\n\t\t      unsigned int c;\n\n\t\t      /* Store zero 3 to 10 times.  */\n\n\t\t      /* We used up to 7 bits since the last\n\t\t\t elf_fetch_bits, so we have at least 8 bits\n\t\t\t available here.  */\n\n\t\t      c = 3 + (val & 0x7);\n\t\t      val >>= 3;\n\t\t      bits -= 3;\n\t\t      if (unlikely ((unsigned int) (plenend - plen) < c))\n\t\t\t{\n\t\t\t  elf_uncompress_failed ();\n\t\t\t  return 0;\n\t\t\t}\n\n\t\t      switch (c)\n\t\t\t{\n\t\t\tcase 10:\n\t\t\t  *plen++ = 0;\n\t\t\t  ATTRIBUTE_FALLTHROUGH;\n\t\t\tcase 9:\n\t\t\t  *plen++ = 0;\n\t\t\t  ATTRIBUTE_FALLTHROUGH;\n\t\t\tcase 8:\n\t\t\t  *plen++ = 0;\n\t\t\t  ATTRIBUTE_FALLTHROUGH;\n\t\t\tcase 7:\n\t\t\t  *plen++ = 0;\n\t\t\t  ATTRIBUTE_FALLTHROUGH;\n\t\t\tcase 6:\n\t\t\t  *plen++ = 0;\n\t\t\t  ATTRIBUTE_FALLTHROUGH;\n\t\t\tcase 5:\n\t\t\t  *plen++ = 0;\n\t\t\t  ATTRIBUTE_FALLTHROUGH;\n\t\t\tcase 4:\n\t\t\t  *plen++ = 0;\n\t\t\t}\n\t\t      *plen++ = 0;\n\t\t      *plen++ = 0;\n\t\t      *plen++ = 0;\n\t\t    }\n\t\t  else if (v == 18)\n\t\t    {\n\t\t      unsigned int c;\n\n\t\t      /* Store zero 11 to 138 times.  */\n\n\t\t      /* We used up to 7 bits since the last\n\t\t\t elf_fetch_bits, so we have at least 8 bits\n\t\t\t available here.  */\n\n\t\t      c = 11 + (val & 0x7f);\n\t\t      val >>= 7;\n\t\t      bits -= 7;\n\t\t      if (unlikely ((unsigned int) (plenend - plen) < c))\n\t\t\t{\n\t\t\t  elf_uncompress_failed ();\n\t\t\t  return 0;\n\t\t\t}\n\n\t\t      memset (plen, 0, c);\n\t\t      plen += c;\n\t\t    }\n\t\t  else\n\t\t    {\n\t\t      elf_uncompress_failed ();\n\t\t      return 0;\n\t\t    }\n\t\t}\n\n\t      /* Make sure that the stop code can appear.  */\n\n\t      plen = plenbase;\n\t      if (unlikely (plen[256] == 0))\n\t\t{\n\t\t  elf_uncompress_failed ();\n\t\t  return 0;\n\t\t}\n\n\t      /* Build the decompression tables.  */\n\n\t      if (!elf_zlib_inflate_table (plen, nlit, zdebug_table,\n\t\t\t\t\t   zdebug_table))\n\t\treturn 0;\n\t      if (!elf_zlib_inflate_table (plen + nlit, ndist, zdebug_table,\n\t\t\t\t\t   (zdebug_table\n\t\t\t\t\t    + ZLIB_HUFFMAN_TABLE_SIZE)))\n\t\treturn 0;\n\t      tlit = zdebug_table;\n\t      tdist = zdebug_table + ZLIB_HUFFMAN_TABLE_SIZE;\n\t    }\n\n\t  /* Inflate values until the end of the block.  This is the\n\t     main loop of the inflation code.  */\n\n\t  while (1)\n\t    {\n\t      uint16_t t;\n\t      unsigned int b;\n\t      uint16_t v;\n\t      unsigned int lit;\n\n\t      if (!elf_fetch_bits (&pin, pinend, &val, &bits))\n\t\treturn 0;\n\n\t      t = tlit[val & 0xff];\n\t      b = (t >> ZLIB_HUFFMAN_BITS_SHIFT) & ZLIB_HUFFMAN_BITS_MASK;\n\t      v = t & ZLIB_HUFFMAN_VALUE_MASK;\n\n\t      if ((t & (1U << ZLIB_HUFFMAN_SECONDARY_SHIFT)) == 0)\n\t\t{\n\t\t  lit = v;\n\t\t  val >>= b + 1;\n\t\t  bits -= b + 1;\n\t\t}\n\t      else\n\t\t{\n\t\t  t = tlit[v + 0x100 + ((val >> 8) & ((1U << b) - 1))];\n\t\t  b = (t >> ZLIB_HUFFMAN_BITS_SHIFT) & ZLIB_HUFFMAN_BITS_MASK;\n\t\t  lit = t & ZLIB_HUFFMAN_VALUE_MASK;\n\t\t  val >>= b + 8;\n\t\t  bits -= b + 8;\n\t\t}\n\n\t      if (lit < 256)\n\t\t{\n\t\t  if (unlikely (pout == poutend))\n\t\t    {\n\t\t      elf_uncompress_failed ();\n\t\t      return 0;\n\t\t    }\n\n\t\t  *pout++ = lit;\n\n\t\t  /* We will need to write the next byte soon.  We ask\n\t\t     for high temporal locality because we will write\n\t\t     to the whole cache line soon.  */\n\t\t  __builtin_prefetch (pout, 1, 3);\n\t\t}\n\t      else if (lit == 256)\n\t\t{\n\t\t  /* The end of the block.  */\n\t\t  break;\n\t\t}\n\t      else\n\t\t{\n\t\t  unsigned int dist;\n\t\t  unsigned int len;\n\n\t\t  /* Convert lit into a length.  */\n\n\t\t  if (lit < 265)\n\t\t    len = lit - 257 + 3;\n\t\t  else if (lit == 285)\n\t\t    len = 258;\n\t\t  else if (unlikely (lit > 285))\n\t\t    {\n\t\t      elf_uncompress_failed ();\n\t\t      return 0;\n\t\t    }\n\t\t  else\n\t\t    {\n\t\t      unsigned int extra;\n\n\t\t      if (!elf_fetch_bits (&pin, pinend, &val, &bits))\n\t\t\treturn 0;\n\n\t\t      /* This is an expression for the table of length\n\t\t\t codes in RFC 1951 3.2.5.  */\n\t\t      lit -= 265;\n\t\t      extra = (lit >> 2) + 1;\n\t\t      len = (lit & 3) << extra;\n\t\t      len += 11;\n\t\t      len += ((1U << (extra - 1)) - 1) << 3;\n\t\t      len += val & ((1U << extra) - 1);\n\t\t      val >>= extra;\n\t\t      bits -= extra;\n\t\t    }\n\n\t\t  if (!elf_fetch_bits (&pin, pinend, &val, &bits))\n\t\t    return 0;\n\n\t\t  t = tdist[val & 0xff];\n\t\t  b = (t >> ZLIB_HUFFMAN_BITS_SHIFT) & ZLIB_HUFFMAN_BITS_MASK;\n\t\t  v = t & ZLIB_HUFFMAN_VALUE_MASK;\n\n\t\t  if ((t & (1U << ZLIB_HUFFMAN_SECONDARY_SHIFT)) == 0)\n\t\t    {\n\t\t      dist = v;\n\t\t      val >>= b + 1;\n\t\t      bits -= b + 1;\n\t\t    }\n\t\t  else\n\t\t    {\n\t\t      t = tdist[v + 0x100 + ((val >> 8) & ((1U << b) - 1))];\n\t\t      b = ((t >> ZLIB_HUFFMAN_BITS_SHIFT)\n\t\t\t   & ZLIB_HUFFMAN_BITS_MASK);\n\t\t      dist = t & ZLIB_HUFFMAN_VALUE_MASK;\n\t\t      val >>= b + 8;\n\t\t      bits -= b + 8;\n\t\t    }\n\n\t\t  /* Convert dist to a distance.  */\n\n\t\t  if (dist == 0)\n\t\t    {\n\t\t      /* A distance of 1.  A common case, meaning\n\t\t\t repeat the last character LEN times.  */\n\n\t\t      if (unlikely (pout == porigout))\n\t\t\t{\n\t\t\t  elf_uncompress_failed ();\n\t\t\t  return 0;\n\t\t\t}\n\n\t\t      if (unlikely ((unsigned int) (poutend - pout) < len))\n\t\t\t{\n\t\t\t  elf_uncompress_failed ();\n\t\t\t  return 0;\n\t\t\t}\n\n\t\t      memset (pout, pout[-1], len);\n\t\t      pout += len;\n\t\t    }\n\t\t  else if (unlikely (dist > 29))\n\t\t    {\n\t\t      elf_uncompress_failed ();\n\t\t      return 0;\n\t\t    }\n\t\t  else\n\t\t    {\n\t\t      if (dist < 4)\n\t\t\tdist = dist + 1;\n\t\t      else\n\t\t\t{\n\t\t\t  unsigned int extra;\n\n\t\t\t  if (!elf_fetch_bits (&pin, pinend, &val, &bits))\n\t\t\t    return 0;\n\n\t\t\t  /* This is an expression for the table of\n\t\t\t     distance codes in RFC 1951 3.2.5.  */\n\t\t\t  dist -= 4;\n\t\t\t  extra = (dist >> 1) + 1;\n\t\t\t  dist = (dist & 1) << extra;\n\t\t\t  dist += 5;\n\t\t\t  dist += ((1U << (extra - 1)) - 1) << 2;\n\t\t\t  dist += val & ((1U << extra) - 1);\n\t\t\t  val >>= extra;\n\t\t\t  bits -= extra;\n\t\t\t}\n\n\t\t      /* Go back dist bytes, and copy len bytes from\n\t\t\t there.  */\n\n\t\t      if (unlikely ((unsigned int) (pout - porigout) < dist))\n\t\t\t{\n\t\t\t  elf_uncompress_failed ();\n\t\t\t  return 0;\n\t\t\t}\n\n\t\t      if (unlikely ((unsigned int) (poutend - pout) < len))\n\t\t\t{\n\t\t\t  elf_uncompress_failed ();\n\t\t\t  return 0;\n\t\t\t}\n\n\t\t      if (dist >= len)\n\t\t\t{\n\t\t\t  memcpy (pout, pout - dist, len);\n\t\t\t  pout += len;\n\t\t\t}\n\t\t      else\n\t\t\t{\n\t\t\t  while (len > 0)\n\t\t\t    {\n\t\t\t      unsigned int copy;\n\n\t\t\t      copy = len < dist ? len : dist;\n\t\t\t      memcpy (pout, pout - dist, copy);\n\t\t\t      len -= copy;\n\t\t\t      pout += copy;\n\t\t\t    }\n\t\t\t}\n\t\t    }\n\t\t}\n\t    }\n\t}\n    }\n\n  /* We should have filled the output buffer.  */\n  if (unlikely (pout != poutend))\n    {\n      elf_uncompress_failed ();\n      return 0;\n    }\n\n  return 1;\n}\n\n/* Verify the zlib checksum.  The checksum is in the 4 bytes at\n   CHECKBYTES, and the uncompressed data is at UNCOMPRESSED /\n   UNCOMPRESSED_SIZE.  Returns 1 on success, 0 on failure.  */\n\nstatic int\nelf_zlib_verify_checksum (const unsigned char *checkbytes,\n\t\t\t  const unsigned char *uncompressed,\n\t\t\t  size_t uncompressed_size)\n{\n  unsigned int i;\n  unsigned int cksum;\n  const unsigned char *p;\n  uint32_t s1;\n  uint32_t s2;\n  size_t hsz;\n\n  cksum = 0;\n  for (i = 0; i < 4; i++)\n    cksum = (cksum << 8) | checkbytes[i];\n\n  s1 = 1;\n  s2 = 0;\n\n  /* Minimize modulo operations.  */\n\n  p = uncompressed;\n  hsz = uncompressed_size;\n  while (hsz >= 5552)\n    {\n      for (i = 0; i < 5552; i += 16)\n\t{\n\t  /* Manually unroll loop 16 times.  */\n\t  s1 = s1 + *p++;\n\t  s2 = s2 + s1;\n\t  s1 = s1 + *p++;\n\t  s2 = s2 + s1;\n\t  s1 = s1 + *p++;\n\t  s2 = s2 + s1;\n\t  s1 = s1 + *p++;\n\t  s2 = s2 + s1;\n\t  s1 = s1 + *p++;\n\t  s2 = s2 + s1;\n\t  s1 = s1 + *p++;\n\t  s2 = s2 + s1;\n\t  s1 = s1 + *p++;\n\t  s2 = s2 + s1;\n\t  s1 = s1 + *p++;\n\t  s2 = s2 + s1;\n\t  s1 = s1 + *p++;\n\t  s2 = s2 + s1;\n\t  s1 = s1 + *p++;\n\t  s2 = s2 + s1;\n\t  s1 = s1 + *p++;\n\t  s2 = s2 + s1;\n\t  s1 = s1 + *p++;\n\t  s2 = s2 + s1;\n\t  s1 = s1 + *p++;\n\t  s2 = s2 + s1;\n\t  s1 = s1 + *p++;\n\t  s2 = s2 + s1;\n\t  s1 = s1 + *p++;\n\t  s2 = s2 + s1;\n\t  s1 = s1 + *p++;\n\t  s2 = s2 + s1;\n\t}\n      hsz -= 5552;\n      s1 %= 65521;\n      s2 %= 65521;\n    }\n\n  while (hsz >= 16)\n    {\n      /* Manually unroll loop 16 times.  */\n      s1 = s1 + *p++;\n      s2 = s2 + s1;\n      s1 = s1 + *p++;\n      s2 = s2 + s1;\n      s1 = s1 + *p++;\n      s2 = s2 + s1;\n      s1 = s1 + *p++;\n      s2 = s2 + s1;\n      s1 = s1 + *p++;\n      s2 = s2 + s1;\n      s1 = s1 + *p++;\n      s2 = s2 + s1;\n      s1 = s1 + *p++;\n      s2 = s2 + s1;\n      s1 = s1 + *p++;\n      s2 = s2 + s1;\n      s1 = s1 + *p++;\n      s2 = s2 + s1;\n      s1 = s1 + *p++;\n      s2 = s2 + s1;\n      s1 = s1 + *p++;\n      s2 = s2 + s1;\n      s1 = s1 + *p++;\n      s2 = s2 + s1;\n      s1 = s1 + *p++;\n      s2 = s2 + s1;\n      s1 = s1 + *p++;\n      s2 = s2 + s1;\n      s1 = s1 + *p++;\n      s2 = s2 + s1;\n      s1 = s1 + *p++;\n      s2 = s2 + s1;\n\n      hsz -= 16;\n    }\n\n  for (i = 0; i < hsz; ++i)\n    {\n      s1 = s1 + *p++;\n      s2 = s2 + s1;\n    }\n\n  s1 %= 65521;\n  s2 %= 65521;\n\n  if (unlikely ((s2 << 16) + s1 != cksum))\n    {\n      elf_uncompress_failed ();\n      return 0;\n    }\n\n  return 1;\n}\n\n/* Inflate a zlib stream from PIN/SIN to POUT/SOUT, and verify the\n   checksum.  Return 1 on success, 0 on error.  */\n\nstatic int\nelf_zlib_inflate_and_verify (const unsigned char *pin, size_t sin,\n\t\t\t     uint16_t *zdebug_table, unsigned char *pout,\n\t\t\t     size_t sout)\n{\n  if (!elf_zlib_inflate (pin, sin, zdebug_table, pout, sout))\n    return 0;\n  if (!elf_zlib_verify_checksum (pin + sin - 4, pout, sout))\n    return 0;\n  return 1;\n}\n\n/* For working memory during zstd compression, we need\n   - a literal length FSE table: 512 64-bit values == 4096 bytes\n   - a match length FSE table: 512 64-bit values == 4096 bytes\n   - a offset FSE table: 256 64-bit values == 2048 bytes\n   - a Huffman tree: 2048 uint16_t values == 4096 bytes\n   - scratch space, one of\n     - to build an FSE table: 512 uint16_t values == 1024 bytes\n     - to build a Huffman tree: 512 uint16_t + 256 uint32_t == 2048 bytes\n*/\n\n#define ZSTD_TABLE_SIZE\t\t\t\t\t\\\n  (2 * 512 * sizeof (struct elf_zstd_fse_baseline_entry)\t\\\n   + 256 * sizeof (struct elf_zstd_fse_baseline_entry)\t\t\\\n   + 2048 * sizeof (uint16_t)\t\t\t\t\t\\\n   + 512 * sizeof (uint16_t) + 256 * sizeof (uint32_t))\n\n#define ZSTD_TABLE_LITERAL_FSE_OFFSET (0)\n\n#define ZSTD_TABLE_MATCH_FSE_OFFSET\t\t\t\\\n  (512 * sizeof (struct elf_zstd_fse_baseline_entry))\n\n#define ZSTD_TABLE_OFFSET_FSE_OFFSET\t\t\t\\\n  (ZSTD_TABLE_MATCH_FSE_OFFSET\t\t\t\t\\\n   + 512 * sizeof (struct elf_zstd_fse_baseline_entry))\n\n#define ZSTD_TABLE_HUFFMAN_OFFSET\t\t\t\t\t\\\n  (ZSTD_TABLE_OFFSET_FSE_OFFSET\t\t\t\t\t\t\\\n   + 256 * sizeof (struct elf_zstd_fse_baseline_entry))\n\n#define ZSTD_TABLE_WORK_OFFSET \\\n  (ZSTD_TABLE_HUFFMAN_OFFSET + 2048 * sizeof (uint16_t))\n\n/* An entry in a zstd FSE table.  */\n\nstruct elf_zstd_fse_entry\n{\n  /* The value that this FSE entry represents.  */\n  unsigned char symbol;\n  /* The number of bits to read to determine the next state.  */\n  unsigned char bits;\n  /* Add the bits to this base to get the next state.  */\n  uint16_t base;\n};\n\nstatic int\nelf_zstd_build_fse (const int16_t *, int, uint16_t *, int,\n\t\t    struct elf_zstd_fse_entry *);\n\n/* Read a zstd FSE table and build the decoding table in *TABLE, updating *PPIN\n   as it reads.  ZDEBUG_TABLE is scratch space; it must be enough for 512\n   uint16_t values (1024 bytes).  MAXIDX is the maximum number of symbols\n   permitted. *TABLE_BITS is the maximum number of bits for symbols in the\n   table: the size of *TABLE is at least 1 << *TABLE_BITS.  This updates\n   *TABLE_BITS to the actual number of bits.  Returns 1 on success, 0 on\n   error.  */\n\nstatic int\nelf_zstd_read_fse (const unsigned char **ppin, const unsigned char *pinend,\n\t\t   uint16_t *zdebug_table, int maxidx,\n\t\t   struct elf_zstd_fse_entry *table, int *table_bits)\n{\n  const unsigned char *pin;\n  int16_t *norm;\n  uint16_t *next;\n  uint64_t val;\n  unsigned int bits;\n  int accuracy_log;\n  uint32_t remaining;\n  uint32_t threshold;\n  int bits_needed;\n  int idx;\n  int prev0;\n\n  pin = *ppin;\n\n  norm = (int16_t *) zdebug_table;\n  next = zdebug_table + 256;\n\n  if (unlikely (pin + 3 >= pinend))\n    {\n      elf_uncompress_failed ();\n      return 0;\n    }\n\n  /* Align PIN to a 32-bit boundary.  */\n\n  val = 0;\n  bits = 0;\n  while ((((uintptr_t) pin) & 3) != 0)\n    {\n      val |= (uint64_t)*pin << bits;\n      bits += 8;\n      ++pin;\n    }\n\n  if (!elf_fetch_bits (&pin, pinend, &val, &bits))\n    return 0;\n\n  accuracy_log = (val & 0xf) + 5;\n  if (accuracy_log > *table_bits)\n    {\n      elf_uncompress_failed ();\n      return 0;\n    }\n  *table_bits = accuracy_log;\n  val >>= 4;\n  bits -= 4;\n\n  /* This code is mostly copied from the reference implementation.  */\n\n  /* The number of remaining probabilities, plus 1.  This sets the number of\n     bits that need to be read for the next value.  */\n  remaining = (1 << accuracy_log) + 1;\n\n  /* The current difference between small and large values, which depends on\n     the number of remaining values.  Small values use one less bit.  */\n  threshold = 1 << accuracy_log;\n\n  /* The number of bits used to compute threshold.  */\n  bits_needed = accuracy_log + 1;\n\n  /* The next character value.  */\n  idx = 0;\n\n  /* Whether the last count was 0.  */\n  prev0 = 0;\n\n  while (remaining > 1 && idx <= maxidx)\n    {\n      uint32_t max;\n      int32_t count;\n\n      if (!elf_fetch_bits (&pin, pinend, &val, &bits))\n\treturn 0;\n\n      if (prev0)\n\t{\n\t  int zidx;\n\n\t  /* Previous count was 0, so there is a 2-bit repeat flag.  If the\n\t     2-bit flag is 0b11, it adds 3 and then there is another repeat\n\t     flag.  */\n\t  zidx = idx;\n\t  while ((val & 0xfff) == 0xfff)\n\t    {\n\t      zidx += 3 * 6;\n\t      val >>= 12;\n\t      bits -= 12;\n\t      if  (!elf_fetch_bits (&pin, pinend, &val, &bits))\n\t\treturn 0;\n\t    }\n\t  while ((val & 3) == 3)\n\t    {\n\t      zidx += 3;\n\t      val >>= 2;\n\t      bits -= 2;\n\t      if (!elf_fetch_bits (&pin, pinend, &val, &bits))\n\t\treturn 0;\n\t    }\n\t  /* We have at least 13 bits here, don't need to fetch.  */\n\t  zidx += val & 3;\n\t  val >>= 2;\n\t  bits -= 2;\n\n\t  if (unlikely (zidx > maxidx))\n\t    {\n\t      elf_uncompress_failed ();\n\t      return 0;\n\t    }\n\n\t  for (; idx < zidx; idx++)\n\t    norm[idx] = 0;\n\n\t  prev0 = 0;\n\t  continue;\n\t}\n\n      max = (2 * threshold - 1) - remaining;\n      if ((val & (threshold - 1)) < max)\n\t{\n\t  /* A small value.  */\n\t  count = (int32_t) ((uint32_t) val & (threshold - 1));\n\t  val >>= bits_needed - 1;\n\t  bits -= bits_needed - 1;\n\t}\n      else\n\t{\n\t  /* A large value.  */\n\t  count = (int32_t) ((uint32_t) val & (2 * threshold - 1));\n\t  if (count >= (int32_t) threshold)\n\t    count -= (int32_t) max;\n\t  val >>= bits_needed;\n\t  bits -= bits_needed;\n\t}\n\n      count--;\n      if (count >= 0)\n\tremaining -= count;\n      else\n\tremaining--;\n      if (unlikely (idx >= 256))\n\t{\n\t  elf_uncompress_failed ();\n\t  return 0;\n\t}\n      norm[idx] = (int16_t) count;\n      ++idx;\n\n      prev0 = count == 0;\n\n      while (remaining < threshold)\n\t{\n\t  bits_needed--;\n\t  threshold >>= 1;\n\t}\n    }\n\n  if (unlikely (remaining != 1))\n    {\n      elf_uncompress_failed ();\n      return 0;\n    }\n\n  /* If we've read ahead more than a byte, back up.  */\n  while (bits >= 8)\n    {\n      --pin;\n      bits -= 8;\n    }\n\n  *ppin = pin;\n\n  for (; idx <= maxidx; idx++)\n    norm[idx] = 0;\n\n  return elf_zstd_build_fse (norm, idx, next, *table_bits, table);\n}\n\n/* Build the FSE decoding table from a list of probabilities.  This reads from\n   NORM of length IDX, uses NEXT as scratch space, and writes to *TABLE, whose\n   size is TABLE_BITS.  */\n\nstatic int\nelf_zstd_build_fse (const int16_t *norm, int idx, uint16_t *next,\n\t\t    int table_bits, struct elf_zstd_fse_entry *table)\n{\n  int table_size;\n  int high_threshold;\n  int i;\n  int pos;\n  int step;\n  int mask;\n\n  table_size = 1 << table_bits;\n  high_threshold = table_size - 1;\n  for (i = 0; i < idx; i++)\n    {\n      int16_t n;\n\n      n = norm[i];\n      if (n >= 0)\n\tnext[i] = (uint16_t) n;\n      else\n\t{\n\t  table[high_threshold].symbol = (unsigned char) i;\n\t  high_threshold--;\n\t  next[i] = 1;\n\t}\n    }\n\n  pos = 0;\n  step = (table_size >> 1) + (table_size >> 3) + 3;\n  mask = table_size - 1;\n  for (i = 0; i < idx; i++)\n    {\n      int n;\n      int j;\n\n      n = (int) norm[i];\n      for (j = 0; j < n; j++)\n\t{\n\t  table[pos].symbol = (unsigned char) i;\n\t  pos = (pos + step) & mask;\n\t  while (unlikely (pos > high_threshold))\n\t    pos = (pos + step) & mask;\n\t}\n    }\n  if (unlikely (pos != 0))\n    {\n      elf_uncompress_failed ();\n      return 0;\n    }\n\n  for (i = 0; i < table_size; i++)\n    {\n      unsigned char sym;\n      uint16_t next_state;\n      int high_bit;\n      int bits;\n\n      sym = table[i].symbol;\n      next_state = next[sym];\n      ++next[sym];\n\n      if (next_state == 0)\n\t{\n\t  elf_uncompress_failed ();\n\t  return 0;\n\t}\n      high_bit = 31 - __builtin_clz (next_state);\n\n      bits = table_bits - high_bit;\n      table[i].bits = (unsigned char) bits;\n      table[i].base = (uint16_t) ((next_state << bits) - table_size);\n    }\n\n  return 1;\n}\n\n/* Encode the baseline and bits into a single 32-bit value.  */\n\n#define ZSTD_ENCODE_BASELINE_BITS(baseline, basebits)\t\\\n  ((uint32_t)(baseline) | ((uint32_t)(basebits) << 24))\n\n#define ZSTD_DECODE_BASELINE(baseline_basebits)\t\\\n  ((uint32_t)(baseline_basebits) & 0xffffff)\n\n#define ZSTD_DECODE_BASEBITS(baseline_basebits)\t\\\n  ((uint32_t)(baseline_basebits) >> 24)\n\n/* Given a literal length code, we need to read a number of bits and add that\n   to a baseline.  For states 0 to 15 the baseline is the state and the number\n   of bits is zero.  */\n\n#define ZSTD_LITERAL_LENGTH_BASELINE_OFFSET (16)\n\nstatic const uint32_t elf_zstd_literal_length_base[] =\n{\n  ZSTD_ENCODE_BASELINE_BITS(16, 1),\n  ZSTD_ENCODE_BASELINE_BITS(18, 1),\n  ZSTD_ENCODE_BASELINE_BITS(20, 1),\n  ZSTD_ENCODE_BASELINE_BITS(22, 1),\n  ZSTD_ENCODE_BASELINE_BITS(24, 2),\n  ZSTD_ENCODE_BASELINE_BITS(28, 2),\n  ZSTD_ENCODE_BASELINE_BITS(32, 3),\n  ZSTD_ENCODE_BASELINE_BITS(40, 3),\n  ZSTD_ENCODE_BASELINE_BITS(48, 4),\n  ZSTD_ENCODE_BASELINE_BITS(64, 6),\n  ZSTD_ENCODE_BASELINE_BITS(128, 7),\n  ZSTD_ENCODE_BASELINE_BITS(256, 8),\n  ZSTD_ENCODE_BASELINE_BITS(512, 9),\n  ZSTD_ENCODE_BASELINE_BITS(1024, 10),\n  ZSTD_ENCODE_BASELINE_BITS(2048, 11),\n  ZSTD_ENCODE_BASELINE_BITS(4096, 12),\n  ZSTD_ENCODE_BASELINE_BITS(8192, 13),\n  ZSTD_ENCODE_BASELINE_BITS(16384, 14),\n  ZSTD_ENCODE_BASELINE_BITS(32768, 15),\n  ZSTD_ENCODE_BASELINE_BITS(65536, 16)\n};\n\n/* The same applies to match length codes.  For states 0 to 31 the baseline is\n   the state + 3 and the number of bits is zero.  */\n\n#define ZSTD_MATCH_LENGTH_BASELINE_OFFSET (32)\n\nstatic const uint32_t elf_zstd_match_length_base[] =\n{\n  ZSTD_ENCODE_BASELINE_BITS(35, 1),\n  ZSTD_ENCODE_BASELINE_BITS(37, 1),\n  ZSTD_ENCODE_BASELINE_BITS(39, 1),\n  ZSTD_ENCODE_BASELINE_BITS(41, 1),\n  ZSTD_ENCODE_BASELINE_BITS(43, 2),\n  ZSTD_ENCODE_BASELINE_BITS(47, 2),\n  ZSTD_ENCODE_BASELINE_BITS(51, 3),\n  ZSTD_ENCODE_BASELINE_BITS(59, 3),\n  ZSTD_ENCODE_BASELINE_BITS(67, 4),\n  ZSTD_ENCODE_BASELINE_BITS(83, 4),\n  ZSTD_ENCODE_BASELINE_BITS(99, 5),\n  ZSTD_ENCODE_BASELINE_BITS(131, 7),\n  ZSTD_ENCODE_BASELINE_BITS(259, 8),\n  ZSTD_ENCODE_BASELINE_BITS(515, 9),\n  ZSTD_ENCODE_BASELINE_BITS(1027, 10),\n  ZSTD_ENCODE_BASELINE_BITS(2051, 11),\n  ZSTD_ENCODE_BASELINE_BITS(4099, 12),\n  ZSTD_ENCODE_BASELINE_BITS(8195, 13),\n  ZSTD_ENCODE_BASELINE_BITS(16387, 14),\n  ZSTD_ENCODE_BASELINE_BITS(32771, 15),\n  ZSTD_ENCODE_BASELINE_BITS(65539, 16)\n};\n\n/* An entry in an FSE table used for literal/match/length values.  For these we\n   have to map the symbol to a baseline value, and we have to read zero or more\n   bits and add that value to the baseline value.  Rather than look the values\n   up in a separate table, we grow the FSE table so that we get better memory\n   caching.  */\n\nstruct elf_zstd_fse_baseline_entry\n{\n  /* The baseline for the value that this FSE entry represents..  */\n  uint32_t baseline;\n  /* The number of bits to read to add to the baseline.  */\n  unsigned char basebits;\n  /* The number of bits to read to determine the next state.  */\n  unsigned char bits;\n  /* Add the bits to this base to get the next state.  */\n  uint16_t base;\n};\n\n/* Convert the literal length FSE table FSE_TABLE to an FSE baseline table at\n   BASELINE_TABLE.  Note that FSE_TABLE and BASELINE_TABLE will overlap.  */\n\nstatic int\nelf_zstd_make_literal_baseline_fse (\n    const struct elf_zstd_fse_entry *fse_table,\n    int table_bits,\n    struct elf_zstd_fse_baseline_entry *baseline_table)\n{\n  size_t count;\n  const struct elf_zstd_fse_entry *pfse;\n  struct elf_zstd_fse_baseline_entry *pbaseline;\n\n  /* Convert backward to avoid overlap.  */\n\n  count = 1U << table_bits;\n  pfse = fse_table + count;\n  pbaseline = baseline_table + count;\n  while (pfse > fse_table)\n    {\n      unsigned char symbol;\n      unsigned char bits;\n      uint16_t base;\n\n      --pfse;\n      --pbaseline;\n      symbol = pfse->symbol;\n      bits = pfse->bits;\n      base = pfse->base;\n      if (symbol < ZSTD_LITERAL_LENGTH_BASELINE_OFFSET)\n\t{\n\t  pbaseline->baseline = (uint32_t)symbol;\n\t  pbaseline->basebits = 0;\n\t}\n      else\n\t{\n\t  unsigned int idx;\n\t  uint32_t basebits;\n\n\t  if (unlikely (symbol > 35))\n\t    {\n\t      elf_uncompress_failed ();\n\t      return 0;\n\t    }\n\t  idx = symbol - ZSTD_LITERAL_LENGTH_BASELINE_OFFSET;\n\t  basebits = elf_zstd_literal_length_base[idx];\n\t  pbaseline->baseline = ZSTD_DECODE_BASELINE(basebits);\n\t  pbaseline->basebits = ZSTD_DECODE_BASEBITS(basebits);\n\t}\n      pbaseline->bits = bits;\n      pbaseline->base = base;\n    }\n\n  return 1;\n}\n\n/* Convert the offset length FSE table FSE_TABLE to an FSE baseline table at\n   BASELINE_TABLE.  Note that FSE_TABLE and BASELINE_TABLE will overlap.  */\n\nstatic int\nelf_zstd_make_offset_baseline_fse (\n    const struct elf_zstd_fse_entry *fse_table,\n    int table_bits,\n    struct elf_zstd_fse_baseline_entry *baseline_table)\n{\n  size_t count;\n  const struct elf_zstd_fse_entry *pfse;\n  struct elf_zstd_fse_baseline_entry *pbaseline;\n\n  /* Convert backward to avoid overlap.  */\n\n  count = 1U << table_bits;\n  pfse = fse_table + count;\n  pbaseline = baseline_table + count;\n  while (pfse > fse_table)\n    {\n      unsigned char symbol;\n      unsigned char bits;\n      uint16_t base;\n\n      --pfse;\n      --pbaseline;\n      symbol = pfse->symbol;\n      bits = pfse->bits;\n      base = pfse->base;\n      if (unlikely (symbol > 31))\n\t{\n\t  elf_uncompress_failed ();\n\t  return 0;\n\t}\n\n      /* The simple way to write this is\n\n\t   pbaseline->baseline = (uint32_t)1 << symbol;\n\t   pbaseline->basebits = symbol;\n\n\t That will give us an offset value that corresponds to the one\n\t described in the RFC.  However, for offset values > 3, we have to\n\t subtract 3.  And for offset values 1, 2, 3 we use a repeated offset.\n\t The baseline is always a power of 2, and is never 0, so for these low\n\t values we will see one entry that is baseline 1, basebits 0, and one\n\t entry that is baseline 2, basebits 1.  All other entries will have\n\t baseline >= 4 and basebits >= 2.\n\n\t So we can check for RFC offset <= 3 by checking for basebits <= 1.\n\t And that means that we can subtract 3 here and not worry about doing\n\t it in the hot loop.  */\n\n      pbaseline->baseline = (uint32_t)1 << symbol;\n      if (symbol >= 2)\n\tpbaseline->baseline -= 3;\n      pbaseline->basebits = symbol;\n      pbaseline->bits = bits;\n      pbaseline->base = base;\n    }\n\n  return 1;\n}\n\n/* Convert the match length FSE table FSE_TABLE to an FSE baseline table at\n   BASELINE_TABLE.  Note that FSE_TABLE and BASELINE_TABLE will overlap.  */\n\nstatic int\nelf_zstd_make_match_baseline_fse (\n    const struct elf_zstd_fse_entry *fse_table,\n    int table_bits,\n    struct elf_zstd_fse_baseline_entry *baseline_table)\n{\n  size_t count;\n  const struct elf_zstd_fse_entry *pfse;\n  struct elf_zstd_fse_baseline_entry *pbaseline;\n\n  /* Convert backward to avoid overlap.  */\n\n  count = 1U << table_bits;\n  pfse = fse_table + count;\n  pbaseline = baseline_table + count;\n  while (pfse > fse_table)\n    {\n      unsigned char symbol;\n      unsigned char bits;\n      uint16_t base;\n\n      --pfse;\n      --pbaseline;\n      symbol = pfse->symbol;\n      bits = pfse->bits;\n      base = pfse->base;\n      if (symbol < ZSTD_MATCH_LENGTH_BASELINE_OFFSET)\n\t{\n\t  pbaseline->baseline = (uint32_t)symbol + 3;\n\t  pbaseline->basebits = 0;\n\t}\n      else\n\t{\n\t  unsigned int idx;\n\t  uint32_t basebits;\n\n\t  if (unlikely (symbol > 52))\n\t    {\n\t      elf_uncompress_failed ();\n\t      return 0;\n\t    }\n\t  idx = symbol - ZSTD_MATCH_LENGTH_BASELINE_OFFSET;\n\t  basebits = elf_zstd_match_length_base[idx];\n\t  pbaseline->baseline = ZSTD_DECODE_BASELINE(basebits);\n\t  pbaseline->basebits = ZSTD_DECODE_BASEBITS(basebits);\n\t}\n      pbaseline->bits = bits;\n      pbaseline->base = base;\n    }\n\n  return 1;\n}\n\n#ifdef BACKTRACE_GENERATE_ZSTD_FSE_TABLES\n\n/* Used to generate the predefined FSE decoding tables for zstd.  */\n\n#include <stdio.h>\n\n/* These values are straight from RFC 8878.  */\n\nstatic int16_t lit[36] =\n{\n   4, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1,\n   2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 1, 1, 1, 1, 1,\n  -1,-1,-1,-1\n};\n\nstatic int16_t match[53] =\n{\n   1, 4, 3, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1,\n   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,-1,-1,\n  -1,-1,-1,-1,-1\n};\n\nstatic int16_t offset[29] =\n{\n  1, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1,\n  1, 1, 1, 1, 1, 1, 1, 1,-1,-1,-1,-1,-1\n};\n\nstatic uint16_t next[256];\n\nstatic void\nprint_table (const struct elf_zstd_fse_baseline_entry *table, size_t size)\n{\n  size_t i;\n\n  printf (\"{\\n\");\n  for (i = 0; i < size; i += 3)\n    {\n      int j;\n\n      printf (\" \");\n      for (j = 0; j < 3 && i + j < size; ++j)\n\tprintf (\" { %u, %d, %d, %d },\", table[i + j].baseline,\n\t\ttable[i + j].basebits, table[i + j].bits,\n\t\ttable[i + j].base);\n      printf (\"\\n\");\n    }\n  printf (\"};\\n\");\n}\n\nint\nmain ()\n{\n  struct elf_zstd_fse_entry lit_table[64];\n  struct elf_zstd_fse_baseline_entry lit_baseline[64];\n  struct elf_zstd_fse_entry match_table[64];\n  struct elf_zstd_fse_baseline_entry match_baseline[64];\n  struct elf_zstd_fse_entry offset_table[32];\n  struct elf_zstd_fse_baseline_entry offset_baseline[32];\n\n  if (!elf_zstd_build_fse (lit, sizeof lit / sizeof lit[0], next,\n\t\t\t   6, lit_table))\n    {\n      fprintf (stderr, \"elf_zstd_build_fse failed\\n\");\n      exit (EXIT_FAILURE);\n    }\n\n  if (!elf_zstd_make_literal_baseline_fse (lit_table, 6, lit_baseline))\n    {\n      fprintf (stderr, \"elf_zstd_make_literal_baseline_fse failed\\n\");\n      exit (EXIT_FAILURE);\n    }\n\n  printf (\"static const struct elf_zstd_fse_baseline_entry \"\n\t  \"elf_zstd_lit_table[64] =\\n\");\n  print_table (lit_baseline,\n\t       sizeof lit_baseline / sizeof lit_baseline[0]);\n  printf (\"\\n\");\n\n  if (!elf_zstd_build_fse (match, sizeof match / sizeof match[0], next,\n\t\t\t   6, match_table))\n    {\n      fprintf (stderr, \"elf_zstd_build_fse failed\\n\");\n      exit (EXIT_FAILURE);\n    }\n\n  if (!elf_zstd_make_match_baseline_fse (match_table, 6, match_baseline))\n    {\n      fprintf (stderr, \"elf_zstd_make_match_baseline_fse failed\\n\");\n      exit (EXIT_FAILURE);\n    }\n\n  printf (\"static const struct elf_zstd_fse_baseline_entry \"\n\t  \"elf_zstd_match_table[64] =\\n\");\n  print_table (match_baseline,\n\t       sizeof match_baseline / sizeof match_baseline[0]);\n  printf (\"\\n\");\n\n  if (!elf_zstd_build_fse (offset, sizeof offset / sizeof offset[0], next,\n\t\t\t   5, offset_table))\n    {\n      fprintf (stderr, \"elf_zstd_build_fse failed\\n\");\n      exit (EXIT_FAILURE);\n    }\n\n  if (!elf_zstd_make_offset_baseline_fse (offset_table, 5, offset_baseline))\n    {\n      fprintf (stderr, \"elf_zstd_make_offset_baseline_fse failed\\n\");\n      exit (EXIT_FAILURE);\n    }\n\n  printf (\"static const struct elf_zstd_fse_baseline_entry \"\n\t  \"elf_zstd_offset_table[32] =\\n\");\n  print_table (offset_baseline,\n\t       sizeof offset_baseline / sizeof offset_baseline[0]);\n  printf (\"\\n\");\n\n  return 0;\n}\n\n#endif\n\n/* The fixed tables generated by the #ifdef'ed out main function\n   above.  */\n\nstatic const struct elf_zstd_fse_baseline_entry elf_zstd_lit_table[64] =\n{\n  { 0, 0, 4, 0 }, { 0, 0, 4, 16 }, { 1, 0, 5, 32 },\n  { 3, 0, 5, 0 }, { 4, 0, 5, 0 }, { 6, 0, 5, 0 },\n  { 7, 0, 5, 0 }, { 9, 0, 5, 0 }, { 10, 0, 5, 0 },\n  { 12, 0, 5, 0 }, { 14, 0, 6, 0 }, { 16, 1, 5, 0 },\n  { 20, 1, 5, 0 }, { 22, 1, 5, 0 }, { 28, 2, 5, 0 },\n  { 32, 3, 5, 0 }, { 48, 4, 5, 0 }, { 64, 6, 5, 32 },\n  { 128, 7, 5, 0 }, { 256, 8, 6, 0 }, { 1024, 10, 6, 0 },\n  { 4096, 12, 6, 0 }, { 0, 0, 4, 32 }, { 1, 0, 4, 0 },\n  { 2, 0, 5, 0 }, { 4, 0, 5, 32 }, { 5, 0, 5, 0 },\n  { 7, 0, 5, 32 }, { 8, 0, 5, 0 }, { 10, 0, 5, 32 },\n  { 11, 0, 5, 0 }, { 13, 0, 6, 0 }, { 16, 1, 5, 32 },\n  { 18, 1, 5, 0 }, { 22, 1, 5, 32 }, { 24, 2, 5, 0 },\n  { 32, 3, 5, 32 }, { 40, 3, 5, 0 }, { 64, 6, 4, 0 },\n  { 64, 6, 4, 16 }, { 128, 7, 5, 32 }, { 512, 9, 6, 0 },\n  { 2048, 11, 6, 0 }, { 0, 0, 4, 48 }, { 1, 0, 4, 16 },\n  { 2, 0, 5, 32 }, { 3, 0, 5, 32 }, { 5, 0, 5, 32 },\n  { 6, 0, 5, 32 }, { 8, 0, 5, 32 }, { 9, 0, 5, 32 },\n  { 11, 0, 5, 32 }, { 12, 0, 5, 32 }, { 15, 0, 6, 0 },\n  { 18, 1, 5, 32 }, { 20, 1, 5, 32 }, { 24, 2, 5, 32 },\n  { 28, 2, 5, 32 }, { 40, 3, 5, 32 }, { 48, 4, 5, 32 },\n  { 65536, 16, 6, 0 }, { 32768, 15, 6, 0 }, { 16384, 14, 6, 0 },\n  { 8192, 13, 6, 0 },\n};\n\nstatic const struct elf_zstd_fse_baseline_entry elf_zstd_match_table[64] =\n{\n  { 3, 0, 6, 0 }, { 4, 0, 4, 0 }, { 5, 0, 5, 32 },\n  { 6, 0, 5, 0 }, { 8, 0, 5, 0 }, { 9, 0, 5, 0 },\n  { 11, 0, 5, 0 }, { 13, 0, 6, 0 }, { 16, 0, 6, 0 },\n  { 19, 0, 6, 0 }, { 22, 0, 6, 0 }, { 25, 0, 6, 0 },\n  { 28, 0, 6, 0 }, { 31, 0, 6, 0 }, { 34, 0, 6, 0 },\n  { 37, 1, 6, 0 }, { 41, 1, 6, 0 }, { 47, 2, 6, 0 },\n  { 59, 3, 6, 0 }, { 83, 4, 6, 0 }, { 131, 7, 6, 0 },\n  { 515, 9, 6, 0 }, { 4, 0, 4, 16 }, { 5, 0, 4, 0 },\n  { 6, 0, 5, 32 }, { 7, 0, 5, 0 }, { 9, 0, 5, 32 },\n  { 10, 0, 5, 0 }, { 12, 0, 6, 0 }, { 15, 0, 6, 0 },\n  { 18, 0, 6, 0 }, { 21, 0, 6, 0 }, { 24, 0, 6, 0 },\n  { 27, 0, 6, 0 }, { 30, 0, 6, 0 }, { 33, 0, 6, 0 },\n  { 35, 1, 6, 0 }, { 39, 1, 6, 0 }, { 43, 2, 6, 0 },\n  { 51, 3, 6, 0 }, { 67, 4, 6, 0 }, { 99, 5, 6, 0 },\n  { 259, 8, 6, 0 }, { 4, 0, 4, 32 }, { 4, 0, 4, 48 },\n  { 5, 0, 4, 16 }, { 7, 0, 5, 32 }, { 8, 0, 5, 32 },\n  { 10, 0, 5, 32 }, { 11, 0, 5, 32 }, { 14, 0, 6, 0 },\n  { 17, 0, 6, 0 }, { 20, 0, 6, 0 }, { 23, 0, 6, 0 },\n  { 26, 0, 6, 0 }, { 29, 0, 6, 0 }, { 32, 0, 6, 0 },\n  { 65539, 16, 6, 0 }, { 32771, 15, 6, 0 }, { 16387, 14, 6, 0 },\n  { 8195, 13, 6, 0 }, { 4099, 12, 6, 0 }, { 2051, 11, 6, 0 },\n  { 1027, 10, 6, 0 },\n};\n\nstatic const struct elf_zstd_fse_baseline_entry elf_zstd_offset_table[32] =\n{\n  { 1, 0, 5, 0 }, { 61, 6, 4, 0 }, { 509, 9, 5, 0 },\n  { 32765, 15, 5, 0 }, { 2097149, 21, 5, 0 }, { 5, 3, 5, 0 },\n  { 125, 7, 4, 0 }, { 4093, 12, 5, 0 }, { 262141, 18, 5, 0 },\n  { 8388605, 23, 5, 0 }, { 29, 5, 5, 0 }, { 253, 8, 4, 0 },\n  { 16381, 14, 5, 0 }, { 1048573, 20, 5, 0 }, { 1, 2, 5, 0 },\n  { 125, 7, 4, 16 }, { 2045, 11, 5, 0 }, { 131069, 17, 5, 0 },\n  { 4194301, 22, 5, 0 }, { 13, 4, 5, 0 }, { 253, 8, 4, 16 },\n  { 8189, 13, 5, 0 }, { 524285, 19, 5, 0 }, { 2, 1, 5, 0 },\n  { 61, 6, 4, 16 }, { 1021, 10, 5, 0 }, { 65533, 16, 5, 0 },\n  { 268435453, 28, 5, 0 }, { 134217725, 27, 5, 0 }, { 67108861, 26, 5, 0 },\n  { 33554429, 25, 5, 0 }, { 16777213, 24, 5, 0 },\n};\n\n/* Read a zstd Huffman table and build the decoding table in *TABLE, reading\n   and updating *PPIN.  This sets *PTABLE_BITS to the number of bits of the\n   table, such that the table length is 1 << *TABLE_BITS.  ZDEBUG_TABLE is\n   scratch space; it must be enough for 512 uint16_t values + 256 32-bit values\n   (2048 bytes).  Returns 1 on success, 0 on error.  */\n\nstatic int\nelf_zstd_read_huff (const unsigned char **ppin, const unsigned char *pinend,\n\t\t    uint16_t *zdebug_table, uint16_t *table, int *ptable_bits)\n{\n  const unsigned char *pin;\n  unsigned char hdr;\n  unsigned char *weights;\n  size_t count;\n  uint32_t *weight_mark;\n  size_t i;\n  uint32_t weight_mask;\n  size_t table_bits;\n\n  pin = *ppin;\n  if (unlikely (pin >= pinend))\n    {\n      elf_uncompress_failed ();\n      return 0;\n    }\n  hdr = *pin;\n  ++pin;\n\n  weights = (unsigned char *) zdebug_table;\n\n  if (hdr < 128)\n    {\n      /* Table is compressed using FSE.  */\n\n      struct elf_zstd_fse_entry *fse_table;\n      int fse_table_bits;\n      uint16_t *scratch;\n      const unsigned char *pfse;\n      const unsigned char *pback;\n      uint64_t val;\n      unsigned int bits;\n      unsigned int state1, state2;\n\n      /* SCRATCH is used temporarily by elf_zstd_read_fse.  It overlaps\n\t WEIGHTS.  */\n      scratch = zdebug_table;\n      fse_table = (struct elf_zstd_fse_entry *) (scratch + 512);\n      fse_table_bits = 6;\n\n      pfse = pin;\n      if (!elf_zstd_read_fse (&pfse, pinend, scratch, 255, fse_table,\n\t\t\t      &fse_table_bits))\n\treturn 0;\n\n      if (unlikely (pin + hdr > pinend))\n\t{\n\t  elf_uncompress_failed ();\n\t  return 0;\n\t}\n\n      /* We no longer need SCRATCH.  Start recording weights.  We need up to\n\t 256 bytes of weights and 64 bytes of rank counts, so it won't overlap\n\t FSE_TABLE.  */\n\n      pback = pin + hdr - 1;\n\n      if (!elf_fetch_backward_init (&pback, pfse, &val, &bits))\n\treturn 0;\n\n      bits -= fse_table_bits;\n      state1 = (val >> bits) & ((1U << fse_table_bits) - 1);\n      bits -= fse_table_bits;\n      state2 = (val >> bits) & ((1U << fse_table_bits) - 1);\n\n      /* There are two independent FSE streams, tracked by STATE1 and STATE2.\n\t We decode them alternately.  */\n\n      count = 0;\n      while (1)\n\t{\n\t  struct elf_zstd_fse_entry *pt;\n\t  uint64_t v;\n\n\t  pt = &fse_table[state1];\n\n\t  if (unlikely (pin < pinend) && bits < pt->bits)\n\t    {\n\t      if (unlikely (count >= 254))\n\t\t{\n\t\t  elf_uncompress_failed ();\n\t\t  return 0;\n\t\t}\n\t      weights[count] = (unsigned char) pt->symbol;\n\t      weights[count + 1] = (unsigned char) fse_table[state2].symbol;\n\t      count += 2;\n\t      break;\n\t    }\n\n\t  if (unlikely (pt->bits == 0))\n\t    v = 0;\n\t  else\n\t    {\n\t      if (!elf_fetch_bits_backward (&pback, pfse, &val, &bits))\n\t\treturn 0;\n\n\t      bits -= pt->bits;\n\t      v = (val >> bits) & (((uint64_t)1 << pt->bits) - 1);\n\t    }\n\n\t  state1 = pt->base + v;\n\n\t  if (unlikely (count >= 255))\n\t    {\n\t      elf_uncompress_failed ();\n\t      return 0;\n\t    }\n\n\t  weights[count] = pt->symbol;\n\t  ++count;\n\n\t  pt = &fse_table[state2];\n\n\t  if (unlikely (pin < pinend && bits < pt->bits))\n\t    {\n\t      if (unlikely (count >= 254))\n\t\t{\n\t\t  elf_uncompress_failed ();\n\t\t  return 0;\n\t\t}\n\t      weights[count] = (unsigned char) pt->symbol;\n\t      weights[count + 1] = (unsigned char) fse_table[state1].symbol;\n\t      count += 2;\n\t      break;\n\t    }\n\n\t  if (unlikely (pt->bits == 0))\n\t    v = 0;\n\t  else\n\t    {\n\t      if (!elf_fetch_bits_backward (&pback, pfse, &val, &bits))\n\t\treturn 0;\n\n\t      bits -= pt->bits;\n\t      v = (val >> bits) & (((uint64_t)1 << pt->bits) - 1);\n\t    }\n\n\t  state2 = pt->base + v;\n\n\t  if (unlikely (count >= 255))\n\t    {\n\t      elf_uncompress_failed ();\n\t      return 0;\n\t    }\n\n\t  weights[count] = pt->symbol;\n\t  ++count;\n\t}\n\n      pin += hdr;\n    }\n  else\n    {\n      /* Table is not compressed.  Each weight is 4 bits.  */\n\n      count = hdr - 127;\n      if (unlikely (pin + ((count + 1) / 2) >= pinend))\n\t{\n\t  elf_uncompress_failed ();\n\t  return 0;\n\t}\n      for (i = 0; i < count; i += 2)\n\t{\n\t  unsigned char b;\n\n\t  b = *pin;\n\t  ++pin;\n\t  weights[i] = b >> 4;\n\t  weights[i + 1] = b & 0xf;\n\t}\n    }\n\n  weight_mark = (uint32_t *) (weights + 256);\n  memset (weight_mark, 0, 13 * sizeof (uint32_t));\n  weight_mask = 0;\n  for (i = 0; i < count; ++i)\n    {\n      unsigned char w;\n\n      w = weights[i];\n      if (unlikely (w > 12))\n\t{\n\t  elf_uncompress_failed ();\n\t  return 0;\n\t}\n      ++weight_mark[w];\n      if (w > 0)\n\tweight_mask += 1U << (w - 1);\n    }\n  if (unlikely (weight_mask == 0))\n    {\n      elf_uncompress_failed ();\n      return 0;\n    }\n\n  table_bits = 32 - __builtin_clz (weight_mask);\n  if (unlikely (table_bits > 11))\n    {\n      elf_uncompress_failed ();\n      return 0;\n    }\n\n  /* Work out the last weight value, which is omitted because the weights must\n     sum to a power of two.  */\n  {\n    uint32_t left;\n    uint32_t high_bit;\n\n    left = ((uint32_t)1 << table_bits) - weight_mask;\n    if (left == 0)\n      {\n\telf_uncompress_failed ();\n\treturn 0;\n      }\n    high_bit = 31 - __builtin_clz (left);\n    if (((uint32_t)1 << high_bit) != left)\n      {\n\telf_uncompress_failed ();\n\treturn 0;\n      }\n\n    if (unlikely (count >= 256))\n      {\n\telf_uncompress_failed ();\n\treturn 0;\n      }\n\n    weights[count] = high_bit + 1;\n    ++count;\n    ++weight_mark[high_bit + 1];\n  }\n\n  if (weight_mark[1] < 2 || (weight_mark[1] & 1) != 0)\n    {\n      elf_uncompress_failed ();\n      return 0;\n    }\n\n  /* Change WEIGHT_MARK from a count of weights to the index of the first\n     symbol for that weight.  We shift the indexes to also store how many we\n     have seen so far, below.  */\n  {\n    uint32_t next;\n\n    next = 0;\n    for (i = 0; i < table_bits; ++i)\n      {\n\tuint32_t cur;\n\n\tcur = next;\n\tnext += weight_mark[i + 1] << i;\n\tweight_mark[i + 1] = cur;\n      }\n  }\n\n  for (i = 0; i < count; ++i)\n    {\n      unsigned char weight;\n      uint32_t length;\n      uint16_t tval;\n      size_t start;\n      uint32_t j;\n\n      weight = weights[i];\n      if (weight == 0)\n\tcontinue;\n\n      length = 1U << (weight - 1);\n      tval = (i << 8) | (table_bits + 1 - weight);\n      start = weight_mark[weight];\n      for (j = 0; j < length; ++j)\n\ttable[start + j] = tval;\n      weight_mark[weight] += length;\n    }\n\n  *ppin = pin;\n  *ptable_bits = (int)table_bits;\n\n  return 1;\n}\n\n/* Read and decompress the literals and store them ending at POUTEND.  This\n   works because we are going to use all the literals in the output, so they\n   must fit into the output buffer.  HUFFMAN_TABLE, and PHUFFMAN_TABLE_BITS\n   store the Huffman table across calls.  SCRATCH is used to read a Huffman\n   table.  Store the start of the decompressed literals in *PPLIT.  Update\n   *PPIN.  Return 1 on success, 0 on error.  */\n\nstatic int\nelf_zstd_read_literals (const unsigned char **ppin,\n\t\t\tconst unsigned char *pinend,\n\t\t\tunsigned char *pout,\n\t\t\tunsigned char *poutend,\n\t\t\tuint16_t *scratch,\n\t\t\tuint16_t *huffman_table,\n\t\t\tint *phuffman_table_bits,\n\t\t\tunsigned char **pplit)\n{\n  const unsigned char *pin;\n  unsigned char *plit;\n  unsigned char hdr;\n  uint32_t regenerated_size;\n  uint32_t compressed_size;\n  int streams;\n  uint32_t total_streams_size;\n  unsigned int huffman_table_bits;\n  uint64_t huffman_mask;\n\n  pin = *ppin;\n  if (unlikely (pin >= pinend))\n    {\n      elf_uncompress_failed ();\n      return 0;\n    }\n  hdr = *pin;\n  ++pin;\n\n  if ((hdr & 3) == 0 || (hdr & 3) == 1)\n    {\n      int raw;\n\n      /* Raw_Literals_Block or RLE_Literals_Block */\n\n      raw = (hdr & 3) == 0;\n\n      switch ((hdr >> 2) & 3)\n\t{\n\tcase 0: case 2:\n\t  regenerated_size = hdr >> 3;\n\t  break;\n\tcase 1:\n\t  if (unlikely (pin >= pinend))\n\t    {\n\t      elf_uncompress_failed ();\n\t      return 0;\n\t    }\n\t  regenerated_size = (hdr >> 4) + ((uint32_t)(*pin) << 4);\n\t  ++pin;\n\t  break;\n\tcase 3:\n\t  if (unlikely (pin + 1 >= pinend))\n\t    {\n\t      elf_uncompress_failed ();\n\t      return 0;\n\t    }\n\t  regenerated_size = ((hdr >> 4)\n\t\t\t      + ((uint32_t)*pin << 4)\n\t\t\t      + ((uint32_t)pin[1] << 12));\n\t  pin += 2;\n\t  break;\n\tdefault:\n\t  elf_uncompress_failed ();\n\t  return 0;\n\t}\n\n      if (unlikely ((size_t)(poutend - pout) < regenerated_size))\n\t{\n\t  elf_uncompress_failed ();\n\t  return 0;\n\t}\n\n      plit = poutend - regenerated_size;\n\n      if (raw)\n\t{\n\t  if (unlikely (pin + regenerated_size >= pinend))\n\t    {\n\t      elf_uncompress_failed ();\n\t      return 0;\n\t    }\n\t  memcpy (plit, pin, regenerated_size);\n\t  pin += regenerated_size;\n\t}\n      else\n\t{\n\t  if (pin >= pinend)\n\t    {\n\t      elf_uncompress_failed ();\n\t      return 0;\n\t    }\n\t  memset (plit, *pin, regenerated_size);\n\t  ++pin;\n\t}\n\n      *ppin = pin;\n      *pplit = plit;\n\n      return 1;\n    }\n\n  /* Compressed_Literals_Block or Treeless_Literals_Block */\n\n  switch ((hdr >> 2) & 3)\n    {\n    case 0: case 1:\n      if (unlikely (pin + 1 >= pinend))\n\t{\n\t  elf_uncompress_failed ();\n\t  return 0;\n\t}\n      regenerated_size = (hdr >> 4) | ((uint32_t)(*pin & 0x3f) << 4);\n      compressed_size = (uint32_t)*pin >> 6 | ((uint32_t)pin[1] << 2);\n      pin += 2;\n      streams = ((hdr >> 2) & 3) == 0 ? 1 : 4;\n      break;\n    case 2:\n      if (unlikely (pin + 2 >= pinend))\n\t{\n\t  elf_uncompress_failed ();\n\t  return 0;\n\t}\n      regenerated_size = (((uint32_t)hdr >> 4)\n\t\t\t  | ((uint32_t)*pin << 4)\n\t\t\t  | (((uint32_t)pin[1] & 3) << 12));\n      compressed_size = (((uint32_t)pin[1] >> 2)\n\t\t\t | ((uint32_t)pin[2] << 6));\n      pin += 3;\n      streams = 4;\n      break;\n    case 3:\n      if (unlikely (pin + 3 >= pinend))\n\t{\n\t  elf_uncompress_failed ();\n\t  return 0;\n\t}\n      regenerated_size = (((uint32_t)hdr >> 4)\n\t\t\t  | ((uint32_t)*pin << 4)\n\t\t\t  | (((uint32_t)pin[1] & 0x3f) << 12));\n      compressed_size = (((uint32_t)pin[1] >> 6)\n\t\t\t | ((uint32_t)pin[2] << 2)\n\t\t\t | ((uint32_t)pin[3] << 10));\n      pin += 4;\n      streams = 4;\n      break;\n    default:\n      elf_uncompress_failed ();\n      return 0;\n    }\n\n  if (unlikely (pin + compressed_size > pinend))\n    {\n      elf_uncompress_failed ();\n      return 0;\n    }\n\n  pinend = pin + compressed_size;\n  *ppin = pinend;\n\n  if (unlikely ((size_t)(poutend - pout) < regenerated_size))\n    {\n      elf_uncompress_failed ();\n      return 0;\n    }\n\n  plit = poutend - regenerated_size;\n\n  *pplit = plit;\n\n  total_streams_size = compressed_size;\n  if ((hdr & 3) == 2)\n    {\n      const unsigned char *ptable;\n\n      /* Compressed_Literals_Block.  Read Huffman tree.  */\n\n      ptable = pin;\n      if (!elf_zstd_read_huff (&ptable, pinend, scratch, huffman_table,\n\t\t\t       phuffman_table_bits))\n\treturn 0;\n\n      if (unlikely (total_streams_size < (size_t)(ptable - pin)))\n\t{\n\t  elf_uncompress_failed ();\n\t  return 0;\n\t}\n\n      total_streams_size -= ptable - pin;\n      pin = ptable;\n    }\n  else\n    {\n      /* Treeless_Literals_Block.  Reuse previous Huffman tree.  */\n      if (unlikely (*phuffman_table_bits == 0))\n\t{\n\t  elf_uncompress_failed ();\n\t  return 0;\n\t}\n    }\n\n  /* Decompress COMPRESSED_SIZE bytes of data at PIN using the huffman table,\n     storing REGENERATED_SIZE bytes of decompressed data at PLIT.  */\n\n  huffman_table_bits = (unsigned int)*phuffman_table_bits;\n  huffman_mask = ((uint64_t)1 << huffman_table_bits) - 1;\n\n  if (streams == 1)\n    {\n      const unsigned char *pback;\n      const unsigned char *pbackend;\n      uint64_t val;\n      unsigned int bits;\n      uint32_t i;\n\n      pback = pin + total_streams_size - 1;\n      pbackend = pin;\n      if (!elf_fetch_backward_init (&pback, pbackend, &val, &bits))\n\treturn 0;\n\n      /* This is one of the inner loops of the decompression algorithm, so we\n\t put some effort into optimization.  We can't get more than 64 bytes\n\t from a single call to elf_fetch_bits_backward, and we can't subtract\n\t more than 11 bits at a time.  */\n\n      if (regenerated_size >= 64)\n\t{\n\t  unsigned char *plitstart;\n\t  unsigned char *plitstop;\n\n\t  plitstart = plit;\n\t  plitstop = plit + regenerated_size - 64;\n\t  while (plit < plitstop)\n\t    {\n\t      uint16_t t;\n\n\t      if (!elf_fetch_bits_backward (&pback, pbackend, &val, &bits))\n\t\treturn 0;\n\n\t      if (bits < 16)\n\t\tbreak;\n\n\t      while (bits >= 33)\n\t\t{\n\t\t  t = huffman_table[(val >> (bits - huffman_table_bits))\n\t\t\t\t    & huffman_mask];\n\t\t  *plit = t >> 8;\n\t\t  ++plit;\n\t\t  bits -= t & 0xff;\n\n\t\t  t = huffman_table[(val >> (bits - huffman_table_bits))\n\t\t\t\t    & huffman_mask];\n\t\t  *plit = t >> 8;\n\t\t  ++plit;\n\t\t  bits -= t & 0xff;\n\n\t\t  t = huffman_table[(val >> (bits - huffman_table_bits))\n\t\t\t\t    & huffman_mask];\n\t\t  *plit = t >> 8;\n\t\t  ++plit;\n\t\t  bits -= t & 0xff;\n\t\t}\n\n\t      while (bits > 11)\n\t\t{\n\t\t  t = huffman_table[(val >> (bits - huffman_table_bits))\n\t\t\t\t    & huffman_mask];\n\t\t  *plit = t >> 8;\n\t\t  ++plit;\n\t\t  bits -= t & 0xff;\n\t\t}\n\t    }\n\n\t  regenerated_size -= plit - plitstart;\n\t}\n\n      for (i = 0; i < regenerated_size; ++i)\n\t{\n\t  uint16_t t;\n\n\t  if (!elf_fetch_bits_backward (&pback, pbackend, &val, &bits))\n\t    return 0;\n\n\t  if (unlikely (bits < huffman_table_bits))\n\t    {\n\t      t = huffman_table[(val << (huffman_table_bits - bits))\n\t\t\t\t& huffman_mask];\n\t      if (unlikely (bits < (t & 0xff)))\n\t\t{\n\t\t  elf_uncompress_failed ();\n\t\t  return 0;\n\t\t}\n\t    }\n\t  else\n\t    t = huffman_table[(val >> (bits - huffman_table_bits))\n\t\t\t      & huffman_mask];\n\n\t  *plit = t >> 8;\n\t  ++plit;\n\t  bits -= t & 0xff;\n\t}\n\n      return 1;\n    }\n\n  {\n    uint32_t stream_size1, stream_size2, stream_size3, stream_size4;\n    uint32_t tot;\n    const unsigned char *pback1, *pback2, *pback3, *pback4;\n    const unsigned char *pbackend1, *pbackend2, *pbackend3, *pbackend4;\n    uint64_t val1, val2, val3, val4;\n    unsigned int bits1, bits2, bits3, bits4;\n    unsigned char *plit1, *plit2, *plit3, *plit4;\n    uint32_t regenerated_stream_size;\n    uint32_t regenerated_stream_size4;\n    uint16_t t1, t2, t3, t4;\n    uint32_t i;\n    uint32_t limit;\n\n    /* Read jump table.  */\n    if (unlikely (pin + 5 >= pinend))\n      {\n\telf_uncompress_failed ();\n\treturn 0;\n      }\n    stream_size1 = (uint32_t)*pin | ((uint32_t)pin[1] << 8);\n    pin += 2;\n    stream_size2 = (uint32_t)*pin | ((uint32_t)pin[1] << 8);\n    pin += 2;\n    stream_size3 = (uint32_t)*pin | ((uint32_t)pin[1] << 8);\n    pin += 2;\n    tot = stream_size1 + stream_size2 + stream_size3;\n    if (unlikely (tot > total_streams_size - 6))\n      {\n\telf_uncompress_failed ();\n\treturn 0;\n      }\n    stream_size4 = total_streams_size - 6 - tot;\n\n    pback1 = pin + stream_size1 - 1;\n    pbackend1 = pin;\n\n    pback2 = pback1 + stream_size2;\n    pbackend2 = pback1 + 1;\n\n    pback3 = pback2 + stream_size3;\n    pbackend3 = pback2 + 1;\n\n    pback4 = pback3 + stream_size4;\n    pbackend4 = pback3 + 1;\n\n    if (!elf_fetch_backward_init (&pback1, pbackend1, &val1, &bits1))\n      return 0;\n    if (!elf_fetch_backward_init (&pback2, pbackend2, &val2, &bits2))\n      return 0;\n    if (!elf_fetch_backward_init (&pback3, pbackend3, &val3, &bits3))\n      return 0;\n    if (!elf_fetch_backward_init (&pback4, pbackend4, &val4, &bits4))\n      return 0;\n\n    regenerated_stream_size = (regenerated_size + 3) / 4;\n\n    plit1 = plit;\n    plit2 = plit1 + regenerated_stream_size;\n    plit3 = plit2 + regenerated_stream_size;\n    plit4 = plit3 + regenerated_stream_size;\n\n    regenerated_stream_size4 = regenerated_size - regenerated_stream_size * 3;\n\n    /* We can't get more than 64 literal bytes from a single call to\n       elf_fetch_bits_backward.  The fourth stream can be up to 3 bytes less,\n       so use as the limit.  */\n\n    limit = regenerated_stream_size4 <= 64 ? 0 : regenerated_stream_size4 - 64;\n    i = 0;\n    while (i < limit)\n      {\n\tif (!elf_fetch_bits_backward (&pback1, pbackend1, &val1, &bits1))\n\t  return 0;\n\tif (!elf_fetch_bits_backward (&pback2, pbackend2, &val2, &bits2))\n\t  return 0;\n\tif (!elf_fetch_bits_backward (&pback3, pbackend3, &val3, &bits3))\n\t  return 0;\n\tif (!elf_fetch_bits_backward (&pback4, pbackend4, &val4, &bits4))\n\t  return 0;\n\n\t/* We can't subtract more than 11 bits at a time.  */\n\n\tdo\n\t  {\n\t    t1 = huffman_table[(val1 >> (bits1 - huffman_table_bits))\n\t\t\t       & huffman_mask];\n\t    t2 = huffman_table[(val2 >> (bits2 - huffman_table_bits))\n\t\t\t       & huffman_mask];\n\t    t3 = huffman_table[(val3 >> (bits3 - huffman_table_bits))\n\t\t\t       & huffman_mask];\n\t    t4 = huffman_table[(val4 >> (bits4 - huffman_table_bits))\n\t\t\t       & huffman_mask];\n\n\t    *plit1 = t1 >> 8;\n\t    ++plit1;\n\t    bits1 -= t1 & 0xff;\n\n\t    *plit2 = t2 >> 8;\n\t    ++plit2;\n\t    bits2 -= t2 & 0xff;\n\n\t    *plit3 = t3 >> 8;\n\t    ++plit3;\n\t    bits3 -= t3 & 0xff;\n\n\t    *plit4 = t4 >> 8;\n\t    ++plit4;\n\t    bits4 -= t4 & 0xff;\n\n\t    ++i;\n\t  }\n\twhile (bits1 > 11 && bits2 > 11 && bits3 > 11 && bits4 > 11);\n      }\n\n    while (i < regenerated_stream_size)\n      {\n\tint use4;\n\n\tuse4 = i < regenerated_stream_size4;\n\n\tif (!elf_fetch_bits_backward (&pback1, pbackend1, &val1, &bits1))\n\t  return 0;\n\tif (!elf_fetch_bits_backward (&pback2, pbackend2, &val2, &bits2))\n\t  return 0;\n\tif (!elf_fetch_bits_backward (&pback3, pbackend3, &val3, &bits3))\n\t  return 0;\n\tif (use4)\n\t  {\n\t    if (!elf_fetch_bits_backward (&pback4, pbackend4, &val4, &bits4))\n\t      return 0;\n\t  }\n\n\tif (unlikely (bits1 < huffman_table_bits))\n\t  {\n\t    t1 = huffman_table[(val1 << (huffman_table_bits - bits1))\n\t\t\t       & huffman_mask];\n\t    if (unlikely (bits1 < (t1 & 0xff)))\n\t      {\n\t\telf_uncompress_failed ();\n\t\treturn 0;\n\t      }\n\t  }\n\telse\n\t  t1 = huffman_table[(val1 >> (bits1 - huffman_table_bits))\n\t\t\t     & huffman_mask];\n\n\tif (unlikely (bits2 < huffman_table_bits))\n\t  {\n\t    t2 = huffman_table[(val2 << (huffman_table_bits - bits2))\n\t\t\t       & huffman_mask];\n\t    if (unlikely (bits2 < (t2 & 0xff)))\n\t      {\n\t\telf_uncompress_failed ();\n\t\treturn 0;\n\t      }\n\t  }\n\telse\n\t  t2 = huffman_table[(val2 >> (bits2 - huffman_table_bits))\n\t\t\t     & huffman_mask];\n\n\tif (unlikely (bits3 < huffman_table_bits))\n\t  {\n\t    t3 = huffman_table[(val3 << (huffman_table_bits - bits3))\n\t\t\t       & huffman_mask];\n\t    if (unlikely (bits3 < (t3 & 0xff)))\n\t      {\n\t\telf_uncompress_failed ();\n\t\treturn 0;\n\t      }\n\t  }\n\telse\n\t  t3 = huffman_table[(val3 >> (bits3 - huffman_table_bits))\n\t\t\t     & huffman_mask];\n\n\tif (use4)\n\t  {\n\t    if (unlikely (bits4 < huffman_table_bits))\n\t      {\n\t\tt4 = huffman_table[(val4 << (huffman_table_bits - bits4))\n\t\t\t\t   & huffman_mask];\n\t\tif (unlikely (bits4 < (t4 & 0xff)))\n\t\t  {\n\t\t    elf_uncompress_failed ();\n\t\t    return 0;\n\t\t  }\n\t      }\n\t    else\n\t      t4 = huffman_table[(val4 >> (bits4 - huffman_table_bits))\n\t\t\t\t & huffman_mask];\n\n\t    *plit4 = t4 >> 8;\n\t    ++plit4;\n\t    bits4 -= t4 & 0xff;\n\t  }\n\n\t*plit1 = t1 >> 8;\n\t++plit1;\n\tbits1 -= t1 & 0xff;\n\n\t*plit2 = t2 >> 8;\n\t++plit2;\n\tbits2 -= t2 & 0xff;\n\n\t*plit3 = t3 >> 8;\n\t++plit3;\n\tbits3 -= t3 & 0xff;\n\n\t++i;\n      }\n  }\n\n  return 1;\n}\n\n/* The information used to decompress a sequence code, which can be a literal\n   length, an offset, or a match length.  */\n\nstruct elf_zstd_seq_decode\n{\n  const struct elf_zstd_fse_baseline_entry *table;\n  int table_bits;\n};\n\n/* Unpack a sequence code compression mode.  */\n\nstatic int\nelf_zstd_unpack_seq_decode (int mode,\n\t\t\t    const unsigned char **ppin,\n\t\t\t    const unsigned char *pinend,\n\t\t\t    const struct elf_zstd_fse_baseline_entry *predef,\n\t\t\t    int predef_bits,\n\t\t\t    uint16_t *scratch,\n\t\t\t    int maxidx,\n\t\t\t    struct elf_zstd_fse_baseline_entry *table,\n\t\t\t    int table_bits,\n\t\t\t    int (*conv)(const struct elf_zstd_fse_entry *,\n\t\t\t\t\tint,\n\t\t\t\t\tstruct elf_zstd_fse_baseline_entry *),\n\t\t\t    struct elf_zstd_seq_decode *decode)\n{\n  switch (mode)\n    {\n    case 0:\n      decode->table = predef;\n      decode->table_bits = predef_bits;\n      break;\n\n    case 1:\n      {\n\tstruct elf_zstd_fse_entry entry;\n\n\tif (unlikely (*ppin >= pinend))\n\t  {\n\t    elf_uncompress_failed ();\n\t    return 0;\n\t  }\n\tentry.symbol = **ppin;\n\t++*ppin;\n\tentry.bits = 0;\n\tentry.base = 0;\n\tdecode->table_bits = 0;\n\tif (!conv (&entry, 0, table))\n\t  return 0;\n      }\n      break;\n\n    case 2:\n      {\n\tstruct elf_zstd_fse_entry *fse_table;\n\n\t/* We use the same space for the simple FSE table and the baseline\n\t   table.  */\n\tfse_table = (struct elf_zstd_fse_entry *)table;\n\tdecode->table_bits = table_bits;\n\tif (!elf_zstd_read_fse (ppin, pinend, scratch, maxidx, fse_table,\n\t\t\t\t&decode->table_bits))\n\t  return 0;\n\tif (!conv (fse_table, decode->table_bits, table))\n\t  return 0;\n\tdecode->table = table;\n      }\n      break;\n\n    case 3:\n      if (unlikely (decode->table_bits == -1))\n\t{\n\t  elf_uncompress_failed ();\n\t  return 0;\n\t}\n      break;\n\n    default:\n      elf_uncompress_failed ();\n      return 0;\n    }\n\n  return 1;\n}\n\n/* Decompress a zstd stream from PIN/SIN to POUT/SOUT.  Code based on RFC 8878.\n   Return 1 on success, 0 on error.  */\n\nstatic int\nelf_zstd_decompress (const unsigned char *pin, size_t sin,\n\t\t     unsigned char *zdebug_table, unsigned char *pout,\n\t\t     size_t sout)\n{\n  const unsigned char *pinend;\n  unsigned char *poutstart;\n  unsigned char *poutend;\n  struct elf_zstd_seq_decode literal_decode;\n  struct elf_zstd_fse_baseline_entry *literal_fse_table;\n  struct elf_zstd_seq_decode match_decode;\n  struct elf_zstd_fse_baseline_entry *match_fse_table;\n  struct elf_zstd_seq_decode offset_decode;\n  struct elf_zstd_fse_baseline_entry *offset_fse_table;\n  uint16_t *huffman_table;\n  int huffman_table_bits;\n  uint32_t repeated_offset1;\n  uint32_t repeated_offset2;\n  uint32_t repeated_offset3;\n  uint16_t *scratch;\n  unsigned char hdr;\n  int has_checksum;\n  uint64_t content_size;\n  int last_block;\n\n  pinend = pin + sin;\n  poutstart = pout;\n  poutend = pout + sout;\n\n  literal_decode.table = NULL;\n  literal_decode.table_bits = -1;\n  literal_fse_table = ((struct elf_zstd_fse_baseline_entry *)\n\t\t       (zdebug_table + ZSTD_TABLE_LITERAL_FSE_OFFSET));\n\n  match_decode.table = NULL;\n  match_decode.table_bits = -1;\n  match_fse_table = ((struct elf_zstd_fse_baseline_entry *)\n\t\t     (zdebug_table + ZSTD_TABLE_MATCH_FSE_OFFSET));\n\n  offset_decode.table = NULL;\n  offset_decode.table_bits = -1;\n  offset_fse_table = ((struct elf_zstd_fse_baseline_entry *)\n\t\t      (zdebug_table + ZSTD_TABLE_OFFSET_FSE_OFFSET));\n  huffman_table = ((uint16_t *)\n\t\t   (zdebug_table + ZSTD_TABLE_HUFFMAN_OFFSET));\n  huffman_table_bits = 0;\n  scratch = ((uint16_t *)\n\t     (zdebug_table + ZSTD_TABLE_WORK_OFFSET));\n\n  repeated_offset1 = 1;\n  repeated_offset2 = 4;\n  repeated_offset3 = 8;\n\n  if (unlikely (sin < 4))\n    {\n      elf_uncompress_failed ();\n      return 0;\n    }\n\n  /* These values are the zstd magic number.  */\n  if (unlikely (pin[0] != 0x28\n\t\t|| pin[1] != 0xb5\n\t\t|| pin[2] != 0x2f\n\t\t|| pin[3] != 0xfd))\n    {\n      elf_uncompress_failed ();\n      return 0;\n    }\n\n  pin += 4;\n\n  if (unlikely (pin >= pinend))\n    {\n      elf_uncompress_failed ();\n      return 0;\n    }\n\n  hdr = *pin++;\n\n  /* We expect a single frame.  */\n  if (unlikely ((hdr & (1 << 5)) == 0))\n    {\n      elf_uncompress_failed ();\n      return 0;\n    }\n  /* Reserved bit must be zero.  */\n  if (unlikely ((hdr & (1 << 3)) != 0))\n    {\n      elf_uncompress_failed ();\n      return 0;\n    }\n  /* We do not expect a dictionary.  */\n  if (unlikely ((hdr & 3) != 0))\n    {\n      elf_uncompress_failed ();\n      return 0;\n    }\n  has_checksum = (hdr & (1 << 2)) != 0;\n  switch (hdr >> 6)\n    {\n    case 0:\n      if (unlikely (pin >= pinend))\n\t{\n\t  elf_uncompress_failed ();\n\t  return 0;\n\t}\n      content_size = (uint64_t) *pin++;\n      break;\n    case 1:\n      if (unlikely (pin + 1 >= pinend))\n\t{\n\t  elf_uncompress_failed ();\n\t  return 0;\n\t}\n      content_size = (((uint64_t) pin[0]) | (((uint64_t) pin[1]) << 8)) + 256;\n      pin += 2;\n      break;\n    case 2:\n      if (unlikely (pin + 3 >= pinend))\n\t{\n\t  elf_uncompress_failed ();\n\t  return 0;\n\t}\n      content_size = ((uint64_t) pin[0]\n\t\t      | (((uint64_t) pin[1]) << 8)\n\t\t      | (((uint64_t) pin[2]) << 16)\n\t\t      | (((uint64_t) pin[3]) << 24));\n      pin += 4;\n      break;\n    case 3:\n      if (unlikely (pin + 7 >= pinend))\n\t{\n\t  elf_uncompress_failed ();\n\t  return 0;\n\t}\n      content_size = ((uint64_t) pin[0]\n\t\t      | (((uint64_t) pin[1]) << 8)\n\t\t      | (((uint64_t) pin[2]) << 16)\n\t\t      | (((uint64_t) pin[3]) << 24)\n\t\t      | (((uint64_t) pin[4]) << 32)\n\t\t      | (((uint64_t) pin[5]) << 40)\n\t\t      | (((uint64_t) pin[6]) << 48)\n\t\t      | (((uint64_t) pin[7]) << 56));\n      pin += 8;\n      break;\n    default:\n      elf_uncompress_failed ();\n      return 0;\n    }\n\n  if (unlikely (content_size != (size_t) content_size\n\t\t|| (size_t) content_size != sout))\n    {\n      elf_uncompress_failed ();\n      return 0;\n    }\n\n  last_block = 0;\n  while (!last_block)\n    {\n      uint32_t block_hdr;\n      int block_type;\n      uint32_t block_size;\n\n      if (unlikely (pin + 2 >= pinend))\n\t{\n\t  elf_uncompress_failed ();\n\t  return 0;\n\t}\n      block_hdr = ((uint32_t) pin[0]\n\t\t   | (((uint32_t) pin[1]) << 8)\n\t\t   | (((uint32_t) pin[2]) << 16));\n      pin += 3;\n\n      last_block = block_hdr & 1;\n      block_type = (block_hdr >> 1) & 3;\n      block_size = block_hdr >> 3;\n\n      switch (block_type)\n\t{\n\tcase 0:\n\t  /* Raw_Block */\n\t  if (unlikely ((size_t) block_size > (size_t) (pinend - pin)))\n\t    {\n\t      elf_uncompress_failed ();\n\t      return 0;\n\t    }\n\t  if (unlikely ((size_t) block_size > (size_t) (poutend - pout)))\n\t    {\n\t      elf_uncompress_failed ();\n\t      return 0;\n\t    }\n\t  memcpy (pout, pin, block_size);\n\t  pout += block_size;\n\t  pin += block_size;\n\t  break;\n\n\tcase 1:\n\t  /* RLE_Block */\n\t  if (unlikely (pin >= pinend))\n\t    {\n\t      elf_uncompress_failed ();\n\t      return 0;\n\t    }\n\t  if (unlikely ((size_t) block_size > (size_t) (poutend - pout)))\n\t    {\n\t      elf_uncompress_failed ();\n\t      return 0;\n\t    }\n\t  memset (pout, *pin, block_size);\n\t  pout += block_size;\n\t  pin++;\n\t  break;\n\n\tcase 2:\n\t  {\n\t    const unsigned char *pblockend;\n\t    unsigned char *plitstack;\n\t    unsigned char *plit;\n\t    uint32_t literal_count;\n\t    unsigned char seq_hdr;\n\t    size_t seq_count;\n\t    size_t seq;\n\t    const unsigned char *pback;\n\t    uint64_t val;\n\t    unsigned int bits;\n\t    unsigned int literal_state;\n\t    unsigned int offset_state;\n\t    unsigned int match_state;\n\n\t    /* Compressed_Block */\n\t    if (unlikely ((size_t) block_size > (size_t) (pinend - pin)))\n\t      {\n\t\telf_uncompress_failed ();\n\t\treturn 0;\n\t      }\n\n\t    pblockend = pin + block_size;\n\n\t    /* Read the literals into the end of the output space, and leave\n\t       PLIT pointing at them.  */\n\n\t    if (!elf_zstd_read_literals (&pin, pblockend, pout, poutend,\n\t\t\t\t\t scratch, huffman_table,\n\t\t\t\t\t &huffman_table_bits,\n\t\t\t\t\t &plitstack))\n\t      return 0;\n\t    plit = plitstack;\n\t    literal_count = poutend - plit;\n\n\t    seq_hdr = *pin;\n\t    pin++;\n\t    if (seq_hdr < 128)\n\t      seq_count = seq_hdr;\n\t    else if (seq_hdr < 255)\n\t      {\n\t\tif (unlikely (pin >= pinend))\n\t\t  {\n\t\t    elf_uncompress_failed ();\n\t\t    return 0;\n\t\t  }\n\t\tseq_count = ((seq_hdr - 128) << 8) + *pin;\n\t\tpin++;\n\t      }\n\t    else\n\t      {\n\t\tif (unlikely (pin + 1 >= pinend))\n\t\t  {\n\t\t    elf_uncompress_failed ();\n\t\t    return 0;\n\t\t  }\n\t\tseq_count = *pin + (pin[1] << 8) + 0x7f00;\n\t\tpin += 2;\n\t      }\n\n\t    if (seq_count > 0)\n\t      {\n\t\tint (*pfn)(const struct elf_zstd_fse_entry *,\n\t\t\t   int, struct elf_zstd_fse_baseline_entry *);\n\n\t\tif (unlikely (pin >= pinend))\n\t\t  {\n\t\t    elf_uncompress_failed ();\n\t\t    return 0;\n\t\t  }\n\t\tseq_hdr = *pin;\n\t\t++pin;\n\n\t\tpfn = elf_zstd_make_literal_baseline_fse;\n\t\tif (!elf_zstd_unpack_seq_decode ((seq_hdr >> 6) & 3,\n\t\t\t\t\t\t &pin, pinend,\n\t\t\t\t\t\t &elf_zstd_lit_table[0], 6,\n\t\t\t\t\t\t scratch, 35,\n\t\t\t\t\t\t literal_fse_table, 9, pfn,\n\t\t\t\t\t\t &literal_decode))\n\t\t  return 0;\n\n\t\tpfn = elf_zstd_make_offset_baseline_fse;\n\t\tif (!elf_zstd_unpack_seq_decode ((seq_hdr >> 4) & 3,\n\t\t\t\t\t\t &pin, pinend,\n\t\t\t\t\t\t &elf_zstd_offset_table[0], 5,\n\t\t\t\t\t\t scratch, 31,\n\t\t\t\t\t\t offset_fse_table, 8, pfn,\n\t\t\t\t\t\t &offset_decode))\n\t\t  return 0;\n\n\t\tpfn = elf_zstd_make_match_baseline_fse;\n\t\tif (!elf_zstd_unpack_seq_decode ((seq_hdr >> 2) & 3,\n\t\t\t\t\t\t &pin, pinend,\n\t\t\t\t\t\t &elf_zstd_match_table[0], 6,\n\t\t\t\t\t\t scratch, 52,\n\t\t\t\t\t\t match_fse_table, 9, pfn,\n\t\t\t\t\t\t &match_decode))\n\t\t  return 0;\n\t      }\n\n\t    pback = pblockend - 1;\n\t    if (!elf_fetch_backward_init (&pback, pin, &val, &bits))\n\t      return 0;\n\n\t    bits -= literal_decode.table_bits;\n\t    literal_state = ((val >> bits)\n\t\t\t     & ((1U << literal_decode.table_bits) - 1));\n\n\t    if (!elf_fetch_bits_backward (&pback, pin, &val, &bits))\n\t      return 0;\n\t    bits -= offset_decode.table_bits;\n\t    offset_state = ((val >> bits)\n\t\t\t    & ((1U << offset_decode.table_bits) - 1));\n\n\t    if (!elf_fetch_bits_backward (&pback, pin, &val, &bits))\n\t      return 0;\n\t    bits -= match_decode.table_bits;\n\t    match_state = ((val >> bits)\n\t\t\t   & ((1U << match_decode.table_bits) - 1));\n\n\t    seq = 0;\n\t    while (1)\n\t      {\n\t\tconst struct elf_zstd_fse_baseline_entry *pt;\n\t\tuint32_t offset_basebits;\n\t\tuint32_t offset_baseline;\n\t\tuint32_t offset_bits;\n\t\tuint32_t offset_base;\n\t\tuint32_t offset;\n\t\tuint32_t match_baseline;\n\t\tuint32_t match_bits;\n\t\tuint32_t match_base;\n\t\tuint32_t match;\n\t\tuint32_t literal_baseline;\n\t\tuint32_t literal_bits;\n\t\tuint32_t literal_base;\n\t\tuint32_t literal;\n\t\tuint32_t need;\n\t\tuint32_t add;\n\n\t\tpt = &offset_decode.table[offset_state];\n\t\toffset_basebits = pt->basebits;\n\t\toffset_baseline = pt->baseline;\n\t\toffset_bits = pt->bits;\n\t\toffset_base = pt->base;\n\n\t\t/* This case can be more than 16 bits, which is all that\n\t\t   elf_fetch_bits_backward promises.  */\n\t\tneed = offset_basebits;\n\t\tadd = 0;\n\t\tif (unlikely (need > 16))\n\t\t  {\n\t\t    if (!elf_fetch_bits_backward (&pback, pin, &val, &bits))\n\t\t      return 0;\n\t\t    bits -= 16;\n\t\t    add = (val >> bits) & ((1U << 16) - 1);\n\t\t    need -= 16;\n\t\t    add <<= need;\n\t\t  }\n\t\tif (need > 0)\n\t\t  {\n\t\t    if (!elf_fetch_bits_backward (&pback, pin, &val, &bits))\n\t\t      return 0;\n\t\t    bits -= need;\n\t\t    add += (val >> bits) & ((1U << need) - 1);\n\t\t  }\n\n\t\toffset = offset_baseline + add;\n\n\t\tpt = &match_decode.table[match_state];\n\t\tneed = pt->basebits;\n\t\tmatch_baseline = pt->baseline;\n\t\tmatch_bits = pt->bits;\n\t\tmatch_base = pt->base;\n\n\t\tadd = 0;\n\t\tif (need > 0)\n\t\t  {\n\t\t    if (!elf_fetch_bits_backward (&pback, pin, &val, &bits))\n\t\t      return 0;\n\t\t    bits -= need;\n\t\t    add = (val >> bits) & ((1U << need) - 1);\n\t\t  }\n\n\t\tmatch = match_baseline + add;\n\n\t\tpt = &literal_decode.table[literal_state];\n\t\tneed = pt->basebits;\n\t\tliteral_baseline = pt->baseline;\n\t\tliteral_bits = pt->bits;\n\t\tliteral_base = pt->base;\n\n\t\tadd = 0;\n\t\tif (need > 0)\n\t\t  {\n\t\t    if (!elf_fetch_bits_backward (&pback, pin, &val, &bits))\n\t\t      return 0;\n\t\t    bits -= need;\n\t\t    add = (val >> bits) & ((1U << need) - 1);\n\t\t  }\n\n\t\tliteral = literal_baseline + add;\n\n\t\t/* See the comment in elf_zstd_make_offset_baseline_fse.  */\n\t\tif (offset_basebits > 1)\n\t\t  {\n\t\t    repeated_offset3 = repeated_offset2;\n\t\t    repeated_offset2 = repeated_offset1;\n\t\t    repeated_offset1 = offset;\n\t\t  }\n\t\telse\n\t\t  {\n\t\t    if (unlikely (literal == 0))\n\t\t      ++offset;\n\t\t    switch (offset)\n\t\t      {\n\t\t      case 1:\n\t\t\toffset = repeated_offset1;\n\t\t\tbreak;\n\t\t      case 2:\n\t\t\toffset = repeated_offset2;\n\t\t\trepeated_offset2 = repeated_offset1;\n\t\t\trepeated_offset1 = offset;\n\t\t\tbreak;\n\t\t      case 3:\n\t\t\toffset = repeated_offset3;\n\t\t\trepeated_offset3 = repeated_offset2;\n\t\t\trepeated_offset2 = repeated_offset1;\n\t\t\trepeated_offset1 = offset;\n\t\t\tbreak;\n\t\t      case 4:\n\t\t\toffset = repeated_offset1 - 1;\n\t\t\trepeated_offset3 = repeated_offset2;\n\t\t\trepeated_offset2 = repeated_offset1;\n\t\t\trepeated_offset1 = offset;\n\t\t\tbreak;\n\t\t      }\n\t\t  }\n\n\t\t++seq;\n\t\tif (seq < seq_count)\n\t\t  {\n\t\t    uint32_t v;\n\n\t\t    /* Update the three states.  */\n\n\t\t    if (!elf_fetch_bits_backward (&pback, pin, &val, &bits))\n\t\t      return 0;\n\n\t\t    need = literal_bits;\n\t\t    bits -= need;\n\t\t    v = (val >> bits) & (((uint32_t)1 << need) - 1);\n\n\t\t    literal_state = literal_base + v;\n\n\t\t    if (!elf_fetch_bits_backward (&pback, pin, &val, &bits))\n\t\t      return 0;\n\n\t\t    need = match_bits;\n\t\t    bits -= need;\n\t\t    v = (val >> bits) & (((uint32_t)1 << need) - 1);\n\n\t\t    match_state = match_base + v;\n\n\t\t    if (!elf_fetch_bits_backward (&pback, pin, &val, &bits))\n\t\t      return 0;\n\n\t\t    need = offset_bits;\n\t\t    bits -= need;\n\t\t    v = (val >> bits) & (((uint32_t)1 << need) - 1);\n\n\t\t    offset_state = offset_base + v;\n\t\t  }\n\n\t\t/* The next sequence is now in LITERAL, OFFSET, MATCH.  */\n\n\t\t/* Copy LITERAL bytes from the literals.  */\n\n\t\tif (unlikely ((size_t)(poutend - pout) < literal))\n\t\t  {\n\t\t    elf_uncompress_failed ();\n\t\t    return 0;\n\t\t  }\n\n\t\tif (unlikely (literal_count < literal))\n\t\t  {\n\t\t    elf_uncompress_failed ();\n\t\t    return 0;\n\t\t  }\n\n\t\tliteral_count -= literal;\n\n\t\t/* Often LITERAL is small, so handle small cases quickly.  */\n\t\tswitch (literal)\n\t\t  {\n\t\t  case 8:\n\t\t    *pout++ = *plit++;\n\t\t    /* FALLTHROUGH */\n\t\t  case 7:\n\t\t    *pout++ = *plit++;\n\t\t    /* FALLTHROUGH */\n\t\t  case 6:\n\t\t    *pout++ = *plit++;\n\t\t    /* FALLTHROUGH */\n\t\t  case 5:\n\t\t    *pout++ = *plit++;\n\t\t    /* FALLTHROUGH */\n\t\t  case 4:\n\t\t    *pout++ = *plit++;\n\t\t    /* FALLTHROUGH */\n\t\t  case 3:\n\t\t    *pout++ = *plit++;\n\t\t    /* FALLTHROUGH */\n\t\t  case 2:\n\t\t    *pout++ = *plit++;\n\t\t    /* FALLTHROUGH */\n\t\t  case 1:\n\t\t    *pout++ = *plit++;\n\t\t    break;\n\n\t\t  case 0:\n\t\t    break;\n\n\t\t  default:\n\t\t    if (unlikely ((size_t)(plit - pout) < literal))\n\t\t      {\n\t\t\tuint32_t move;\n\n\t\t\tmove = plit - pout;\n\t\t\twhile (literal > move)\n\t\t\t  {\n\t\t\t    memcpy (pout, plit, move);\n\t\t\t    pout += move;\n\t\t\t    plit += move;\n\t\t\t    literal -= move;\n\t\t\t  }\n\t\t      }\n\n\t\t    memcpy (pout, plit, literal);\n\t\t    pout += literal;\n\t\t    plit += literal;\n\t\t  }\n\n\t\tif (match > 0)\n\t\t  {\n\t\t    /* Copy MATCH bytes from the decoded output at OFFSET.  */\n\n\t\t    if (unlikely ((size_t)(poutend - pout) < match))\n\t\t      {\n\t\t\telf_uncompress_failed ();\n\t\t\treturn 0;\n\t\t      }\n\n\t\t    if (unlikely ((size_t)(pout - poutstart) < offset))\n\t\t      {\n\t\t\telf_uncompress_failed ();\n\t\t\treturn 0;\n\t\t      }\n\n\t\t    if (offset >= match)\n\t\t      {\n\t\t\tmemcpy (pout, pout - offset, match);\n\t\t\tpout += match;\n\t\t      }\n\t\t    else\n\t\t      {\n\t\t\twhile (match > 0)\n\t\t\t  {\n\t\t\t    uint32_t copy;\n\n\t\t\t    copy = match < offset ? match : offset;\n\t\t\t    memcpy (pout, pout - offset, copy);\n\t\t\t    match -= copy;\n\t\t\t    pout += copy;\n\t\t\t  }\n\t\t      }\n\t\t  }\n\n\t\tif (unlikely (seq >= seq_count))\n\t\t  {\n\t\t    /* Copy remaining literals.  */\n\t\t    if (literal_count > 0 && plit != pout)\n\t\t      {\n\t\t\tif (unlikely ((size_t)(poutend - pout)\n\t\t\t\t      < literal_count))\n\t\t\t  {\n\t\t\t    elf_uncompress_failed ();\n\t\t\t    return 0;\n\t\t\t  }\n\n\t\t\tif ((size_t)(plit - pout) < literal_count)\n\t\t\t  {\n\t\t\t    uint32_t move;\n\n\t\t\t    move = plit - pout;\n\t\t\t    while (literal_count > move)\n\t\t\t      {\n\t\t\t\tmemcpy (pout, plit, move);\n\t\t\t\tpout += move;\n\t\t\t\tplit += move;\n\t\t\t\tliteral_count -= move;\n\t\t\t      }\n\t\t\t  }\n\n\t\t\tmemcpy (pout, plit, literal_count);\n\t\t      }\n\n\t\t    pout += literal_count;\n\n\t\t    break;\n\t\t  }\n\t      }\n\n\t    pin = pblockend;\n\t  }\n\t  break;\n\n\tcase 3:\n\tdefault:\n\t  elf_uncompress_failed ();\n\t  return 0;\n\t}\n    }\n\n  if (has_checksum)\n    {\n      if (unlikely (pin + 4 > pinend))\n\t{\n\t  elf_uncompress_failed ();\n\t  return 0;\n\t}\n\n      /* We don't currently verify the checksum.  Currently running GNU ld with\n\t --compress-debug-sections=zstd does not seem to generate a\n\t checksum.  */\n\n      pin += 4;\n    }\n\n  if (pin != pinend)\n    {\n      elf_uncompress_failed ();\n      return 0;\n    }\n\n  return 1;\n}\n\n#define ZDEBUG_TABLE_SIZE \\\n  (ZLIB_TABLE_SIZE > ZSTD_TABLE_SIZE ? ZLIB_TABLE_SIZE : ZSTD_TABLE_SIZE)\n\n/* Uncompress the old compressed debug format, the one emitted by\n   --compress-debug-sections=zlib-gnu.  The compressed data is in\n   COMPRESSED / COMPRESSED_SIZE, and the function writes to\n   *UNCOMPRESSED / *UNCOMPRESSED_SIZE.  ZDEBUG_TABLE is work space to\n   hold Huffman tables.  Returns 0 on error, 1 on successful\n   decompression or if something goes wrong.  In general we try to\n   carry on, by returning 1, even if we can't decompress.  */\n\nstatic int\nelf_uncompress_zdebug (struct backtrace_state *state,\n\t\t       const unsigned char *compressed, size_t compressed_size,\n\t\t       uint16_t *zdebug_table,\n\t\t       backtrace_error_callback error_callback, void *data,\n\t\t       unsigned char **uncompressed, size_t *uncompressed_size)\n{\n  size_t sz;\n  size_t i;\n  unsigned char *po;\n\n  *uncompressed = NULL;\n  *uncompressed_size = 0;\n\n  /* The format starts with the four bytes ZLIB, followed by the 8\n     byte length of the uncompressed data in big-endian order,\n     followed by a zlib stream.  */\n\n  if (compressed_size < 12 || memcmp (compressed, \"ZLIB\", 4) != 0)\n    return 1;\n\n  sz = 0;\n  for (i = 0; i < 8; i++)\n    sz = (sz << 8) | compressed[i + 4];\n\n  if (*uncompressed != NULL && *uncompressed_size >= sz)\n    po = *uncompressed;\n  else\n    {\n      po = (unsigned char *) backtrace_alloc (state, sz, error_callback, data);\n      if (po == NULL)\n\treturn 0;\n    }\n\n  if (!elf_zlib_inflate_and_verify (compressed + 12, compressed_size - 12,\n\t\t\t\t    zdebug_table, po, sz))\n    return 1;\n\n  *uncompressed = po;\n  *uncompressed_size = sz;\n\n  return 1;\n}\n\n/* Uncompress the new compressed debug format, the official standard\n   ELF approach emitted by --compress-debug-sections=zlib-gabi.  The\n   compressed data is in COMPRESSED / COMPRESSED_SIZE, and the\n   function writes to *UNCOMPRESSED / *UNCOMPRESSED_SIZE.\n   ZDEBUG_TABLE is work space as for elf_uncompress_zdebug.  Returns 0\n   on error, 1 on successful decompression or if something goes wrong.\n   In general we try to carry on, by returning 1, even if we can't\n   decompress.  */\n\nstatic int\nelf_uncompress_chdr (struct backtrace_state *state,\n\t\t     const unsigned char *compressed, size_t compressed_size,\n\t\t     uint16_t *zdebug_table,\n\t\t     backtrace_error_callback error_callback, void *data,\n\t\t     unsigned char **uncompressed, size_t *uncompressed_size)\n{\n  b_elf_chdr chdr;\n  char *alc;\n  size_t alc_len;\n  unsigned char *po;\n\n  *uncompressed = NULL;\n  *uncompressed_size = 0;\n\n  /* The format starts with an ELF compression header.  */\n  if (compressed_size < sizeof (b_elf_chdr))\n    return 1;\n\n  /* The lld linker can misalign a compressed section, so we can't safely read\n     the fields directly as we can for other ELF sections.  See\n     https://github.com/ianlancetaylor/libbacktrace/pull/120.  */\n  memcpy (&chdr, compressed, sizeof (b_elf_chdr));\n\n  alc = NULL;\n  alc_len = 0;\n  if (*uncompressed != NULL && *uncompressed_size >= chdr.ch_size)\n    po = *uncompressed;\n  else\n    {\n      alc_len = chdr.ch_size;\n      alc = (char*)backtrace_alloc (state, alc_len, error_callback, data);\n      if (alc == NULL)\n\treturn 0;\n      po = (unsigned char *) alc;\n    }\n\n  switch (chdr.ch_type)\n    {\n    case ELFCOMPRESS_ZLIB:\n      if (!elf_zlib_inflate_and_verify (compressed + sizeof (b_elf_chdr),\n\t\t\t\t\tcompressed_size - sizeof (b_elf_chdr),\n\t\t\t\t\tzdebug_table, po, chdr.ch_size))\n\tgoto skip;\n      break;\n\n    case ELFCOMPRESS_ZSTD:\n      if (!elf_zstd_decompress (compressed + sizeof (b_elf_chdr),\n\t\t\t\tcompressed_size - sizeof (b_elf_chdr),\n\t\t\t\t(unsigned char *)zdebug_table, po,\n\t\t\t\tchdr.ch_size))\n\tgoto skip;\n      break;\n\n    default:\n      /* Unsupported compression algorithm.  */\n      goto skip;\n    }\n\n  *uncompressed = po;\n  *uncompressed_size = chdr.ch_size;\n\n  return 1;\n\n skip:\n  if (alc != NULL && alc_len > 0)\n    backtrace_free (state, alc, alc_len, error_callback, data);\n  return 1;\n}\n\n/* This function is a hook for testing the zlib support.  It is only\n   used by tests.  */\n\nint\nbacktrace_uncompress_zdebug (struct backtrace_state *state,\n\t\t\t     const unsigned char *compressed,\n\t\t\t     size_t compressed_size,\n\t\t\t     backtrace_error_callback error_callback,\n\t\t\t     void *data, unsigned char **uncompressed,\n\t\t\t     size_t *uncompressed_size)\n{\n  uint16_t *zdebug_table;\n  int ret;\n\n  zdebug_table = ((uint16_t *) backtrace_alloc (state, ZDEBUG_TABLE_SIZE,\n\t\t\t\t\t\terror_callback, data));\n  if (zdebug_table == NULL)\n    return 0;\n  ret = elf_uncompress_zdebug (state, compressed, compressed_size,\n\t\t\t       zdebug_table, error_callback, data,\n\t\t\t       uncompressed, uncompressed_size);\n  backtrace_free (state, zdebug_table, ZDEBUG_TABLE_SIZE,\n\t\t  error_callback, data);\n  return ret;\n}\n\n/* This function is a hook for testing the zstd support.  It is only used by\n   tests.  */\n\nint\nbacktrace_uncompress_zstd (struct backtrace_state *state,\n\t\t\t   const unsigned char *compressed,\n\t\t\t   size_t compressed_size,\n\t\t\t   backtrace_error_callback error_callback,\n\t\t\t   void *data, unsigned char *uncompressed,\n\t\t\t   size_t uncompressed_size)\n{\n  unsigned char *zdebug_table;\n  int ret;\n\n  zdebug_table = ((unsigned char *) backtrace_alloc (state, ZDEBUG_TABLE_SIZE,\n\t\t\t\t\t\t     error_callback, data));\n  if (zdebug_table == NULL)\n    return 0;\n  ret = elf_zstd_decompress (compressed, compressed_size,\n\t\t\t     zdebug_table, uncompressed, uncompressed_size);\n  backtrace_free (state, zdebug_table, ZDEBUG_TABLE_SIZE,\n\t\t  error_callback, data);\n  return ret;\n}\n\n/* Number of LZMA states.  */\n#define LZMA_STATES (12)\n\n/* Number of LZMA position states.  The pb value of the property byte\n   is the number of bits to include in these states, and the maximum\n   value of pb is 4.  */\n#define LZMA_POS_STATES (16)\n\n/* Number of LZMA distance states.  These are used match distances\n   with a short match length: up to 4 bytes.  */\n#define LZMA_DIST_STATES (4)\n\n/* Number of LZMA distance slots.  LZMA uses six bits to encode larger\n   match lengths, so 1 << 6 possible probabilities.  */\n#define LZMA_DIST_SLOTS (64)\n\n/* LZMA distances 0 to 3 are encoded directly, larger values use a\n   probability model.  */\n#define LZMA_DIST_MODEL_START (4)\n\n/* The LZMA probability model ends at 14.  */\n#define LZMA_DIST_MODEL_END (14)\n\n/* LZMA distance slots for distances less than 127.  */\n#define LZMA_FULL_DISTANCES (128)\n\n/* LZMA uses four alignment bits.  */\n#define LZMA_ALIGN_SIZE (16)\n\n/* LZMA match length is encoded with 4, 5, or 10 bits, some of which\n   are already known.  */\n#define LZMA_LEN_LOW_SYMBOLS (8)\n#define LZMA_LEN_MID_SYMBOLS (8)\n#define LZMA_LEN_HIGH_SYMBOLS (256)\n\n/* LZMA literal encoding.  */\n#define LZMA_LITERAL_CODERS_MAX (16)\n#define LZMA_LITERAL_CODER_SIZE (0x300)\n\n/* LZMA is based on a large set of probabilities, each managed\n   independently.  Each probability is an 11 bit number that we store\n   in a uint16_t.  We use a single large array of probabilities.  */\n\n/* Lengths of entries in the LZMA probabilities array.  The names used\n   here are copied from the Linux kernel implementation.  */\n\n#define LZMA_PROB_IS_MATCH_LEN (LZMA_STATES * LZMA_POS_STATES)\n#define LZMA_PROB_IS_REP_LEN LZMA_STATES\n#define LZMA_PROB_IS_REP0_LEN LZMA_STATES\n#define LZMA_PROB_IS_REP1_LEN LZMA_STATES\n#define LZMA_PROB_IS_REP2_LEN LZMA_STATES\n#define LZMA_PROB_IS_REP0_LONG_LEN (LZMA_STATES * LZMA_POS_STATES)\n#define LZMA_PROB_DIST_SLOT_LEN (LZMA_DIST_STATES * LZMA_DIST_SLOTS)\n#define LZMA_PROB_DIST_SPECIAL_LEN (LZMA_FULL_DISTANCES - LZMA_DIST_MODEL_END)\n#define LZMA_PROB_DIST_ALIGN_LEN LZMA_ALIGN_SIZE\n#define LZMA_PROB_MATCH_LEN_CHOICE_LEN 1\n#define LZMA_PROB_MATCH_LEN_CHOICE2_LEN 1\n#define LZMA_PROB_MATCH_LEN_LOW_LEN (LZMA_POS_STATES * LZMA_LEN_LOW_SYMBOLS)\n#define LZMA_PROB_MATCH_LEN_MID_LEN (LZMA_POS_STATES * LZMA_LEN_MID_SYMBOLS)\n#define LZMA_PROB_MATCH_LEN_HIGH_LEN LZMA_LEN_HIGH_SYMBOLS\n#define LZMA_PROB_REP_LEN_CHOICE_LEN 1\n#define LZMA_PROB_REP_LEN_CHOICE2_LEN 1\n#define LZMA_PROB_REP_LEN_LOW_LEN (LZMA_POS_STATES * LZMA_LEN_LOW_SYMBOLS)\n#define LZMA_PROB_REP_LEN_MID_LEN (LZMA_POS_STATES * LZMA_LEN_MID_SYMBOLS)\n#define LZMA_PROB_REP_LEN_HIGH_LEN LZMA_LEN_HIGH_SYMBOLS\n#define LZMA_PROB_LITERAL_LEN \\\n  (LZMA_LITERAL_CODERS_MAX * LZMA_LITERAL_CODER_SIZE)\n\n/* Offsets into the LZMA probabilities array.  This is mechanically\n   generated from the above lengths.  */\n\n#define LZMA_PROB_IS_MATCH_OFFSET 0\n#define LZMA_PROB_IS_REP_OFFSET \\\n  (LZMA_PROB_IS_MATCH_OFFSET + LZMA_PROB_IS_MATCH_LEN)\n#define LZMA_PROB_IS_REP0_OFFSET \\\n  (LZMA_PROB_IS_REP_OFFSET + LZMA_PROB_IS_REP_LEN)\n#define LZMA_PROB_IS_REP1_OFFSET \\\n  (LZMA_PROB_IS_REP0_OFFSET + LZMA_PROB_IS_REP0_LEN)\n#define LZMA_PROB_IS_REP2_OFFSET \\\n  (LZMA_PROB_IS_REP1_OFFSET + LZMA_PROB_IS_REP1_LEN)\n#define LZMA_PROB_IS_REP0_LONG_OFFSET \\\n  (LZMA_PROB_IS_REP2_OFFSET + LZMA_PROB_IS_REP2_LEN)\n#define LZMA_PROB_DIST_SLOT_OFFSET \\\n  (LZMA_PROB_IS_REP0_LONG_OFFSET + LZMA_PROB_IS_REP0_LONG_LEN)\n#define LZMA_PROB_DIST_SPECIAL_OFFSET \\\n  (LZMA_PROB_DIST_SLOT_OFFSET + LZMA_PROB_DIST_SLOT_LEN)\n#define LZMA_PROB_DIST_ALIGN_OFFSET \\\n  (LZMA_PROB_DIST_SPECIAL_OFFSET + LZMA_PROB_DIST_SPECIAL_LEN)\n#define LZMA_PROB_MATCH_LEN_CHOICE_OFFSET \\\n  (LZMA_PROB_DIST_ALIGN_OFFSET + LZMA_PROB_DIST_ALIGN_LEN)\n#define LZMA_PROB_MATCH_LEN_CHOICE2_OFFSET \\\n  (LZMA_PROB_MATCH_LEN_CHOICE_OFFSET + LZMA_PROB_MATCH_LEN_CHOICE_LEN)\n#define LZMA_PROB_MATCH_LEN_LOW_OFFSET \\\n  (LZMA_PROB_MATCH_LEN_CHOICE2_OFFSET + LZMA_PROB_MATCH_LEN_CHOICE2_LEN)\n#define LZMA_PROB_MATCH_LEN_MID_OFFSET \\\n  (LZMA_PROB_MATCH_LEN_LOW_OFFSET + LZMA_PROB_MATCH_LEN_LOW_LEN)\n#define LZMA_PROB_MATCH_LEN_HIGH_OFFSET \\\n  (LZMA_PROB_MATCH_LEN_MID_OFFSET + LZMA_PROB_MATCH_LEN_MID_LEN)\n#define LZMA_PROB_REP_LEN_CHOICE_OFFSET \\\n  (LZMA_PROB_MATCH_LEN_HIGH_OFFSET + LZMA_PROB_MATCH_LEN_HIGH_LEN)\n#define LZMA_PROB_REP_LEN_CHOICE2_OFFSET \\\n  (LZMA_PROB_REP_LEN_CHOICE_OFFSET + LZMA_PROB_REP_LEN_CHOICE_LEN)\n#define LZMA_PROB_REP_LEN_LOW_OFFSET \\\n  (LZMA_PROB_REP_LEN_CHOICE2_OFFSET + LZMA_PROB_REP_LEN_CHOICE2_LEN)\n#define LZMA_PROB_REP_LEN_MID_OFFSET \\\n  (LZMA_PROB_REP_LEN_LOW_OFFSET + LZMA_PROB_REP_LEN_LOW_LEN)\n#define LZMA_PROB_REP_LEN_HIGH_OFFSET \\\n  (LZMA_PROB_REP_LEN_MID_OFFSET + LZMA_PROB_REP_LEN_MID_LEN)\n#define LZMA_PROB_LITERAL_OFFSET \\\n  (LZMA_PROB_REP_LEN_HIGH_OFFSET + LZMA_PROB_REP_LEN_HIGH_LEN)\n\n#define LZMA_PROB_TOTAL_COUNT \\\n  (LZMA_PROB_LITERAL_OFFSET + LZMA_PROB_LITERAL_LEN)\n\n/* Check that the number of LZMA probabilities is the same as the\n   Linux kernel implementation.  */\n\n#if LZMA_PROB_TOTAL_COUNT != 1846 + (1 << 4) * 0x300\n #error Wrong number of LZMA probabilities\n#endif\n\n/* Expressions for the offset in the LZMA probabilities array of a\n   specific probability.  */\n\n#define LZMA_IS_MATCH(state, pos) \\\n  (LZMA_PROB_IS_MATCH_OFFSET + (state) * LZMA_POS_STATES + (pos))\n#define LZMA_IS_REP(state) \\\n  (LZMA_PROB_IS_REP_OFFSET + (state))\n#define LZMA_IS_REP0(state) \\\n  (LZMA_PROB_IS_REP0_OFFSET + (state))\n#define LZMA_IS_REP1(state) \\\n  (LZMA_PROB_IS_REP1_OFFSET + (state))\n#define LZMA_IS_REP2(state) \\\n  (LZMA_PROB_IS_REP2_OFFSET + (state))\n#define LZMA_IS_REP0_LONG(state, pos) \\\n  (LZMA_PROB_IS_REP0_LONG_OFFSET + (state) * LZMA_POS_STATES + (pos))\n#define LZMA_DIST_SLOT(dist, slot) \\\n  (LZMA_PROB_DIST_SLOT_OFFSET + (dist) * LZMA_DIST_SLOTS + (slot))\n#define LZMA_DIST_SPECIAL(dist) \\\n  (LZMA_PROB_DIST_SPECIAL_OFFSET + (dist))\n#define LZMA_DIST_ALIGN(dist) \\\n  (LZMA_PROB_DIST_ALIGN_OFFSET + (dist))\n#define LZMA_MATCH_LEN_CHOICE \\\n  LZMA_PROB_MATCH_LEN_CHOICE_OFFSET\n#define LZMA_MATCH_LEN_CHOICE2 \\\n  LZMA_PROB_MATCH_LEN_CHOICE2_OFFSET\n#define LZMA_MATCH_LEN_LOW(pos, sym) \\\n  (LZMA_PROB_MATCH_LEN_LOW_OFFSET + (pos) * LZMA_LEN_LOW_SYMBOLS + (sym))\n#define LZMA_MATCH_LEN_MID(pos, sym) \\\n  (LZMA_PROB_MATCH_LEN_MID_OFFSET + (pos) * LZMA_LEN_MID_SYMBOLS + (sym))\n#define LZMA_MATCH_LEN_HIGH(sym) \\\n  (LZMA_PROB_MATCH_LEN_HIGH_OFFSET + (sym))\n#define LZMA_REP_LEN_CHOICE \\\n  LZMA_PROB_REP_LEN_CHOICE_OFFSET\n#define LZMA_REP_LEN_CHOICE2 \\\n  LZMA_PROB_REP_LEN_CHOICE2_OFFSET\n#define LZMA_REP_LEN_LOW(pos, sym) \\\n  (LZMA_PROB_REP_LEN_LOW_OFFSET + (pos) * LZMA_LEN_LOW_SYMBOLS + (sym))\n#define LZMA_REP_LEN_MID(pos, sym) \\\n  (LZMA_PROB_REP_LEN_MID_OFFSET + (pos) * LZMA_LEN_MID_SYMBOLS + (sym))\n#define LZMA_REP_LEN_HIGH(sym) \\\n  (LZMA_PROB_REP_LEN_HIGH_OFFSET + (sym))\n#define LZMA_LITERAL(code, size) \\\n  (LZMA_PROB_LITERAL_OFFSET + (code) * LZMA_LITERAL_CODER_SIZE + (size))\n\n/* Read an LZMA varint from BUF, reading and updating *POFFSET,\n   setting *VAL.  Returns 0 on error, 1 on success.  */\n\nstatic int\nelf_lzma_varint (const unsigned char *compressed, size_t compressed_size,\n\t\t size_t *poffset, uint64_t *val)\n{\n  size_t off;\n  int i;\n  uint64_t v;\n  unsigned char b;\n\n  off = *poffset;\n  i = 0;\n  v = 0;\n  while (1)\n    {\n      if (unlikely (off >= compressed_size))\n\t{\n\t  elf_uncompress_failed ();\n\t  return 0;\n\t}\n      b = compressed[off];\n      v |= (b & 0x7f) << (i * 7);\n      ++off;\n      if ((b & 0x80) == 0)\n\t{\n\t  *poffset = off;\n\t  *val = v;\n\t  return 1;\n\t}\n      ++i;\n      if (unlikely (i >= 9))\n\t{\n\t  elf_uncompress_failed ();\n\t  return 0;\n\t}\n    }\n}\n\n/* Normalize the LZMA range decoder, pulling in an extra input byte if\n   needed.  */\n\nstatic void\nelf_lzma_range_normalize (const unsigned char *compressed,\n\t\t\t  size_t compressed_size, size_t *poffset,\n\t\t\t  uint32_t *prange, uint32_t *pcode)\n{\n  if (*prange < (1U << 24))\n    {\n      if (unlikely (*poffset >= compressed_size))\n\t{\n\t  /* We assume this will be caught elsewhere.  */\n\t  elf_uncompress_failed ();\n\t  return;\n\t}\n      *prange <<= 8;\n      *pcode <<= 8;\n      *pcode += compressed[*poffset];\n      ++*poffset;\n    }\n}\n\n/* Read and return a single bit from the LZMA stream, reading and\n   updating *PROB.  Each bit comes from the range coder.  */\n\nstatic int\nelf_lzma_bit (const unsigned char *compressed, size_t compressed_size,\n\t      uint16_t *prob, size_t *poffset, uint32_t *prange,\n\t      uint32_t *pcode)\n{\n  uint32_t bound;\n\n  elf_lzma_range_normalize (compressed, compressed_size, poffset,\n\t\t\t    prange, pcode);\n  bound = (*prange >> 11) * (uint32_t) *prob;\n  if (*pcode < bound)\n    {\n      *prange = bound;\n      *prob += ((1U << 11) - *prob) >> 5;\n      return 0;\n    }\n  else\n    {\n      *prange -= bound;\n      *pcode -= bound;\n      *prob -= *prob >> 5;\n      return 1;\n    }\n}\n\n/* Read an integer of size BITS from the LZMA stream, most significant\n   bit first.  The bits are predicted using PROBS.  */\n\nstatic uint32_t\nelf_lzma_integer (const unsigned char *compressed, size_t compressed_size,\n\t\t  uint16_t *probs, uint32_t bits, size_t *poffset,\n\t\t  uint32_t *prange, uint32_t *pcode)\n{\n  uint32_t sym;\n  uint32_t i;\n\n  sym = 1;\n  for (i = 0; i < bits; i++)\n    {\n      int bit;\n\n      bit = elf_lzma_bit (compressed, compressed_size, probs + sym, poffset,\n\t\t\t  prange, pcode);\n      sym <<= 1;\n      sym += bit;\n    }\n  return sym - (1 << bits);\n}\n\n/* Read an integer of size BITS from the LZMA stream, least\n   significant bit first.  The bits are predicted using PROBS.  */\n\nstatic uint32_t\nelf_lzma_reverse_integer (const unsigned char *compressed,\n\t\t\t  size_t compressed_size, uint16_t *probs,\n\t\t\t  uint32_t bits, size_t *poffset, uint32_t *prange,\n\t\t\t  uint32_t *pcode)\n{\n  uint32_t sym;\n  uint32_t val;\n  uint32_t i;\n\n  sym = 1;\n  val = 0;\n  for (i = 0; i < bits; i++)\n    {\n      int bit;\n\n      bit = elf_lzma_bit (compressed, compressed_size, probs + sym, poffset,\n\t\t\t  prange, pcode);\n      sym <<= 1;\n      sym += bit;\n      val += bit << i;\n    }\n  return val;\n}\n\n/* Read a length from the LZMA stream.  IS_REP picks either LZMA_MATCH\n   or LZMA_REP probabilities.  */\n\nstatic uint32_t\nelf_lzma_len (const unsigned char *compressed, size_t compressed_size,\n\t      uint16_t *probs, int is_rep, unsigned int pos_state,\n\t      size_t *poffset, uint32_t *prange, uint32_t *pcode)\n{\n  uint16_t *probs_choice;\n  uint16_t *probs_sym;\n  uint32_t bits;\n  uint32_t len;\n\n  probs_choice = probs + (is_rep\n\t\t\t  ? LZMA_REP_LEN_CHOICE\n\t\t\t  : LZMA_MATCH_LEN_CHOICE);\n  if (elf_lzma_bit (compressed, compressed_size, probs_choice, poffset,\n\t\t    prange, pcode))\n    {\n      probs_choice = probs + (is_rep\n\t\t\t      ? LZMA_REP_LEN_CHOICE2\n\t\t\t      : LZMA_MATCH_LEN_CHOICE2);\n      if (elf_lzma_bit (compressed, compressed_size, probs_choice,\n\t\t\tpoffset, prange, pcode))\n\t{\n\t  probs_sym = probs + (is_rep\n\t\t\t       ? LZMA_REP_LEN_HIGH (0)\n\t\t\t       : LZMA_MATCH_LEN_HIGH (0));\n\t  bits = 8;\n\t  len = 2 + 8 + 8;\n\t}\n      else\n\t{\n\t  probs_sym = probs + (is_rep\n\t\t\t       ? LZMA_REP_LEN_MID (pos_state, 0)\n\t\t\t       : LZMA_MATCH_LEN_MID (pos_state, 0));\n\t  bits = 3;\n\t  len = 2 + 8;\n\t}\n    }\n  else\n    {\n      probs_sym = probs + (is_rep\n\t\t\t   ? LZMA_REP_LEN_LOW (pos_state, 0)\n\t\t\t   : LZMA_MATCH_LEN_LOW (pos_state, 0));\n      bits = 3;\n      len = 2;\n    }\n\n  len += elf_lzma_integer (compressed, compressed_size, probs_sym, bits,\n\t\t\t   poffset, prange, pcode);\n  return len;\n}\n\n/* Uncompress one LZMA block from a minidebug file.  The compressed\n   data is at COMPRESSED + *POFFSET.  Update *POFFSET.  Store the data\n   into the memory at UNCOMPRESSED, size UNCOMPRESSED_SIZE.  CHECK is\n   the stream flag from the xz header.  Return 1 on successful\n   decompression.  */\n\nstatic int\nelf_uncompress_lzma_block (const unsigned char *compressed,\n\t\t\t   size_t compressed_size, unsigned char check,\n\t\t\t   uint16_t *probs, unsigned char *uncompressed,\n\t\t\t   size_t uncompressed_size, size_t *poffset)\n{\n  size_t off;\n  size_t block_header_offset;\n  size_t block_header_size;\n  unsigned char block_flags;\n  uint64_t header_compressed_size;\n  uint64_t header_uncompressed_size;\n  unsigned char lzma2_properties;\n  size_t crc_offset;\n  uint32_t computed_crc;\n  uint32_t stream_crc;\n  size_t uncompressed_offset;\n  size_t dict_start_offset;\n  unsigned int lc;\n  unsigned int lp;\n  unsigned int pb;\n  uint32_t range;\n  uint32_t code;\n  uint32_t lstate;\n  uint32_t dist[4];\n\n  off = *poffset;\n  block_header_offset = off;\n\n  /* Block header size is a single byte.  */\n  if (unlikely (off >= compressed_size))\n    {\n      elf_uncompress_failed ();\n      return 0;\n    }\n  block_header_size = (compressed[off] + 1) * 4;\n  if (unlikely (off + block_header_size > compressed_size))\n    {\n      elf_uncompress_failed ();\n      return 0;\n    }\n\n  /* Block flags.  */\n  block_flags = compressed[off + 1];\n  if (unlikely ((block_flags & 0x3c) != 0))\n    {\n      elf_uncompress_failed ();\n      return 0;\n    }\n\n  off += 2;\n\n  /* Optional compressed size.  */\n  header_compressed_size = 0;\n  if ((block_flags & 0x40) != 0)\n    {\n      *poffset = off;\n      if (!elf_lzma_varint (compressed, compressed_size, poffset,\n\t\t\t    &header_compressed_size))\n\treturn 0;\n      off = *poffset;\n    }\n\n  /* Optional uncompressed size.  */\n  header_uncompressed_size = 0;\n  if ((block_flags & 0x80) != 0)\n    {\n      *poffset = off;\n      if (!elf_lzma_varint (compressed, compressed_size, poffset,\n\t\t\t    &header_uncompressed_size))\n\treturn 0;\n      off = *poffset;\n    }\n\n  /* The recipe for creating a minidebug file is to run the xz program\n     with no arguments, so we expect exactly one filter: lzma2.  */\n\n  if (unlikely ((block_flags & 0x3) != 0))\n    {\n      elf_uncompress_failed ();\n      return 0;\n    }\n\n  if (unlikely (off + 2 >= block_header_offset + block_header_size))\n    {\n      elf_uncompress_failed ();\n      return 0;\n    }\n\n  /* The filter ID for LZMA2 is 0x21.  */\n  if (unlikely (compressed[off] != 0x21))\n    {\n      elf_uncompress_failed ();\n      return 0;\n    }\n  ++off;\n\n  /* The size of the filter properties for LZMA2 is 1.  */\n  if (unlikely (compressed[off] != 1))\n    {\n      elf_uncompress_failed ();\n      return 0;\n    }\n  ++off;\n\n  lzma2_properties = compressed[off];\n  ++off;\n\n  if (unlikely (lzma2_properties > 40))\n    {\n      elf_uncompress_failed ();\n      return 0;\n    }\n\n  /* The properties describe the dictionary size, but we don't care\n     what that is.  */\n\n  /* Skip to just before CRC, verifying zero bytes in between.  */\n  crc_offset = block_header_offset + block_header_size - 4;\n  if (unlikely (crc_offset + 4 > compressed_size))\n    {\n      elf_uncompress_failed ();\n      return 0;\n    }\n  for (; off < crc_offset; off++)\n    {\n      if (compressed[off] != 0)\n\t{\n\t  elf_uncompress_failed ();\n\t  return 0;\n\t}\n    }\n\n  /* Block header CRC.  */\n  computed_crc = elf_crc32 (0, compressed + block_header_offset,\n\t\t\t    block_header_size - 4);\n  stream_crc = ((uint32_t)compressed[off]\n\t\t| ((uint32_t)compressed[off + 1] << 8)\n\t\t| ((uint32_t)compressed[off + 2] << 16)\n\t\t| ((uint32_t)compressed[off + 3] << 24));\n  if (unlikely (computed_crc != stream_crc))\n    {\n      elf_uncompress_failed ();\n      return 0;\n    }\n  off += 4;\n\n  /* Read a sequence of LZMA2 packets.  */\n\n  uncompressed_offset = 0;\n  dict_start_offset = 0;\n  lc = 0;\n  lp = 0;\n  pb = 0;\n  lstate = 0;\n  while (off < compressed_size)\n    {\n      unsigned char control;\n\n      range = 0xffffffff;\n      code = 0;\n\n      control = compressed[off];\n      ++off;\n      if (unlikely (control == 0))\n\t{\n\t  /* End of packets.  */\n\t  break;\n\t}\n\n      if (control == 1 || control >= 0xe0)\n\t{\n\t  /* Reset dictionary to empty.  */\n\t  dict_start_offset = uncompressed_offset;\n\t}\n\n      if (control < 0x80)\n\t{\n\t  size_t chunk_size;\n\n\t  /* The only valid values here are 1 or 2.  A 1 means to\n\t     reset the dictionary (done above).  Then we see an\n\t     uncompressed chunk.  */\n\n\t  if (unlikely (control > 2))\n\t    {\n\t      elf_uncompress_failed ();\n\t      return 0;\n\t    }\n\n\t  /* An uncompressed chunk is a two byte size followed by\n\t     data.  */\n\n\t  if (unlikely (off + 2 > compressed_size))\n\t    {\n\t      elf_uncompress_failed ();\n\t      return 0;\n\t    }\n\n\t  chunk_size = compressed[off] << 8;\n\t  chunk_size += compressed[off + 1];\n\t  ++chunk_size;\n\n\t  off += 2;\n\n\t  if (unlikely (off + chunk_size > compressed_size))\n\t    {\n\t      elf_uncompress_failed ();\n\t      return 0;\n\t    }\n\t  if (unlikely (uncompressed_offset + chunk_size > uncompressed_size))\n\t    {\n\t      elf_uncompress_failed ();\n\t      return 0;\n\t    }\n\n\t  memcpy (uncompressed + uncompressed_offset, compressed + off,\n\t\t  chunk_size);\n\t  uncompressed_offset += chunk_size;\n\t  off += chunk_size;\n\t}\n      else\n\t{\n\t  size_t uncompressed_chunk_start;\n\t  size_t uncompressed_chunk_size;\n\t  size_t compressed_chunk_size;\n\t  size_t limit;\n\n\t  /* An LZMA chunk.  This starts with an uncompressed size and\n\t     a compressed size.  */\n\n\t  if (unlikely (off + 4 >= compressed_size))\n\t    {\n\t      elf_uncompress_failed ();\n\t      return 0;\n\t    }\n\n\t  uncompressed_chunk_start = uncompressed_offset;\n\n\t  uncompressed_chunk_size = (control & 0x1f) << 16;\n\t  uncompressed_chunk_size += compressed[off] << 8;\n\t  uncompressed_chunk_size += compressed[off + 1];\n\t  ++uncompressed_chunk_size;\n\n\t  compressed_chunk_size = compressed[off + 2] << 8;\n\t  compressed_chunk_size += compressed[off + 3];\n\t  ++compressed_chunk_size;\n\n\t  off += 4;\n\n\t  /* Bit 7 (0x80) is set.\n\t     Bits 6 and 5 (0x40 and 0x20) are as follows:\n\t     0: don't reset anything\n\t     1: reset state\n\t     2: reset state, read properties\n\t     3: reset state, read properties, reset dictionary (done above) */\n\n\t  if (control >= 0xc0)\n\t    {\n\t      unsigned char props;\n\n\t      /* Bit 6 is set, read properties.  */\n\n\t      if (unlikely (off >= compressed_size))\n\t\t{\n\t\t  elf_uncompress_failed ();\n\t\t  return 0;\n\t\t}\n\t      props = compressed[off];\n\t      ++off;\n\t      if (unlikely (props > (4 * 5 + 4) * 9 + 8))\n\t\t{\n\t\t  elf_uncompress_failed ();\n\t\t  return 0;\n\t\t}\n\t      pb = 0;\n\t      while (props >= 9 * 5)\n\t\t{\n\t\t  props -= 9 * 5;\n\t\t  ++pb;\n\t\t}\n\t      lp = 0;\n\t      while (props > 9)\n\t\t{\n\t\t  props -= 9;\n\t\t  ++lp;\n\t\t}\n\t      lc = props;\n\t      if (unlikely (lc + lp > 4))\n\t\t{\n\t\t  elf_uncompress_failed ();\n\t\t  return 0;\n\t\t}\n\t    }\n\n\t  if (control >= 0xa0)\n\t    {\n\t      size_t i;\n\n\t      /* Bit 5 or 6 is set, reset LZMA state.  */\n\n\t      lstate = 0;\n\t      memset (&dist, 0, sizeof dist);\n\t      for (i = 0; i < LZMA_PROB_TOTAL_COUNT; i++)\n\t\tprobs[i] = 1 << 10;\n\t      range = 0xffffffff;\n\t      code = 0;\n\t    }\n\n\t  /* Read the range code.  */\n\n\t  if (unlikely (off + 5 > compressed_size))\n\t    {\n\t      elf_uncompress_failed ();\n\t      return 0;\n\t    }\n\n\t  /* The byte at compressed[off] is ignored for some\n\t     reason.  */\n\n\t  code = ((compressed[off + 1] << 24)\n\t\t  + (compressed[off + 2] << 16)\n\t\t  + (compressed[off + 3] << 8)\n\t\t  + compressed[off + 4]);\n\t  off += 5;\n\n\t  /* This is the main LZMA decode loop.  */\n\n\t  limit = off + compressed_chunk_size;\n\t  *poffset = off;\n\t  while (*poffset < limit)\n\t    {\n\t      unsigned int pos_state;\n\n\t      if (unlikely (uncompressed_offset\n\t\t\t    == (uncompressed_chunk_start\n\t\t\t\t+ uncompressed_chunk_size)))\n\t\t{\n\t\t  /* We've decompressed all the expected bytes.  */\n\t\t  break;\n\t\t}\n\n\t      pos_state = ((uncompressed_offset - dict_start_offset)\n\t\t\t   & ((1 << pb) - 1));\n\n\t      if (elf_lzma_bit (compressed, compressed_size,\n\t\t\t\tprobs + LZMA_IS_MATCH (lstate, pos_state),\n\t\t\t\tpoffset, &range, &code))\n\t\t{\n\t\t  uint32_t len;\n\n\t\t  if (elf_lzma_bit (compressed, compressed_size,\n\t\t\t\t    probs + LZMA_IS_REP (lstate),\n\t\t\t\t    poffset, &range, &code))\n\t\t    {\n\t\t      int short_rep;\n\t\t      uint32_t next_dist;\n\n\t\t      /* Repeated match.  */\n\n\t\t      short_rep = 0;\n\t\t      if (elf_lzma_bit (compressed, compressed_size,\n\t\t\t\t\tprobs + LZMA_IS_REP0 (lstate),\n\t\t\t\t\tpoffset, &range, &code))\n\t\t\t{\n\t\t\t  if (elf_lzma_bit (compressed, compressed_size,\n\t\t\t\t\t    probs + LZMA_IS_REP1 (lstate),\n\t\t\t\t\t    poffset, &range, &code))\n\t\t\t    {\n\t\t\t      if (elf_lzma_bit (compressed, compressed_size,\n\t\t\t\t\t\tprobs + LZMA_IS_REP2 (lstate),\n\t\t\t\t\t\tpoffset, &range, &code))\n\t\t\t\t{\n\t\t\t\t  next_dist = dist[3];\n\t\t\t\t  dist[3] = dist[2];\n\t\t\t\t}\n\t\t\t      else\n\t\t\t\t{\n\t\t\t\t  next_dist = dist[2];\n\t\t\t\t}\n\t\t\t      dist[2] = dist[1];\n\t\t\t    }\n\t\t\t  else\n\t\t\t    {\n\t\t\t      next_dist = dist[1];\n\t\t\t    }\n\n\t\t\t  dist[1] = dist[0];\n\t\t\t  dist[0] = next_dist;\n\t\t\t}\n\t\t      else\n\t\t\t{\n\t\t\t  if (!elf_lzma_bit (compressed, compressed_size,\n\t\t\t\t\t    (probs\n\t\t\t\t\t     + LZMA_IS_REP0_LONG (lstate,\n\t\t\t\t\t\t\t\t  pos_state)),\n\t\t\t\t\t    poffset, &range, &code))\n\t\t\t    short_rep = 1;\n\t\t\t}\n\n\t\t      if (lstate < 7)\n\t\t\tlstate = short_rep ? 9 : 8;\n\t\t      else\n\t\t\tlstate = 11;\n\n\t\t      if (short_rep)\n\t\t\tlen = 1;\n\t\t      else\n\t\t\tlen = elf_lzma_len (compressed, compressed_size,\n\t\t\t\t\t    probs, 1, pos_state, poffset,\n\t\t\t\t\t    &range, &code);\n\t\t    }\n\t\t  else\n\t\t    {\n\t\t      uint32_t dist_state;\n\t\t      uint32_t dist_slot;\n\t\t      uint16_t *probs_dist;\n\n\t\t      /* Match.  */\n\n\t\t      if (lstate < 7)\n\t\t\tlstate = 7;\n\t\t      else\n\t\t\tlstate = 10;\n\t\t      dist[3] = dist[2];\n\t\t      dist[2] = dist[1];\n\t\t      dist[1] = dist[0];\n\t\t      len = elf_lzma_len (compressed, compressed_size,\n\t\t\t\t\t  probs, 0, pos_state, poffset,\n\t\t\t\t\t  &range, &code);\n\n\t\t      if (len < 4 + 2)\n\t\t\tdist_state = len - 2;\n\t\t      else\n\t\t\tdist_state = 3;\n\t\t      probs_dist = probs + LZMA_DIST_SLOT (dist_state, 0);\n\t\t      dist_slot = elf_lzma_integer (compressed,\n\t\t\t\t\t\t    compressed_size,\n\t\t\t\t\t\t    probs_dist, 6,\n\t\t\t\t\t\t    poffset, &range,\n\t\t\t\t\t\t    &code);\n\t\t      if (dist_slot < LZMA_DIST_MODEL_START)\n\t\t\tdist[0] = dist_slot;\n\t\t      else\n\t\t\t{\n\t\t\t  uint32_t limit;\n\n\t\t\t  limit = (dist_slot >> 1) - 1;\n\t\t\t  dist[0] = 2 + (dist_slot & 1);\n\t\t\t  if (dist_slot < LZMA_DIST_MODEL_END)\n\t\t\t    {\n\t\t\t      dist[0] <<= limit;\n\t\t\t      probs_dist = (probs\n\t\t\t\t\t    + LZMA_DIST_SPECIAL(dist[0]\n\t\t\t\t\t\t\t\t- dist_slot\n\t\t\t\t\t\t\t\t- 1));\n\t\t\t      dist[0] +=\n\t\t\t\telf_lzma_reverse_integer (compressed,\n\t\t\t\t\t\t\t  compressed_size,\n\t\t\t\t\t\t\t  probs_dist,\n\t\t\t\t\t\t\t  limit, poffset,\n\t\t\t\t\t\t\t  &range, &code);\n\t\t\t    }\n\t\t\t  else\n\t\t\t    {\n\t\t\t      uint32_t dist0;\n\t\t\t      uint32_t i;\n\n\t\t\t      dist0 = dist[0];\n\t\t\t      for (i = 0; i < limit - 4; i++)\n\t\t\t\t{\n\t\t\t\t  uint32_t mask;\n\n\t\t\t\t  elf_lzma_range_normalize (compressed,\n\t\t\t\t\t\t\t    compressed_size,\n\t\t\t\t\t\t\t    poffset,\n\t\t\t\t\t\t\t    &range, &code);\n\t\t\t\t  range >>= 1;\n\t\t\t\t  code -= range;\n\t\t\t\t  mask = -(code >> 31);\n\t\t\t\t  code += range & mask;\n\t\t\t\t  dist0 <<= 1;\n\t\t\t\t  dist0 += mask + 1;\n\t\t\t\t}\n\t\t\t      dist0 <<= 4;\n\t\t\t      probs_dist = probs + LZMA_DIST_ALIGN (0);\n\t\t\t      dist0 +=\n\t\t\t\telf_lzma_reverse_integer (compressed,\n\t\t\t\t\t\t\t  compressed_size,\n\t\t\t\t\t\t\t  probs_dist, 4,\n\t\t\t\t\t\t\t  poffset,\n\t\t\t\t\t\t\t  &range, &code);\n\t\t\t      dist[0] = dist0;\n\t\t\t    }\n\t\t\t}\n\t\t    }\n\n\t\t  if (unlikely (uncompressed_offset\n\t\t\t\t- dict_start_offset < dist[0] + 1))\n\t\t    {\n\t\t      elf_uncompress_failed ();\n\t\t      return 0;\n\t\t    }\n\t\t  if (unlikely (uncompressed_offset + len > uncompressed_size))\n\t\t    {\n\t\t      elf_uncompress_failed ();\n\t\t      return 0;\n\t\t    }\n\n\t\t  if (dist[0] == 0)\n\t\t    {\n\t\t      /* A common case, meaning repeat the last\n\t\t\t character LEN times.  */\n\t\t      memset (uncompressed + uncompressed_offset,\n\t\t\t      uncompressed[uncompressed_offset - 1],\n\t\t\t      len);\n\t\t      uncompressed_offset += len;\n\t\t    }\n\t\t  else if (dist[0] + 1 >= len)\n\t\t    {\n\t\t      memcpy (uncompressed + uncompressed_offset,\n\t\t\t      uncompressed + uncompressed_offset - dist[0] - 1,\n\t\t\t      len);\n\t\t      uncompressed_offset += len;\n\t\t    }\n\t\t  else\n\t\t    {\n\t\t      while (len > 0)\n\t\t\t{\n\t\t\t  uint32_t copy;\n\n\t\t\t  copy = len < dist[0] + 1 ? len : dist[0] + 1;\n\t\t\t  memcpy (uncompressed + uncompressed_offset,\n\t\t\t\t  (uncompressed + uncompressed_offset\n\t\t\t\t   - dist[0] - 1),\n\t\t\t\t  copy);\n\t\t\t  len -= copy;\n\t\t\t  uncompressed_offset += copy;\n\t\t\t}\n\t\t    }\n\t\t}\n\t      else\n\t\t{\n\t\t  unsigned char prev;\n\t\t  unsigned char low;\n\t\t  size_t high;\n\t\t  uint16_t *lit_probs;\n\t\t  unsigned int sym;\n\n\t\t  /* Literal value.  */\n\n\t\t  if (uncompressed_offset > 0)\n\t\t    prev = uncompressed[uncompressed_offset - 1];\n\t\t  else\n\t\t    prev = 0;\n\t\t  low = prev >> (8 - lc);\n\t\t  high = (((uncompressed_offset - dict_start_offset)\n\t\t\t   & ((1 << lp) - 1))\n\t\t\t  << lc);\n\t\t  lit_probs = probs + LZMA_LITERAL (low + high, 0);\n\t\t  if (lstate < 7)\n\t\t    sym = elf_lzma_integer (compressed, compressed_size,\n\t\t\t\t\t    lit_probs, 8, poffset, &range,\n\t\t\t\t\t    &code);\n\t\t  else\n\t\t    {\n\t\t      unsigned int match;\n\t\t      unsigned int bit;\n\t\t      unsigned int match_bit;\n\t\t      unsigned int idx;\n\n\t\t      sym = 1;\n\t\t      if (uncompressed_offset >= dist[0] + 1)\n\t\t\tmatch = uncompressed[uncompressed_offset - dist[0] - 1];\n\t\t      else\n\t\t\tmatch = 0;\n\t\t      match <<= 1;\n\t\t      bit = 0x100;\n\t\t      do\n\t\t\t{\n\t\t\t  match_bit = match & bit;\n\t\t\t  match <<= 1;\n\t\t\t  idx = bit + match_bit + sym;\n\t\t\t  sym <<= 1;\n\t\t\t  if (elf_lzma_bit (compressed, compressed_size,\n\t\t\t\t\t    lit_probs + idx, poffset,\n\t\t\t\t\t    &range, &code))\n\t\t\t    {\n\t\t\t      ++sym;\n\t\t\t      bit &= match_bit;\n\t\t\t    }\n\t\t\t  else\n\t\t\t    {\n\t\t\t      bit &= ~ match_bit;\n\t\t\t    }\n\t\t\t}\n\t\t      while (sym < 0x100);\n\t\t    }\n\n\t\t  if (unlikely (uncompressed_offset >= uncompressed_size))\n\t\t    {\n\t\t      elf_uncompress_failed ();\n\t\t      return 0;\n\t\t    }\n\n\t\t  uncompressed[uncompressed_offset] = (unsigned char) sym;\n\t\t  ++uncompressed_offset;\n\t\t  if (lstate <= 3)\n\t\t    lstate = 0;\n\t\t  else if (lstate <= 9)\n\t\t    lstate -= 3;\n\t\t  else\n\t\t    lstate -= 6;\n\t\t}\n\t    }\n\n\t  elf_lzma_range_normalize (compressed, compressed_size, poffset,\n\t\t\t\t    &range, &code);\n\n\t  off = *poffset;\n\t}\n    }\n\n  /* We have reached the end of the block.  Pad to four byte\n     boundary.  */\n  off = (off + 3) &~ (size_t) 3;\n  if (unlikely (off > compressed_size))\n    {\n      elf_uncompress_failed ();\n      return 0;\n    }\n\n  switch (check)\n    {\n    case 0:\n      /* No check.  */\n      break;\n\n    case 1:\n      /* CRC32 */\n      if (unlikely (off + 4 > compressed_size))\n\t{\n\t  elf_uncompress_failed ();\n\t  return 0;\n\t}\n      computed_crc = elf_crc32 (0, uncompressed, uncompressed_offset);\n      stream_crc = ((uint32_t)compressed[off]\n\t\t    | ((uint32_t)compressed[off + 1] << 8)\n\t\t    | ((uint32_t)compressed[off + 2] << 16)\n\t\t    | ((uint32_t)compressed[off + 3] << 24));\n      if (computed_crc != stream_crc)\n\t{\n\t  elf_uncompress_failed ();\n\t  return 0;\n\t}\n      off += 4;\n      break;\n\n    case 4:\n      /* CRC64.  We don't bother computing a CRC64 checksum.  */\n      if (unlikely (off + 8 > compressed_size))\n\t{\n\t  elf_uncompress_failed ();\n\t  return 0;\n\t}\n      off += 8;\n      break;\n\n    case 10:\n      /* SHA.  We don't bother computing a SHA checksum.  */\n      if (unlikely (off + 32 > compressed_size))\n\t{\n\t  elf_uncompress_failed ();\n\t  return 0;\n\t}\n      off += 32;\n      break;\n\n    default:\n      elf_uncompress_failed ();\n      return 0;\n    }\n\n  *poffset = off;\n\n  return 1;\n}\n\n/* Uncompress LZMA data found in a minidebug file.  The minidebug\n   format is described at\n   https://sourceware.org/gdb/current/onlinedocs/gdb/MiniDebugInfo.html.\n   Returns 0 on error, 1 on successful decompression.  For this\n   function we return 0 on failure to decompress, as the calling code\n   will carry on in that case.  */\n\nstatic int\nelf_uncompress_lzma (struct backtrace_state *state,\n\t\t     const unsigned char *compressed, size_t compressed_size,\n\t\t     backtrace_error_callback error_callback, void *data,\n\t\t     unsigned char **uncompressed, size_t *uncompressed_size)\n{\n  size_t header_size;\n  size_t footer_size;\n  unsigned char check;\n  uint32_t computed_crc;\n  uint32_t stream_crc;\n  size_t offset;\n  size_t index_size;\n  size_t footer_offset;\n  size_t index_offset;\n  uint64_t index_compressed_size;\n  uint64_t index_uncompressed_size;\n  unsigned char *mem;\n  uint16_t *probs;\n  size_t compressed_block_size;\n\n  /* The format starts with a stream header and ends with a stream\n     footer.  */\n  header_size = 12;\n  footer_size = 12;\n  if (unlikely (compressed_size < header_size + footer_size))\n    {\n      elf_uncompress_failed ();\n      return 0;\n    }\n\n  /* The stream header starts with a magic string.  */\n  if (unlikely (memcmp (compressed, \"\\375\" \"7zXZ\\0\", 6) != 0))\n    {\n      elf_uncompress_failed ();\n      return 0;\n    }\n\n  /* Next come stream flags.  The first byte is zero, the second byte\n     is the check.  */\n  if (unlikely (compressed[6] != 0))\n    {\n      elf_uncompress_failed ();\n      return 0;\n    }\n  check = compressed[7];\n  if (unlikely ((check & 0xf8) != 0))\n    {\n      elf_uncompress_failed ();\n      return 0;\n    }\n\n  /* Next comes a CRC of the stream flags.  */\n  computed_crc = elf_crc32 (0, compressed + 6, 2);\n  stream_crc = ((uint32_t)compressed[8]\n\t\t| ((uint32_t)compressed[9] << 8)\n\t\t| ((uint32_t)compressed[10] << 16)\n\t\t| ((uint32_t)compressed[11] << 24));\n  if (unlikely (computed_crc != stream_crc))\n    {\n      elf_uncompress_failed ();\n      return 0;\n    }\n\n  /* Now that we've parsed the header, parse the footer, so that we\n     can get the uncompressed size.  */\n\n  /* The footer ends with two magic bytes.  */\n\n  offset = compressed_size;\n  if (unlikely (memcmp (compressed + offset - 2, \"YZ\", 2) != 0))\n    {\n      elf_uncompress_failed ();\n      return 0;\n    }\n  offset -= 2;\n\n  /* Before that are the stream flags, which should be the same as the\n     flags in the header.  */\n  if (unlikely (compressed[offset - 2] != 0\n\t\t|| compressed[offset - 1] != check))\n    {\n      elf_uncompress_failed ();\n      return 0;\n    }\n  offset -= 2;\n\n  /* Before that is the size of the index field, which precedes the\n     footer.  */\n  index_size = (compressed[offset - 4]\n\t\t| (compressed[offset - 3] << 8)\n\t\t| (compressed[offset - 2] << 16)\n\t\t| (compressed[offset - 1] << 24));\n  index_size = (index_size + 1) * 4;\n  offset -= 4;\n\n  /* Before that is a footer CRC.  */\n  computed_crc = elf_crc32 (0, compressed + offset, 6);\n  stream_crc = ((uint32_t)compressed[offset - 4]\n\t\t| ((uint32_t)compressed[offset - 3] << 8)\n\t\t| ((uint32_t)compressed[offset - 2] << 16)\n\t\t| ((uint32_t)compressed[offset - 1] << 24));\n  if (unlikely (computed_crc != stream_crc))\n    {\n      elf_uncompress_failed ();\n      return 0;\n    }\n  offset -= 4;\n\n  /* The index comes just before the footer.  */\n  if (unlikely (offset < index_size + header_size))\n    {\n      elf_uncompress_failed ();\n      return 0;\n    }\n\n  footer_offset = offset;\n  offset -= index_size;\n  index_offset = offset;\n\n  /* The index starts with a zero byte.  */\n  if (unlikely (compressed[offset] != 0))\n    {\n      elf_uncompress_failed ();\n      return 0;\n    }\n  ++offset;\n\n  /* Next is the number of blocks.  We expect zero blocks for an empty\n     stream, and otherwise a single block.  */\n  if (unlikely (compressed[offset] == 0))\n    {\n      *uncompressed = NULL;\n      *uncompressed_size = 0;\n      return 1;\n    }\n  if (unlikely (compressed[offset] != 1))\n    {\n      elf_uncompress_failed ();\n      return 0;\n    }\n  ++offset;\n\n  /* Next is the compressed size and the uncompressed size.  */\n  if (!elf_lzma_varint (compressed, compressed_size, &offset,\n\t\t\t&index_compressed_size))\n    return 0;\n  if (!elf_lzma_varint (compressed, compressed_size, &offset,\n\t\t\t&index_uncompressed_size))\n    return 0;\n\n  /* Pad to a four byte boundary.  */\n  offset = (offset + 3) &~ (size_t) 3;\n\n  /* Next is a CRC of the index.  */\n  computed_crc = elf_crc32 (0, compressed + index_offset,\n\t\t\t    offset - index_offset);\n  stream_crc = ((uint32_t)compressed[offset]\n\t\t| ((uint32_t)compressed[offset + 1] << 8)\n\t\t| ((uint32_t)compressed[offset + 2] << 16)\n\t\t| ((uint32_t)compressed[offset + 3] << 24));\n  if (unlikely (computed_crc != stream_crc))\n    {\n      elf_uncompress_failed ();\n      return 0;\n    }\n  offset += 4;\n\n  /* We should now be back at the footer.  */\n  if (unlikely (offset != footer_offset))\n    {\n      elf_uncompress_failed ();\n      return 0;\n    }\n\n  /* Allocate space to hold the uncompressed data.  If we succeed in\n     uncompressing the LZMA data, we never free this memory.  */\n  mem = (unsigned char *) backtrace_alloc (state, index_uncompressed_size,\n\t\t\t\t\t   error_callback, data);\n  if (unlikely (mem == NULL))\n    return 0;\n  *uncompressed = mem;\n  *uncompressed_size = index_uncompressed_size;\n\n  /* Allocate space for probabilities.  */\n  probs = ((uint16_t *)\n\t   backtrace_alloc (state,\n\t\t\t    LZMA_PROB_TOTAL_COUNT * sizeof (uint16_t),\n\t\t\t    error_callback, data));\n  if (unlikely (probs == NULL))\n    {\n      backtrace_free (state, mem, index_uncompressed_size, error_callback,\n\t\t      data);\n      return 0;\n    }\n\n  /* Uncompress the block, which follows the header.  */\n  offset = 12;\n  if (!elf_uncompress_lzma_block (compressed, compressed_size, check, probs,\n\t\t\t\t  mem, index_uncompressed_size, &offset))\n    {\n      backtrace_free (state, mem, index_uncompressed_size, error_callback,\n\t\t      data);\n      return 0;\n    }\n\n  compressed_block_size = offset - 12;\n  if (unlikely (compressed_block_size\n\t\t!= ((index_compressed_size + 3) &~ (size_t) 3)))\n    {\n      elf_uncompress_failed ();\n      backtrace_free (state, mem, index_uncompressed_size, error_callback,\n\t\t      data);\n      return 0;\n    }\n\n  offset = (offset + 3) &~ (size_t) 3;\n  if (unlikely (offset != index_offset))\n    {\n      elf_uncompress_failed ();\n      backtrace_free (state, mem, index_uncompressed_size, error_callback,\n\t\t      data);\n      return 0;\n    }\n\n  return 1;\n}\n\n/* This function is a hook for testing the LZMA support.  It is only\n   used by tests.  */\n\nint\nbacktrace_uncompress_lzma (struct backtrace_state *state,\n\t\t\t   const unsigned char *compressed,\n\t\t\t   size_t compressed_size,\n\t\t\t   backtrace_error_callback error_callback,\n\t\t\t   void *data, unsigned char **uncompressed,\n\t\t\t   size_t *uncompressed_size)\n{\n  return elf_uncompress_lzma (state, compressed, compressed_size,\n\t\t\t      error_callback, data, uncompressed,\n\t\t\t      uncompressed_size);\n}\n\n/* Add the backtrace data for one ELF file.  Returns 1 on success,\n   0 on failure (in both cases descriptor is closed) or -1 if exe\n   is non-zero and the ELF file is ET_DYN, which tells the caller that\n   elf_add will need to be called on the descriptor again after\n   base_address is determined.  */\n\nstatic int\nelf_add (struct backtrace_state *state, const char *filename, int descriptor,\n\t const unsigned char *memory, size_t memory_size,\n\t struct libbacktrace_base_address base_address,\n\t struct elf_ppc64_opd_data *caller_opd,\n\t backtrace_error_callback error_callback, void *data,\n\t fileline *fileline_fn, int *found_sym, int *found_dwarf,\n\t struct dwarf_data **fileline_entry, int exe, int debuginfo,\n\t const char *with_buildid_data, uint32_t with_buildid_size)\n{\n  struct elf_view ehdr_view;\n  b_elf_ehdr ehdr;\n  off_t shoff;\n  unsigned int shnum;\n  unsigned int shstrndx;\n  struct elf_view shdrs_view;\n  int shdrs_view_valid;\n  const b_elf_shdr *shdrs;\n  const b_elf_shdr *shstrhdr;\n  size_t shstr_size;\n  off_t shstr_off;\n  struct elf_view names_view;\n  int names_view_valid;\n  const char *names;\n  unsigned int symtab_shndx;\n  unsigned int dynsym_shndx;\n  unsigned int i;\n  struct debug_section_info sections[DEBUG_MAX];\n  struct debug_section_info zsections[DEBUG_MAX];\n  struct elf_view symtab_view;\n  int symtab_view_valid;\n  struct elf_view strtab_view;\n  int strtab_view_valid;\n  struct elf_view buildid_view;\n  int buildid_view_valid;\n  const char *buildid_data;\n  uint32_t buildid_size;\n  struct elf_view debuglink_view;\n  int debuglink_view_valid;\n  const char *debuglink_name;\n  uint32_t debuglink_crc;\n  struct elf_view debugaltlink_view;\n  int debugaltlink_view_valid;\n  const char *debugaltlink_name;\n  const char *debugaltlink_buildid_data;\n  uint32_t debugaltlink_buildid_size;\n  struct elf_view gnu_debugdata_view;\n  int gnu_debugdata_view_valid;\n  size_t gnu_debugdata_size;\n  unsigned char *gnu_debugdata_uncompressed;\n  size_t gnu_debugdata_uncompressed_size;\n  off_t min_offset;\n  off_t max_offset;\n  off_t debug_size;\n  struct elf_view debug_view;\n  int debug_view_valid;\n  unsigned int using_debug_view;\n  uint16_t *zdebug_table;\n  struct elf_view split_debug_view[DEBUG_MAX];\n  unsigned char split_debug_view_valid[DEBUG_MAX];\n  struct elf_ppc64_opd_data opd_data, *opd;\n  int opd_view_valid;\n  struct dwarf_sections dwarf_sections;\n  struct dwarf_data *fileline_altlink = NULL;\n\n  if (!debuginfo)\n    {\n      *found_sym = 0;\n      *found_dwarf = 0;\n    }\n\n  shdrs_view_valid = 0;\n  names_view_valid = 0;\n  symtab_view_valid = 0;\n  strtab_view_valid = 0;\n  buildid_view_valid = 0;\n  buildid_data = NULL;\n  buildid_size = 0;\n  debuglink_view_valid = 0;\n  debuglink_name = NULL;\n  debuglink_crc = 0;\n  debugaltlink_view_valid = 0;\n  debugaltlink_name = NULL;\n  debugaltlink_buildid_data = NULL;\n  debugaltlink_buildid_size = 0;\n  gnu_debugdata_view_valid = 0;\n  gnu_debugdata_size = 0;\n  debug_view_valid = 0;\n  memset (&split_debug_view_valid[0], 0, sizeof split_debug_view_valid);\n  opd = NULL;\n  opd_view_valid = 0;\n\n  if (!elf_get_view (state, descriptor, memory, memory_size, 0, sizeof ehdr,\n\t\t     error_callback, data, &ehdr_view))\n    goto fail;\n\n  memcpy (&ehdr, ehdr_view.view.data, sizeof ehdr);\n\n  elf_release_view (state, &ehdr_view, error_callback, data);\n\n  if (ehdr.e_ident[EI_MAG0] != ELFMAG0\n      || ehdr.e_ident[EI_MAG1] != ELFMAG1\n      || ehdr.e_ident[EI_MAG2] != ELFMAG2\n      || ehdr.e_ident[EI_MAG3] != ELFMAG3)\n    {\n      error_callback (data, \"executable file is not ELF\", 0);\n      goto fail;\n    }\n  if (ehdr.e_ident[EI_VERSION] != EV_CURRENT)\n    {\n      error_callback (data, \"executable file is unrecognized ELF version\", 0);\n      goto fail;\n    }\n\n#if BACKTRACE_ELF_SIZE == 32\n#define BACKTRACE_ELFCLASS ELFCLASS32\n#else\n#define BACKTRACE_ELFCLASS ELFCLASS64\n#endif\n\n  if (ehdr.e_ident[EI_CLASS] != BACKTRACE_ELFCLASS)\n    {\n      error_callback (data, \"executable file is unexpected ELF class\", 0);\n      goto fail;\n    }\n\n  if (ehdr.e_ident[EI_DATA] != ELFDATA2LSB\n      && ehdr.e_ident[EI_DATA] != ELFDATA2MSB)\n    {\n      error_callback (data, \"executable file has unknown endianness\", 0);\n      goto fail;\n    }\n\n  /* If the executable is ET_DYN, it is either a PIE, or we are running\n     directly a shared library with .interp.  We need to wait for\n     dl_iterate_phdr in that case to determine the actual base_address.  */\n  if (exe && ehdr.e_type == ET_DYN)\n    return -1;\n\n  shoff = ehdr.e_shoff;\n  shnum = ehdr.e_shnum;\n  shstrndx = ehdr.e_shstrndx;\n\n  if ((shnum == 0 || shstrndx == SHN_XINDEX)\n      && shoff != 0)\n    {\n      struct elf_view shdr_view;\n      const b_elf_shdr *shdr;\n\n      if (!elf_get_view (state, descriptor, memory, memory_size, shoff,\n\t\t\t sizeof shdr, error_callback, data, &shdr_view))\n\tgoto fail;\n\n      shdr = (const b_elf_shdr *) shdr_view.view.data;\n\n      if (shnum == 0)\n\tshnum = shdr->sh_size;\n\n      if (shstrndx == SHN_XINDEX)\n\t{\n\t  shstrndx = shdr->sh_link;\n\n\t  /* Versions of the GNU binutils between 2.12 and 2.18 did\n\t     not handle objects with more than SHN_LORESERVE sections\n\t     correctly.  All large section indexes were offset by\n\t     0x100.  There is more information at\n\t     http://sourceware.org/bugzilla/show_bug.cgi?id-5900 .\n\t     Fortunately these object files are easy to detect, as the\n\t     GNU binutils always put the section header string table\n\t     near the end of the list of sections.  Thus if the\n\t     section header string table index is larger than the\n\t     number of sections, then we know we have to subtract\n\t     0x100 to get the real section index.  */\n\t  if (shstrndx >= shnum && shstrndx >= SHN_LORESERVE + 0x100)\n\t    shstrndx -= 0x100;\n\t}\n\n      elf_release_view (state, &shdr_view, error_callback, data);\n    }\n\n  if (shnum == 0 || shstrndx == 0)\n    goto fail;\n\n  /* To translate PC to file/line when using DWARF, we need to find\n     the .debug_info and .debug_line sections.  */\n\n  /* Read the section headers, skipping the first one.  */\n\n  if (!elf_get_view (state, descriptor, memory, memory_size,\n\t\t     shoff + sizeof (b_elf_shdr),\n\t\t     (shnum - 1) * sizeof (b_elf_shdr),\n\t\t     error_callback, data, &shdrs_view))\n    goto fail;\n  shdrs_view_valid = 1;\n  shdrs = (const b_elf_shdr *) shdrs_view.view.data;\n\n  /* Read the section names.  */\n\n  shstrhdr = &shdrs[shstrndx - 1];\n  shstr_size = shstrhdr->sh_size;\n  shstr_off = shstrhdr->sh_offset;\n\n  if (!elf_get_view (state, descriptor, memory, memory_size, shstr_off,\n\t\t     shstrhdr->sh_size, error_callback, data, &names_view))\n    goto fail;\n  names_view_valid = 1;\n  names = (const char *) names_view.view.data;\n\n  symtab_shndx = 0;\n  dynsym_shndx = 0;\n\n  memset (sections, 0, sizeof sections);\n  memset (zsections, 0, sizeof zsections);\n\n  /* Look for the symbol table.  */\n  for (i = 1; i < shnum; ++i)\n    {\n      const b_elf_shdr *shdr;\n      unsigned int sh_name;\n      const char *name;\n      int j;\n\n      shdr = &shdrs[i - 1];\n\n      if (shdr->sh_type == SHT_SYMTAB)\n\tsymtab_shndx = i;\n      else if (shdr->sh_type == SHT_DYNSYM)\n\tdynsym_shndx = i;\n\n      sh_name = shdr->sh_name;\n      if (sh_name >= shstr_size)\n\t{\n\t  error_callback (data, \"ELF section name out of range\", 0);\n\t  goto fail;\n\t}\n\n      name = names + sh_name;\n\n      for (j = 0; j < (int) DEBUG_MAX; ++j)\n\t{\n\t  if (strcmp (name, dwarf_section_names[j]) == 0)\n\t    {\n\t      sections[j].offset = shdr->sh_offset;\n\t      sections[j].size = shdr->sh_size;\n\t      sections[j].compressed = (shdr->sh_flags & SHF_COMPRESSED) != 0;\n\t      break;\n\t    }\n\t}\n\n      if (name[0] == '.' && name[1] == 'z')\n\t{\n\t  for (j = 0; j < (int) DEBUG_MAX; ++j)\n\t    {\n\t      if (strcmp (name + 2, dwarf_section_names[j] + 1) == 0)\n\t\t{\n\t\t  zsections[j].offset = shdr->sh_offset;\n\t\t  zsections[j].size = shdr->sh_size;\n\t\t  break;\n\t\t}\n\t    }\n\t}\n\n      /* Read the build ID if present.  This could check for any\n\t SHT_NOTE section with the right note name and type, but gdb\n\t looks for a specific section name.  */\n      if ((!debuginfo || with_buildid_data != NULL)\n\t  && !buildid_view_valid\n\t  && strcmp (name, \".note.gnu.build-id\") == 0)\n\t{\n\t  const b_elf_note *note;\n\n\t  if (!elf_get_view (state, descriptor, memory, memory_size,\n\t\t\t     shdr->sh_offset, shdr->sh_size, error_callback,\n\t\t\t     data, &buildid_view))\n\t    goto fail;\n\n\t  buildid_view_valid = 1;\n\t  note = (const b_elf_note *) buildid_view.view.data;\n\t  if (note->type == NT_GNU_BUILD_ID\n\t      && note->namesz == 4\n\t      && strncmp (note->name, \"GNU\", 4) == 0\n\t      && shdr->sh_size <= 12 + ((note->namesz + 3) & ~ 3) + note->descsz)\n\t    {\n\t      buildid_data = &note->name[0] + ((note->namesz + 3) & ~ 3);\n\t      buildid_size = note->descsz;\n\t    }\n\n\t  if (with_buildid_size != 0)\n\t    {\n\t      if (buildid_size != with_buildid_size)\n\t\tgoto fail;\n\n\t      if (memcmp (buildid_data, with_buildid_data, buildid_size) != 0)\n\t\tgoto fail;\n\t    }\n\t}\n\n      /* Read the debuglink file if present.  */\n      if (!debuginfo\n\t  && !debuglink_view_valid\n\t  && strcmp (name, \".gnu_debuglink\") == 0)\n\t{\n\t  const char *debuglink_data;\n\t  size_t crc_offset;\n\n\t  if (!elf_get_view (state, descriptor, memory, memory_size,\n\t\t\t     shdr->sh_offset, shdr->sh_size, error_callback,\n\t\t\t     data, &debuglink_view))\n\t    goto fail;\n\n\t  debuglink_view_valid = 1;\n\t  debuglink_data = (const char *) debuglink_view.view.data;\n\t  crc_offset = strnlen (debuglink_data, shdr->sh_size);\n\t  crc_offset = (crc_offset + 3) & ~3;\n\t  if (crc_offset + 4 <= shdr->sh_size)\n\t    {\n\t      debuglink_name = debuglink_data;\n\t      debuglink_crc = *(const uint32_t*)(debuglink_data + crc_offset);\n\t    }\n\t}\n\n      if (!debugaltlink_view_valid\n\t  && strcmp (name, \".gnu_debugaltlink\") == 0)\n\t{\n\t  const char *debugaltlink_data;\n\t  size_t debugaltlink_name_len;\n\n\t  if (!elf_get_view (state, descriptor, memory, memory_size,\n\t\t\t     shdr->sh_offset, shdr->sh_size, error_callback,\n\t\t\t     data, &debugaltlink_view))\n\t    goto fail;\n\n\t  debugaltlink_view_valid = 1;\n\t  debugaltlink_data = (const char *) debugaltlink_view.view.data;\n\t  debugaltlink_name = debugaltlink_data;\n\t  debugaltlink_name_len = strnlen (debugaltlink_data, shdr->sh_size);\n\t  if (debugaltlink_name_len < shdr->sh_size)\n\t    {\n\t      /* Include terminating zero.  */\n\t      debugaltlink_name_len += 1;\n\n\t      debugaltlink_buildid_data\n\t\t= debugaltlink_data + debugaltlink_name_len;\n\t      debugaltlink_buildid_size = shdr->sh_size - debugaltlink_name_len;\n\t    }\n\t}\n\n      if (!debuginfo\n\t  && !gnu_debugdata_view_valid\n\t  && strcmp (name, \".gnu_debugdata\") == 0)\n\t{\n\t  if (!elf_get_view (state, descriptor, memory, memory_size,\n\t\t\t     shdr->sh_offset, shdr->sh_size, error_callback,\n\t\t\t     data, &gnu_debugdata_view))\n\t    goto fail;\n\n\t  gnu_debugdata_size = shdr->sh_size;\n\t  gnu_debugdata_view_valid = 1;\n\t}\n\n      /* Read the .opd section on PowerPC64 ELFv1.  */\n      if (ehdr.e_machine == EM_PPC64\n\t  && (ehdr.e_flags & EF_PPC64_ABI) < 2\n\t  && shdr->sh_type == SHT_PROGBITS\n\t  && strcmp (name, \".opd\") == 0)\n\t{\n\t  if (!elf_get_view (state, descriptor, memory, memory_size,\n\t\t\t     shdr->sh_offset, shdr->sh_size, error_callback,\n\t\t\t     data, &opd_data.view))\n\t    goto fail;\n\n\t  opd = &opd_data;\n\t  opd->addr = shdr->sh_addr;\n\t  opd->data = (const char *) opd_data.view.view.data;\n\t  opd->size = shdr->sh_size;\n\t  opd_view_valid = 1;\n\t}\n    }\n\n  /* A debuginfo file may not have a useful .opd section, but we can use the\n     one from the original executable.  */\n  if (opd == NULL)\n    opd = caller_opd;\n\n  if (symtab_shndx == 0)\n    symtab_shndx = dynsym_shndx;\n  if (symtab_shndx != 0)\n    {\n      const b_elf_shdr *symtab_shdr;\n      unsigned int strtab_shndx;\n      const b_elf_shdr *strtab_shdr;\n      struct elf_syminfo_data *sdata;\n\n      symtab_shdr = &shdrs[symtab_shndx - 1];\n      strtab_shndx = symtab_shdr->sh_link;\n      if (strtab_shndx >= shnum)\n\t{\n\t  error_callback (data,\n\t\t\t  \"ELF symbol table strtab link out of range\", 0);\n\t  goto fail;\n\t}\n      strtab_shdr = &shdrs[strtab_shndx - 1];\n\n      if (!elf_get_view (state, descriptor, memory, memory_size,\n\t\t\t symtab_shdr->sh_offset, symtab_shdr->sh_size,\n\t\t\t error_callback, data, &symtab_view))\n\tgoto fail;\n      symtab_view_valid = 1;\n\n      if (!elf_get_view (state, descriptor, memory, memory_size,\n\t\t\t strtab_shdr->sh_offset, strtab_shdr->sh_size,\n\t\t\t error_callback, data, &strtab_view))\n\tgoto fail;\n      strtab_view_valid = 1;\n\n      sdata = ((struct elf_syminfo_data *)\n\t       backtrace_alloc (state, sizeof *sdata, error_callback, data));\n      if (sdata == NULL)\n\tgoto fail;\n\n      if (!elf_initialize_syminfo (state, base_address,\n\t\t\t\t   (const unsigned char*)symtab_view.view.data, symtab_shdr->sh_size,\n\t\t\t\t   (const unsigned char*)strtab_view.view.data, strtab_shdr->sh_size,\n\t\t\t\t   error_callback, data, sdata, opd))\n\t{\n\t  backtrace_free (state, sdata, sizeof *sdata, error_callback, data);\n\t  goto fail;\n\t}\n\n      /* We no longer need the symbol table, but we hold on to the\n\t string table permanently.  */\n      elf_release_view (state, &symtab_view, error_callback, data);\n      symtab_view_valid = 0;\n      strtab_view_valid = 0;\n\n      *found_sym = 1;\n\n      elf_add_syminfo_data (state, sdata);\n    }\n\n  elf_release_view (state, &shdrs_view, error_callback, data);\n  shdrs_view_valid = 0;\n  elf_release_view (state, &names_view, error_callback, data);\n  names_view_valid = 0;\n\n  /* If the debug info is in a separate file, read that one instead.  */\n\n  if (buildid_data != NULL)\n    {\n      int d;\n\n      d = elf_open_debugfile_by_buildid (state, buildid_data, buildid_size,\n\t\t\t\t\t filename, error_callback, data);\n      if (d >= 0)\n\t{\n\t  int ret;\n\n\t  elf_release_view (state, &buildid_view, error_callback, data);\n\t  if (debuglink_view_valid)\n\t    elf_release_view (state, &debuglink_view, error_callback, data);\n\t  if (debugaltlink_view_valid)\n\t    elf_release_view (state, &debugaltlink_view, error_callback, data);\n\t  ret = elf_add (state, \"\", d, NULL, 0, base_address, opd,\n\t\t\t error_callback, data, fileline_fn, found_sym,\n\t\t\t found_dwarf, NULL, 0, 1, NULL, 0);\n\t  if (ret < 0)\n\t    backtrace_close (d, error_callback, data);\n\t  else if (descriptor >= 0)\n\t    backtrace_close (descriptor, error_callback, data);\n\t  return ret;\n\t}\n    }\n\n  if (buildid_view_valid)\n    {\n      elf_release_view (state, &buildid_view, error_callback, data);\n      buildid_view_valid = 0;\n    }\n\n  if (debuglink_name != NULL)\n    {\n      int d;\n\n      d = elf_open_debugfile_by_debuglink (state, filename, debuglink_name,\n\t\t\t\t\t   debuglink_crc, error_callback,\n\t\t\t\t\t   data);\n      if (d >= 0)\n\t{\n\t  int ret;\n\n\t  elf_release_view (state, &debuglink_view, error_callback, data);\n\t  if (debugaltlink_view_valid)\n\t    elf_release_view (state, &debugaltlink_view, error_callback, data);\n\t  ret = elf_add (state, \"\", d, NULL, 0, base_address, opd,\n\t\t\t error_callback, data, fileline_fn, found_sym,\n\t\t\t found_dwarf, NULL, 0, 1, NULL, 0);\n\t  if (ret < 0)\n\t    backtrace_close (d, error_callback, data);\n\t  else if (descriptor >= 0)\n\t    backtrace_close(descriptor, error_callback, data);\n\t  return ret;\n\t}\n    }\n\n  if (debuglink_view_valid)\n    {\n      elf_release_view (state, &debuglink_view, error_callback, data);\n      debuglink_view_valid = 0;\n    }\n\n  if (debugaltlink_name != NULL)\n    {\n      int d;\n\n      d = elf_open_debugfile_by_debuglink (state, filename, debugaltlink_name,\n\t\t\t\t\t   0, error_callback, data);\n      if (d >= 0)\n\t{\n\t  int ret;\n\n\t  ret = elf_add (state, filename, d, NULL, 0, base_address, opd,\n\t\t\t error_callback, data, fileline_fn, found_sym,\n\t\t\t found_dwarf, &fileline_altlink, 0, 1,\n\t\t\t debugaltlink_buildid_data, debugaltlink_buildid_size);\n\t  elf_release_view (state, &debugaltlink_view, error_callback, data);\n\t  debugaltlink_view_valid = 0;\n\t  if (ret < 0)\n\t    {\n\t      backtrace_close (d, error_callback, data);\n\t      return ret;\n\t    }\n\t}\n    }\n\n  if (debugaltlink_view_valid)\n    {\n      elf_release_view (state, &debugaltlink_view, error_callback, data);\n      debugaltlink_view_valid = 0;\n    }\n\n  if (gnu_debugdata_view_valid)\n    {\n      int ret;\n\n      ret = elf_uncompress_lzma (state,\n\t\t\t\t ((const unsigned char *)\n\t\t\t\t  gnu_debugdata_view.view.data),\n\t\t\t\t gnu_debugdata_size, error_callback, data,\n\t\t\t\t &gnu_debugdata_uncompressed,\n\t\t\t\t &gnu_debugdata_uncompressed_size);\n\n      elf_release_view (state, &gnu_debugdata_view, error_callback, data);\n      gnu_debugdata_view_valid = 0;\n\n      if (ret)\n\t{\n\t  ret = elf_add (state, filename, -1, gnu_debugdata_uncompressed,\n\t\t\t gnu_debugdata_uncompressed_size, base_address, opd,\n\t\t\t error_callback, data, fileline_fn, found_sym,\n\t\t\t found_dwarf, NULL, 0, 0, NULL, 0);\n\t  if (ret >= 0 && descriptor >= 0)\n\t    backtrace_close(descriptor, error_callback, data);\n\t  return ret;\n\t}\n    }\n\n  if (opd_view_valid)\n    {\n      elf_release_view (state, &opd->view, error_callback, data);\n      opd_view_valid = 0;\n      opd = NULL;\n    }\n\n  /* Read all the debug sections in a single view, since they are\n     probably adjacent in the file.  If any of sections are\n     uncompressed, we never release this view.  */\n\n  min_offset = 0;\n  max_offset = 0;\n  debug_size = 0;\n  for (i = 0; i < (int) DEBUG_MAX; ++i)\n    {\n      off_t end;\n\n      if (sections[i].size != 0)\n\t{\n\t  if (min_offset == 0 || sections[i].offset < min_offset)\n\t    min_offset = sections[i].offset;\n\t  end = sections[i].offset + sections[i].size;\n\t  if (end > max_offset)\n\t    max_offset = end;\n\t  debug_size += sections[i].size;\n\t}\n      if (zsections[i].size != 0)\n\t{\n\t  if (min_offset == 0 || zsections[i].offset < min_offset)\n\t    min_offset = zsections[i].offset;\n\t  end = zsections[i].offset + zsections[i].size;\n\t  if (end > max_offset)\n\t    max_offset = end;\n\t  debug_size += zsections[i].size;\n\t}\n    }\n  if (min_offset == 0 || max_offset == 0)\n    {\n      if (descriptor >= 0)\n\t{\n\t  if (!backtrace_close (descriptor, error_callback, data))\n\t    goto fail;\n\t}\n      return 1;\n    }\n\n  /* If the total debug section size is large, assume that there are\n     gaps between the sections, and read them individually.  */\n\n  if (max_offset - min_offset < 0x20000000\n      || max_offset - min_offset < debug_size + 0x10000)\n    {\n      if (!elf_get_view (state, descriptor, memory, memory_size, min_offset,\n\t\t\t max_offset - min_offset, error_callback, data,\n\t\t\t &debug_view))\n\tgoto fail;\n      debug_view_valid = 1;\n    }\n  else\n    {\n      memset (&split_debug_view[0], 0, sizeof split_debug_view);\n      for (i = 0; i < (int) DEBUG_MAX; ++i)\n\t{\n\t  struct debug_section_info *dsec;\n\n\t  if (sections[i].size != 0)\n\t    dsec = &sections[i];\n\t  else if (zsections[i].size != 0)\n\t    dsec = &zsections[i];\n\t  else\n\t    continue;\n\n\t  if (!elf_get_view (state, descriptor, memory, memory_size,\n\t\t\t     dsec->offset, dsec->size, error_callback, data,\n\t\t\t     &split_debug_view[i]))\n\t    goto fail;\n\t  split_debug_view_valid[i] = 1;\n\n\t  if (sections[i].size != 0)\n\t    sections[i].data = ((const unsigned char *)\n\t\t\t\tsplit_debug_view[i].view.data);\n\t  else\n\t    zsections[i].data = ((const unsigned char *)\n\t\t\t\t split_debug_view[i].view.data);\n\t}\n    }\n\n  /* We've read all we need from the executable.  */\n  if (descriptor >= 0)\n    {\n      if (!backtrace_close (descriptor, error_callback, data))\n\tgoto fail;\n      descriptor = -1;\n    }\n\n  using_debug_view = 0;\n  if (debug_view_valid)\n    {\n      for (i = 0; i < (int) DEBUG_MAX; ++i)\n\t{\n\t  if (sections[i].size == 0)\n\t    sections[i].data = NULL;\n\t  else\n\t    {\n\t      sections[i].data = ((const unsigned char *) debug_view.view.data\n\t\t\t\t  + (sections[i].offset - min_offset));\n\t      ++using_debug_view;\n\t    }\n\n\t  if (zsections[i].size == 0)\n\t    zsections[i].data = NULL;\n\t  else\n\t    zsections[i].data = ((const unsigned char *) debug_view.view.data\n\t\t\t\t + (zsections[i].offset - min_offset));\n\t}\n    }\n\n  /* Uncompress the old format (--compress-debug-sections=zlib-gnu).  */\n\n  zdebug_table = NULL;\n  for (i = 0; i < (int) DEBUG_MAX; ++i)\n    {\n      if (sections[i].size == 0 && zsections[i].size > 0)\n\t{\n\t  unsigned char *uncompressed_data;\n\t  size_t uncompressed_size;\n\n\t  if (zdebug_table == NULL)\n\t    {\n\t      zdebug_table = ((uint16_t *)\n\t\t\t      backtrace_alloc (state, ZLIB_TABLE_SIZE,\n\t\t\t\t\t       error_callback, data));\n\t      if (zdebug_table == NULL)\n\t\tgoto fail;\n\t    }\n\n\t  uncompressed_data = NULL;\n\t  uncompressed_size = 0;\n\t  if (!elf_uncompress_zdebug (state, zsections[i].data,\n\t\t\t\t      zsections[i].size, zdebug_table,\n\t\t\t\t      error_callback, data,\n\t\t\t\t      &uncompressed_data, &uncompressed_size))\n\t    goto fail;\n\t  sections[i].data = uncompressed_data;\n\t  sections[i].size = uncompressed_size;\n\t  sections[i].compressed = 0;\n\n\t  if (split_debug_view_valid[i])\n\t    {\n\t      elf_release_view (state, &split_debug_view[i],\n\t\t\t\terror_callback, data);\n\t      split_debug_view_valid[i] = 0;\n\t    }\n\t}\n    }\n\n  if (zdebug_table != NULL)\n    {\n      backtrace_free (state, zdebug_table, ZLIB_TABLE_SIZE,\n\t\t      error_callback, data);\n      zdebug_table = NULL;\n    }\n\n  /* Uncompress the official ELF format\n     (--compress-debug-sections=zlib-gabi, --compress-debug-sections=zstd).  */\n  for (i = 0; i < (int) DEBUG_MAX; ++i)\n    {\n      unsigned char *uncompressed_data;\n      size_t uncompressed_size;\n\n      if (sections[i].size == 0 || !sections[i].compressed)\n\tcontinue;\n\n      if (zdebug_table == NULL)\n\t{\n\t  zdebug_table = ((uint16_t *)\n\t\t\t  backtrace_alloc (state, ZDEBUG_TABLE_SIZE,\n\t\t\t\t\t   error_callback, data));\n\t  if (zdebug_table == NULL)\n\t    goto fail;\n\t}\n\n      uncompressed_data = NULL;\n      uncompressed_size = 0;\n      if (!elf_uncompress_chdr (state, sections[i].data, sections[i].size,\n\t\t\t\tzdebug_table, error_callback, data,\n\t\t\t\t&uncompressed_data, &uncompressed_size))\n\tgoto fail;\n      sections[i].data = uncompressed_data;\n      sections[i].size = uncompressed_size;\n      sections[i].compressed = 0;\n\n      if (debug_view_valid)\n\t--using_debug_view;\n      else if (split_debug_view_valid[i])\n\t{\n\t  elf_release_view (state, &split_debug_view[i], error_callback, data);\n\t  split_debug_view_valid[i] = 0;\n\t}\n    }\n\n  if (zdebug_table != NULL)\n    backtrace_free (state, zdebug_table, ZDEBUG_TABLE_SIZE,\n\t\t    error_callback, data);\n\n  if (debug_view_valid && using_debug_view == 0)\n    {\n      elf_release_view (state, &debug_view, error_callback, data);\n      debug_view_valid = 0;\n    }\n\n  for (i = 0; i < (int) DEBUG_MAX; ++i)\n    {\n      dwarf_sections.data[i] = sections[i].data;\n      dwarf_sections.size[i] = sections[i].size;\n    }\n\n  if (!backtrace_dwarf_add (state, base_address, &dwarf_sections,\n\t\t\t    ehdr.e_ident[EI_DATA] == ELFDATA2MSB,\n\t\t\t    fileline_altlink,\n\t\t\t    error_callback, data, fileline_fn,\n\t\t\t    fileline_entry))\n    goto fail;\n\n  *found_dwarf = 1;\n\n  return 1;\n\n fail:\n  if (shdrs_view_valid)\n    elf_release_view (state, &shdrs_view, error_callback, data);\n  if (names_view_valid)\n    elf_release_view (state, &names_view, error_callback, data);\n  if (symtab_view_valid)\n    elf_release_view (state, &symtab_view, error_callback, data);\n  if (strtab_view_valid)\n    elf_release_view (state, &strtab_view, error_callback, data);\n  if (debuglink_view_valid)\n    elf_release_view (state, &debuglink_view, error_callback, data);\n  if (debugaltlink_view_valid)\n    elf_release_view (state, &debugaltlink_view, error_callback, data);\n  if (gnu_debugdata_view_valid)\n    elf_release_view (state, &gnu_debugdata_view, error_callback, data);\n  if (buildid_view_valid)\n    elf_release_view (state, &buildid_view, error_callback, data);\n  if (debug_view_valid)\n    elf_release_view (state, &debug_view, error_callback, data);\n  for (i = 0; i < (int) DEBUG_MAX; ++i)\n    {\n      if (split_debug_view_valid[i])\n\telf_release_view (state, &split_debug_view[i], error_callback, data);\n    }\n  if (opd_view_valid)\n    elf_release_view (state, &opd->view, error_callback, data);\n  if (descriptor >= 0)\n    backtrace_close (descriptor, error_callback, data);\n  return 0;\n}\n\n/* Data passed to phdr_callback.  */\n\nstruct phdr_data\n{\n  struct backtrace_state *state;\n  backtrace_error_callback error_callback;\n  void *data;\n  fileline *fileline_fn;\n  int *found_sym;\n  int *found_dwarf;\n  const char *exe_filename;\n  int exe_descriptor;\n};\n\n/* Callback passed to dl_iterate_phdr.  Load debug info from shared\n   libraries.  */\n\nstruct PhdrIterate\n{\n  char* dlpi_name;\n  ElfW(Addr) dlpi_addr;\n  ElfW(Addr) dlpi_end_addr;\n};\nFastVector<PhdrIterate> s_phdrData(16);\n\nstruct ElfAddrRange\n{\n  ElfW(Addr) dlpi_addr;\n  ElfW(Addr) dlpi_end_addr;\n};\nFastVector<ElfAddrRange> s_sortedKnownElfRanges(16);\n\nstatic int address_in_known_elf_ranges(uintptr_t pc)\n{\n    auto it = std::lower_bound( s_sortedKnownElfRanges.begin(), s_sortedKnownElfRanges.end(), pc, \n            []( const ElfAddrRange& lhs, const uintptr_t rhs ) { return uintptr_t(lhs.dlpi_addr) > rhs; } );\n\tif( it != s_sortedKnownElfRanges.end() && pc <= it->dlpi_end_addr )\n\t{\n\t\treturn true;\n\t}\n\treturn false;\n}\n\nstatic int\nphdr_callback_mock (struct dl_phdr_info *info, size_t size ATTRIBUTE_UNUSED,\n  void *pdata)\n{\n  if( address_in_known_elf_ranges(info->dlpi_addr) )\n  {\n\treturn 0;\n  }\n\n  auto ptr = s_phdrData.push_next();\n  if (info->dlpi_name)\n  {\n    size_t sz = strlen (info->dlpi_name) + 1;\n    ptr->dlpi_name = (char*)tracy_malloc (sz);\n    memcpy (ptr->dlpi_name, info->dlpi_name, sz);\n  }\n  else ptr->dlpi_name = nullptr;\n  ptr->dlpi_addr = info->dlpi_addr;\n\n  // calculate the end address as well, so we can quickly determine if a PC is within the range of this image\n  ptr->dlpi_end_addr = uintptr_t(info->dlpi_addr) + (info->dlpi_phnum ? uintptr_t(\n                            info->dlpi_phdr[info->dlpi_phnum - 1].p_vaddr + \n                            info->dlpi_phdr[info->dlpi_phnum - 1].p_memsz) : 0);\n\n  return 0;\n}\n\nstatic int\n#ifdef __i386__\n__attribute__ ((__force_align_arg_pointer__))\n#endif\nphdr_callback (struct PhdrIterate *info, void *pdata)\n{\n  struct phdr_data *pd = (struct phdr_data *) pdata;\n  const char *filename;\n  int descriptor;\n  int does_not_exist;\n  struct libbacktrace_base_address base_address;\n  fileline elf_fileline_fn;\n  int found_dwarf;\n\n  /* There is not much we can do if we don't have the module name,\n     unless executable is ET_DYN, where we expect the very first\n     phdr_callback to be for the PIE.  */\n  if (info->dlpi_name == NULL || info->dlpi_name[0] == '\\0')\n    {\n      if (pd->exe_descriptor == -1)\n\treturn 0;\n      filename = pd->exe_filename;\n      descriptor = pd->exe_descriptor;\n      pd->exe_descriptor = -1;\n    }\n  else\n    {\n      if (pd->exe_descriptor != -1)\n\t{\n\t  backtrace_close (pd->exe_descriptor, pd->error_callback, pd->data);\n\t  pd->exe_descriptor = -1;\n\t}\n\n      filename = info->dlpi_name;\n      descriptor = backtrace_open (info->dlpi_name, pd->error_callback,\n\t\t\t\t   pd->data, &does_not_exist);\n      if (descriptor < 0)\n\treturn 0;\n    }\n\n  base_address.m = info->dlpi_addr;\n  if (elf_add (pd->state, filename, descriptor, NULL, 0, base_address, NULL,\n\t       pd->error_callback, pd->data, &elf_fileline_fn, pd->found_sym,\n\t       &found_dwarf, NULL, 0, 0, NULL, 0))\n    {\n      if (found_dwarf)\n\t{\n\t  *pd->found_dwarf = 1;\n\t  *pd->fileline_fn = elf_fileline_fn;\n\t}\n    }\n\n  return 0;\n}\n\nstatic int elf_iterate_phdr_and_add_new_files(phdr_data *pd)\n{\n\tassert(s_phdrData.empty());\n\t// dl_iterate_phdr, will only add entries for elf files loaded in a previously unseen range\n\tdl_iterate_phdr(phdr_callback_mock, nullptr);\n\n\tif(s_phdrData.size() == 0)\n\t{\n\t\treturn 0;\n\t}\n\n\tuint32_t headersAdded = 0;\n\tfor (auto &v : s_phdrData)\n\t{\n\t\tphdr_callback(&v, (void *)pd);\n\n\t\tauto newEntry = s_sortedKnownElfRanges.push_next();\n\t\tnewEntry->dlpi_addr = v.dlpi_addr;\n\t\tnewEntry->dlpi_end_addr = v.dlpi_end_addr;\n\n\t\ttracy_free(v.dlpi_name);\n\n\t\theadersAdded++;\n\t}\n\n\ts_phdrData.clear();\n\n   \tstd::sort( s_sortedKnownElfRanges.begin(), s_sortedKnownElfRanges.end(), \n\t\t[]( const ElfAddrRange& lhs, const ElfAddrRange& rhs ) { return lhs.dlpi_addr > rhs.dlpi_addr; } );\n\n\treturn headersAdded;\n}\n\n#ifdef TRACY_LIBBACKTRACE_ELF_DYNLOAD_SUPPORT\n/* Request an elf entry update if the pc passed in is not in any of the known elf ranges. \nThis could mean that new images were dlopened and we need to add those new elf entries */\nstatic int elf_refresh_address_ranges_if_needed(struct backtrace_state *state, uintptr_t pc)\n{\n\tif ( address_in_known_elf_ranges(pc) )\n\t{\n\t\treturn 0;\n\t}\n\n\tstruct phdr_data pd;\n\tint found_sym = 0;\n\tint found_dwarf = 0;\n\tfileline fileline_fn = nullptr;\n\tpd.state = state;\n\tpd.error_callback = nullptr;\n\tpd.data = nullptr;\n\tpd.fileline_fn = &fileline_fn;\n\tpd.found_sym = &found_sym;\n\tpd.found_dwarf = &found_dwarf;\n\tpd.exe_filename = nullptr;\n\tpd.exe_descriptor = -1;\n\n\treturn elf_iterate_phdr_and_add_new_files(&pd);\n}\n#endif //#ifdef TRACY_LIBBACKTRACE_ELF_DYNLOAD_SUPPORT\n\n/* Initialize the backtrace data we need from an ELF executable.  At\n   the ELF level, all we need to do is find the debug info\n   sections.  */\n\nint\nbacktrace_initialize (struct backtrace_state *state, const char *filename,\n\t\t      int descriptor, backtrace_error_callback error_callback,\n\t\t      void *data, fileline *fileline_fn)\n{\n  int ret;\n  int found_sym;\n  int found_dwarf;\n  fileline elf_fileline_fn = elf_nodebug;\n  struct phdr_data pd;\n\n\n  /* When using fdpic we must use dl_iterate_phdr for all modules, including\n     the main executable, so that we can get the right base address\n     mapping.  */\n  if (!libbacktrace_using_fdpic ())\n    {\n      struct libbacktrace_base_address zero_base_address;\n\n      memset (&zero_base_address, 0, sizeof zero_base_address);\n      ret = elf_add (state, filename, descriptor, NULL, 0, zero_base_address,\n\t\t     NULL, error_callback, data, &elf_fileline_fn, &found_sym,\n\t\t     &found_dwarf, NULL, 1, 0, NULL, 0);\n      if (!ret)\n\treturn 0;\n    }\n\n  pd.state = state;\n  pd.error_callback = error_callback;\n  pd.data = data;\n  pd.fileline_fn = &elf_fileline_fn;\n  pd.found_sym = &found_sym;\n  pd.found_dwarf = &found_dwarf;\n  pd.exe_filename = filename;\n  pd.exe_descriptor = ret < 0 ? descriptor : -1;\n\n  elf_iterate_phdr_and_add_new_files(&pd);\n\n  if (!state->threaded)\n    {\n      if (found_sym)\n\tstate->syminfo_fn = elf_syminfo;\n      else if (state->syminfo_fn == NULL)\n\tstate->syminfo_fn = elf_nosyms;\n    }\n  else\n    {\n      if (found_sym)\n\tbacktrace_atomic_store_pointer (&state->syminfo_fn, &elf_syminfo);\n      else\n\t(void) __sync_bool_compare_and_swap (&state->syminfo_fn, NULL,\n\t\t\t\t\t     elf_nosyms);\n    }\n\n  if (!state->threaded)\n    *fileline_fn = state->fileline_fn;\n  else\n    *fileline_fn = backtrace_atomic_load_pointer (&state->fileline_fn);\n\n  if (*fileline_fn == NULL || *fileline_fn == elf_nodebug)\n    *fileline_fn = elf_fileline_fn;\n\n  // install an address range refresh callback so we can cope with dynamically loaded elf files\n#ifdef TRACY_LIBBACKTRACE_ELF_DYNLOAD_SUPPORT\n  state->request_known_address_ranges_refresh_fn = elf_refresh_address_ranges_if_needed;\n#else\n  state->request_known_address_ranges_refresh_fn = NULL;\n#endif\n\n  return 1;\n}\n\n}\n"
  },
  {
    "path": "tracy-client-sys/tracy/libbacktrace/fileline.cpp",
    "content": "/* fileline.c -- Get file and line number information in a backtrace.\n   Copyright (C) 2012-2021 Free Software Foundation, Inc.\n   Written by Ian Lance Taylor, Google.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n    (1) Redistributions of source code must retain the above copyright\n    notice, this list of conditions and the following disclaimer.\n\n    (2) Redistributions in binary form must reproduce the above copyright\n    notice, this list of conditions and the following disclaimer in\n    the documentation and/or other materials provided with the\n    distribution.\n\n    (3) The name of the author may not be used to\n    endorse or promote products derived from this software without\n    specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\nIMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\nWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,\nINDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\nHOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\nSTRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\nIN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGE.  */\n\n#include \"config.h\"\n\n#include <sys/types.h>\n#include <sys/stat.h>\n#include <errno.h>\n#include <fcntl.h>\n#include <stdlib.h>\n#include <unistd.h>\n\n#if defined (HAVE_KERN_PROC_ARGS) || defined (HAVE_KERN_PROC)\n#include <sys/sysctl.h>\n#endif\n\n#ifdef HAVE_MACH_O_DYLD_H\n#include <mach-o/dyld.h>\n#endif\n\n#ifdef HAVE_WINDOWS_H\n#ifndef WIN32_MEAN_AND_LEAN\n#define WIN32_MEAN_AND_LEAN\n#endif\n\n#ifndef NOMINMAX\n#define NOMINMAX\n#endif\n\n#include <windows.h>\n#endif\n\n#include \"backtrace.hpp\"\n#include \"internal.hpp\"\n\n#ifndef HAVE_GETEXECNAME\n#define getexecname() NULL\n#endif\n\nnamespace tracy\n{\n\n#if !defined (HAVE_KERN_PROC_ARGS) && !defined (HAVE_KERN_PROC)\n\n#define sysctl_exec_name1(state, error_callback, data) NULL\n#define sysctl_exec_name2(state, error_callback, data) NULL\n\n#else /* defined (HAVE_KERN_PROC_ARGS) || |defined (HAVE_KERN_PROC) */\n\nstatic char *\nsysctl_exec_name (struct backtrace_state *state,\n\t\t  int mib0, int mib1, int mib2, int mib3,\n\t\t  backtrace_error_callback error_callback, void *data)\n{\n  int mib[4];\n  size_t len;\n  char *name;\n  size_t rlen;\n\n  mib[0] = mib0;\n  mib[1] = mib1;\n  mib[2] = mib2;\n  mib[3] = mib3;\n\n  if (sysctl (mib, 4, NULL, &len, NULL, 0) < 0)\n    return NULL;\n  name = (char *) backtrace_alloc (state, len, error_callback, data);\n  if (name == NULL)\n    return NULL;\n  rlen = len;\n  if (sysctl (mib, 4, name, &rlen, NULL, 0) < 0)\n    {\n      backtrace_free (state, name, len, error_callback, data);\n      return NULL;\n    }\n  return name;\n}\n\n#ifdef HAVE_KERN_PROC_ARGS\n\nstatic char *\nsysctl_exec_name1 (struct backtrace_state *state,\n\t\t   backtrace_error_callback error_callback, void *data)\n{\n  /* This variant is used on NetBSD.  */\n  return sysctl_exec_name (state, CTL_KERN, KERN_PROC_ARGS, -1,\n\t\t\t   KERN_PROC_PATHNAME, error_callback, data);\n}\n\n#else\n\n#define sysctl_exec_name1(state, error_callback, data) NULL\n\n#endif\n\n#ifdef HAVE_KERN_PROC\n\nstatic char *\nsysctl_exec_name2 (struct backtrace_state *state,\n\t\t   backtrace_error_callback error_callback, void *data)\n{\n  /* This variant is used on FreeBSD.  */\n  return sysctl_exec_name (state, CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1,\n\t\t\t   error_callback, data);\n}\n\n#else\n\n#define sysctl_exec_name2(state, error_callback, data) NULL\n\n#endif\n\n#endif /* defined (HAVE_KERN_PROC_ARGS) || |defined (HAVE_KERN_PROC) */\n\n#ifdef HAVE_MACH_O_DYLD_H\n\nstatic char *\nmacho_get_executable_path (struct backtrace_state *state,\n\t\t\t   backtrace_error_callback error_callback, void *data)\n{\n  uint32_t len;\n  char *name;\n\n  len = 0;\n  if (_NSGetExecutablePath (NULL, &len) == 0)\n    return NULL;\n  name = (char *) backtrace_alloc (state, len, error_callback, data);\n  if (name == NULL)\n    return NULL;\n  if (_NSGetExecutablePath (name, &len) != 0)\n    {\n      backtrace_free (state, name, len, error_callback, data);\n      return NULL;\n    }\n  return name;\n}\n\n#else /* !defined (HAVE_MACH_O_DYLD_H) */\n\n#define macho_get_executable_path(state, error_callback, data) NULL\n\n#endif /* !defined (HAVE_MACH_O_DYLD_H) */\n\n#if HAVE_DECL__PGMPTR\n\n#define windows_executable_filename() _pgmptr\n\n#else /* !HAVE_DECL__PGMPTR */\n\n#define windows_executable_filename() NULL\n\n#endif /* !HAVE_DECL__PGMPTR */\n\n#ifdef HAVE_WINDOWS_H\n\n#define FILENAME_BUF_SIZE (MAX_PATH)\n\nstatic char *\nwindows_get_executable_path (char *buf, backtrace_error_callback error_callback,\n\t\t\t     void *data)\n{\n  size_t got;\n  int error;\n\n  got = GetModuleFileNameA (NULL, buf, FILENAME_BUF_SIZE - 1);\n  error = GetLastError ();\n  if (got == 0\n      || (got == FILENAME_BUF_SIZE - 1 && error == ERROR_INSUFFICIENT_BUFFER))\n    {\n      error_callback (data,\n\t\t      \"could not get the filename of the current executable\",\n\t\t      error);\n      return NULL;\n    }\n  return buf;\n}\n\n#else /* !defined (HAVE_WINDOWS_H) */\n\n#define windows_get_executable_path(buf, error_callback, data) NULL\n#define FILENAME_BUF_SIZE 64\n\n#endif /* !defined (HAVE_WINDOWS_H) */\n\n/* Initialize the fileline information from the executable.  Returns 1\n   on success, 0 on failure.  */\n\nstatic int\nfileline_initialize (struct backtrace_state *state,\n\t\t     backtrace_error_callback error_callback, void *data)\n{\n  int failed;\n  fileline fileline_fn;\n  int pass;\n  int called_error_callback;\n  int descriptor;\n  const char *filename;\n  char buf[FILENAME_BUF_SIZE];\n\n  if (!state->threaded)\n    failed = state->fileline_initialization_failed;\n  else\n    failed = backtrace_atomic_load_int (&state->fileline_initialization_failed);\n\n  if (failed)\n    {\n      error_callback (data, \"failed to read executable information\", -1);\n      return 0;\n    }\n\n  if (!state->threaded)\n    fileline_fn = state->fileline_fn;\n  else\n    fileline_fn = backtrace_atomic_load_pointer (&state->fileline_fn);\n  if (fileline_fn != NULL)\n    return 1;\n\n  /* We have not initialized the information.  Do it now.  */\n\n  descriptor = -1;\n  called_error_callback = 0;\n  for (pass = 0; pass < 10; ++pass)\n    {\n      int does_not_exist;\n\n      switch (pass)\n\t{\n\tcase 0:\n\t  filename = state->filename;\n\t  break;\n\tcase 1:\n\t  filename = getexecname ();\n\t  break;\n\tcase 2:\n\t  /* Test this before /proc/self/exe, as the latter exists but points\n\t     to the wine binary (and thus doesn't work).  */\n\t  filename = windows_executable_filename ();\n\t  break;\n\tcase 3:\n\t  filename = \"/proc/self/exe\";\n\t  break;\n\tcase 4:\n\t  filename = \"/proc/curproc/file\";\n\t  break;\n\tcase 5:\n\t  snprintf (buf, sizeof (buf), \"/proc/%ld/object/a.out\",\n\t\t    (long) getpid ());\n\t  filename = buf;\n\t  break;\n\tcase 6:\n\t  filename = sysctl_exec_name1 (state, error_callback, data);\n\t  break;\n\tcase 7:\n\t  filename = sysctl_exec_name2 (state, error_callback, data);\n\t  break;\n\tcase 8:\n\t  filename = macho_get_executable_path (state, error_callback, data);\n\t  break;\n\tcase 9:\n\t  filename = windows_get_executable_path (buf, error_callback, data);\n\t  break;\n\tdefault:\n\t  abort ();\n\t}\n\n      if (filename == NULL)\n\tcontinue;\n\n      descriptor = backtrace_open (filename, error_callback, data,\n\t\t\t\t   &does_not_exist);\n      if (descriptor < 0 && !does_not_exist)\n\t{\n\t  called_error_callback = 1;\n\t  break;\n\t}\n      if (descriptor >= 0)\n\tbreak;\n    }\n\n  if (descriptor < 0)\n    {\n      if (!called_error_callback)\n\t{\n\t  if (state->filename != NULL)\n\t    error_callback (data, state->filename, ENOENT);\n\t  else\n\t    error_callback (data,\n\t\t\t    \"libbacktrace could not find executable to open\",\n\t\t\t    0);\n\t}\n      failed = 1;\n    }\n\n  if (!failed)\n    {\n      if (!backtrace_initialize (state, filename, descriptor, error_callback,\n\t\t\t\t data, &fileline_fn))\n\tfailed = 1;\n    }\n\n  if (failed)\n    {\n      if (!state->threaded)\n\tstate->fileline_initialization_failed = 1;\n      else\n\tbacktrace_atomic_store_int (&state->fileline_initialization_failed, 1);\n      return 0;\n    }\n\n  if (!state->threaded)\n    state->fileline_fn = fileline_fn;\n  else\n    {\n      backtrace_atomic_store_pointer (&state->fileline_fn, fileline_fn);\n\n      /* Note that if two threads initialize at once, one of the data\n\t sets may be leaked.  */\n    }\n\n  return 1;\n}\n\n/* Given a PC, find the file name, line number, and function name.  */\n\nint\nbacktrace_pcinfo (struct backtrace_state *state, uintptr_t pc,\n\t\t  backtrace_full_callback callback,\n\t\t  backtrace_error_callback error_callback, void *data)\n{\n  if (!fileline_initialize (state, error_callback, data))\n    return 0;\n\n  if (state->fileline_initialization_failed)\n    return 0;\n\n  return state->fileline_fn (state, pc, callback, error_callback, data);\n}\n\n/* Given a PC, find the symbol for it, and its value.  */\n\nint\nbacktrace_syminfo (struct backtrace_state *state, uintptr_t pc,\n\t\t   backtrace_syminfo_callback callback,\n\t\t   backtrace_error_callback error_callback, void *data)\n{\n  if (!fileline_initialize (state, error_callback, data))\n    return 0;\n\n  if (state->fileline_initialization_failed)\n    return 0;\n\n  state->syminfo_fn (state, pc, callback, error_callback, data);\n  return 1;\n}\n\n/* A backtrace_syminfo_callback that can call into a\n   backtrace_full_callback, used when we have a symbol table but no\n   debug info.  */\n\nvoid\nbacktrace_syminfo_to_full_callback (void *data, uintptr_t pc,\n\t\t\t\t    const char *symname,\n\t\t\t\t    uintptr_t symval ATTRIBUTE_UNUSED,\n\t\t\t\t    uintptr_t symsize ATTRIBUTE_UNUSED)\n{\n  struct backtrace_call_full *bdata = (struct backtrace_call_full *) data;\n\n  bdata->ret = bdata->full_callback (bdata->full_data, pc, 0, NULL, 0, symname);\n}\n\n/* An error callback that corresponds to\n   backtrace_syminfo_to_full_callback.  */\n\nvoid\nbacktrace_syminfo_to_full_error_callback (void *data, const char *msg,\n\t\t\t\t\t  int errnum)\n{\n  struct backtrace_call_full *bdata = (struct backtrace_call_full *) data;\n\n  bdata->full_error_callback (bdata->full_data, msg, errnum);\n}\n\n}\n"
  },
  {
    "path": "tracy-client-sys/tracy/libbacktrace/filenames.hpp",
    "content": "/* btest.c -- Filename header for libbacktrace library\n   Copyright (C) 2012-2018 Free Software Foundation, Inc.\n   Written by Ian Lance Taylor, Google.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n    (1) Redistributions of source code must retain the above copyright\n    notice, this list of conditions and the following disclaimer.\n\n    (2) Redistributions in binary form must reproduce the above copyright\n    notice, this list of conditions and the following disclaimer in\n    the documentation and/or other materials provided with the\n    distribution.\n\n    (3) The name of the author may not be used to\n    endorse or promote products derived from this software without\n    specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\nIMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\nWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,\nINDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\nHOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\nSTRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\nIN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGE.  */\n\n#ifndef GCC_VERSION\n# define GCC_VERSION (__GNUC__ * 1000 + __GNUC_MINOR__)\n#endif\n\n#if (GCC_VERSION < 2007)\n# define __attribute__(x)\n#endif\n\n#ifndef ATTRIBUTE_UNUSED\n# define ATTRIBUTE_UNUSED __attribute__ ((__unused__))\n#endif\n\n#if defined(__MSDOS__) || defined(_WIN32) || defined(__OS2__) || defined (__CYGWIN__)\n# define IS_DIR_SEPARATOR(c) ((c) == '/' || (c) == '\\\\')\n# define HAS_DRIVE_SPEC(f) ((f)[0] != '\\0' && (f)[1] == ':')\n# define IS_ABSOLUTE_PATH(f) (IS_DIR_SEPARATOR((f)[0]) || HAS_DRIVE_SPEC(f))\n#else\n# define IS_DIR_SEPARATOR(c) ((c) == '/')\n# define IS_ABSOLUTE_PATH(f) (IS_DIR_SEPARATOR((f)[0]))\n#endif\n"
  },
  {
    "path": "tracy-client-sys/tracy/libbacktrace/internal.hpp",
    "content": "/* internal.h -- Internal header file for stack backtrace library.\n   Copyright (C) 2012-2021 Free Software Foundation, Inc.\n   Written by Ian Lance Taylor, Google.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n    (1) Redistributions of source code must retain the above copyright\n    notice, this list of conditions and the following disclaimer.\n\n    (2) Redistributions in binary form must reproduce the above copyright\n    notice, this list of conditions and the following disclaimer in\n    the documentation and/or other materials provided with the\n    distribution.\n\n    (3) The name of the author may not be used to\n    endorse or promote products derived from this software without\n    specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\nIMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\nWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,\nINDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\nHOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\nSTRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\nIN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGE.  */\n\n#ifndef BACKTRACE_INTERNAL_H\n#define BACKTRACE_INTERNAL_H\n\n/* We assume that <sys/types.h> and \"backtrace.h\" have already been\n   included.  */\n\n#ifndef GCC_VERSION\n# define GCC_VERSION (__GNUC__ * 1000 + __GNUC_MINOR__)\n#endif\n\n#if (GCC_VERSION < 2007)\n# define __attribute__(x)\n#endif\n\n#ifndef ATTRIBUTE_UNUSED\n# define ATTRIBUTE_UNUSED __attribute__ ((__unused__))\n#endif\n\n#ifndef ATTRIBUTE_MALLOC\n# if (GCC_VERSION >= 2096)\n#  define ATTRIBUTE_MALLOC __attribute__ ((__malloc__))\n# else\n#  define ATTRIBUTE_MALLOC\n# endif\n#endif\n\n#ifndef ATTRIBUTE_FALLTHROUGH\n# if (GCC_VERSION >= 7000)\n#  define ATTRIBUTE_FALLTHROUGH __attribute__ ((__fallthrough__))\n# else\n#  define ATTRIBUTE_FALLTHROUGH\n# endif\n#endif\n\n#ifndef HAVE_SYNC_FUNCTIONS\n\n/* Define out the sync functions.  These should never be called if\n   they are not available.  */\n\n#define __sync_bool_compare_and_swap(A, B, C) (abort(), 1)\n#define __sync_lock_test_and_set(A, B) (abort(), 0)\n#define __sync_lock_release(A) abort()\n\n#endif /* !defined (HAVE_SYNC_FUNCTIONS) */\n\n#ifdef HAVE_ATOMIC_FUNCTIONS\n\n/* We have the atomic builtin functions.  */\n\n#define backtrace_atomic_load_pointer(p) \\\n    __atomic_load_n ((p), __ATOMIC_ACQUIRE)\n#define backtrace_atomic_load_int(p) \\\n    __atomic_load_n ((p), __ATOMIC_ACQUIRE)\n#define backtrace_atomic_store_pointer(p, v) \\\n    __atomic_store_n ((p), (v), __ATOMIC_RELEASE)\n#define backtrace_atomic_store_size_t(p, v) \\\n    __atomic_store_n ((p), (v), __ATOMIC_RELEASE)\n#define backtrace_atomic_store_int(p, v) \\\n    __atomic_store_n ((p), (v), __ATOMIC_RELEASE)\n\n#else /* !defined (HAVE_ATOMIC_FUNCTIONS) */\n#ifdef HAVE_SYNC_FUNCTIONS\n\n/* We have the sync functions but not the atomic functions.  Define\n   the atomic ones in terms of the sync ones.  */\n\nextern void *backtrace_atomic_load_pointer (void *);\nextern int backtrace_atomic_load_int (int *);\nextern void backtrace_atomic_store_pointer (void *, void *);\nextern void backtrace_atomic_store_size_t (size_t *, size_t);\nextern void backtrace_atomic_store_int (int *, int);\n\n#else /* !defined (HAVE_SYNC_FUNCTIONS) */\n\n/* We have neither the sync nor the atomic functions.  These will\n   never be called.  */\n\n#define backtrace_atomic_load_pointer(p) (abort(), (void *) NULL)\n#define backtrace_atomic_load_int(p) (abort(), 0)\n#define backtrace_atomic_store_pointer(p, v) abort()\n#define backtrace_atomic_store_size_t(p, v) abort()\n#define backtrace_atomic_store_int(p, v) abort()\n\n#endif /* !defined (HAVE_SYNC_FUNCTIONS) */\n#endif /* !defined (HAVE_ATOMIC_FUNCTIONS) */\n\nnamespace tracy\n{\n\n/* The type of the function that collects file/line information.  This\n   is like backtrace_pcinfo.  */\n\ntypedef int (*fileline) (struct backtrace_state *state, uintptr_t pc,\n\t\t\t backtrace_full_callback callback,\n\t\t\t backtrace_error_callback error_callback, void *data);\n\n/* The type of the function that collects symbol information.  This is\n   like backtrace_syminfo.  */\n\ntypedef void (*syminfo) (struct backtrace_state *state, uintptr_t pc,\n\t\t\t backtrace_syminfo_callback callback,\n\t\t\t backtrace_error_callback error_callback, void *data);\n\n/* The type of the function that will trigger an known address range refresh\n (if pc passed in is for an address whichs lies ourtisde of known ranges) */\ntypedef int (*request_known_address_ranges_refresh)(struct backtrace_state *state,\n             uintptr_t pc);\n\n/* What the backtrace state pointer points to.  */\n\nstruct backtrace_state\n{\n  /* The name of the executable.  */\n  const char *filename;\n  /* Non-zero if threaded.  */\n  int threaded;\n  /* The master lock for fileline_fn, fileline_data, syminfo_fn,\n     syminfo_data, fileline_initialization_failed and everything the\n     data pointers point to.  */\n  void *lock;\n  /* The function that returns file/line information.  */\n  fileline fileline_fn;\n  /* The data to pass to FILELINE_FN.  */\n  void *fileline_data;\n  /* The function that returns symbol information.  */\n  syminfo syminfo_fn;\n  /* The data to pass to SYMINFO_FN.  */\n  void *syminfo_data;\n  /* Whether initializing the file/line information failed.  */\n  int fileline_initialization_failed;\n  /* The lock for the freelist.  */\n  int lock_alloc;\n  /* The freelist when using mmap.  */\n  struct backtrace_freelist_struct *freelist;\n  /* Trigger an known address range refresh */\n  request_known_address_ranges_refresh request_known_address_ranges_refresh_fn;\n};\n\n/* Open a file for reading.  Returns -1 on error.  If DOES_NOT_EXIST\n   is not NULL, *DOES_NOT_EXIST will be set to 0 normally and set to 1\n   if the file does not exist.  If the file does not exist and\n   DOES_NOT_EXIST is not NULL, the function will return -1 and will\n   not call ERROR_CALLBACK.  On other errors, or if DOES_NOT_EXIST is\n   NULL, the function will call ERROR_CALLBACK before returning.  */\nextern int backtrace_open (const char *filename,\n\t\t\t   backtrace_error_callback error_callback,\n\t\t\t   void *data,\n\t\t\t   int *does_not_exist);\n\n/* A view of the contents of a file.  This supports mmap when\n   available.  A view will remain in memory even after backtrace_close\n   is called on the file descriptor from which the view was\n   obtained.  */\n\nstruct backtrace_view\n{\n  /* The data that the caller requested.  */\n  const void *data;\n  /* The base of the view.  */\n  void *base;\n  /* The total length of the view.  */\n  size_t len;\n};\n\n/* Create a view of SIZE bytes from DESCRIPTOR at OFFSET.  Store the\n   result in *VIEW.  Returns 1 on success, 0 on error.  */\nextern int backtrace_get_view (struct backtrace_state *state, int descriptor,\n\t\t\t       off_t offset, uint64_t size,\n\t\t\t       backtrace_error_callback error_callback,\n\t\t\t       void *data, struct backtrace_view *view);\n\n/* Release a view created by backtrace_get_view.  */\nextern void backtrace_release_view (struct backtrace_state *state,\n\t\t\t\t    struct backtrace_view *view,\n\t\t\t\t    backtrace_error_callback error_callback,\n\t\t\t\t    void *data);\n\n/* Close a file opened by backtrace_open.  Returns 1 on success, 0 on\n   error.  */\n\nextern int backtrace_close (int descriptor,\n\t\t\t    backtrace_error_callback error_callback,\n\t\t\t    void *data);\n\n/* Sort without using memory.  */\n\nextern void backtrace_qsort (void *base, size_t count, size_t size,\n\t\t\t     int (*compar) (const void *, const void *));\n\n/* Allocate memory.  This is like malloc.  If ERROR_CALLBACK is NULL,\n   this does not report an error, it just returns NULL.  */\n\nextern void *backtrace_alloc (struct backtrace_state *state, size_t size,\n\t\t\t      backtrace_error_callback error_callback,\n\t\t\t      void *data) ATTRIBUTE_MALLOC;\n\n/* Free memory allocated by backtrace_alloc.  If ERROR_CALLBACK is\n   NULL, this does not report an error.  */\n\nextern void backtrace_free (struct backtrace_state *state, void *mem,\n\t\t\t    size_t size,\n\t\t\t    backtrace_error_callback error_callback,\n\t\t\t    void *data);\n\n/* A growable vector of some struct.  This is used for more efficient\n   allocation when we don't know the final size of some group of data\n   that we want to represent as an array.  */\n\nstruct backtrace_vector\n{\n  /* The base of the vector.  */\n  void *base;\n  /* The number of bytes in the vector.  */\n  size_t size;\n  /* The number of bytes available at the current allocation.  */\n  size_t alc;\n};\n\n/* Grow VEC by SIZE bytes.  Return a pointer to the newly allocated\n   bytes.  Note that this may move the entire vector to a new memory\n   location.  Returns NULL on failure.  */\n\nextern void *backtrace_vector_grow (struct backtrace_state *state, size_t size,\n\t\t\t\t    backtrace_error_callback error_callback,\n\t\t\t\t    void *data,\n\t\t\t\t    struct backtrace_vector *vec);\n\n/* Finish the current allocation on VEC.  Prepare to start a new\n   allocation.  The finished allocation will never be freed.  Returns\n   a pointer to the base of the finished entries, or NULL on\n   failure.  */\n\nextern void* backtrace_vector_finish (struct backtrace_state *state,\n\t\t\t\t      struct backtrace_vector *vec,\n\t\t\t\t      backtrace_error_callback error_callback,\n\t\t\t\t      void *data);\n\n/* Release any extra space allocated for VEC.  This may change\n   VEC->base.  Returns 1 on success, 0 on failure.  */\n\nextern int backtrace_vector_release (struct backtrace_state *state,\n\t\t\t\t     struct backtrace_vector *vec,\n\t\t\t\t     backtrace_error_callback error_callback,\n\t\t\t\t     void *data);\n\n/* Free the space managed by VEC.  This will reset VEC.  */\n\nstatic inline void\nbacktrace_vector_free (struct backtrace_state *state,\n\t\t       struct backtrace_vector *vec,\n\t\t       backtrace_error_callback error_callback, void *data)\n{\n  vec->alc += vec->size;\n  vec->size = 0;\n  backtrace_vector_release (state, vec, error_callback, data);\n}\n\n/* Read initial debug data from a descriptor, and set the\n   fileline_data, syminfo_fn, and syminfo_data fields of STATE.\n   Return the fileln_fn field in *FILELN_FN--this is done this way so\n   that the synchronization code is only implemented once.  This is\n   called after the descriptor has first been opened.  It will close\n   the descriptor if it is no longer needed.  Returns 1 on success, 0\n   on error.  There will be multiple implementations of this function,\n   for different file formats.  Each system will compile the\n   appropriate one.  */\n\nextern int backtrace_initialize (struct backtrace_state *state,\n\t\t\t\t const char *filename,\n\t\t\t\t int descriptor,\n\t\t\t\t backtrace_error_callback error_callback,\n\t\t\t\t void *data,\n\t\t\t\t fileline *fileline_fn);\n\n/* An enum for the DWARF sections we care about.  */\n\nenum dwarf_section\n{\n  DEBUG_INFO,\n  DEBUG_LINE,\n  DEBUG_ABBREV,\n  DEBUG_RANGES,\n  DEBUG_STR,\n  DEBUG_ADDR,\n  DEBUG_STR_OFFSETS,\n  DEBUG_LINE_STR,\n  DEBUG_RNGLISTS,\n\n  DEBUG_MAX\n};\n\n/* Data for the DWARF sections we care about.  */\n\nstruct dwarf_sections\n{\n  const unsigned char *data[DEBUG_MAX];\n  size_t size[DEBUG_MAX];\n};\n\n/* DWARF data read from a file, used for .gnu_debugaltlink.  */\n\nstruct dwarf_data;\n\n/* The load address mapping.  */\n\n#if defined(__FDPIC__) && defined(HAVE_DL_ITERATE_PHDR) && (defined(HAVE_LINK_H) || defined(HAVE_SYS_LINK_H))\n\n#ifdef HAVE_LINK_H\n #include <link.h>\n#endif\n#ifdef HAVE_SYS_LINK_H\n #include <sys/link.h>\n#endif\n\n#define libbacktrace_using_fdpic() (1)\n\nstruct libbacktrace_base_address\n{\n  struct elf32_fdpic_loadaddr m;\n};\n\n#define libbacktrace_add_base(pc, base) \\\n  ((uintptr_t) (__RELOC_POINTER ((pc), (base).m)))\n\n#else /* not _FDPIC__ */\n\n#define libbacktrace_using_fdpic() (0)\n\nstruct libbacktrace_base_address\n{\n  uintptr_t m;\n};\n\n#define libbacktrace_add_base(pc, base) ((pc) + (base).m)\n\n#endif /* not _FDPIC__ */\n\n/* Add file/line information for a DWARF module.  */\n\nextern int backtrace_dwarf_add (struct backtrace_state *state,\n\t\t\t\tstruct libbacktrace_base_address base_address,\n\t\t\t\tconst struct dwarf_sections *dwarf_sections,\n\t\t\t\tint is_bigendian,\n\t\t\t\tstruct dwarf_data *fileline_altlink,\n\t\t\t\tbacktrace_error_callback error_callback,\n\t\t\t\tvoid *data, fileline *fileline_fn,\n\t\t\t\tstruct dwarf_data **fileline_entry);\n\n/* A data structure to pass to backtrace_syminfo_to_full.  */\n\nstruct backtrace_call_full\n{\n  backtrace_full_callback full_callback;\n  backtrace_error_callback full_error_callback;\n  void *full_data;\n  int ret;\n};\n\n/* A backtrace_syminfo_callback that can call into a\n   backtrace_full_callback, used when we have a symbol table but no\n   debug info.  */\n\nextern void backtrace_syminfo_to_full_callback (void *data, uintptr_t pc,\n\t\t\t\t\t\tconst char *symname,\n\t\t\t\t\t\tuintptr_t symval,\n\t\t\t\t\t\tuintptr_t symsize);\n\n/* An error callback that corresponds to\n   backtrace_syminfo_to_full_callback.  */\n\nextern void backtrace_syminfo_to_full_error_callback (void *, const char *,\n\t\t\t\t\t\t      int);\n\n/* A test-only hook for elf_uncompress_zdebug.  */\n\nextern int backtrace_uncompress_zdebug (struct backtrace_state *,\n\t\t\t\t\tconst unsigned char *compressed,\n\t\t\t\t\tsize_t compressed_size,\n\t\t\t\t\tbacktrace_error_callback, void *data,\n\t\t\t\t\tunsigned char **uncompressed,\n\t\t\t\t\tsize_t *uncompressed_size);\n\n/* A test-only hook for elf_zstd_decompress.  */\n\nextern int backtrace_uncompress_zstd (struct backtrace_state *,\n\t\t\t\t      const unsigned char *compressed,\n\t\t\t\t      size_t compressed_size,\n\t\t\t\t      backtrace_error_callback, void *data,\n\t\t\t\t      unsigned char *uncompressed,\n\t\t\t\t      size_t uncompressed_size);\n\n/* A test-only hook for elf_uncompress_lzma.  */\n\nextern int backtrace_uncompress_lzma (struct backtrace_state *,\n\t\t\t\t      const unsigned char *compressed,\n\t\t\t\t      size_t compressed_size,\n\t\t\t\t      backtrace_error_callback, void *data,\n\t\t\t\t      unsigned char **uncompressed,\n\t\t\t\t      size_t *uncompressed_size);\n\n}\n\n#endif\n"
  },
  {
    "path": "tracy-client-sys/tracy/libbacktrace/macho.cpp",
    "content": "/* elf.c -- Get debug data from a Mach-O file for backtraces.\n   Copyright (C) 2020-2021 Free Software Foundation, Inc.\n   Written by Ian Lance Taylor, Google.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n    (1) Redistributions of source code must retain the above copyright\n    notice, this list of conditions and the following disclaimer.\n\n    (2) Redistributions in binary form must reproduce the above copyright\n    notice, this list of conditions and the following disclaimer in\n    the documentation and/or other materials provided with the\n    distribution.\n\n    (3) The name of the author may not be used to\n    endorse or promote products derived from this software without\n    specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\nIMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\nWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,\nINDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\nHOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\nSTRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\nIN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGE.  */\n\n#include \"config.h\"\n\n#include <sys/types.h>\n#include <dirent.h>\n#include <stdlib.h>\n#include <string.h>\n\n#ifdef HAVE_MACH_O_DYLD_H\n#include <mach-o/dyld.h>\n#endif\n\n#include \"backtrace.hpp\"\n#include \"internal.hpp\"\n\nnamespace tracy\n{\n\n/* Mach-O file header for a 32-bit executable.  */\n\nstruct macho_header_32\n{\n  uint32_t magic;\t/* Magic number (MACH_O_MAGIC_32) */\n  uint32_t cputype;\t/* CPU type */\n  uint32_t cpusubtype;\t/* CPU subtype */\n  uint32_t filetype;\t/* Type of file (object, executable) */\n  uint32_t ncmds;\t/* Number of load commands */\n  uint32_t sizeofcmds;\t/* Total size of load commands */\n  uint32_t flags;\t/* Flags for special features */\n};\n\n/* Mach-O file header for a 64-bit executable.  */\n\nstruct macho_header_64\n{\n  uint32_t magic;\t/* Magic number (MACH_O_MAGIC_64) */\n  uint32_t cputype;\t/* CPU type */\n  uint32_t cpusubtype;\t/* CPU subtype */\n  uint32_t filetype;\t/* Type of file (object, executable) */\n  uint32_t ncmds;\t/* Number of load commands */\n  uint32_t sizeofcmds;\t/* Total size of load commands */\n  uint32_t flags;\t/* Flags for special features */\n  uint32_t reserved;\t/* Reserved */\n};\n\n/* Mach-O file header for a fat executable.  */\n\nstruct macho_header_fat\n{\n  uint32_t magic;\t/* Magic number (MACH_O_MH_(MAGIC|CIGAM)_FAT(_64)?) */\n  uint32_t nfat_arch;   /* Number of components */\n};\n\n/* Values for the header magic field.  */\n\n#define MACH_O_MH_MAGIC_32\t0xfeedface\n#define MACH_O_MH_MAGIC_64\t0xfeedfacf\n#define MACH_O_MH_MAGIC_FAT\t0xcafebabe\n#define MACH_O_MH_CIGAM_FAT\t0xbebafeca\n#define MACH_O_MH_MAGIC_FAT_64\t0xcafebabf\n#define MACH_O_MH_CIGAM_FAT_64\t0xbfbafeca\n\n/* Value for the header filetype field.  */\n\n#define MACH_O_MH_EXECUTE\t0x02\n#define MACH_O_MH_DYLIB\t\t0x06\n#define MACH_O_MH_DSYM\t\t0x0a\n\n/* A component of a fat file.  A fat file starts with a\n   macho_header_fat followed by nfat_arch instances of this\n   struct.  */\n\nstruct macho_fat_arch\n{\n  uint32_t cputype;\t/* CPU type */\n  uint32_t cpusubtype;\t/* CPU subtype */\n  uint32_t offset;\t/* File offset of this entry */\n  uint32_t size;\t/* Size of this entry */\n  uint32_t align;\t/* Alignment of this entry */\n};\n\n/* A component of a 64-bit fat file.  This is used if the magic field\n   is MAGIC_FAT_64.  This is only used when some file size or file\n   offset is too large to represent in the 32-bit format.  */\n\nstruct macho_fat_arch_64\n{\n  uint32_t cputype;\t/* CPU type */\n  uint32_t cpusubtype;\t/* CPU subtype */\n  uint64_t offset;\t/* File offset of this entry */\n  uint64_t size;\t/* Size of this entry */\n  uint32_t align;\t/* Alignment of this entry */\n  uint32_t reserved;\t/* Reserved */\n};\n\n/* Values for the fat_arch cputype field (and the header cputype\n   field).  */\n\n#define MACH_O_CPU_ARCH_ABI64 0x01000000\n\n#define MACH_O_CPU_TYPE_X86 7\n#define MACH_O_CPU_TYPE_ARM 12\n#define MACH_O_CPU_TYPE_PPC 18\n\n#define MACH_O_CPU_TYPE_X86_64 (MACH_O_CPU_TYPE_X86 | MACH_O_CPU_ARCH_ABI64)\n#define MACH_O_CPU_TYPE_ARM64  (MACH_O_CPU_TYPE_ARM | MACH_O_CPU_ARCH_ABI64)\n#define MACH_O_CPU_TYPE_PPC64  (MACH_O_CPU_TYPE_PPC | MACH_O_CPU_ARCH_ABI64)\n\n/* The header of a load command.  */\n\nstruct macho_load_command\n{\n  uint32_t cmd;\t\t/* The type of load command */\n  uint32_t cmdsize;\t/* Size in bytes of the entire command */\n};\n\n/* Values for the load_command cmd field.  */\n\n#define MACH_O_LC_SEGMENT\t0x01\n#define MACH_O_LC_SYMTAB\t0x02\n#define MACH_O_LC_SEGMENT_64\t0x19\n#define MACH_O_LC_UUID\t\t0x1b\n\n/* The length of a section of segment name.  */\n\n#define MACH_O_NAMELEN (16)\n\n/* LC_SEGMENT load command.  */\n\nstruct macho_segment_command\n{\n  uint32_t cmd;\t\t\t/* The type of load command (LC_SEGMENT) */\n  uint32_t cmdsize;\t\t/* Size in bytes of the entire command */\n  char segname[MACH_O_NAMELEN];\t/* Segment name */\n  uint32_t vmaddr;\t\t/* Virtual memory address */\n  uint32_t vmsize;\t\t/* Virtual memory size */\n  uint32_t fileoff;\t\t/* Offset of data to be mapped */\n  uint32_t filesize;\t\t/* Size of data in file */\n  uint32_t maxprot;\t\t/* Maximum permitted virtual protection */\n  uint32_t initprot;\t\t/* Initial virtual memory protection */\n  uint32_t nsects;\t\t/* Number of sections in this segment */\n  uint32_t flags;\t\t/* Flags */\n};\n\n/* LC_SEGMENT_64 load command.  */\n\nstruct macho_segment_64_command\n{\n  uint32_t cmd;\t\t\t/* The type of load command (LC_SEGMENT) */\n  uint32_t cmdsize;\t\t/* Size in bytes of the entire command */\n  char segname[MACH_O_NAMELEN];\t/* Segment name */\n  uint64_t vmaddr;\t\t/* Virtual memory address */\n  uint64_t vmsize;\t\t/* Virtual memory size */\n  uint64_t fileoff;\t\t/* Offset of data to be mapped */\n  uint64_t filesize;\t\t/* Size of data in file */\n  uint32_t maxprot;\t\t/* Maximum permitted virtual protection */\n  uint32_t initprot;\t\t/* Initial virtual memory protection */\n  uint32_t nsects;\t\t/* Number of sections in this segment */\n  uint32_t flags;\t\t/* Flags */\n};\n\n/* LC_SYMTAB load command.  */\n\nstruct macho_symtab_command\n{\n  uint32_t cmd;\t\t/* The type of load command (LC_SEGMENT) */\n  uint32_t cmdsize;\t/* Size in bytes of the entire command */\n  uint32_t symoff;\t/* File offset of symbol table */\n  uint32_t nsyms;\t/* Number of symbols */\n  uint32_t stroff;\t/* File offset of string table */\n  uint32_t strsize;\t/* String table size */\n};\n\n/* The length of a Mach-O uuid.  */\n\n#define MACH_O_UUID_LEN (16)\n\n/* LC_UUID load command.  */\n\nstruct macho_uuid_command\n{\n  uint32_t cmd;\t\t\t\t/* Type of load command (LC_UUID) */\n  uint32_t cmdsize;\t\t\t/* Size in bytes of command */\n  unsigned char uuid[MACH_O_UUID_LEN];\t/* UUID */\n};\n\n/* 32-bit section header within a LC_SEGMENT segment.  */\n\nstruct macho_section\n{\n  char sectname[MACH_O_NAMELEN];\t/* Section name */\n  char segment[MACH_O_NAMELEN];\t\t/* Segment of this section */\n  uint32_t addr;\t\t\t/* Address in memory */\n  uint32_t size;\t\t\t/* Section size */\n  uint32_t offset;\t\t\t/* File offset */\n  uint32_t align;\t\t\t/* Log2 of section alignment */\n  uint32_t reloff;\t\t\t/* File offset of relocations */\n  uint32_t nreloc;\t\t\t/* Number of relocs for this section */\n  uint32_t flags;\t\t\t/* Flags */\n  uint32_t reserved1;\n  uint32_t reserved2;\n};\n\n/* 64-bit section header within a LC_SEGMENT_64 segment.   */\n\nstruct macho_section_64\n{\n  char sectname[MACH_O_NAMELEN];\t/* Section name */\n  char segment[MACH_O_NAMELEN];\t\t/* Segment of this section */\n  uint64_t addr;\t\t\t/* Address in memory */\n  uint64_t size;\t\t\t/* Section size */\n  uint32_t offset;\t\t\t/* File offset */\n  uint32_t align;\t\t\t/* Log2 of section alignment */\n  uint32_t reloff;\t\t\t/* File offset of section relocations */\n  uint32_t nreloc;\t\t\t/* Number of relocs for this section */\n  uint32_t flags;\t\t\t/* Flags */\n  uint32_t reserved1;\n  uint32_t reserved2;\n  uint32_t reserved3;\n};\n\n/* 32-bit symbol data.  */\n\nstruct macho_nlist\n{\n  uint32_t n_strx;\t/* Index of name in string table */\n  uint8_t n_type;\t/* Type flag */\n  uint8_t n_sect;\t/* Section number */\n  uint16_t n_desc;\t/* Stabs description field */\n  uint32_t n_value;\t/* Value */\n};\n\n/* 64-bit symbol data.  */\n\nstruct macho_nlist_64\n{\n  uint32_t n_strx;\t/* Index of name in string table */\n  uint8_t n_type;\t/* Type flag */\n  uint8_t n_sect;\t/* Section number */\n  uint16_t n_desc;\t/* Stabs description field */\n  uint64_t n_value;\t/* Value */\n};\n\n/* Value found in nlist n_type field.  */\n\n#define MACH_O_N_STAB\t0xe0\t/* Stabs debugging symbol */\n#define MACH_O_N_TYPE\t0x0e\t/* Mask for type bits */\n\n/* Values found after masking with MACH_O_N_TYPE.  */\n#define MACH_O_N_UNDF\t0x00\t/* Undefined symbol */\n#define MACH_O_N_ABS\t0x02\t/* Absolute symbol */\n#define MACH_O_N_SECT\t0x0e\t/* Defined in section from n_sect field */\n\n\n/* Information we keep for a Mach-O symbol.  */\n\nstruct macho_symbol\n{\n  const char *name;\t/* Symbol name */\n  uintptr_t address;\t/* Symbol address */\n};\n\n/* Information to pass to macho_syminfo.  */\n\nstruct macho_syminfo_data\n{\n  struct macho_syminfo_data *next;\t/* Next module */\n  struct macho_symbol *symbols;\t\t/* Symbols sorted by address */\n  size_t count;\t\t\t\t/* Number of symbols */\n};\n\n/* Names of sections, indexed by enum dwarf_section in internal.h.  */\n\nstatic const char * const dwarf_section_names[DEBUG_MAX] =\n{\n  \"__debug_info\",\n  \"__debug_line\",\n  \"__debug_abbrev\",\n  \"__debug_ranges\",\n  \"__debug_str\",\n  \"__debug_addr\",\n  \"__debug_str_offs\",\n  \"__debug_line_str\",\n  \"__debug_rnglists\"\n};\n\n/* Forward declaration.  */\n\nstatic int macho_add (struct backtrace_state *, const char *, int, off_t,\n\t\t      const unsigned char *, struct libbacktrace_base_address,\n\t\t      int, backtrace_error_callback, void *, fileline *,\n\t\t      int *);\n\n/* A dummy callback function used when we can't find any debug info.  */\n\nstatic int\nmacho_nodebug (struct backtrace_state *state ATTRIBUTE_UNUSED,\n\t       uintptr_t pc ATTRIBUTE_UNUSED,\n\t       backtrace_full_callback callback ATTRIBUTE_UNUSED,\n\t       backtrace_error_callback error_callback, void *data)\n{\n  error_callback (data, \"no debug info in Mach-O executable\", -1);\n  return 0;\n}\n\n/* A dummy callback function used when we can't find a symbol\n   table.  */\n\nstatic void\nmacho_nosyms (struct backtrace_state *state ATTRIBUTE_UNUSED,\n\t      uintptr_t addr ATTRIBUTE_UNUSED,\n\t      backtrace_syminfo_callback callback ATTRIBUTE_UNUSED,\n\t      backtrace_error_callback error_callback, void *data)\n{\n  error_callback (data, \"no symbol table in Mach-O executable\", -1);\n}\n\n/* Add a single DWARF section to DWARF_SECTIONS, if we need the\n   section.  Returns 1 on success, 0 on failure.  */\n\nstatic int\nmacho_add_dwarf_section (struct backtrace_state *state, int descriptor,\n\t\t\t const char *sectname, uint32_t offset, uint64_t size,\n\t\t\t backtrace_error_callback error_callback, void *data,\n\t\t\t struct dwarf_sections *dwarf_sections)\n{\n  int i;\n\n  for (i = 0; i < (int) DEBUG_MAX; ++i)\n    {\n      if (dwarf_section_names[i][0] != '\\0'\n\t  && strncmp (sectname, dwarf_section_names[i], MACH_O_NAMELEN) == 0)\n\t{\n\t  struct backtrace_view section_view;\n\n\t  /* FIXME: Perhaps it would be better to try to use a single\n\t     view to read all the DWARF data, as we try to do for\n\t     ELF.  */\n\n\t  if (!backtrace_get_view (state, descriptor, offset, size,\n\t\t\t\t   error_callback, data, &section_view))\n\t    return 0;\n\t  dwarf_sections->data[i] = (const unsigned char *) section_view.data;\n\t  dwarf_sections->size[i] = size;\n\t  break;\n\t}\n    }\n  return 1;\n}\n\n/* Collect DWARF sections from a DWARF segment.  Returns 1 on success,\n   0 on failure.  */\n\nstatic int\nmacho_add_dwarf_segment (struct backtrace_state *state, int descriptor,\n\t\t\t off_t offset, unsigned int cmd, const char *psecs,\n\t\t\t size_t sizesecs, unsigned int nsects,\n\t\t\t backtrace_error_callback error_callback, void *data,\n\t\t\t struct dwarf_sections *dwarf_sections)\n{\n  size_t sec_header_size;\n  size_t secoffset;\n  unsigned int i;\n\n  switch (cmd)\n    {\n    case MACH_O_LC_SEGMENT:\n      sec_header_size = sizeof (struct macho_section);\n      break;\n    case MACH_O_LC_SEGMENT_64:\n      sec_header_size = sizeof (struct macho_section_64);\n      break;\n    default:\n      abort ();\n    }\n\n  secoffset = 0;\n  for (i = 0; i < nsects; ++i)\n    {\n      if (secoffset + sec_header_size > sizesecs)\n\t{\n\t  error_callback (data, \"section overflow withing segment\", 0);\n\t  return 0;\n\t}\n\n      switch (cmd)\n\t{\n\tcase MACH_O_LC_SEGMENT:\n\t  {\n\t    struct macho_section section;\n\n\t    memcpy (&section, psecs + secoffset, sizeof section);\n\t    macho_add_dwarf_section (state, descriptor, section.sectname,\n\t\t\t\t     offset + section.offset, section.size,\n\t\t\t\t     error_callback, data, dwarf_sections);\n\t  }\n\t  break;\n\n\tcase MACH_O_LC_SEGMENT_64:\n\t  {\n\t    struct macho_section_64 section;\n\n\t    memcpy (&section, psecs + secoffset, sizeof section);\n\t    macho_add_dwarf_section (state, descriptor, section.sectname,\n\t\t\t\t     offset + section.offset, section.size,\n\t\t\t\t     error_callback, data, dwarf_sections);\n\t  }\n\t  break;\n\n\tdefault:\n\t  abort ();\n\t}\n\n      secoffset += sec_header_size;\n    }\n\n  return 1;\n}\n\n/* Compare struct macho_symbol for qsort.  */\n\nstatic int\nmacho_symbol_compare (const void *v1, const void *v2)\n{\n  const struct macho_symbol *m1 = (const struct macho_symbol *) v1;\n  const struct macho_symbol *m2 = (const struct macho_symbol *) v2;\n\n  if (m1->address < m2->address)\n    return -1;\n  else if (m1->address > m2->address)\n    return 1;\n  else\n    return 0;\n}\n\n/* Compare an address against a macho_symbol for bsearch.  We allocate\n   one extra entry in the array so that this can safely look at the\n   next entry.  */\n\nstatic int\nmacho_symbol_search (const void *vkey, const void *ventry)\n{\n  const uintptr_t *key = (const uintptr_t *) vkey;\n  const struct macho_symbol *entry = (const struct macho_symbol *) ventry;\n  uintptr_t addr;\n\n  addr = *key;\n  if (addr < entry->address)\n    return -1;\n  else if (entry->name[0] == '\\0'\n\t   && entry->address == ~(uintptr_t) 0)\n    return -1;\n  else if ((entry + 1)->name[0] == '\\0'\n\t   && (entry + 1)->address == ~(uintptr_t) 0)\n    return -1;\n  else if (addr >= (entry + 1)->address)\n    return 1;\n  else\n    return 0;\n}\n\n/* Return whether the symbol type field indicates a symbol table entry\n   that we care about: a function or data symbol.  */\n\nstatic int\nmacho_defined_symbol (uint8_t type)\n{\n  if ((type & MACH_O_N_STAB) != 0)\n    return 0;\n  switch (type & MACH_O_N_TYPE)\n    {\n    case MACH_O_N_UNDF:\n      return 0;\n    case MACH_O_N_ABS:\n      return 1;\n    case MACH_O_N_SECT:\n      return 1;\n    default:\n      return 0;\n    }\n}\n\n/* Add symbol table information for a Mach-O file.  */\n\nstatic int\nmacho_add_symtab (struct backtrace_state *state, int descriptor,\n\t\t  struct libbacktrace_base_address base_address, int is_64,\n\t\t  off_t symoff, unsigned int nsyms, off_t stroff,\n\t\t  unsigned int strsize,\n\t\t  backtrace_error_callback error_callback, void *data)\n{\n  size_t symsize;\n  struct backtrace_view sym_view;\n  int sym_view_valid;\n  struct backtrace_view str_view;\n  int str_view_valid;\n  size_t ndefs;\n  size_t symtaboff;\n  unsigned int i;\n  size_t macho_symbol_size;\n  struct macho_symbol *macho_symbols;\n  unsigned int j;\n  struct macho_syminfo_data *sdata;\n\n  sym_view_valid = 0;\n  str_view_valid = 0;\n  macho_symbol_size = 0;\n  macho_symbols = NULL;\n\n  if (is_64)\n    symsize = sizeof (struct macho_nlist_64);\n  else\n    symsize = sizeof (struct macho_nlist);\n\n  if (!backtrace_get_view (state, descriptor, symoff, nsyms * symsize,\n\t\t\t   error_callback, data, &sym_view))\n    goto fail;\n  sym_view_valid = 1;\n\n  if (!backtrace_get_view (state, descriptor, stroff, strsize,\n\t\t\t   error_callback, data, &str_view))\n    return 0;\n  str_view_valid = 1;\n\n  ndefs = 0;\n  symtaboff = 0;\n  for (i = 0; i < nsyms; ++i, symtaboff += symsize)\n    {\n      if (is_64)\n\t{\n\t  struct macho_nlist_64 nlist;\n\n\t  memcpy (&nlist, (const char *) sym_view.data + symtaboff,\n\t\t  sizeof nlist);\n\t  if (macho_defined_symbol (nlist.n_type))\n\t    ++ndefs;\n\t}\n      else\n\t{\n\t  struct macho_nlist nlist;\n\n\t  memcpy (&nlist, (const char *) sym_view.data + symtaboff,\n\t\t  sizeof nlist);\n\t  if (macho_defined_symbol (nlist.n_type))\n\t    ++ndefs;\n\t}\n    }\n\n  /* Add 1 to ndefs to make room for a sentinel.  */\n  macho_symbol_size = (ndefs + 1) * sizeof (struct macho_symbol);\n  macho_symbols = ((struct macho_symbol *)\n\t\t   backtrace_alloc (state, macho_symbol_size, error_callback,\n\t\t\t\t    data));\n  if (macho_symbols == NULL)\n    goto fail;\n\n  j = 0;\n  symtaboff = 0;\n  for (i = 0; i < nsyms; ++i, symtaboff += symsize)\n    {\n      uint32_t strx;\n      uint64_t value;\n      const char *name;\n\n      strx = 0;\n      value = 0;\n      if (is_64)\n\t{\n\t  struct macho_nlist_64 nlist;\n\n\t  memcpy (&nlist, (const char *) sym_view.data + symtaboff,\n\t\t  sizeof nlist);\n\t  if (!macho_defined_symbol (nlist.n_type))\n\t    continue;\n\n\t  strx = nlist.n_strx;\n\t  value = nlist.n_value;\n\t}\n      else\n\t{\n\t  struct macho_nlist nlist;\n\n\t  memcpy (&nlist, (const char *) sym_view.data + symtaboff,\n\t\t  sizeof nlist);\n\t  if (!macho_defined_symbol (nlist.n_type))\n\t    continue;\n\n\t  strx = nlist.n_strx;\n\t  value = nlist.n_value;\n\t}\n\n      if (strx >= strsize)\n\t{\n\t  error_callback (data, \"symbol string index out of range\", 0);\n\t  goto fail;\n\t}\n\n      name = (const char *) str_view.data + strx;\n      if (name[0] == '_')\n\t++name;\n      macho_symbols[j].name = name;\n      macho_symbols[j].address = libbacktrace_add_base (value, base_address);\n      ++j;\n    }\n\n  sdata = ((struct macho_syminfo_data *)\n\t   backtrace_alloc (state, sizeof *sdata, error_callback, data));\n  if (sdata == NULL)\n    goto fail;\n\n  /* We need to keep the string table since it holds the names, but we\n     can release the symbol table.  */\n\n  backtrace_release_view (state, &sym_view, error_callback, data);\n  sym_view_valid = 0;\n  str_view_valid = 0;\n\n  /* Add a trailing sentinel symbol.  */\n  macho_symbols[j].name = \"\";\n  macho_symbols[j].address = ~(uintptr_t) 0;\n\n  backtrace_qsort (macho_symbols, ndefs + 1, sizeof (struct macho_symbol),\n\t\t   macho_symbol_compare);\n\n  sdata->next = NULL;\n  sdata->symbols = macho_symbols;\n  sdata->count = ndefs;\n\n  if (!state->threaded)\n    {\n      struct macho_syminfo_data **pp;\n\n      for (pp = (struct macho_syminfo_data **) (void *) &state->syminfo_data;\n\t   *pp != NULL;\n\t   pp = &(*pp)->next)\n\t;\n      *pp = sdata;\n    }\n  else\n    {\n      while (1)\n\t{\n\t  struct macho_syminfo_data **pp;\n\n\t  pp = (struct macho_syminfo_data **) (void *) &state->syminfo_data;\n\n\t  while (1)\n\t    {\n\t      struct macho_syminfo_data *p;\n\n\t      p = backtrace_atomic_load_pointer (pp);\n\t      \n\t      if (p == NULL)\n\t\tbreak;\n\n\t      pp = &p->next;\n\t    }\n\n\t  if (__sync_bool_compare_and_swap (pp, NULL, sdata))\n\t    break;\n\t}\n    }\n\n  return 1;\n\n fail:\n  if (macho_symbols != NULL)\n    backtrace_free (state, macho_symbols, macho_symbol_size,\n\t\t    error_callback, data);\n  if (sym_view_valid)\n    backtrace_release_view (state, &sym_view, error_callback, data);\n  if (str_view_valid)\n    backtrace_release_view (state, &str_view, error_callback, data);\n  return 0;\n}\n\n/* Return the symbol name and value for an ADDR.  */\n\nstatic void\nmacho_syminfo (struct backtrace_state *state, uintptr_t addr,\n\t       backtrace_syminfo_callback callback,\n\t       backtrace_error_callback error_callback ATTRIBUTE_UNUSED,\n\t       void *data)\n{\n  struct macho_syminfo_data *sdata;\n  struct macho_symbol *sym;\n\n  sym = NULL;\n  if (!state->threaded)\n    {\n      for (sdata = (struct macho_syminfo_data *) state->syminfo_data;\n\t   sdata != NULL;\n\t   sdata = sdata->next)\n\t{\n\t  sym = ((struct macho_symbol *)\n\t\t bsearch (&addr, sdata->symbols, sdata->count,\n\t\t\t  sizeof (struct macho_symbol), macho_symbol_search));\n\t  if (sym != NULL)\n\t    break;\n\t}\n    }\n  else\n    {\n      struct macho_syminfo_data **pp;\n\n      pp = (struct macho_syminfo_data **) (void *) &state->syminfo_data;\n      while (1)\n\t{\n\t  sdata = backtrace_atomic_load_pointer (pp);\n\t  if (sdata == NULL)\n\t    break;\n\n\t  sym = ((struct macho_symbol *)\n\t\t bsearch (&addr, sdata->symbols, sdata->count,\n\t\t\t  sizeof (struct macho_symbol), macho_symbol_search));\n\t  if (sym != NULL)\n\t    break;\n\n\t  pp = &sdata->next;\n\t}\n    }\n\n  if (sym == NULL)\n    callback (data, addr, NULL, 0, 0);\n  else\n    callback (data, addr, sym->name, sym->address, 0);\n}\n\n/* Look through a fat file to find the relevant executable.  Returns 1\n   on success, 0 on failure (in both cases descriptor is closed).  */\n\nstatic int\nmacho_add_fat (struct backtrace_state *state, const char *filename,\n\t       int descriptor, int swapped, off_t offset,\n\t       const unsigned char *match_uuid,\n\t       struct libbacktrace_base_address base_address,\n\t       int skip_symtab, uint32_t nfat_arch, int is_64,\n\t       backtrace_error_callback error_callback, void *data,\n\t       fileline *fileline_fn, int *found_sym)\n{\n  int arch_view_valid;\n  unsigned int cputype;\n  size_t arch_size;\n  struct backtrace_view arch_view;\n  unsigned int i;\n\n  arch_view_valid = 0;\n\n#if defined (__x86_64__)\n  cputype = MACH_O_CPU_TYPE_X86_64;\n#elif defined (__i386__)\n  cputype = MACH_O_CPU_TYPE_X86;\n#elif defined (__aarch64__)\n  cputype = MACH_O_CPU_TYPE_ARM64;\n#elif defined (__arm__)\n  cputype = MACH_O_CPU_TYPE_ARM;\n#elif defined (__ppc__)\n  cputype = MACH_O_CPU_TYPE_PPC;\n#elif defined (__ppc64__)\n  cputype = MACH_O_CPU_TYPE_PPC64;\n#else\n  error_callback (data, \"unknown Mach-O architecture\", 0);\n  goto fail;\n#endif\n\n  if (is_64)\n    arch_size = sizeof (struct macho_fat_arch_64);\n  else\n    arch_size = sizeof (struct macho_fat_arch);\n\n  if (!backtrace_get_view (state, descriptor, offset,\n\t\t\t   nfat_arch * arch_size,\n\t\t\t   error_callback, data, &arch_view))\n    goto fail;\n\n  for (i = 0; i < nfat_arch; ++i)\n    {\n      uint32_t fcputype;\n      uint64_t foffset;\n\n      if (is_64)\n\t{\n\t  struct macho_fat_arch_64 fat_arch_64;\n\n\t  memcpy (&fat_arch_64,\n\t\t  (const char *) arch_view.data + i * arch_size,\n\t\t  arch_size);\n\t  fcputype = fat_arch_64.cputype;\n\t  foffset = fat_arch_64.offset;\n\t  if (swapped)\n\t    {\n\t      fcputype = __builtin_bswap32 (fcputype);\n\t      foffset = __builtin_bswap64 (foffset);\n\t    }\n\t}\n      else\n\t{\n\t  struct macho_fat_arch fat_arch_32;\n\n\t  memcpy (&fat_arch_32,\n\t\t  (const char *) arch_view.data + i * arch_size,\n\t\t  arch_size);\n\t  fcputype = fat_arch_32.cputype;\n\t  foffset = (uint64_t) fat_arch_32.offset;\n\t  if (swapped)\n\t    {\n\t      fcputype = __builtin_bswap32 (fcputype);\n\t      foffset = (uint64_t) __builtin_bswap32 ((uint32_t) foffset);\n\t    }\n\t}\n\n      if (fcputype == cputype)\n\t{\n\t  /* FIXME: What about cpusubtype?  */\n\t  backtrace_release_view (state, &arch_view, error_callback, data);\n\t  return macho_add (state, filename, descriptor, foffset, match_uuid,\n\t\t\t    base_address, skip_symtab, error_callback, data,\n\t\t\t    fileline_fn, found_sym);\n\t}\n    }\n\n  error_callback (data, \"could not find executable in fat file\", 0);\n\n fail:\n  if (arch_view_valid)\n    backtrace_release_view (state, &arch_view, error_callback, data);\n  if (descriptor != -1)\n    backtrace_close (descriptor, error_callback, data);\n  return 0;\n}\n\n/* Look for the dsym file for FILENAME.  This is called if FILENAME\n   does not have debug info or a symbol table.  Returns 1 on success,\n   0 on failure.  */\n\nstatic int\nmacho_add_dsym (struct backtrace_state *state, const char *filename,\n\t\tstruct libbacktrace_base_address base_address,\n\t\tconst unsigned char *uuid,\n\t\tbacktrace_error_callback error_callback, void *data,\n\t\tfileline* fileline_fn)\n{\n  const char *p;\n  const char *dirname;\n  char *diralc;\n  size_t dirnamelen;\n  const char *basename;\n  size_t basenamelen;\n  const char *dsymsuffixdir;\n  size_t dsymsuffixdirlen;\n  size_t dsymlen;\n  char *dsym;\n  char *ps;\n  int d;\n  int does_not_exist;\n  int dummy_found_sym;\n\n  diralc = NULL;\n  dirnamelen = 0;\n  dsym = NULL;\n  dsymlen = 0;\n\n  p = strrchr (filename, '/');\n  if (p == NULL)\n    {\n      dirname = \".\";\n      dirnamelen = 1;\n      basename = filename;\n      basenamelen = strlen (basename);\n      diralc = NULL;\n    }\n  else\n    {\n      dirnamelen = p - filename;\n      diralc = (char*)backtrace_alloc (state, dirnamelen + 1, error_callback, data);\n      if (diralc == NULL)\n\tgoto fail;\n      memcpy (diralc, filename, dirnamelen);\n      diralc[dirnamelen] = '\\0';\n      dirname = diralc;\n      basename = p + 1;\n      basenamelen = strlen (basename);\n    }\n\n  dsymsuffixdir = \".dSYM/Contents/Resources/DWARF/\";\n  dsymsuffixdirlen = strlen (dsymsuffixdir);\n\n  dsymlen = (dirnamelen\n\t     + 1\n\t     + basenamelen\n\t     + dsymsuffixdirlen\n\t     + basenamelen\n\t     + 1);\n  dsym = (char*)backtrace_alloc (state, dsymlen, error_callback, data);\n  if (dsym == NULL)\n    goto fail;\n\n  ps = dsym;\n  memcpy (ps, dirname, dirnamelen);\n  ps += dirnamelen;\n  *ps++ = '/';\n  memcpy (ps, basename, basenamelen);\n  ps += basenamelen;\n  memcpy (ps, dsymsuffixdir, dsymsuffixdirlen);\n  ps += dsymsuffixdirlen;\n  memcpy (ps, basename, basenamelen);\n  ps += basenamelen;\n  *ps = '\\0';\n\n  if (diralc != NULL)\n    {\n      backtrace_free (state, diralc, dirnamelen + 1, error_callback, data);\n      diralc = NULL;\n    }\n\n  d = backtrace_open (dsym, error_callback, data, &does_not_exist);\n  if (d < 0)\n    {\n      /* The file does not exist, so we can't read the debug info.\n\t Just return success.  */\n      backtrace_free (state, dsym, dsymlen, error_callback, data);\n      return 1;\n    }\n\n  if (!macho_add (state, dsym, d, 0, uuid, base_address, 1,\n\t\t  error_callback, data, fileline_fn, &dummy_found_sym))\n    goto fail;\n\n  backtrace_free (state, dsym, dsymlen, error_callback, data);\n\n  return 1;\n\n fail:\n  if (dsym != NULL)\n    backtrace_free (state, dsym, dsymlen, error_callback, data);\n  if (diralc != NULL)\n    backtrace_free (state, diralc, dirnamelen, error_callback, data);\n  return 0;\n}\n\n/* Add the backtrace data for a Macho-O file.  Returns 1 on success, 0\n   on failure (in both cases descriptor is closed).\n\n   FILENAME: the name of the executable.\n   DESCRIPTOR: an open descriptor for the executable, closed here.\n   OFFSET: the offset within the file of this executable, for fat files.\n   MATCH_UUID: if not NULL, UUID that must match.\n   BASE_ADDRESS: the load address of the executable.\n   SKIP_SYMTAB: if non-zero, ignore the symbol table; used for dSYM files.\n   FILELINE_FN: set to the fileline function, by backtrace_dwarf_add.\n   FOUND_SYM: set to non-zero if we found the symbol table.\n*/\n\nstatic int\nmacho_add (struct backtrace_state *state, const char *filename, int descriptor,\n\t   off_t offset, const unsigned char *match_uuid,\n\t   struct libbacktrace_base_address base_address, int skip_symtab,\n\t   backtrace_error_callback error_callback, void *data,\n\t   fileline *fileline_fn, int *found_sym)\n{\n  struct backtrace_view header_view;\n  struct macho_header_32 header;\n  off_t hdroffset;\n  int is_64;\n  struct backtrace_view cmds_view;\n  int cmds_view_valid;\n  struct dwarf_sections dwarf_sections;\n  int have_dwarf;\n  unsigned char uuid[MACH_O_UUID_LEN];\n  int have_uuid;\n  size_t cmdoffset;\n  unsigned int i;\n\n  *found_sym = 0;\n\n  cmds_view_valid = 0;\n\n  /* The 32-bit and 64-bit file headers start out the same, so we can\n     just always read the 32-bit version.  A fat header is shorter but\n     it will always be followed by data, so it's OK to read extra.  */\n\n  if (!backtrace_get_view (state, descriptor, offset,\n\t\t\t   sizeof (struct macho_header_32),\n\t\t\t   error_callback, data, &header_view))\n    goto fail;\n\n  memcpy (&header, header_view.data, sizeof header);\n\n  backtrace_release_view (state, &header_view, error_callback, data);\n\n  switch (header.magic)\n    {\n    case MACH_O_MH_MAGIC_32:\n      is_64 = 0;\n      hdroffset = offset + sizeof (struct macho_header_32);\n      break;\n    case MACH_O_MH_MAGIC_64:\n      is_64 = 1;\n      hdroffset = offset + sizeof (struct macho_header_64);\n      break;\n    case MACH_O_MH_MAGIC_FAT:\n    case MACH_O_MH_MAGIC_FAT_64:\n      {\n\tstruct macho_header_fat fat_header;\n\n\thdroffset = offset + sizeof (struct macho_header_fat);\n\tmemcpy (&fat_header, &header, sizeof fat_header);\n\treturn macho_add_fat (state, filename, descriptor, 0, hdroffset,\n\t\t\t      match_uuid, base_address, skip_symtab,\n\t\t\t      fat_header.nfat_arch,\n\t\t\t      header.magic == MACH_O_MH_MAGIC_FAT_64,\n\t\t\t      error_callback, data, fileline_fn, found_sym);\n      }\n    case MACH_O_MH_CIGAM_FAT:\n    case MACH_O_MH_CIGAM_FAT_64:\n      {\n\tstruct macho_header_fat fat_header;\n\tuint32_t nfat_arch;\n\n\thdroffset = offset + sizeof (struct macho_header_fat);\n\tmemcpy (&fat_header, &header, sizeof fat_header);\n\tnfat_arch = __builtin_bswap32 (fat_header.nfat_arch);\n\treturn macho_add_fat (state, filename, descriptor, 1, hdroffset,\n\t\t\t      match_uuid, base_address, skip_symtab,\n\t\t\t      nfat_arch,\n\t\t\t      header.magic == MACH_O_MH_CIGAM_FAT_64,\n\t\t\t      error_callback, data, fileline_fn, found_sym);\n      }\n    default:\n      error_callback (data, \"executable file is not in Mach-O format\", 0);\n      goto fail;\n    }\n\n  switch (header.filetype)\n    {\n    case MACH_O_MH_EXECUTE:\n    case MACH_O_MH_DYLIB:\n    case MACH_O_MH_DSYM:\n      break;\n    default:\n      error_callback (data, \"executable file is not an executable\", 0);\n      goto fail;\n    }\n\n  if (!backtrace_get_view (state, descriptor, hdroffset, header.sizeofcmds,\n\t\t\t   error_callback, data, &cmds_view))\n    goto fail;\n  cmds_view_valid = 1;\n\n  memset (&dwarf_sections, 0, sizeof dwarf_sections);\n  have_dwarf = 0;\n  memset (&uuid, 0, sizeof uuid);\n  have_uuid = 0;\n\n  cmdoffset = 0;\n  for (i = 0; i < header.ncmds; ++i)\n    {\n      const char *pcmd;\n      struct macho_load_command load_command;\n\n      if (cmdoffset + sizeof load_command > header.sizeofcmds)\n\tbreak;\n\n      pcmd = (const char *) cmds_view.data + cmdoffset;\n      memcpy (&load_command, pcmd, sizeof load_command);\n\n      switch (load_command.cmd)\n\t{\n\tcase MACH_O_LC_SEGMENT:\n\t  {\n\t    struct macho_segment_command segcmd;\n\n\t    memcpy (&segcmd, pcmd, sizeof segcmd);\n\t    if (memcmp (segcmd.segname,\n\t\t\t\"__DWARF\\0\\0\\0\\0\\0\\0\\0\\0\\0\",\n\t\t\tMACH_O_NAMELEN) == 0)\n\t      {\n\t\tif (!macho_add_dwarf_segment (state, descriptor, offset,\n\t\t\t\t\t      load_command.cmd,\n\t\t\t\t\t      pcmd + sizeof segcmd,\n\t\t\t\t\t      (load_command.cmdsize\n\t\t\t\t\t       - sizeof segcmd),\n\t\t\t\t\t      segcmd.nsects, error_callback,\n\t\t\t\t\t      data, &dwarf_sections))\n\t\t  goto fail;\n\t\thave_dwarf = 1;\n\t      }\n\t  }\n\t  break;\n\n\tcase MACH_O_LC_SEGMENT_64:\n\t  {\n\t    struct macho_segment_64_command segcmd;\n\n\t    memcpy (&segcmd, pcmd, sizeof segcmd);\n\t    if (memcmp (segcmd.segname,\n\t\t\t\"__DWARF\\0\\0\\0\\0\\0\\0\\0\\0\\0\",\n\t\t\tMACH_O_NAMELEN) == 0)\n\t      {\n\t\tif (!macho_add_dwarf_segment (state, descriptor, offset,\n\t\t\t\t\t      load_command.cmd,\n\t\t\t\t\t      pcmd + sizeof segcmd,\n\t\t\t\t\t      (load_command.cmdsize\n\t\t\t\t\t       - sizeof segcmd),\n\t\t\t\t\t      segcmd.nsects, error_callback,\n\t\t\t\t\t      data, &dwarf_sections))\n\t\t  goto fail;\n\t\thave_dwarf = 1;\n\t      }\n\t  }\n\t  break;\n\n\tcase MACH_O_LC_SYMTAB:\n\t  if (!skip_symtab)\n\t    {\n\t      struct macho_symtab_command symcmd;\n\n\t      memcpy (&symcmd, pcmd, sizeof symcmd);\n\t      if (!macho_add_symtab (state, descriptor, base_address, is_64,\n\t\t\t\t     offset + symcmd.symoff, symcmd.nsyms,\n\t\t\t\t     offset + symcmd.stroff, symcmd.strsize,\n\t\t\t\t     error_callback, data))\n\t\tgoto fail;\n\n\t      *found_sym = 1;\n\t    }\n\t  break;\n\n\tcase MACH_O_LC_UUID:\n\t  {\n\t    struct macho_uuid_command uuidcmd;\n\n\t    memcpy (&uuidcmd, pcmd, sizeof uuidcmd);\n\t    memcpy (&uuid[0], &uuidcmd.uuid[0], MACH_O_UUID_LEN);\n\t    have_uuid = 1;\n\t  }\n\t  break;\n\n\tdefault:\n\t  break;\n\t}\n\n      cmdoffset += load_command.cmdsize;\n    }\n\n  if (!backtrace_close (descriptor, error_callback, data))\n    goto fail;\n  descriptor = -1;\n\n  backtrace_release_view (state, &cmds_view, error_callback, data);\n  cmds_view_valid = 0;\n\n  if (match_uuid != NULL)\n    {\n      /* If we don't have a UUID, or it doesn't match, just ignore\n\t this file.  */\n      if (!have_uuid\n\t  || memcmp (match_uuid, &uuid[0], MACH_O_UUID_LEN) != 0)\n\treturn 1;\n    }\n\n  if (have_dwarf)\n    {\n      int is_big_endian;\n\n      is_big_endian = 0;\n#if defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__)\n#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__\n      is_big_endian = 1;\n#endif\n#endif\n\n      if (!backtrace_dwarf_add (state, base_address, &dwarf_sections,\n\t\t\t\tis_big_endian, NULL, error_callback, data,\n\t\t\t\tfileline_fn, NULL))\n\tgoto fail;\n    }\n\n  if (!have_dwarf && have_uuid)\n    {\n      if (!macho_add_dsym (state, filename, base_address, &uuid[0],\n\t\t\t   error_callback, data, fileline_fn))\n\tgoto fail;\n    }\n\n  return 1;\n\n fail:\n  if (cmds_view_valid)\n    backtrace_release_view (state, &cmds_view, error_callback, data);\n  if (descriptor != -1)\n    backtrace_close (descriptor, error_callback, data);\n  return 0;\n}\n\n#ifdef HAVE_MACH_O_DYLD_H\n\n/* Initialize the backtrace data we need from a Mach-O executable\n   using the dyld support functions.  This closes descriptor.  */\n\nint\nbacktrace_initialize (struct backtrace_state *state, const char *filename,\n\t\t      int descriptor, backtrace_error_callback error_callback,\n\t\t      void *data, fileline *fileline_fn)\n{\n  uint32_t c;\n  uint32_t i;\n  int closed_descriptor;\n  int found_sym;\n  fileline macho_fileline_fn;\n\n  closed_descriptor = 0;\n  found_sym = 0;\n  macho_fileline_fn = macho_nodebug;\n\n  c = _dyld_image_count ();\n  for (i = 0; i < c; ++i)\n    {\n      struct libbacktrace_base_address base_address;\n      const char *name;\n      int d;\n      fileline mff;\n      int mfs;\n\n      name = _dyld_get_image_name (i);\n      if (name == NULL)\n\tcontinue;\n\n      if (strcmp (name, filename) == 0 && !closed_descriptor)\n\t{\n\t  d = descriptor;\n\t  closed_descriptor = 1;\n\t}\n      else\n\t{\n\t  int does_not_exist;\n\n\t  d = backtrace_open (name, error_callback, data, &does_not_exist);\n\t  if (d < 0)\n\t    continue;\n\t}\n\n      base_address.m = _dyld_get_image_vmaddr_slide (i);\n\n      mff = macho_nodebug;\n      if (!macho_add (state, name, d, 0, NULL, base_address, 0,\n\t\t      error_callback, data, &mff, &mfs))\n\tcontinue;\n\n      if (mff != macho_nodebug)\n\tmacho_fileline_fn = mff;\n      if (mfs)\n\tfound_sym = 1;\n    }\n\n  if (!closed_descriptor)\n    backtrace_close (descriptor, error_callback, data);\n\n  if (!state->threaded)\n    {\n      if (found_sym)\n\tstate->syminfo_fn = macho_syminfo;\n      else if (state->syminfo_fn == NULL)\n\tstate->syminfo_fn = macho_nosyms;\n    }\n  else\n    {\n      if (found_sym)\n\tbacktrace_atomic_store_pointer (&state->syminfo_fn, &macho_syminfo);\n      else\n\t(void) __sync_bool_compare_and_swap (&state->syminfo_fn, NULL,\n\t\t\t\t\t     macho_nosyms);\n    }\n\n  if (!state->threaded)\n    *fileline_fn = state->fileline_fn;\n  else\n    *fileline_fn = backtrace_atomic_load_pointer (&state->fileline_fn);\n\n  if (*fileline_fn == NULL || *fileline_fn == macho_nodebug)\n    *fileline_fn = macho_fileline_fn;\n\n  return 1;\n}\n\n#else /* !defined (HAVE_MACH_O_DYLD_H) */\n\n/* Initialize the backtrace data we need from a Mach-O executable\n   without using the dyld support functions.  This closes\n   descriptor.  */\n\nint\nbacktrace_initialize (struct backtrace_state *state, const char *filename,\n\t\t      int descriptor, backtrace_error_callback error_callback,\n\t\t      void *data, fileline *fileline_fn)\n{\n  fileline macho_fileline_fn;\n  struct libbacktrace_base_address zero_base_address;\n  int found_sym;\n\n  macho_fileline_fn = macho_nodebug;\n  memset (&zero_base_address, 0, sizeof zero_base_address);\n  if (!macho_add (state, filename, descriptor, 0, NULL, zero_base_address, 0,\n\t\t  error_callback, data, &macho_fileline_fn, &found_sym))\n    return 0;\n\n  if (!state->threaded)\n    {\n      if (found_sym)\n\tstate->syminfo_fn = macho_syminfo;\n      else if (state->syminfo_fn == NULL)\n\tstate->syminfo_fn = macho_nosyms;\n    }\n  else\n    {\n      if (found_sym)\n\tbacktrace_atomic_store_pointer (&state->syminfo_fn, &macho_syminfo);\n      else\n\t(void) __sync_bool_compare_and_swap (&state->syminfo_fn, NULL,\n\t\t\t\t\t     macho_nosyms);\n    }\n\n  if (!state->threaded)\n    *fileline_fn = state->fileline_fn;\n  else\n    *fileline_fn = backtrace_atomic_load_pointer (&state->fileline_fn);\n\n  if (*fileline_fn == NULL || *fileline_fn == macho_nodebug)\n    *fileline_fn = macho_fileline_fn;\n\n  return 1;\n}\n\n#endif /* !defined (HAVE_MACH_O_DYLD_H) */\n\n}\n"
  },
  {
    "path": "tracy-client-sys/tracy/libbacktrace/mmapio.cpp",
    "content": "/* mmapio.c -- File views using mmap.\n   Copyright (C) 2012-2021 Free Software Foundation, Inc.\n   Written by Ian Lance Taylor, Google.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n    (1) Redistributions of source code must retain the above copyright\n    notice, this list of conditions and the following disclaimer.\n\n    (2) Redistributions in binary form must reproduce the above copyright\n    notice, this list of conditions and the following disclaimer in\n    the documentation and/or other materials provided with the\n    distribution.\n\n    (3) The name of the author may not be used to\n    endorse or promote products derived from this software without\n    specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\nIMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\nWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,\nINDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\nHOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\nSTRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\nIN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGE.  */\n\n#include \"config.h\"\n\n#include <errno.h>\n#include <sys/types.h>\n#include <sys/mman.h>\n#include <unistd.h>\n\n#include \"backtrace.hpp\"\n#include \"internal.hpp\"\n\n#ifndef HAVE_DECL_GETPAGESIZE\nextern int getpagesize (void);\n#endif\n\n#ifndef MAP_FAILED\n#define MAP_FAILED ((void *)-1)\n#endif\n\nnamespace tracy\n{\n\n/* This file implements file views and memory allocation when mmap is\n   available.  */\n\n/* Create a view of SIZE bytes from DESCRIPTOR at OFFSET.  */\n\nint\nbacktrace_get_view (struct backtrace_state *state ATTRIBUTE_UNUSED,\n\t\t    int descriptor, off_t offset, uint64_t size,\n\t\t    backtrace_error_callback error_callback,\n\t\t    void *data, struct backtrace_view *view)\n{\n  size_t pagesize;\n  unsigned int inpage;\n  off_t pageoff;\n  void *map;\n\n  if ((uint64_t) (size_t) size != size)\n    {\n      error_callback (data, \"file size too large\", 0);\n      return 0;\n    }\n\n  pagesize = getpagesize ();\n  inpage = offset % pagesize;\n  pageoff = offset - inpage;\n\n  size += inpage;\n  size = (size + (pagesize - 1)) & ~ (pagesize - 1);\n\n  map = mmap (NULL, size, PROT_READ, MAP_PRIVATE, descriptor, pageoff);\n  if (map == MAP_FAILED)\n    {\n      error_callback (data, \"mmap\", errno);\n      return 0;\n    }\n\n  view->data = (char *) map + inpage;\n  view->base = map;\n  view->len = size;\n\n  return 1;\n}\n\n/* Release a view read by backtrace_get_view.  */\n\nvoid\nbacktrace_release_view (struct backtrace_state *state ATTRIBUTE_UNUSED,\n\t\t\tstruct backtrace_view *view,\n\t\t\tbacktrace_error_callback error_callback,\n\t\t\tvoid *data)\n{\n  union {\n    const void *cv;\n    void *v;\n  } cc;\n\n  cc.cv = view->base;\n  if (munmap (cc.v, view->len) < 0)\n    error_callback (data, \"munmap\", errno);\n}\n\n}\n"
  },
  {
    "path": "tracy-client-sys/tracy/libbacktrace/posix.cpp",
    "content": "/* posix.c -- POSIX file I/O routines for the backtrace library.\n   Copyright (C) 2012-2021 Free Software Foundation, Inc.\n   Written by Ian Lance Taylor, Google.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n    (1) Redistributions of source code must retain the above copyright\n    notice, this list of conditions and the following disclaimer.\n\n    (2) Redistributions in binary form must reproduce the above copyright\n    notice, this list of conditions and the following disclaimer in\n    the documentation and/or other materials provided with the\n    distribution.\n\n    (3) The name of the author may not be used to\n    endorse or promote products derived from this software without\n    specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\nIMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\nWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,\nINDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\nHOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\nSTRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\nIN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGE.  */\n\n#include \"config.h\"\n\n#include <errno.h>\n#include <sys/types.h>\n#include <sys/stat.h>\n#include <fcntl.h>\n#include <unistd.h>\n\n#include \"backtrace.hpp\"\n#include \"internal.hpp\"\n\n#ifndef O_BINARY\n#define O_BINARY 0\n#endif\n\n#ifndef O_CLOEXEC\n#define O_CLOEXEC 0\n#endif\n\n#ifndef FD_CLOEXEC\n#define FD_CLOEXEC 1\n#endif\n\nnamespace tracy\n{\n\n/* Open a file for reading.  */\n\nint\nbacktrace_open (const char *filename, backtrace_error_callback error_callback,\n\t\tvoid *data, int *does_not_exist)\n{\n  int descriptor;\n\n  if (does_not_exist != NULL)\n    *does_not_exist = 0;\n\n  descriptor = open (filename, (int) (O_RDONLY | O_BINARY | O_CLOEXEC));\n  if (descriptor < 0)\n    {\n      /* If DOES_NOT_EXIST is not NULL, then don't call ERROR_CALLBACK\n\t if the file does not exist.  We treat lacking permission to\n\t open the file as the file not existing; this case arises when\n\t running the libgo syscall package tests as root.  */\n      if (does_not_exist != NULL && (errno == ENOENT || errno == EACCES))\n\t*does_not_exist = 1;\n      else\n\terror_callback (data, filename, errno);\n      return -1;\n    }\n\n#ifdef HAVE_FCNTL\n  /* Set FD_CLOEXEC just in case the kernel does not support\n     O_CLOEXEC. It doesn't matter if this fails for some reason.\n     FIXME: At some point it should be safe to only do this if\n     O_CLOEXEC == 0.  */\n  fcntl (descriptor, F_SETFD, FD_CLOEXEC);\n#endif\n\n  return descriptor;\n}\n\n/* Close DESCRIPTOR.  */\n\nint\nbacktrace_close (int descriptor, backtrace_error_callback error_callback,\n\t\t void *data)\n{\n  if (close (descriptor) < 0)\n    {\n      error_callback (data, \"close\", errno);\n      return 0;\n    }\n  return 1;\n}\n\n}\n"
  },
  {
    "path": "tracy-client-sys/tracy/libbacktrace/sort.cpp",
    "content": "/* sort.c -- Sort without allocating memory\n   Copyright (C) 2012-2021 Free Software Foundation, Inc.\n   Written by Ian Lance Taylor, Google.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n    (1) Redistributions of source code must retain the above copyright\n    notice, this list of conditions and the following disclaimer.\n\n    (2) Redistributions in binary form must reproduce the above copyright\n    notice, this list of conditions and the following disclaimer in\n    the documentation and/or other materials provided with the\n    distribution.\n\n    (3) The name of the author may not be used to\n    endorse or promote products derived from this software without\n    specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\nIMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\nWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,\nINDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\nHOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\nSTRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\nIN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGE.  */\n\n#include \"config.h\"\n\n#include <stddef.h>\n#include <sys/types.h>\n\n#include \"backtrace.hpp\"\n#include \"internal.hpp\"\n\nnamespace tracy\n{\n\n/* The GNU glibc version of qsort allocates memory, which we must not\n   do if we are invoked by a signal handler.  So provide our own\n   sort.  */\n\nstatic void\nswap (char *a, char *b, size_t size)\n{\n  size_t i;\n\n  for (i = 0; i < size; i++, a++, b++)\n    {\n      char t;\n\n      t = *a;\n      *a = *b;\n      *b = t;\n    }\n}\n\nvoid\nbacktrace_qsort (void *basearg, size_t count, size_t size,\n\t\t int (*compar) (const void *, const void *))\n{\n  char *base = (char *) basearg;\n  size_t i;\n  size_t mid;\n\n tail_recurse:\n  if (count < 2)\n    return;\n\n  /* The symbol table and DWARF tables, which is all we use this\n     routine for, tend to be roughly sorted.  Pick the middle element\n     in the array as our pivot point, so that we are more likely to\n     cut the array in half for each recursion step.  */\n  swap (base, base + (count / 2) * size, size);\n\n  mid = 0;\n  for (i = 1; i < count; i++)\n    {\n      if ((*compar) (base, base + i * size) > 0)\n\t{\n\t  ++mid;\n\t  if (i != mid)\n\t    swap (base + mid * size, base + i * size, size);\n\t}\n    }\n\n  if (mid > 0)\n    swap (base, base + mid * size, size);\n\n  /* Recurse with the smaller array, loop with the larger one.  That\n     ensures that our maximum stack depth is log count.  */\n  if (2 * mid < count)\n    {\n      backtrace_qsort (base, mid, size, compar);\n      base += (mid + 1) * size;\n      count -= mid + 1;\n      goto tail_recurse;\n    }\n  else\n    {\n      backtrace_qsort (base + (mid + 1) * size, count - (mid + 1),\n\t\t       size, compar);\n      count = mid;\n      goto tail_recurse;\n    }\n}\n\n}\n"
  },
  {
    "path": "tracy-client-sys/tracy/libbacktrace/state.cpp",
    "content": "/* state.c -- Create the backtrace state.\n   Copyright (C) 2012-2021 Free Software Foundation, Inc.\n   Written by Ian Lance Taylor, Google.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n    (1) Redistributions of source code must retain the above copyright\n    notice, this list of conditions and the following disclaimer.\n\n    (2) Redistributions in binary form must reproduce the above copyright\n    notice, this list of conditions and the following disclaimer in\n    the documentation and/or other materials provided with the\n    distribution.\n\n    (3) The name of the author may not be used to\n    endorse or promote products derived from this software without\n    specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\nIMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\nWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,\nINDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\nHOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\nSTRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\nIN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGE.  */\n\n#include \"config.h\"\n\n#include <string.h>\n#include <sys/types.h>\n\n#include \"backtrace.hpp\"\n#include \"internal.hpp\"\n\nnamespace tracy\n{\n\n/* Create the backtrace state.  This will then be passed to all the\n   other routines.  */\n\nstruct backtrace_state *\nbacktrace_create_state (const char *filename, int threaded,\n\t\t\tbacktrace_error_callback error_callback,\n\t\t\tvoid *data)\n{\n  struct backtrace_state init_state;\n  struct backtrace_state *state;\n\n#ifndef HAVE_SYNC_FUNCTIONS\n  if (threaded)\n    {\n      error_callback (data, \"backtrace library does not support threads\", 0);\n      return NULL;\n    }\n#endif\n\n  memset (&init_state, 0, sizeof init_state);\n  init_state.filename = filename;\n  init_state.threaded = threaded;\n\n  state = ((struct backtrace_state *)\n\t   backtrace_alloc (&init_state, sizeof *state, error_callback, data));\n  if (state == NULL)\n    return NULL;\n  *state = init_state;\n\n  return state;\n}\n\n}\n"
  },
  {
    "path": "tracy-client-sys/tracy/tracy/Tracy.hpp",
    "content": "#ifndef __TRACY_HPP__\n#define __TRACY_HPP__\n\n#include \"../common/TracyColor.hpp\"\n#include \"../common/TracySystem.hpp\"\n\n#ifndef TracyFunction\n#  define TracyFunction __FUNCTION__\n#endif\n\n#ifndef TracyFile\n#  define TracyFile __FILE__\n#endif\n\n#ifndef TracyLine\n#  define TracyLine TracyConcat(__LINE__,U) // MSVC Edit and continue __LINE__ is non-constant. See https://developercommunity.visualstudio.com/t/-line-cannot-be-used-as-an-argument-for-constexpr/195665\n#endif\n\n#ifndef TRACY_ENABLE\n\n#define TracyNoop\n\n#define ZoneNamed(x,y)\n#define ZoneNamedN(x,y,z)\n#define ZoneNamedC(x,y,z)\n#define ZoneNamedNC(x,y,z,w)\n\n#define ZoneTransient(x,y)\n#define ZoneTransientN(x,y,z)\n\n#define ZoneScoped\n#define ZoneScopedN(x)\n#define ZoneScopedC(x)\n#define ZoneScopedNC(x,y)\n\n#define ZoneText(x,y)\n#define ZoneTextV(x,y,z)\n#define ZoneTextF(x,...)\n#define ZoneTextVF(x,y,...)\n#define ZoneName(x,y)\n#define ZoneNameV(x,y,z)\n#define ZoneNameF(x,...)\n#define ZoneNameVF(x,y,...)\n#define ZoneColor(x)\n#define ZoneColorV(x,y)\n#define ZoneValue(x)\n#define ZoneValueV(x,y)\n#define ZoneIsActive false\n#define ZoneIsActiveV(x) false\n\n#define FrameMark\n#define FrameMarkNamed(x)\n#define FrameMarkStart(x)\n#define FrameMarkEnd(x)\n\n#define FrameImage(x,y,z,w,a)\n\n#define TracyLockable( type, varname ) type varname\n#define TracyLockableN( type, varname, desc ) type varname\n#define TracySharedLockable( type, varname ) type varname\n#define TracySharedLockableN( type, varname, desc ) type varname\n#define LockableBase( type ) type\n#define SharedLockableBase( type ) type\n#define LockMark(x) (void)x\n#define LockableName(x,y,z)\n\n#define TracyPlot(x,y)\n#define TracyPlotConfig(x,y,z,w,a)\n\n#define TracyMessage(x,y)\n#define TracyMessageL(x)\n#define TracyMessageC(x,y,z)\n#define TracyMessageLC(x,y)\n#define TracyAppInfo(x,y)\n\n#define TracyAlloc(x,y)\n#define TracyFree(x)\n#define TracyMemoryDiscard(x)\n#define TracySecureAlloc(x,y)\n#define TracySecureFree(x)\n#define TracySecureMemoryDiscard(x)\n\n#define TracyAllocN(x,y,z)\n#define TracyFreeN(x,y)\n#define TracySecureAllocN(x,y,z)\n#define TracySecureFreeN(x,y)\n\n#define ZoneNamedS(x,y,z)\n#define ZoneNamedNS(x,y,z,w)\n#define ZoneNamedCS(x,y,z,w)\n#define ZoneNamedNCS(x,y,z,w,a)\n\n#define ZoneTransientS(x,y,z)\n#define ZoneTransientNS(x,y,z,w)\n\n#define ZoneScopedS(x)\n#define ZoneScopedNS(x,y)\n#define ZoneScopedCS(x,y)\n#define ZoneScopedNCS(x,y,z)\n\n#define TracyAllocS(x,y,z)\n#define TracyFreeS(x,y)\n#define TracyMemoryDiscardS(x,y)\n#define TracySecureAllocS(x,y,z)\n#define TracySecureFreeS(x,y)\n#define TracySecureMemoryDiscardS(x,y)\n\n#define TracyAllocNS(x,y,z,w)\n#define TracyFreeNS(x,y,z)\n#define TracySecureAllocNS(x,y,z,w)\n#define TracySecureFreeNS(x,y,z)\n\n#define TracyMessageS(x,y,z)\n#define TracyMessageLS(x,y)\n#define TracyMessageCS(x,y,z,w)\n#define TracyMessageLCS(x,y,z)\n\n#define TracySourceCallbackRegister(x,y)\n#define TracyParameterRegister(x,y)\n#define TracyParameterSetup(x,y,z,w)\n#define TracyIsConnected false\n#define TracyIsStarted false\n#define TracySetProgramName(x)\n\n#define TracyFiberEnter(x)\n#define TracyFiberEnterHint(x,y)\n#define TracyFiberLeave\n\n#else\n\n#include <string.h>\n\n#include \"../client/TracyLock.hpp\"\n#include \"../client/TracyProfiler.hpp\"\n#include \"../client/TracyScoped.hpp\"\n\n#ifndef TRACY_CALLSTACK\n#define TRACY_CALLSTACK 0\n#endif\n\n#define TracyNoop tracy::ProfilerAvailable()\n\n#define ZoneNamed( varname, active ) static constexpr tracy::SourceLocationData TracyConcat(__tracy_source_location,TracyLine) { nullptr, TracyFunction,  TracyFile, (uint32_t)TracyLine, 0 }; tracy::ScopedZone varname( &TracyConcat(__tracy_source_location,TracyLine), TRACY_CALLSTACK, active )\n#define ZoneNamedN( varname, name, active ) static constexpr tracy::SourceLocationData TracyConcat(__tracy_source_location,TracyLine) { name, TracyFunction,  TracyFile, (uint32_t)TracyLine, 0 }; tracy::ScopedZone varname( &TracyConcat(__tracy_source_location,TracyLine), TRACY_CALLSTACK, active )\n#define ZoneNamedC( varname, color, active ) static constexpr tracy::SourceLocationData TracyConcat(__tracy_source_location,TracyLine) { nullptr, TracyFunction,  TracyFile, (uint32_t)TracyLine, color }; tracy::ScopedZone varname( &TracyConcat(__tracy_source_location,TracyLine), TRACY_CALLSTACK, active )\n#define ZoneNamedNC( varname, name, color, active ) static constexpr tracy::SourceLocationData TracyConcat(__tracy_source_location,TracyLine) { name, TracyFunction,  TracyFile, (uint32_t)TracyLine, color }; tracy::ScopedZone varname( &TracyConcat(__tracy_source_location,TracyLine), TRACY_CALLSTACK, active )\n\n#define ZoneTransient( varname, active ) tracy::ScopedZone varname( TracyLine, TracyFile, strlen( TracyFile ), TracyFunction, strlen( TracyFunction ), nullptr, 0, TRACY_CALLSTACK, active )\n#define ZoneTransientN( varname, name, active ) tracy::ScopedZone varname( TracyLine, TracyFile, strlen( TracyFile ), TracyFunction, strlen( TracyFunction ), name, strlen( name ), TRACY_CALLSTACK, active )\n#define ZoneTransientNC( varname, name, color, active ) tracy::ScopedZone varname( TracyLine, TracyFile, strlen( TracyFile ), TracyFunction, strlen( TracyFunction ), name, strlen( name ), color, TRACY_CALLSTACK, active )\n\n#if defined(TRACY_ALLOW_SHADOW_WARNING)\n    #define SuppressVarShadowWarning(Expr) Expr\n#elif defined(__clang__)\n    #define SuppressVarShadowWarning(Expr) \\\n        _Pragma(\"clang diagnostic push\") \\\n        _Pragma(\"clang diagnostic ignored \\\"-Wshadow\\\"\") \\\n        Expr; \\\n        _Pragma(\"clang diagnostic pop\")\n#elif defined(__GNUC__)\n    #define SuppressVarShadowWarning(Expr) \\\n        _Pragma(\"GCC diagnostic push\") \\\n        _Pragma(\"GCC diagnostic ignored \\\"-Wshadow\\\"\") \\\n        Expr; \\\n        _Pragma(\"GCC diagnostic pop\")\n#elif defined(_MSC_VER) \n    #define SuppressVarShadowWarning(Expr) \\\n        _Pragma(\"warning(push)\") \\\n        _Pragma(\"warning(disable : 4456)\") \\\n        Expr; \\\n        _Pragma(\"warning(pop)\")\n#else\n    #define SuppressVarShadowWarning(Expr) Expr\n#endif\n\n#define ZoneScoped SuppressVarShadowWarning( ZoneNamed( ___tracy_scoped_zone, true ) )\n#define ZoneScopedN( name ) SuppressVarShadowWarning( ZoneNamedN( ___tracy_scoped_zone, name, true ) )\n#define ZoneScopedC( color ) SuppressVarShadowWarning( ZoneNamedC( ___tracy_scoped_zone, color, true ) )\n#define ZoneScopedNC( name, color ) SuppressVarShadowWarning( ZoneNamedNC( ___tracy_scoped_zone, name, color, true ) )\n\n#define ZoneText( txt, size ) ___tracy_scoped_zone.Text( txt, size )\n#define ZoneTextV( varname, txt, size ) varname.Text( txt, size )\n#define ZoneTextF( fmt, ... ) ___tracy_scoped_zone.TextFmt( fmt, ##__VA_ARGS__ )\n#define ZoneTextVF( varname, fmt, ... ) varname.TextFmt( fmt, ##__VA_ARGS__ )\n#define ZoneName( txt, size ) ___tracy_scoped_zone.Name( txt, size )\n#define ZoneNameV( varname, txt, size ) varname.Name( txt, size )\n#define ZoneNameF( fmt, ... ) ___tracy_scoped_zone.NameFmt( fmt, ##__VA_ARGS__ )\n#define ZoneNameVF( varname, fmt, ... ) varname.NameFmt( fmt, ##__VA_ARGS__ )\n#define ZoneColor( color ) ___tracy_scoped_zone.Color( color )\n#define ZoneColorV( varname, color ) varname.Color( color )\n#define ZoneValue( value ) ___tracy_scoped_zone.Value( value )\n#define ZoneValueV( varname, value ) varname.Value( value )\n#define ZoneIsActive ___tracy_scoped_zone.IsActive()\n#define ZoneIsActiveV( varname ) varname.IsActive()\n\n#define FrameMark tracy::Profiler::SendFrameMark( nullptr )\n#define FrameMarkNamed( name ) tracy::Profiler::SendFrameMark( name )\n#define FrameMarkStart( name ) tracy::Profiler::SendFrameMark( name, tracy::QueueType::FrameMarkMsgStart )\n#define FrameMarkEnd( name ) tracy::Profiler::SendFrameMark( name, tracy::QueueType::FrameMarkMsgEnd )\n\n#define FrameImage( image, width, height, offset, flip ) tracy::Profiler::SendFrameImage( image, width, height, offset, flip )\n\n#define TracyLockable( type, varname ) tracy::Lockable<type> varname { [] () -> const tracy::SourceLocationData* { static constexpr tracy::SourceLocationData srcloc { nullptr, #type \" \" #varname, TracyFile, TracyLine, 0 }; return &srcloc; }() }\n#define TracyLockableN( type, varname, desc ) tracy::Lockable<type> varname { [] () -> const tracy::SourceLocationData* { static constexpr tracy::SourceLocationData srcloc { nullptr, desc, TracyFile, TracyLine, 0 }; return &srcloc; }() }\n#define TracySharedLockable( type, varname ) tracy::SharedLockable<type> varname { [] () -> const tracy::SourceLocationData* { static constexpr tracy::SourceLocationData srcloc { nullptr, #type \" \" #varname, TracyFile, TracyLine, 0 }; return &srcloc; }() }\n#define TracySharedLockableN( type, varname, desc ) tracy::SharedLockable<type> varname { [] () -> const tracy::SourceLocationData* { static constexpr tracy::SourceLocationData srcloc { nullptr, desc, TracyFile, TracyLine, 0 }; return &srcloc; }() }\n#define LockableBase( type ) tracy::Lockable<type>\n#define SharedLockableBase( type ) tracy::SharedLockable<type>\n#define LockMark( varname ) static constexpr tracy::SourceLocationData TracyConcat(__tracy_lock_location_,TracyLine) { nullptr, TracyFunction,  TracyFile, (uint32_t)TracyLine, 0 }; varname.Mark( &TracyConcat(__tracy_lock_location_,TracyLine) )\n#define LockableName( varname, txt, size ) varname.CustomName( txt, size )\n\n#define TracyPlot( name, val ) tracy::Profiler::PlotData( name, val )\n#define TracyPlotConfig( name, type, step, fill, color ) tracy::Profiler::ConfigurePlot( name, type, step, fill, color )\n\n#define TracyAppInfo( txt, size ) tracy::Profiler::MessageAppInfo( txt, size )\n\n#define TracyMessage( txt, size ) tracy::Profiler::Message( txt, size, TRACY_CALLSTACK )\n#define TracyMessageL( txt ) tracy::Profiler::Message( txt, TRACY_CALLSTACK )\n#define TracyMessageC( txt, size, color ) tracy::Profiler::MessageColor( txt, size, color, TRACY_CALLSTACK )\n#define TracyMessageLC( txt, color ) tracy::Profiler::MessageColor( txt, color, TRACY_CALLSTACK )\n\n#define TracyAlloc( ptr, size ) tracy::Profiler::MemAllocCallstack( ptr, size, TRACY_CALLSTACK, false )\n#define TracyFree( ptr ) tracy::Profiler::MemFreeCallstack( ptr, TRACY_CALLSTACK, false )\n#define TracySecureAlloc( ptr, size ) tracy::Profiler::MemAllocCallstack( ptr, size, TRACY_CALLSTACK, true )\n#define TracySecureFree( ptr ) tracy::Profiler::MemFreeCallstack( ptr, TRACY_CALLSTACK, true )\n\n#define TracyAllocN( ptr, size, name ) tracy::Profiler::MemAllocCallstackNamed( ptr, size, TRACY_CALLSTACK, false, name )\n#define TracyFreeN( ptr, name ) tracy::Profiler::MemFreeCallstackNamed( ptr, TRACY_CALLSTACK, false, name )\n#define TracyMemoryDiscard( name ) tracy::Profiler::MemDiscardCallstack( name, false, TRACY_CALLSTACK )\n#define TracySecureAllocN( ptr, size, name ) tracy::Profiler::MemAllocCallstackNamed( ptr, size, TRACY_CALLSTACK, true, name )\n#define TracySecureFreeN( ptr, name ) tracy::Profiler::MemFreeCallstackNamed( ptr, TRACY_CALLSTACK, true, name )\n#define TracySecureMemoryDiscard( name ) tracy::Profiler::MemDiscardCallstack( name, true, TRACY_CALLSTACK )\n\n#define ZoneNamedS( varname, depth, active ) static constexpr tracy::SourceLocationData TracyConcat(__tracy_source_location,TracyLine) { nullptr, TracyFunction,  TracyFile, (uint32_t)TracyLine, 0 }; tracy::ScopedZone varname( &TracyConcat(__tracy_source_location,TracyLine), depth, active )\n#define ZoneNamedNS( varname, name, depth, active ) static constexpr tracy::SourceLocationData TracyConcat(__tracy_source_location,TracyLine) { name, TracyFunction,  TracyFile, (uint32_t)TracyLine, 0 }; tracy::ScopedZone varname( &TracyConcat(__tracy_source_location,TracyLine), depth, active )\n#define ZoneNamedCS( varname, color, depth, active ) static constexpr tracy::SourceLocationData TracyConcat(__tracy_source_location,TracyLine) { nullptr, TracyFunction,  TracyFile, (uint32_t)TracyLine, color }; tracy::ScopedZone varname( &TracyConcat(__tracy_source_location,TracyLine), depth, active )\n#define ZoneNamedNCS( varname, name, color, depth, active ) static constexpr tracy::SourceLocationData TracyConcat(__tracy_source_location,TracyLine) { name, TracyFunction,  TracyFile, (uint32_t)TracyLine, color }; tracy::ScopedZone varname( &TracyConcat(__tracy_source_location,TracyLine), depth, active )\n\n#define ZoneTransientS( varname, depth, active ) tracy::ScopedZone varname( TracyLine, TracyFile, strlen( TracyFile ), TracyFunction, strlen( TracyFunction ), nullptr, 0, depth, active )\n#define ZoneTransientNS( varname, name, depth, active ) tracy::ScopedZone varname( TracyLine, TracyFile, strlen( TracyFile ), TracyFunction, strlen( TracyFunction ), name, strlen( name ), depth, active )\n\n#define ZoneScopedS( depth ) ZoneNamedS( ___tracy_scoped_zone, depth, true )\n#define ZoneScopedNS( name, depth ) ZoneNamedNS( ___tracy_scoped_zone, name, depth, true )\n#define ZoneScopedCS( color, depth ) ZoneNamedCS( ___tracy_scoped_zone, color, depth, true )\n#define ZoneScopedNCS( name, color, depth ) ZoneNamedNCS( ___tracy_scoped_zone, name, color, depth, true )\n\n#define TracyAllocS( ptr, size, depth ) tracy::Profiler::MemAllocCallstack( ptr, size, depth, false )\n#define TracyFreeS( ptr, depth ) tracy::Profiler::MemFreeCallstack( ptr, depth, false )\n#define TracySecureAllocS( ptr, size, depth ) tracy::Profiler::MemAllocCallstack( ptr, size, depth, true )\n#define TracySecureFreeS( ptr, depth ) tracy::Profiler::MemFreeCallstack( ptr, depth, true )\n\n#define TracyAllocNS( ptr, size, depth, name ) tracy::Profiler::MemAllocCallstackNamed( ptr, size, depth, false, name )\n#define TracyFreeNS( ptr, depth, name ) tracy::Profiler::MemFreeCallstackNamed( ptr, depth, false, name )\n#define TracyMemoryDiscardS( name, depth ) tracy::Profiler::MemDiscardCallstack( name, false, depth )\n#define TracySecureAllocNS( ptr, size, depth, name ) tracy::Profiler::MemAllocCallstackNamed( ptr, size, depth, true, name )\n#define TracySecureFreeNS( ptr, depth, name ) tracy::Profiler::MemFreeCallstackNamed( ptr, depth, true, name )\n#define TracySecureMemoryDiscardS( name, depth ) tracy::Profiler::MemDiscardCallstack( name, true, depth )\n\n#define TracyMessageS( txt, size, depth ) tracy::Profiler::Message( txt, size, depth )\n#define TracyMessageLS( txt, depth ) tracy::Profiler::Message( txt, depth )\n#define TracyMessageCS( txt, size, color, depth ) tracy::Profiler::MessageColor( txt, size, color, depth )\n#define TracyMessageLCS( txt, color, depth ) tracy::Profiler::MessageColor( txt, color, depth )\n\n#define TracySourceCallbackRegister( cb, data ) tracy::Profiler::SourceCallbackRegister( cb, data )\n#define TracyParameterRegister( cb, data ) tracy::Profiler::ParameterRegister( cb, data )\n#define TracyParameterSetup( idx, name, isBool, val ) tracy::Profiler::ParameterSetup( idx, name, isBool, val )\n#define TracyIsConnected tracy::GetProfiler().IsConnected()\n#define TracySetProgramName( name ) tracy::GetProfiler().SetProgramName( name );\n\n#ifdef TRACY_FIBERS\n#  define TracyFiberEnter( fiber ) tracy::Profiler::EnterFiber( fiber, 0 )\n#  define TracyFiberEnterHint( fiber, groupHint ) tracy::Profiler::EnterFiber( fiber, groupHint )\n#  define TracyFiberLeave tracy::Profiler::LeaveFiber()\n#endif\n\n#endif\n\n#endif\n"
  },
  {
    "path": "tracy-client-sys/tracy/tracy/TracyC.h",
    "content": "#ifndef __TRACYC_HPP__\n#define __TRACYC_HPP__\n\n#include <stddef.h>\n#include <stdint.h>\n\n#include \"../common/TracyApi.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nenum TracyPlotFormatEnum\n{\n    TracyPlotFormatNumber,\n    TracyPlotFormatMemory,\n    TracyPlotFormatPercentage,\n    TracyPlotFormatWatt\n};\n\nTRACY_API void ___tracy_set_thread_name( const char* name );\n\n#define TracyCSetThreadName( name ) ___tracy_set_thread_name( name );\n\n#ifndef TracyFunction\n#  define TracyFunction __FUNCTION__\n#endif\n\n#ifndef TracyFile\n#  define TracyFile __FILE__\n#endif\n\n#ifndef TracyLine\n#  define TracyLine __LINE__\n#endif\n\n#ifndef TRACY_ENABLE\n\ntypedef const void* TracyCZoneCtx;\n\ntypedef const void* TracyCLockCtx;\n\n#define TracyCZone(c,x)\n#define TracyCZoneN(c,x,y)\n#define TracyCZoneC(c,x,y)\n#define TracyCZoneNC(c,x,y,z)\n#define TracyCZoneEnd(c)\n#define TracyCZoneText(c,x,y)\n#define TracyCZoneName(c,x,y)\n#define TracyCZoneColor(c,x)\n#define TracyCZoneValue(c,x)\n\n#define TracyCAlloc(x,y)\n#define TracyCFree(x)\n#define TracyCMemoryDiscard(x)\n#define TracyCSecureAlloc(x,y)\n#define TracyCSecureFree(x)\n#define TracyCSecureMemoryDiscard(x)\n\n#define TracyCAllocN(x,y,z)\n#define TracyCFreeN(x,y)\n#define TracyCSecureAllocN(x,y,z)\n#define TracyCSecureFreeN(x,y)\n\n#define TracyCFrameMark\n#define TracyCFrameMarkNamed(x)\n#define TracyCFrameMarkStart(x)\n#define TracyCFrameMarkEnd(x)\n#define TracyCFrameImage(x,y,z,w,a)\n\n#define TracyCPlot(x,y)\n#define TracyCPlotF(x,y)\n#define TracyCPlotI(x,y)\n#define TracyCPlotConfig(x,y,z,w,a)\n\n#define TracyCMessage(x,y)\n#define TracyCMessageL(x)\n#define TracyCMessageC(x,y,z)\n#define TracyCMessageLC(x,y)\n#define TracyCAppInfo(x,y)\n\n#define TracyCZoneS(x,y,z)\n#define TracyCZoneNS(x,y,z,w)\n#define TracyCZoneCS(x,y,z,w)\n#define TracyCZoneNCS(x,y,z,w,a)\n\n#define TracyCAllocS(x,y,z)\n#define TracyCFreeS(x,y)\n#define TracyCMemoryDiscardS(x,y)\n#define TracyCSecureAllocS(x,y,z)\n#define TracyCSecureFreeS(x,y)\n#define TracyCSecureMemoryDiscardS(x,y)\n\n#define TracyCAllocNS(x,y,z,w)\n#define TracyCFreeNS(x,y,z)\n#define TracyCSecureAllocNS(x,y,z,w)\n#define TracyCSecureFreeNS(x,y,z)\n\n#define TracyCMessageS(x,y,z)\n#define TracyCMessageLS(x,y)\n#define TracyCMessageCS(x,y,z,w)\n#define TracyCMessageLCS(x,y,z)\n\n#define TracyCLockCtx(l)\n#define TracyCLockAnnounce(l)\n#define TracyCLockTerminate(l)\n#define TracyCLockBeforeLock(l)\n#define TracyCLockAfterLock(l)\n#define TracyCLockAfterUnlock(l)\n#define TracyCLockAfterTryLock(l,x)\n#define TracyCLockMark(l)\n#define TracyCLockCustomName(l,x,y)\n\n#define TracyCIsConnected 0\n#define TracyCIsStarted 0\n\n#define TracyCBeginSamplingProfiling() 0\n#define TracyCEndSamplingProfiling()\n\n#ifdef TRACY_FIBERS\n#  define TracyCFiberEnter(fiber)\n#  define TracyCFiberLeave\n#endif\n\n#else\n\n#ifndef TracyConcat\n#  define TracyConcat(x,y) TracyConcatIndirect(x,y)\n#endif\n#ifndef TracyConcatIndirect\n#  define TracyConcatIndirect(x,y) x##y\n#endif\n\nstruct ___tracy_source_location_data\n{\n    const char* name;\n    const char* function;\n    const char* file;\n    uint32_t line;\n    uint32_t color;\n};\n\nstruct ___tracy_c_zone_context\n{\n    uint32_t id;\n    int32_t active;\n};\n\nstruct ___tracy_gpu_time_data\n{\n    int64_t gpuTime;\n    uint16_t queryId;\n    uint8_t context;\n};\n\nstruct ___tracy_gpu_zone_begin_data {\n    uint64_t srcloc;\n    uint16_t queryId;\n    uint8_t context;\n};\n\nstruct ___tracy_gpu_zone_begin_callstack_data {\n    uint64_t srcloc;\n    int32_t depth;\n    uint16_t queryId;\n    uint8_t context;\n};\n\nstruct ___tracy_gpu_zone_end_data {\n    uint16_t queryId;\n    uint8_t context;\n};\n\nstruct ___tracy_gpu_new_context_data {\n    int64_t gpuTime;\n    float period;\n    uint8_t context;\n    uint8_t flags;\n    uint8_t type;\n};\n\nstruct ___tracy_gpu_context_name_data {\n    uint8_t context;\n    const char* name;\n    uint16_t len;\n};\n\nstruct ___tracy_gpu_calibration_data {\n    int64_t gpuTime;\n    int64_t cpuDelta;\n    uint8_t context;\n};\n\nstruct ___tracy_gpu_time_sync_data {\n    int64_t gpuTime;\n    uint8_t context;\n};\n\nstruct __tracy_lockable_context_data;\n\n// Some containers don't support storing const types.\n// This struct, as visible to user, is immutable, so treat it as if const was declared here.\ntypedef /*const*/ struct ___tracy_c_zone_context TracyCZoneCtx;\n\ntypedef struct __tracy_lockable_context_data* TracyCLockCtx;\n\n#ifdef TRACY_MANUAL_LIFETIME\nTRACY_API void ___tracy_startup_profiler(void);\nTRACY_API void ___tracy_shutdown_profiler(void);\nTRACY_API int32_t ___tracy_profiler_started(void);\n\n#  define TracyCIsStarted ___tracy_profiler_started()\n#else\n#  define TracyCIsStarted 1\n#endif\n\nTRACY_API uint64_t ___tracy_alloc_srcloc( uint32_t line, const char* source, size_t sourceSz, const char* function, size_t functionSz, uint32_t color );\nTRACY_API uint64_t ___tracy_alloc_srcloc_name( uint32_t line, const char* source, size_t sourceSz, const char* function, size_t functionSz, const char* name, size_t nameSz, uint32_t color );\n\nTRACY_API TracyCZoneCtx ___tracy_emit_zone_begin( const struct ___tracy_source_location_data* srcloc, int32_t active );\nTRACY_API TracyCZoneCtx ___tracy_emit_zone_begin_callstack( const struct ___tracy_source_location_data* srcloc, int32_t depth, int32_t active );\nTRACY_API TracyCZoneCtx ___tracy_emit_zone_begin_alloc( uint64_t srcloc, int32_t active );\nTRACY_API TracyCZoneCtx ___tracy_emit_zone_begin_alloc_callstack( uint64_t srcloc, int32_t depth, int32_t active );\nTRACY_API void ___tracy_emit_zone_end( TracyCZoneCtx ctx );\nTRACY_API void ___tracy_emit_zone_text( TracyCZoneCtx ctx, const char* txt, size_t size );\nTRACY_API void ___tracy_emit_zone_name( TracyCZoneCtx ctx, const char* txt, size_t size );\nTRACY_API void ___tracy_emit_zone_color( TracyCZoneCtx ctx, uint32_t color );\nTRACY_API void ___tracy_emit_zone_value( TracyCZoneCtx ctx, uint64_t value );\n\nTRACY_API void ___tracy_emit_gpu_zone_begin( const struct ___tracy_gpu_zone_begin_data );\nTRACY_API void ___tracy_emit_gpu_zone_begin_callstack( const struct ___tracy_gpu_zone_begin_callstack_data );\nTRACY_API void ___tracy_emit_gpu_zone_begin_alloc( const struct ___tracy_gpu_zone_begin_data );\nTRACY_API void ___tracy_emit_gpu_zone_begin_alloc_callstack( const struct ___tracy_gpu_zone_begin_callstack_data );\nTRACY_API void ___tracy_emit_gpu_zone_end( const struct ___tracy_gpu_zone_end_data data );\nTRACY_API void ___tracy_emit_gpu_time( const struct ___tracy_gpu_time_data );\nTRACY_API void ___tracy_emit_gpu_new_context( const struct ___tracy_gpu_new_context_data );\nTRACY_API void ___tracy_emit_gpu_context_name( const struct ___tracy_gpu_context_name_data );\nTRACY_API void ___tracy_emit_gpu_calibration( const struct ___tracy_gpu_calibration_data );\nTRACY_API void ___tracy_emit_gpu_time_sync( const struct ___tracy_gpu_time_sync_data );\n\nTRACY_API void ___tracy_emit_gpu_zone_begin_serial( const struct ___tracy_gpu_zone_begin_data );\nTRACY_API void ___tracy_emit_gpu_zone_begin_callstack_serial( const struct ___tracy_gpu_zone_begin_callstack_data );\nTRACY_API void ___tracy_emit_gpu_zone_begin_alloc_serial( const struct ___tracy_gpu_zone_begin_data );\nTRACY_API void ___tracy_emit_gpu_zone_begin_alloc_callstack_serial( const struct ___tracy_gpu_zone_begin_callstack_data );\nTRACY_API void ___tracy_emit_gpu_zone_end_serial( const struct ___tracy_gpu_zone_end_data data );\nTRACY_API void ___tracy_emit_gpu_time_serial( const struct ___tracy_gpu_time_data );\nTRACY_API void ___tracy_emit_gpu_new_context_serial( const struct ___tracy_gpu_new_context_data );\nTRACY_API void ___tracy_emit_gpu_context_name_serial( const struct ___tracy_gpu_context_name_data );\nTRACY_API void ___tracy_emit_gpu_calibration_serial( const struct ___tracy_gpu_calibration_data );\nTRACY_API void ___tracy_emit_gpu_time_sync_serial( const struct ___tracy_gpu_time_sync_data );\n\nTRACY_API int32_t ___tracy_connected(void);\n\n#ifndef TRACY_CALLSTACK\n#define TRACY_CALLSTACK 0\n#endif\n\n#define TracyCZone( ctx, active ) static const struct ___tracy_source_location_data TracyConcat(__tracy_source_location,TracyLine) = { NULL, __func__,  TracyFile, (uint32_t)TracyLine, 0 }; TracyCZoneCtx ctx = ___tracy_emit_zone_begin_callstack( &TracyConcat(__tracy_source_location,TracyLine), TRACY_CALLSTACK, active );\n#define TracyCZoneN( ctx, name, active ) static const struct ___tracy_source_location_data TracyConcat(__tracy_source_location,TracyLine) = { name, __func__,  TracyFile, (uint32_t)TracyLine, 0 }; TracyCZoneCtx ctx = ___tracy_emit_zone_begin_callstack( &TracyConcat(__tracy_source_location,TracyLine), TRACY_CALLSTACK, active );\n#define TracyCZoneC( ctx, color, active ) static const struct ___tracy_source_location_data TracyConcat(__tracy_source_location,TracyLine) = { NULL, __func__,  TracyFile, (uint32_t)TracyLine, color }; TracyCZoneCtx ctx = ___tracy_emit_zone_begin_callstack( &TracyConcat(__tracy_source_location,TracyLine), TRACY_CALLSTACK, active );\n#define TracyCZoneNC( ctx, name, color, active ) static const struct ___tracy_source_location_data TracyConcat(__tracy_source_location,TracyLine) = { name, __func__,  TracyFile, (uint32_t)TracyLine, color }; TracyCZoneCtx ctx = ___tracy_emit_zone_begin_callstack( &TracyConcat(__tracy_source_location,TracyLine), TRACY_CALLSTACK, active );\n\n#define TracyCZoneEnd( ctx ) ___tracy_emit_zone_end( ctx );\n\n#define TracyCZoneText( ctx, txt, size ) ___tracy_emit_zone_text( ctx, txt, size );\n#define TracyCZoneName( ctx, txt, size ) ___tracy_emit_zone_name( ctx, txt, size );\n#define TracyCZoneColor( ctx, color ) ___tracy_emit_zone_color( ctx, color );\n#define TracyCZoneValue( ctx, value ) ___tracy_emit_zone_value( ctx, value );\n\n\nTRACY_API void ___tracy_emit_memory_alloc( const void* ptr, size_t size, int32_t secure );\nTRACY_API void ___tracy_emit_memory_alloc_callstack( const void* ptr, size_t size, int32_t depth, int32_t secure );\nTRACY_API void ___tracy_emit_memory_free( const void* ptr, int32_t secure );\nTRACY_API void ___tracy_emit_memory_free_callstack( const void* ptr, int32_t depth, int32_t secure );\nTRACY_API void ___tracy_emit_memory_alloc_named( const void* ptr, size_t size, int32_t secure, const char* name );\nTRACY_API void ___tracy_emit_memory_alloc_callstack_named( const void* ptr, size_t size, int32_t depth, int32_t secure, const char* name );\nTRACY_API void ___tracy_emit_memory_free_named( const void* ptr, int32_t secure, const char* name );\nTRACY_API void ___tracy_emit_memory_free_callstack_named( const void* ptr, int32_t depth, int32_t secure, const char* name );\nTRACY_API void ___tracy_emit_memory_discard( const char* name, int32_t secure );\nTRACY_API void ___tracy_emit_memory_discard_callstack( const char* name, int32_t secure, int32_t depth );\n\nTRACY_API void ___tracy_emit_message( const char* txt, size_t size, int32_t callstack_depth );\nTRACY_API void ___tracy_emit_messageL( const char* txt, int32_t callstack_depth );\nTRACY_API void ___tracy_emit_messageC( const char* txt, size_t size, uint32_t color, int32_t callstack_depth );\nTRACY_API void ___tracy_emit_messageLC( const char* txt, uint32_t color, int32_t callstack_depth );\n\n#define TracyCAlloc( ptr, size ) ___tracy_emit_memory_alloc_callstack( ptr, size, TRACY_CALLSTACK, 0 )\n#define TracyCFree( ptr ) ___tracy_emit_memory_free_callstack( ptr, TRACY_CALLSTACK, 0 )\n#define TracyCMemoryDiscard( name ) ___tracy_emit_memory_discard_callstack( name, 0, TRACY_CALLSTACK );\n#define TracyCSecureAlloc( ptr, size ) ___tracy_emit_memory_alloc_callstack( ptr, size, TRACY_CALLSTACK, 1 )\n#define TracyCSecureFree( ptr ) ___tracy_emit_memory_free_callstack( ptr, TRACY_CALLSTACK, 1 )\n#define TracyCSecureMemoryDiscard( name ) ___tracy_emit_memory_discard_callstack( name, 1, TRACY_CALLSTACK );\n\n#define TracyCAllocN( ptr, size, name ) ___tracy_emit_memory_alloc_callstack_named( ptr, size, TRACY_CALLSTACK, 0, name )\n#define TracyCFreeN( ptr, name ) ___tracy_emit_memory_free_callstack_named( ptr, TRACY_CALLSTACK, 0, name )\n#define TracyCSecureAllocN( ptr, size, name ) ___tracy_emit_memory_alloc_callstack_named( ptr, size, TRACY_CALLSTACK, 1, name )\n#define TracyCSecureFreeN( ptr, name ) ___tracy_emit_memory_free_callstack_named( ptr, TRACY_CALLSTACK, 1, name )\n\n#define TracyCMessage( txt, size ) ___tracy_emit_message( txt, size, TRACY_CALLSTACK );\n#define TracyCMessageL( txt ) ___tracy_emit_messageL( txt, TRACY_CALLSTACK );\n#define TracyCMessageC( txt, size, color ) ___tracy_emit_messageC( txt, size, color, TRACY_CALLSTACK );\n#define TracyCMessageLC( txt, color ) ___tracy_emit_messageLC( txt, color, TRACY_CALLSTACK );\n\n\nTRACY_API void ___tracy_emit_frame_mark( const char* name );\nTRACY_API void ___tracy_emit_frame_mark_start( const char* name );\nTRACY_API void ___tracy_emit_frame_mark_end( const char* name );\nTRACY_API void ___tracy_emit_frame_image( const void* image, uint16_t w, uint16_t h, uint8_t offset, int32_t flip );\n\n#define TracyCFrameMark ___tracy_emit_frame_mark( 0 );\n#define TracyCFrameMarkNamed( name ) ___tracy_emit_frame_mark( name );\n#define TracyCFrameMarkStart( name ) ___tracy_emit_frame_mark_start( name );\n#define TracyCFrameMarkEnd( name ) ___tracy_emit_frame_mark_end( name );\n#define TracyCFrameImage( image, width, height, offset, flip ) ___tracy_emit_frame_image( image, width, height, offset, flip );\n\n\nTRACY_API void ___tracy_emit_plot( const char* name, double val );\nTRACY_API void ___tracy_emit_plot_float( const char* name, float val );\nTRACY_API void ___tracy_emit_plot_int( const char* name, int64_t val );\nTRACY_API void ___tracy_emit_plot_config( const char* name, int32_t type, int32_t step, int32_t fill, uint32_t color );\nTRACY_API void ___tracy_emit_message_appinfo( const char* txt, size_t size );\n\n#define TracyCPlot( name, val ) ___tracy_emit_plot( name, val );\n#define TracyCPlotF( name, val ) ___tracy_emit_plot_float( name, val );\n#define TracyCPlotI( name, val ) ___tracy_emit_plot_int( name, val );\n#define TracyCPlotConfig( name, type, step, fill, color ) ___tracy_emit_plot_config( name, type, step, fill, color );\n#define TracyCAppInfo( txt, size ) ___tracy_emit_message_appinfo( txt, size );\n\n\n#define TracyCZoneS( ctx, depth, active ) static const struct ___tracy_source_location_data TracyConcat(__tracy_source_location,TracyLine) = { NULL, __func__,  TracyFile, (uint32_t)TracyLine, 0 }; TracyCZoneCtx ctx = ___tracy_emit_zone_begin_callstack( &TracyConcat(__tracy_source_location,TracyLine), depth, active );\n#define TracyCZoneNS( ctx, name, depth, active ) static const struct ___tracy_source_location_data TracyConcat(__tracy_source_location,TracyLine) = { name, __func__,  TracyFile, (uint32_t)TracyLine, 0 }; TracyCZoneCtx ctx = ___tracy_emit_zone_begin_callstack( &TracyConcat(__tracy_source_location,TracyLine), depth, active );\n#define TracyCZoneCS( ctx, color, depth, active ) static const struct ___tracy_source_location_data TracyConcat(__tracy_source_location,TracyLine) = { NULL, __func__,  TracyFile, (uint32_t)TracyLine, color }; TracyCZoneCtx ctx = ___tracy_emit_zone_begin_callstack( &TracyConcat(__tracy_source_location,TracyLine), depth, active );\n#define TracyCZoneNCS( ctx, name, color, depth, active ) static const struct ___tracy_source_location_data TracyConcat(__tracy_source_location,TracyLine) = { name, __func__,  TracyFile, (uint32_t)TracyLine, color }; TracyCZoneCtx ctx = ___tracy_emit_zone_begin_callstack( &TracyConcat(__tracy_source_location,TracyLine), depth, active );\n\n#define TracyCAllocS( ptr, size, depth ) ___tracy_emit_memory_alloc_callstack( ptr, size, depth, 0 )\n#define TracyCFreeS( ptr, depth ) ___tracy_emit_memory_free_callstack( ptr, depth, 0 )\n#define TracyCMemoryDiscardS( name, depth ) ___tracy_emit_memory_discard_callstack( name, 0, depth )\n#define TracyCSecureAllocS( ptr, size, depth ) ___tracy_emit_memory_alloc_callstack( ptr, size, depth, 1 )\n#define TracyCSecureFreeS( ptr, depth ) ___tracy_emit_memory_free_callstack( ptr, depth, 1 )\n#define TracyCSecureMemoryDiscardS( name, depth ) ___tracy_emit_memory_discard_callstack( name, 1, depth )\n\n#define TracyCAllocNS( ptr, size, depth, name ) ___tracy_emit_memory_alloc_callstack_named( ptr, size, depth, 0, name )\n#define TracyCFreeNS( ptr, depth, name ) ___tracy_emit_memory_free_callstack_named( ptr, depth, 0, name )\n#define TracyCSecureAllocNS( ptr, size, depth, name ) ___tracy_emit_memory_alloc_callstack_named( ptr, size, depth, 1, name )\n#define TracyCSecureFreeNS( ptr, depth, name ) ___tracy_emit_memory_free_callstack_named( ptr, depth, 1, name )\n\n#define TracyCMessageS( txt, size, depth ) ___tracy_emit_message( txt, size, depth );\n#define TracyCMessageLS( txt, depth ) ___tracy_emit_messageL( txt, depth );\n#define TracyCMessageCS( txt, size, color, depth ) ___tracy_emit_messageC( txt, size, color, depth );\n#define TracyCMessageLCS( txt, color, depth ) ___tracy_emit_messageLC( txt, color, depth );\n\n\nTRACY_API struct __tracy_lockable_context_data* ___tracy_announce_lockable_ctx( const struct ___tracy_source_location_data* srcloc );\nTRACY_API void ___tracy_terminate_lockable_ctx( struct __tracy_lockable_context_data* lockdata );\nTRACY_API int32_t ___tracy_before_lock_lockable_ctx( struct __tracy_lockable_context_data* lockdata );\nTRACY_API void ___tracy_after_lock_lockable_ctx( struct __tracy_lockable_context_data* lockdata );\nTRACY_API void ___tracy_after_unlock_lockable_ctx( struct __tracy_lockable_context_data* lockdata );\nTRACY_API void ___tracy_after_try_lock_lockable_ctx( struct __tracy_lockable_context_data* lockdata, int32_t acquired );\nTRACY_API void ___tracy_mark_lockable_ctx( struct __tracy_lockable_context_data* lockdata, const struct ___tracy_source_location_data* srcloc );\nTRACY_API void ___tracy_custom_name_lockable_ctx( struct __tracy_lockable_context_data* lockdata, const char* name, size_t nameSz );\n\n#define TracyCLockAnnounce( lock ) static const struct ___tracy_source_location_data TracyConcat(__tracy_source_location,TracyLine) = { NULL, __func__,  TracyFile, (uint32_t)TracyLine, 0 }; lock = ___tracy_announce_lockable_ctx( &TracyConcat(__tracy_source_location,TracyLine) );\n#define TracyCLockTerminate( lock ) ___tracy_terminate_lockable_ctx( lock );\n#define TracyCLockBeforeLock( lock ) ___tracy_before_lock_lockable_ctx( lock );\n#define TracyCLockAfterLock( lock ) ___tracy_after_lock_lockable_ctx( lock );\n#define TracyCLockAfterUnlock( lock ) ___tracy_after_unlock_lockable_ctx( lock );\n#define TracyCLockAfterTryLock( lock, acquired ) ___tracy_after_try_lock_lockable_ctx( lock, acquired );\n#define TracyCLockMark( lock ) static const struct ___tracy_source_location_data TracyConcat(__tracy_source_location,TracyLine) = { NULL, __func__,  TracyFile, (uint32_t)TracyLine, 0 }; ___tracy_mark_lockable_ctx( lock, &TracyConcat(__tracy_source_location,TracyLine) );\n#define TracyCLockCustomName( lock, name, nameSz ) ___tracy_custom_name_lockable_ctx( lock, name, nameSz );\n\n#define TracyCIsConnected ___tracy_connected()\n\nTRACY_API int ___tracy_begin_sampling_profiler( void );\nTRACY_API void ___tracy_end_sampling_profiler( void );\n\n#define TracyCBeginSamplingProfiling() ___tracy_begin_sampling_profiling()\n#define TracyCEndSamplingProfiling() ___tracy_end_sampling_profiling()\n\n#ifdef TRACY_FIBERS\nTRACY_API void ___tracy_fiber_enter( const char* fiber );\nTRACY_API void ___tracy_fiber_leave( void );\n\n#  define TracyCFiberEnter( fiber ) ___tracy_fiber_enter( fiber );\n#  define TracyCFiberLeave ___tracy_fiber_leave();\n#endif\n\n#endif\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "tracy-client-sys/tracy/tracy/TracyCUDA.hpp",
    "content": "#ifndef __TRACYCUDA_HPP__\n#define __TRACYCUDA_HPP__\n\n#ifndef TRACY_ENABLE\n\n#define TracyCUDAContext() nullptr\n#define TracyCUDAContextDestroy(ctx)\n#define TracyCUDAContextName(ctx, name, size)\n\n#define TracyCUDAStartProfiling(ctx)\n#define TracyCUDAStopProfiling(ctx)\n\n#define TracyCUDACollect(ctx)\n\n#else\n#include <cupti.h>\n\n#include <cassert>\n#include <cmath>\n#include <string>\n#include <string_view>\n#include <atomic>\n#include <mutex>\n#include <shared_mutex>\n#include <condition_variable>\n#include <vector>\n#include <unordered_set>\n#include <unordered_map>\n\n#ifndef _MSC_VER\n#include <cxxabi.h>\n#endif\n\n#include <tracy/Tracy.hpp>\n\n#ifndef UNREFERENCED\n#define UNREFERENCED(x) (void)x\n#endif//UNREFERENCED\n\n#ifndef TRACY_CUDA_CALIBRATED_CONTEXT\n#define TRACY_CUDA_CALIBRATED_CONTEXT (1)\n#endif//TRACY_CUDA_CALIBRATED_CONTEXT\n\n#ifndef TRACY_CUDA_ENABLE_COLLECTOR_THREAD\n#define TRACY_CUDA_ENABLE_COLLECTOR_THREAD (1)\n#endif//TRACY_CUDA_ENABLE_COLLECTOR_THREAD\n\n#ifndef TRACY_CUDA_ENABLE_CUDA_CALL_STATS\n#define TRACY_CUDA_ENABLE_CUDA_CALL_STATS (0)\n#endif//TRACY_CUDA_ENABLE_CUDA_CALL_STATS\n\nnamespace {\n\n// TODO(marcos): wrap these in structs for better type safety\nusing CUptiTimestamp = uint64_t;\nusing TracyTimestamp =  int64_t;\n\nstruct IncrementalRegression {\n    using float_t = double;\n    struct Parameters {\n        float_t slope, intercept;\n    };\n\n    int n = 0;\n    float_t x_mean = 0;\n    float_t y_mean = 0;\n    float_t x_svar = 0;\n    float_t y_svar = 0;\n    float_t xy_scov = 0;\n\n    auto parameters() const {\n        float_t slope = xy_scov / x_svar;\n        float_t intercept = y_mean - slope * x_mean;\n        return Parameters{ slope, intercept };\n    }\n\n    auto orthogonal() const {\n        // NOTE(marcos): orthogonal regression is Deming regression with delta = 1\n        float_t delta = float_t(1);   // delta = 1 -> orthogonal regression\n        float_t k = y_svar - delta * x_svar;\n        float_t slope = (k + sqrt(k * k + 4 * delta * xy_scov * xy_scov)) / (2 * xy_scov);\n        float_t intercept = y_mean - slope * x_mean;\n        return Parameters{ slope, intercept };\n    }\n\n    void addSample(float_t x, float_t y) {\n        ++n;\n        float_t x_mean_prev = x_mean;\n        float_t y_mean_prev = y_mean;\n        x_mean += (x - x_mean) / n;\n        y_mean += (y - y_mean) / n;\n        x_svar += (x - x_mean_prev) * (x - x_mean);\n        y_svar += (y - y_mean_prev) * (y - y_mean);\n        xy_scov += (x - x_mean_prev) * (y - y_mean);\n    }\n};\n\ntracy_force_inline TracyTimestamp tracyGetTimestamp() {\n    return tracy::Profiler::GetTime();\n}\n\nauto& getCachedRegressionParameters() {\n    // WARN(marcos): in theory, these linear regression parameters would be loaded/stored atomically;\n    // in practice, however, it should not matter so long as the loads/stores are not \"sliced\"\n    static IncrementalRegression::Parameters cached;\n    return cached;\n}\n\nTracyTimestamp tracyFromCUpti(CUptiTimestamp cuptiTime) {\n    // NOTE(marcos): linear regression estimate\n    // y_hat = slope * x + intercept | X: CUptiTimestamp, Y: TracyTimestamp\n    auto [slope, intercept] = getCachedRegressionParameters();\n    double y_hat = slope * cuptiTime + intercept;\n    TracyTimestamp tracyTime = TracyTimestamp(y_hat);\n    assert(tracyTime >= 0);\n    return tracyTime;\n}\n\ntemplate<typename T, typename U>\ntracy_force_inline void tracyMemWrite(T& where,U what) {\n    static_assert(std::is_same_v<T, U>, \"tracy::MemWrite: type mismatch.\");\n    tracy::MemWrite(&where, what);\n}\n\nvoid* tracyMalloc(size_t bytes) {\n    return tracy::tracy_malloc(bytes);\n}\n\nvoid tracyFree(void* ptr) {\n    tracy::tracy_free(ptr);\n}\n\nvoid tracyZoneBegin(TracyTimestamp time, tracy::SourceLocationData* srcLoc) {\n    using namespace tracy;\n    TracyQueuePrepare(QueueType::ZoneBegin);\n    tracyMemWrite(item->zoneBegin.time, time);\n    tracyMemWrite(item->zoneBegin.srcloc, (uint64_t)srcLoc);\n    TracyQueueCommit(zoneBeginThread);\n}\n\nvoid tracyZoneEnd(TracyTimestamp time) {\n    using namespace tracy;\n    TracyQueuePrepare(QueueType::ZoneEnd);\n    tracyMemWrite(item->zoneEnd.time, time);\n    TracyQueueCommit(zoneEndThread);\n}\n\nvoid tracyPlot(const char* name, float value, TracyTimestamp time) {\n    using namespace tracy;\n    TracyLfqPrepare(QueueType::PlotDataFloat);\n    tracyMemWrite(item->plotDataFloat.name, (uint64_t)name);\n    tracyMemWrite(item->plotDataFloat.time, time);\n    tracyMemWrite(item->plotDataFloat.val, value);\n    TracyLfqCommit;\n}\n\nvoid tracyPlot(const char* name, float value, CUptiTimestamp time) {\n    tracyPlot(name, value, tracyFromCUpti(time));\n}\n\nvoid tracyPlotActivity(const char* name, TracyTimestamp start, TracyTimestamp end, float value = 1.0f, float baseline = 0.0f) {\n    tracyPlot(name, baseline, start);\n    tracyPlot(name, value, start + 3);\n    tracyPlot(name, value, end - 3);\n    tracyPlot(name, baseline, end);\n}\n\nvoid tracyPlotActivity(const char* name, CUptiTimestamp start, CUptiTimestamp end, float value = 1.0f, float baseline = 0.0f) {\n    tracyPlotActivity(name, tracyFromCUpti(start), tracyFromCUpti(end), value, baseline);\n}\n\nvoid tracyPlotBlip(const char* name, TracyTimestamp time, float value = 1.0f, float baseline = 0.0f) {\n    tracyPlot(name, baseline, time - 3);\n    tracyPlot(name, value, time);\n    tracyPlot(name, baseline, time + 3);\n}\n\nvoid tracyPlotBlip(const char* name, CUptiTimestamp time, float value = 1.0f, float baseline = 0.0f) {\n    tracyPlotBlip(name, tracyFromCUpti(time), value, baseline);\n}\n\nvoid tracyEmitMemAlloc(const char* name, const void* ptr, size_t size, TracyTimestamp time) {\n    using namespace tracy;\n    const auto thread = GetThreadHandle();\n\n    auto item = Profiler::QueueSerial();\n    tracyMemWrite(item->hdr.type, QueueType::MemNamePayload);\n    tracyMemWrite(item->memName.name, (uint64_t)name);\n    Profiler::QueueSerialFinish();\n\n    item = Profiler::QueueSerial();\n    tracyMemWrite(item->hdr.type, QueueType::MemAllocNamed);\n    tracyMemWrite(item->memAlloc.time, time);\n    tracyMemWrite(item->memAlloc.thread, thread);\n    tracyMemWrite(item->memAlloc.ptr, (uint64_t)ptr);\n\n    if (compile_time_condition<sizeof(size) == 4>::value)\n    {\n        memcpy(&item->memAlloc.size, &size, 4);\n        memset(&item->memAlloc.size + 4, 0, 2);\n    }\n    else\n    {\n        assert(sizeof(size) == 8);\n        memcpy(&item->memAlloc.size, &size, 4);\n        memcpy(((char *)&item->memAlloc.size) + 4, ((char *)&size) + 4, 2);\n    }\n    Profiler::QueueSerialFinish();\n}\n\nvoid tracyEmitMemFree(const char* name, const void* ptr, TracyTimestamp time) {\n    using namespace tracy;\n    const auto thread = GetThreadHandle();\n\n    auto item = Profiler::QueueSerial();\n    tracyMemWrite(item->hdr.type, QueueType::MemNamePayload);\n    tracyMemWrite(item->memName.name, (uint64_t)name);\n    Profiler::QueueSerialFinish();\n\n    item = Profiler::QueueSerial();\n    tracyMemWrite(item->hdr.type, QueueType::MemFreeNamed);\n    tracyMemWrite(item->memFree.time, time);\n    tracyMemWrite(item->memFree.thread, thread);\n    tracyMemWrite(item->memFree.ptr, (uint64_t)ptr);\n    Profiler::QueueSerialFinish();\n}\n\nvoid tracyEmitMemAlloc(const char* name, const void* ptr, size_t size, CUptiTimestamp cuptiTime) {\n    tracyEmitMemAlloc(name, ptr, size, tracyFromCUpti(cuptiTime));\n}\n\nvoid tracyEmitMemFree(const char* name, const void* ptr, CUptiTimestamp cuptiTime) {\n    tracyEmitMemFree(name, ptr, tracyFromCUpti(cuptiTime));\n}\n\nvoid tracyAnnounceGpuTimestamp(TracyTimestamp apiStart, TracyTimestamp apiEnd,\n    uint16_t queryId, uint8_t gpuContextId, \n    const tracy::SourceLocationData* sourceLocation, uint32_t threadId) {\n    using namespace tracy;\n\n    auto item = Profiler::QueueSerial();\n    tracyMemWrite(item->hdr.type, QueueType::GpuZoneBeginSerial);\n    tracyMemWrite(item->gpuZoneBegin.cpuTime, apiStart);\n    tracyMemWrite(item->gpuZoneBegin.srcloc, (uint64_t)sourceLocation);\n    tracyMemWrite(item->gpuZoneBegin.thread, threadId);\n    tracyMemWrite(item->gpuZoneBegin.queryId, uint16_t(queryId+0));\n    tracyMemWrite(item->gpuZoneBegin.context, gpuContextId);\n    Profiler::QueueSerialFinish();\n\n    item = Profiler::QueueSerial();\n    tracyMemWrite(item->hdr.type, QueueType::GpuZoneEndSerial);\n    tracyMemWrite(item->gpuZoneEnd.cpuTime, apiEnd);\n    tracyMemWrite(item->gpuZoneEnd.thread, threadId);\n    tracyMemWrite(item->gpuZoneEnd.queryId, uint16_t(queryId+1));\n    tracyMemWrite(item->gpuZoneEnd.context, gpuContextId);\n    Profiler::QueueSerialFinish();\n}\n\nvoid tracySubmitGpuTimestamp(CUptiTimestamp gpuStart, CUptiTimestamp gpuEnd,\n    uint16_t queryId, uint8_t gpuContextId) {\n    using namespace tracy;\n\n    auto item = Profiler::QueueSerial();\n    tracyMemWrite(item->hdr.type, QueueType::GpuTime);\n    tracyMemWrite(item->gpuTime.gpuTime, (int64_t)gpuStart);\n    tracyMemWrite(item->gpuTime.queryId, uint16_t(queryId+0));\n    tracyMemWrite(item->gpuTime.context, gpuContextId);\n    Profiler::QueueSerialFinish();\n\n    item = Profiler::QueueSerial();\n    tracyMemWrite(item->hdr.type, QueueType::GpuTime);\n    tracyMemWrite(item->gpuTime.gpuTime, (int64_t)gpuEnd);\n    tracyMemWrite(item->gpuTime.queryId, uint16_t(queryId+1));\n    tracyMemWrite(item->gpuTime.context, gpuContextId);\n    Profiler::QueueSerialFinish();\n}\n\n#define CUPTI_API_CALL(call) CUptiCallChecked(call, #call, __FILE__, __LINE__)\n\n#define DRIVER_API_CALL(call) cudaDriverCallChecked(call, #call, __FILE__, __LINE__)\n\nCUptiResult CUptiCallChecked(CUptiResult result, const char* call, const char* file, int line) noexcept {\n    if (result == CUPTI_SUCCESS)\n        return result;\n    const char* resultMsg = \"\";\n    CUPTI_API_CALL(cuptiGetResultString(result, &resultMsg));   // maybe not a good idea to recurse here...\n    fprintf(stderr, \"ERROR:\\t%s:%d:\\n\\tfunction '%s' failed with error '%s'.\\n\", file, line, call, resultMsg);\n    //assert(result == CUPTI_SUCCESS);\n    return result;\n}\n\nCUresult cudaDriverCallChecked(CUresult result, const char* call, const char* file, int line) noexcept {\n    if (result == CUDA_SUCCESS)\n        return result;\n    const char* resultMsg = \"\";\n    DRIVER_API_CALL(cuGetErrorString(result, &resultMsg));   // maybe not a good idea to recurse here...\n    fprintf(stderr, \"ERROR:\\t%s:%d:\\n\\tfunction '%s' failed with error '%s'.\\n\", file, line, call, resultMsg);\n    //assert(result == CUDA_SUCCESS);\n    return result;\n}\n\ntemplate<typename TKey, typename TValue>\nstruct ConcurrentHashMap {\n    static constexpr bool instrument = false;\n    auto acquire_read_lock() {\n        if (m.try_lock_shared())\n            return std::shared_lock<std::shared_mutex>(m, std::adopt_lock);\n        ZoneNamedC(rwlock, tracy::Color::Tomato, instrument);\n        return std::shared_lock<std::shared_mutex>(m);\n    }\n    auto acquire_write_lock() {\n        if (m.try_lock())\n            return std::unique_lock<std::shared_mutex>(m, std::adopt_lock);\n        ZoneNamedC(wxlock, tracy::Color::Tomato, instrument);\n        return std::unique_lock<std::shared_mutex>(m);\n    }\n    std::unordered_map<TKey, TValue> mapping;\n    std::shared_mutex m;\n    auto& operator[](TKey key) {\n        {\n            auto lock = acquire_read_lock();\n            auto it = mapping.find(key);\n            if (it != mapping.end()) {\n                return it->second;\n            }\n        }\n        return emplace(key, TValue{}).first->second;\n    }\n    auto find(TKey key) {\n        ZoneNamed(find, instrument);\n        auto lock = acquire_read_lock();\n        return mapping.find(key);\n    }\n    auto fetch(TKey key, TValue& value) {\n        ZoneNamed(fetch, instrument);\n        auto it = mapping.find(key);\n        if (it != mapping.end()) {\n            value = it->second;\n            return true;\n        }\n        return false;\n    }\n    auto end() {\n        ZoneNamed(end, instrument);\n        auto lock = acquire_read_lock();\n        return mapping.end();\n    }\n    template<typename... Args>\n    auto emplace(TKey key, Args&&... args) {\n        ZoneNamed(emplace, instrument);\n        auto lock = acquire_write_lock();\n        return mapping.emplace(std::forward<TKey>(key), std::forward<Args>(args)...);\n    }\n    auto erase(TKey key) {\n        ZoneNamed(erase, instrument);\n        auto lock = acquire_write_lock();\n        return mapping.erase(key);\n    }\n};\n\n#if TRACY_CUDA_ENABLE_CUDA_CALL_STATS\nstruct ProfilerStats {\n    static constexpr bool instrument = false;\n\n    ConcurrentHashMap<uint32_t, std::atomic<int>> apiCallCount;\n\n    void update(CUpti_CallbackDomain domain, CUpti_CallbackId cbid) {\n        ZoneNamed(update, instrument);\n        uint32_t key = (domain << 24) | (cbid & 0x00'FFFFFF);\n        auto it = apiCallCount.find(key);\n        if (it == apiCallCount.end()) {\n            it = apiCallCount.emplace(key, 0).first;\n        }\n        it->second.fetch_add(1, std::memory_order::memory_order_relaxed);\n    }\n};\n#endif\n\n// StringTable: string memoization/interning\nstruct StringTable {\n    static constexpr bool instrument = false;\n\n    // TODO(marcos): this could be just a \"ConcurrentHashSet\"\n    ConcurrentHashMap<std::string_view, std::string_view> table;\n\n    ~StringTable() { /* TODO(marcos): free string copy */ }\n\n    std::string_view operator[](std::string_view str) {\n        ZoneNamedN(lookup, \"StringTable::lookup\", instrument);\n        std::string_view memoized;\n        if (!table.fetch(str, memoized)) {\n            ZoneNamedN(lookup, \"StringTable::insert\", instrument);\n            char* copy = (char*)tracyMalloc(str.size() + 1);\n            strncpy(copy, str.data(), str.size());\n            copy[str.size()] = '\\0';\n            std::string_view value (copy, str.size());\n            auto [it, inserted] = table.emplace(value, value);\n            if (!inserted) {\n                // another thread inserted it while we were trying to: cleanup\n                tracyFree(copy);\n            }\n            memoized = it->second;\n        }\n        assert(str == memoized);\n        return memoized;\n    }\n};\n\nstruct SourceLocationMap {\n    static constexpr bool instrument = false;\n\n    // NOTE(marcos): the address of an unordered_map value may become invalid\n    // later on (e.g., during a rehash), so mapping to a pointer is necessary\n    ConcurrentHashMap<std::string_view, tracy::SourceLocationData*> locations;\n\n    ~SourceLocationMap() { /* TODO(marcos): free SourceLocationData* entries */ }\n\n    tracy::SourceLocationData* retrieve(std::string_view function) {\n        ZoneNamed(retrieve, instrument);\n        tracy::SourceLocationData* pSrcLoc = nullptr;\n        locations.fetch(function, pSrcLoc);\n        return pSrcLoc;\n    }\n\n    tracy::SourceLocationData* add(std::string_view function, std::string_view file, int line, uint32_t color=0) {\n        ZoneNamed(emplace, instrument);\n        assert(*function.end() == '\\0');\n        assert(*file.end() == '\\0');\n        void* bytes = tracyMalloc(sizeof(tracy::SourceLocationData));\n        auto pSrcLoc = new(bytes)tracy::SourceLocationData{ function.data(), TracyFunction, file.data(), (uint32_t)line, color };\n        auto [it, inserted] = locations.emplace(function, pSrcLoc);\n        if (!inserted) {\n            // another thread inserted it while we were trying to: cleanup\n            tracyFree(pSrcLoc); // POD: no destructor to call\n        }\n        assert(it->second != nullptr);\n        return it->second;\n    }\n};\n\nstruct SourceLocationLUT {\n    static constexpr bool instrument = false;\n\n    ~SourceLocationLUT() { /* no action needed: no dynamic allocation */ }\n\n    tracy::SourceLocationData runtime [CUpti_runtime_api_trace_cbid::CUPTI_RUNTIME_TRACE_CBID_SIZE] = {};\n    tracy::SourceLocationData driver [CUpti_driver_api_trace_cbid::CUPTI_DRIVER_TRACE_CBID_SIZE] = {};\n\n    tracy::SourceLocationData* retrieve(CUpti_CallbackDomain domain, CUpti_CallbackId cbid, CUpti_CallbackData* apiInfo) {\n        ZoneNamed(retrieve, instrument);\n        tracy::SourceLocationData* pSrcLoc = nullptr;\n        switch (domain) {\n        case CUPTI_CB_DOMAIN_RUNTIME_API :\n            if ((cbid > 0) && (cbid < CUPTI_RUNTIME_TRACE_CBID_SIZE)) {\n                pSrcLoc = &runtime[cbid];\n            }\n            break;\n        case CUPTI_CB_DOMAIN_DRIVER_API :\n            if ((cbid > 0) && (cbid < CUPTI_DRIVER_TRACE_CBID_SIZE)) {\n                pSrcLoc = &driver[cbid];\n            }\n            break;\n        default:\n            break;\n        }\n        if (pSrcLoc->name == nullptr) {\n            const char* function = apiInfo->functionName ? apiInfo->functionName : \"cuda???\";\n            // cuptiGetCallbackName includes the \"version suffix\" of the function/cbid\n            //CUPTI_API_CALL(cuptiGetCallbackName(domain, cbid, &function));\n            *pSrcLoc = tracy::SourceLocationData{ function, TracyFunction, TracyFile, TracyLine, 0 };\n        }\n        return pSrcLoc;\n    }\n};\n\nuint32_t tracyTimelineId(uint32_t contextId, uint32_t streamId) {\n    // 0xA7C5 = 42,949 => 42,949 * 100,000 = 4,294,900,000\n    // 4,294,900,000 + 65,535  = 4,294,965,535 < 4,294,967,295 (max uint32)\n    assert(contextId <= 0xA7C5);\n    assert((streamId == CUPTI_INVALID_STREAM_ID) || (streamId < 0xFFFF));\n    uint32_t packed = (contextId * 100'000) + (streamId & 0x0000'FFFF);\n    return packed;\n}\n\n} // unnamed/anonymous namespace\n\nnamespace tracy\n{\n    class CUDACtx\n    {\n    public:\n        static CUDACtx* Create() {\n            auto& s = Singleton::Get();\n            std::unique_lock<std::mutex> lock (s.m);\n            if (s.ref_count == 0) {\n                assert(s.ctx == nullptr);\n                s.ctx = new CUDACtx(s.ctx_id);\n                s.ref_count += 1;\n                s.ctx_id = s.ctx->m_tracyGpuContext;\n            }\n            return s.ctx;\n        }\n\n        static void Destroy(CUDACtx* ctx) {\n            auto& s = Singleton::Get();\n            std::unique_lock<std::mutex> lock(s.m);\n            assert(ctx == s.ctx);\n            s.ref_count -= 1;\n            if (s.ref_count == 0) {\n                delete s.ctx;\n                s.ctx = nullptr;\n            }\n        }\n\n        void Collect()\n        {\n            ZoneScoped;\n            CUPTI::FlushActivity();\n        }\n\n        void printStats()\n        {\n            #if TRACY_CUDA_ENABLE_CUDA_CALL_STATS\n            fprintf(stdout, \"\\nCUDA API stats:\\n\");\n            {\n                struct Stats { CUpti_CallbackDomain domain; CUpti_CallbackId cbid; int count; };\n                std::vector<Stats> sorted;\n                for (auto&& api : stats.apiCallCount.mapping) {\n                    auto domain = CUpti_CallbackDomain(api.first >> 24);\n                    auto cbid = CUpti_CallbackId(api.first & 0x00'FFFFFF);\n                    int count = api.second;\n                    sorted.emplace_back(Stats{ domain, cbid, count });\n                }\n                std::sort(sorted.begin(), sorted.end(), [](const Stats& x, const Stats& y) { return x.count > y.count; });\n                for (auto&& api : sorted) {\n                    const char* function = \"\";\n                    CUPTI_API_CALL(cuptiGetCallbackName(api.domain, api.cbid, &function));\n                    printf(\"- %s : %d\\n\", function, api.count);\n                }\n            }\n            #endif\n        }\n\n        void StartProfiling()\n        {\n            ZoneScoped;\n            CUPTI::BeginInstrumentation(this);\n        }\n\n        void StopProfiling()\n        {\n            ZoneScoped;\n            CUPTI::EndInstrumentation();\n            printStats();\n        }\n\n        void Name(const char *name, uint16_t len)\n        {\n            auto ptr = (char*)tracyMalloc(len);\n            memcpy(ptr, name, len);\n\n            auto item = Profiler::QueueSerial();\n            tracyMemWrite(item->hdr.type, QueueType::GpuContextName);\n            tracyMemWrite(item->gpuContextNameFat.context, m_tracyGpuContext);\n            tracyMemWrite(item->gpuContextNameFat.ptr, (uint64_t)ptr);\n            tracyMemWrite(item->gpuContextNameFat.size, len);\n            SubmitQueueItem(item);\n        }\n\n        tracy_force_inline void SubmitQueueItem(tracy::QueueItem *item)\n        {\n#ifdef TRACY_ON_DEMAND\n            GetProfiler().DeferItem(*item);\n#endif\n            Profiler::QueueSerialFinish();\n        }\n\n        static void QueryTimestamps(TracyTimestamp& tTracy, CUptiTimestamp& tCUpti) {\n            TracyTimestamp tTracy1 = tracyGetTimestamp();\n            CUPTI_API_CALL(cuptiGetTimestamp(&tCUpti));\n            TracyTimestamp tTracy2 = tracyGetTimestamp();\n            // NOTE(marcos): giving more weight to 'tTracy2'\n            tTracy = (3*tTracy1 + 5*tTracy2) / 8;\n        }\n\n        // NOTE(marcos): recalibration is 'static' since Tracy and CUPTI timestamps\n        // are \"global\" across all contexts; that said, each Tracy GPU context needs\n        // its own GpuCalibration message, but for now there's just a singleton context.\n        void Recalibrate() {\n            ZoneScoped;\n            // NOTE(marcos): only one thread should do the calibration, but there's\n            // no good reason to block threads that also trying to do the same\n            static std::mutex m;\n            if (!m.try_lock())\n                return;\n            std::unique_lock<std::mutex> lock (m, std::adopt_lock);\n            ZoneNamedNC(zone, \"tracy::CUDACtx::Recalibrate[effective]\", tracy::Color::Goldenrod, true);\n            TracyTimestamp tTracy;\n            CUptiTimestamp tCUpti;\n            QueryTimestamps(tTracy, tCUpti);\n            #if TRACY_CUDA_CALIBRATED_CONTEXT\n            static CUptiTimestamp prevCUptiTime = tCUpti;\n            int64_t deltaTicksCUpti = tCUpti - prevCUptiTime;\n            if (deltaTicksCUpti > 0) {\n                prevCUptiTime = tCUpti;\n                auto* item = Profiler::QueueSerial();\n                tracyMemWrite(item->hdr.type, QueueType::GpuCalibration);\n                tracyMemWrite(item->gpuCalibration.gpuTime, (int64_t)tCUpti);\n                tracyMemWrite(item->gpuCalibration.cpuTime, tTracy);\n                tracyMemWrite(item->gpuCalibration.cpuDelta, deltaTicksCUpti);\n                tracyMemWrite(item->gpuCalibration.context, m_tracyGpuContext);\n                Profiler::QueueSerialFinish();\n            }\n            #endif\n            // NOTE(marcos): update linear regression incrementally, which will refine\n            // the estimation of Tracy timestamps (Y) from CUpti timestamps (X)\n            static IncrementalRegression model;\n            model.addSample(double(tCUpti), double(tTracy));\n            // NOTE(marcos): using orthogonal regression because the independet variable\n            // (X: CUpti timestamps) measurements are also imprecise\n            getCachedRegressionParameters() = model.orthogonal();\n        }\n\n    protected:\n        void EmitGpuZone(TracyTimestamp apiStart, TracyTimestamp apiEnd,\n            CUptiTimestamp gpuStart, CUptiTimestamp gpuEnd,\n            const tracy::SourceLocationData* pSrcLoc,\n            uint32_t cudaContextId, uint32_t cudaStreamId) {\n            //uint32_t timelineId = tracy::GetThreadHandle();\n            uint32_t timelineId = tracyTimelineId(cudaContextId, cudaStreamId);\n            uint16_t queryId = m_queryIdGen.fetch_add(2);\n            tracyAnnounceGpuTimestamp(apiStart, apiEnd, queryId, m_tracyGpuContext, pSrcLoc, timelineId);\n            tracySubmitGpuTimestamp(gpuStart, gpuEnd, queryId, m_tracyGpuContext);\n        }\n\n        void OnEventsProcessed() {\n            Recalibrate();\n        }\n\n        struct CUPTI {\n        static void CUPTIAPI OnBufferRequested(uint8_t **buffer, size_t *size, size_t *maxNumRecords)\n        {\n            ZoneScoped;\n            // TODO(marcos): avoid malloc and instead suballocate from a large circular buffer;\n            // according to the CUPTI documentation: \"To minimize profiling overhead the client\n            // should return as quickly as possible from these callbacks.\"\n            *size = 1 * 1024*1024; // 1MB\n            *buffer = (uint8_t*)tracyMalloc(*size);\n            assert(*buffer != nullptr);\n            FlushActivityAsync();\n        }\n\n        static void CUPTIAPI OnBufferCompleted(CUcontext ctx, uint32_t streamId, uint8_t* buffer, size_t size, size_t validSize)\n        {\n            // CUDA 6.0 onwards: all buffers from this callback are \"global\" buffers\n            // (i.e. there is no context/stream specific buffer; ctx is always NULL)\n            ZoneScoped;\n            tracy::SetThreadName(\"NVIDIA CUPTI Worker\");\n            CUptiResult status;\n            CUpti_Activity* record = nullptr;\n            while ((status = cuptiActivityGetNextRecord(buffer, validSize, &record)) == CUPTI_SUCCESS) {\n                DoProcessDeviceEvent(record);\n            }\n            if (status != CUPTI_ERROR_MAX_LIMIT_REACHED) {\n                CUptiCallChecked(status, \"cuptiActivityGetNextRecord\", TracyFile, TracyLine);\n            }\n            size_t dropped = 0;\n            CUPTI_API_CALL(cuptiActivityGetNumDroppedRecords(ctx, streamId, &dropped));\n            assert(dropped == 0);\n            tracyFree(buffer);\n            PersistentState::Get().profilerHost->OnEventsProcessed();\n        }\n\n        // correlationID -> [CPU start time, CPU end time, CUPTI start time]\n        using CorrelationID = uint32_t;\n        struct APICallInfo { TracyTimestamp start = 0, end = 0; CUptiTimestamp cupti = CUPTI_TIMESTAMP_UNKNOWN; CUDACtx* host = nullptr; };\n\n        static void CUPTIAPI OnCallbackAPI(\n            void* userdata,\n            CUpti_CallbackDomain domain,\n            CUpti_CallbackId cbid,\n            const void* cbdata)\n        {\n            static constexpr bool instrument = false;\n\n            TracyTimestamp apiCallStartTime = tracyGetTimestamp();\n            CUDACtx* profilerHost = (CUDACtx*)userdata;\n\n            switch (domain) {\n            case CUPTI_CB_DOMAIN_RUNTIME_API:\n            case CUPTI_CB_DOMAIN_DRIVER_API:\n                break;\n            case CUPTI_CB_DOMAIN_RESOURCE: {\n                // match 'callbackId' with CUpti_CallbackIdResource\n                // interpret 'cbdata' as CUpti_ResourceData,\n                //                 or as CUpti_ModuleResourceData,\n                //                 or as CUpti_GraphData,\n                //                 or as CUpti_StreamAttrData,\n                //                 or as ... (what else?)\n                return;\n            }\n            case CUPTI_CB_DOMAIN_SYNCHRONIZE: {\n                // match 'callbackId' with CUpti_CallbackIdSync\n                // interpret 'cbdata' as CUpti_SynchronizeData\n                return;\n            }\n            case CUPTI_CB_DOMAIN_STATE: {\n                // match 'callbackId' with CUpti_CallbackIdState\n                // interpret 'cbdata' as CUpti_StateData\n                return;\n            }\n            case CUPTI_CB_DOMAIN_NVTX: {\n                // match 'callbackId' with CUpti_nvtx_api_trace_cbid\n                // interpret 'cbdata' as CUpti_NvtxData\n                return;\n            }\n            case CUPTI_CB_DOMAIN_FORCE_INT:\n                // NOTE(marcos): the \"FORCE_INT\" values in CUPTI enums exist only to\n                // force the enum to have a specific representation (signed 32bits)\n            case CUPTI_CB_DOMAIN_INVALID:\n            default:\n                // TODO(marcos): unexpected error!\n                return;\n            }\n    \n            // if we reached this point, then we are in the (runtime or driver) API domain\n            CUpti_CallbackData* apiInfo = (CUpti_CallbackData*)cbdata;\n\n            // Emit the Tracy 'ZoneBegin' message upon entering the API call\n            // TODO(marcos): a RAII object could be useful here...\n            if (apiInfo->callbackSite == CUPTI_API_ENTER) {\n                #if TRACY_CUDA_ENABLE_CUDA_CALL_STATS\n                ctx->stats.update(domain, cbid);\n                #endif\n\n                auto& cudaCallSourceLocation = PersistentState::Get().cudaCallSourceLocation;\n                auto pSrcLoc = cudaCallSourceLocation.retrieve(domain, cbid, apiInfo);\n\n                // HACK(marcos): the SourceLocationLUT::retrieve zone (above) should\n                // not be emitted before its enclosing zone (below) actually begins,\n                // so we delay the beginning of the enclosing zone to \"unstack\" them\n                if (SourceLocationLUT::instrument)\n                    apiCallStartTime = tracyGetTimestamp();\n                tracyZoneBegin(apiCallStartTime, pSrcLoc);\n            }\n\n            if (apiInfo->callbackSite == CUPTI_API_ENTER) {\n                ZoneNamedN(enter, \"tracy::CUDACtx::OnCUptiCallback[enter]\", instrument);\n                // Track API calls that generate device activity:\n                bool trackDeviceActivity = false;\n                CUstream hStream = nullptr;\n                if (domain == CUPTI_CB_DOMAIN_RUNTIME_API) {\n                    #define GET_STREAM_FUNC(Params, field) [](CUpti_CallbackData* api) { return ((Params*)api->functionParams)->field; }\n                    #define NON_STREAM_FUNC() [](CUpti_CallbackData*) { return cudaStream_t(nullptr); }\n                    static std::unordered_map<CUpti_runtime_api_trace_cbid, cudaStream_t(*)(CUpti_CallbackData*)> cbidRuntimeTrackers = {\n                        // Runtime: Kernel\n                        { CUPTI_RUNTIME_TRACE_CBID_cudaLaunchKernel_v7000,          GET_STREAM_FUNC(cudaLaunchKernel_v7000_params, stream) },\n                        { CUPTI_RUNTIME_TRACE_CBID_cudaLaunchKernel_ptsz_v7000,     GET_STREAM_FUNC(cudaLaunchKernel_ptsz_v7000_params, stream) },\n                        { CUPTI_RUNTIME_TRACE_CBID_cudaLaunchKernelExC_v11060,      GET_STREAM_FUNC(cudaLaunchKernelExC_v11060_params, config->stream) },\n                        { CUPTI_RUNTIME_TRACE_CBID_cudaLaunchKernelExC_ptsz_v11060, GET_STREAM_FUNC(cudaLaunchKernelExC_ptsz_v11060_params, config->stream) },\n                        // Runtime: Memory\n                        { CUPTI_RUNTIME_TRACE_CBID_cudaMalloc_v3020, NON_STREAM_FUNC() },\n                        { CUPTI_RUNTIME_TRACE_CBID_cudaFree_v3020,   NON_STREAM_FUNC() },\n                        // Runtime: Memcpy\n                        { CUPTI_RUNTIME_TRACE_CBID_cudaMemcpy_v3020,      NON_STREAM_FUNC() },\n                        { CUPTI_RUNTIME_TRACE_CBID_cudaMemcpyAsync_v3020, GET_STREAM_FUNC(cudaMemcpyAsync_v3020_params, stream) },\n                        // Runtime: Memset\n                        { CUPTI_RUNTIME_TRACE_CBID_cudaMemset_v3020,      NON_STREAM_FUNC() },\n                        { CUPTI_RUNTIME_TRACE_CBID_cudaMemsetAsync_v3020, GET_STREAM_FUNC(cudaMemsetAsync_v3020_params, stream) },\n                        // Runtime: Synchronization\n                        { CUPTI_RUNTIME_TRACE_CBID_cudaStreamSynchronize_v3020, NON_STREAM_FUNC() },\n                        { CUPTI_RUNTIME_TRACE_CBID_cudaEventSynchronize_v3020,  NON_STREAM_FUNC() },\n                        { CUPTI_RUNTIME_TRACE_CBID_cudaEventQuery_v3020,        NON_STREAM_FUNC() },\n                        { CUPTI_RUNTIME_TRACE_CBID_cudaStreamWaitEvent_v3020,   NON_STREAM_FUNC() },\n                        { CUPTI_RUNTIME_TRACE_CBID_cudaDeviceSynchronize_v3020, NON_STREAM_FUNC() },\n                    };\n                    #undef NON_STREAM_FUNC\n                    #undef GET_STREAM_FUNC\n                    auto it = cbidRuntimeTrackers.find(CUpti_runtime_api_trace_cbid(cbid));\n                    if (it != cbidRuntimeTrackers.end()) {\n                        trackDeviceActivity = true;\n                        hStream = (CUstream)it->second(apiInfo);\n                    }\n                }\n                if (domain == CUPTI_CB_DOMAIN_DRIVER_API) {\n                    #define GET_STREAM_FUNC(Params, field) [](CUpti_CallbackData* api) { return ((Params*)api->functionParams)->field; }\n                    #define NON_STREAM_FUNC() [](CUpti_CallbackData*) { return CUstream(nullptr); }\n                    static std::unordered_map<CUpti_driver_api_trace_cbid, CUstream(*)(CUpti_CallbackData*)> cbidDriverTrackers = {\n                        // Driver: Kernel\n                        { CUPTI_DRIVER_TRACE_CBID_cuLaunchKernel,        GET_STREAM_FUNC(cuLaunchKernel_params, hStream) },\n                        { CUPTI_DRIVER_TRACE_CBID_cuLaunchKernel_ptsz,   GET_STREAM_FUNC(cuLaunchKernel_ptsz_params, hStream)} ,\n                        { CUPTI_DRIVER_TRACE_CBID_cuLaunchKernelEx,      GET_STREAM_FUNC(cuLaunchKernelEx_params, config->hStream) },\n                        { CUPTI_DRIVER_TRACE_CBID_cuLaunchKernelEx_ptsz, GET_STREAM_FUNC(cuLaunchKernelEx_params, config->hStream) },\n                    };\n                    #undef NON_STREAM_FUNC\n                    #undef GET_STREAM_FUNC\n                    auto it = cbidDriverTrackers.find(CUpti_driver_api_trace_cbid(cbid));\n                    if (it != cbidDriverTrackers.end()) {\n                        trackDeviceActivity = true;\n                        hStream = it->second(apiInfo);\n                    }\n                }\n                if (trackDeviceActivity) {\n                    // NOTE(marcos): we should NOT track if the stream is being captured\n                    CUstreamCaptureStatus status = {};\n                    DRIVER_API_CALL(cuStreamIsCapturing(hStream, &status));\n                    trackDeviceActivity = !(status == CU_STREAM_CAPTURE_STATUS_ACTIVE);\n                }\n                if (trackDeviceActivity) {\n                    CUptiTimestamp tgpu;\n                    // TODO(marcos): do a \"reverse-estimate\" to obtain CUpti time from Tracy time instead?\n                    CUPTI_API_CALL(cuptiGetTimestamp(&tgpu));\n                    auto& cudaCallSiteInfo = PersistentState::Get().cudaCallSiteInfo;\n                    cudaCallSiteInfo.emplace(apiInfo->correlationId, APICallInfo{ apiCallStartTime, apiCallStartTime, tgpu, profilerHost });\n                }\n                auto& entryFlags = *apiInfo->correlationData;\n                assert(entryFlags == 0);\n                entryFlags |= trackDeviceActivity ? 0x8000 : 0;\n            }\n\n            if (apiInfo->callbackSite == CUPTI_API_EXIT) {\n                APICallInfo* pApiInterval = [](CUpti_CallbackData* apiInfo) {\n                    ZoneNamedN(exit, \"tracy::CUDACtx::OnCUptiCallback[exit]\", instrument);\n                    auto entryFlags = *apiInfo->correlationData;\n                    bool trackDeviceActivity = (entryFlags & 0x8000) != 0;\n                    if (trackDeviceActivity) {\n                        auto& cudaCallSiteInfo = PersistentState::Get().cudaCallSiteInfo;\n                        auto it = cudaCallSiteInfo.find(apiInfo->correlationId);\n                        if (it != cudaCallSiteInfo.end()) {\n                            // WARN(marcos): leaking the address of a hash-map value could spell trouble\n                            return &it->second;\n                        }\n                    }\n                    // NOTE(marcos): this can happen if the GPU activity completes\n                    // before the CUDA function that enqueued it returns (e.g., sync)\n                    static APICallInfo sentinel;\n                    return &sentinel;\n                }(apiInfo);\n                pApiInterval->end = tracyGetTimestamp();\n                tracyZoneEnd(pApiInterval->end);\n            }\n        }\n\n        static bool matchActivityToAPICall(uint32_t correlationId, APICallInfo& apiCallInfo) {\n            static constexpr bool instrument = false;\n            ZoneNamed(match, instrument);\n            auto& cudaCallSiteInfo = PersistentState::Get().cudaCallSiteInfo;\n            if (!cudaCallSiteInfo.fetch(correlationId, apiCallInfo)) {\n                return false;\n            }\n            cudaCallSiteInfo.erase(correlationId);\n            assert(apiCallInfo.host != nullptr);\n            return true;\n        }\n\n        static void matchError(uint32_t correlationId, const char* kind) {\n            char msg [128];\n            snprintf(msg, sizeof(msg), \"ERROR: device activity '%s' has no matching CUDA API call (id=%u).\", kind, correlationId);\n            TracyMessageC(msg, strlen(msg), tracy::Color::Tomato);\n        }\n\n        static std::string extractActualName(char** name){\n            //If name does not start with number, return empty string\n            if (!isdigit(**name))\n            {\n                return std::string();\n            }\n            // Assuming name starts with number followed by actual name\n            std::string actualName;\n            char* currStr = *name;\n            int num = 0;\n            while (*currStr >= '0' && *currStr <= '9')\n            {\n                num = num * 10 + (*currStr - '0');\n                currStr++;\n            }\n\n            // Return the string start at currStr ends at num\n            actualName = std::string(currStr, num);\n            // check if actualName starts with _GLOBAL__N__\n            if (actualName.rfind(\"_GLOBAL__N__\", 0) == 0)\n            {\n                // _GLOBAL__N__ with an id stands for anonymous namespace\n                actualName = std::string(\"(anonymous_namespace)\");\n            }\n\n            *name = currStr + num;\n            return actualName;\n        }\n\n        static std::string extractActualNameNested(const char* demangledName)\n        {\n            ZoneNamedN(demangle, \"demangle_kernel\", false);\n            //If name does not start with _Z, return a new std::string with original name\n            if (demangledName[0] != '_' || demangledName[1] != 'Z')\n            {\n                return std::string(demangledName);\n            }\n            std::string actualName;\n            char* currStr = (char*)demangledName + 2;\n\n            if (*currStr == 'N')\n            {\n                currStr++;\n                // extract actual name from nested name\n                std::string nestedName = extractActualName(&currStr);\n                actualName += nestedName;\n                while (1)\n                {\n                    //Loop until nested name is empty\n                    nestedName = extractActualName(&currStr);\n                    if (nestedName.empty())\n                    {\n                        break;\n                    }\n                    actualName += \"::\" + nestedName;\n                }\n            } else\n            {\n                actualName = extractActualName(&currStr);\n            }\n            return actualName;\n        }\n\n        static tracy::SourceLocationData* getKernelSourceLocation(const char* kernelName)\n        {\n            auto& kernelSrcLoc = PersistentState::Get().kernelSrcLoc;\n            std::string_view demangledName;\n        #ifndef _MSC_VER\n            // TODO(marcos): extractActualNameNested is the main bottleneck right now;\n            // we need a specialized StringTable mapping from \"peristent\" kernel names\n            // (const char*/uintptr_t) to memoized, lazily initialized demangled names\n            auto& demangledNameTable = PersistentState::Get().demangledNameTable;\n            std::string demangled = extractActualNameNested(kernelName);\n            demangledName = demangledNameTable[demangled];\n        #else\n            demangledName = kernelName;\n        #endif\n            auto pSrcLoc = kernelSrcLoc.retrieve(demangledName);\n            if (pSrcLoc == nullptr) {\n                pSrcLoc = kernelSrcLoc.add(demangledName, TracyFile, TracyLine);\n            }\n            return pSrcLoc;\n        }\n\n        static void DoProcessDeviceEvent(CUpti_Activity *record)\n        {\n            static constexpr bool instrument = false;\n            ZoneNamed(activity, instrument);\n\n            switch (record->kind)\n            {\n            case CUPTI_ACTIVITY_KIND_CONCURRENT_KERNEL:\n            {   \n                ZoneNamedN(kernel, \"tracy::CUDACtx::DoProcessDeviceEvent[kernel]\", instrument);\n                CUpti_ActivityKernel9* kernel9 = (CUpti_ActivityKernel9*) record;\n                APICallInfo apiCall;\n                if (!matchActivityToAPICall(kernel9->correlationId, apiCall)) {\n                    return matchError(kernel9->correlationId, \"KERNEL\");\n                }\n                apiCall.host->EmitGpuZone(apiCall.start, apiCall.end, kernel9->start, kernel9->end, getKernelSourceLocation(kernel9->name), kernel9->contextId, kernel9->streamId);\n                auto latency_ms = (kernel9->start - apiCall.cupti) / 1'000'000.0;\n                tracyPlotBlip(\"Kernel Latency (ms)\", kernel9->start, latency_ms);\n                break;\n            }\n\n            case CUPTI_ACTIVITY_KIND_MEMCPY:\n            {\n                ZoneNamedN(kernel, \"tracy::CUDACtx::DoProcessDeviceEvent[memcpy]\", instrument);\n                CUpti_ActivityMemcpy5* memcpy5 = (CUpti_ActivityMemcpy5*) record;\n                APICallInfo apiCall;\n                if (!matchActivityToAPICall(memcpy5->correlationId, apiCall)) {\n                    return matchError(memcpy5->correlationId, \"MEMCPY\");\n                }\n                static constexpr tracy::SourceLocationData TracyCUPTISrcLocDeviceMemcpy { \"CUDA::memcpy\", TracyFunction, TracyFile, (uint32_t)TracyLine, tracy::Color::Blue };\n                apiCall.host->EmitGpuZone(apiCall.start, apiCall.end, memcpy5->start, memcpy5->end, &TracyCUPTISrcLocDeviceMemcpy, memcpy5->contextId, memcpy5->streamId);\n                static constexpr const char* graph_name = \"CUDA Memory Copy\";\n                tracyEmitMemAlloc(graph_name, (void*)(uintptr_t)memcpy5->correlationId, memcpy5->bytes, memcpy5->start);\n                tracyEmitMemFree (graph_name, (void*)(uintptr_t)memcpy5->correlationId,                 memcpy5->end);\n                break;\n            }\n\n            case CUPTI_ACTIVITY_KIND_MEMSET:\n            {\n                ZoneNamedN(kernel, \"tracy::CUDACtx::DoProcessDeviceEvent[memset]\", instrument);\n                CUpti_ActivityMemset4* memset4 = (CUpti_ActivityMemset4*) record;\n                APICallInfo apiCall;\n                if (!matchActivityToAPICall(memset4->correlationId, apiCall)) {\n                    return matchError(memset4->correlationId, \"MEMSET\");\n                }\n                static constexpr tracy::SourceLocationData TracyCUPTISrcLocDeviceMemset { \"CUDA::memset\", TracyFunction, TracyFile, (uint32_t)TracyLine, tracy::Color::Blue };\n                apiCall.host->EmitGpuZone(apiCall.start, apiCall.end, memset4->start, memset4->end, &TracyCUPTISrcLocDeviceMemset, memset4->contextId, memset4->streamId);\n                static constexpr const char* graph_name = \"CUDA Memory Set\";\n                tracyEmitMemAlloc(graph_name, (void*)(uintptr_t)memset4->correlationId, memset4->bytes, memset4->start);\n                tracyEmitMemFree (graph_name, (void*)(uintptr_t)memset4->correlationId,                 memset4->end);\n                break;\n            }\n\n            case CUPTI_ACTIVITY_KIND_SYNCHRONIZATION:\n            {\n                ZoneNamedN(kernel, \"tracy::CUDACtx::DoProcessDeviceEvent[sync]\", instrument);\n                CUpti_ActivitySynchronization* synchronization = (CUpti_ActivitySynchronization*) record;\n                APICallInfo apiCall;\n                if (!matchActivityToAPICall(synchronization->correlationId, apiCall)) {\n                    return matchError(synchronization->correlationId, \"SYNCHRONIZATION\");\n                }\n                // NOTE(marcos): synchronization can happen at different levels/objects:\n                // a. on the entire context : cuCtxSynchronize()    -> timeline(ctx,0)\n                // b. on a specific stream  : cuStreamSynchronize() -> timeline(ctx,stream)\n                // c. on a specific event   : cuEventSynchronize()  -> timeline(ctx,0xffff)\n                static constexpr tracy::SourceLocationData TracyCUPTISrcLocContextSynchronization { \"CUDA::Context::sync\", TracyFunction, TracyFile, (uint32_t)TracyLine, tracy::Color::Magenta };\n                auto* pSrcLoc = &TracyCUPTISrcLocContextSynchronization;\n                uint32_t cudaContextId = synchronization->contextId;\n                uint32_t cudaStreamId = 0;\n                if (synchronization->streamId != CUPTI_SYNCHRONIZATION_INVALID_VALUE) {\n                    static constexpr tracy::SourceLocationData TracyCUPTISrcLocStreamSynchronization{ \"CUDA::Stream::sync\", TracyFunction, TracyFile, (uint32_t)TracyLine, tracy::Color::Magenta3 };\n                    pSrcLoc = &TracyCUPTISrcLocStreamSynchronization;\n                    cudaStreamId = synchronization->streamId;\n                }\n                if (synchronization->cudaEventId != CUPTI_SYNCHRONIZATION_INVALID_VALUE) {\n                    static constexpr tracy::SourceLocationData TracyCUPTISrcLocEventSynchronization{ \"CUDA::Event::sync\", TracyFunction, TracyFile, (uint32_t)TracyLine, tracy::Color::Magenta4 };\n                    pSrcLoc = &TracyCUPTISrcLocEventSynchronization;\n                    cudaStreamId = 0xFFFFFFFF;\n                    // TODO(marcos): CUpti_ActivitySynchronization2 introduces a new\n                    // field 'cudaEventSyncId' which complements 'cudaEventId'\n                }\n                apiCall.host->EmitGpuZone(apiCall.start, apiCall.end, synchronization->start, synchronization->end, pSrcLoc, cudaContextId, cudaStreamId);\n                static constexpr const char* graph_name = \"CUDA Synchronization\";\n                tracyEmitMemAlloc(graph_name, (void*)(uintptr_t)synchronization->correlationId, 1, synchronization->start);\n                tracyEmitMemFree (graph_name, (void*)(uintptr_t)synchronization->correlationId,    synchronization->end);\n                break;\n            }\n            case CUPTI_ACTIVITY_KIND_MEMORY2:\n            {\n                ZoneNamedN(kernel, \"tracy::CUDACtx::DoProcessDeviceEvent[malloc/free]\", instrument);\n                CUpti_ActivityMemory3* memory3 = (CUpti_ActivityMemory3*)record;\n                APICallInfo apiCall;\n                if (!matchActivityToAPICall(memory3->correlationId, apiCall)) {\n                    return matchError(memory3->correlationId, \"MEMORY\");\n                }\n                static constexpr const char* graph_name = \"CUDA Memory Allocation\";\n                if (memory3->memoryOperationType == CUPTI_ACTIVITY_MEMORY_OPERATION_TYPE_ALLOCATION){\n                    auto& memAllocAddress = PersistentState::Get().memAllocAddress;\n                    memAllocAddress[memory3->address] = 1;\n                    tracyEmitMemAlloc(graph_name, (void*)memory3->address, memory3->bytes, memory3->timestamp);\n                }\n                else if (memory3->memoryOperationType == CUPTI_ACTIVITY_MEMORY_OPERATION_TYPE_RELEASE){\n                    auto& memAllocAddress = PersistentState::Get().memAllocAddress;\n                    int dontCare;\n                    if (!memAllocAddress.fetch(memory3->address, dontCare)){\n                        // Note(Frank): This is a hack to handle the case where the memory allocation\n                        // corresponds to the memory release is not found.\n                        // This can happen when the memory is allocated when profiling is not enabled.\n                        matchError(memory3->correlationId, \"MEMORY/RELEASE\");\n                        tracyEmitMemAlloc(graph_name, (void*)memory3->address, memory3->bytes, memory3->timestamp);\n                    } else {\n                        memAllocAddress.erase(memory3->address);\n                    }\n                    tracyEmitMemFree(graph_name, (void*)memory3->address, memory3->timestamp);\n                }\n                break;\n            }\n            case CUPTI_ACTIVITY_KIND_CUDA_EVENT :\n            {\n                // NOTE(marcos): a byproduct of CUPTI_ACTIVITY_KIND_SYNCHRONIZATION\n                // (I think this is related to cudaEvent*() API calls)\n                CUpti_ActivityCudaEvent2* event = (CUpti_ActivityCudaEvent2*)record;\n                UNREFERENCED(event);\n                break;\n            }\n            default:\n            {\n                char buffer[64];\n                snprintf(buffer, sizeof(buffer), \"Unknown activity record (kind is %d)\", record->kind);\n                TracyMessageC(buffer, strlen(buffer), tracy::Color::Crimson);\n                break;\n            }\n            }\n        }\n\n        static constexpr CUpti_CallbackDomain domains[] = {\n            CUPTI_CB_DOMAIN_RUNTIME_API,\n            CUPTI_CB_DOMAIN_DRIVER_API,\n            //CUPTI_CB_DOMAIN_RESOURCE,\n            //CUPTI_CB_DOMAIN_SYNCHRONIZE,\n            //CUPTI_CB_DOMAIN_NVTX,\n            //CUPTI_CB_DOMAIN_STATE\n        };\n\n        static constexpr CUpti_ActivityKind activities[] = {\n            //CUPTI_ACTIVITY_KIND_KERNEL, // mutually exclusive with CONCURRENT_KERNEL\n            CUPTI_ACTIVITY_KIND_CONCURRENT_KERNEL,\n            CUPTI_ACTIVITY_KIND_MEMCPY,\n            CUPTI_ACTIVITY_KIND_MEMSET,\n            CUPTI_ACTIVITY_KIND_SYNCHRONIZATION,\n            CUPTI_ACTIVITY_KIND_MEMORY2,\n            //CUPTI_ACTIVITY_KIND_MEMCPY2,\n            //CUPTI_ACTIVITY_KIND_OVERHEAD,\n            //CUPTI_ACTIVITY_KIND_INTERNAL_LAUNCH_API,\n            //CUPTI_ACTIVITY_KIND_RUNTIME,\n            //CUPTI_ACTIVITY_KIND_DRIVER,\n        };\n\n        static void BeginInstrumentation(CUDACtx* profilerHost) {\n            auto& currentProfilerHost = PersistentState::Get().profilerHost;\n            if (currentProfilerHost != nullptr) {\n                return;\n            }\n            currentProfilerHost = profilerHost;\n\n            // NOTE(frank): full-stop synchronization to ensure we only handle\n            // CUDA API calls and device activities that happens past this point\n            cudaDeviceSynchronize();\n\n            auto& subscriber = PersistentState::Get().subscriber;\n            CUPTI_API_CALL(cuptiSubscribe(&subscriber, CUPTI::OnCallbackAPI, profilerHost));\n            CUPTI_API_CALL(cuptiActivityRegisterCallbacks(CUPTI::OnBufferRequested, CUPTI::OnBufferCompleted));\n            for (auto domain : domains) {\n                CUPTI_API_CALL(cuptiEnableDomain(uint32_t(true), subscriber, domain));\n            }\n            for (auto activity : activities) {\n                CUPTI_API_CALL(cuptiActivityEnable(activity));\n            }\n\n            #if TRACY_CUDA_ENABLE_COLLECTOR_THREAD\n            auto& collector = PersistentState::Get().collector;\n            collector.period = 160;\n            collector.signal.notify_one();\n            #endif\n        }\n\n        static void EndInstrumentation() {\n            auto& currentProfilerHost = PersistentState::Get().profilerHost;\n            if (currentProfilerHost == nullptr) {\n                return;\n            }\n\n            // NOTE(frank): full-stop synchronization to ensure we catch\n            // and drain all the activities that has been tracked up to now.\n            cudaDeviceSynchronize();\n\n            FlushActivity();\n\n            auto& subscriber = PersistentState::Get().subscriber;\n            for (auto activity : activities) {\n                CUPTI_API_CALL(cuptiActivityDisable(activity));\n            }\n            for (auto domain : domains) {\n                CUPTI_API_CALL(cuptiEnableDomain(uint32_t(false), subscriber, domain));\n            }\n            // TODO(marcos): is here a counterpart for 'cuptiActivityRegisterCallbacks()'?\n            CUPTI_API_CALL(cuptiUnsubscribe(subscriber));\n\n            #if TRACY_CUDA_ENABLE_COLLECTOR_THREAD\n            auto& collector = PersistentState::Get().collector;\n            collector.period = ~uint32_t(0);\n            collector.signal.notify_one();\n            #endif\n\n            currentProfilerHost = nullptr;\n        }\n\n        static void FlushActivity()\n        {\n            // NOTE(marcos): only one thread should do the collection at any given time,\n            // but there's no reason to block threads that are also trying to do the same\n            static std::mutex m;\n            if (!m.try_lock())\n                return;\n            std::unique_lock<std::mutex> lock (m, std::adopt_lock);\n            ZoneNamedNC(zone, \"cuptiActivityFlushAll\", tracy::Color::Red4, true);\n            CUPTI_API_CALL(cuptiActivityFlushAll(CUPTI_ACTIVITY_FLAG_NONE));\n        }\n\n        #if TRACY_CUDA_ENABLE_COLLECTOR_THREAD\n        // WARN(marcos): technically, CUPTI already offers async flushing of\n        // activity records through cuptiActivityFlushPeriod(), but I haven't\n        // had much luck getting reliable, consistent delivery with it...\n        struct Collector {\n            std::atomic<bool> running = true;\n            volatile uint32_t period = ~uint32_t(0);\n            std::mutex mtx;\n            std::condition_variable signal;\n            std::thread thread = std::thread(\n                [this]() {\n                    tracy::SetThreadName(\"Tracy CUDA Collector\");\n                    atexit([]() {\n                        auto& collector = CUPTI::PersistentState::Get().collector;\n                        collector.running = false;\n                        collector.signal.notify_one();\n                        collector.thread.join();\n                    });\n                    while (running) {\n                        {\n                            std::unique_lock<std::mutex> lock(mtx);\n                            signal.wait_for(lock, std::chrono::milliseconds(period));\n                        }\n                        FlushActivity();\n                    }\n                }\n            );\n        };\n        #endif\n\n        static void FlushActivityAsync()\n        {\n            #if TRACY_CUDA_ENABLE_COLLECTOR_THREAD\n            ZoneScoped;\n            auto& collector = PersistentState::Get().collector;\n            collector.signal.notify_one();\n            #endif\n        }\n\n        struct PersistentState {\n            // NOTE(marcos): these objects must remain in memory past the application\n            // returning from main() because the Tracy client worker thread may still\n            // be responding to string/source-location requests from the server\n            SourceLocationMap kernelSrcLoc;\n            StringTable demangledNameTable;\n            SourceLocationLUT cudaCallSourceLocation;\n\n            // NOTE(marcos): these objects do not need to persist, but their relative\n            // footprint is trivial enough that we don't care if we let them leak\n            ConcurrentHashMap<CorrelationID, APICallInfo> cudaCallSiteInfo;\n            ConcurrentHashMap<uintptr_t, int> memAllocAddress;\n            CUpti_SubscriberHandle subscriber = {};\n            CUDACtx* profilerHost = nullptr;\n\n            Collector collector;\n\n            static PersistentState& Get() {\n                static PersistentState& persistent = *(new PersistentState());\n                return persistent;\n            }\n        };\n\n        };\n\n        CUDACtx(uint8_t gpuContextID = 255)\n        {\n            ZoneScoped;\n\n            if (gpuContextID != 255) {\n                m_tracyGpuContext = gpuContextID;\n                return;\n            }\n\n            m_tracyGpuContext = GetGpuCtxCounter().fetch_add(1, std::memory_order_relaxed);\n            assert(m_tracyGpuContext != 255);\n\n            TracyTimestamp tTracy;\n            CUptiTimestamp tCUpti;\n            QueryTimestamps(tTracy, tCUpti);\n\n            // Announce to Tracy about a new GPU context/timeline:\n            auto item = Profiler::QueueSerial();\n            tracyMemWrite(item->hdr.type, QueueType::GpuNewContext);\n            tracyMemWrite(item->gpuNewContext.cpuTime, tTracy);\n            tracyMemWrite(item->gpuNewContext.gpuTime, (int64_t)tCUpti); // TODO: Be more careful about this cast\n            tracyMemWrite(item->gpuNewContext.thread, (uint32_t)0);\n            tracyMemWrite(item->gpuNewContext.period, 1.0f);\n            tracyMemWrite(item->gpuNewContext.type, GpuContextType::CUDA);\n            tracyMemWrite(item->gpuNewContext.context, m_tracyGpuContext);\n            #if TRACY_CUDA_CALIBRATED_CONTEXT\n            tracyMemWrite(item->gpuNewContext.flags, GpuContextCalibration);\n            #else\n            tracyMemWrite(item->gpuNewContext.flags, tracy::GpuContextFlags(0));\n            #endif\n            Profiler::QueueSerialFinish();\n\n            constexpr const char* tracyCtxName = \"CUDA GPU/Device Activity\";\n            this->Name(tracyCtxName, uint16_t(strlen(tracyCtxName)));\n\n            // NOTE(marcos): a few rounds of calibation amorthized over 1 second\n            // in order to get a meaningful linear regression estimator\n            Recalibrate();\n            std::this_thread::sleep_for(std::chrono::milliseconds(100));\n            Recalibrate();\n            std::this_thread::sleep_for(std::chrono::milliseconds(200));\n            Recalibrate();\n            std::this_thread::sleep_for(std::chrono::milliseconds(300));\n            Recalibrate();\n            std::this_thread::sleep_for(std::chrono::milliseconds(400));\n            Recalibrate();\n        }\n\n        ~CUDACtx()\n        {\n            ZoneScoped;\n        }\n\n        struct Singleton {\n            CUDACtx* ctx = nullptr;\n            std::mutex m;\n            int ref_count = 0;\n            uint8_t ctx_id = 255;\n            static Singleton& Get() {\n                static Singleton singleton;\n                return singleton;\n            }\n        };\n\n        #if TRACY_CUDA_ENABLE_CUDA_CALL_STATS\n        ProfilerStats stats = {};\n        #endif\n\n        uint8_t m_tracyGpuContext = 255;\n        static constexpr size_t cacheline = 64;\n        alignas(cacheline) std::atomic<uint16_t> m_queryIdGen = 0;\n    };\n\n}\n\n#define TracyCUDAContext() tracy::CUDACtx::Create()\n#define TracyCUDAContextDestroy(ctx) tracy::CUDACtx::Destroy(ctx)\n#define TracyCUDAContextName(ctx, name, size) ctx->Name(name, size)\n\n#define TracyCUDAStartProfiling(ctx) ctx->StartProfiling()\n#define TracyCUDAStopProfiling(ctx) ctx->StopProfiling()\n\n#define TracyCUDACollect(ctx) ctx->Collect()\n\n#endif\n\n#endif"
  },
  {
    "path": "tracy-client-sys/tracy/tracy/TracyD3D11.hpp",
    "content": "#ifndef __TRACYD3D11_HPP__\n#define __TRACYD3D11_HPP__\n\n#ifndef TRACY_ENABLE\n\n#define TracyD3D11Context(device,queue) nullptr\n#define TracyD3D11Destroy(ctx)\n#define TracyD3D11ContextName(ctx, name, size)\n\n#define TracyD3D11NewFrame(ctx)\n\n#define TracyD3D11Zone(ctx, name)\n#define TracyD3D11ZoneC(ctx, name, color)\n#define TracyD3D11NamedZone(ctx, varname, name, active)\n#define TracyD3D11NamedZoneC(ctx, varname, name, color, active)\n#define TracyD3D11ZoneTransient(ctx, varname, name, active)\n\n#define TracyD3D11ZoneS(ctx, name, depth)\n#define TracyD3D11ZoneCS(ctx, name, color, depth)\n#define TracyD3D11NamedZoneS(ctx, varname, name, depth, active)\n#define TracyD3D11NamedZoneCS(ctx, varname, name, color, depth, active)\n#define TracyD3D11ZoneTransientS(ctx, varname, name, depth, active)\n\n#define TracyD3D11Collect(ctx)\n\nnamespace tracy\n{\nclass D3D11ZoneScope {};\n}\n\nusing TracyD3D11Ctx = void*;\n\n#else\n\n#include <atomic>\n#include <assert.h>\n#include <stdlib.h>\n\n#include \"Tracy.hpp\"\n#include \"../client/TracyProfiler.hpp\"\n#include \"../client/TracyCallstack.hpp\"\n#include \"../common/TracyYield.hpp\"\n\n#include <d3d11.h>\n\n#define TracyD3D11Panic(msg, ...) do { assert(false && \"TracyD3D11: \" msg); TracyMessageLC(\"TracyD3D11: \" msg, tracy::Color::Red4); __VA_ARGS__; } while(false);\n\nnamespace tracy\n{\n\nclass D3D11Ctx\n{\n    friend class D3D11ZoneScope;\n\n    static constexpr uint32_t MaxQueries = 64 * 1024;\n\n    enum CollectMode { POLL, BLOCK };\n\npublic:\n    D3D11Ctx( ID3D11Device* device, ID3D11DeviceContext* devicectx )\n    {\n        // TODO: consider calling ID3D11Device::GetImmediateContext() instead of passing it as an argument\n        m_device = device;\n        device->AddRef();\n        m_immediateDevCtx = devicectx;\n        devicectx->AddRef();\n\n        {\n            D3D11_QUERY_DESC desc = { };\n            desc.Query = D3D11_QUERY_TIMESTAMP_DISJOINT;\n            if (FAILED(m_device->CreateQuery(&desc, &m_disjointQuery)))\n            {\n                TracyD3D11Panic(\"unable to create disjoint timestamp query.\", return);\n            }\n        }\n\n        for (ID3D11Query*& query : m_queries)\n        {\n            D3D11_QUERY_DESC desc = { };\n            desc.Query = D3D11_QUERY_TIMESTAMP;\n            if (FAILED(m_device->CreateQuery(&desc, &query)))\n            {\n                TracyD3D11Panic(\"unable to create timestamp query.\", return);\n            }\n        }\n\n        // Calibrate CPU and GPU timestamps\n        int64_t tcpu = 0;\n        int64_t tgpu = 0;\n        for (int attempts = 0; attempts < 50; attempts++)\n        {\n            m_immediateDevCtx->Begin(m_disjointQuery);\n            m_immediateDevCtx->End(m_queries[0]);\n            m_immediateDevCtx->End(m_disjointQuery);\n\n            int64_t tcpu0 = Profiler::GetTime();\n            WaitForQuery(m_disjointQuery);\n            // NOTE: one would expect that by waiting for the enclosing disjoint query to finish,\n            // all timestamp queries within would also be readily available, but that does not\n            // seem to be the case here... See https://github.com/wolfpld/tracy/issues/947\n            WaitForQuery(m_queries[0]);\n            int64_t tcpu1 = Profiler::GetTime();\n\n            D3D11_QUERY_DATA_TIMESTAMP_DISJOINT disjoint = { };\n            if (m_immediateDevCtx->GetData(m_disjointQuery, &disjoint, sizeof(disjoint), 0) != S_OK)\n            {\n                TracyMessageLC(\"TracyD3D11: unable to query GPU timestamp; retrying...\", tracy::Color::Tomato);\n                continue;\n            }\n\n            if (disjoint.Disjoint)\n                continue;\n\n            UINT64 timestamp = 0;\n            if (m_immediateDevCtx->GetData(m_queries[0], &timestamp, sizeof(timestamp), 0) != S_OK)\n                continue;   // this should never happen (we waited for the query to finish above)\n\n            tcpu = tcpu0 + (tcpu1 - tcpu0) * 1 / 2;\n            tgpu = timestamp * (1000000000 / disjoint.Frequency);\n            break;\n        }\n\n        // ready to roll\n        m_contextId = GetGpuCtxCounter().fetch_add(1);\n        m_immediateDevCtx->Begin(m_disjointQuery);\n        m_previousCheckpoint = m_nextCheckpoint = 0;\n\n        auto* item = Profiler::QueueSerial();\n        MemWrite( &item->hdr.type, QueueType::GpuNewContext );\n        MemWrite( &item->gpuNewContext.cpuTime, tcpu );\n        MemWrite( &item->gpuNewContext.gpuTime, tgpu );\n        MemWrite( &item->gpuNewContext.thread, uint32_t(0) );   // #TODO: why not GetThreadHandle()?\n        MemWrite( &item->gpuNewContext.period, 1.0f );\n        MemWrite( &item->gpuNewContext.context, m_contextId);\n        MemWrite( &item->gpuNewContext.flags, uint8_t(0) );\n        MemWrite( &item->gpuNewContext.type, GpuContextType::Direct3D11 );\n\n#ifdef TRACY_ON_DEMAND\n        GetProfiler().DeferItem( *item );\n#endif\n\n        Profiler::QueueSerialFinish();\n    }\n\n    ~D3D11Ctx()\n    {\n        // collect all pending timestamps before destroying everything\n        do\n        {\n            Collect(BLOCK);\n        } while (m_previousCheckpoint != m_queryCounter);\n\n        for (ID3D11Query* query : m_queries)\n        {\n            query->Release();\n        }\n        m_immediateDevCtx->End(m_disjointQuery);\n        m_disjointQuery->Release();\n        m_immediateDevCtx->Release();\n        m_device->Release();\n    }\n\n    void Name( const char* name, uint16_t len )\n    {\n        auto ptr = (char*)tracy_malloc( len );\n        memcpy( ptr, name, len );\n\n        auto item = Profiler::QueueSerial();\n        MemWrite( &item->hdr.type, QueueType::GpuContextName );\n        MemWrite( &item->gpuContextNameFat.context, m_contextId );\n        MemWrite( &item->gpuContextNameFat.ptr, (uint64_t)ptr );\n        MemWrite( &item->gpuContextNameFat.size, len );\n#ifdef TRACY_ON_DEMAND\n        GetProfiler().DeferItem( *item );\n#endif\n        Profiler::QueueSerialFinish();\n    }\n\n    void Collect(CollectMode mode = POLL)\n    {\n        ZoneScopedC( Color::Red4 );\n\n#ifdef TRACY_ON_DEMAND\n        if( !GetProfiler().IsConnected() )\n        {\n            m_previousCheckpoint = m_nextCheckpoint = m_queryCounter;\n            return;\n        }\n#endif\n\n        if (m_previousCheckpoint == m_nextCheckpoint)\n        {\n            uintptr_t nextCheckpoint = m_queryCounter;\n            if (nextCheckpoint == m_nextCheckpoint)\n            {\n                return;\n            }\n            m_nextCheckpoint = nextCheckpoint;\n            m_immediateDevCtx->End(m_disjointQuery);\n        }\n\n        if (mode == CollectMode::BLOCK)\n        {\n            WaitForQuery(m_disjointQuery);\n        }\n\n        D3D11_QUERY_DATA_TIMESTAMP_DISJOINT disjoint = { };\n        if (m_immediateDevCtx->GetData(m_disjointQuery, &disjoint, sizeof(disjoint), D3D11_ASYNC_GETDATA_DONOTFLUSH) != S_OK)\n        {\n            return;\n        }\n\n        if (disjoint.Disjoint == TRUE)\n        {\n            m_previousCheckpoint = m_nextCheckpoint;\n            TracyD3D11Panic(\"disjoint timestamps detected; dropping.\");\n            return;\n        }\n\n        auto begin = m_previousCheckpoint;\n        auto end = m_nextCheckpoint;\n        for (auto i = begin; i != end; ++i)\n        {\n            uint32_t k = RingIndex(i);\n            UINT64 timestamp = 0;\n            if (m_immediateDevCtx->GetData(m_queries[k], &timestamp, sizeof(timestamp), 0) != S_OK)\n            {\n                TracyD3D11Panic(\"timestamp expected to be ready, but it was not!\");\n                break;\n            }\n            timestamp *= (1000000000ull / disjoint.Frequency);\n            auto* item = Profiler::QueueSerial();\n            MemWrite(&item->hdr.type, QueueType::GpuTime);\n            MemWrite(&item->gpuTime.gpuTime, static_cast<int64_t>(timestamp));\n            MemWrite(&item->gpuTime.queryId, static_cast<uint16_t>(k));\n            MemWrite(&item->gpuTime.context, m_contextId);\n            Profiler::QueueSerialFinish();\n        }\n\n        // disjoint timestamp queries should only be invoked once per frame or less\n        // https://learn.microsoft.com/en-us/windows/win32/api/d3d11/ne-d3d11-d3d11_query\n        m_immediateDevCtx->Begin(m_disjointQuery);\n        m_previousCheckpoint = m_nextCheckpoint;\n    }\n\nprivate:\n    tracy_force_inline uint32_t RingIndex(uintptr_t index)\n    {\n        index %= MaxQueries;\n        return static_cast<uint32_t>(index);\n    }\n\n    tracy_force_inline uint32_t RingCount(uintptr_t begin, uintptr_t end)\n    {\n        // wrap-around safe: all unsigned\n        uintptr_t count = end - begin;\n        return static_cast<uint32_t>(count);\n    }\n\n    tracy_force_inline uint32_t NextQueryId()\n    {\n        auto id = m_queryCounter++;\n        if (RingCount(m_previousCheckpoint, id) >= MaxQueries)\n        {\n            TracyD3D11Panic(\"too many pending timestamp queries.\");\n            // #TODO: return some sentinel value; ideally a \"hidden\" query index\n        }\n        return RingIndex(id);\n    }\n\n    tracy_force_inline ID3D11Query* GetQueryObjectFromId(uint32_t id)\n    {\n        return m_queries[id];\n    }\n\n    tracy_force_inline void WaitForQuery(ID3D11Query* query)\n    {\n        m_immediateDevCtx->Flush();\n        while (m_immediateDevCtx->GetData(query, nullptr, 0, 0) != S_OK)\n            YieldThread();  // busy-wait :-( attempt to reduce power usage with _mm_pause() & friends...\n    }\n\n    tracy_force_inline uint8_t GetContextId() const\n    {\n        return m_contextId;\n    }\n\n    ID3D11Device* m_device = nullptr;\n    ID3D11DeviceContext* m_immediateDevCtx = nullptr;\n\n    ID3D11Query* m_queries[MaxQueries];\n    ID3D11Query* m_disjointQuery = nullptr;\n\n    uint8_t m_contextId = 255;  // NOTE: apparently, 255 means invalid id; is this documented anywhere?\n\n    uintptr_t m_queryCounter = 0;\n\n    uintptr_t m_previousCheckpoint = 0;\n    uintptr_t m_nextCheckpoint = 0;\n};\n\nclass D3D11ZoneScope\n{\npublic:\n    tracy_force_inline D3D11ZoneScope( D3D11Ctx* ctx, const SourceLocationData* srcloc, bool active )\n        : D3D11ZoneScope(ctx, active)\n    {\n        if( !m_active ) return;\n\n        auto* item = Profiler::QueueSerial();\n        WriteQueueItem(item, QueueType::GpuZoneBeginSerial, reinterpret_cast<uint64_t>(srcloc));\n    }\n\n    tracy_force_inline D3D11ZoneScope( D3D11Ctx* ctx, const SourceLocationData* srcloc, int32_t depth, bool active )\n        : D3D11ZoneScope(ctx, active)\n    {\n        if( !m_active ) return;\n\n        if( depth > 0 && has_callstack() )\n        {\n            auto* item = Profiler::QueueSerialCallstack(Callstack(depth));\n            WriteQueueItem(item, QueueType::GpuZoneBeginCallstackSerial, reinterpret_cast<uint64_t>(srcloc));\n        }\n        else\n        {\n            auto* item = Profiler::QueueSerial();\n            WriteQueueItem(item, QueueType::GpuZoneBeginSerial, reinterpret_cast<uint64_t>(srcloc));\n        }\n    }\n\n    tracy_force_inline D3D11ZoneScope(D3D11Ctx* ctx, uint32_t line, const char* source, size_t sourceSz, const char* function, size_t functionSz, const char* name, size_t nameSz, bool active)\n        : D3D11ZoneScope(ctx, active)\n    {\n        if( !m_active ) return;\n\n        const auto sourceLocation = Profiler::AllocSourceLocation(line, source, sourceSz, function, functionSz, name, nameSz);\n\n        auto* item = Profiler::QueueSerial();\n        WriteQueueItem(item, QueueType::GpuZoneBeginAllocSrcLocSerial, sourceLocation);\n    }\n\n    tracy_force_inline D3D11ZoneScope(D3D11Ctx* ctx, uint32_t line, const char* source, size_t sourceSz, const char* function, size_t functionSz, const char* name, size_t nameSz, int32_t depth, bool active)\n        : D3D11ZoneScope(ctx, active)\n    {\n        if( !m_active ) return;\n\n        const auto sourceLocation = Profiler::AllocSourceLocation(line, source, sourceSz, function, functionSz, name, nameSz);\n\n        if ( depth > 0 && has_callstack() )\n        {\n            auto* item = Profiler::QueueSerialCallstack(Callstack(depth));\n            WriteQueueItem(item, QueueType::GpuZoneBeginAllocSrcLocCallstackSerial, sourceLocation);\n        }\n        else\n        {\n            auto* item = Profiler::QueueSerial();\n            WriteQueueItem(item, QueueType::GpuZoneBeginAllocSrcLocSerial, sourceLocation);\n        }\n    }\n\n    tracy_force_inline ~D3D11ZoneScope()\n    {\n        if( !m_active ) return;\n\n        const auto queryId = m_ctx->NextQueryId();\n        m_ctx->m_immediateDevCtx->End(m_ctx->GetQueryObjectFromId(queryId));\n\n        auto* item = Profiler::QueueSerial();\n        MemWrite( &item->hdr.type, QueueType::GpuZoneEndSerial );\n        MemWrite( &item->gpuZoneEnd.cpuTime, Profiler::GetTime() );\n        MemWrite( &item->gpuZoneEnd.thread, GetThreadHandle() );\n        MemWrite( &item->gpuZoneEnd.queryId, uint16_t( queryId ) );\n        MemWrite( &item->gpuZoneEnd.context, m_ctx->GetContextId() );\n        Profiler::QueueSerialFinish();\n    }\n\nprivate:\n    tracy_force_inline D3D11ZoneScope( D3D11Ctx* ctx, bool active )\n#ifdef TRACY_ON_DEMAND\n        : m_active( active && GetProfiler().IsConnected() )\n#else\n        : m_active( active )\n#endif\n    {\n        if( !m_active ) return;\n        m_ctx = ctx;\n    }\n\n    void WriteQueueItem(tracy::QueueItem* item, tracy::QueueType queueItemType, uint64_t sourceLocation)\n    {\n        const auto queryId = m_ctx->NextQueryId();\n        m_ctx->m_immediateDevCtx->End(m_ctx->GetQueryObjectFromId(queryId));\n\n        MemWrite( &item->hdr.type, queueItemType);\n        MemWrite( &item->gpuZoneBegin.cpuTime, Profiler::GetTime() );\n        MemWrite( &item->gpuZoneBegin.srcloc, sourceLocation );\n        MemWrite( &item->gpuZoneBegin.thread, GetThreadHandle() );\n        MemWrite( &item->gpuZoneBegin.queryId, uint16_t( queryId ) );\n        MemWrite( &item->gpuZoneBegin.context, m_ctx->GetContextId() );\n        Profiler::QueueSerialFinish();\n    }\n\n    const bool m_active;\n\n    D3D11Ctx* m_ctx;\n};\n\nstatic inline D3D11Ctx* CreateD3D11Context( ID3D11Device* device, ID3D11DeviceContext* devicectx )\n{\n    auto ctx = (D3D11Ctx*)tracy_malloc( sizeof( D3D11Ctx ) );\n    new(ctx) D3D11Ctx( device, devicectx );\n    return ctx;\n}\n\nstatic inline void DestroyD3D11Context( D3D11Ctx* ctx )\n{\n    ctx->~D3D11Ctx();\n    tracy_free( ctx );\n}\n}\n\n#undef TracyD3D11Panic\n\nusing TracyD3D11Ctx = tracy::D3D11Ctx*;\n\n#define TracyD3D11Context( device, devicectx ) tracy::CreateD3D11Context( device, devicectx );\n#define TracyD3D11Destroy(ctx) tracy::DestroyD3D11Context(ctx);\n#define TracyD3D11ContextName(ctx, name, size) ctx->Name(name, size);\n\n#define TracyD3D11UnnamedZone ___tracy_gpu_d3d11_zone\n#define TracyD3D11SrcLocSymbol TracyConcat(__tracy_gpu_d3d11_source_location,TracyLine)\n#define TracyD3D11SrcLocObject(name, color) static constexpr tracy::SourceLocationData TracyD3D11SrcLocSymbol { name, TracyFunction, TracyFile, (uint32_t)TracyLine, color };\n\n#if defined TRACY_HAS_CALLSTACK && defined TRACY_CALLSTACK\n#  define TracyD3D11Zone( ctx, name ) TracyD3D11NamedZoneS( ctx, TracyD3D11UnnamedZone, name, TRACY_CALLSTACK, true )\n#  define TracyD3D11ZoneC( ctx, name, color ) TracyD3D11NamedZoneCS( ctx, TracyD3D11UnnamedZone, name, color, TRACY_CALLSTACK, true )\n#  define TracyD3D11NamedZone( ctx, varname, name, active ) TracyD3D11SrcLocObject(name, 0); tracy::D3D11ZoneScope varname( ctx, &TracyD3D11SrcLocSymbol, TRACY_CALLSTACK, active );\n#  define TracyD3D11NamedZoneC( ctx, varname, name, color, active ) TracyD3D11SrcLocObject(name, color); tracy::D3D11ZoneScope varname( ctx, &TracyD3D11SrcLocSymbol, TRACY_CALLSTACK, active );\n#  define TracyD3D11ZoneTransient(ctx, varname, name, active) TracyD3D11ZoneTransientS(ctx, varname, cmdList, name, TRACY_CALLSTACK, active)\n#else\n#  define TracyD3D11Zone( ctx, name ) TracyD3D11NamedZone( ctx, TracyD3D11UnnamedZone, name, true )\n#  define TracyD3D11ZoneC( ctx, name, color ) TracyD3D11NamedZoneC( ctx, TracyD3D11UnnamedZone, name, color, true )\n#  define TracyD3D11NamedZone( ctx, varname, name, active ) TracyD3D11SrcLocObject(name, 0); tracy::D3D11ZoneScope varname( ctx, &TracyD3D11SrcLocSymbol, active );\n#  define TracyD3D11NamedZoneC( ctx, varname, name, color, active ) TracyD3D11SrcLocObject(name, color); tracy::D3D11ZoneScope varname( ctx, &TracyD3D11SrcLocSymbol, active );\n#  define TracyD3D11ZoneTransient(ctx, varname, name, active) tracy::D3D11ZoneScope varname{ ctx, TracyLine, TracyFile, strlen(TracyFile), TracyFunction, strlen(TracyFunction), name, strlen(name), active };\n#endif\n\n#ifdef TRACY_HAS_CALLSTACK\n#  define TracyD3D11ZoneS( ctx, name, depth ) TracyD3D11NamedZoneS( ctx, TracyD3D11UnnamedZone, name, depth, true )\n#  define TracyD3D11ZoneCS( ctx, name, color, depth ) TracyD3D11NamedZoneCS( ctx, TracyD3D11UnnamedZone, name, color, depth, true )\n#  define TracyD3D11NamedZoneS( ctx, varname, name, depth, active ) TracyD3D11SrcLocObject(name, 0); tracy::D3D11ZoneScope varname( ctx, &TracyD3D11SrcLocSymbol, depth, active );\n#  define TracyD3D11NamedZoneCS( ctx, varname, name, color, depth, active ) TracyD3D11SrcLocObject(name, color); tracy::D3D11ZoneScope varname( ctx, &TracyD3D11SrcLocSymbol, depth, active );\n#  define TracyD3D11ZoneTransientS(ctx, varname, name, depth, active) tracy::D3D11ZoneScope varname{ ctx, TracyLine, TracyFile, strlen(TracyFile), TracyFunction, strlen(TracyFunction), name, strlen(name), depth, active };\n#else\n#  define TracyD3D11ZoneS( ctx, name, depth, active ) TracyD3D11Zone( ctx, name )\n#  define TracyD3D11ZoneCS( ctx, name, color, depth, active ) TracyD3D11ZoneC( name, color )\n#  define TracyD3D11NamedZoneS( ctx, varname, name, depth, active ) TracyD3D11NamedZone( ctx, varname, name, active )\n#  define TracyD3D11NamedZoneCS( ctx, varname, name, color, depth, active ) TracyD3D11NamedZoneC( ctx, varname, name, color, active )\n#  define TracyD3D11ZoneTransientS(ctx, varname, name, depth, active) TracyD3D11ZoneTransient(ctx, varname, name, active)\n#endif\n\n#define TracyD3D11Collect( ctx ) ctx->Collect();\n\n#endif\n\n#endif\n"
  },
  {
    "path": "tracy-client-sys/tracy/tracy/TracyD3D12.hpp",
    "content": "#ifndef __TRACYD3D12_HPP__\n#define __TRACYD3D12_HPP__\n\n#ifndef TRACY_ENABLE\n\n#define TracyD3D12Context(device, queue) nullptr\n#define TracyD3D12Destroy(ctx)\n#define TracyD3D12ContextName(ctx, name, size)\n\n#define TracyD3D12NewFrame(ctx)\n\n#define TracyD3D12Zone(ctx, cmdList, name)\n#define TracyD3D12ZoneC(ctx, cmdList, name, color)\n#define TracyD3D12NamedZone(ctx, varname, cmdList, name, active)\n#define TracyD3D12NamedZoneC(ctx, varname, cmdList, name, color, active)\n#define TracyD3D12ZoneTransient(ctx, varname, cmdList, name, active)\n\n#define TracyD3D12ZoneS(ctx, cmdList, name, depth)\n#define TracyD3D12ZoneCS(ctx, cmdList, name, color, depth)\n#define TracyD3D12NamedZoneS(ctx, varname, cmdList, name, depth, active)\n#define TracyD3D12NamedZoneCS(ctx, varname, cmdList, name, color, depth, active)\n#define TracyD3D12ZoneTransientS(ctx, varname, cmdList, name, depth, active)\n\n#define TracyD3D12Collect(ctx)\n\nnamespace tracy\n{\n    class D3D12ZoneScope {};\n}\n\nusing TracyD3D12Ctx = void*;\n\n#else\n\n#include \"Tracy.hpp\"\n#include \"../client/TracyProfiler.hpp\"\n#include \"../client/TracyCallstack.hpp\"\n\n#include <cstdlib>\n#include <cassert>\n#include <d3d12.h>\n#include <dxgi.h>\n#include <queue>\n\n#define TracyD3D12Panic(msg, ...) do { assert(false && \"TracyD3D12: \" msg); TracyMessageLC(\"TracyD3D12: \" msg, tracy::Color::Red4); __VA_ARGS__; } while(false);\n\nnamespace tracy\n{\n\n    struct D3D12QueryPayload\n    {\n        uint32_t m_queryIdStart = 0;\n        uint32_t m_queryCount = 0;\n    };\n\n    // Command queue context.\n    class D3D12QueueCtx\n    {\n        friend class D3D12ZoneScope;\n\n        ID3D12Device* m_device = nullptr;\n        ID3D12CommandQueue* m_queue = nullptr;\n        uint8_t m_contextId = 255;  // TODO: apparently, 255 means \"invalid id\"; is this documented somewhere?\n        ID3D12QueryHeap* m_queryHeap = nullptr;\n        ID3D12Resource* m_readbackBuffer = nullptr;\n\n        // In-progress payload.\n        uint32_t m_queryLimit = 0;\n        std::atomic<uint32_t> m_queryCounter = 0;\n        uint32_t m_previousQueryCounter = 0;\n\n        uint32_t m_activePayload = 0;\n        ID3D12Fence* m_payloadFence = nullptr;\n        std::queue<D3D12QueryPayload> m_payloadQueue;\n\n        UINT64 m_prevCalibrationTicksCPU = 0;\n\n        void RecalibrateClocks()\n        {\n            UINT64 cpuTimestamp;\n            UINT64 gpuTimestamp;\n            if (FAILED(m_queue->GetClockCalibration(&gpuTimestamp, &cpuTimestamp)))\n            {\n                TracyD3D12Panic(\"failed to obtain queue clock calibration counters.\", return);\n            }\n\n            int64_t cpuDeltaTicks = cpuTimestamp - m_prevCalibrationTicksCPU;\n            if (cpuDeltaTicks > 0)\n            {\n                static const int64_t nanosecodsPerTick = int64_t(1000000000) / GetFrequencyQpc();\n                int64_t cpuDeltaNS = cpuDeltaTicks * nanosecodsPerTick;\n                // Save the device cpu timestamp, not the Tracy profiler timestamp:\n                m_prevCalibrationTicksCPU = cpuTimestamp;\n\n                cpuTimestamp = Profiler::GetTime();\n\n                auto* item = Profiler::QueueSerial();\n                MemWrite(&item->hdr.type, QueueType::GpuCalibration);\n                MemWrite(&item->gpuCalibration.gpuTime, gpuTimestamp);\n                MemWrite(&item->gpuCalibration.cpuTime, cpuTimestamp);\n                MemWrite(&item->gpuCalibration.cpuDelta, cpuDeltaNS);\n                MemWrite(&item->gpuCalibration.context, GetId());\n                SubmitQueueItem(item);\n            }\n        }\n\n        tracy_force_inline void SubmitQueueItem(tracy::QueueItem* item)\n        {\n#ifdef TRACY_ON_DEMAND\n            GetProfiler().DeferItem(*item);\n#endif\n            Profiler::QueueSerialFinish();\n        }\n\n    public:\n        D3D12QueueCtx(ID3D12Device* device, ID3D12CommandQueue* queue)\n            : m_device(device)\n            , m_queue(queue)\n        {\n            // Verify we support timestamp queries on this queue.\n\n            if (queue->GetDesc().Type == D3D12_COMMAND_LIST_TYPE_COPY)\n            {\n                D3D12_FEATURE_DATA_D3D12_OPTIONS3 featureData{};\n\n                HRESULT hr = device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS3, &featureData, sizeof(featureData));\n                if (FAILED(hr) || (featureData.CopyQueueTimestampQueriesSupported == FALSE))\n                {\n                    TracyD3D12Panic(\"Platform does not support profiling of copy queues.\", return);\n                }\n            }\n\n            static constexpr uint32_t MaxQueries = 64 * 1024;  // Must be even, because queries are (begin, end) pairs\n            m_queryLimit = MaxQueries;\n\n            D3D12_QUERY_HEAP_DESC heapDesc{};\n            heapDesc.Type = queue->GetDesc().Type == D3D12_COMMAND_LIST_TYPE_COPY ? D3D12_QUERY_HEAP_TYPE_COPY_QUEUE_TIMESTAMP : D3D12_QUERY_HEAP_TYPE_TIMESTAMP;\n            heapDesc.Count = m_queryLimit;\n            heapDesc.NodeMask = 0;  // #TODO: Support multiple adapters.\n\n            while (FAILED(device->CreateQueryHeap(&heapDesc, IID_PPV_ARGS(&m_queryHeap))))\n            {\n                m_queryLimit /= 2;\n                heapDesc.Count = m_queryLimit;\n            }\n\n            // Create a readback buffer, which will be used as a destination for the query data.\n\n            D3D12_RESOURCE_DESC readbackBufferDesc{};\n            readbackBufferDesc.Alignment = 0;\n            readbackBufferDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;\n            readbackBufferDesc.Width = m_queryLimit * sizeof(uint64_t);\n            readbackBufferDesc.Height = 1;\n            readbackBufferDesc.DepthOrArraySize = 1;\n            readbackBufferDesc.Format = DXGI_FORMAT_UNKNOWN;\n            readbackBufferDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;  // Buffers are always row major.\n            readbackBufferDesc.MipLevels = 1;\n            readbackBufferDesc.SampleDesc.Count = 1;\n            readbackBufferDesc.SampleDesc.Quality = 0;\n            readbackBufferDesc.Flags = D3D12_RESOURCE_FLAG_NONE;\n\n            D3D12_HEAP_PROPERTIES readbackHeapProps{};\n            readbackHeapProps.Type = D3D12_HEAP_TYPE_READBACK;\n            readbackHeapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;\n            readbackHeapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;\n            readbackHeapProps.CreationNodeMask = 0;\n            readbackHeapProps.VisibleNodeMask = 0;  // #TODO: Support multiple adapters.\n\n            if (FAILED(device->CreateCommittedResource(&readbackHeapProps, D3D12_HEAP_FLAG_NONE, &readbackBufferDesc, D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(&m_readbackBuffer))))\n            {\n                TracyD3D12Panic(\"Failed to create query readback buffer.\", return);\n            }\n\n            if (FAILED(device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&m_payloadFence))))\n            {\n                TracyD3D12Panic(\"Failed to create payload fence.\", return);\n            }\n\n            float period = [queue]()\n            {\n                uint64_t timestampFrequency;\n                if (FAILED(queue->GetTimestampFrequency(&timestampFrequency)))\n                {\n                    return 0.0f;\n                }\n                return static_cast<float>( 1E+09 / static_cast<double>(timestampFrequency) );\n            }();\n\n            if (period == 0.0f)\n            {\n                TracyD3D12Panic(\"Failed to get timestamp frequency.\", return);\n            }\n\n            uint64_t cpuTimestamp;\n            uint64_t gpuTimestamp;\n            if (FAILED(queue->GetClockCalibration(&gpuTimestamp, &cpuTimestamp)))\n            {\n                TracyD3D12Panic(\"Failed to get queue clock calibration.\", return);\n            }\n\n            // Save the device cpu timestamp, not the profiler's timestamp.\n            m_prevCalibrationTicksCPU = cpuTimestamp;\n\n            cpuTimestamp = Profiler::GetTime();\n\n            // all checked: ready to roll\n            m_contextId = GetGpuCtxCounter().fetch_add(1);\n\n            auto* item = Profiler::QueueSerial();\n            MemWrite(&item->hdr.type, QueueType::GpuNewContext);\n            MemWrite(&item->gpuNewContext.cpuTime, cpuTimestamp);\n            MemWrite(&item->gpuNewContext.gpuTime, gpuTimestamp);\n            MemWrite(&item->gpuNewContext.thread, decltype(item->gpuNewContext.thread)(0)); // #TODO: why 0 instead of GetThreadHandle()?\n            MemWrite(&item->gpuNewContext.period, period);\n            MemWrite(&item->gpuNewContext.context, GetId());\n            MemWrite(&item->gpuNewContext.flags, GpuContextCalibration);\n            MemWrite(&item->gpuNewContext.type, GpuContextType::Direct3D12);\n            SubmitQueueItem(item);\n        }\n\n        ~D3D12QueueCtx()\n        {\n            ZoneScopedC(Color::Red4);\n            // collect all pending timestamps\n            while (m_payloadFence->GetCompletedValue() != m_activePayload)\n                /* busy-wait ... */;\n            Collect();\n            m_payloadFence->Release();\n            m_readbackBuffer->Release();\n            m_queryHeap->Release();\n        }\n\n\n        void NewFrame()\n        {\n            uint32_t queryCounter = m_queryCounter.exchange(0);\n            m_payloadQueue.emplace(D3D12QueryPayload{ m_previousQueryCounter, queryCounter });\n            m_previousQueryCounter += queryCounter;\n\n            if (m_previousQueryCounter >= m_queryLimit)\n            {\n                m_previousQueryCounter -= m_queryLimit;\n            }\n\n            m_queue->Signal(m_payloadFence, ++m_activePayload);\n        }\n\n        void Name( const char* name, uint16_t len )\n        {\n            auto ptr = (char*)tracy_malloc( len );\n            memcpy( ptr, name, len );\n\n            auto item = Profiler::QueueSerial();\n            MemWrite( &item->hdr.type, QueueType::GpuContextName );\n            MemWrite( &item->gpuContextNameFat.context, GetId());\n            MemWrite( &item->gpuContextNameFat.ptr, (uint64_t)ptr );\n            MemWrite( &item->gpuContextNameFat.size, len );\n            SubmitQueueItem(item);\n        }\n\n        void Collect()\n        {\n            ZoneScopedC(Color::Red4);\n\n#ifdef TRACY_ON_DEMAND\n            if (!GetProfiler().IsConnected())\n            {\n                m_queryCounter = 0;\n\n                return;\n            }\n#endif\n\n            // Find out what payloads are available.\n            const auto newestReadyPayload = m_payloadFence->GetCompletedValue();\n            const auto payloadCount = m_payloadQueue.size() - (m_activePayload - newestReadyPayload);\n\n            if (!payloadCount)\n            {\n                return;  // No payloads are available yet, exit out.\n            }\n\n            D3D12_RANGE mapRange{ 0, m_queryLimit * sizeof(uint64_t) };\n\n            // Map the readback buffer so we can fetch the query data from the GPU.\n            void* readbackBufferMapping = nullptr;\n\n            if (FAILED(m_readbackBuffer->Map(0, &mapRange, &readbackBufferMapping)))\n            {\n                TracyD3D12Panic(\"Failed to map readback buffer.\", return);\n            }\n\n            auto* timestampData = static_cast<uint64_t*>(readbackBufferMapping);\n\n            for (uint32_t i = 0; i < payloadCount; ++i)\n            {\n                const auto& payload = m_payloadQueue.front();\n\n                for (uint32_t j = 0; j < payload.m_queryCount; ++j)\n                {\n                    const auto counter = (payload.m_queryIdStart + j) % m_queryLimit;\n                    const auto timestamp = timestampData[counter];\n                    const auto queryId = counter;\n\n                    auto* item = Profiler::QueueSerial();\n                    MemWrite(&item->hdr.type, QueueType::GpuTime);\n                    MemWrite(&item->gpuTime.gpuTime, timestamp);\n                    MemWrite(&item->gpuTime.queryId, static_cast<uint16_t>(queryId));\n                    MemWrite(&item->gpuTime.context, GetId());\n\n                    Profiler::QueueSerialFinish();\n                }\n\n                m_payloadQueue.pop();\n            }\n\n            m_readbackBuffer->Unmap(0, nullptr);\n\n            // Recalibrate to account for drift.\n            RecalibrateClocks();\n        }\n\n    private:\n        tracy_force_inline uint32_t NextQueryId()\n        {\n            uint32_t queryCounter = m_queryCounter.fetch_add(2);\n            if (queryCounter >= m_queryLimit)\n            {\n                TracyD3D12Panic(\"Submitted too many GPU queries! Consider increasing MaxQueries.\");\n                // #TODO: consider returning an invalid id or sentinel value here\n            }\n\n            const uint32_t id = (m_previousQueryCounter + queryCounter) % m_queryLimit;\n\n            return id;\n        }\n\n        tracy_force_inline uint8_t GetId() const\n        {\n            return m_contextId;\n        }\n    };\n\n    class D3D12ZoneScope\n    {\n        const bool m_active;\n        D3D12QueueCtx* m_ctx = nullptr;\n        ID3D12GraphicsCommandList* m_cmdList = nullptr;\n        uint32_t m_queryId = 0;  // Used for tracking in nested zones.\n\n        tracy_force_inline void WriteQueueItem(QueueItem* item, QueueType type, uint64_t srcLocation)\n        {\n            MemWrite(&item->hdr.type, type);\n            MemWrite(&item->gpuZoneBegin.cpuTime, Profiler::GetTime());\n            MemWrite(&item->gpuZoneBegin.srcloc, srcLocation);\n            MemWrite(&item->gpuZoneBegin.thread, GetThreadHandle());\n            MemWrite(&item->gpuZoneBegin.queryId, static_cast<uint16_t>(m_queryId));\n            MemWrite(&item->gpuZoneBegin.context, m_ctx->GetId());\n            Profiler::QueueSerialFinish();\n        }\n\n        tracy_force_inline D3D12ZoneScope(D3D12QueueCtx* ctx, ID3D12GraphicsCommandList* cmdList, bool active)\n#ifdef TRACY_ON_DEMAND\n            : m_active(active&& GetProfiler().IsConnected())\n#else\n            : m_active(active)\n#endif\n        {\n            if (!m_active) return;\n\n            m_ctx = ctx;\n            m_cmdList = cmdList;\n\n            m_queryId = m_ctx->NextQueryId();\n            m_cmdList->EndQuery(m_ctx->m_queryHeap, D3D12_QUERY_TYPE_TIMESTAMP, m_queryId);\n        }\n\n    public:\n        tracy_force_inline D3D12ZoneScope(D3D12QueueCtx* ctx, ID3D12GraphicsCommandList* cmdList, const SourceLocationData* srcLocation, bool active)\n            : D3D12ZoneScope(ctx, cmdList, active)\n        {\n            if (!m_active) return;\n\n            auto* item = Profiler::QueueSerial();\n            WriteQueueItem(item, QueueType::GpuZoneBeginSerial, reinterpret_cast<uint64_t>(srcLocation));\n        }\n\n        tracy_force_inline D3D12ZoneScope(D3D12QueueCtx* ctx, ID3D12GraphicsCommandList* cmdList, const SourceLocationData* srcLocation, int32_t depth, bool active)\n            : D3D12ZoneScope(ctx, cmdList, active)\n        {\n            if (!m_active) return;\n\n            auto* item = Profiler::QueueSerialCallstack(Callstack(depth));\n            WriteQueueItem(item, QueueType::GpuZoneBeginCallstackSerial, reinterpret_cast<uint64_t>(srcLocation));\n        }\n\n        tracy_force_inline D3D12ZoneScope(D3D12QueueCtx* ctx, uint32_t line, const char* source, size_t sourceSz, const char* function, size_t functionSz, const char* name, size_t nameSz, ID3D12GraphicsCommandList* cmdList, bool active)\n            : D3D12ZoneScope(ctx, cmdList, active)\n        {\n            if (!m_active) return;\n\n            const auto sourceLocation = Profiler::AllocSourceLocation(line, source, sourceSz, function, functionSz, name, nameSz);\n\n            auto* item = Profiler::QueueSerial();\n            WriteQueueItem(item, QueueType::GpuZoneBeginAllocSrcLocSerial, sourceLocation);\n        }\n\n        tracy_force_inline D3D12ZoneScope(D3D12QueueCtx* ctx, uint32_t line, const char* source, size_t sourceSz, const char* function, size_t functionSz, const char* name, size_t nameSz, ID3D12GraphicsCommandList* cmdList, int32_t depth, bool active)\n            : D3D12ZoneScope(ctx, cmdList, active)\n        {\n            if (!m_active) return;\n\n            const auto sourceLocation = Profiler::AllocSourceLocation(line, source, sourceSz, function, functionSz, name, nameSz);\n\n            auto* item = Profiler::QueueSerialCallstack(Callstack(depth));\n            WriteQueueItem(item, QueueType::GpuZoneBeginAllocSrcLocCallstackSerial, sourceLocation);\n        }\n\n        tracy_force_inline ~D3D12ZoneScope()\n        {\n            if (!m_active) return;\n\n            const auto queryId = m_queryId + 1;  // Our end query slot is immediately after the begin slot.\n            m_cmdList->EndQuery(m_ctx->m_queryHeap, D3D12_QUERY_TYPE_TIMESTAMP, queryId);\n\n            auto* item = Profiler::QueueSerial();\n            MemWrite(&item->hdr.type, QueueType::GpuZoneEndSerial);\n            MemWrite(&item->gpuZoneEnd.cpuTime, Profiler::GetTime());\n            MemWrite(&item->gpuZoneEnd.thread, GetThreadHandle());\n            MemWrite(&item->gpuZoneEnd.queryId, static_cast<uint16_t>(queryId));\n            MemWrite(&item->gpuZoneEnd.context, m_ctx->GetId());\n            Profiler::QueueSerialFinish();\n\n            m_cmdList->ResolveQueryData(m_ctx->m_queryHeap, D3D12_QUERY_TYPE_TIMESTAMP, m_queryId, 2, m_ctx->m_readbackBuffer, m_queryId * sizeof(uint64_t));\n        }\n    };\n\n    static inline D3D12QueueCtx* CreateD3D12Context(ID3D12Device* device, ID3D12CommandQueue* queue)\n    {\n        auto* ctx = static_cast<D3D12QueueCtx*>(tracy_malloc(sizeof(D3D12QueueCtx)));\n        new (ctx) D3D12QueueCtx{ device, queue };\n\n        return ctx;\n    }\n\n    static inline void DestroyD3D12Context(D3D12QueueCtx* ctx)\n    {\n        ctx->~D3D12QueueCtx();\n        tracy_free(ctx);\n    }\n\n}\n\n#undef TracyD3D12Panic\n\nusing TracyD3D12Ctx = tracy::D3D12QueueCtx*;\n\n#define TracyD3D12Context(device, queue) tracy::CreateD3D12Context(device, queue);\n#define TracyD3D12Destroy(ctx) tracy::DestroyD3D12Context(ctx);\n#define TracyD3D12ContextName(ctx, name, size) ctx->Name(name, size);\n\n#define TracyD3D12NewFrame(ctx) ctx->NewFrame();\n\n#define TracyD3D12UnnamedZone ___tracy_gpu_d3d12_zone\n#define TracyD3D12SrcLocSymbol TracyConcat(__tracy_d3d12_source_location,TracyLine)\n#define TracyD3D12SrcLocObject(name, color) static constexpr tracy::SourceLocationData TracyD3D12SrcLocSymbol { name, TracyFunction, TracyFile, (uint32_t)TracyLine, color };\n\n#if defined TRACY_HAS_CALLSTACK && defined TRACY_CALLSTACK\n#  define TracyD3D12Zone(ctx, cmdList, name) TracyD3D12NamedZoneS(ctx, TracyD3D12UnnamedZone, cmdList, name, TRACY_CALLSTACK, true)\n#  define TracyD3D12ZoneC(ctx, cmdList, name, color) TracyD3D12NamedZoneCS(ctx, TracyD3D12UnnamedZone, cmdList, name, color, TRACY_CALLSTACK, true)\n#  define TracyD3D12NamedZone(ctx, varname, cmdList, name, active) TracyD3D12SrcLocObject(name, 0); tracy::D3D12ZoneScope varname{ ctx, cmdList, &TracyD3D12SrcLocSymbol, TRACY_CALLSTACK, active };\n#  define TracyD3D12NamedZoneC(ctx, varname, cmdList, name, color, active) TracyD3D12SrcLocObject(name, color); tracy::D3D12ZoneScope varname{ ctx, cmdList, &TracyD3D12SrcLocSymbol, TRACY_CALLSTACK, active };\n#  define TracyD3D12ZoneTransient(ctx, varname, cmdList, name, active) TracyD3D12ZoneTransientS(ctx, varname, cmdList, name, TRACY_CALLSTACK, active)\n#else\n#  define TracyD3D12Zone(ctx, cmdList, name) TracyD3D12NamedZone(ctx, TracyD3D12UnnamedZone, cmdList, name, true)\n#  define TracyD3D12ZoneC(ctx, cmdList, name, color) TracyD3D12NamedZoneC(ctx, TracyD3D12UnnamedZone, cmdList, name, color, true)\n#  define TracyD3D12NamedZone(ctx, varname, cmdList, name, active) TracyD3D12SrcLocObject(name, 0); tracy::D3D12ZoneScope varname{ ctx, cmdList, &TracyD3D12SrcLocSymbol, active };\n#  define TracyD3D12NamedZoneC(ctx, varname, cmdList, name, color, active) TracyD3D12SrcLocObject(name, color); tracy::D3D12ZoneScope varname{ ctx, cmdList, &TracyD3D12SrcLocSymbol, active };\n#  define TracyD3D12ZoneTransient(ctx, varname, cmdList, name, active) tracy::D3D12ZoneScope varname{ ctx, TracyLine, TracyFile, strlen(TracyFile), TracyFunction, strlen(TracyFunction), name, strlen(name), cmdList, active };\n#endif\n\n#ifdef TRACY_HAS_CALLSTACK\n#  define TracyD3D12ZoneS(ctx, cmdList, name, depth) TracyD3D12NamedZoneS(ctx, TracyD3D12UnnamedZone, cmdList, name, depth, true)\n#  define TracyD3D12ZoneCS(ctx, cmdList, name, color, depth) TracyD3D12NamedZoneCS(ctx, TracyD3D12UnnamedZone, cmdList, name, color, depth, true)\n#  define TracyD3D12NamedZoneS(ctx, varname, cmdList, name, depth, active) TracyD3D12SrcLocObject(name, 0); tracy::D3D12ZoneScope varname{ ctx, cmdList, &TracyD3D12SrcLocSymbol, depth, active };\n#  define TracyD3D12NamedZoneCS(ctx, varname, cmdList, name, color, depth, active) TracyD3D12SrcLocObject(name, color); tracy::D3D12ZoneScope varname{ ctx, cmdList, &TracyD3D12SrcLocSymbol, depth, active };\n#  define TracyD3D12ZoneTransientS(ctx, varname, cmdList, name, depth, active) tracy::D3D12ZoneScope varname{ ctx, TracyLine, TracyFile, strlen(TracyFile), TracyFunction, strlen(TracyFunction), name, strlen(name), cmdList, depth, active };\n#else\n#  define TracyD3D12ZoneS(ctx, cmdList, name, depth) TracyD3D12Zone(ctx, cmdList, name)\n#  define TracyD3D12ZoneCS(ctx, cmdList, name, color, depth) TracyD3D12Zone(ctx, cmdList, name, color)\n#  define TracyD3D12NamedZoneS(ctx, varname, cmdList, name, depth, active) TracyD3D12NamedZone(ctx, varname, cmdList, name, active)\n#  define TracyD3D12NamedZoneCS(ctx, varname, cmdList, name, color, depth, active) TracyD3D12NamedZoneC(ctx, varname, cmdList, name, color, active)\n#  define TracyD3D12ZoneTransientS(ctx, varname, cmdList, name, depth, active) TracyD3D12ZoneTransient(ctx, varname, cmdList, name, active)\n#endif\n\n#define TracyD3D12Collect(ctx) ctx->Collect();\n\n#endif\n\n#endif\n"
  },
  {
    "path": "tracy-client-sys/tracy/tracy/TracyLua.hpp",
    "content": "#ifndef __TRACYLUA_HPP__\n#define __TRACYLUA_HPP__\n\n// Include this file after you include lua headers.\n\n#ifndef TRACY_ENABLE\n\n#include <string.h>\n\nnamespace tracy\n{\n\nnamespace detail\n{\nstatic inline int noop( lua_State* L ) { return 0; }\n}\n\nstatic inline void LuaRegister( lua_State* L )\n{\n    lua_newtable( L );\n    lua_pushcfunction( L, detail::noop );\n    lua_setfield( L, -2, \"ZoneBegin\" );\n    lua_pushcfunction( L, detail::noop );\n    lua_setfield( L, -2, \"ZoneBeginN\" );\n    lua_pushcfunction( L, detail::noop );\n    lua_setfield( L, -2, \"ZoneBeginS\" );\n    lua_pushcfunction( L, detail::noop );\n    lua_setfield( L, -2, \"ZoneBeginNS\" );\n    lua_pushcfunction( L, detail::noop );\n    lua_setfield( L, -2, \"ZoneEnd\" );\n    lua_pushcfunction( L, detail::noop );\n    lua_setfield( L, -2, \"ZoneText\" );\n    lua_pushcfunction( L, detail::noop );\n    lua_setfield( L, -2, \"ZoneName\" );\n    lua_pushcfunction( L, detail::noop );\n    lua_setfield( L, -2, \"Message\" );\n    lua_setglobal( L, \"tracy\" );\n}\n\nstatic inline char* FindEnd( char* ptr )\n{\n    unsigned int cnt = 1;\n    while( cnt != 0 )\n    {\n        if( *ptr == '(' ) cnt++;\n        else if( *ptr == ')' ) cnt--;\n        ptr++;\n    }\n    return ptr;\n}\n\nstatic inline void LuaRemove( char* script )\n{\n    while( *script )\n    {\n        if( strncmp( script, \"tracy.\", 6 ) == 0 )\n        {\n            if( strncmp( script + 6, \"Zone\", 4 ) == 0 )\n            {\n                if( strncmp( script + 10, \"End()\", 5 ) == 0 )\n                {\n                    memset( script, ' ', 15 );\n                    script += 15;\n                }\n                else if( strncmp( script + 10, \"Begin()\", 7 ) == 0 )\n                {\n                    memset( script, ' ', 17 );\n                    script += 17;\n                }\n                else if( strncmp( script + 10, \"Text(\", 5 ) == 0 )\n                {\n                    auto end = FindEnd( script + 15 );\n                    memset( script, ' ', end - script );\n                    script = end;\n                }\n                else if( strncmp( script + 10, \"Name(\", 5 ) == 0 )\n                {\n                    auto end = FindEnd( script + 15 );\n                    memset( script, ' ', end - script );\n                    script = end;\n                }\n                else if( strncmp( script + 10, \"BeginN(\", 7 ) == 0 )\n                {\n                    auto end = FindEnd( script + 17 );\n                    memset( script, ' ', end - script );\n                    script = end;\n                }\n                else if( strncmp( script + 10, \"BeginS(\", 7 ) == 0 )\n                {\n                    auto end = FindEnd( script + 17 );\n                    memset( script, ' ', end - script );\n                    script = end;\n                }\n                else if( strncmp( script + 10, \"BeginNS(\", 8 ) == 0 )\n                {\n                    auto end = FindEnd( script + 18 );\n                    memset( script, ' ', end - script );\n                    script = end;\n                }\n                else\n                {\n                    script += 10;\n                }\n            }\n            else if( strncmp( script + 6, \"Message(\", 8 ) == 0 )\n            {\n                auto end = FindEnd( script + 14 );\n                memset( script, ' ', end - script );\n                script = end;\n            }\n            else\n            {\n                script += 6;\n            }\n        }\n        else\n        {\n            script++;\n        }\n    }\n}\n\nstatic inline void LuaHook( lua_State* L, lua_Debug* ar ) {}\n\n}\n\n#else\n\n#include <assert.h>\n#include <limits>\n\n#include \"../common/TracyColor.hpp\"\n#include \"../common/TracyAlign.hpp\"\n#include \"../common/TracyForceInline.hpp\"\n#include \"../common/TracySystem.hpp\"\n#include \"../client/TracyProfiler.hpp\"\n\nnamespace tracy\n{\n\n#ifdef TRACY_ON_DEMAND\nTRACY_API LuaZoneState& GetLuaZoneState();\n#endif\n\nnamespace detail\n{\n\nstatic inline void LuaShortenSrc( char* dst, const char* src )\n{\n    size_t l = std::min( (size_t)255, strlen( src ) );\n    memcpy( dst, src, l );\n    dst[l] = 0;\n}\n\n#ifdef TRACY_HAS_CALLSTACK\nstatic tracy_force_inline void SendLuaCallstack( lua_State* L, uint32_t depth )\n{\n    assert( depth <= 64 );\n    lua_Debug dbg[64];\n    const char* func[64];\n    uint32_t fsz[64];\n    uint32_t ssz[64];\n\n    uint8_t cnt;\n    uint16_t spaceNeeded = sizeof( cnt );\n    for( cnt=0; cnt<depth; cnt++ )\n    {\n        if( lua_getstack( L, cnt+1, dbg+cnt ) == 0 ) break;\n        lua_getinfo( L, \"Snl\", dbg+cnt );\n        func[cnt] = dbg[cnt].name ? dbg[cnt].name : dbg[cnt].short_src;\n        fsz[cnt] = uint32_t( strlen( func[cnt] ) );\n        ssz[cnt] = uint32_t( strlen( dbg[cnt].source ) );\n        spaceNeeded += fsz[cnt] + ssz[cnt];\n    }\n    spaceNeeded += cnt * ( 4 + 2 + 2 );     // source line, function string length, source string length\n\n    auto ptr = (char*)tracy_malloc( spaceNeeded + 2 );\n    auto dst = ptr;\n    memcpy( dst, &spaceNeeded, 2 ); dst += 2;\n    memcpy( dst, &cnt, 1 ); dst++;\n    for( uint8_t i=0; i<cnt; i++ )\n    {\n        const uint32_t line = dbg[i].currentline;\n        memcpy( dst, &line, 4 ); dst += 4;\n        assert( fsz[i] <= (std::numeric_limits<uint16_t>::max)() );\n        memcpy( dst, fsz+i, 2 ); dst += 2;\n        memcpy( dst, func[i], fsz[i] ); dst += fsz[i];\n        assert( ssz[i] <= (std::numeric_limits<uint16_t>::max)() );\n        memcpy( dst, ssz+i, 2 ); dst += 2;\n        memcpy( dst, dbg[i].source, ssz[i] ), dst += ssz[i];\n    }\n    assert( dst - ptr == spaceNeeded + 2 );\n\n    TracyQueuePrepare( QueueType::CallstackAlloc );\n    MemWrite( &item->callstackAllocFat.ptr, (uint64_t)ptr );\n    MemWrite( &item->callstackAllocFat.nativePtr, (uint64_t)Callstack( depth ) );\n    TracyQueueCommit( callstackAllocFatThread );\n}\n\nstatic inline int LuaZoneBeginS( lua_State* L )\n{\n#ifdef TRACY_ON_DEMAND\n    const auto zoneCnt = GetLuaZoneState().counter++;\n    if( zoneCnt != 0 && !GetLuaZoneState().active ) return 0;\n    GetLuaZoneState().active = GetProfiler().IsConnected();\n    if( !GetLuaZoneState().active ) return 0;\n#endif\n\n#ifdef TRACY_CALLSTACK\n    const uint32_t depth = TRACY_CALLSTACK;\n#else\n    const auto depth = uint32_t( lua_tointeger( L, 1 ) );\n#endif\n    SendLuaCallstack( L, depth );\n\n    lua_Debug dbg;\n    lua_getstack( L, 1, &dbg );\n    lua_getinfo( L, \"Snl\", &dbg );\n    char src[256];\n    LuaShortenSrc( src, dbg.source );\n    const auto srcloc = Profiler::AllocSourceLocation( dbg.currentline, src, dbg.name ? dbg.name : dbg.short_src );\n\n    TracyQueuePrepare( QueueType::ZoneBeginAllocSrcLocCallstack );\n    MemWrite( &item->zoneBegin.time, Profiler::GetTime() );\n    MemWrite( &item->zoneBegin.srcloc, srcloc );\n    TracyQueueCommit( zoneBeginThread );\n\n    return 0;\n}\n\nstatic inline int LuaZoneBeginNS( lua_State* L )\n{\n#ifdef TRACY_ON_DEMAND\n    const auto zoneCnt = GetLuaZoneState().counter++;\n    if( zoneCnt != 0 && !GetLuaZoneState().active ) return 0;\n    GetLuaZoneState().active = GetProfiler().IsConnected();\n    if( !GetLuaZoneState().active ) return 0;\n#endif\n\n#ifdef TRACY_CALLSTACK\n    const uint32_t depth = TRACY_CALLSTACK;\n#else\n    const auto depth = uint32_t( lua_tointeger( L, 2 ) );\n#endif\n    SendLuaCallstack( L, depth );\n\n    lua_Debug dbg;\n    lua_getstack( L, 1, &dbg );\n    lua_getinfo( L, \"Snl\", &dbg );\n    size_t nsz;\n    char src[256];\n    LuaShortenSrc( src, dbg.source );\n    const auto name = lua_tolstring( L, 1, &nsz );\n    const auto srcloc = Profiler::AllocSourceLocation( dbg.currentline, src, dbg.name ? dbg.name : dbg.short_src, name, nsz );\n\n    TracyQueuePrepare( QueueType::ZoneBeginAllocSrcLocCallstack );\n    MemWrite( &item->zoneBegin.time, Profiler::GetTime() );\n    MemWrite( &item->zoneBegin.srcloc, srcloc );\n    TracyQueueCommit( zoneBeginThread );\n\n    return 0;\n}\n#endif\n\nstatic inline int LuaZoneBegin( lua_State* L )\n{\n#if defined TRACY_HAS_CALLSTACK && defined TRACY_CALLSTACK\n    return LuaZoneBeginS( L );\n#else\n#ifdef TRACY_ON_DEMAND\n    const auto zoneCnt = GetLuaZoneState().counter++;\n    if( zoneCnt != 0 && !GetLuaZoneState().active ) return 0;\n    GetLuaZoneState().active = GetProfiler().IsConnected();\n    if( !GetLuaZoneState().active ) return 0;\n#endif\n\n    lua_Debug dbg;\n    lua_getstack( L, 1, &dbg );\n    lua_getinfo( L, \"Snl\", &dbg );\n    char src[256];\n    LuaShortenSrc( src, dbg.source );\n    const auto srcloc = Profiler::AllocSourceLocation( dbg.currentline, src, dbg.name ? dbg.name : dbg.short_src );\n\n    TracyQueuePrepare( QueueType::ZoneBeginAllocSrcLoc );\n    MemWrite( &item->zoneBegin.time, Profiler::GetTime() );\n    MemWrite( &item->zoneBegin.srcloc, srcloc );\n    TracyQueueCommit( zoneBeginThread );\n    return 0;\n#endif\n}\n\nstatic inline int LuaZoneBeginN( lua_State* L )\n{\n#if defined TRACY_HAS_CALLSTACK && defined TRACY_CALLSTACK\n    return LuaZoneBeginNS( L );\n#else\n#ifdef TRACY_ON_DEMAND\n    const auto zoneCnt = GetLuaZoneState().counter++;\n    if( zoneCnt != 0 && !GetLuaZoneState().active ) return 0;\n    GetLuaZoneState().active = GetProfiler().IsConnected();\n    if( !GetLuaZoneState().active ) return 0;\n#endif\n\n    lua_Debug dbg;\n    lua_getstack( L, 1, &dbg );\n    lua_getinfo( L, \"Snl\", &dbg );\n    size_t nsz;\n    char src[256];\n    LuaShortenSrc( src, dbg.source );\n    const auto name = lua_tolstring( L, 1, &nsz );\n    const auto srcloc = Profiler::AllocSourceLocation( dbg.currentline, src, dbg.name ? dbg.name : dbg.short_src, name, nsz );\n\n    TracyQueuePrepare( QueueType::ZoneBeginAllocSrcLoc );\n    MemWrite( &item->zoneBegin.time, Profiler::GetTime() );\n    MemWrite( &item->zoneBegin.srcloc, srcloc );\n    TracyQueueCommit( zoneBeginThread );\n    return 0;\n#endif\n}\n\nstatic inline int LuaZoneEnd( lua_State* L )\n{\n#ifdef TRACY_ON_DEMAND\n    assert( GetLuaZoneState().counter != 0 );\n    GetLuaZoneState().counter--;\n    if( !GetLuaZoneState().active ) return 0;\n    if( !GetProfiler().IsConnected() )\n    {\n        GetLuaZoneState().active = false;\n        return 0;\n    }\n#endif\n\n    TracyQueuePrepare( QueueType::ZoneEnd );\n    MemWrite( &item->zoneEnd.time, Profiler::GetTime() );\n    TracyQueueCommit( zoneEndThread );\n    return 0;\n}\n\nstatic inline int LuaZoneText( lua_State* L )\n{\n#ifdef TRACY_ON_DEMAND\n    if( !GetLuaZoneState().active ) return 0;\n    if( !GetProfiler().IsConnected() )\n    {\n        GetLuaZoneState().active = false;\n        return 0;\n    }\n#endif\n\n    auto txt = lua_tostring( L, 1 );\n    const auto size = strlen( txt );\n    assert( size < (std::numeric_limits<uint16_t>::max)() );\n\n    auto ptr = (char*)tracy_malloc( size );\n    memcpy( ptr, txt, size );\n\n    TracyQueuePrepare( QueueType::ZoneText );\n    MemWrite( &item->zoneTextFat.text, (uint64_t)ptr );\n    MemWrite( &item->zoneTextFat.size, (uint16_t)size );\n    TracyQueueCommit( zoneTextFatThread );\n    return 0;\n}\n\nstatic inline int LuaZoneName( lua_State* L )\n{\n#ifdef TRACY_ON_DEMAND\n    if( !GetLuaZoneState().active ) return 0;\n    if( !GetProfiler().IsConnected() )\n    {\n        GetLuaZoneState().active = false;\n        return 0;\n    }\n#endif\n\n    auto txt = lua_tostring( L, 1 );\n    const auto size = strlen( txt );\n    assert( size < (std::numeric_limits<uint16_t>::max)() );\n\n    auto ptr = (char*)tracy_malloc( size );\n    memcpy( ptr, txt, size );\n\n    TracyQueuePrepare( QueueType::ZoneName );\n    MemWrite( &item->zoneTextFat.text, (uint64_t)ptr );\n    MemWrite( &item->zoneTextFat.size, (uint16_t)size );\n    TracyQueueCommit( zoneTextFatThread );\n    return 0;\n}\n\nstatic inline int LuaMessage( lua_State* L )\n{\n#ifdef TRACY_ON_DEMAND\n    if( !GetProfiler().IsConnected() ) return 0;\n#endif\n\n    auto txt = lua_tostring( L, 1 );\n    const auto size = strlen( txt );\n    assert( size < (std::numeric_limits<uint16_t>::max)() );\n\n    auto ptr = (char*)tracy_malloc( size );\n    memcpy( ptr, txt, size );\n\n    TracyQueuePrepare( QueueType::Message );\n    MemWrite( &item->messageFat.time, Profiler::GetTime() );\n    MemWrite( &item->messageFat.text, (uint64_t)ptr );\n    MemWrite( &item->messageFat.size, (uint16_t)size );\n    TracyQueueCommit( messageFatThread );\n    return 0;\n}\n\n}\n\nstatic inline void LuaRegister( lua_State* L )\n{\n    lua_newtable( L );\n    lua_pushcfunction( L, detail::LuaZoneBegin );\n    lua_setfield( L, -2, \"ZoneBegin\" );\n    lua_pushcfunction( L, detail::LuaZoneBeginN );\n    lua_setfield( L, -2, \"ZoneBeginN\" );\n#ifdef TRACY_HAS_CALLSTACK\n    lua_pushcfunction( L, detail::LuaZoneBeginS );\n    lua_setfield( L, -2, \"ZoneBeginS\" );\n    lua_pushcfunction( L, detail::LuaZoneBeginNS );\n    lua_setfield( L, -2, \"ZoneBeginNS\" );\n#else\n    lua_pushcfunction( L, detail::LuaZoneBegin );\n    lua_setfield( L, -2, \"ZoneBeginS\" );\n    lua_pushcfunction( L, detail::LuaZoneBeginN );\n    lua_setfield( L, -2, \"ZoneBeginNS\" );\n#endif\n    lua_pushcfunction( L, detail::LuaZoneEnd );\n    lua_setfield( L, -2, \"ZoneEnd\" );\n    lua_pushcfunction( L, detail::LuaZoneText );\n    lua_setfield( L, -2, \"ZoneText\" );\n    lua_pushcfunction( L, detail::LuaZoneName );\n    lua_setfield( L, -2, \"ZoneName\" );\n    lua_pushcfunction( L, detail::LuaMessage );\n    lua_setfield( L, -2, \"Message\" );\n    lua_setglobal( L, \"tracy\" );\n}\n\nstatic inline void LuaRemove( char* script ) {}\n\nstatic inline void LuaHook( lua_State* L, lua_Debug* ar )\n{\n    if ( ar->event == LUA_HOOKCALL )\n    {\n#ifdef TRACY_ON_DEMAND\n        const auto zoneCnt = GetLuaZoneState().counter++;\n        if ( zoneCnt != 0 && !GetLuaZoneState().active ) return;\n        GetLuaZoneState().active = GetProfiler().IsConnected();\n        if ( !GetLuaZoneState().active ) return;\n#endif\n        lua_getinfo( L, \"Snl\", ar );\n\n        char src[256];\n        detail::LuaShortenSrc( src, ar->short_src );\n\n        const auto srcloc = Profiler::AllocSourceLocation( ar->currentline, src, ar->name ? ar->name : ar->short_src );\n        TracyQueuePrepare( QueueType::ZoneBeginAllocSrcLoc );\n        MemWrite( &item->zoneBegin.time, Profiler::GetTime() );\n        MemWrite( &item->zoneBegin.srcloc, srcloc );\n        TracyQueueCommit( zoneBeginThread );\n    }\n    else if (ar->event == LUA_HOOKRET) {\n#ifdef TRACY_ON_DEMAND\n        assert( GetLuaZoneState().counter != 0 );\n        GetLuaZoneState().counter--;\n        if ( !GetLuaZoneState().active ) return;\n        if ( !GetProfiler().IsConnected() )\n        {\n            GetLuaZoneState().active = false;\n            return;\n        }\n#endif\n        TracyQueuePrepare( QueueType::ZoneEnd );\n        MemWrite( &item->zoneEnd.time, Profiler::GetTime() );\n        TracyQueueCommit( zoneEndThread );\n    }\n}\n\n}\n\n#endif\n\n#endif\n"
  },
  {
    "path": "tracy-client-sys/tracy/tracy/TracyMetal.hmm",
    "content": "#ifndef __TRACYMETAL_HMM__\n#define __TRACYMETAL_HMM__\n\n/* This file implements a Metal API back-end for Tracy (it has only been tested on Apple\n   Silicon devices, but it should also work on Intel-based Macs and older iOS devices).\n   The Metal back-end in Tracy operates differently than other GPU back-ends like Vulkan,\n   Direct3D and OpenGL. Specifically, TracyMetalZone() must be placed around the site where\n   a command encoder is created. This is because not all hardware supports timestamps at\n   command granularity, and can only provide timestamps around an entire command encoder.\n   This accommodates for all tiers of hardware; in the future, variants of TracyMetalZone()\n   will be added to support the habitual command-level granularity of Tracy GPU back-ends.\n   Metal also imposes a few restrictions that make the process of requesting and collecting\n   queries more complicated in Tracy:\n   a) timestamp query buffers are limited to 4096 queries (32KB, where each query is 8 bytes)\n   b) when a timestamp query buffer is created, Metal initializes all timestamps with zeroes,\n      and there's no way to reset them back to zero after timestamps get resolved; the only\n      way to clear the timestamps is by allocating a new timestamp query buffer\n   c) if a command encoder records no commands and its corresponding command buffer ends up\n      committed to the command queue, Metal will \"optimize-away\" the encoder along with any\n      timestamp queries associated with it (the timestamp will remain as zero and will never\n      get resolved)\n   Because of the limitations above, two timestamp buffers are managed internally. Once one\n   of the buffers fills up with requests, the second buffer can start serving new requests.\n   Once all requests in a buffer get resolved and collected, the entire buffer is discarded\n   and a new one allocated for future requests. (Proper cycling through a ring buffer would\n   require bookkeeping and completion handlers to collect only the known complete queries.)\n   In the current implementation, there is potential for a race condition when the buffer is\n   discarded and reallocated. In practice, the race condition will never materialize so long\n   as TracyMetalCollect() is called frequently to keep the amount of unresolved queries low.\n   Finally, there's a timeout mechanism during timestamp collection to detect \"empty\" command\n   encoders and ensure progress.\n*/\n\n#ifndef TRACY_ENABLE\n\n#define TracyMetalContext(device) nullptr\n#define TracyMetalDestroy(ctx)\n#define TracyMetalContextName(ctx, name, size)\n\n#define TracyMetalZone(ctx, encoderDesc, name)\n#define TracyMetalZoneC(ctx, encoderDesc, name, color)\n#define TracyMetalNamedZone(ctx, varname, encoderDesc, name, active)\n#define TracyMetalNamedZoneC(ctx, varname, encoderDesc, name, color, active)\n\n#define TracyMetalCollect(ctx)\n\nnamespace tracy\n{\nclass MetalZoneScope {};\n}\n\nusing TracyMetalCtx = void;\n\n#else\n\n#if not __has_feature(objc_arc)\n#error TracyMetal requires ARC to be enabled.\n#endif\n\n#include <atomic>\n#include <cassert>\n#include <cstdlib>\n\n#include \"Tracy.hpp\"\n#include \"../client/TracyProfiler.hpp\"\n#include \"../client/TracyCallstack.hpp\"\n#include \"../common/TracyAlign.hpp\"\n#include \"../common/TracyAlloc.hpp\"\n\n// ok to import if in obj-c code\n#import <Metal/Metal.h>\n\n#define TRACY_METAL_VA_ARGS(...) , ##__VA_ARGS__\n\n#define TracyMetalPanic(ret, msg, ...) do { \\\n    char buffer [1024]; \\\n    snprintf(buffer, sizeof(buffer), \"TracyMetal: \" msg TRACY_METAL_VA_ARGS(__VA_ARGS__)); \\\n    TracyMessageC(buffer, strlen(buffer), tracy::Color::OrangeRed); \\\n    fprintf(stderr, \"%s\\n\", buffer); \\\n    ret; \\\n    } while(false);\n\n#ifndef TRACY_METAL_TIMESTAMP_COLLECT_TIMEOUT\n#define TRACY_METAL_TIMESTAMP_COLLECT_TIMEOUT 0.200f\n#endif//TRACY_METAL_TIMESTAMP_COLLECT_TIMEOUT\n\n#ifndef TRACY_METAL_DEBUG_MASK\n#define TRACY_METAL_DEBUG_MASK (0)\n#endif//TRACY_METAL_DEBUG_MASK\n\n#if TRACY_METAL_DEBUG_MASK\n    #define TracyMetalDebugMasked(mask, ...) if constexpr (mask & TRACY_METAL_DEBUG_MASK) { __VA_ARGS__; }\n#else\n    #define TracyMetalDebugMasked(mask, ...)\n#endif\n\n#if TRACY_METAL_DEBUG_MASK & (1 << 1)\n    #define TracyMetalDebug_0b00010(...) __VA_ARGS__;\n#else\n    #define TracyMetalDebug_0b00010(...)\n#endif\n\n#if TRACY_METAL_DEBUG_MASK & (1 << 4)\n    #define TracyMetalDebug_0b10000(...) __VA_ARGS__;\n#else\n    #define TracyMetalDebug_0b10000(...)\n#endif\n\n#ifndef TracyMetalDebugZoneScopeWireTap\n#define TracyMetalDebugZoneScopeWireTap\n#endif//TracyMetalDebugZoneScopeWireTap\n\nnamespace tracy\n{\n\nclass MetalCtx\n{\n    friend class MetalZoneScope;\n\n    enum { MaxQueries = 4 * 1024 };    // Metal: between 8 and 32768 _BYTES_...\n\npublic:\n    static MetalCtx* Create(id<MTLDevice> device)\n    {\n        ZoneScopedNC(\"tracy::MetalCtx::Create\", Color::Red4);\n        auto ctx = static_cast<MetalCtx*>(tracy_malloc(sizeof(MetalCtx)));\n        new (ctx) MetalCtx(device);\n        if (ctx->m_contextId == 255)\n        {\n            TracyMetalPanic({assert(false);} return nullptr, \"ERROR: unable to create context.\");\n            Destroy(ctx);\n        }\n        return ctx;\n    }\n\n    static void Destroy(MetalCtx* ctx)\n    {\n        ZoneScopedNC(\"tracy::MetalCtx::Destroy\", Color::Red4);\n        ctx->~MetalCtx();\n        tracy_free(ctx);\n    }\n\n    void Name( const char* name, uint16_t len )\n    {\n        auto ptr = (char*)tracy_malloc( len );\n        memcpy( ptr, name, len );\n\n        auto* item = Profiler::QueueSerial();\n        MemWrite( &item->hdr.type, QueueType::GpuContextName );\n        MemWrite( &item->gpuContextNameFat.context, m_contextId );\n        MemWrite( &item->gpuContextNameFat.ptr, (uint64_t)ptr );\n        MemWrite( &item->gpuContextNameFat.size, len );\n        SubmitQueueItem(item);\n    }\n\n    bool Collect()\n    {\n        ZoneScopedNC(\"tracy::MetalCtx::Collect\", Color::Red4);\n\n#ifdef TRACY_ON_DEMAND\n        if (!GetProfiler().IsConnected())\n        {\n            return true;\n        }\n#endif\n\n        // Only one thread is allowed to collect timestamps at any given time\n        // but there's no need to block contending threads\n        if (!m_collectionMutex.try_lock())\n        {\n            return true;\n        }\n\n        std::unique_lock lock (m_collectionMutex, std::adopt_lock);\n\n        uintptr_t begin = m_previousCheckpoint.load();\n        uintptr_t latestCheckpoint = m_queryCounter.load(); // TODO: MTLEvent? MTLFence?;\n        TracyMetalDebugMasked(1<<3, ZoneValue(begin));\n        TracyMetalDebugMasked(1<<3, ZoneValue(latestCheckpoint));\n\n        uint32_t count = RingCount(begin, latestCheckpoint);\n        if (count == 0)   // no pending timestamp queries\n        {\n            //uintptr_t nextCheckpoint = m_queryCounter.load();\n            //if (nextCheckpoint != latestCheckpoint)\n            //{\n            //    // TODO: signal event / fence now?\n            //}\n            return true;\n        }\n\n        // resolve up until the ring buffer boundary and let a subsequenty call\n        // to Collect handle the wrap-around\n        bool reallocateBuffer = false;\n        if (RingIndex(begin) + count >= RingSize())\n        {\n            count = RingSize() - RingIndex(begin);\n            reallocateBuffer = true;\n        }\n        TracyMetalDebugMasked(1<<3, ZoneValue(count));\n        \n        auto buffer_idx = (begin / MaxQueries) % 2;\n        auto counterSampleBuffer = m_counterSampleBuffers[buffer_idx];\n\n        if (count >= RingSize())\n        {\n            TracyMetalPanic(return false, \"Collect: FULL! too many pending timestamp queries. [%llu, %llu] (%u)\", begin, latestCheckpoint, count);\n        }\n\n        TracyMetalDebugMasked(1<<3, TracyMetalPanic(, \"Collect: [%llu, %llu] :: (%u)\", begin, latestCheckpoint, count));\n\n        NSRange range = NSMakeRange(RingIndex(begin), count);\n        NSData* data = [counterSampleBuffer resolveCounterRange:range];\n        NSUInteger numResolvedTimestamps = data.length / sizeof(MTLCounterResultTimestamp);\n        MTLCounterResultTimestamp* timestamps = (MTLCounterResultTimestamp *)(data.bytes);\n        if (timestamps == nil)\n        {\n            TracyMetalPanic(return false, \"Collect: unable to resolve timestamps.\");\n        }\n\n        if (numResolvedTimestamps != count)\n        {\n            TracyMetalPanic(, \"Collect: numResolvedTimestamps != count : %u != %u\", (uint32_t)numResolvedTimestamps, count);\n        }\n\n        int resolved = 0;\n        for (auto i = 0; i < numResolvedTimestamps; i += 2)\n        {\n            TracyMetalDebug_0b10000( ZoneScopedN(\"tracy::MetalCtx::Collect::[i]\") );\n            MTLTimestamp t_start = timestamps[i+0].timestamp;\n            MTLTimestamp t_end = timestamps[i+1].timestamp;\n            uint32_t k = RingIndex(begin + i);\n            TracyMetalDebugMasked(1<<4, TracyMetalPanic(, \"Collect: timestamp[%u] = %llu | timestamp[%u] = %llu | diff = %llu\\n\", k, t_start, k+1, t_end, (t_end - t_start)));\n            if ((t_start == MTLCounterErrorValue)  || (t_end == MTLCounterErrorValue))\n            {\n                TracyMetalPanic(, \"Collect: invalid timestamp (MTLCounterErrorValue) at %u.\", k);\n                break;\n            }\n            // Metal will initialize timestamp buffer with zeroes; encountering a zero-value\n            // timestamp means that the timestamp has not been written and resolved yet\n            if ((t_start == 0) || (t_end == 0))\n            {\n                auto checkTime = std::chrono::high_resolution_clock::now();\n                auto requestTime = m_timestampRequestTime[k];\n                auto ms_in_flight = std::chrono::duration<float>(checkTime-requestTime).count()*1000.0f;\n                TracyMetalDebugMasked(1<<4, TracyMetalPanic(, \"Collect: invalid timestamp (zero) at %u [%.0fms in flight].\", k, ms_in_flight));\n                const float timeout_ms = TRACY_METAL_TIMESTAMP_COLLECT_TIMEOUT * 1000.0f;\n                if (ms_in_flight < timeout_ms)\n                    break;\n                TracyMetalDebug_0b10000( ZoneScopedN(\"tracy::MetalCtx::Collect::Drop\") );\n                TracyMetalPanic(, \"Collect: giving up on timestamp at %u [%.0fms in flight].\", k, ms_in_flight);\n                t_start = m_mostRecentTimestamp + 5;\n                t_end = t_start + 5;\n            }\n            TracyMetalDebugMasked(1<<2, TracyFreeN((void*)(uintptr_t)(k+0), \"TracyMetalGpuZone\"));\n            TracyMetalDebugMasked(1<<2, TracyFreeN((void*)(uintptr_t)(k+1), \"TracyMetalGpuZone\"));\n            {\n            auto* item = Profiler::QueueSerial();\n            MemWrite(&item->hdr.type, QueueType::GpuTime);\n            MemWrite(&item->gpuTime.gpuTime, static_cast<int64_t>(t_start));\n            MemWrite(&item->gpuTime.queryId, static_cast<uint16_t>(k));\n            MemWrite(&item->gpuTime.context, m_contextId);\n            Profiler::QueueSerialFinish();\n            }\n            {\n            auto* item = Profiler::QueueSerial();\n            MemWrite(&item->hdr.type, QueueType::GpuTime);\n            MemWrite(&item->gpuTime.gpuTime, static_cast<int64_t>(t_end));\n            MemWrite(&item->gpuTime.queryId, static_cast<uint16_t>(k+1));\n            MemWrite(&item->gpuTime.context, m_contextId);\n            Profiler::QueueSerialFinish();\n            }\n            m_mostRecentTimestamp = (t_end > m_mostRecentTimestamp) ? t_end : m_mostRecentTimestamp;\n            TracyMetalDebugMasked(1<<1, TracyFreeN((void*)(uintptr_t)k, \"TracyMetalTimestampQueryId\"));\n            resolved += 2;\n        }\n        TracyMetalDebugMasked(1<<3, ZoneValue(RingCount(begin, m_previousCheckpoint.load())));\n        \n        m_previousCheckpoint += resolved;\n        \n        // Check whether the timestamp buffer has been fully resolved/collected:\n        // WARN: there's technically a race condition here: NextQuery() may reference the\n        // buffer that is being released instead of the new one. In practice, this should\n        // never happen so long as Collect is called frequently enough to prevent pending\n        // timestamp query requests from piling up too quickly.\n        if ((resolved == count) && (m_previousCheckpoint.load() % MaxQueries) == 0)\n        {\n            m_counterSampleBuffers[buffer_idx] = NewTimestampSampleBuffer(m_device, MaxQueries);\n        }\n\n        //RecalibrateClocks();    // to account for drift\n\n        return true;\n    }\n\nprivate:\n    MetalCtx(id<MTLDevice> device)\n    : m_device(device)\n    {\n        TracyMetalDebugMasked(1<<0, TracyMetalPanic(, \"MTLCounterErrorValue = 0x%llx\", MTLCounterErrorValue));\n        TracyMetalDebugMasked(1<<0, TracyMetalPanic(, \"MTLCounterDontSample = 0x%llx\", MTLCounterDontSample));\n        \n        if (m_device == nil)\n        {\n            TracyMetalPanic({assert(false);} return, \"device is nil.\");\n        }\n        if (![m_device supportsCounterSampling:MTLCounterSamplingPointAtStageBoundary])\n        {\n            TracyMetalPanic({assert(false);} return, \"ERROR: timestamp sampling at pipeline stage boundary is not supported.\");\n        }\n        if (![m_device supportsCounterSampling:MTLCounterSamplingPointAtDrawBoundary])\n        {\n            TracyMetalDebugMasked(1<<0, fprintf(stderr, \"WARNING: timestamp sampling at draw call boundary is not supported.\\n\"));\n        }\n        if (![m_device supportsCounterSampling:MTLCounterSamplingPointAtBlitBoundary])\n        {\n            TracyMetalDebugMasked(1<<0, fprintf(stderr, \"WARNING: timestamp sampling at blit boundary is not supported.\\n\"));\n        }\n        if (![m_device supportsCounterSampling:MTLCounterSamplingPointAtDispatchBoundary])\n        {\n            TracyMetalDebugMasked(1<<0, fprintf(stderr, \"WARNING: timestamp sampling at compute dispatch boundary is not supported.\\n\"));\n        }\n        if (![m_device supportsCounterSampling:MTLCounterSamplingPointAtTileDispatchBoundary])\n        {\n            TracyMetalDebugMasked(1<<0, fprintf(stderr, \"WARNING: timestamp sampling at tile dispatch boundary is not supported.\\n\"));\n        }\n        \n        m_counterSampleBuffers[0] = NewTimestampSampleBuffer(m_device, MaxQueries);\n        m_counterSampleBuffers[1] = NewTimestampSampleBuffer(m_device, MaxQueries);\n        \n        m_timestampRequestTime.resize(MaxQueries);\n\n        MTLTimestamp cpuTimestamp = 0;\n        MTLTimestamp gpuTimestamp = 0;\n        [m_device sampleTimestamps:&cpuTimestamp gpuTimestamp:&gpuTimestamp];\n        m_mostRecentTimestamp = gpuTimestamp;\n        TracyMetalDebugMasked(1<<0, TracyMetalPanic(, \"Calibration: CPU timestamp (Metal): %llu\", cpuTimestamp));\n        TracyMetalDebugMasked(1<<0, TracyMetalPanic(, \"Calibration: GPU timestamp (Metal): %llu\", gpuTimestamp));\n\n        cpuTimestamp = Profiler::GetTime();\n        TracyMetalDebugMasked(1<<0, TracyMetalPanic(, \"Calibration: CPU timestamp (Tracy): %llu\", cpuTimestamp));\n\n        float period = 1.0f;\n        \n        m_contextId = GetGpuCtxCounter().fetch_add(1);\n        \n        auto* item = Profiler::QueueSerial();\n        MemWrite(&item->hdr.type, QueueType::GpuNewContext);\n        MemWrite(&item->gpuNewContext.cpuTime, int64_t(cpuTimestamp));\n        MemWrite(&item->gpuNewContext.gpuTime, int64_t(gpuTimestamp));\n        MemWrite(&item->gpuNewContext.thread, uint32_t(0)); // TODO: why not GetThreadHandle()?\n        MemWrite(&item->gpuNewContext.period, period);\n        MemWrite(&item->gpuNewContext.context, m_contextId);\n        //MemWrite(&item->gpuNewContext.flags, GpuContextCalibration);\n        MemWrite(&item->gpuNewContext.flags, GpuContextFlags(0));\n        MemWrite(&item->gpuNewContext.type, GpuContextType::Metal);\n        SubmitQueueItem(item);\n    }\n\n    ~MetalCtx()\n    {\n        // collect the last remnants of Metal GPU activity...\n        // TODO: add a timeout to this loop?\n        while (m_previousCheckpoint.load() != m_queryCounter.load())\n            Collect();\n    }\n\n    tracy_force_inline void SubmitQueueItem(QueueItem* item)\n    {\n#ifdef TRACY_ON_DEMAND\n        GetProfiler().DeferItem(*item);\n#endif\n        Profiler::QueueSerialFinish();\n    }\n\n    tracy_force_inline uint32_t RingIndex(uintptr_t index)\n    {\n        index %= MaxQueries;\n        return static_cast<uint32_t>(index);\n    }\n\n    tracy_force_inline uint32_t RingCount(uintptr_t begin, uintptr_t end)\n    {\n        // wrap-around safe: all unsigned\n        uintptr_t count = end - begin;\n        return static_cast<uint32_t>(count);\n    }\n\n    tracy_force_inline uint32_t RingSize() const\n    {\n        return MaxQueries;\n    }\n\n    struct Query { id<MTLCounterSampleBuffer> buffer; uint32_t idx; };\n\n    tracy_force_inline Query NextQuery()\n    {\n        TracyMetalDebug_0b00010( ZoneScopedNC(\"Tracy::MetalCtx::NextQuery\", tracy::Color::LightCoral) );\n        auto id = m_queryCounter.fetch_add(2);\n        TracyMetalDebug_0b00010( ZoneValue(id) );\n        auto count = RingCount(m_previousCheckpoint, id);\n        if (count >= MaxQueries)\n        {\n            // TODO: return a proper (hidden) \"sentinel\" query\n            Query sentinel = Query{ m_counterSampleBuffers[1], MaxQueries-2 };\n            TracyMetalPanic(\n                return sentinel,\n                \"NextQueryId: FULL! too many pending timestamp queries. Consider calling TracyMetalCollect() more frequently. [%llu, %llu] (%u)\",\n                m_previousCheckpoint.load(), id, count\n            );\n        }\n        uint32_t buffer_idx = (id / MaxQueries) % 2;\n        TracyMetalDebug_0b00010( ZoneValue(buffer_idx) );\n        auto buffer = m_counterSampleBuffers[buffer_idx];\n        if (buffer == nil)\n            TracyMetalPanic(, \"NextQueryId: sample buffer is nil! (id=%llu)\", id);\n        uint32_t idx = RingIndex(id);\n        TracyMetalDebug_0b00010( ZoneValue(idx) );\n        TracyMetalDebug_0b00010( TracyAllocN((void*)(uintptr_t)idx, 2, \"TracyMetalTimestampQueryId\") );\n        m_timestampRequestTime[idx] = std::chrono::high_resolution_clock::now();\n        return Query{ buffer, idx };\n    }\n\n    tracy_force_inline uint8_t GetContextId() const\n    {\n        return m_contextId;\n    }\n    \n    static id<MTLCounterSampleBuffer> NewTimestampSampleBuffer(id<MTLDevice> device, size_t count)\n    {\n        ZoneScopedN(\"tracy::MetalCtx::NewTimestampSampleBuffer\");\n\n        id<MTLCounterSet> timestampCounterSet = nil;\n        for (id<MTLCounterSet> counterSet in device.counterSets)\n        {\n            if ([counterSet.name isEqualToString:MTLCommonCounterSetTimestamp])\n            {\n                timestampCounterSet = counterSet;\n                break;\n            }\n        }\n        if (timestampCounterSet == nil)\n        {\n            TracyMetalPanic({assert(false);} return nil, \"ERROR: timestamp counters are not supported on the platform.\");\n        }\n\n        MTLCounterSampleBufferDescriptor* sampleDescriptor = [[MTLCounterSampleBufferDescriptor alloc] init];\n        sampleDescriptor.counterSet = timestampCounterSet;\n        sampleDescriptor.sampleCount = MaxQueries;\n        sampleDescriptor.storageMode = MTLStorageModeShared;\n        sampleDescriptor.label = @\"TracyMetalTimestampPool\";\n\n        NSError* error = nil;\n        id<MTLCounterSampleBuffer> counterSampleBuffer = [device newCounterSampleBufferWithDescriptor:sampleDescriptor error:&error];\n        if (error != nil)\n        {\n            //NSLog(@\"%@ | %@\", error.localizedDescription, error.localizedFailureReason);\n            TracyMetalPanic({assert(false);} return nil,\n                \"ERROR: unable to create sample buffer for timestamp counters : %s | %s\",\n                [error.localizedDescription cString], [error.localizedFailureReason cString]);\n        }\n        \n        return counterSampleBuffer;\n    }\n\n    uint8_t m_contextId = 255;\n\n    id<MTLDevice> m_device = nil;\n    id<MTLCounterSampleBuffer> m_counterSampleBuffers [2] = {};\n\n    using atomic_counter = std::atomic<uintptr_t>;\n    static_assert(atomic_counter::is_always_lock_free);\n    atomic_counter m_queryCounter = 0;\n\n    atomic_counter m_previousCheckpoint = 0;\n    MTLTimestamp m_mostRecentTimestamp = 0;\n    \n    std::vector<std::chrono::high_resolution_clock::time_point> m_timestampRequestTime;\n    \n    std::mutex m_collectionMutex;\n};\n\nclass MetalZoneScope\n{\npublic:\n    tracy_force_inline MetalZoneScope( MetalCtx* ctx, MTLComputePassDescriptor* desc, const SourceLocationData* srcloc, bool is_active )\n#ifdef TRACY_ON_DEMAND\n        : m_active( is_active && GetProfiler().IsConnected() )\n#else\n        : m_active( is_active )\n#endif\n    {\n        if ( !m_active ) return;\n        if (desc == nil) TracyMetalPanic({assert(false);} return, \"compute pass descriptor is nil.\");\n        m_ctx = ctx;\n\n        auto& query = m_query = ctx->NextQuery();\n\n        desc.sampleBufferAttachments[0].sampleBuffer = query.buffer;\n        desc.sampleBufferAttachments[0].startOfEncoderSampleIndex = query.idx+0;\n        desc.sampleBufferAttachments[0].endOfEncoderSampleIndex   = query.idx+1;\n\n        SubmitZoneBeginGpu(ctx, query.idx + 0, srcloc);\n    }\n\n    tracy_force_inline MetalZoneScope( MetalCtx* ctx, MTLBlitPassDescriptor* desc, const SourceLocationData* srcloc, bool is_active )\n#ifdef TRACY_ON_DEMAND\n        : m_active( is_active && GetProfiler().IsConnected() )\n#else\n        : m_active( is_active )\n#endif\n    {\n        if ( !m_active ) return;\n        if (desc == nil) TracyMetalPanic({assert(false); }return, \"blit pass descriptor is nil.\");\n        m_ctx = ctx;\n\n        auto& query = m_query = ctx->NextQuery();\n\n        desc.sampleBufferAttachments[0].sampleBuffer = query.buffer;\n        desc.sampleBufferAttachments[0].startOfEncoderSampleIndex = query.idx+0;\n        desc.sampleBufferAttachments[0].endOfEncoderSampleIndex = query.idx+1;\n\n        SubmitZoneBeginGpu(ctx, query.idx + 0, srcloc);\n    }\n\n    tracy_force_inline MetalZoneScope( MetalCtx* ctx, MTLRenderPassDescriptor* desc, const SourceLocationData* srcloc, bool is_active )\n#ifdef TRACY_ON_DEMAND\n        : m_active( is_active && GetProfiler().IsConnected() )\n#else\n        : m_active( is_active )\n#endif\n    {\n        if ( !m_active ) return;\n        if (desc == nil) TracyMetalPanic({assert(false);} return, \"render pass descriptor is nil.\");\n        m_ctx = ctx;\n\n        auto& query = m_query = ctx->NextQuery();\n\n        desc.sampleBufferAttachments[0].sampleBuffer = query.buffer;\n        desc.sampleBufferAttachments[0].startOfVertexSampleIndex = query.idx+0;\n        desc.sampleBufferAttachments[0].endOfVertexSampleIndex = MTLCounterDontSample;\n        desc.sampleBufferAttachments[0].startOfFragmentSampleIndex = MTLCounterDontSample;\n        desc.sampleBufferAttachments[0].endOfFragmentSampleIndex = query.idx+1;\n\n        SubmitZoneBeginGpu(ctx, query.idx + 0, srcloc);\n    }\n\n    /* TODO: implement this constructor interfarce for \"command-level\" profiling, if the device supports it\n    tracy_force_inline MetalZoneScope( MetalCtx* ctx, id<MTLComputeCommandEncoder> cmdEncoder, const SourceLocationData* srcloc, bool is_active )\n#ifdef TRACY_ON_DEMAND\n        : m_active( is_active && GetProfiler().IsConnected() )\n#else\n        : m_active( is_active )\n#endif\n    {\n        if( !m_active ) return;\n        m_ctx = ctx;\n        m_cmdEncoder = cmdEncoder;\n\n        auto& query = m_query = ctx->NextQueryId();\n\n        [m_cmdEncoder sampleCountersInBuffer:m_ctx->m_counterSampleBuffer atSampleIndex:query.idx withBarrier:YES];\n\n        SubmitZoneBeginGpu(ctx, query.idx, srcloc);\n    }\n    */\n\n    tracy_force_inline ~MetalZoneScope()\n    {\n        if( !m_active ) return;\n\n        SubmitZoneEndGpu(m_ctx, m_query.idx + 1);\n    }\n    \n    TracyMetalDebugZoneScopeWireTap;\n\nprivate:\n    const bool m_active;\n\n    MetalCtx* m_ctx;\n\n    /* TODO: declare it for \"command-level\" profiling\n    id<MTLComputeCommandEncoder> m_cmdEncoder;\n    */\n    \n    static void SubmitZoneBeginGpu(MetalCtx* ctx, uint32_t queryId, const SourceLocationData* srcloc)\n    {\n        auto* item = Profiler::QueueSerial();\n        MemWrite( &item->hdr.type, QueueType::GpuZoneBeginSerial );\n        MemWrite( &item->gpuZoneBegin.cpuTime, Profiler::GetTime() );\n        MemWrite( &item->gpuZoneBegin.srcloc, (uint64_t)srcloc );\n        MemWrite( &item->gpuZoneBegin.thread, GetThreadHandle() );\n        MemWrite( &item->gpuZoneBegin.queryId, uint16_t( queryId ) );\n        MemWrite( &item->gpuZoneBegin.context, ctx->GetContextId() );\n        Profiler::QueueSerialFinish();\n        \n        TracyMetalDebugMasked(1<<2, TracyAllocN((void*)(uintptr_t)queryId, 1, \"TracyMetalGpuZone\"));\n    }\n    \n    static void SubmitZoneEndGpu(MetalCtx* ctx, uint32_t queryId)\n    {\n        auto* item = Profiler::QueueSerial();\n        MemWrite( &item->hdr.type, QueueType::GpuZoneEndSerial );\n        MemWrite( &item->gpuZoneEnd.cpuTime, Profiler::GetTime() );\n        MemWrite( &item->gpuZoneEnd.thread, GetThreadHandle() );\n        MemWrite( &item->gpuZoneEnd.queryId, uint16_t( queryId ) );\n        MemWrite( &item->gpuZoneEnd.context, ctx->GetContextId() );\n        Profiler::QueueSerialFinish();\n        \n        TracyMetalDebugMasked(1<<2, TracyAllocN((void*)(uintptr_t)queryId, 1, \"TracyMetalGpuZone\"));\n    }\n\n    MetalCtx::Query m_query = {};\n};\n\n}\n\nusing TracyMetalCtx = tracy::MetalCtx;\n\n#define TracyMetalContext(device) tracy::MetalCtx::Create(device)\n#define TracyMetalDestroy(ctx) tracy::MetalCtx::Destroy(ctx)\n#define TracyMetalContextName(ctx, name, size) ctx->Name(name, size)\n\n#define TracyMetalZone( ctx, encoderDesc, name ) TracyMetalNamedZone( ctx, ___tracy_gpu_zone, encoderDesc, name, true )\n#define TracyMetalZoneC( ctx, encoderDesc, name, color ) TracyMetalNamedZoneC( ctx, ___tracy_gpu_zone, encoderDesc, name, color, true )\n#define TracyMetalNamedZone( ctx, varname, encoderDesc, name, active ) static constexpr tracy::SourceLocationData TracyConcat(__tracy_gpu_source_location,TracyLine) { name, TracyFunction,  TracyFile, (uint32_t)TracyLine, 0 }; tracy::MetalZoneScope varname( ctx, encoderDesc, &TracyConcat(__tracy_gpu_source_location,TracyLine), active );\n#define TracyMetalNamedZoneC( ctx, varname, encoderDesc, name, color, active ) static constexpr tracy::SourceLocationData TracyConcat(__tracy_gpu_source_location,TracyLine) { name, TracyFunction, TracyFile, (uint32_t)TracyLine, color }; tracy::MetalZoneScope varname( ctx, encoderDesc, &TracyConcat(__tracy_gpu_source_location,TracyLine), active );\n\n#define TracyMetalCollect( ctx ) ctx->Collect();\n\n\n\n#undef TracyMetalDebug_ZoneScopeWireTap\n#undef TracyMetalDebug_0b00010\n#undef TracyMetalDebug_0b10000\n#undef TracyMetalDebugMasked\n#undef TRACY_METAL_DEBUG_MASK\n#undef TRACY_METAL_TIMESTAMP_COLLECT_TIMEOUT\n#undef TracyMetalPanic\n#undef TRACY_METAL_VA_ARGS\n\n#endif\n\n#endif//__TRACYMETAL_HMM__\n"
  },
  {
    "path": "tracy-client-sys/tracy/tracy/TracyOpenCL.hpp",
    "content": "#ifndef __TRACYOPENCL_HPP__\n#define __TRACYOPENCL_HPP__\n\n#if !defined TRACY_ENABLE\n\n#define TracyCLContext(c, x) nullptr\n#define TracyCLDestroy(c)\n#define TracyCLContextName(c, x, y)\n\n#define TracyCLNamedZone(c, x, y, z)\n#define TracyCLNamedZoneC(c, x, y, z, w)\n#define TracyCLZone(c, x)\n#define TracyCLZoneC(c, x, y)\n#define TracyCLZoneTransient(c,x,y,z)\n\n#define TracyCLNamedZoneS(c, x, y, z, w)\n#define TracyCLNamedZoneCS(c, x, y, z, w, v)\n#define TracyCLZoneS(c, x, y)\n#define TracyCLZoneCS(c, x, y, z)\n#define TracyCLZoneTransientS(c,x,y,z,w)\n\n#define TracyCLNamedZoneSetEvent(x, e)\n#define TracyCLZoneSetEvent(e)\n\n#define TracyCLCollect(c)\n\nnamespace tracy\n{\n    class OpenCLCtxScope {};\n}\n\nusing TracyCLCtx = void*;\n\n#else\n\n#include <CL/cl.h>\n\n#include <atomic>\n#include <cassert>\n#include <sstream>\n\n#include \"Tracy.hpp\"\n#include \"../client/TracyCallstack.hpp\"\n#include \"../client/TracyProfiler.hpp\"\n#include \"../common/TracyAlloc.hpp\"\n\n#define TRACY_CL_TO_STRING_INDIRECT(T) #T\n#define TRACY_CL_TO_STRING(T) TRACY_CL_TO_STRING_INDIRECT(T)\n#define TRACY_CL_ASSERT(p) if(!(p)) {                                                         \\\n    TracyMessageL( \"TRACY_CL_ASSERT failed on \" TracyFile \":\" TRACY_CL_TO_STRING(TracyLine) );  \\\n    assert(false && \"TRACY_CL_ASSERT failed\");                                                \\\n}\n#define TRACY_CL_CHECK_ERROR(err) if(err != CL_SUCCESS) {                    \\\n    std::ostringstream oss;                                                  \\\n    oss << \"TRACY_CL_CHECK_ERROR failed on \" << TracyFile << \":\" << TracyLine  \\\n        << \": error code \" << err;                                           \\\n    auto msg = oss.str();                                                    \\\n    TracyMessage(msg.data(), msg.size());                                    \\\n    assert(false && \"TRACY_CL_CHECK_ERROR failed\");                          \\\n}\n\nnamespace tracy {\n\n    enum class EventPhase : uint8_t\n    {\n        Begin,\n        End\n    };\n\n    struct EventInfo\n    {\n        cl_event event;\n        EventPhase phase;\n    };\n\n    class OpenCLCtx\n    {\n    public:\n        enum { QueryCount = 64 * 1024 };\n\n        OpenCLCtx(cl_context context, cl_device_id device)\n            : m_contextId(GetGpuCtxCounter().fetch_add(1, std::memory_order_relaxed))\n            , m_head(0)\n            , m_tail(0)\n        {\n            int64_t tcpu, tgpu;\n            TRACY_CL_ASSERT(m_contextId != 255);\n\n            cl_int err = CL_SUCCESS;\n            cl_command_queue queue = clCreateCommandQueue(context, device, CL_QUEUE_PROFILING_ENABLE, &err);\n            TRACY_CL_CHECK_ERROR(err)\n            uint32_t dummyValue = 42;\n            cl_mem dummyBuffer = clCreateBuffer(context, CL_MEM_WRITE_ONLY, sizeof(uint32_t), nullptr, &err);\n            TRACY_CL_CHECK_ERROR(err)\n            cl_event writeBufferEvent;\n            TRACY_CL_CHECK_ERROR(clEnqueueWriteBuffer(queue, dummyBuffer, CL_FALSE, 0, sizeof(uint32_t), &dummyValue, 0, nullptr, &writeBufferEvent));\n            TRACY_CL_CHECK_ERROR(clWaitForEvents(1, &writeBufferEvent));\n\n            tcpu = Profiler::GetTime();\n\n            cl_int eventStatus;\n            TRACY_CL_CHECK_ERROR(clGetEventInfo(writeBufferEvent, CL_EVENT_COMMAND_EXECUTION_STATUS, sizeof(cl_int), &eventStatus, nullptr));\n            TRACY_CL_ASSERT(eventStatus == CL_COMPLETE);\n            TRACY_CL_CHECK_ERROR(clGetEventProfilingInfo(writeBufferEvent, CL_PROFILING_COMMAND_END, sizeof(cl_ulong), &tgpu, nullptr));\n            TRACY_CL_CHECK_ERROR(clReleaseEvent(writeBufferEvent));\n            TRACY_CL_CHECK_ERROR(clReleaseMemObject(dummyBuffer));\n            TRACY_CL_CHECK_ERROR(clReleaseCommandQueue(queue));\n\n            auto item = Profiler::QueueSerial();\n            MemWrite(&item->hdr.type, QueueType::GpuNewContext);\n            MemWrite(&item->gpuNewContext.cpuTime, tcpu);\n            MemWrite(&item->gpuNewContext.gpuTime, tgpu);\n            memset(&item->gpuNewContext.thread, 0, sizeof(item->gpuNewContext.thread));\n            MemWrite(&item->gpuNewContext.period, 1.0f);\n            MemWrite(&item->gpuNewContext.type, GpuContextType::OpenCL);\n            MemWrite(&item->gpuNewContext.context, (uint8_t) m_contextId);\n            MemWrite(&item->gpuNewContext.flags, (uint8_t)0);\n#ifdef TRACY_ON_DEMAND\n            GetProfiler().DeferItem(*item);\n#endif\n            Profiler::QueueSerialFinish();\n        }\n\n        void Name( const char* name, uint16_t len )\n        {\n            auto ptr = (char*)tracy_malloc( len );\n            memcpy( ptr, name, len );\n\n            auto item = Profiler::QueueSerial();\n            MemWrite( &item->hdr.type, QueueType::GpuContextName );\n            MemWrite( &item->gpuContextNameFat.context, (uint8_t)m_contextId );\n            MemWrite( &item->gpuContextNameFat.ptr, (uint64_t)ptr );\n            MemWrite( &item->gpuContextNameFat.size, len );\n#ifdef TRACY_ON_DEMAND\n            GetProfiler().DeferItem( *item );\n#endif\n            Profiler::QueueSerialFinish();\n        }\n\n        void Collect()\n        {\n            ZoneScopedC(Color::Red4);\n\n            if (m_tail == m_head) return;\n\n#ifdef TRACY_ON_DEMAND\n            if (!GetProfiler().IsConnected())\n            {\n                m_head = m_tail = 0;\n            }\n#endif\n\n            for (; m_tail != m_head; m_tail = (m_tail + 1) % QueryCount)\n            {\n                EventInfo eventInfo = GetQuery(m_tail);\n                cl_int eventStatus;\n                cl_int err = clGetEventInfo(eventInfo.event, CL_EVENT_COMMAND_EXECUTION_STATUS, sizeof(cl_int), &eventStatus, nullptr);\n                if (err != CL_SUCCESS)\n                {\n                    std::ostringstream oss;\n                    oss << \"clGetEventInfo falied with error code \" << err << \", on event \" << eventInfo.event << \", skipping...\";\n                    auto msg = oss.str();\n                    TracyMessage(msg.data(), msg.size());\n                    if (eventInfo.event == nullptr) {\n                        TracyMessageL(\"A TracyCLZone must be paird with a TracyCLZoneSetEvent, check your code!\");\n                    }\n                    assert(false && \"clGetEventInfo failed, maybe a TracyCLZone is not paired with TracyCLZoneSetEvent\");\n                    continue;\n                }\n                if (eventStatus != CL_COMPLETE) return;\n\n                cl_int eventInfoQuery = (eventInfo.phase == EventPhase::Begin)\n                    ? CL_PROFILING_COMMAND_START\n                    : CL_PROFILING_COMMAND_END;\n\n                cl_ulong eventTimeStamp = 0;\n                err = clGetEventProfilingInfo(eventInfo.event, eventInfoQuery, sizeof(cl_ulong), &eventTimeStamp, nullptr);\n                if (err == CL_PROFILING_INFO_NOT_AVAILABLE)\n                {\n                    TracyMessageL(\"command queue is not created with CL_QUEUE_PROFILING_ENABLE flag, check your code!\");\n                    assert(false && \"command queue is not created with CL_QUEUE_PROFILING_ENABLE flag\");\n                }\n                else\n                    TRACY_CL_CHECK_ERROR(err);\n\n                TRACY_CL_ASSERT(eventTimeStamp != 0);\n\n                auto item = Profiler::QueueSerial();\n                MemWrite(&item->hdr.type, QueueType::GpuTime);\n                MemWrite(&item->gpuTime.gpuTime, (int64_t)eventTimeStamp);\n                MemWrite(&item->gpuTime.queryId, (uint16_t)m_tail);\n                MemWrite(&item->gpuTime.context, m_contextId);\n                Profiler::QueueSerialFinish();\n\n                if (eventInfo.phase == EventPhase::End)\n                {\n                    // Done with the event, so release it\n                    TRACY_CL_CHECK_ERROR(clReleaseEvent(eventInfo.event));\n                }\n            }\n        }\n\n        tracy_force_inline uint8_t GetId() const\n        {\n            return m_contextId;\n        }\n\n        tracy_force_inline unsigned int NextQueryId(EventInfo eventInfo)\n        {\n            const auto id = m_head;\n            m_head = (m_head + 1) % QueryCount;\n            TRACY_CL_ASSERT(m_head != m_tail);\n            m_query[id] = eventInfo;\n            return id;\n        }\n\n        tracy_force_inline EventInfo& GetQuery(unsigned int id)\n        {\n            TRACY_CL_ASSERT(id < QueryCount);\n            return m_query[id];\n        }\n\n    private:\n\n        unsigned int m_contextId;\n\n        EventInfo m_query[QueryCount];\n        unsigned int m_head; // index at which a new event should be inserted\n        unsigned int m_tail; // oldest event\n\n    };\n\n    class OpenCLCtxScope {\n    public:\n        tracy_force_inline OpenCLCtxScope(OpenCLCtx* ctx, const SourceLocationData* srcLoc, bool is_active)\n#ifdef TRACY_ON_DEMAND\n            : m_active(is_active&& GetProfiler().IsConnected())\n#else\n            : m_active(is_active)\n#endif\n            , m_ctx(ctx)\n            , m_event(nullptr)\n        {\n            if (!m_active) return;\n\n            m_beginQueryId = ctx->NextQueryId(EventInfo{ nullptr, EventPhase::Begin });\n\n            auto item = Profiler::QueueSerial();\n            MemWrite(&item->hdr.type, QueueType::GpuZoneBeginSerial);\n            MemWrite(&item->gpuZoneBegin.cpuTime, Profiler::GetTime());\n            MemWrite(&item->gpuZoneBegin.srcloc, (uint64_t)srcLoc);\n            MemWrite(&item->gpuZoneBegin.thread, GetThreadHandle());\n            MemWrite(&item->gpuZoneBegin.queryId, (uint16_t)m_beginQueryId);\n            MemWrite(&item->gpuZoneBegin.context, ctx->GetId());\n            Profiler::QueueSerialFinish();\n        }\n\n        tracy_force_inline OpenCLCtxScope(OpenCLCtx* ctx, const SourceLocationData* srcLoc, int32_t depth, bool is_active)\n#ifdef TRACY_ON_DEMAND\n            : m_active(is_active&& GetProfiler().IsConnected())\n#else\n            : m_active(is_active)\n#endif\n            , m_ctx(ctx)\n            , m_event(nullptr)\n        {\n            if (!m_active) return;\n\n            m_beginQueryId = ctx->NextQueryId(EventInfo{ nullptr, EventPhase::Begin });\n\n            GetProfiler().SendCallstack(depth);\n\n            auto item = Profiler::QueueSerial();\n            MemWrite(&item->hdr.type, QueueType::GpuZoneBeginCallstackSerial);\n            MemWrite(&item->gpuZoneBegin.cpuTime, Profiler::GetTime());\n            MemWrite(&item->gpuZoneBegin.srcloc, (uint64_t)srcLoc);\n            MemWrite(&item->gpuZoneBegin.thread, GetThreadHandle());\n            MemWrite(&item->gpuZoneBegin.queryId, (uint16_t)m_beginQueryId);\n            MemWrite(&item->gpuZoneBegin.context, ctx->GetId());\n            Profiler::QueueSerialFinish();\n        }\n\n        tracy_force_inline OpenCLCtxScope(OpenCLCtx* ctx, uint32_t line, const char* source, size_t sourceSz, const char* function, size_t functionSz, const char* name, size_t nameSz, bool is_active)\n#ifdef TRACY_ON_DEMAND\n            : m_active(is_active && GetProfiler().IsConnected())\n#else\n            : m_active(is_active)\n#endif\n            , m_ctx(ctx)\n            , m_event(nullptr)\n        {\n            if (!m_active) return;\n\n            m_beginQueryId = ctx->NextQueryId(EventInfo{ nullptr, EventPhase::Begin });\n\n            const auto srcloc = Profiler::AllocSourceLocation( line, source, sourceSz, function, functionSz, name, nameSz );\n            auto item = Profiler::QueueSerial();\n            MemWrite( &item->hdr.type, QueueType::GpuZoneBeginAllocSrcLocSerial );\n            MemWrite(&item->gpuZoneBegin.cpuTime, Profiler::GetTime());\n            MemWrite(&item->gpuZoneBegin.srcloc, srcloc);\n            MemWrite(&item->gpuZoneBegin.thread, GetThreadHandle());\n            MemWrite(&item->gpuZoneBegin.queryId, (uint16_t)m_beginQueryId);\n            MemWrite(&item->gpuZoneBegin.context, ctx->GetId());\n            Profiler::QueueSerialFinish();\n        }\n\n        tracy_force_inline OpenCLCtxScope(OpenCLCtx* ctx, uint32_t line, const char* source, size_t sourceSz, const char* function, size_t functionSz, const char* name, size_t nameSz, int32_t depth, bool is_active)\n#ifdef TRACY_ON_DEMAND\n            : m_active(is_active && GetProfiler().IsConnected())\n#else\n            : m_active(is_active)\n#endif\n            , m_ctx(ctx)\n            , m_event(nullptr)\n        {\n            if (!m_active) return;\n\n            m_beginQueryId = ctx->NextQueryId(EventInfo{ nullptr, EventPhase::Begin });\n\n            const auto srcloc = Profiler::AllocSourceLocation( line, source, sourceSz, function, functionSz, name, nameSz );\n            auto item = Profiler::QueueSerialCallstack( Callstack( depth ) );\n            MemWrite(&item->hdr.type, QueueType::GpuZoneBeginAllocSrcLocCallstackSerial);\n            MemWrite(&item->gpuZoneBegin.cpuTime, Profiler::GetTime());\n            MemWrite(&item->gpuZoneBegin.srcloc, srcloc);\n            MemWrite(&item->gpuZoneBegin.thread, GetThreadHandle());\n            MemWrite(&item->gpuZoneBegin.queryId, (uint16_t)m_beginQueryId);\n            MemWrite(&item->gpuZoneBegin.context, ctx->GetId());\n            Profiler::QueueSerialFinish();\n        }\n\n        tracy_force_inline void SetEvent(cl_event event)\n        {\n            if (!m_active) return;\n            m_event = event;\n            TRACY_CL_CHECK_ERROR(clRetainEvent(m_event));\n            m_ctx->GetQuery(m_beginQueryId).event = m_event;\n        }\n\n        tracy_force_inline ~OpenCLCtxScope()\n        {\n            if (!m_active) return;\n            const auto queryId = m_ctx->NextQueryId(EventInfo{ m_event, EventPhase::End });\n\n            auto item = Profiler::QueueSerial();\n            MemWrite(&item->hdr.type, QueueType::GpuZoneEndSerial);\n            MemWrite(&item->gpuZoneEnd.cpuTime, Profiler::GetTime());\n            MemWrite(&item->gpuZoneEnd.thread, GetThreadHandle());\n            MemWrite(&item->gpuZoneEnd.queryId, (uint16_t)queryId);\n            MemWrite(&item->gpuZoneEnd.context, m_ctx->GetId());\n            Profiler::QueueSerialFinish();\n        }\n\n        const bool m_active;\n        OpenCLCtx* m_ctx;\n        cl_event m_event;\n        unsigned int m_beginQueryId;\n    };\n\n    static inline OpenCLCtx* CreateCLContext(cl_context context, cl_device_id device)\n    {\n        auto ctx = (OpenCLCtx*)tracy_malloc(sizeof(OpenCLCtx));\n        new (ctx) OpenCLCtx(context, device);\n        return ctx;\n    }\n\n    static inline void DestroyCLContext(OpenCLCtx* ctx)\n    {\n        ctx->~OpenCLCtx();\n        tracy_free(ctx);\n    }\n\n}  // namespace tracy\n\nusing TracyCLCtx = tracy::OpenCLCtx*;\n\n#define TracyCLContext(ctx, device) tracy::CreateCLContext(ctx, device);\n#define TracyCLDestroy(ctx) tracy::DestroyCLContext(ctx);\n#define TracyCLContextName(ctx, name, size) ctx->Name(name, size);\n#if defined TRACY_HAS_CALLSTACK && defined TRACY_CALLSTACK\n#  define TracyCLNamedZone(ctx, varname, name, active) static constexpr tracy::SourceLocationData TracyConcat(__tracy_gpu_source_location,TracyLine) { name, TracyFunction, TracyFile, (uint32_t)TracyLine, 0 }; tracy::OpenCLCtxScope varname(ctx, &TracyConcat(__tracy_gpu_source_location,TracyLine), TRACY_CALLSTACK, active );\n#  define TracyCLNamedZoneC(ctx, varname, name, color, active) static constexpr tracy::SourceLocationData TracyConcat(__tracy_gpu_source_location,TracyLine) { name, TracyFunction, TracyFile, (uint32_t)TracyLine, color }; tracy::OpenCLCtxScope varname(ctx, &TracyConcat(__tracy_gpu_source_location,TracyLine), TRACY_CALLSTACK, active );\n#  define TracyCLZone(ctx, name) TracyCLNamedZoneS(ctx, __tracy_gpu_zone, name, TRACY_CALLSTACK, true)\n#  define TracyCLZoneC(ctx, name, color) TracyCLNamedZoneCS(ctx, __tracy_gpu_zone, name, color, TRACY_CALLSTACK, true)\n#  define TracyCLZoneTransient( ctx, varname, name, active ) tracy::OpenCLCtxScope varname( ctx, TracyLine, TracyFile, strlen( TracyFile ), TracyFunction, strlen( TracyFunction ), name, strlen( name ), TRACY_CALLSTACK, active );\n#else\n#  define TracyCLNamedZone(ctx, varname, name, active) static constexpr tracy::SourceLocationData TracyConcat(__tracy_gpu_source_location,TracyLine){ name, TracyFunction, TracyFile, (uint32_t)TracyLine, 0 }; tracy::OpenCLCtxScope varname(ctx, &TracyConcat(__tracy_gpu_source_location,TracyLine), active);\n#  define TracyCLNamedZoneC(ctx, varname, name, color, active) static constexpr tracy::SourceLocationData TracyConcat(__tracy_gpu_source_location,TracyLine){ name, TracyFunction, TracyFile, (uint32_t)TracyLine, color }; tracy::OpenCLCtxScope varname(ctx, &TracyConcat(__tracy_gpu_source_location,TracyLine), active);\n#  define TracyCLZone(ctx, name) TracyCLNamedZone(ctx, __tracy_gpu_zone, name, true)\n#  define TracyCLZoneC(ctx, name, color) TracyCLNamedZoneC(ctx, __tracy_gpu_zone, name, color, true )\n#  define TracyCLZoneTransient( ctx, varname, name, active ) tracy::OpenCLCtxScope varname( ctx, TracyLine, TracyFile, strlen( TracyFile ), TracyFunction, strlen( TracyFunction ), name, strlen( name ), active );\n#endif\n\n#ifdef TRACY_HAS_CALLSTACK\n#  define TracyCLNamedZoneS(ctx, varname, name, depth, active) static constexpr tracy::SourceLocationData TracyConcat(__tracy_gpu_source_location,TracyLine){ name, TracyFunction, TracyFile, (uint32_t)TracyLine, 0 }; tracy::OpenCLCtxScope varname(ctx, &TracyConcat(__tracy_gpu_source_location,TracyLine), depth, active);\n#  define TracyCLNamedZoneCS(ctx, varname, name, color, depth, active) static constexpr tracy::SourceLocationData TracyConcat(__tracy_gpu_source_location,TracyLine){ name, TracyFunction, TracyFile, (uint32_t)TracyLine, color }; tracy::OpenCLCtxScope varname(ctx, &TracyConcat(__tracy_gpu_source_location,TracyLine), depth, active);\n#  define TracyCLZoneS(ctx, name, depth) TracyCLNamedZoneS(ctx, __tracy_gpu_zone, name, depth, true)\n#  define TracyCLZoneCS(ctx, name, color, depth) TracyCLNamedZoneCS(ctx, __tracy_gpu_zone, name, color, depth, true)\n#  define TracyCLZoneTransientS( ctx, varname, name, depth, active ) tracy::OpenCLCtxScope varname( ctx, TracyLine, TracyFile, strlen( TracyFile ), TracyFunction, strlen( TracyFunction ), name, strlen( name ), depth, active );\n#else\n#  define TracyCLNamedZoneS(ctx, varname, name, depth, active) TracyCLNamedZone(ctx, varname, name, active)\n#  define TracyCLNamedZoneCS(ctx, varname, name, color, depth, active) TracyCLNamedZoneC(ctx, varname, name, color, active)\n#  define TracyCLZoneS(ctx, name, depth) TracyCLZone(ctx, name)\n#  define TracyCLZoneCS(ctx, name, color, depth) TracyCLZoneC(ctx, name, color)\n#  define TracyCLZoneTransientS( ctx, varname, name, depth, active ) TracyCLZoneTransient( ctx, varname, name, active )\n#endif\n\n#define TracyCLNamedZoneSetEvent(varname, event) varname.SetEvent(event)\n#define TracyCLZoneSetEvent(event) __tracy_gpu_zone.SetEvent(event)\n\n#define TracyCLCollect(ctx) ctx->Collect()\n\n#endif\n\n#endif\n"
  },
  {
    "path": "tracy-client-sys/tracy/tracy/TracyOpenGL.hpp",
    "content": "#ifndef __TRACYOPENGL_HPP__\n#define __TRACYOPENGL_HPP__\n\n#if !defined TRACY_ENABLE || defined __APPLE__\n\n#define TracyGpuContext\n#define TracyGpuContextName(x,y)\n#define TracyGpuNamedZone(x,y,z)\n#define TracyGpuNamedZoneC(x,y,z,w)\n#define TracyGpuZone(x)\n#define TracyGpuZoneC(x,y)\n#define TracyGpuZoneTransient(x,y,z)\n#define TracyGpuCollect\n\n#define TracyGpuNamedZoneS(x,y,z,w)\n#define TracyGpuNamedZoneCS(x,y,z,w,a)\n#define TracyGpuZoneS(x,y)\n#define TracyGpuZoneCS(x,y,z)\n#define TracyGpuZoneTransientS(x,y,z,w)\n\nnamespace tracy\n{\nstruct SourceLocationData;\nclass GpuCtxScope\n{\npublic:\n    GpuCtxScope( const SourceLocationData*, bool ) {}\n    GpuCtxScope( const SourceLocationData*, int32_t, bool ) {}\n};\n}\n\n#else\n\n#include <atomic>\n#include <assert.h>\n#include <stdlib.h>\n\n#include \"Tracy.hpp\"\n#include \"../client/TracyProfiler.hpp\"\n#include \"../client/TracyCallstack.hpp\"\n#include \"../common/TracyAlign.hpp\"\n#include \"../common/TracyAlloc.hpp\"\n\n#if !defined GL_TIMESTAMP && defined GL_TIMESTAMP_EXT\n#  define GL_TIMESTAMP GL_TIMESTAMP_EXT\n#  define GL_QUERY_COUNTER_BITS GL_QUERY_COUNTER_BITS_EXT\n#  define glGetQueryObjectiv glGetQueryObjectivEXT\n#  define glGetQueryObjectui64v glGetQueryObjectui64vEXT\n#  define glQueryCounter glQueryCounterEXT\n#endif\n\n#define TracyGpuContext tracy::GetGpuCtx().ptr = (tracy::GpuCtx*)tracy::tracy_malloc( sizeof( tracy::GpuCtx ) ); new(tracy::GetGpuCtx().ptr) tracy::GpuCtx;\n#define TracyGpuContextName( name, size ) tracy::GetGpuCtx().ptr->Name( name, size );\n#if defined TRACY_HAS_CALLSTACK && defined TRACY_CALLSTACK\n#  define TracyGpuNamedZone( varname, name, active ) static constexpr tracy::SourceLocationData TracyConcat(__tracy_gpu_source_location,TracyLine) { name, TracyFunction,  TracyFile, (uint32_t)TracyLine, 0 }; tracy::GpuCtxScope varname( &TracyConcat(__tracy_gpu_source_location,TracyLine), TRACY_CALLSTACK, active );\n#  define TracyGpuNamedZoneC( varname, name, color, active ) static constexpr tracy::SourceLocationData TracyConcat(__tracy_gpu_source_location,TracyLine) { name, TracyFunction,  TracyFile, (uint32_t)TracyLine, color }; tracy::GpuCtxScope varname( &TracyConcat(__tracy_gpu_source_location,TracyLine), TRACY_CALLSTACK, active );\n#  define TracyGpuZone( name ) TracyGpuNamedZoneS( ___tracy_gpu_zone, name, TRACY_CALLSTACK, true )\n#  define TracyGpuZoneC( name, color ) TracyGpuNamedZoneCS( ___tracy_gpu_zone, name, color, TRACY_CALLSTACK, true )\n#  define TracyGpuZoneTransient( varname, name, active ) tracy::GpuCtxScope varname( TracyLine, TracyFile, strlen( TracyFile ), TracyFunction, strlen( TracyFunction ), name, strlen( name ), TRACY_CALLSTACK, active );\n#else\n#  define TracyGpuNamedZone( varname, name, active ) static constexpr tracy::SourceLocationData TracyConcat(__tracy_gpu_source_location,TracyLine) { name, TracyFunction,  TracyFile, (uint32_t)TracyLine, 0 }; tracy::GpuCtxScope varname( &TracyConcat(__tracy_gpu_source_location,TracyLine), active );\n#  define TracyGpuNamedZoneC( varname, name, color, active ) static constexpr tracy::SourceLocationData TracyConcat(__tracy_gpu_source_location,TracyLine) { name, TracyFunction,  TracyFile, (uint32_t)TracyLine, color }; tracy::GpuCtxScope varname( &TracyConcat(__tracy_gpu_source_location,TracyLine), active );\n#  define TracyGpuZone( name ) TracyGpuNamedZone( ___tracy_gpu_zone, name, true )\n#  define TracyGpuZoneC( name, color ) TracyGpuNamedZoneC( ___tracy_gpu_zone, name, color, true )\n#  define TracyGpuZoneTransient( varname, name, active ) tracy::GpuCtxScope varname( TracyLine, TracyFile, strlen( TracyFile ), TracyFunction, strlen( TracyFunction ), name, strlen( name ), active );\n#endif\n#define TracyGpuCollect tracy::GetGpuCtx().ptr->Collect();\n\n#ifdef TRACY_HAS_CALLSTACK\n#  define TracyGpuNamedZoneS( varname, name, depth, active ) static constexpr tracy::SourceLocationData TracyConcat(__tracy_gpu_source_location,TracyLine) { name, TracyFunction,  TracyFile, (uint32_t)TracyLine, 0 }; tracy::GpuCtxScope varname( &TracyConcat(__tracy_gpu_source_location,TracyLine), depth, active );\n#  define TracyGpuNamedZoneCS( varname, name, color, depth, active ) static constexpr tracy::SourceLocationData TracyConcat(__tracy_gpu_source_location,TracyLine) { name, TracyFunction,  TracyFile, (uint32_t)TracyLine, color }; tracy::GpuCtxScope varname( &TracyConcat(__tracy_gpu_source_location,TracyLine), depth, active );\n#  define TracyGpuZoneS( name, depth ) TracyGpuNamedZoneS( ___tracy_gpu_zone, name, depth, true )\n#  define TracyGpuZoneCS( name, color, depth ) TracyGpuNamedZoneCS( ___tracy_gpu_zone, name, color, depth, true )\n#  define TracyGpuZoneTransientS( varname, name, depth, active ) tracy::GpuCtxScope varname( TracyLine, TracyFile, strlen( TracyFile ), TracyFunction, strlen( TracyFunction ), name, strlen( name ), depth, active );\n#else\n#  define TracyGpuNamedZoneS( varname, name, depth, active ) TracyGpuNamedZone( varname, name, active )\n#  define TracyGpuNamedZoneCS( varname, name, color, depth, active ) TracyGpuNamedZoneC( varname, name, color, active )\n#  define TracyGpuZoneS( name, depth ) TracyGpuZone( name )\n#  define TracyGpuZoneCS( name, color, depth ) TracyGpuZoneC( name, color )\n#  define TracyGpuZoneTransientS( varname, name, depth, active ) TracyGpuZoneTransient( varname, name, active )\n#endif\n\nnamespace tracy\n{\n\nclass GpuCtx\n{\n    friend class GpuCtxScope;\n\n    enum { QueryCount = 64 * 1024 };\n\npublic:\n    GpuCtx()\n        : m_context( GetGpuCtxCounter().fetch_add( 1, std::memory_order_relaxed ) )\n        , m_head( 0 )\n        , m_tail( 0 )\n    {\n        assert( m_context != 255 );\n\n        glGenQueries( QueryCount, m_query );\n\n        int64_t tgpu;\n        glGetInteger64v( GL_TIMESTAMP, &tgpu );\n        int64_t tcpu = Profiler::GetTime();\n\n        GLint bits;\n        glGetQueryiv( GL_TIMESTAMP, GL_QUERY_COUNTER_BITS, &bits );\n\n        const float period = 1.f;\n        const auto thread = GetThreadHandle();\n        TracyLfqPrepare( QueueType::GpuNewContext );\n        MemWrite( &item->gpuNewContext.cpuTime, tcpu );\n        MemWrite( &item->gpuNewContext.gpuTime, tgpu );\n        MemWrite( &item->gpuNewContext.thread, thread );\n        MemWrite( &item->gpuNewContext.period, period );\n        MemWrite( &item->gpuNewContext.context, m_context );\n        MemWrite( &item->gpuNewContext.flags, uint8_t( 0 ) );\n        MemWrite( &item->gpuNewContext.type, GpuContextType::OpenGl );\n\n#ifdef TRACY_ON_DEMAND\n        GetProfiler().DeferItem( *item );\n#endif\n\n        TracyLfqCommit;\n    }\n\n    void Name( const char* name, uint16_t len )\n    {\n        auto ptr = (char*)tracy_malloc( len );\n        memcpy( ptr, name, len );\n\n        TracyLfqPrepare( QueueType::GpuContextName );\n        MemWrite( &item->gpuContextNameFat.context, m_context );\n        MemWrite( &item->gpuContextNameFat.ptr, (uint64_t)ptr );\n        MemWrite( &item->gpuContextNameFat.size, len );\n#ifdef TRACY_ON_DEMAND\n        GetProfiler().DeferItem( *item );\n#endif\n        TracyLfqCommit;\n    }\n\n    void Collect()\n    {\n        ZoneScopedC( Color::Red4 );\n\n        if( m_tail == m_head ) return;\n\n#ifdef TRACY_ON_DEMAND\n        if( !GetProfiler().IsConnected() )\n        {\n            m_head = m_tail = 0;\n            return;\n        }\n#endif\n\n        while( m_tail != m_head )\n        {\n            GLint available;\n            glGetQueryObjectiv( m_query[m_tail], GL_QUERY_RESULT_AVAILABLE, &available );\n            if( !available ) return;\n\n            uint64_t time;\n            glGetQueryObjectui64v( m_query[m_tail], GL_QUERY_RESULT, &time );\n\n            TracyLfqPrepare( QueueType::GpuTime );\n            MemWrite( &item->gpuTime.gpuTime, (int64_t)time );\n            MemWrite( &item->gpuTime.queryId, (uint16_t)m_tail );\n            MemWrite( &item->gpuTime.context, m_context );\n            TracyLfqCommit;\n\n            m_tail = ( m_tail + 1 ) % QueryCount;\n        }\n    }\n\nprivate:\n    tracy_force_inline unsigned int NextQueryId()\n    {\n        const auto id = m_head;\n        m_head = ( m_head + 1 ) % QueryCount;\n        assert( m_head != m_tail );\n        return id;\n    }\n\n    tracy_force_inline unsigned int TranslateOpenGlQueryId( unsigned int id )\n    {\n        return m_query[id];\n    }\n\n    tracy_force_inline uint8_t GetId() const\n    {\n        return m_context;\n    }\n\n    unsigned int m_query[QueryCount];\n    uint8_t m_context;\n\n    unsigned int m_head;\n    unsigned int m_tail;\n};\n\nclass GpuCtxScope\n{\npublic:\n    tracy_force_inline GpuCtxScope( const SourceLocationData* srcloc, bool is_active )\n#ifdef TRACY_ON_DEMAND\n        : m_active( is_active && GetProfiler().IsConnected() )\n#else\n        : m_active( is_active )\n#endif\n    {\n        if( !m_active ) return;\n\n        const auto queryId = GetGpuCtx().ptr->NextQueryId();\n        glQueryCounter( GetGpuCtx().ptr->TranslateOpenGlQueryId( queryId ), GL_TIMESTAMP );\n\n        TracyLfqPrepare( QueueType::GpuZoneBegin );\n        MemWrite( &item->gpuZoneBegin.cpuTime, Profiler::GetTime() );\n        memset( &item->gpuZoneBegin.thread, 0, sizeof( item->gpuZoneBegin.thread ) );\n        MemWrite( &item->gpuZoneBegin.queryId, uint16_t( queryId ) );\n        MemWrite( &item->gpuZoneBegin.context, GetGpuCtx().ptr->GetId() );\n        MemWrite( &item->gpuZoneBegin.srcloc, (uint64_t)srcloc );\n        TracyLfqCommit;\n    }\n\n    tracy_force_inline GpuCtxScope( const SourceLocationData* srcloc, int32_t depth, bool is_active )\n#ifdef TRACY_ON_DEMAND\n        : m_active( is_active && GetProfiler().IsConnected() )\n#else\n        : m_active( is_active )\n#endif\n    {\n        if( !m_active ) return;\n\n        const auto queryId = GetGpuCtx().ptr->NextQueryId();\n        glQueryCounter( GetGpuCtx().ptr->TranslateOpenGlQueryId( queryId ), GL_TIMESTAMP );\n\n#ifdef TRACY_FIBERS\n        TracyLfqPrepare( QueueType::GpuZoneBegin );\n        memset( &item->gpuZoneBegin.thread, 0, sizeof( item->gpuZoneBegin.thread ) );\n#else\n        GetProfiler().SendCallstack( depth );\n        TracyLfqPrepare( QueueType::GpuZoneBeginCallstack );\n        MemWrite( &item->gpuZoneBegin.thread, GetThreadHandle() );\n#endif\n        MemWrite( &item->gpuZoneBegin.cpuTime, Profiler::GetTime() );\n        MemWrite( &item->gpuZoneBegin.queryId, uint16_t( queryId ) );\n        MemWrite( &item->gpuZoneBegin.context, GetGpuCtx().ptr->GetId() );\n        MemWrite( &item->gpuZoneBegin.srcloc, (uint64_t)srcloc );\n        TracyLfqCommit;\n    }\n\n    tracy_force_inline GpuCtxScope( uint32_t line, const char* source, size_t sourceSz, const char* function, size_t functionSz, const char* name, size_t nameSz, bool is_active )\n#ifdef TRACY_ON_DEMAND\n        : m_active( is_active && GetProfiler().IsConnected() )\n#else\n        : m_active( is_active )\n#endif\n    {\n        if( !m_active ) return;\n\n        const auto queryId = GetGpuCtx().ptr->NextQueryId();\n        glQueryCounter( GetGpuCtx().ptr->TranslateOpenGlQueryId( queryId ), GL_TIMESTAMP );\n\n        TracyLfqPrepare( QueueType::GpuZoneBeginAllocSrcLoc );\n        const auto srcloc = Profiler::AllocSourceLocation( line, source, sourceSz, function, functionSz, name, nameSz );\n        MemWrite( &item->gpuZoneBegin.cpuTime, Profiler::GetTime() );\n        memset( &item->gpuZoneBegin.thread, 0, sizeof( item->gpuZoneBegin.thread ) );\n        MemWrite( &item->gpuZoneBegin.queryId, uint16_t( queryId ) );\n        MemWrite( &item->gpuZoneBegin.context, GetGpuCtx().ptr->GetId() );\n        MemWrite( &item->gpuZoneBegin.srcloc, (uint64_t)srcloc );\n        TracyLfqCommit;\n    }\n\n    tracy_force_inline GpuCtxScope( uint32_t line, const char* source, size_t sourceSz, const char* function, size_t functionSz, const char* name, size_t nameSz, int32_t depth, bool is_active )\n#ifdef TRACY_ON_DEMAND\n        : m_active( is_active && GetProfiler().IsConnected() )\n#else\n        : m_active( is_active )\n#endif\n    {\n        if( !m_active ) return;\n\n        const auto queryId = GetGpuCtx().ptr->NextQueryId();\n        glQueryCounter( GetGpuCtx().ptr->TranslateOpenGlQueryId( queryId ), GL_TIMESTAMP );\n\n#ifdef TRACY_FIBERS\n        TracyLfqPrepare( QueueType::GpuZoneBeginAllocSrcLoc );\n        memset( &item->gpuZoneBegin.thread, 0, sizeof( item->gpuZoneBegin.thread ) );\n#else\n        GetProfiler().SendCallstack( depth );\n        TracyLfqPrepare( QueueType::GpuZoneBeginAllocSrcLocCallstack );\n        MemWrite( &item->gpuZoneBegin.thread, GetThreadHandle() );\n#endif\n        const auto srcloc = Profiler::AllocSourceLocation( line, source, sourceSz, function, functionSz, name, nameSz );\n        MemWrite( &item->gpuZoneBegin.cpuTime, Profiler::GetTime() );\n        MemWrite( &item->gpuZoneBegin.queryId, uint16_t( queryId ) );\n        MemWrite( &item->gpuZoneBegin.context, GetGpuCtx().ptr->GetId() );\n        MemWrite( &item->gpuZoneBegin.srcloc, (uint64_t)srcloc );\n        TracyLfqCommit;\n    }\n\n    tracy_force_inline ~GpuCtxScope()\n    {\n        if( !m_active ) return;\n\n        const auto queryId = GetGpuCtx().ptr->NextQueryId();\n        glQueryCounter( GetGpuCtx().ptr->TranslateOpenGlQueryId( queryId ), GL_TIMESTAMP );\n\n        TracyLfqPrepare( QueueType::GpuZoneEnd );\n        MemWrite( &item->gpuZoneEnd.cpuTime, Profiler::GetTime() );\n        memset( &item->gpuZoneEnd.thread, 0, sizeof( item->gpuZoneEnd.thread ) );\n        MemWrite( &item->gpuZoneEnd.queryId, uint16_t( queryId ) );\n        MemWrite( &item->gpuZoneEnd.context, GetGpuCtx().ptr->GetId() );\n        TracyLfqCommit;\n    }\n\nprivate:\n    const bool m_active;\n};\n\n}\n\n#endif\n\n#endif\n"
  },
  {
    "path": "tracy-client-sys/tracy/tracy/TracyVulkan.hpp",
    "content": "#ifndef __TRACYVULKAN_HPP__\n#define __TRACYVULKAN_HPP__\n\n#if !defined TRACY_ENABLE\n\n#define TracyVkContext(x,y,z,w) nullptr\n#define TracyVkContextCalibrated(x,y,z,w,a,b) nullptr\n#if defined VK_EXT_host_query_reset\n#define TracyVkContextHostCalibrated(x,y,z,w,a) nullptr\n#endif\n#define TracyVkDestroy(x)\n#define TracyVkContextName(c,x,y)\n#define TracyVkNamedZone(c,x,y,z,w)\n#define TracyVkNamedZoneC(c,x,y,z,w,a)\n#define TracyVkZone(c,x,y)\n#define TracyVkZoneC(c,x,y,z)\n#define TracyVkZoneTransient(c,x,y,z,w)\n#define TracyVkCollect(c,x)\n#define TracyVkCollectHost(c)\n\n#define TracyVkNamedZoneS(c,x,y,z,w,a)\n#define TracyVkNamedZoneCS(c,x,y,z,w,v,a)\n#define TracyVkZoneS(c,x,y,z)\n#define TracyVkZoneCS(c,x,y,z,w)\n#define TracyVkZoneTransientS(c,x,y,z,w,a)\n\nnamespace tracy\n{\nclass VkCtxScope {};\n}\n\nusing TracyVkCtx = void*;\n\n#else\n\n#if !defined VK_NULL_HANDLE\n#  error \"You must include Vulkan headers before including TracyVulkan.hpp\"\n#endif\n\n#include <assert.h>\n#include <stdlib.h>\n#include \"Tracy.hpp\"\n#include \"../client/TracyProfiler.hpp\"\n#include \"../client/TracyCallstack.hpp\"\n\n#include <atomic>\n\nnamespace tracy\n{\n\n#if defined TRACY_VK_USE_SYMBOL_TABLE\n#define LoadVkDeviceCoreSymbols(Operation) \\\n    Operation(vkBeginCommandBuffer) \\\n    Operation(vkCmdResetQueryPool) \\\n    Operation(vkCmdWriteTimestamp) \\\n    Operation(vkCreateQueryPool) \\\n    Operation(vkDestroyQueryPool) \\\n    Operation(vkEndCommandBuffer) \\\n    Operation(vkGetQueryPoolResults) \\\n    Operation(vkQueueSubmit) \\\n    Operation(vkQueueWaitIdle) \\\n    Operation(vkResetQueryPool)\n\n#define LoadVkDeviceExtensionSymbols(Operation) \\\n    Operation(vkGetCalibratedTimestampsEXT)\n\n#define LoadVkInstanceExtensionSymbols(Operation) \\\n    Operation(vkGetPhysicalDeviceCalibrateableTimeDomainsEXT)\n\n#define LoadVkInstanceCoreSymbols(Operation) \\\n    Operation(vkGetPhysicalDeviceProperties)\n\nstruct VkSymbolTable\n{\n#define MAKE_PFN(name) PFN_##name name;\n    LoadVkDeviceCoreSymbols(MAKE_PFN)\n    LoadVkDeviceExtensionSymbols(MAKE_PFN)\n    LoadVkInstanceExtensionSymbols(MAKE_PFN)\n    LoadVkInstanceCoreSymbols(MAKE_PFN)\n#undef MAKE_PFN\n};\n\n#define VK_FUNCTION_WRAPPER(callSignature) m_symbols.callSignature\n#define CONTEXT_VK_FUNCTION_WRAPPER(callSignature) m_ctx->m_symbols.callSignature\n#else\n#define VK_FUNCTION_WRAPPER(callSignature) callSignature\n#define CONTEXT_VK_FUNCTION_WRAPPER(callSignature) callSignature\n#endif\n\nclass VkCtx\n{\n    friend class VkCtxScope;\n\n    enum { QueryCount = 64 * 1024 };\n\npublic:\n#if defined TRACY_VK_USE_SYMBOL_TABLE\n    VkCtx( VkInstance instance, VkPhysicalDevice physdev, VkDevice device, VkQueue queue, VkCommandBuffer cmdbuf, PFN_vkGetInstanceProcAddr instanceProcAddr, PFN_vkGetDeviceProcAddr deviceProcAddr, bool calibrated )\n#else\n    VkCtx( VkPhysicalDevice physdev, VkDevice device, VkQueue queue, VkCommandBuffer cmdbuf, PFN_vkGetPhysicalDeviceCalibrateableTimeDomainsEXT vkGetPhysicalDeviceCalibrateableTimeDomainsEXT, PFN_vkGetCalibratedTimestampsEXT vkGetCalibratedTimestampsEXT)\n#endif\n        : m_device( device )\n        , m_timeDomain( VK_TIME_DOMAIN_DEVICE_EXT )\n        , m_context( GetGpuCtxCounter().fetch_add( 1, std::memory_order_relaxed ) )\n        , m_head( 0 )\n        , m_tail( 0 )\n        , m_oldCnt( 0 )\n        , m_queryCount( QueryCount )\n#if !defined TRACY_VK_USE_SYMBOL_TABLE\n        , m_vkGetCalibratedTimestampsEXT( vkGetCalibratedTimestampsEXT )\n#endif\n    {\n        assert( m_context != 255 );\n\n#if defined TRACY_VK_USE_SYMBOL_TABLE\n        PopulateSymbolTable(instance, instanceProcAddr, deviceProcAddr);\n        if ( calibrated )\n        {\n            m_vkGetCalibratedTimestampsEXT = m_symbols.vkGetCalibratedTimestampsEXT;\n        }\n\n#endif\n\n        if( VK_FUNCTION_WRAPPER( vkGetPhysicalDeviceCalibrateableTimeDomainsEXT ) && m_vkGetCalibratedTimestampsEXT )\n        {\n            FindAvailableTimeDomains( physdev, VK_FUNCTION_WRAPPER( vkGetPhysicalDeviceCalibrateableTimeDomainsEXT ) );\n        }\n\n        CreateQueryPool();\n\n        VkCommandBufferBeginInfo beginInfo = {};\n        beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;\n        beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;\n\n        VkSubmitInfo submitInfo = {};\n        submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;\n        submitInfo.commandBufferCount = 1;\n        submitInfo.pCommandBuffers = &cmdbuf;\n\n        VK_FUNCTION_WRAPPER( vkBeginCommandBuffer( cmdbuf, &beginInfo ) );\n        VK_FUNCTION_WRAPPER( vkCmdResetQueryPool( cmdbuf, m_query, 0, m_queryCount ) );\n        VK_FUNCTION_WRAPPER( vkEndCommandBuffer( cmdbuf ) );\n        VK_FUNCTION_WRAPPER( vkQueueSubmit( queue, 1, &submitInfo, VK_NULL_HANDLE ) );\n        VK_FUNCTION_WRAPPER( vkQueueWaitIdle( queue ) );\n\n        int64_t tcpu, tgpu;\n        if( m_timeDomain == VK_TIME_DOMAIN_DEVICE_EXT )\n        {\n            VK_FUNCTION_WRAPPER( vkBeginCommandBuffer( cmdbuf, &beginInfo ) );\n            VK_FUNCTION_WRAPPER( vkCmdWriteTimestamp( cmdbuf, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, m_query, 0 ) );\n            VK_FUNCTION_WRAPPER( vkEndCommandBuffer( cmdbuf ) );\n            VK_FUNCTION_WRAPPER( vkQueueSubmit( queue, 1, &submitInfo, VK_NULL_HANDLE ) );\n            VK_FUNCTION_WRAPPER( vkQueueWaitIdle( queue ) );\n\n            tcpu = Profiler::GetTime();\n            VK_FUNCTION_WRAPPER( vkGetQueryPoolResults( device, m_query, 0, 1, sizeof( tgpu ), &tgpu, sizeof( tgpu ), VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT ) );\n\n            VK_FUNCTION_WRAPPER( vkBeginCommandBuffer( cmdbuf, &beginInfo ) );\n            VK_FUNCTION_WRAPPER( vkCmdResetQueryPool( cmdbuf, m_query, 0, 1 ) );\n            VK_FUNCTION_WRAPPER( vkEndCommandBuffer( cmdbuf ) );\n            VK_FUNCTION_WRAPPER( vkQueueSubmit( queue, 1, &submitInfo, VK_NULL_HANDLE ) );\n            VK_FUNCTION_WRAPPER( vkQueueWaitIdle( queue ) );\n        }\n        else\n        {\n            FindCalibratedTimestampDeviation();\n            Calibrate( device, m_prevCalibration, tgpu );\n            tcpu = Profiler::GetTime();\n        }\n\n        WriteInitialItem( physdev, tcpu, tgpu );\n\n        m_res = (int64_t*)tracy_malloc( sizeof( int64_t ) * m_queryCount );\n    }\n\n#if defined VK_EXT_host_query_reset\n    /**\n     * This alternative constructor does not use command buffers and instead uses functionality from\n     * VK_EXT_host_query_reset (core with 1.2 and non-optional) and VK_EXT_calibrated_timestamps. This requires\n     * the physical device to have another time domain apart from DEVICE to be calibrateable.\n     */\n#if defined TRACY_VK_USE_SYMBOL_TABLE\n    VkCtx( VkInstance instance, VkPhysicalDevice physdev, VkDevice device, PFN_vkGetInstanceProcAddr instanceProcAddr, PFN_vkGetDeviceProcAddr deviceProcAddr )\n#else\n    VkCtx( VkPhysicalDevice physdev, VkDevice device, PFN_vkResetQueryPoolEXT vkResetQueryPool, PFN_vkGetPhysicalDeviceCalibrateableTimeDomainsEXT vkGetPhysicalDeviceCalibrateableTimeDomainsEXT, PFN_vkGetCalibratedTimestampsEXT vkGetCalibratedTimestampsEXT )\n#endif\n        : m_device( device )\n        , m_timeDomain( VK_TIME_DOMAIN_DEVICE_EXT )\n        , m_context( GetGpuCtxCounter().fetch_add(1, std::memory_order_relaxed) )\n        , m_head( 0 )\n        , m_tail( 0 )\n        , m_oldCnt( 0 )\n        , m_queryCount( QueryCount )\n#if !defined TRACY_VK_USE_SYMBOL_TABLE\n        , m_vkGetCalibratedTimestampsEXT( vkGetCalibratedTimestampsEXT )\n#endif\n    {\n        assert( m_context != 255);\n\n#if defined TRACY_VK_USE_SYMBOL_TABLE\n        PopulateSymbolTable(instance, instanceProcAddr, deviceProcAddr);\n        m_vkGetCalibratedTimestampsEXT = m_symbols.vkGetCalibratedTimestampsEXT;\n#endif\n\n        assert( VK_FUNCTION_WRAPPER( vkResetQueryPool ) != nullptr );\n        assert( VK_FUNCTION_WRAPPER( vkGetPhysicalDeviceCalibrateableTimeDomainsEXT ) != nullptr );\n        assert( VK_FUNCTION_WRAPPER( vkGetCalibratedTimestampsEXT ) != nullptr );\n\n        FindAvailableTimeDomains( physdev, VK_FUNCTION_WRAPPER( vkGetPhysicalDeviceCalibrateableTimeDomainsEXT ) );\n\n        // We require a host time domain to be available to properly calibrate.\n        FindCalibratedTimestampDeviation();\n        int64_t tgpu;\n        Calibrate( device, m_prevCalibration, tgpu );\n        int64_t tcpu = Profiler::GetTime();\n\n        CreateQueryPool();\n        VK_FUNCTION_WRAPPER( vkResetQueryPool( device, m_query, 0, m_queryCount ) );\n\n        WriteInitialItem( physdev, tcpu, tgpu );\n\n        // We need the buffer to be twice as large for availability values\n        size_t resSize = sizeof( int64_t ) * m_queryCount * 2;\n        m_res = (int64_t*)tracy_malloc( resSize );\n    }\n#endif\n\n    ~VkCtx()\n    {\n        tracy_free( m_res );\n        VK_FUNCTION_WRAPPER( vkDestroyQueryPool( m_device, m_query, nullptr ) );\n    }\n\n    void Name( const char* name, uint16_t len )\n    {\n        auto ptr = (char*)tracy_malloc( len );\n        memcpy( ptr, name, len );\n\n        auto item = Profiler::QueueSerial();\n        MemWrite( &item->hdr.type, QueueType::GpuContextName );\n        MemWrite( &item->gpuContextNameFat.context, m_context );\n        MemWrite( &item->gpuContextNameFat.ptr, (uint64_t)ptr );\n        MemWrite( &item->gpuContextNameFat.size, len );\n#ifdef TRACY_ON_DEMAND\n        GetProfiler().DeferItem( *item );\n#endif\n        Profiler::QueueSerialFinish();\n    }\n\n    void Collect( VkCommandBuffer cmdbuf )\n    {\n        ZoneScopedC( Color::Red4 );\n\n        const uint64_t head = m_head.load(std::memory_order_relaxed);\n        if( m_tail == head ) return;\n\n#ifdef TRACY_ON_DEMAND\n        if( !GetProfiler().IsConnected() )\n        {\n            cmdbuf ?\n                VK_FUNCTION_WRAPPER( vkCmdResetQueryPool( cmdbuf, m_query, 0, m_queryCount ) ) :\n                VK_FUNCTION_WRAPPER( vkResetQueryPool( m_device, m_query, 0, m_queryCount ) );\n            m_tail = head;\n            m_oldCnt = 0;\n            int64_t tgpu;\n            if( m_timeDomain != VK_TIME_DOMAIN_DEVICE_EXT ) Calibrate( m_device, m_prevCalibration, tgpu );\n            return;\n        }\n#endif\n        assert( head > m_tail );\n\n        const unsigned int wrappedTail = (unsigned int)( m_tail % m_queryCount );\n\n        unsigned int cnt;\n        if( m_oldCnt != 0 )\n        {\n            cnt = m_oldCnt;\n            m_oldCnt = 0;\n        }\n        else\n        {\n            cnt = (unsigned int)( head - m_tail );\n            assert( cnt <= m_queryCount );\n            if( wrappedTail + cnt > m_queryCount )\n            {\n                cnt = m_queryCount - wrappedTail;\n            }\n        }\n\n\n        VK_FUNCTION_WRAPPER( vkGetQueryPoolResults( m_device, m_query, wrappedTail, cnt, sizeof( int64_t ) * m_queryCount * 2, m_res, sizeof( int64_t ) * 2, VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WITH_AVAILABILITY_BIT ) );\n\n        for( unsigned int idx=0; idx<cnt; idx++ )\n        {\n            int64_t avail = m_res[idx * 2 + 1];\n            if( avail == 0 )\n            {\n                m_oldCnt = cnt - idx;\n                cnt = idx;\n\n                break;\n            }\n\n            auto item = Profiler::QueueSerial();\n            MemWrite( &item->hdr.type, QueueType::GpuTime );\n            MemWrite( &item->gpuTime.gpuTime, m_res[idx * 2] );\n            MemWrite( &item->gpuTime.queryId, uint16_t( wrappedTail + idx ) );\n            MemWrite( &item->gpuTime.context, m_context );\n            Profiler::QueueSerialFinish();\n        }\n\n        if( m_timeDomain != VK_TIME_DOMAIN_DEVICE_EXT )\n        {\n            int64_t tgpu, tcpu;\n            Calibrate( m_device, tcpu, tgpu );\n            const auto refCpu = Profiler::GetTime();\n            const auto delta = tcpu - m_prevCalibration;\n            if( delta > 0 )\n            {\n                m_prevCalibration = tcpu;\n                auto item = Profiler::QueueSerial();\n                MemWrite( &item->hdr.type, QueueType::GpuCalibration );\n                MemWrite( &item->gpuCalibration.gpuTime, tgpu );\n                MemWrite( &item->gpuCalibration.cpuTime, refCpu );\n                MemWrite( &item->gpuCalibration.cpuDelta, delta );\n                MemWrite( &item->gpuCalibration.context, m_context );\n                Profiler::QueueSerialFinish();\n            }\n        }\n\n        cmdbuf ?\n            VK_FUNCTION_WRAPPER( vkCmdResetQueryPool( cmdbuf, m_query, wrappedTail, cnt ) ) :\n            VK_FUNCTION_WRAPPER( vkResetQueryPool( m_device, m_query, wrappedTail, cnt ) );\n\n        m_tail += cnt;\n    }\n\n    tracy_force_inline unsigned int NextQueryId()\n    {\n        const uint64_t id = m_head.fetch_add(1, std::memory_order_relaxed);\n        return id % m_queryCount;\n    }\n\n    tracy_force_inline uint8_t GetId() const\n    {\n        return m_context;\n    }\n\n    tracy_force_inline VkQueryPool GetQueryPool() const\n    {\n         return m_query;\n    }\n\nprivate:\n    tracy_force_inline void Calibrate( VkDevice device, int64_t& tCpu, int64_t& tGpu )\n    {\n        assert( m_timeDomain != VK_TIME_DOMAIN_DEVICE_EXT );\n        VkCalibratedTimestampInfoEXT spec[2] = {\n            { VK_STRUCTURE_TYPE_CALIBRATED_TIMESTAMP_INFO_EXT, nullptr, VK_TIME_DOMAIN_DEVICE_EXT },\n            { VK_STRUCTURE_TYPE_CALIBRATED_TIMESTAMP_INFO_EXT, nullptr, m_timeDomain },\n        };\n        uint64_t ts[2];\n        uint64_t deviation;\n        do\n        {\n            m_vkGetCalibratedTimestampsEXT( device, 2, spec, ts, &deviation );\n        }\n        while( deviation > m_deviation );\n\n#if defined _WIN32\n        tGpu = ts[0];\n        tCpu = ts[1] * m_qpcToNs;\n#elif defined __linux__ && defined CLOCK_MONOTONIC_RAW\n        tGpu = ts[0];\n        tCpu = ts[1];\n#else\n        assert( false );\n#endif\n    }\n\n    tracy_force_inline void CreateQueryPool()\n    {\n        VkQueryPoolCreateInfo poolInfo = {};\n        poolInfo.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO;\n        poolInfo.queryCount = m_queryCount;\n        poolInfo.queryType = VK_QUERY_TYPE_TIMESTAMP;\n        while ( VK_FUNCTION_WRAPPER( vkCreateQueryPool( m_device, &poolInfo, nullptr, &m_query ) != VK_SUCCESS ) )\n        {\n            m_queryCount /= 2;\n            poolInfo.queryCount = m_queryCount;\n        }\n    }\n\n    tracy_force_inline void FindAvailableTimeDomains( VkPhysicalDevice physicalDevice, PFN_vkGetPhysicalDeviceCalibrateableTimeDomainsEXT _vkGetPhysicalDeviceCalibrateableTimeDomainsEXT )\n    {\n        uint32_t num;\n        _vkGetPhysicalDeviceCalibrateableTimeDomainsEXT( physicalDevice, &num, nullptr );\n        if(num > 4) num = 4;\n        VkTimeDomainEXT data[4];\n        _vkGetPhysicalDeviceCalibrateableTimeDomainsEXT( physicalDevice, &num, data );\n        VkTimeDomainEXT supportedDomain = (VkTimeDomainEXT)-1;\n#if defined _WIN32\n        supportedDomain = VK_TIME_DOMAIN_QUERY_PERFORMANCE_COUNTER_EXT;\n#elif defined __linux__ && defined CLOCK_MONOTONIC_RAW\n        supportedDomain = VK_TIME_DOMAIN_CLOCK_MONOTONIC_RAW_EXT;\n#endif\n        for( uint32_t i=0; i<num; i++ ) {\n            if(data[i] == supportedDomain) {\n                m_timeDomain = data[i];\n                break;\n            }\n        }\n    }\n\n    tracy_force_inline void FindCalibratedTimestampDeviation()\n    {\n        assert( m_timeDomain != VK_TIME_DOMAIN_DEVICE_EXT );\n        constexpr size_t NumProbes = 32;\n        VkCalibratedTimestampInfoEXT spec[2] = {\n            { VK_STRUCTURE_TYPE_CALIBRATED_TIMESTAMP_INFO_EXT, nullptr, VK_TIME_DOMAIN_DEVICE_EXT },\n            { VK_STRUCTURE_TYPE_CALIBRATED_TIMESTAMP_INFO_EXT, nullptr, m_timeDomain },\n        };\n        uint64_t ts[2];\n        uint64_t deviation[NumProbes];\n        for( size_t i=0; i<NumProbes; i++ ) {\n            m_vkGetCalibratedTimestampsEXT( m_device, 2, spec, ts, deviation + i );\n        }\n        uint64_t minDeviation = deviation[0];\n        for( size_t i=1; i<NumProbes; i++ ) {\n            if ( minDeviation > deviation[i] ) {\n                minDeviation = deviation[i];\n            }\n        }\n        m_deviation = minDeviation * 3 / 2;\n\n#if defined _WIN32\n        m_qpcToNs = int64_t( 1000000000. / GetFrequencyQpc() );\n#endif\n    }\n\n    tracy_force_inline void WriteInitialItem( VkPhysicalDevice physdev, int64_t tcpu, int64_t tgpu )\n    {\n        uint8_t flags = 0;\n        if( m_timeDomain != VK_TIME_DOMAIN_DEVICE_EXT ) flags |= GpuContextCalibration;\n\n        VkPhysicalDeviceProperties prop;\n        VK_FUNCTION_WRAPPER( vkGetPhysicalDeviceProperties( physdev, &prop ) );\n        const float period = prop.limits.timestampPeriod;\n\n        auto item = Profiler::QueueSerial();\n        MemWrite( &item->hdr.type, QueueType::GpuNewContext );\n        MemWrite( &item->gpuNewContext.cpuTime, tcpu );\n        MemWrite( &item->gpuNewContext.gpuTime, tgpu );\n        memset( &item->gpuNewContext.thread, 0, sizeof( item->gpuNewContext.thread ) );\n        MemWrite( &item->gpuNewContext.period, period );\n        MemWrite( &item->gpuNewContext.context, m_context );\n        MemWrite( &item->gpuNewContext.flags, flags );\n        MemWrite( &item->gpuNewContext.type, GpuContextType::Vulkan );\n\n#ifdef TRACY_ON_DEMAND\n        GetProfiler().DeferItem( *item );\n#endif\n        Profiler::QueueSerialFinish();\n    }\n\n#if defined TRACY_VK_USE_SYMBOL_TABLE\n    void PopulateSymbolTable( VkInstance instance, PFN_vkGetInstanceProcAddr instanceProcAddr, PFN_vkGetDeviceProcAddr deviceProcAddr )\n    {\n#define VK_GET_DEVICE_SYMBOL( name ) \\\n        (PFN_##name)deviceProcAddr( m_device, #name );\n#define VK_LOAD_DEVICE_SYMBOL( name ) \\\n        m_symbols.name = VK_GET_DEVICE_SYMBOL( name );\n#define VK_GET_INSTANCE_SYMBOL( name ) \\\n        (PFN_##name)instanceProcAddr( instance, #name );\n#define VK_LOAD_INSTANCE_SYMBOL( name ) \\\n        m_symbols.name = VK_GET_INSTANCE_SYMBOL( name );\n\n        LoadVkDeviceCoreSymbols( VK_LOAD_DEVICE_SYMBOL )\n        LoadVkDeviceExtensionSymbols( VK_LOAD_DEVICE_SYMBOL )\n        LoadVkInstanceExtensionSymbols( VK_LOAD_INSTANCE_SYMBOL )\n        LoadVkInstanceCoreSymbols( VK_LOAD_INSTANCE_SYMBOL )\n#undef VK_GET_DEVICE_SYMBOL\n#undef VK_LOAD_DEVICE_SYMBOL\n#undef VK_GET_INSTANCE_SYMBOL\n#undef VK_LOAD_INSTANCE_SYMBOL\n    }\n#endif\n\n    VkDevice m_device;\n    VkQueryPool m_query;\n    VkTimeDomainEXT m_timeDomain;\n#if defined TRACY_VK_USE_SYMBOL_TABLE\n    VkSymbolTable m_symbols;\n#endif\n    uint64_t m_deviation;\n#ifdef _WIN32\n    int64_t m_qpcToNs;\n#endif\n    int64_t m_prevCalibration;\n    uint8_t m_context;\n\n    std::atomic<uint64_t> m_head;\n    uint64_t m_tail;\n    unsigned int m_oldCnt;\n    unsigned int m_queryCount;\n\n    int64_t* m_res;\n\n    PFN_vkGetCalibratedTimestampsEXT m_vkGetCalibratedTimestampsEXT;\n};\n\nclass VkCtxScope\n{\npublic:\n    tracy_force_inline VkCtxScope( VkCtx* ctx, const SourceLocationData* srcloc, VkCommandBuffer cmdbuf, bool is_active )\n#ifdef TRACY_ON_DEMAND\n        : m_active( is_active && GetProfiler().IsConnected() )\n#else\n        : m_active( is_active )\n#endif\n    {\n        if( !m_active ) return;\n        m_cmdbuf = cmdbuf;\n        m_ctx = ctx;\n\n        const auto queryId = ctx->NextQueryId();\n        CONTEXT_VK_FUNCTION_WRAPPER( vkCmdWriteTimestamp( cmdbuf, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, ctx->m_query, queryId ) );\n\n        auto item = Profiler::QueueSerial();\n        MemWrite( &item->hdr.type, QueueType::GpuZoneBeginSerial );\n        MemWrite( &item->gpuZoneBegin.cpuTime, Profiler::GetTime() );\n        MemWrite( &item->gpuZoneBegin.srcloc, (uint64_t)srcloc );\n        MemWrite( &item->gpuZoneBegin.thread, GetThreadHandle() );\n        MemWrite( &item->gpuZoneBegin.queryId, uint16_t( queryId ) );\n        MemWrite( &item->gpuZoneBegin.context, ctx->GetId() );\n        Profiler::QueueSerialFinish();\n    }\n\n    tracy_force_inline VkCtxScope( VkCtx* ctx, const SourceLocationData* srcloc, VkCommandBuffer cmdbuf, int32_t depth, bool is_active )\n#ifdef TRACY_ON_DEMAND\n        : m_active( is_active && GetProfiler().IsConnected() )\n#else\n        : m_active( is_active )\n#endif\n    {\n        if( !m_active ) return;\n        m_cmdbuf = cmdbuf;\n        m_ctx = ctx;\n\n        const auto queryId = ctx->NextQueryId();\n        CONTEXT_VK_FUNCTION_WRAPPER( vkCmdWriteTimestamp( cmdbuf, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, ctx->m_query, queryId ) );\n\n        QueueItem *item;\n        if( depth > 0 && has_callstack() )\n        {\n            item = Profiler::QueueSerialCallstack( Callstack( depth ) );\n            MemWrite( &item->hdr.type, QueueType::GpuZoneBeginCallstackSerial );\n        }\n        else\n        {\n            item = Profiler::QueueSerial();\n            MemWrite( &item->hdr.type, QueueType::GpuZoneBeginSerial );\n        }\n        MemWrite( &item->gpuZoneBegin.cpuTime, Profiler::GetTime() );\n        MemWrite( &item->gpuZoneBegin.srcloc, (uint64_t)srcloc );\n        MemWrite( &item->gpuZoneBegin.thread, GetThreadHandle() );\n        MemWrite( &item->gpuZoneBegin.queryId, uint16_t( queryId ) );\n        MemWrite( &item->gpuZoneBegin.context, ctx->GetId() );\n        Profiler::QueueSerialFinish();\n    }\n\n    tracy_force_inline VkCtxScope( VkCtx* ctx, uint32_t line, const char* source, size_t sourceSz, const char* function, size_t functionSz, const char* name, size_t nameSz, VkCommandBuffer cmdbuf, bool is_active )\n#ifdef TRACY_ON_DEMAND\n        : m_active( is_active && GetProfiler().IsConnected() )\n#else\n        : m_active( is_active )\n#endif\n    {\n        if( !m_active ) return;\n        m_cmdbuf = cmdbuf;\n        m_ctx = ctx;\n\n        const auto queryId = ctx->NextQueryId();\n        CONTEXT_VK_FUNCTION_WRAPPER( vkCmdWriteTimestamp( cmdbuf, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, ctx->m_query, queryId ) );\n\n        const auto srcloc = Profiler::AllocSourceLocation( line, source, sourceSz, function, functionSz, name, nameSz );\n        auto item = Profiler::QueueSerial();\n        MemWrite( &item->hdr.type, QueueType::GpuZoneBeginAllocSrcLocSerial );\n        MemWrite( &item->gpuZoneBegin.cpuTime, Profiler::GetTime() );\n        MemWrite( &item->gpuZoneBegin.srcloc, srcloc );\n        MemWrite( &item->gpuZoneBegin.thread, GetThreadHandle() );\n        MemWrite( &item->gpuZoneBegin.queryId, uint16_t( queryId ) );\n        MemWrite( &item->gpuZoneBegin.context, ctx->GetId() );\n        Profiler::QueueSerialFinish();\n    }\n\n    tracy_force_inline VkCtxScope( VkCtx* ctx, uint32_t line, const char* source, size_t sourceSz, const char* function, size_t functionSz, const char* name, size_t nameSz, VkCommandBuffer cmdbuf, int32_t depth, bool is_active )\n#ifdef TRACY_ON_DEMAND\n        : m_active( is_active && GetProfiler().IsConnected() )\n#else\n        : m_active( is_active )\n#endif\n    {\n        if( !m_active ) return;\n        m_cmdbuf = cmdbuf;\n        m_ctx = ctx;\n\n        const auto queryId = ctx->NextQueryId();\n        CONTEXT_VK_FUNCTION_WRAPPER( vkCmdWriteTimestamp( cmdbuf, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, ctx->m_query, queryId ) );\n\n        const auto srcloc = Profiler::AllocSourceLocation( line, source, sourceSz, function, functionSz, name, nameSz );\n        QueueItem *item;\n        if( depth > 0 && has_callstack() )\n        {\n            item = Profiler::QueueSerialCallstack( Callstack( depth ) );\n            MemWrite( &item->hdr.type, QueueType::GpuZoneBeginAllocSrcLocCallstackSerial );\n        }\n        else\n        {\n            item = Profiler::QueueSerial();\n            MemWrite( &item->hdr.type, QueueType::GpuZoneBeginAllocSrcLocSerial );\n        }\n        MemWrite( &item->gpuZoneBegin.cpuTime, Profiler::GetTime() );\n        MemWrite( &item->gpuZoneBegin.srcloc, srcloc );\n        MemWrite( &item->gpuZoneBegin.thread, GetThreadHandle() );\n        MemWrite( &item->gpuZoneBegin.queryId, uint16_t( queryId ) );\n        MemWrite( &item->gpuZoneBegin.context, ctx->GetId() );\n        Profiler::QueueSerialFinish();\n    }\n\n    tracy_force_inline ~VkCtxScope()\n    {\n        if( !m_active ) return;\n\n        const auto queryId = m_ctx->NextQueryId();\n        CONTEXT_VK_FUNCTION_WRAPPER( vkCmdWriteTimestamp( m_cmdbuf, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, m_ctx->m_query, queryId ) );\n\n        auto item = Profiler::QueueSerial();\n        MemWrite( &item->hdr.type, QueueType::GpuZoneEndSerial );\n        MemWrite( &item->gpuZoneEnd.cpuTime, Profiler::GetTime() );\n        MemWrite( &item->gpuZoneEnd.thread, GetThreadHandle() );\n        MemWrite( &item->gpuZoneEnd.queryId, uint16_t( queryId ) );\n        MemWrite( &item->gpuZoneEnd.context, m_ctx->GetId() );\n        Profiler::QueueSerialFinish();\n    }\n\nprivate:\n    const bool m_active;\n\n    VkCommandBuffer m_cmdbuf;\n    VkCtx* m_ctx;\n};\n\n#if defined TRACY_VK_USE_SYMBOL_TABLE\nstatic inline VkCtx* CreateVkContext( VkInstance instance, VkPhysicalDevice physdev, VkDevice device, VkQueue queue, VkCommandBuffer cmdbuf, PFN_vkGetInstanceProcAddr instanceProcAddr, PFN_vkGetDeviceProcAddr getDeviceProcAddr, bool calibrated = false )\n#else\nstatic inline VkCtx* CreateVkContext( VkPhysicalDevice physdev, VkDevice device, VkQueue queue, VkCommandBuffer cmdbuf, PFN_vkGetPhysicalDeviceCalibrateableTimeDomainsEXT gpdctd, PFN_vkGetCalibratedTimestampsEXT gct )\n#endif\n{\n    auto ctx = (VkCtx*)tracy_malloc( sizeof( VkCtx ) );\n#if defined TRACY_VK_USE_SYMBOL_TABLE\n    new(ctx) VkCtx( instance, physdev, device, queue, cmdbuf, instanceProcAddr, getDeviceProcAddr, calibrated );\n#else\n    new(ctx) VkCtx( physdev, device, queue, cmdbuf, gpdctd, gct );\n#endif\n    return ctx;\n}\n\n#if defined VK_EXT_host_query_reset\n#if defined TRACY_VK_USE_SYMBOL_TABLE\nstatic inline VkCtx* CreateVkContext( VkInstance instance, VkPhysicalDevice physdev, VkDevice device, PFN_vkGetInstanceProcAddr instanceProcAddr, PFN_vkGetDeviceProcAddr getDeviceProcAddr )\n#else\nstatic inline VkCtx* CreateVkContext( VkPhysicalDevice physdev, VkDevice device, PFN_vkResetQueryPoolEXT qpreset, PFN_vkGetPhysicalDeviceCalibrateableTimeDomainsEXT gpdctd, PFN_vkGetCalibratedTimestampsEXT gct )\n#endif\n{\n    auto ctx = (VkCtx*)tracy_malloc( sizeof( VkCtx ) );\n#if defined TRACY_VK_USE_SYMBOL_TABLE\n    new(ctx) VkCtx( instance, physdev, device, instanceProcAddr, getDeviceProcAddr );\n#else\n    new(ctx) VkCtx( physdev, device, qpreset, gpdctd, gct );\n#endif\n    return ctx;\n}\n#endif\n\nstatic inline void DestroyVkContext( VkCtx* ctx )\n{\n    ctx->~VkCtx();\n    tracy_free( ctx );\n}\n\n}\n\nusing TracyVkCtx = tracy::VkCtx*;\n\n#if defined TRACY_VK_USE_SYMBOL_TABLE\n#define TracyVkContext( instance, physdev, device, queue, cmdbuf, instanceProcAddr, deviceProcAddr ) tracy::CreateVkContext( instance, physdev, device, queue, cmdbuf, instanceProcAddr, deviceProcAddr );\n#else\n#define TracyVkContext( physdev, device, queue, cmdbuf ) tracy::CreateVkContext( physdev, device, queue, cmdbuf, nullptr, nullptr );\n#endif\n#if defined TRACY_VK_USE_SYMBOL_TABLE\n#define TracyVkContextCalibrated( instance, physdev, device, queue, cmdbuf, instanceProcAddr, deviceProcAddr ) tracy::CreateVkContext( instance, physdev, device, queue, cmdbuf, instanceProcAddr, deviceProcAddr, true );\n#else\n#define TracyVkContextCalibrated( physdev, device, queue, cmdbuf, gpdctd, gct ) tracy::CreateVkContext( physdev, device, queue, cmdbuf, gpdctd, gct );\n#endif\n#if defined VK_EXT_host_query_reset\n#if defined TRACY_VK_USE_SYMBOL_TABLE\n#define TracyVkContextHostCalibrated( instance, physdev, device, instanceProcAddr, deviceProcAddr ) tracy::CreateVkContext( instance, physdev, device, instanceProcAddr, deviceProcAddr );\n#else\n#define TracyVkContextHostCalibrated( physdev, device, qpreset, gpdctd, gct ) tracy::CreateVkContext( physdev, device, qpreset, gpdctd, gct );\n#endif\n#endif\n#define TracyVkDestroy( ctx ) tracy::DestroyVkContext( ctx );\n#define TracyVkContextName( ctx, name, size ) ctx->Name( name, size );\n#if defined TRACY_HAS_CALLSTACK && defined TRACY_CALLSTACK\n#  define TracyVkNamedZone( ctx, varname, cmdbuf, name, active ) static constexpr tracy::SourceLocationData TracyConcat(__tracy_gpu_source_location,TracyLine) { name, TracyFunction,  TracyFile, (uint32_t)TracyLine, 0 }; tracy::VkCtxScope varname( ctx, &TracyConcat(__tracy_gpu_source_location,TracyLine), cmdbuf, TRACY_CALLSTACK, active );\n#  define TracyVkNamedZoneC( ctx, varname, cmdbuf, name, color, active ) static constexpr tracy::SourceLocationData TracyConcat(__tracy_gpu_source_location,TracyLine) { name, TracyFunction,  TracyFile, (uint32_t)TracyLine, color }; tracy::VkCtxScope varname( ctx, &TracyConcat(__tracy_gpu_source_location,TracyLine), cmdbuf, TRACY_CALLSTACK, active );\n#  define TracyVkZone( ctx, cmdbuf, name ) TracyVkNamedZoneS( ctx, ___tracy_gpu_zone, cmdbuf, name, TRACY_CALLSTACK, true )\n#  define TracyVkZoneC( ctx, cmdbuf, name, color ) TracyVkNamedZoneCS( ctx, ___tracy_gpu_zone, cmdbuf, name, color, TRACY_CALLSTACK, true )\n#  define TracyVkZoneTransient( ctx, varname, cmdbuf, name, active ) TracyVkZoneTransientS( ctx, varname, cmdbuf, name, TRACY_CALLSTACK, active )\n#else\n#  define TracyVkNamedZone( ctx, varname, cmdbuf, name, active ) static constexpr tracy::SourceLocationData TracyConcat(__tracy_gpu_source_location,TracyLine) { name, TracyFunction,  TracyFile, (uint32_t)TracyLine, 0 }; tracy::VkCtxScope varname( ctx, &TracyConcat(__tracy_gpu_source_location,TracyLine), cmdbuf, active );\n#  define TracyVkNamedZoneC( ctx, varname, cmdbuf, name, color, active ) static constexpr tracy::SourceLocationData TracyConcat(__tracy_gpu_source_location,TracyLine) { name, TracyFunction,  TracyFile, (uint32_t)TracyLine, color }; tracy::VkCtxScope varname( ctx, &TracyConcat(__tracy_gpu_source_location,TracyLine), cmdbuf, active );\n#  define TracyVkZone( ctx, cmdbuf, name ) TracyVkNamedZone( ctx, ___tracy_gpu_zone, cmdbuf, name, true )\n#  define TracyVkZoneC( ctx, cmdbuf, name, color ) TracyVkNamedZoneC( ctx, ___tracy_gpu_zone, cmdbuf, name, color, true )\n#  define TracyVkZoneTransient( ctx, varname, cmdbuf, name, active ) tracy::VkCtxScope varname( ctx, TracyLine, TracyFile, strlen( TracyFile ), TracyFunction, strlen( TracyFunction ), name, strlen( name ), cmdbuf, active );\n#endif\n#define TracyVkCollect( ctx, cmdbuf ) ctx->Collect( cmdbuf );\n#define TracyVkCollectHost( ctx ) ctx->Collect( VK_NULL_HANDLE );\n\n#ifdef TRACY_HAS_CALLSTACK\n#  define TracyVkNamedZoneS( ctx, varname, cmdbuf, name, depth, active ) static constexpr tracy::SourceLocationData TracyConcat(__tracy_gpu_source_location,TracyLine) { name, TracyFunction,  TracyFile, (uint32_t)TracyLine, 0 }; tracy::VkCtxScope varname( ctx, &TracyConcat(__tracy_gpu_source_location,TracyLine), cmdbuf, depth, active );\n#  define TracyVkNamedZoneCS( ctx, varname, cmdbuf, name, color, depth, active ) static constexpr tracy::SourceLocationData TracyConcat(__tracy_gpu_source_location,TracyLine) { name, TracyFunction,  TracyFile, (uint32_t)TracyLine, color }; tracy::VkCtxScope varname( ctx, &TracyConcat(__tracy_gpu_source_location,TracyLine), cmdbuf, depth, active );\n#  define TracyVkZoneS( ctx, cmdbuf, name, depth ) TracyVkNamedZoneS( ctx, ___tracy_gpu_zone, cmdbuf, name, depth, true )\n#  define TracyVkZoneCS( ctx, cmdbuf, name, color, depth ) TracyVkNamedZoneCS( ctx, ___tracy_gpu_zone, cmdbuf, name, color, depth, true )\n#  define TracyVkZoneTransientS( ctx, varname, cmdbuf, name, depth, active ) tracy::VkCtxScope varname( ctx, TracyLine, TracyFile, strlen( TracyFile ), TracyFunction, strlen( TracyFunction ), name, strlen( name ), cmdbuf, depth, active );\n#else\n#  define TracyVkNamedZoneS( ctx, varname, cmdbuf, name, depth, active ) TracyVkNamedZone( ctx, varname, cmdbuf, name, active )\n#  define TracyVkNamedZoneCS( ctx, varname, cmdbuf, name, color, depth, active ) TracyVkNamedZoneC( ctx, varname, cmdbuf, name, color, active )\n#  define TracyVkZoneS( ctx, cmdbuf, name, depth ) TracyVkZone( ctx, cmdbuf, name )\n#  define TracyVkZoneCS( ctx, cmdbuf, name, color, depth ) TracyVkZoneC( ctx, cmdbuf, name, color )\n#  define TracyVkZoneTransientS( ctx, varname, cmdbuf, name, depth, active ) TracyVkZoneTransient( ctx, varname, cmdbuf, name, active )\n#endif\n\n#endif\n\n#endif\n"
  }
]