Compare commits

..

1 Commits

Author SHA1 Message Date
Bartosz Taudul
eb5e4b2c0f Test of shaded histogram graph. 2019-08-30 20:07:57 +02:00
664 changed files with 107244 additions and 391063 deletions

23
.appveyor.yml Normal file
View File

@@ -0,0 +1,23 @@
version: '{build}'
platform:
- x64
image:
- Visual Studio 2019
- Ubuntu1804
install:
- cmd: cd c:\tools\vcpkg
- cmd: git pull
- cmd: bootstrap-vcpkg.bat
- cmd: vcpkg install freetype glfw3 --triplet x64-windows-static
- cmd: vcpkg integrate install
- cmd: cd %APPVEYOR_BUILD_FOLDER%
build_script:
- cmd: msbuild .\update\build\win32\update.vcxproj
- cmd: msbuild .\profiler\build\win32\Tracy.vcxproj
- cmd: msbuild .\capture\build\win32\capture.vcxproj
- sh: sudo apt-get update && sudo apt-get -y install libglfw3-dev libgtk2.0-dev
- sh: make -C update/build/unix debug release
- sh: make -C profiler/build/unix debug release
- sh: make -C capture/build/unix debug release
- sh: make -C test
test: off

View File

@@ -1,35 +0,0 @@
# Empirical format config, based on observed style guide
# Use this only as an help to fit the surrounding code style - don't reformat whole files at once
---
BasedOnStyle: Microsoft
AllowShortIfStatementsOnASingleLine: AllIfsAndElse
AllowShortLoopsOnASingleLine: true
AllowShortCaseLabelsOnASingleLine: true
AllowShortFunctionsOnASingleLine: All
# AllowShortEnumsOnASingleLine: true # Broken for some reason, even in last versions of clang-format... So don't use it or it may change formating in the future.
AllowShortLambdasOnASingleLine: All
BreakConstructorInitializers: BeforeComma
BreakStringLiterals: false
SpaceAfterTemplateKeyword: false
AlwaysBreakTemplateDeclarations: Yes
# Allman seems to break lambda formatting for some reason with `ColumnLimit: 0`. See https://github.com/llvm/llvm-project/issues/50275
# Even though it is supposed to have been fixed, issue still remains in 20.1.8. (and is very much present in 18.x which is the one shipped by VS2022 and VSCord clangd as of 2025-07-27)
# Things work fine with `BasedOnStyle: Microsoft` so use that instead
#BreakBeforeBraces: Allman
ColumnLimit: 0
# We'd like to use LeftWithLastLine but it's only available in >=19.x
#AlignEscapedNewlines: LeftWithLastLine
AlignEscapedNewlines: Left
FixNamespaceComments: false
IndentPPDirectives: AfterHash
IndentAccessModifiers: false
AccessModifierOffset: -4
LambdaBodyIndentation: OuterScope
PPIndentWidth: 2
IndentWidth: 4
PointerAlignment: Left
SpaceBeforeParens: Never
SpacesInParentheses: true
TabWidth: 4
AlignTrailingComments:
Kind: Leave

View File

@@ -1,66 +0,0 @@
---
Checks:
'
clang-diagnostic-*,
clang-analyzer-*,
bugprone-*,
google-*,
misc-*,
modernize-*,
performance-*,
readability-*,
-bugprone-easily-swappable-parameters,
-bugprone-implicit-widening-of-multiplication-result,
-bugprone-narrowing-conversions,
-bugprone-reserved-identifier,
-google-readability-braces-around-statements,
-google-readability-casting,
-google-readability-function-size,
-google-readability-todo,
-google-readability-namespace-comments,
-misc-confusable-identifiers,
-misc-no-recursion,
-misc-use-anonymous-namespace,
-misc-use-internal-linkage,
-modernize-avoid-c-arrays,
-modernize-deprecated-headers,
-modernize-use-default-member-init,
-modernize-use-designated-initializers,
-modernize-use-trailing-return-type,
-performance-no-int-to-ptr,
-readability-braces-around-statements,
-readability-else-after-return,
-readability-function-cognitive-complexity,
-readability-function-size,
-readability-identifier-length,
-readability-implicit-bool-conversion,
-readability-isolate-declaration,
-readability-magic-numbers,
-readability-math-missing-parentheses,
-readability-qualified-auto,
-readability-uppercase-literal-suffix
'
WarningsAsErrors: ''
HeaderFilterRegex: ''
FormatStyle: none
CheckOptions:
llvm-else-after-return.WarnOnConditionVariables: 'false'
modernize-loop-convert.MinConfidence: reasonable
modernize-replace-auto-ptr.IncludeStyle: llvm
modernize-pass-by-value.IncludeStyle: llvm
google-readability-namespace-comments.ShortNamespaceLines: '10'
google-readability-namespace-comments.SpacesBeforeComments: '2'
cppcoreguidelines-non-private-member-variables-in-classes.IgnoreClassesWithAllMemberVariablesBeingPublic: 'true'
google-readability-braces-around-statements.ShortStatementLines: '1'
cert-err33-c.CheckedFunctions: '::aligned_alloc;::asctime_s;::at_quick_exit;::atexit;::bsearch;::bsearch_s;::btowc;::c16rtomb;::c32rtomb;::calloc;::clock;::cnd_broadcast;::cnd_init;::cnd_signal;::cnd_timedwait;::cnd_wait;::ctime_s;::fclose;::fflush;::fgetc;::fgetpos;::fgets;::fgetwc;::fopen;::fopen_s;::fprintf;::fprintf_s;::fputc;::fputs;::fputwc;::fputws;::fread;::freopen;::freopen_s;::fscanf;::fscanf_s;::fseek;::fsetpos;::ftell;::fwprintf;::fwprintf_s;::fwrite;::fwscanf;::fwscanf_s;::getc;::getchar;::getenv;::getenv_s;::gets_s;::getwc;::getwchar;::gmtime;::gmtime_s;::localtime;::localtime_s;::malloc;::mbrtoc16;::mbrtoc32;::mbsrtowcs;::mbsrtowcs_s;::mbstowcs;::mbstowcs_s;::memchr;::mktime;::mtx_init;::mtx_lock;::mtx_timedlock;::mtx_trylock;::mtx_unlock;::printf_s;::putc;::putwc;::raise;::realloc;::remove;::rename;::scanf;::scanf_s;::setlocale;::setvbuf;::signal;::snprintf;::snprintf_s;::sprintf;::sprintf_s;::sscanf;::sscanf_s;::strchr;::strerror_s;::strftime;::strpbrk;::strrchr;::strstr;::strtod;::strtof;::strtoimax;::strtok;::strtok_s;::strtol;::strtold;::strtoll;::strtoul;::strtoull;::strtoumax;::strxfrm;::swprintf;::swprintf_s;::swscanf;::swscanf_s;::thrd_create;::thrd_detach;::thrd_join;::thrd_sleep;::time;::timespec_get;::tmpfile;::tmpfile_s;::tmpnam;::tmpnam_s;::tss_create;::tss_get;::tss_set;::ungetc;::ungetwc;::vfprintf;::vfprintf_s;::vfscanf;::vfscanf_s;::vfwprintf;::vfwprintf_s;::vfwscanf;::vfwscanf_s;::vprintf_s;::vscanf;::vscanf_s;::vsnprintf;::vsnprintf_s;::vsprintf;::vsprintf_s;::vsscanf;::vsscanf_s;::vswprintf;::vswprintf_s;::vswscanf;::vswscanf_s;::vwprintf_s;::vwscanf;::vwscanf_s;::wcrtomb;::wcschr;::wcsftime;::wcspbrk;::wcsrchr;::wcsrtombs;::wcsrtombs_s;::wcsstr;::wcstod;::wcstof;::wcstoimax;::wcstok;::wcstok_s;::wcstol;::wcstold;::wcstoll;::wcstombs;::wcstombs_s;::wcstoul;::wcstoull;::wcstoumax;::wcsxfrm;::wctob;::wctrans;::wctype;::wmemchr;::wprintf_s;::wscanf;::wscanf_s;'
modernize-loop-convert.MaxCopySize: '16'
cert-dcl16-c.NewSuffixes: 'L;LL;LU;LLU'
cert-oop54-cpp.WarnOnlyIfThisHasSuspiciousField: 'false'
cert-str34-c.DiagnoseSignedUnsignedCharComparisons: 'false'
modernize-use-nullptr.NullMacros: 'NULL'
llvm-qualified-auto.AddConstToQualified: 'false'
modernize-loop-convert.NamingStyle: CamelCase
llvm-else-after-return.WarnOnUnfixable: 'false'
google-readability-function-size.StatementThreshold: '800'
...

1
.github/FUNDING.yml vendored
View File

@@ -1 +0,0 @@
github: wolfpld

View File

@@ -1,35 +0,0 @@
name: 'Test Tracy'
description: 'Build the Tracy test application with various cmake flag combinations'
inputs:
extra_cmake_flags:
description: 'Additional cmake flags appended to each configure command (e.g. cross-compilation flags)'
required: false
default: ''
runs:
using: 'composite'
steps:
- name: Test application
shell: bash
run: |
# test compilation with different flags
# we clean the build folder to reset cached variables between runs
cmake -B tests/tracy/build -S tests/tracy -DCMAKE_BUILD_TYPE=Release ${{ inputs.extra_cmake_flags }}
cmake --build tests/tracy/build --parallel
cmake -E rm -rf tests/tracy/build
# same with TRACY_ON_DEMAND
cmake -B tests/tracy/build -S tests/tracy -DCMAKE_BUILD_TYPE=Release -DTRACY_ON_DEMAND=ON ${{ inputs.extra_cmake_flags }}
cmake --build tests/tracy/build --parallel
cmake -E rm -rf tests/tracy/build
# same with TRACY_MANUAL_LIFETIME
cmake -B tests/tracy/build -S tests/tracy -DCMAKE_BUILD_TYPE=Release -DTRACY_MANUAL_LIFETIME=ON ${{ inputs.extra_cmake_flags }}
cmake --build tests/tracy/build --parallel
cmake -E rm -rf tests/tracy/build
# same with TRACY_DEMANGLE
cmake -B tests/tracy/build -S tests/tracy -DCMAKE_BUILD_TYPE=Release -DTRACY_DEMANGLE=ON ${{ inputs.extra_cmake_flags }}
cmake --build tests/tracy/build --parallel
cmake -E rm -rf tests/tracy/build

BIN
.github/sponsor.png vendored

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

View File

@@ -1,49 +0,0 @@
name: android
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
workflow_dispatch:
permissions:
contents: read
concurrency:
group: android-${{ github.ref }}
cancel-in-progress: true
env:
CPM_SOURCE_CACHE: ${{ github.workspace }}/cpm-cache
jobs:
build-android:
runs-on: ubuntu-latest
container: archlinux:base-devel
steps:
- name: Install dependencies
run: pacman -Syu --noconfirm && pacman -S --noconfirm --needed cmake git ninja nodejs unzip
- name: Setup NDK
uses: nttld/setup-ndk@v1
id: setup-ndk
with:
ndk-version: r29
- run: echo "ANDROID_NDK_ROOT=${{ steps.setup-ndk.outputs.ndk-path }}" >> $GITHUB_ENV
- name: Trust git repo
run: git config --global --add safe.directory '*'
- uses: actions/checkout@v4
- name: Cache CPM packages
uses: actions/cache@v4
with:
path: ${{ env.CPM_SOURCE_CACHE }}
key: ${{ runner.os }}-cpm-${{ hashFiles('**/vendor.cmake', '**/CMakeLists.txt') }}
restore-keys: ${{ runner.os }}-cpm-
- name: Library v7
run: |
cmake -B build-v7 -DCMAKE_BUILD_TYPE=Release -DTRACY_ENABLE=ON -DCMAKE_TOOLCHAIN_FILE=${ANDROID_NDK_ROOT}/build/cmake/android.toolchain.cmake -DANDROID_ABI=armeabi-v7a
cmake --build build-v7
- name: Library v8
run: |
cmake -B build-v8 -DCMAKE_BUILD_TYPE=Release -DTRACY_ENABLE=ON -DCMAKE_TOOLCHAIN_FILE=${ANDROID_NDK_ROOT}/build/cmake/android.toolchain.cmake -DANDROID_ABI=arm64-v8a
cmake --build build-v8

View File

@@ -1,55 +0,0 @@
name: appimage
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
workflow_dispatch:
workflow_call:
permissions:
contents: read
concurrency:
group: appimage-${{ github.ref }}
cancel-in-progress: true
env:
CPM_SOURCE_CACHE: ${{ github.workspace }}/cpm-cache
jobs:
build-appimage:
runs-on: ubuntu-latest
container: ubuntu:24.04
steps:
- name: Install dependencies
run: |
apt-get update
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
build-essential cmake ninja-build meson pkg-config git ca-certificates \
curl file desktop-file-utils nodejs patchelf \
libegl-dev libxkbcommon-dev libdbus-1-dev libssl-dev \
libffi-dev libexpat1-dev
- name: Trust git repo
run: git config --global --add safe.directory '*'
- uses: actions/checkout@v4
- name: Cache CPM packages
uses: actions/cache@v4
with:
path: ${{ env.CPM_SOURCE_CACHE }}
key: ${{ runner.os }}-cpm-${{ hashFiles('**/vendor.cmake', '**/CMakeLists.txt') }}
restore-keys: ${{ runner.os }}-cpm-
- name: Cache wayland
uses: actions/cache@v4
with:
path: profiler/build-appimage/wayland
key: ${{ runner.os }}-wayland-${{ hashFiles('profiler/appimage/build.sh') }}
- name: Build AppImage
run: profiler/appimage/build.sh
env:
GIT_REV: ${{ github.sha }}
- uses: actions/upload-artifact@v4
with:
name: appimage
path: profiler/build-appimage/tracy-profiler-x86_64.AppImage

View File

@@ -1,77 +0,0 @@
name: emscripten
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
workflow_dispatch:
permissions:
contents: read
concurrency:
group: emscripten-${{ github.ref }}
cancel-in-progress: true
env:
CPM_SOURCE_CACHE: ${{ github.workspace }}/cpm-cache
jobs:
build-emscripten:
runs-on: ubuntu-latest
container: archlinux:base-devel
steps:
- name: Install dependencies
run: pacman -Syu --noconfirm && pacman -S --noconfirm --needed cmake git unzip python ninja zstd nodejs
- name: Setup emscripten
uses: emscripten-core/setup-emsdk@v16
with:
version: 5.0.7
- name: Trust git repo
run: git config --global --add safe.directory '*'
- uses: actions/checkout@v4
- name: Cache CPM packages
uses: actions/cache@v4
with:
path: ${{ env.CPM_SOURCE_CACHE }}
key: ${{ runner.os }}-cpm-${{ hashFiles('**/vendor.cmake', '**/CMakeLists.txt') }}
restore-keys: ${{ runner.os }}-cpm-
- name: Profiler GUI
run: |
cmake -G Ninja -B profiler/build -S profiler -DCMAKE_BUILD_TYPE=MinSizeRel -DGIT_REV=${{ github.sha }} -DCMAKE_TOOLCHAIN_FILE=${{env.EMSDK}}/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake
cmake --build profiler/build --parallel
- name: Compress artifacts
run: |
zstd -18 profiler/build/tracy-profiler.js profiler/build/tracy-profiler.wasm
gzip -9 profiler/build/tracy-profiler.js profiler/build/tracy-profiler.wasm
- name: Find Artifacts
id: find_artifacts
run: |
mkdir -p bin
cp profiler/build/index.html bin
cp profiler/build/favicon.svg bin
cp profiler/build/tracy-profiler.data bin
cp profiler/build/tracy-profiler.js.gz bin
cp profiler/build/tracy-profiler.js.zst bin
cp profiler/build/tracy-profiler.wasm.gz bin
cp profiler/build/tracy-profiler.wasm.zst bin
- uses: actions/upload-artifact@v4
with:
name: emscripten
path: bin
deploy:
runs-on: ubuntu-latest
needs: build-emscripten
if: github.ref == 'refs/heads/master'
steps:
- uses: actions/download-artifact@v4
- uses: wlixcc/SFTP-Deploy-Action@v1.2.4
with:
username: ${{ secrets.USERNAME }}
server: ${{ secrets.SERVER }}
port: ${{ secrets.PORT }}
ssh_private_key: ${{ secrets.PRIVATE_KEY }}
local_path: './emscripten/*'
remote_path: ${{ secrets.REMOTE_PATH }}
sftp_only: true

View File

@@ -1,33 +0,0 @@
name: Manual
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
workflow_dispatch:
workflow_call:
permissions:
contents: read
concurrency:
group: latex-${{ github.ref }}
cancel-in-progress: true
jobs:
build-manual:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Compile LaTeX
uses: xu-cheng/latex-action@v3
with:
working_directory: manual
root_file: tracy.tex
- uses: actions/upload-artifact@v4
with:
name: manual
path: manual/tracy.pdf

View File

@@ -1,74 +0,0 @@
name: linux-cli
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
workflow_dispatch:
workflow_call:
permissions:
contents: read
concurrency:
group: linux-cli-${{ github.ref }}
cancel-in-progress: true
env:
CPM_SOURCE_CACHE: ${{ github.workspace }}/cpm-cache
jobs:
build-linux-cli:
runs-on: ubuntu-latest
container: ubuntu:24.04
steps:
- name: Install dependencies
run: |
apt-get update
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
build-essential cmake git ca-certificates curl nodejs
- name: Trust git repo
run: git config --global --add safe.directory '*'
- uses: actions/checkout@v4
- name: Cache CPM packages
uses: actions/cache@v4
with:
path: ${{ env.CPM_SOURCE_CACHE }}
key: ${{ runner.os }}-cpm-${{ hashFiles('**/vendor.cmake', '**/CMakeLists.txt') }}
restore-keys: ${{ runner.os }}-cpm-
- name: Build update
run: |
cmake -B update/build -S update -DCMAKE_BUILD_TYPE=Release -DNO_ISA_EXTENSIONS=ON -DGIT_REV=${{ github.sha }}
cmake --build update/build --parallel
- name: Build capture
run: |
cmake -B capture/build -S capture -DCMAKE_BUILD_TYPE=Release -DNO_ISA_EXTENSIONS=ON -DGIT_REV=${{ github.sha }}
cmake --build capture/build --parallel
- name: Build csvexport
run: |
cmake -B csvexport/build -S csvexport -DCMAKE_BUILD_TYPE=Release -DNO_ISA_EXTENSIONS=ON -DGIT_REV=${{ github.sha }}
cmake --build csvexport/build --parallel
- name: Build import
run: |
cmake -B import/build -S import -DCMAKE_BUILD_TYPE=Release -DNO_ISA_EXTENSIONS=ON -DGIT_REV=${{ github.sha }}
cmake --build import/build --parallel
- name: Build merge
run: |
cmake -B merge/build -S merge -DCMAKE_BUILD_TYPE=Release -DNO_ISA_EXTENSIONS=ON -DGIT_REV=${{ github.sha }}
cmake --build merge/build --parallel
- name: Stage release files
run: |
mkdir -p linux-cli
cp update/build/tracy-update linux-cli/
cp capture/build/tracy-capture linux-cli/
cp capture/build/tracy-capture-daemon linux-cli/
cp csvexport/build/tracy-csvexport linux-cli/
cp import/build/tracy-import-chrome linux-cli/
cp import/build/tracy-import-fuchsia linux-cli/
cp merge/build/tracy-merge linux-cli/
strip linux-cli/tracy-*
- uses: actions/upload-artifact@v4
with:
name: linux-cli
path: linux-cli

View File

@@ -1,103 +0,0 @@
name: linux
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
workflow_dispatch:
permissions:
contents: read
concurrency:
group: linux-${{ github.ref }}
cancel-in-progress: true
env:
CPM_SOURCE_CACHE: ${{ github.workspace }}/cpm-cache
jobs:
build-linux:
runs-on: ubuntu-latest
container: archlinux:base-devel
steps:
- name: Install dependencies
run: pacman -Syu --noconfirm && pacman -S --noconfirm --needed freetype2 debuginfod wayland dbus libxkbcommon libglvnd meson cmake git wayland-protocols nodejs lua clang sdl3_image python-jinja
- name: Trust git repo
run: git config --global --add safe.directory '*'
- uses: actions/checkout@v4
- name: Cache CPM packages
uses: actions/cache@v4
with:
path: ${{ env.CPM_SOURCE_CACHE }}
key: ${{ runner.os }}-cpm-${{ hashFiles('**/vendor.cmake', '**/CMakeLists.txt') }}
restore-keys: ${{ runner.os }}-cpm-
- name: Determine build parallelism
run: |
if [ "${ACT:-}" != "true" ] && [ "${FORGEJO_ACTIONS:-}" != "true" ]; then
echo "CMAKE_PARALLEL=--parallel 2" >> "$GITHUB_ENV"
else
echo "CMAKE_PARALLEL=--parallel" >> "$GITHUB_ENV"
fi
- name: Dyna example / clang
run: |
CC=clang CXX=clang++ cmake -B examples/dyna/build-clang -S examples/dyna -DCMAKE_BUILD_TYPE=Release
cmake --build examples/dyna/build-clang $CMAKE_PARALLEL
- name: Dyna example / gcc
run: |
CC=gcc CXX=g++ cmake -B examples/dyna/build-gcc -S examples/dyna -DCMAKE_BUILD_TYPE=Release
cmake --build examples/dyna/build-gcc $CMAKE_PARALLEL
- name: Profiler GUI
run: |
cmake -B profiler/build -S profiler -DCMAKE_BUILD_TYPE=Release -DGIT_REV=${{ github.sha }}
cmake --build profiler/build $CMAKE_PARALLEL
- name: Update utility
run: |
cmake -B update/build -S update -DCMAKE_BUILD_TYPE=Release -DGIT_REV=${{ github.sha }}
cmake --build update/build $CMAKE_PARALLEL
- name: Capture utility
run: |
cmake -B capture/build -S capture -DCMAKE_BUILD_TYPE=Release -DGIT_REV=${{ github.sha }}
cmake --build capture/build $CMAKE_PARALLEL
- name: Csvexport utility
run: |
cmake -B csvexport/build -S csvexport -DCMAKE_BUILD_TYPE=Release -DGIT_REV=${{ github.sha }}
cmake --build csvexport/build $CMAKE_PARALLEL
- name: Import utilities
run: |
cmake -B import/build -S import -DCMAKE_BUILD_TYPE=Release -DGIT_REV=${{ github.sha }}
cmake --build import/build $CMAKE_PARALLEL
- name: Merge utility
run: |
cmake -B merge/build -S merge -DCMAKE_BUILD_TYPE=Release -DGIT_REV=${{ github.sha }}
cmake --build merge/build $CMAKE_PARALLEL
- name: Library (cmake)
run: |
cmake -B build -DCMAKE_BUILD_TYPE=Release -DTRACY_ENABLE=ON
cmake --build build $CMAKE_PARALLEL
env:
CMAKE_INSTALL_PREFIX: ${{ github.workspace }}/bin
- name: Library (meson)
run: |
meson setup -Dprefix=$GITHUB_WORKSPACE/bin/lib -Dtracy_enable=true build-meson
meson compile -C build-meson
- name: Test application
uses: ./.github/actions/test-tracy
- name: Find Artifacts
id: find_artifacts
run: |
mkdir -p bin
cp profiler/build/tracy-profiler bin
cp update/build/tracy-update bin
cp capture/build/tracy-capture bin
cp capture/build/tracy-capture-daemon bin
cp csvexport/build/tracy-csvexport bin
cp import/build/tracy-import-chrome bin
cp import/build/tracy-import-fuchsia bin
cp merge/build/tracy-merge bin
strip bin/tracy-*
- uses: actions/upload-artifact@v4
with:
name: arch-linux
path: bin

View File

@@ -1,80 +0,0 @@
name: macos
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
workflow_dispatch:
workflow_call:
permissions:
contents: read
concurrency:
group: macos-${{ github.ref }}
cancel-in-progress: true
env:
CPM_SOURCE_CACHE: ${{ github.workspace }}/cpm-cache
jobs:
build-macos:
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- name: Cache CPM packages
uses: actions/cache@v4
with:
path: ${{ env.CPM_SOURCE_CACHE }}
key: ${{ runner.os }}-cpm-${{ hashFiles('**/vendor.cmake', '**/CMakeLists.txt') }}
restore-keys: ${{ runner.os }}-cpm-
- name: Install dependencies
run: brew install pkg-config meson
- name: Trust git repo
run: git config --global --add safe.directory '*'
- name: Build library
run: meson setup -Dtracy_enable=true build && meson compile -C build
- name: Test application
uses: ./.github/actions/test-tracy
- name: Build profiler
run: |
cmake -B profiler/build -S profiler -DCMAKE_BUILD_TYPE=Release -DBUNDLE=ON -DGIT_REV=${{ github.sha }}
cmake --build profiler/build --parallel 2 --config Release
- name: Build update
run: |
cmake -B update/build -S update -DCMAKE_BUILD_TYPE=Release -DGIT_REV=${{ github.sha }}
cmake --build update/build --parallel --config Release
- name: Build capture
run: |
cmake -B capture/build -S capture -DCMAKE_BUILD_TYPE=Release -DGIT_REV=${{ github.sha }}
cmake --build capture/build --parallel --config Release
- name: Build csvexport
run: |
cmake -B csvexport/build -S csvexport -DCMAKE_BUILD_TYPE=Release -DGIT_REV=${{ github.sha }}
cmake --build csvexport/build --parallel --config Release
- name: Build import
run: |
cmake -B import/build -S import -DCMAKE_BUILD_TYPE=Release -DGIT_REV=${{ github.sha }}
cmake --build import/build --parallel --config Release
- name: Build merge
run: |
cmake -B merge/build -S merge -DCMAKE_BUILD_TYPE=Release -DGIT_REV=${{ github.sha }}
cmake --build merge/build --parallel --config Release
- name: Package artifacts
run: |
mkdir -p bin
cp -r profiler/build/tracy-profiler.app bin
cp update/build/tracy-update bin
cp capture/build/tracy-capture bin
cp capture/build/tracy-capture-daemon bin
cp csvexport/build/tracy-csvexport bin
cp import/build/tracy-import-chrome bin
cp import/build/tracy-import-fuchsia bin
cp merge/build/tracy-merge bin
strip bin/tracy-profiler.app/Contents/MacOS/tracy-profiler
strip bin/tracy-update bin/tracy-capture bin/tracy-capture-daemon bin/tracy-csvexport bin/tracy-import-chrome bin/tracy-import-fuchsia bin/tracy-merge
- uses: actions/upload-artifact@v4
with:
name: macos
path: bin

View File

@@ -1,68 +0,0 @@
name: build-mingw
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
workflow_dispatch:
permissions:
contents: read
concurrency:
group: mingw-${{ github.ref }}
cancel-in-progress: true
env:
CPM_SOURCE_CACHE: ${{ github.workspace }}/cpm-cache
jobs:
build-mingw:
runs-on: ubuntu-latest
container: archlinux:base-devel
steps:
- name: Install dependencies
run: |
pacman -Syu --noconfirm
pacman -S --noconfirm --needed mingw-w64-gcc cmake git nodejs meson
- name: Trust git repo
run: git config --global --add safe.directory '*'
- uses: actions/checkout@v4
- name: Cache CPM packages
uses: actions/cache@v4
with:
path: ${{ env.CPM_SOURCE_CACHE }}
key: ${{ runner.os }}-cpm-${{ hashFiles('**/vendor.cmake', '**/CMakeLists.txt') }}
restore-keys: ${{ runner.os }}-cpm-
- name: Build TracyClient
run: |
cmake -B build -DCMAKE_BUILD_TYPE=Release -DTRACY_ENABLE=ON \
-DCMAKE_SYSTEM_NAME=Windows \
-DCMAKE_C_COMPILER=x86_64-w64-mingw32-gcc \
-DCMAKE_CXX_COMPILER=x86_64-w64-mingw32-g++
cmake --build build
- name: Library (meson)
run: |
cat > mingw-cross.txt << 'EOF'
[binaries]
c = '/usr/bin/x86_64-w64-mingw32-gcc'
cpp = '/usr/bin/x86_64-w64-mingw32-g++'
ar = '/usr/bin/x86_64-w64-mingw32-ar'
strip = '/usr/bin/x86_64-w64-mingw32-strip'
[host_machine]
system = 'windows'
cpu_family = 'x86_64'
cpu = 'x86_64'
endian = 'little'
EOF
meson setup build-meson --cross-file mingw-cross.txt -Ddefault_library=static -Dtracy_enable=true
meson compile -C build-meson
- name: Test application
uses: ./.github/actions/test-tracy
with:
extra_cmake_flags: >-
-DCMAKE_SYSTEM_NAME=Windows
-DCMAKE_C_COMPILER=x86_64-w64-mingw32-gcc
-DCMAKE_CXX_COMPILER=x86_64-w64-mingw32-g++

View File

@@ -1,65 +0,0 @@
name: release
on:
release:
types: [published]
permissions:
contents: read
concurrency:
group: release-${{ github.event.release.tag_name }}
cancel-in-progress: false
jobs:
release-build-windows:
uses: ./.github/workflows/windows.yml
release-build-macos:
uses: ./.github/workflows/macos.yml
release-build-manual:
uses: ./.github/workflows/latex.yml
release-build-appimage:
uses: ./.github/workflows/appimage.yml
release-build-linux-cli:
uses: ./.github/workflows/linux-cli.yml
attach-to-release:
needs: [release-build-windows, release-build-macos, release-build-manual, release-build-appimage, release-build-linux-cli]
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/download-artifact@v4
- name: Create versioned Windows zip
run: |
VERSION="${{ github.event.release.tag_name }}"
VERSION_NO_V="${VERSION#v}"
cd windows
zip -r ../windows-$VERSION_NO_V.zip .
- name: Create versioned macOS zip
run: |
VERSION="${{ github.event.release.tag_name }}"
VERSION_NO_V="${VERSION#v}"
cd macos
chmod +x tracy-* tracy-profiler.app/Contents/MacOS/*
zip -r ../macos-$VERSION_NO_V.zip .
- name: Create versioned Linux zip
run: |
VERSION="${{ github.event.release.tag_name }}"
VERSION_NO_V="${VERSION#v}"
mkdir linux
cp appimage/* linux/
cp linux-cli/* linux/
cd linux
zip -r ../linux-$VERSION_NO_V.zip .
- uses: softprops/action-gh-release@v2
with:
files: |
windows-*.zip
macos-*.zip
linux-*.zip
manual/tracy.pdf

View File

@@ -1,75 +0,0 @@
name: windows
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
workflow_dispatch:
workflow_call:
permissions:
contents: read
concurrency:
group: windows-${{ github.ref }}
cancel-in-progress: true
env:
CPM_SOURCE_CACHE: ${{ github.workspace }}/cpm-cache
jobs:
build-windows:
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
- name: Cache CPM packages
uses: actions/cache@v4
with:
path: ${{ env.CPM_SOURCE_CACHE }}
key: ${{ runner.os }}-cpm-${{ hashFiles('**/vendor.cmake', '**/CMakeLists.txt') }}
restore-keys: ${{ runner.os }}-cpm-
- uses: microsoft/setup-msbuild@v2
- name: Trust git repo
run: git config --global --add safe.directory '*'
- name: Test application
uses: ./.github/actions/test-tracy
- name: Build profiler
run: |
cmake -B profiler/build -S profiler -DCMAKE_BUILD_TYPE=Release -DGIT_REV=${{ github.sha }}
cmake --build profiler/build --parallel 2 --config Release
- name: Build update
run: |
cmake -B update/build -S update -DCMAKE_BUILD_TYPE=Release -DGIT_REV=${{ github.sha }}
cmake --build update/build --parallel --config Release
- name: Build capture
run: |
cmake -B capture/build -S capture -DCMAKE_BUILD_TYPE=Release -DGIT_REV=${{ github.sha }}
cmake --build capture/build --parallel --config Release
- name: Build csvexport
run: |
cmake -B csvexport/build -S csvexport -DCMAKE_BUILD_TYPE=Release -DGIT_REV=${{ github.sha }}
cmake --build csvexport/build --parallel --config Release
- name: Build import
run: |
cmake -B import/build -S import -DCMAKE_BUILD_TYPE=Release -DGIT_REV=${{ github.sha }}
cmake --build import/build --parallel --config Release
- name: Build merge
run: |
cmake -B merge/build -S merge -DCMAKE_BUILD_TYPE=Release -DGIT_REV=${{ github.sha }}
cmake --build merge/build --parallel --config Release
- name: Package artifacts
run: |
mkdir bin
copy profiler\build\Release\tracy-profiler.exe bin
copy update\build\Release\tracy-update.exe bin
copy capture\build\Release\tracy-capture.exe bin
copy capture\build\Release\tracy-capture-daemon.exe bin
copy csvexport\build\Release\tracy-csvexport.exe bin
copy import\build\Release\tracy-import-chrome.exe bin
copy import\build\Release\tracy-import-fuchsia.exe bin
copy merge\build\Release\tracy-merge.exe bin
- uses: actions/upload-artifact@v4
with:
name: windows
path: bin

32
.gitignore vendored
View File

@@ -1,32 +1,22 @@
.vs
_build
_compiler
*.opendb
*.db
*.vcxproj.user
x64
Release
Debug
*.d
*.o
*.so
*.swp
*.obj
imgui.ini
test/tracy_test
test/tracy_test.exe
*/build/unix/*-*
manual/t*.aux
manual/t*.log
manual/t*.out
manual/t*.pdf
manual/t*.synctex.gz
manual/t*.toc
manual/t*.bbl
manual/t*.blg
manual/t*.fdb_latexmk
manual/t*.fls
profiler/build-appimage
.deps/
.dirstamp
/_*/**
/**/__pycache__/**
extra/tracy-build
.cache
.uv-cache/
.venv/
compile_commands.json
examples/ToyPathTracer/Windows/TestCpu
examples/ToyPathTracer/Windows/x64
*.user
profiler/build/win32/packages
profiler/build/win32/Tracy.aps

View File

@@ -1,2 +0,0 @@
<wolf@nereid.pl> <wolf.pld@gmail.com>
<wolf@nereid.pl> <bartosz.taudul@game-lion.com>

View File

@@ -1,340 +0,0 @@
---
name: tracy-gui-verify
description: Build, serve, and drive the Tracy Profiler's emscripten (web) GUI in a headless browser with verified mouse/keyboard semantics. Use when developing or testing the profiler GUI. No X11/Wayland/DISPLAY required — the browser is the display server.
---
# Test the Tracy web GUI in a browser
Build the emscripten profiler GUI into an instrumented temporary workspace,
serve it, and drive it with the browser tool. The harness exports
(`debug_snapshot`/`debug_clear`) expose the app-side mouse/ID state — they
are the ground truth for targeting and verification, not screenshots.
Applies to this repo's emscripten build with ImGui 1.92.9b-docking and
Emscripten 5.0.7. Constants marked M are workstation-dependent — re-verify
them. Everything else is stable; do not re-derive it.
## Setup
```sh
sh <this-skill-dir>/setup.sh # workspace=/tmp/tracy-protocol
# or: TRACY_WEB_WS=/elsewhere TRACY_WEB_REPO=<repo> sh setup.sh
```
`<this-skill-dir>` is the project-scoped `.omp/skills/tracy-gui-verify/`
under the active project root — not a fixed home directory. If multiple
copies exist (one per project that has used this skill), use the copy
inside the repo being tested; `TRACY_WEB_REPO` controls which repo is
copied into the workspace.
The script: fresh source copy (excludes `.git` and build dirs) → applies
`harness.patch` (adds `debug_snapshot`/`debug_clear` exports + event/frame
recording to the emscripten backend, in the COPY only) → configures → builds
Release with the emsdk at `$EMSDK_DIR` (default `~/emsdk`) and the CPM cache at
`~/.cache/cpm`.
**Pitfall:** if the workspace is deleted while a `tracy-web` server is running,
stop the hub process first — a stale server keeps the *deleted* cwd and silently
returns empty responses while the port still accepts connections.
**Pitfall:** a `tracy-web` that died in an earlier session leaves the daemon in
`failed` state: `stop` only reports the old failure, and `start` keeps returning
"Daemon tracy-web has unacknowledged completion notifications" while the port
stays free. Drain the daemon with `hub op=logs name=tracy-web` (the log also
shows the cause), then relaunch with `hub op=restart name=tracy-web` (retained
spec). If the port is NOT free, a stale process owns it — often one serving an
earlier (now-stale) build directory: the new `httpd.py` dies on the bind and
your requests silently hit the old directory. Check `ss -tlnp | grep 8000` and
kill the owner. After any start/restart, verify the server is actually
serving: `curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:8000/index.html`
must return 200 — the daemon message is not proof of a server.
**After editing the GUI in the repo:** copy the changed files into
`$WS/src/` (same relative path), re-run `cmake --build $WS/build -j$(nproc)`,
reload the page. If a change touches `profiler/src/BackendEmscripten.cpp` or
`profiler/CMakeLists.txt`, the harness patch may no longer apply — re-apply it
manually (keep the `Dbg*` harness section, the `DbgPushEvent`/`DbgPushFrame`
calls in the mouse callbacks + `NewFrame`, and the two `debug_*` exports in
`-sEXPORTED_FUNCTIONS`).
## Serve + open + ready
Server (long-running → `hub`):
```
hub op=start name=tracy-web application=python3 args=["$WS/build/httpd.py"]
cwd=$WS/build ready={port:8000} persist=true
```
`httpd.py` sends the COOP/COEP headers required for pthreads/SharedArrayBuffer —
use it, not a bare http.server.
Browser:
```
browser open url=http://127.0.0.1:8000/index.html viewport={width:1600,height:900}
```
**Ready signal** (in a `run` cell; `run` code executes in Node scope — page JS
goes through `tab.evaluate`):
```js
let title = null;
for (let i = 0; i < 360; i++) {
title = await tab.evaluate(() => document.title);
if (/ - Tracy Profiler/.test(title)) break;
await new Promise(r => setTimeout(r, 250));
}
```
Title is `Tracy Profiler X.Y.Z` until the preloaded `embed.tracy` (DarkRL
capture) finishes loading, then `<trace> (embed.tracy) - Tracy Profiler X.Y.Z`
(`profiler/src/main.cpp` `SetWindowTitleCallback`). Wait ~1.5 s after, then
confirm the app loop lives: `snap().frames.at(-1).tick > 0`.
## Harness API (ground truth)
```js
const snap = () => tab.evaluate(() => JSON.parse(Module.ccall('debug_snapshot','string',[],[])));
const clear = () => tab.evaluate(() => Module.ccall('debug_clear','void',[],[]));
```
`snap()``{ dpr, innerW, innerH, bufW, bufH, rectL, rectT, rectW, rectH,
title, cursor, frames:[…64], events:[…64] }` (newest last).
- `frames[]`: one sample **per rAF tick, including idle ticks**. `tick` = main-loop
count (always advances), `f` = `ImGui::GetFrameCount()` (advances only when a
frame actually renders — the idle gate, §Idle), `mx/my` = app mouse position,
`md[3]` = mouse button states, `q` = pending input events, `wa` =
`tracy::s_wasActive` at tick start, `hi`/`ai` = ImGui `HoveredId`/`ActiveId`.
- `events[]`: raw callback data as the app received it. `type` 0=move 1=down
2=up 3=enter 4=leave 5=wheel; `tx/ty` = Emscripten int `targetX/Y`; `ax/ay` =
position passed to ImGui (`-1` for non-move); `t` = DOMHighResTimeStamp.
## Coordinate mapping
```
appX = floor( trunc(cssX - rectL) * dpr ) // device px, what ImGui hit-tests
cssX = appX / dpr // inverse for targeting
screenshot_px = cssX * dpr
```
Chain: DOM `clientX` → Emscripten `targetX = int(clientX - (rect.left|0))`
(`src/lib/libhtml5.js`, `EmscriptenMouseEvent.targetX` is an `int`) → Tracy
`AddMousePosEvent(targetX * dpr, …)` (`BackendEmscripten.cpp`) → ImGui `ImFloor`
(`imgui.cpp` `AddMousePosEvent`). Canvas fills the viewport, so `rectL/rectT`
are 0 (re-read anyway).
**M: `dpr` on this workstation's headless browser is 1.25** (canvas buffer
2000×1125 for a 1600×900 viewport; screenshots are captured at device px).
Never assume 1. App positions come in multiples of `dpr`; verify targeting
within ±1 px via `frames[].mx/my`.
## Click protocol
Click = move, press, refresh through the hold, release, verify — all
against rendered frames. The idle gate (§Idle) renders only 3 frames per
wake, and a hold with no mouse events at all refreshes nothing, so a
fixed-wait down/up from a cold idle can be swallowed (both events received,
zero frames rendered) or released after the wake budget expires. Issuing
mouse moves while the button is down keeps the budget alive: a same-coord
re-move is delivered (verified: it reaches the canvas handler, wakes the
app, and a same-coord hold click straddles cleanly) and is the safest
refresh — zero hover drift; a ±`dx` px wiggle works too, but must stay
inside the hit area:
```js
async function click(cssX, cssY, holdMs = 400) {
await page.mouse.move(cssX, cssY); // 1. ALWAYS move first
await new Promise(r => setTimeout(r, 150)); // 2. >= 1 rendered frame
const pre = await snap();
const pf = pre.frames.at(-1);
await clear();
await page.mouse.down(); // 3. press
let df = null, hiDuring = null;
const t0 = Date.now();
while (Date.now() - t0 < holdMs) {
await new Promise(r => setTimeout(r, 70));
await page.mouse.move(cssX, cssY); // 4. same-coord re-move refreshes the wake budget
const f = (await snap()).frames.at(-1);
if (f.md[0] === 1) { df ??= f.f; hiDuring = f.hi; }
}
await page.mouse.up(); // 5. release
let uf = null;
for (let i = 0; i < 40; i++) {
await new Promise(r => setTimeout(r, 40));
const f = (await snap()).frames.at(-1);
if (f.md[0] === 0) { uf = f.f; break; }
}
await new Promise(r => setTimeout(r, 400));
const s = await snap();
const d = s.dpr, ex = Math.floor(Math.trunc(cssX - s.rectL) * d), ey = Math.floor(Math.trunc(cssY - s.rectT) * d);
return { hoverID: pf.hi, hiDuring, appPos: [pf.mx, pf.my], expected: [ex, ey],
straddle: { df, uf },
ok: df !== null && uf !== null && uf > df && hiDuring === pf.hi &&
Math.abs(pf.mx - ex) <= 1 && Math.abs(pf.my - ey) <= 1 };
}
```
Rules:
1. **Move before every click.** The emscripten mousemove handler is the only
thing that sets the app mouse position; mousedown/mouseup only queue button
state. Fresh page position is invalid (`-FLT_MAX`) — a click without a prior
move activates nothing.
2. **Press and release must each render** in separate frames with the item
hovered (ImGui's `PressedOnClickRelease` — doc table at
`imgui_widgets.cpp:489-497`; input trickling,
`ConfigInputTrickleEventQueue`, defers a same-frame release). The
same-coord refresh is what guarantees rendered frames across the hold
from a cold idle.
3. **Verify every click:** `ok: true` (position landed, press and release each
rendered, hover held — `hiDuring === hoverID`) plus a screenshot diff.
Non-ImGui targets (timeline zone bars) have `hi = 0` by design — for those
verify by screenshot, not hover.
4. **Double-click trap:** two same-position clicks <300 ms apart = double-click
(`MouseDoubleClickTime = 0.3 s`) → zoom/thread-info actions fire. Wait
≥350 ms between repeated clicks at one spot.
5. **Drag:** move → down → (move + wait 70 ms)×n → up. **Wheel:**
`page.mouse.wheel({ deltaY: ±500 })` after positioning. **Keys:**
`page.keyboard.type(..., { delay: 50 })` after focusing the input by click;
`page.keyboard.press('Enter')`.
6. **Danger:** toolbar device x 1032 (css 826) = red power button (leftmost
toolbar icon, hover ID 3313137574), closes the trace view (back to "Get
started"). Never click it unless intended.
## Idle and power saving
`main.cpp DrawContents` keeps an `activeFrames = 3` budget refreshed on any
input event (`tracy::s_wasActive`), a connected client, view animation, or a
queued input; exhausted → `sleep 16 ms` with **no `ImGui::NewFrame` and no GL
draw** (canvas keeps the last frame). Expect ~97 % of ticks to skip rendering
while idle.
- Clicks from a cold idle land only via the click protocol's hold refresh
(§Click protocol) — a fixed-wait down/up can be swallowed by the idle gate
(both events received, zero frames rendered). **Before interacting, assert
`tick`/`f` is advancing**; a stalled main loop (initial trace parse, hidden
tab) renders nothing and drops everything. During the initial load the
cursor style is `wait`.
- `focusLostLimit` (reduce render rate on focus loss) is desktop-only; it does
not exist in the emscripten path.
- `canvas.style.cursor` is **not** a hover oracle: this ImGui build sets the
Hand cursor only in `TextLink`, not on buttons.
## Targeting
Screenshots never resolve targeting. Full-page shots arrive downscaled JPEG
(1024 px wide for a 2000-px device buffer; the factor varies), and
`page.screenshot({ clip })` returns a PNG at device scale — a W×H CSS clip
returns W·dpr × H·dpr px (CSS = clip offset + px/dpr). Icon buttons are
1525 device px wide, so visual estimates carry ±20 px error, enough to hit
the neighboring button or a gap. Target from the app's own hit-testing —
sweep the row and click the run's center:
```js
async function sweepRow(dpr, cssY, devFrom, devTo, step = 4) {
const ranges = []; let cur = null;
for (let dev = devFrom; dev <= devTo; dev += step) {
await page.mouse.move(dev / dpr, cssY);
await new Promise(r => setTimeout(r, 50));
const s = await snap();
const hi = s.frames[s.frames.length - 1].hi;
if (cur && hi === cur.id) cur.end = dev;
else { if (cur) ranges.push(cur); cur = { id: hi, start: dev, end: dev }; }
}
ranges.push(cur);
return ranges.filter(r => r.id !== 0 && r.end - r.start >= 4);
}
```
- Same non-zero `hi` across consecutive steps = one widget; `hi = 0` = gap.
Click the run's center: `click((r.start + r.end) / 2 / dpr, cssY)`.
- **Layout is state-dependent:** docked panels (Statistics, Flame, …) resize the
main window and shift the toolbar — **re-sweep after any state change.**
- **Close popups before sweeping:** while a popup is open, hovers outside the
popup can read `hi = 0` even over live widgets (verified with ZoomPopup over
the toolbar). A % click in ZoomPopup does not close the popup — click an
empty area first.
- Hover IDs are stable across sessions (label hashes) — the map below holds for
the default state (fresh load, no panels, 1600×900, dpr 1.25).
- Zoomed region shots (for correlating IDs with icons): `page.screenshot({clip})`
returns a Buffer — write it with Node `fs`, then `read` the file:
```js
const fs = require('fs');
const buf = await page.screenshot({ clip: { x: 0, y: 0, width: 720, height: 28 } });
fs.writeFileSync('/tmp/toolbar-zoom.png', buf);
```
### Toolbar map — default state (device px; css = device/1.25; row y css 15)
| device x | hover ID | function |
|---|---|---|
| 1032 | 3313137574 | ⏻ power (red, leftmost) — **closes the trace view (DANGER)** |
| 4468 | 608241489 | ⚙ Options gear — opens the Options window (clickable; do not confuse with the power button) |
| 81185 | 2246346107 | 💬 Messages panel toggle |
| 199259 | 3177774389 | 🔍 Find zone toggle (search input hover ID 3637961452, css ~x 100440, y ~90) |
| 271367 | 1419322276 | 📊 Statistics toggle |
| 383451 | 322727105 | 🔥 Flame graph toggle |
| 463551 | 37993378 | 💾 Memory graph toggle |
| 567667 | 2133895361 | ⚖ Compare toggle |
| 679735 | 1808024465 | ⌗ Info (trace information) toggle |
| 751775 | 2535445525 | 🛠 wrench → ToolsPopup (Playback, CPU data, Annotations, Limits, Wait stacks, Frame statistics) |
| 791811 | 3101356487 | 📖 book → User manual toggle |
| 827851 | 2335673581 | 🔍+ → ZoomPopup (50300 % user scale) |
| 864888 | 1263603982 | ◀ previous frame — focuses the timeline on the previous frame (view range shrinks to the frame's timespan) |
| ~8901010 | 0 | frame set name + count text ("Frames: N") — LMB jumps to a specified frame (custom hit-test, like timeline zones) |
| 10121036 | 2142681495 | ▶ next frame — focuses the timeline on the next frame (verified: view range 25.82 s → 203.38 ms) |
| 10521072 | 2961929287 | ▼ frame set selection (switch the active frame set) |
Button names and functions: the user manual, *Control menu* (`manual/tracy.md`). The
web build omits *Connection* (live capture only) and *Tracy Assist* (desktop only).
## User scale (DPI zoom)
The 🔍+ button (hover ID 2335673581) — *Display scale* in the user manual —
opens a ZoomPopup with 50300 % steps.
In the web build this scales the UI **layout only**: fonts,
`Style::ScaleAllSizes`, and window sizes (`main.cpp SetupDPIScale`,
`scale = devicePixelRatio × userScale`). The canvas buffer and the mouse→app
mapping stay at `devicePixelRatio` (`BackendEmscripten.cpp`) — hit regions
become physically larger in the same coordinate space, targeting precision is
unchanged, and the standard click protocol works as-is.
Use it when small buttons are hard to hit or details are hard to read in
screenshots. At 200 % every toolbar hit region is roughly 2× (verified: power
16→40 px, gear 25→50 px, Messages 105→190 px wide; row height 24→46 device
px). The layout **reflows completely** at any scale — re-sweep after changing
it and after setting it back. `userScale` is session-only unless Options →
"Save UI scale" is on; a fresh page load starts at 100 %.
## Limitations
- A *connected* live-streaming client cannot be tested in the web build (the
browser GUI cannot open a TCP server). The embedded-trace GUI is the
live-app proxy: real trace data, full GUI.
- `embed.tracy` (10 MB) is downloaded from share.nereid.pl at configure time —
network needed once per fresh workspace; the file then lives in `$WS/build`.
## References
Sources for the behavior the rules above encode — consult them when re-verifying
a constant or a rule fails:
- `profiler/src/BackendEmscripten.cpp` — emscripten input handlers, canvas/dpr
sizing, cursor mapping.
- `profiler/src/main.cpp:540-574` — idle gate (`activeFrames` budget).
- `profiler/src/profiler/TracyMouse.cpp` — per-frame click state cache.
- `profiler/CMakeLists.txt:334-353` — emscripten link options.
- ImGui 1.92.9b (vendored copy in the CPM cache, `~/.cache/cpm/imgui/`):
`imgui_widgets.cpp:483-545` (click semantics table), `imgui.cpp:11278-11403`
(event trickling), `imgui.cpp:1736` (trickle default on), `imgui.cpp:1992-2016`
(AddMousePosEvent floor/dedup).
- Emscripten 5.0.7: `src/lib/libhtml5.js` (`fillMouseEventData`,
`targetX = e.clientX - (rect.left|0)` into HEAP32), `system/include/emscripten/html5.h`
(`EmscriptenMouseEvent.targetX` is `int`; `EmscriptenWheelEvent` embeds a
`mouse` sub-struct).
- Upstream: imgui issue #4921 (new input event API — events spread over
multiple frames), PR #2525 (same-frame click/release), issue #1992 (rapid
down/up "soft clicks" dropped).

View File

@@ -1,221 +0,0 @@
diff -r a/profiler/CMakeLists.txt b/profiler/CMakeLists.txt
--- a/profiler/CMakeLists.txt
+++ b/profiler/CMakeLists.txt
@@ -340,7 +340,7 @@
-sMAXIMUM_MEMORY=4gb
-sSTACK_SIZE=1048576
-sPTHREAD_POOL_SIZE=8
- -sEXPORTED_FUNCTIONS=_main,_nativeOpenFile,_tracy_paste_clipboard
+ -sEXPORTED_FUNCTIONS=_main,_nativeOpenFile,_tracy_paste_clipboard,_debug_snapshot,_debug_clear
-sEXPORTED_RUNTIME_METHODS=ccall
-sENVIRONMENT=web,worker
--preload-file embed.tracy
diff -r a/profiler/src/BackendEmscripten.cpp b/profiler/src/BackendEmscripten.cpp
--- a/profiler/src/BackendEmscripten.cpp
+++ b/profiler/src/BackendEmscripten.cpp
@@ -1,6 +1,8 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <cstdarg>
+#include <algorithm>
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GLES2/gl2.h>
@@ -10,7 +12,146 @@
#include "Backend.hpp"
#include "RunQueue.hpp"
#include "profiler/TracyImGui.hpp"
+#include "imgui_internal.h"
+// ================= DEBUG HARNESS (temporary copy, not for upstream) =================
+struct DbgEvent
+{
+ int type; // 0=move 1=down 2=up 3=enter 4=leave 5=wheel
+ int button;
+ int targetX;
+ int targetY;
+ double appX; // what was passed to ImGui (targetX * dpr), -1 if n/a
+ double appY;
+ double t; // DOMHighResTimeStamp
+ int wheelX;
+ int wheelY;
+};
+struct DbgFrame
+{
+ double t;
+ int tick; // emscripten main-loop tick count (rAF)
+ int imguiFrame; // ImGui::GetFrameCount()
+ float mx, my; // io.MousePos
+ int md0, md1, md2;
+ int queue; // pending ImGui input events
+ int wasActive; // tracy::s_wasActive at tick start
+ unsigned hi; // ImGui hovered item ID
+ unsigned ai; // ImGui active item ID
+};
+static DbgEvent s_dbgEvents[512];
+static int s_dbgEventHead = 0, s_dbgEventN = 0;
+static DbgFrame s_dbgFrames[512];
+static int s_dbgFrameHead = 0, s_dbgFrameN = 0;
+static int s_dbgTick = 0;
+
+static void DbgPushEvent( int type, int button, int tx, int ty, double ax, double ay, double t, int wx = 0, int wy = 0 )
+{
+ auto& e = s_dbgEvents[s_dbgEventHead];
+ e.type = type; e.button = button; e.targetX = tx; e.targetY = ty;
+ e.appX = ax; e.appY = ay; e.t = t; e.wheelX = wx; e.wheelY = wy;
+ s_dbgEventHead = ( s_dbgEventHead + 1 ) % 512;
+ if ( s_dbgEventN < 512 ) s_dbgEventN++;
+}
+
+static void DbgPushFrame()
+{
+ auto& f = s_dbgFrames[s_dbgFrameHead];
+ auto& io = ImGui::GetIO();
+ f.t = EM_ASM_DOUBLE( { return performance.now(); } );
+ f.tick = s_dbgTick;
+ f.imguiFrame = ImGui::GetFrameCount();
+ f.mx = io.MousePos.x; f.my = io.MousePos.y;
+ f.md0 = io.MouseDown[0]; f.md1 = io.MouseDown[1]; f.md2 = io.MouseDown[2];
+ auto ctx = ImGui::GetCurrentContext();
+ f.queue = ctx ? int( ctx->InputEventsQueue.Size ) : -1;
+ f.wasActive = tracy::s_wasActive;
+ f.hi = ctx ? ctx->HoveredId : 0;
+ f.ai = ctx ? ctx->ActiveId : 0;
+ s_dbgFrameHead = ( s_dbgFrameHead + 1 ) % 512;
+ if ( s_dbgFrameN < 512 ) s_dbgFrameN++;
+}
+
+extern "C" EMSCRIPTEN_KEEPALIVE void debug_clear()
+{
+ s_dbgEventHead = s_dbgEventN = s_dbgFrameHead = s_dbgFrameN = 0;
+}
+
+// Escape a C string for embedding in a JSON string literal (", \, control chars).
+static void JsonEscape( char* out, size_t outsz, const char* in )
+{
+ size_t o = 0;
+ for( const unsigned char* p = ( const unsigned char* )in; *p; p++ )
+ {
+ if ( *p == '"' || *p == '\\' )
+ {
+ if ( o + 2 >= outsz ) break;
+ out[o++] = '\\';
+ out[o++] = char( *p );
+ }
+ else if ( *p < 0x20 )
+ {
+ if ( o + 6 >= outsz ) break;
+ o += size_t( snprintf( out + o, outsz - o, "\\u%04x", *p ) );
+ }
+ else
+ {
+ if ( o + 1 >= outsz ) break;
+ out[o++] = char( *p );
+ }
+ }
+ out[o] = 0;
+}
+
+extern "C" EMSCRIPTEN_KEEPALIVE const char* debug_snapshot()
+{
+ static char buf[512 * 1024];
+ size_t off = 0;
+ auto put = [ & ]( const char* fmt, ... )
+ {
+ if ( off + 1 >= sizeof( buf ) ) return;
+ va_list args;
+ va_start( args, fmt );
+ int n = vsnprintf( buf + off, sizeof( buf ) - off - 1, fmt, args );
+ va_end( args );
+ if ( n > 0 ) off = std::min( off + size_t( n ), sizeof( buf ) - 1 );
+ };
+ const auto dpr = EM_ASM_DOUBLE( { return window.devicePixelRatio; } );
+ const auto innerW = EM_ASM_INT( { return window.innerWidth; } );
+ const auto innerH = EM_ASM_INT( { return window.innerHeight; } );
+ const auto bufW = EM_ASM_INT( { return document.getElementById( 'canvas' ).width; } );
+ const auto bufH = EM_ASM_INT( { return document.getElementById( 'canvas' ).height; } );
+ const auto rectL = EM_ASM_DOUBLE( { var r = document.getElementById( 'canvas' ).getBoundingClientRect(); return r.left; } );
+ const auto rectT = EM_ASM_DOUBLE( { var r = document.getElementById( 'canvas' ).getBoundingClientRect(); return r.top; } );
+ const auto rectW = EM_ASM_DOUBLE( { var r = document.getElementById( 'canvas' ).getBoundingClientRect(); return r.width; } );
+ const auto rectH = EM_ASM_DOUBLE( { var r = document.getElementById( 'canvas' ).getBoundingClientRect(); return r.height; } );
+ char title[256];
+ EM_ASM( { stringToUTF8( document.title, $0, 256 ); }, title );
+ char cursor[64];
+ EM_ASM( { stringToUTF8( document.getElementById( 'canvas' ).style.cursor || "", $0, 64 ); }, cursor );
+ char title_e[1536];
+ char cursor_e[384];
+ JsonEscape( title_e, sizeof( title_e ), title );
+ JsonEscape( cursor_e, sizeof( cursor_e ), cursor );
+ put( "{\"dpr\":%.6f,\"innerW\":%d,\"innerH\":%d,\"bufW\":%d,\"bufH\":%d,\"rectL\":%.3f,\"rectT\":%.3f,\"rectW\":%.3f,\"rectH\":%.3f,\"title\":\"%s\",\"cursor\":\"%s\",\"frames\":[", dpr, innerW, innerH, bufW, bufH, rectL, rectT, rectW, rectH, title_e, cursor_e );
+ const int fn = std::min( s_dbgFrameN, 64 );
+ for ( int i = 0; i < fn; i++ )
+ {
+ auto& f = s_dbgFrames[ ( s_dbgFrameHead - fn + i + 512 ) % 512 ];
+ put( "%s{\"t\":%.3f,\"tick\":%d,\"f\":%d,\"mx\":%.1f,\"my\":%.1f,\"md\":[%d,%d,%d],\"q\":%d,\"wa\":%d,\"hi\":%u,\"ai\":%u}", i ? "," : "", f.t, f.tick, f.imguiFrame, f.mx, f.my, f.md0, f.md1, f.md2, f.queue, f.wasActive, f.hi, f.ai );
+ }
+ put( "],\"events\":[");
+ const int en = std::min( s_dbgEventN, 64 );
+ for ( int i = 0; i < en; i++ )
+ {
+ auto& e = s_dbgEvents[ ( s_dbgEventHead - en + i + 512 ) % 512 ];
+ put( "%s{\"type\":%d,\"btn\":%d,\"tx\":%d,\"ty\":%d,\"ax\":%.3f,\"ay\":%.3f,\"t\":%.3f,\"wx\":%d,\"wy\":%d}", i ? "," : "", e.type, e.button, e.targetX, e.targetY, e.appX, e.appY, e.t, e.wheelX, e.wheelY );
+ }
+ put( "]}");
+ buf[off] = 0;
+ return buf;
+}
+
static std::function<void()> s_redraw;
static std::function<void(float)> s_scaleChanged;
static std::function<int(void)> s_isBusy;
@@ -223,32 +364,38 @@
emscripten_set_mousedown_callback( "#canvas", nullptr, EM_TRUE, []( int, const EmscriptenMouseEvent* e, void* ) -> EM_BOOL {
ImGui::GetIO().AddMouseButtonEvent( e->button == 0 ? 0 : 3 - e->button, true );
tracy::s_wasActive = true;
+ DbgPushEvent( 1, e->button, e->targetX, e->targetY, -1, -1, e->timestamp );
return EM_TRUE;
} );
emscripten_set_mouseup_callback( "#canvas", nullptr, EM_TRUE, []( int, const EmscriptenMouseEvent* e, void* ) -> EM_BOOL {
ImGui::GetIO().AddMouseButtonEvent( e->button == 0 ? 0 : 3 - e->button, false );
tracy::s_wasActive = true;
+ DbgPushEvent( 2, e->button, e->targetX, e->targetY, -1, -1, e->timestamp );
return EM_TRUE;
} );
emscripten_set_mousemove_callback( "#canvas", nullptr, EM_TRUE, []( int, const EmscriptenMouseEvent* e, void* ) -> EM_BOOL {
const auto scale = EM_ASM_DOUBLE( { return window.devicePixelRatio; } );
ImGui::GetIO().AddMousePosEvent( e->targetX * scale, e->targetY * scale );
tracy::s_wasActive = true;
+ DbgPushEvent( 0, -1, e->targetX, e->targetY, e->targetX * scale, e->targetY * scale, e->timestamp );
return EM_TRUE;
} );
- emscripten_set_mouseleave_callback( "#canvas", nullptr, EM_TRUE, []( int, const EmscriptenMouseEvent*, void* ) -> EM_BOOL {
+ emscripten_set_mouseleave_callback( "#canvas", nullptr, EM_TRUE, []( int, const EmscriptenMouseEvent* e, void* ) -> EM_BOOL {
ImGui::GetIO().AddFocusEvent( false );
tracy::s_wasActive = true;
+ DbgPushEvent( 4, -1, e->targetX, e->targetY, -1, -1, e->timestamp );
return EM_TRUE;
} );
- emscripten_set_mouseenter_callback( "#canvas", nullptr, EM_TRUE, []( int, const EmscriptenMouseEvent*, void* ) -> EM_BOOL {
+ emscripten_set_mouseenter_callback( "#canvas", nullptr, EM_TRUE, []( int, const EmscriptenMouseEvent* e, void* ) -> EM_BOOL {
ImGui::GetIO().AddFocusEvent( true );
tracy::s_wasActive = true;
+ DbgPushEvent( 3, -1, e->targetX, e->targetY, -1, -1, e->timestamp );
return EM_TRUE;
} );
emscripten_set_wheel_callback( "#canvas", nullptr, EM_TRUE, []( int, const EmscriptenWheelEvent* e, void* ) -> EM_BOOL {
ImGui::GetIO().AddMouseWheelEvent( e->deltaX * -0.05, e->deltaY * -0.05 );
tracy::s_wasActive = true;
+ DbgPushEvent( 5, -1, e->mouse.targetX, e->mouse.targetY, -1, -1, e->mouse.timestamp, int( e->deltaX ), int( e->deltaY ) );
return EM_TRUE;
} );
emscripten_set_keydown_callback( EMSCRIPTEN_EVENT_TARGET_WINDOW, nullptr, EM_TRUE, [] ( int, const EmscriptenKeyboardEvent* e, void* ) -> EM_BOOL {
@@ -298,6 +445,8 @@
void Backend::NewFrame( int& w, int& h )
{
+ s_dbgTick++;
+ DbgPushFrame();
const auto scale = GetDpiScale();
if( scale != s_prevScale )
{

View File

@@ -1,102 +0,0 @@
#!/bin/sh
# setup.sh - build the instrumented Tracy web GUI workspace (see SKILL.md).
#
# Usage:
# sh setup.sh
# TRACY_WEB_WS=/custom/ws TRACY_WEB_REPO=<repo> sh setup.sh
#
# Idempotent: reuses an existing source copy and build dir, skips
# already-applied harness patch hunks, rebuilds.
set -e
WS="${TRACY_WEB_WS:-/tmp/tracy-protocol}"
# The skill is project-scoped: <repo>/.omp/skills/tracy-gui-verify/
SKILL_DIR=$(cd "$(dirname "$0")" && pwd)
if [ -n "$TRACY_WEB_REPO" ]; then
REPO="$TRACY_WEB_REPO"
else
REPO=$(cd "$SKILL_DIR/../../.." 2>/dev/null && pwd) || REPO=""
fi
EMSDK="${EMSDK_DIR:-$HOME/emsdk}"
[ -x "$EMSDK/emsdk" ] || { echo "error: emsdk not found at $EMSDK (set EMSDK_DIR)" >&2; exit 1; }
[ -f "$REPO/profiler/CMakeLists.txt" ] || { echo "error: not a Tracy repo: '$REPO' (set TRACY_WEB_REPO)" >&2; exit 1; }
. "$EMSDK/emsdk_env.sh" >/dev/null 2>&1 || true
command -v emcc >/dev/null || { echo "error: emcc not on PATH after emsdk_env.sh" >&2; exit 1; }
if [ ! -f "$WS/src/profiler/CMakeLists.txt" ]; then
echo "[setup] fresh source copy -> $WS/src (from $REPO)"
mkdir -p "$WS/src"
# -C applies to both archive creation and extraction; exclude all build dirs
tar -C "$REPO" \
--exclude=.git \
--exclude='*/build*' \
-cf - . | tar -xf - -C "$WS/src"
else
echo "[setup] reusing source copy in $WS/src (copy changed repo files into it first)"
fi
# The harness is fully in place iff each patch hunk's signature line is present.
# patch --forward skips a whole file once its first hunk is detected as already
# applied, so a failed later hunk is invisible in patch's output and exit code —
# verify the content instead of trusting either.
harness_complete()
{
grep -q '_debug_snapshot' "$WS/src/profiler/CMakeLists.txt" \
&& grep -qF 'EMSCRIPTEN_KEEPALIVE const char* debug_snapshot' "$WS/src/profiler/src/BackendEmscripten.cpp" \
&& grep -qF 'DbgPushEvent( 1,' "$WS/src/profiler/src/BackendEmscripten.cpp" \
&& grep -qF 's_dbgTick++;' "$WS/src/profiler/src/BackendEmscripten.cpp"
}
echo "[setup] applying instrumentation harness"
if harness_complete; then
echo "[setup] harness already applied"
rm -f "$WS/src/profiler/CMakeLists.txt.rej" "$WS/src/profiler/src/BackendEmscripten.cpp.rej"
else
rm -f "$WS/src/profiler/CMakeLists.txt.rej" "$WS/src/profiler/src/BackendEmscripten.cpp.rej"
patch -p1 -d "$WS/src" --forward --no-backup-if-mismatch < "$SKILL_DIR/harness.patch" \
|| {
if harness_complete; then
# mixed run: some hunks already present (skipped), the rest applied
rm -f "$WS/src/profiler/CMakeLists.txt.rej" "$WS/src/profiler/src/BackendEmscripten.cpp.rej"
else
rej=$(ls "$WS/src/profiler/CMakeLists.txt.rej" "$WS/src/profiler/src/BackendEmscripten.cpp.rej" 2>/dev/null || true)
if [ -n "$rej" ]; then
kept="The unapplied hunks are kept in:
$(printf '%s\n' $rej | sed 's/^/ /')"
else
kept="No .rej files were produced (fatal patch error); the patch output above is the only evidence."
fi
cat >&2 <<EOF
error: harness patch did not fully apply — $WS/src has drifted from the repo.
$kept
Do not build from this workspace. Either re-apply the harness by hand
(SKILL.md, "After editing the GUI in the repo"), or start fresh:
rm -rf $WS && sh <this-skill-dir>/setup.sh
EOF
exit 1
fi
}
fi
if [ ! -f "$WS/build/CMakeCache.txt" ]; then
echo "[setup] configuring"
cmake -S "$WS/src/profiler" -B "$WS/build" \
-DCMAKE_TOOLCHAIN_FILE="$EMSDK/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake" \
-DCMAKE_BUILD_TYPE=Release \
-DCPM_SOURCE_CACHE="$HOME/.cache/cpm"
fi
echo "[setup] building (first full build ~3-5 min, incremental ~30 s)"
cmake --build "$WS/build" -j "$(nproc)"
cat <<EOF
[setup] done.
workspace : $WS
repo : $REPO
emcc : $(emcc --version | sed -n 1p)
serve : hub op=start name=tracy-web application=python3 args=[$WS/build/httpd.py] cwd=$WS/build ready={port:8000} persist=true
open : browser open url=http://127.0.0.1:8000/index.html viewport={width:1600,height:900}
ready : document.title matches / - Tracy Profiler/ (see SKILL.md)
EOF

View File

@@ -1,7 +0,0 @@
{
"recommendations": [
"llvm-vs-code-extensions.vscode-clangd",
"vadimcn.vscode-lldb",
"ms-vscode.cmake-tools"
]
}

13
.vscode/launch.json vendored
View File

@@ -1,13 +0,0 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "Launch",
"type": "lldb",
"request": "launch",
"program": "${command:cmake.launchTargetPath}",
"args": [],
"cwd": "${workspaceFolder}"
}
]
}

20
.vscode/settings.json vendored
View File

@@ -1,20 +0,0 @@
{
"cmake.sourceDirectory": [
"${workspaceFolder}/profiler",
"${workspaceFolder}/capture",
"${workspaceFolder}/csvexport",
"${workspaceFolder}/import",
"${workspaceFolder}/merge",
"${workspaceFolder}/update",
"${workspaceFolder}/tests/tracy",
"${workspaceFolder}",
],
"cmake.buildDirectory": "${sourceDirectory}/build",
"cmake.autoSelectActiveFolder": false,
"cmake.options.advanced": {
"folder": { "statusBarVisibility": "visible" },
"variant": { "statusBarVisibility": "compact" }
},
"cmake.copyCompileCommands": "${workspaceFolder}/compile_commands.json",
"lldb.launch.initCommands": ["command script import ${workspaceRoot}/extra/natvis.py"],
}

8
AUTHORS Normal file
View File

@@ -0,0 +1,8 @@
Bartosz Taudul <wolf.pld@gmail.com>
Kamil Klimek <kamil.klimek@sharkbits.com> (initial find zone implementation)
Bartosz Szreder <zgredder@gmail.com> (view/worker split)
Arvid Gerstmann <dev@arvid-g.de> (compatibility fixes)
Rokas Kupstys <rokups@zoho.com> (compatibility fixes, initial CI work, MingW support)
Till Rathmann <till.rathmann@gmx.de> (DLL support)
Sherief Farouk <sherief.personal@gmail.com> (compatibility fixes)
Dedmen Miller <dedmen@dedmen.de> (find zone bug fixes, improvements)

View File

@@ -1,297 +0,0 @@
cmake_minimum_required(VERSION 3.13)
# Run version helper script
include(cmake/version.cmake)
project(Tracy LANGUAGES CXX VERSION ${TRACY_VERSION_STRING})
file(GENERATE OUTPUT .gitignore CONTENT "*")
if(${BUILD_SHARED_LIBS})
set(DEFAULT_STATIC OFF)
else()
set(DEFAULT_STATIC ON)
endif()
option(TRACY_STATIC "Whether to build Tracy as a static library" ${DEFAULT_STATIC})
option(TRACY_Fortran "Build Fortran bindings" OFF)
option(TRACY_LTO "Enable Link-Time optimization" OFF)
if(TRACY_Fortran)
enable_language(Fortran)
set(CMAKE_Fortran_VERSION 2003)
endif()
if(TRACY_LTO OR CMAKE_INTERPROCEDURAL_OPTIMIZATION)
include(CheckIPOSupported)
check_ipo_supported(RESULT LTO_SUPPORTED)
if(NOT LTO_SUPPORTED)
message(WARNING "LTO is not supported!")
endif()
else()
set(LTO_SUPPORTED OFF)
endif()
find_package(Threads REQUIRED)
find_package(rocprofiler-sdk PATHS "/opt/rocm/lib/cmake")
set(TRACY_PUBLIC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/public)
if(LTO_SUPPORTED)
set(TRACY_VISIBILITY "OBJECT")
elseif(TRACY_STATIC)
set(TRACY_VISIBILITY "STATIC")
else()
set(TRACY_VISIBILITY "SHARED")
endif()
add_library(TracyClient ${TRACY_VISIBILITY} "${TRACY_PUBLIC_DIR}/TracyClient.cpp")
target_compile_features(TracyClient PUBLIC cxx_std_11)
set_target_properties(TracyClient PROPERTIES INTERPROCEDURAL_OPTIMIZATION ${LTO_SUPPORTED})
target_include_directories(TracyClient SYSTEM PUBLIC
$<BUILD_INTERFACE:${TRACY_PUBLIC_DIR}>
$<INSTALL_INTERFACE:include/tracy>)
target_link_libraries(
TracyClient
PUBLIC
Threads::Threads
${CMAKE_DL_LIBS}
)
if(rocprofiler-sdk_FOUND)
target_compile_definitions(TracyClient PUBLIC TRACY_ROCPROF)
target_link_libraries(TracyClient PUBLIC rocprofiler-sdk::rocprofiler-sdk)
endif()
if(TRACY_Fortran)
add_library(TracyClientF90 ${TRACY_VISIBILITY} "${TRACY_PUBLIC_DIR}/TracyClient.F90")
target_include_directories(TracyClientF90 PUBLIC
$<BUILD_INTERFACE:${PROJECT_BINARY_DIR}>
$<INSTALL_INTERFACE:include/tracy>)
target_link_libraries(
TracyClientF90
PUBLIC
TracyClient
)
set_target_properties(TracyClientF90 PROPERTIES Fortran_MODULE_DIRECTORY ${PROJECT_BINARY_DIR}
INTERPROCEDURAL_OPTIMIZATION ${LTO_SUPPORTED})
endif()
# Public dependency on some libraries required when using Mingw
if(WIN32 AND ${CMAKE_CXX_COMPILER_ID} MATCHES "GNU|Clang")
target_link_libraries(TracyClient PUBLIC ws2_32 dbghelp secur32)
target_compile_definitions(TracyClient PUBLIC WINVER=0x0A00 _WIN32_WINNT=0x0A00)
endif()
if(CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
find_library(EXECINFO_LIBRARY NAMES execinfo REQUIRED)
target_link_libraries(TracyClient PUBLIC ${EXECINFO_LIBRARY})
endif()
if(TRACY_LIBUNWIND_BACKTRACE)
include(FindPkgConfig)
pkg_check_modules(unwind REQUIRED libunwind)
target_include_directories(TracyClient INTERFACE ${unwind_INCLUDE_DIRS})
target_link_libraries(TracyClient INTERFACE ${unwind_LINK_LIBRARIES})
endif()
if(TRACY_DEBUGINFOD)
include(FindPkgConfig)
pkg_check_modules(debuginfod REQUIRED libdebuginfod)
target_include_directories(TracyClient INTERFACE ${debuginfod_INCLUDE_DIRS})
target_link_libraries(TracyClient INTERFACE ${debuginfod_LINK_LIBRARIES})
endif()
add_library(Tracy::TracyClient ALIAS TracyClient)
if(TRACY_Fortran)
add_library(Tracy::TracyClient_Fortran ALIAS TracyClientF90)
endif()
include(cmake/options.cmake)
set_option(TRACY_ENABLE "Enable profiling" OFF TracyClient)
set_option(TRACY_ON_DEMAND "On-demand profiling" OFF TracyClient)
set_option_value(TRACY_CALLSTACK "Override the callstack collection depth for tracy zones" "" TracyClient)
set_option_value_as_string(TRACY_PLATFORM_HEADER "Path to a header providing TRACY_HAS_CUSTOM_* hooks for an unsupported platform" "" TracyClient)
set_option(TRACY_NO_CALLSTACK "Disable all callstack related functionality" OFF TracyClient)
set_option(TRACY_NO_CALLSTACK_INLINES "Disables the inline functions in callstacks" OFF TracyClient)
set_option(TRACY_ONLY_LOCALHOST "Only listen on the localhost interface" OFF TracyClient)
set_option(TRACY_NO_BROADCAST "Disable client discovery by broadcast to local network" OFF TracyClient)
set_option(TRACY_ONLY_IPV4 "Tracy will only accept connections on IPv4 addresses (disable IPv6)" OFF TracyClient)
set_option(TRACY_NO_CODE_TRANSFER "Disable collection of source code" OFF TracyClient)
set_option(TRACY_NO_CONTEXT_SWITCH "Disable capture of context switches" OFF TracyClient)
set_option(TRACY_NO_EXIT "Client executable does not exit until all profile data is sent to server" OFF TracyClient)
set_option(TRACY_NO_SAMPLING "Disable call stack sampling" OFF TracyClient)
set_option(TRACY_NO_WAIT_STACKS "Disable capture of context switch call stacks" OFF TracyClient)
set_option(TRACY_NO_VERIFY "Disable zone validation for C API" OFF TracyClient)
set_option(TRACY_NO_VSYNC_CAPTURE "Disable capture of hardware Vsync events" OFF TracyClient)
set_option(TRACY_NO_FRAME_IMAGE "Disable the frame image support and its thread" OFF TracyClient)
set_option(TRACY_NO_SYSTEM_TRACING "Disable systrace sampling" OFF TracyClient)
set_option(TRACY_PATCHABLE_NOPSLEDS "Enable nopsleds for efficient patching by system-level tools (e.g. rr)" OFF TracyClient)
set_option(TRACY_MANUAL_LIFETIME "Enable the manual lifetime management of the profile" OFF TracyClient)
set_option(TRACY_FIBERS "Enable fibers support" OFF TracyClient)
set_option(TRACY_NO_CRASH_HANDLER "Disable crash handling" OFF TracyClient)
set_option(TRACY_TIMER_FALLBACK "Use lower resolution timers" OFF TracyClient)
set_option(TRACY_DISALLOW_HW_TIMER "Disallow hardware timer (may be useful on VMs). Requires TRACY_TIMER_FALLBACK=ON" OFF TracyClient)
set_option(TRACY_LIBUNWIND_BACKTRACE "Use libunwind backtracing where supported" OFF TracyClient)
set_option(TRACY_SYMBOL_OFFLINE_RESOLVE "Instead of full runtime symbol resolution, only resolve the image path and offset to enable offline symbol resolution" OFF TracyClient)
set_option(TRACY_LIBBACKTRACE_ELF_DYNLOAD_SUPPORT "Enable libbacktrace to support dynamically loaded elfs in symbol resolution resolution after the first symbol resolve operation" OFF TracyClient)
set_option(TRACY_DEBUGINFOD "Enable debuginfod support" OFF TracyClient)
set_option(TRACY_IGNORE_MEMORY_FAULTS "Ignore instrumentation errors from memory free events that do not have a matching allocation, or from repeated allocations of the same address" OFF TracyClient)
set_option(TRACY_OPENGL_AUTO_CALIBRATION "Periodically recalibrate OpenGL GPU/CPU clock drift (forces a CPU/GPU sync each time)" OFF TracyClient)
# advanced
set_option(TRACY_VERBOSE "[advanced] Verbose output from the profiler" OFF TracyClient)
mark_as_advanced(TRACY_VERBOSE)
set_option(TRACY_NO_INTERNAL_MESSAGE "[advanced] Prevent the profiler from logging messages" OFF TracyClient)
mark_as_advanced(TRACY_NO_INTERNAL_MESSAGE)
set_option(TRACY_DEMANGLE "[advanced] Don't use default demangling function - You'll need to provide your own" OFF TracyClient)
mark_as_advanced(TRACY_DEMANGLE)
if(rocprofiler-sdk_FOUND)
set_option(TRACY_ROCPROF_CALIBRATION "[advanced] Use continuous calibration of the Rocprof GPU time." OFF TracyClient)
mark_as_advanced(TRACY_ROCPROF_CALIBRATION)
endif()
# handle incompatible combinations
if(TRACY_DISALLOW_HW_TIMER AND NOT TRACY_TIMER_FALLBACK)
message(FATAL_ERROR "TRACY_DISALLOW_HW_TIMER can not be activated with disabled TRACY_TIMER_FALLBACK")
endif()
if(NOT TRACY_STATIC)
target_compile_definitions(TracyClient PRIVATE TRACY_EXPORTS)
target_compile_definitions(TracyClient PUBLIC TRACY_IMPORTS)
endif()
include(CMakePackageConfigHelpers)
include(GNUInstallDirs)
set_target_properties(TracyClient PROPERTIES VERSION ${PROJECT_VERSION})
if(TRACY_Fortran)
set_target_properties(TracyClientF90 PROPERTIES VERSION ${PROJECT_VERSION})
endif()
set(tracy_includes
${TRACY_PUBLIC_DIR}/tracy/TracyC.h
${TRACY_PUBLIC_DIR}/tracy/Tracy.hpp
${TRACY_PUBLIC_DIR}/tracy/TracyCUDA.hpp
${TRACY_PUBLIC_DIR}/tracy/TracyD3D11.hpp
${TRACY_PUBLIC_DIR}/tracy/TracyD3D12.hpp
${TRACY_PUBLIC_DIR}/tracy/TracyLua.hpp
${TRACY_PUBLIC_DIR}/tracy/TracyMetal.hmm
${TRACY_PUBLIC_DIR}/tracy/TracyOpenCL.hpp
${TRACY_PUBLIC_DIR}/tracy/TracyOpenGL.hpp
${TRACY_PUBLIC_DIR}/tracy/TracyVulkan.hpp
${TRACY_PUBLIC_DIR}/tracy/TracyWebGPU.hpp)
set(client_includes
${TRACY_PUBLIC_DIR}/client/tracy_concurrentqueue.h
${TRACY_PUBLIC_DIR}/client/tracy_rpmalloc.hpp
${TRACY_PUBLIC_DIR}/client/tracy_SPSCQueue.h
${TRACY_PUBLIC_DIR}/client/TracyKCore.hpp
${TRACY_PUBLIC_DIR}/client/TracyArmCpuTable.hpp
${TRACY_PUBLIC_DIR}/client/TracyCallstack.h
${TRACY_PUBLIC_DIR}/client/TracyCallstack.hpp
${TRACY_PUBLIC_DIR}/client/TracyCpuid.hpp
${TRACY_PUBLIC_DIR}/client/TracyDebug.hpp
${TRACY_PUBLIC_DIR}/client/TracyDxt1.hpp
${TRACY_PUBLIC_DIR}/client/TracyFastVector.hpp
${TRACY_PUBLIC_DIR}/client/TracyLock.hpp
${TRACY_PUBLIC_DIR}/client/TracyMangle.hpp
${TRACY_PUBLIC_DIR}/client/TracyProfiler.hpp
${TRACY_PUBLIC_DIR}/client/TracyRingBuffer.hpp
${TRACY_PUBLIC_DIR}/client/TracyScoped.hpp
${TRACY_PUBLIC_DIR}/client/TracyStringHelpers.hpp
${TRACY_PUBLIC_DIR}/client/TracySysPower.hpp
${TRACY_PUBLIC_DIR}/client/TracySysTime.hpp
${TRACY_PUBLIC_DIR}/client/TracySysTrace.hpp
${TRACY_PUBLIC_DIR}/client/TracyThread.hpp)
set(common_includes
${TRACY_PUBLIC_DIR}/common/tracy_lz4.hpp
${TRACY_PUBLIC_DIR}/common/tracy_lz4hc.hpp
${TRACY_PUBLIC_DIR}/common/TracyAlign.hpp
${TRACY_PUBLIC_DIR}/common/TracyAlloc.hpp
${TRACY_PUBLIC_DIR}/common/TracyApi.h
${TRACY_PUBLIC_DIR}/common/TracyAssert.hpp
${TRACY_PUBLIC_DIR}/common/TracyColor.hpp
${TRACY_PUBLIC_DIR}/common/TracyForceInline.hpp
${TRACY_PUBLIC_DIR}/common/TracyFormat.h
${TRACY_PUBLIC_DIR}/common/TracyMutex.hpp
${TRACY_PUBLIC_DIR}/common/TracyProtocol.hpp
${TRACY_PUBLIC_DIR}/common/TracyQueue.hpp
${TRACY_PUBLIC_DIR}/common/TracySocket.hpp
${TRACY_PUBLIC_DIR}/common/TracyStackFrames.hpp
${TRACY_PUBLIC_DIR}/common/TracyString.hpp
${TRACY_PUBLIC_DIR}/common/TracySystem.hpp
${TRACY_PUBLIC_DIR}/common/TracyTaggedUserlandAddress.hpp
${TRACY_PUBLIC_DIR}/common/TracyVersion.hpp
${TRACY_PUBLIC_DIR}/common/TracyWinFamily.hpp
${TRACY_PUBLIC_DIR}/common/TracyYield.hpp)
install(TARGETS TracyClient
EXPORT TracyConfig
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}/$<IF:$<CONFIG:Release>,,$<CONFIG>>
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/$<IF:$<CONFIG:Release>,,$<CONFIG>>
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}/$<IF:$<CONFIG:Release>,,$<CONFIG>>
COMPONENT lib)
if(TRACY_Fortran)
install(TARGETS TracyClientF90
EXPORT TracyConfig
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}/$<IF:$<CONFIG:Release>,,$<CONFIG>>
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/$<IF:$<CONFIG:Release>,,$<CONFIG>>
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}/$<IF:$<CONFIG:Release>,,$<CONFIG>>
COMPONENT lib)
endif()
# Export targets to build tree root
export(TARGETS TracyClient
NAMESPACE Tracy::
FILE ${CMAKE_BINARY_DIR}/TracyTargets.cmake)
if(TRACY_Fortran)
export(TARGETS TracyClientF90
NAMESPACE Tracy::
APPEND
FILE ${CMAKE_BINARY_DIR}/TracyTargets.cmake)
endif()
install(FILES ${tracy_includes}
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/tracy/tracy)
install(FILES ${client_includes}
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/tracy/client)
install(FILES ${common_includes}
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/tracy/common)
if(TRACY_Fortran)
if(${CMAKE_Fortran_COMPILER_ID} MATCHES "Cray")
install(FILES ${PROJECT_BINARY_DIR}/TRACY.mod
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/tracy)
else()
install(FILES ${PROJECT_BINARY_DIR}/tracy.mod
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/tracy)
endif()
endif()
install(EXPORT TracyConfig
NAMESPACE Tracy::
FILE TracyTargets.cmake
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME})
include(CMakePackageConfigHelpers)
configure_package_config_file(${CMAKE_CURRENT_SOURCE_DIR}/Config.cmake.in
"${CMAKE_CURRENT_BINARY_DIR}/TracyConfig.cmake"
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME})
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/TracyConfig.cmake
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME})
write_basic_package_version_file(
"${CMAKE_CURRENT_BINARY_DIR}/TracyConfigVersion.cmake"
COMPATIBILITY SameMinorVersion)
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/TracyConfigVersion.cmake"
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME})
option(TRACY_CLIENT_PYTHON "Whether to build Tracy python client library" OFF)
if(TRACY_CLIENT_PYTHON)
if(TRACY_STATIC)
message(FATAL_ERROR "Python-bindings require a shared client library")
endif()
add_subdirectory(python)
endif()
if(PROJECT_IS_TOP_LEVEL)
set(CMAKE_COLOR_DIAGNOSTICS ON)
endif()

View File

@@ -1,8 +0,0 @@
@PACKAGE_INIT@
set(TRACY_VERSION_STRING "@TRACY_VERSION_STRING@")
include(CMakeFindDependencyMacro)
find_dependency(Threads REQUIRED)
include("${CMAKE_CURRENT_LIST_DIR}/TracyTargets.cmake")

77
FAQ.md Normal file
View File

@@ -0,0 +1,77 @@
# A quick tracy FAQ
### I already use VTune/perf/Very Sleepy/callgrind/MSVC profiler.
These are statistical profilers, which can be used to find hot spots in the code. This is very useful, but it won't show you the underlying reason for semi-random frame stutter that may occur every couple of seconds.
### You can use Telemetry for that.
Telemetry license costs about 8000 $ per year. Tracy is open source software. Telemetry doesn't have Lua bindings.
### You can use the free Brofiler. Crytek does use it, so it has to be good.
After a cursory look at the Brofiler code I can tell that the timer resolution there is at 300 ns. Tracy can achieve 5 ns timer resolution. Brofiler event logging infrastructure seems to be over-engineered. Brofiler can't track lock contention, nor does it have Lua bindings.
### So tracy is supposedly faster?
My measurements show that logging a single zone with tracy takes only 15 ns. In theory, if the program was doing nothing else, tracy should be able to log 66 million zones per second.
### Bullshit, RAD is advertising that they are able only to log about a million zones, over the network nevertheless: "Capture over a million timing zones per second in real-time!"
Tracy can perform network transfer of 15 million zones per second. Should the client and server be on separate machines, this number will be even higher, but you will need more than a gigabit link to achieve the maximum throughput. [Click here for a video of a max-throughput capture.](https://www.youtube.com/watch?v=DSMIHShKGAc)
### Can I connect to my application at any time and start profiling at this moment?
By default no, all events are registered from the beginning of program execution and are waiting in a queue. There's a separate on-demand mode, enabled by using a `TRACY_ON_DEMAND` macro.
### Am I seeing correctly that the profiler allocates one gigabyte of memory per second?
Only in extreme cases. Normal usage has much lower memory pressure.
### Why do you do magic with the static initialization order? Everyone says that's a bad practice.
It allows tracking construction of static objects and memory allocations performed before main() is entered.
### There's no support for consoles.
Welp. But there's mobile support.
### I do need console support.
The code is open. Write your own, then send a patch.
### I don't believe you can capture a zone in 15 ns. Show me the code!
Following is the annotated assembly code (generated from C++ sources) that's responsible for logging start of the zone:
```
call qword ptr [__imp_GetCurrentThreadId]
mov r14d,eax
mov qword ptr [rsp+0F0h],r14 // save thread id for later use
mov r12d,10h
mov rax,qword ptr gs:[58h] // TLS
mov r15,qword ptr [rax] // queue address
mov rdi,qword ptr [r12+r15] // data address
mov rbp,qword ptr [rdi+20h] // buffer counter
mov rbx,rbp
and ebx,7Fh // 128 item buffer
jne Application::InnerLoop+66h --+
mov rdx,rbp |
mov rcx,rdi |
call enqueue_begin_alloc | // reclaim/alloc next buffer
shl rbx,5 <---------------------+ // buffer items are 32 bytes
add rbx,qword ptr [rdi+40h]
mov byte ptr [rbx],4 // queue item type
rdtscp
mov dword ptr [rbx+19h],ecx // cpu id
shl rdx,20h
or rax,rdx // 64 bit timestamp
mov qword ptr [rbx+1],rax
mov qword ptr [rbx+9],r14 // thread id
lea rax,[__tracy_source_location] // static struct address
mov qword ptr [rbx+11h],rax
lea rax,[rbp+1] // increment buffer counter
mov qword ptr [rdi+20h],rax
```
There's also a second code block, for the end of the zone. It's similar, but a bit smaller, as it can use some of the variables that were retrieved above.

View File

@@ -1,7 +1,7 @@
Tracy Profiler (https://github.com/wolfpld/tracy) is licensed under the
Tracy Profiler (https://bitbucket.org/wolfpld/tracy) is licensed under the
3-clause BSD license.
Copyright (c) 2017-2026, Bartosz Taudul <wolf@nereid.pl>
Copyright (c) 2017-2019, Bartosz Taudul <wolf.pld@gmail.com>
All rights reserved.
Redistribution and use in source and binary forms, with or without

1346
NEWS

File diff suppressed because it is too large Load Diff

View File

@@ -1,28 +1,74 @@
# Tracy Profiler
[![Sponsor](.github/sponsor.png)](https://github.com/sponsors/wolfpld/)
[![Build status](https://ci.appveyor.com/api/projects/status/968a88arq06gm3el/branch/master?svg=true)](https://ci.appveyor.com/project/wolfpld/tracy/branch/master)
### A real time, nanosecond resolution, remote telemetry, hybrid frame and sampling profiler for games and other applications.
Tracy supports profiling CPU (Direct support is provided for C, C++, Lua, Python and Fortran integration. At the same time, third-party bindings to many other languages exist on the internet, such as [Rust](https://github.com/nagisa/rust_tracy_client), [Zig](https://github.com/tealsnow/zig-tracy), [C#](https://github.com/clibequilibrium/Tracy-CSharp), [OCaml](https://github.com/imandra-ai/ocaml-tracy), [Odin](https://github.com/oskarnp/odin-tracy), etc.), GPU (All major graphics/compute APIs: OpenGL, Vulkan, Direct3D 11/12, Metal, OpenCL, CUDA, WebGPU.), memory allocations, locks, context switches, automatically attribute screenshots to captured frames, and much more.
- [Documentation](https://github.com/wolfpld/tracy/releases/latest/download/tracy.pdf) for usage and build process instructions
- [Releases](https://github.com/wolfpld/tracy/releases) containing the documentation (`tracy.pdf`) and compiled Windows x64 binaries (`Tracy-<version>.7z`) as assets
- [Changelog](NEWS)
- [Interactive demo](https://tracy.nereid.pl/)
Tracy is a real time, nanosecond resolution frame profiler that can be used for remote or embedded telemetry of your application. It can profile CPU (C, C++11, Lua), GPU (OpenGL, Vulkan) and memory. It also can display locks held by threads and their interactions with each other.
![](doc/profiler.png)
![](doc/profiler2.png)
The following compilers are supported:
![](doc/profiler3.png)
- MSVC
- gcc
- clang
[An Introduction to Tracy Profiler in C++ - Marcos Slomp - CppCon 2023](https://youtu.be/ghXk3Bk5F2U?t=37)
The following platforms are confirmed to be working (this is not a complete list):
- Windows (x86, x64)
- Linux (x86, x64, ARM, ARM64)
- Android (ARM, x86)
- FreeBSD (x64)
- Cygwin (x64)
- WSL (x64)
- OSX (x64)
[Introduction to Tracy Profiler v0.2](https://www.youtube.com/watch?v=fB5B46lbapc)
[New features in Tracy Profiler v0.3](https://www.youtube.com/watch?v=3SXpDpDh2Uo)
[New features in Tracy Profiler v0.4](https://www.youtube.com/watch?v=eAkgkaO8B9o)
[New features in Tracy Profiler v0.5](https://www.youtube.com/watch?v=P6E7qLMmzTQ)
[New features in Tracy Profiler v0.6](https://www.youtube.com/watch?v=uJkrFgriuOo)
[New features in Tracy Profiler v0.7](https://www.youtube.com/watch?v=_hU7vw00MZ4)
[New features in Tracy Profiler v0.8](https://www.youtube.com/watch?v=30wpRpHTTag)
[New features in Tracy Profiler v0.5](https://www.youtube.com/watch?v=P6E7qLMmzTQ)
[A quick FAQ.](FAQ.md)
[List of changes.](NEWS)
### High-level overview
![](doc/design.svg)
Tracy is split into client and server side. The client side collects events using a high-efficiency queue and awaits for an incoming connection. The server part connects to client and receives collected data from the client, which is then reconstructed into a viewable timeline. The transfer is performed using a TCP connection.
### Performance impact
To check how much slowdown is introduced by using Tracy, I have profiled [etcpak](https://bitbucket.org/wolfpld/etcpak), which is the fastest ETC texture compression utility there is. I used an 8192×8192 test image as input data and instrumented everything down to the 4×4 pixel block compression function (that's 4 million blocks to compress). It should be noted that Tracy needs to calibrate its internal timers at each run. This introduces a delay of 115 ms (on my machine), which is negligible when doing lengthy profiling runs, but it skews the results of etcpak timing. The following times have this delay subtracted, to give focus on zone collection impact, which is the thing that really matters here.
| Scenario | Zones | Clean run | Profiling run | Difference |
|-------------------------------------------------------|---------|-----------|---------------|------------|
| Compression of an image to ETC1 format | 4194568 | 0.94 s | 1.003 s | +0.063 s |
| Compression of an image to ETC2 format, with mip-maps | 5592822 | 1.034 s | 1.119 s | +0.085 s |
In both scenarios the per-zone time cost is at ~15 ns. This is in line with the measured 8 ns single event collection time (each zone has to report start and end event).
## Usage instructions
The user manual for Tracy is available [at the following address](https://bitbucket.org/wolfpld/tracy/downloads/tracy.pdf). It provides information about the integration process, required code markup and so on.
## Features
#### Histogram of function execution times
![](doc/histogram.png)
#### Comparison of two profiling runs
![](doc/compare.png)
#### Marking locks
![](doc/locks.png)
#### Plotting data
![](doc/plot.png)
#### Message log
![](doc/messages.png)

148
Tracy.hpp Normal file
View File

@@ -0,0 +1,148 @@
#ifndef __TRACY_HPP__
#define __TRACY_HPP__
#include "common/TracyColor.hpp"
#include "common/TracySystem.hpp"
#ifndef TRACY_ENABLE
#define ZoneNamed(x,y)
#define ZoneNamedN(x,y,z)
#define ZoneNamedC(x,y,z)
#define ZoneNamedNC(x,y,z,w)
#define ZoneScoped
#define ZoneScopedN(x)
#define ZoneScopedC(x)
#define ZoneScopedNC(x,y)
#define ZoneText(x,y)
#define ZoneName(x,y)
#define FrameMark
#define FrameMarkNamed(x)
#define FrameMarkStart(x)
#define FrameMarkEnd(x)
#define FrameImage(x,y,z,w,a)
#define TracyLockable( type, varname ) type varname;
#define TracyLockableN( type, varname, desc ) type varname;
#define TracySharedLockable( type, varname ) type varname;
#define TracySharedLockableN( type, varname, desc ) type varname;
#define LockableBase( type ) type
#define SharedLockableBase( type ) type
#define LockMark(x) (void)x;
#define TracyPlot(x,y)
#define TracyMessage(x,y)
#define TracyMessageL(x)
#define TracyMessageC(x,y,z)
#define TracyMessageLC(x,y)
#define TracyAppInfo(x,y)
#define TracyAlloc(x,y)
#define TracyFree(x)
#define ZoneNamedS(x,y,z)
#define ZoneNamedNS(x,y,z,w)
#define ZoneNamedCS(x,y,z,w)
#define ZoneNamedNCS(x,y,z,w,a)
#define ZoneScopedS(x)
#define ZoneScopedNS(x,y)
#define ZoneScopedCS(x,y)
#define ZoneScopedNCS(x,y,z)
#define TracyAllocS(x,y,z)
#define TracyFreeS(x,y)
#else
#include "client/TracyLock.hpp"
#include "client/TracyProfiler.hpp"
#include "client/TracyScoped.hpp"
#if defined TRACY_HAS_CALLSTACK && defined TRACY_CALLSTACK
# define ZoneNamed( varname, active ) static const tracy::SourceLocationData TracyConcat(__tracy_source_location,__LINE__) { nullptr, __FUNCTION__, __FILE__, (uint32_t)__LINE__, 0 }; tracy::ScopedZone varname( &TracyConcat(__tracy_source_location,__LINE__), TRACY_CALLSTACK, active );
# define ZoneNamedN( varname, name, active ) static const tracy::SourceLocationData TracyConcat(__tracy_source_location,__LINE__) { name, __FUNCTION__, __FILE__, (uint32_t)__LINE__, 0 }; tracy::ScopedZone varname( &TracyConcat(__tracy_source_location,__LINE__), TRACY_CALLSTACK, active );
# define ZoneNamedC( varname, color, active ) static const tracy::SourceLocationData TracyConcat(__tracy_source_location,__LINE__) { nullptr, __FUNCTION__, __FILE__, (uint32_t)__LINE__, color }; tracy::ScopedZone varname( &TracyConcat(__tracy_source_location,__LINE__), TRACY_CALLSTACK, active );
# define ZoneNamedNC( varname, name, color, active ) static const tracy::SourceLocationData TracyConcat(__tracy_source_location,__LINE__) { name, __FUNCTION__, __FILE__, (uint32_t)__LINE__, color }; tracy::ScopedZone varname( &TracyConcat(__tracy_source_location,__LINE__), TRACY_CALLSTACK, active );
#else
# define ZoneNamed( varname, active ) static const tracy::SourceLocationData TracyConcat(__tracy_source_location,__LINE__) { nullptr, __FUNCTION__, __FILE__, (uint32_t)__LINE__, 0 }; tracy::ScopedZone varname( &TracyConcat(__tracy_source_location,__LINE__), active );
# define ZoneNamedN( varname, name, active ) static const tracy::SourceLocationData TracyConcat(__tracy_source_location,__LINE__) { name, __FUNCTION__, __FILE__, (uint32_t)__LINE__, 0 }; tracy::ScopedZone varname( &TracyConcat(__tracy_source_location,__LINE__), active );
# define ZoneNamedC( varname, color, active ) static const tracy::SourceLocationData TracyConcat(__tracy_source_location,__LINE__) { nullptr, __FUNCTION__, __FILE__, (uint32_t)__LINE__, color }; tracy::ScopedZone varname( &TracyConcat(__tracy_source_location,__LINE__), active );
# define ZoneNamedNC( varname, name, color, active ) static const tracy::SourceLocationData TracyConcat(__tracy_source_location,__LINE__) { name, __FUNCTION__, __FILE__, (uint32_t)__LINE__, color }; tracy::ScopedZone varname( &TracyConcat(__tracy_source_location,__LINE__), active );
#endif
#define ZoneScoped ZoneNamed( ___tracy_scoped_zone, true )
#define ZoneScopedN( name ) ZoneNamedN( ___tracy_scoped_zone, name, true )
#define ZoneScopedC( color ) ZoneNamedC( ___tracy_scoped_zone, color, true )
#define ZoneScopedNC( name, color ) ZoneNamedNC( ___tracy_scoped_zone, name, color, true )
#define ZoneText( txt, size ) ___tracy_scoped_zone.Text( txt, size );
#define ZoneName( txt, size ) ___tracy_scoped_zone.Name( txt, size );
#define FrameMark tracy::Profiler::SendFrameMark( nullptr );
#define FrameMarkNamed( name ) tracy::Profiler::SendFrameMark( name );
#define FrameMarkStart( name ) tracy::Profiler::SendFrameMark( name, tracy::QueueType::FrameMarkMsgStart );
#define FrameMarkEnd( name ) tracy::Profiler::SendFrameMark( name, tracy::QueueType::FrameMarkMsgEnd );
#define FrameImage( image, width, height, offset, flip ) tracy::Profiler::SendFrameImage( image, width, height, offset, flip );
#define TracyLockable( type, varname ) tracy::Lockable<type> varname { [] () -> const tracy::SourceLocationData* { static const tracy::SourceLocationData srcloc { nullptr, #type " " #varname, __FILE__, __LINE__, 0 }; return &srcloc; }() };
#define TracyLockableN( type, varname, desc ) tracy::Lockable<type> varname { [] () -> const tracy::SourceLocationData* { static const tracy::SourceLocationData srcloc { nullptr, desc, __FILE__, __LINE__, 0 }; return &srcloc; }() };
#define TracySharedLockable( type, varname ) tracy::SharedLockable<type> varname { [] () -> const tracy::SourceLocationData* { static const tracy::SourceLocationData srcloc { nullptr, #type " " #varname, __FILE__, __LINE__, 0 }; return &srcloc; }() };
#define TracySharedLockableN( type, varname, desc ) tracy::SharedLockable<type> varname { [] () -> const tracy::SourceLocationData* { static const tracy::SourceLocationData srcloc { nullptr, desc, __FILE__, __LINE__, 0 }; return &srcloc; }() };
#define LockableBase( type ) tracy::Lockable<type>
#define SharedLockableBase( type ) tracy::SharedLockable<type>
#define LockMark( varname ) static const tracy::SourceLocationData __tracy_lock_location_##varname { nullptr, __FUNCTION__, __FILE__, (uint32_t)__LINE__, 0 }; varname.Mark( &__tracy_lock_location_##varname );
#define TracyPlot( name, val ) tracy::Profiler::PlotData( name, val );
#define TracyMessage( txt, size ) tracy::Profiler::Message( txt, size );
#define TracyMessageL( txt ) tracy::Profiler::Message( txt );
#define TracyMessageC( txt, size, color ) tracy::Profiler::MessageColor( txt, size, color );
#define TracyMessageLC( txt, color ) tracy::Profiler::MessageColor( txt, color );
#define TracyAppInfo( txt, size ) tracy::Profiler::MessageAppInfo( txt, size );
#if defined TRACY_HAS_CALLSTACK && defined TRACY_CALLSTACK
# define TracyAlloc( ptr, size ) tracy::Profiler::MemAllocCallstack( ptr, size, TRACY_CALLSTACK );
# define TracyFree( ptr ) tracy::Profiler::MemFreeCallstack( ptr, TRACY_CALLSTACK );
#else
# define TracyAlloc( ptr, size ) tracy::Profiler::MemAlloc( ptr, size );
# define TracyFree( ptr ) tracy::Profiler::MemFree( ptr );
#endif
#ifdef TRACY_HAS_CALLSTACK
# define ZoneNamedS( varname, depth, active ) static const tracy::SourceLocationData TracyConcat(__tracy_source_location,__LINE__) { nullptr, __FUNCTION__, __FILE__, (uint32_t)__LINE__, 0 }; tracy::ScopedZone varname( &TracyConcat(__tracy_source_location,__LINE__), depth, active );
# define ZoneNamedNS( varname, name, depth, active ) static const tracy::SourceLocationData TracyConcat(__tracy_source_location,__LINE__) { name, __FUNCTION__, __FILE__, (uint32_t)__LINE__, 0 }; tracy::ScopedZone varname( &TracyConcat(__tracy_source_location,__LINE__), depth, active );
# define ZoneNamedCS( varname, color, depth, active ) static const tracy::SourceLocationData TracyConcat(__tracy_source_location,__LINE__) { nullptr, __FUNCTION__, __FILE__, (uint32_t)__LINE__, color }; tracy::ScopedZone varname( &TracyConcat(__tracy_source_location,__LINE__), depth, active );
# define ZoneNamedNCS( varname, name, color, depth, active ) static const tracy::SourceLocationData TracyConcat(__tracy_source_location,__LINE__) { name, __FUNCTION__, __FILE__, (uint32_t)__LINE__, color }; tracy::ScopedZone varname( &TracyConcat(__tracy_source_location,__LINE__), depth, active );
# define ZoneScopedS( depth ) ZoneNamedS( ___tracy_scoped_zone, depth, true )
# define ZoneScopedNS( name, depth ) ZoneNamedNS( ___tracy_scoped_zone, name, depth, true )
# define ZoneScopedCS( color, depth ) ZoneNamedCS( ___tracy_scoped_zone, color, depth, true )
# define ZoneScopedNCS( name, color, depth ) ZoneNamedNCS( ___tracy_scoped_zone, name, color depth, true )
# define TracyAllocS( ptr, size, depth ) tracy::Profiler::MemAllocCallstack( ptr, size, depth );
# define TracyFreeS( ptr, depth ) tracy::Profiler::MemFreeCallstack( ptr, depth );
#else
# define ZoneNamedS( varname, depth, active ) ZoneNamed( varname, active )
# define ZoneNamedNS( varname, name, depth, active ) ZoneNamedN( varname, name, active )
# define ZoneNamedCS( varname, color, depth, active ) ZoneNamedC( varname, color, active )
# define ZoneNamedNCS( varname, name, color, depth, active ) ZoneNamedNC( varname, name, color, active )
# define ZoneScopedS( depth ) ZoneScoped
# define ZoneScopedNS( name, depth ) ZoneScopedN( name )
# define ZoneScopedCS( color, depth ) ZoneScopedC( color )
# define ZoneScopedNCS( name, color, depth ) ZoneScopedNC( name, color )
# define TracyAllocS( ptr, size, depth ) TracyAlloc( ptr, size )
# define TracyFreeS( ptr, depth ) TracyFree( ptr )
#endif
#endif
#endif

150
TracyC.h Normal file
View File

@@ -0,0 +1,150 @@
#ifndef __TRACYC_HPP__
#define __TRACYC_HPP__
#include <stddef.h>
#include <stdint.h>
#include "client/TracyCallstack.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifndef TRACY_ENABLE
typedef const void* TracyCZoneCtx;
#define TracyCZone(c,x)
#define TracyCZoneN(c,x,y)
#define TracyCZoneC(c,x,y)
#define TracyCZoneNC(c,x,y,z)
#define TracyCZoneEnd(c)
#define TracyCZoneText(c,x,y)
#define TracyCZoneName(c,x,y)
#define TracyCAlloc(x,y)
#define TracyCFree(x)
#define TracyCFrameMark
#define TracyCFrameMarkNamed(x)
#define TracyCFrameMarkStart(x)
#define TracyCFrameMarkEnd(x)
#define TracyCFrameImage(x,y,z,w,a)
#define TracyCPlot(x,y)
#define TracyCMessage(x,y)
#define TracyCMessageL(x)
#define TracyCMessageC(x,y,z)
#define TracyCMessageLC(x,y)
#define TracyCAppInfo(x,y)
#else
#ifndef TracyConcat
# define TracyConcat(x,y) TracyConcatIndirect(x,y)
#endif
#ifndef TracyConcatIndirect
# define TracyConcatIndirect(x,y) x##y
#endif
struct ___tracy_source_location_data
{
const char* name;
const char* function;
const char* file;
uint32_t line;
uint32_t color;
};
struct ___tracy_c_zone_context
{
uint32_t id;
int active;
};
// Some containers don't support storing const types.
// This struct, as visible to user, is immutable, so treat it as if const was declared here.
typedef /*const*/ struct ___tracy_c_zone_context TracyCZoneCtx;
TracyCZoneCtx ___tracy_emit_zone_begin( const struct ___tracy_source_location_data* srcloc, int active );
TracyCZoneCtx ___tracy_emit_zone_begin_callstack( const struct ___tracy_source_location_data* srcloc, int depth, int active );
void ___tracy_emit_zone_end( TracyCZoneCtx ctx );
void ___tracy_emit_zone_text( TracyCZoneCtx ctx, const char* txt, size_t size );
void ___tracy_emit_zone_name( TracyCZoneCtx ctx, const char* txt, size_t size );
#if defined TRACY_HAS_CALLSTACK && defined TRACY_CALLSTACK
# define TracyCZone( ctx, active ) static const struct ___tracy_source_location_data TracyConcat(__tracy_source_location,__LINE__) = { NULL, __FUNCTION__, __FILE__, (uint32_t)__LINE__, 0 }; TracyCZoneCtx ctx = ___tracy_emit_zone_begin_callstack( &TracyConcat(__tracy_source_location,__LINE__), TRACY_CALLSTACK, active );
# define TracyCZoneN( ctx, name, active ) static const struct ___tracy_source_location_data TracyConcat(__tracy_source_location,__LINE__) = { name, __FUNCTION__, __FILE__, (uint32_t)__LINE__, 0 }; TracyCZoneCtx ctx = ___tracy_emit_zone_begin_callstack( &TracyConcat(__tracy_source_location,__LINE__), TRACY_CALLSTACK, active );
# define TracyCZoneC( ctx, color, active ) static const struct ___tracy_source_location_data TracyConcat(__tracy_source_location,__LINE__) = { NULL, __FUNCTION__, __FILE__, (uint32_t)__LINE__, color }; TracyCZoneCtx ctx = ___tracy_emit_zone_begin_callstack( &TracyConcat(__tracy_source_location,__LINE__), TRACY_CALLSTACK, active );
# define TracyCZoneNC( ctx, name, color, active ) static const struct ___tracy_source_location_data TracyConcat(__tracy_source_location,__LINE__) = { name, __FUNCTION__, __FILE__, (uint32_t)__LINE__, color }; TracyCZoneCtx ctx = ___tracy_emit_zone_begin_callstack( &TracyConcat(__tracy_source_location,__LINE__), TRACY_CALLSTACK, active );
#else
# define TracyCZone( ctx, active ) static const struct ___tracy_source_location_data TracyConcat(__tracy_source_location,__LINE__) = { NULL, __FUNCTION__, __FILE__, (uint32_t)__LINE__, 0 }; TracyCZoneCtx ctx = ___tracy_emit_zone_begin( &TracyConcat(__tracy_source_location,__LINE__), active );
# define TracyCZoneN( ctx, name, active ) static const struct ___tracy_source_location_data TracyConcat(__tracy_source_location,__LINE__) = { name, __FUNCTION__, __FILE__, (uint32_t)__LINE__, 0 }; TracyCZoneCtx ctx = ___tracy_emit_zone_begin( &TracyConcat(__tracy_source_location,__LINE__), active );
# define TracyCZoneC( ctx, color, active ) static const struct ___tracy_source_location_data TracyConcat(__tracy_source_location,__LINE__) = { NULL, __FUNCTION__, __FILE__, (uint32_t)__LINE__, color }; TracyCZoneCtx ctx = ___tracy_emit_zone_begin( &TracyConcat(__tracy_source_location,__LINE__), active );
# define TracyCZoneNC( ctx, name, color, active ) static const struct ___tracy_source_location_data TracyConcat(__tracy_source_location,__LINE__) = { name, __FUNCTION__, __FILE__, (uint32_t)__LINE__, color }; TracyCZoneCtx ctx = ___tracy_emit_zone_begin( &TracyConcat(__tracy_source_location,__LINE__), active );
#endif
#define TracyCZoneEnd( ctx ) ___tracy_emit_zone_end( ctx );
#define TracyCZoneText( ctx, txt, size ) ___tracy_emit_zone_text( ctx, txt, size );
#define TracyCZoneName( ctx, txt, size ) ___tracy_emit_zone_name( ctx, txt, size );
void ___tracy_emit_memory_alloc( const void* ptr, size_t size );
void ___tracy_emit_memory_alloc_callstack( const void* ptr, size_t size, int depth );
void ___tracy_emit_memory_free( const void* ptr );
void ___tracy_emit_memory_free_callstack( const void* ptr, int depth );
#if defined TRACY_HAS_CALLSTACK && defined TRACY_CALLSTACK
# define TracyCAlloc( ptr, size ) ___tracy_emit_memory_alloc_callstack( ptr, size, TRACY_CALLSTACK )
# define TracyCFree( ptr ) ___tracy_emit_memory_alloc_free_callstack( ptr, TRACY_CALLSTACK )
#else
# define TracyCAlloc( ptr, size ) ___tracy_emit_memory_alloc( ptr, size );
# define TracyCFree( ptr ) ___tracy_emit_memory_free( ptr );
#endif
void ___tracy_emit_frame_mark( const char* name );
void ___tracy_emit_frame_mark_start( const char* name );
void ___tracy_emit_frame_mark_end( const char* name );
void ___tracy_emit_frame_image( const void* image, uint16_t w, uint16_t h, uint8_t offset, int flip );
#define TracyCFrameMark ___tracy_emit_frame_mark( 0 );
#define TracyCFrameMarkNamed( name ) ___tracy_emit_frame_mark( name );
#define TracyCFrameMarkStart( name ) ___tracy_emit_frame_mark_start( name );
#define TracyCFrameMarkEnd( name ) ___tracy_emit_frame_mark_end( name );
#define TracyCFrameImage( image, width, height, offset, flip ) ___tracy_emit_frame_image( image, width, height, offset, flip );
void ___tracy_emit_plot( const char* name, double val );
void ___tracy_emit_message( const char* txt, size_t size );
void ___tracy_emit_messageL( const char* txt );
void ___tracy_emit_messageC( const char* txt, size_t size, uint32_t color );
void ___tracy_emit_messageLC( const char* txt, uint32_t color );
void ___tracy_emit_message_appinfo( const char* txt, size_t size );
#define TracyCPlot( name, val ) ___tracy_emit_plot( name, val );
#define TracyCMessage( txt, size ) ___tracy_emit_message( txt, size );
#define TracyCMessageL( txt ) ___tracy_emit_messageL( txt );
#define TracyCMessageC( txt, size, color ) ___tracy_emit_messageC( txt, size, color );
#define TracyCMessageLC( txt, color ) ___tracy_emit_messageLC( txt, color );
#define TracyCAppInfo( txt, color ) ___tracy_emit_message_appinfo( txt, color );
#ifdef TRACY_HAS_CALLSTACK
# define TracyCZoneS( ctx, depth, active ) static const struct ___tracy_source_location_data TracyConcat(__tracy_source_location,__LINE__) = { NULL, __FUNCTION__, __FILE__, (uint32_t)__LINE__, 0 }; TracyCZoneCtx ctx = ___tracy_emit_zone_begin_callstack( &TracyConcat(__tracy_source_location,__LINE__), depth, active );
# define TracyCZoneNS( ctx, name, depth, active ) static const struct ___tracy_source_location_data TracyConcat(__tracy_source_location,__LINE__) = { name, __FUNCTION__, __FILE__, (uint32_t)__LINE__, 0 }; TracyCZoneCtx ctx = ___tracy_emit_zone_begin_callstack( &TracyConcat(__tracy_source_location,__LINE__), depth, active );
# define TracyCZoneCS( ctx, color, depth, active ) static const struct ___tracy_source_location_data TracyConcat(__tracy_source_location,__LINE__) = { NULL, __FUNCTION__, __FILE__, (uint32_t)__LINE__, color }; TracyCZoneCtx ctx = ___tracy_emit_zone_begin_callstack( &TracyConcat(__tracy_source_location,__LINE__), depth, active );
# define TracyCZoneNCS( ctx, name, color, depth, active ) static const struct ___tracy_source_location_data TracyConcat(__tracy_source_location,__LINE__) = { name, __FUNCTION__, __FILE__, (uint32_t)__LINE__, color }; TracyCZoneCtx ctx = ___tracy_emit_zone_begin_callstack( &TracyConcat(__tracy_source_location,__LINE__), depth, active );
# define TracyCAllocS( ptr, size, depth ) ___tracy_emit_memory_alloc_callstack( ptr, size, depth )
# define TracyCFreeS( ptr, depth ) ___tracy_emit_memory_alloc_free_callstack( ptr, depth )
#endif
#endif
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -15,33 +15,29 @@
#ifdef TRACY_ENABLE
#ifdef _MSC_VER
# pragma warning(push, 0)
#endif
#include "common/tracy_lz4.cpp"
#include "client/TracyProfiler.cpp"
#include "client/TracyCallstack.cpp"
#include "client/TracySysPower.cpp"
#include "client/TracySysTime.cpp"
#include "client/TracySysTrace.cpp"
#include "common/TracySocket.cpp"
#ifndef TRACY_HAS_CUSTOM_ALLOCATOR
#include "client/tracy_rpmalloc.cpp"
#endif
#include "client/TracyDxt1.cpp"
#include "client/TracyAlloc.cpp"
#include "client/TracyOverride.cpp"
#include "client/TracyKCore.cpp"
#ifdef TRACY_ROCPROF
# include "client/TracyRocprof.cpp"
#if TRACY_HAS_CALLSTACK == 2 || TRACY_HAS_CALLSTACK == 3
# include "libbacktrace/alloc.cpp"
# include "libbacktrace/dwarf.cpp"
# include "libbacktrace/elf.cpp"
# include "libbacktrace/fileline.cpp"
# include "libbacktrace/mmapio.cpp"
# include "libbacktrace/posix.cpp"
# include "libbacktrace/sort.cpp"
# include "libbacktrace/state.cpp"
#endif
#ifdef _MSC_VER
# pragma comment(lib, "ws2_32.lib")
# pragma comment(lib, "advapi32.lib")
# pragma comment(lib, "user32.lib")
# pragma warning(pop)
# pragma comment(lib, "dbghelp.lib")
#endif
#endif

19
TracyClientDLL.cpp Normal file
View File

@@ -0,0 +1,19 @@
//
// Tracy profiler
// ----------------
//
// On multi-DLL projects compile and
// link with this source file (and none
// other) in the executable and in
// DLLs / shared objects that link to
// the main DLL.
//
// Define TRACY_ENABLE to enable profiler.
#ifdef TRACY_ENABLE
# ifndef TRACY_IMPORTS
# define TRACY_IMPORTS 1
# endif
# include "common/TracySystem.cpp"
#endif

550
TracyLua.hpp Normal file
View File

@@ -0,0 +1,550 @@
#ifndef __TRACYLUA_HPP__
#define __TRACYLUA_HPP__
// Include this file after you include lua headers.
#ifndef TRACY_ENABLE
#include <string.h>
namespace tracy
{
namespace detail
{
static inline int noop( lua_State* L ) { return 0; }
}
static inline void LuaRegister( lua_State* L )
{
lua_newtable( L );
lua_pushcfunction( L, detail::noop );
lua_setfield( L, -2, "ZoneBegin" );
lua_pushcfunction( L, detail::noop );
lua_setfield( L, -2, "ZoneBeginN" );
lua_pushcfunction( L, detail::noop );
lua_setfield( L, -2, "ZoneBeginS" );
lua_pushcfunction( L, detail::noop );
lua_setfield( L, -2, "ZoneBeginNS" );
lua_pushcfunction( L, detail::noop );
lua_setfield( L, -2, "ZoneEnd" );
lua_pushcfunction( L, detail::noop );
lua_setfield( L, -2, "ZoneText" );
lua_pushcfunction( L, detail::noop );
lua_setfield( L, -2, "ZoneName" );
lua_pushcfunction( L, detail::noop );
lua_setfield( L, -2, "Message" );
lua_setglobal( L, "tracy" );
}
static inline char* FindEnd( char* ptr )
{
unsigned int cnt = 1;
while( cnt != 0 )
{
if( *ptr == '(' ) cnt++;
else if( *ptr == ')' ) cnt--;
ptr++;
}
return ptr;
}
static inline void LuaRemove( char* script )
{
while( *script )
{
if( strncmp( script, "tracy.", 6 ) == 0 )
{
if( strncmp( script + 6, "Zone", 4 ) == 0 )
{
if( strncmp( script + 10, "End()", 5 ) == 0 )
{
memset( script, ' ', 15 );
script += 15;
}
else if( strncmp( script + 10, "Begin()", 7 ) == 0 )
{
memset( script, ' ', 17 );
script += 17;
}
else if( strncmp( script + 10, "Text(", 5 ) == 0 )
{
auto end = FindEnd( script + 15 );
memset( script, ' ', end - script );
script = end;
}
else if( strncmp( script + 10, "Name(", 5 ) == 0 )
{
auto end = FindEnd( script + 15 );
memset( script, ' ', end - script );
script = end;
}
else if( strncmp( script + 10, "BeginN(", 7 ) == 0 )
{
auto end = FindEnd( script + 17 );
memset( script, ' ', end - script );
script = end;
}
else if( strncmp( script + 10, "BeginS(", 7 ) == 0 )
{
auto end = FindEnd( script + 17 );
memset( script, ' ', end - script );
script = end;
}
else if( strncmp( script + 10, "BeginNS(", 8 ) == 0 )
{
auto end = FindEnd( script + 18 );
memset( script, ' ', end - script );
script = end;
}
else
{
script += 10;
}
}
else if( strncmp( script + 6, "Message(", 8 ) == 0 )
{
auto end = FindEnd( script + 14 );
memset( script, ' ', end - script );
script = end;
}
else
{
script += 6;
}
}
else
{
script++;
}
}
}
}
#else
#include <assert.h>
#include "common/TracyColor.hpp"
#include "common/TracyAlign.hpp"
#include "common/TracyForceInline.hpp"
#include "common/TracySystem.hpp"
#include "client/TracyProfiler.hpp"
namespace tracy
{
#ifdef TRACY_ON_DEMAND
TRACY_API LuaZoneState& GetLuaZoneState();
#endif
namespace detail
{
#ifdef TRACY_HAS_CALLSTACK
static tracy_force_inline void SendLuaCallstack( lua_State* L, uint32_t depth )
{
assert( depth <= 64 );
lua_Debug dbg[64];
const char* func[64];
uint32_t fsz[64];
uint32_t ssz[64];
uint32_t spaceNeeded = 4; // cnt
uint32_t cnt;
for( cnt=0; cnt<depth; cnt++ )
{
if( lua_getstack( L, cnt+1, dbg+cnt ) == 0 ) break;
lua_getinfo( L, "Snl", dbg+cnt );
func[cnt] = dbg[cnt].name ? dbg[cnt].name : dbg[cnt].short_src;
fsz[cnt] = uint32_t( strlen( func[cnt] ) );
ssz[cnt] = uint32_t( strlen( dbg[cnt].source ) );
spaceNeeded += fsz[cnt] + ssz[cnt];
}
spaceNeeded += cnt * ( 4 + 4 + 4 ); // source line, function string length, source string length
auto ptr = (char*)tracy_malloc( spaceNeeded + 4 );
auto dst = ptr;
memcpy( dst, &spaceNeeded, 4 ); dst += 4;
memcpy( dst, &cnt, 4 ); dst += 4;
for( uint32_t i=0; i<cnt; i++ )
{
const uint32_t line = dbg[i].currentline;
memcpy( dst, &line, 4 ); dst += 4;
memcpy( dst, fsz+i, 4 ); dst += 4;
memcpy( dst, func[i], fsz[i] ); dst += fsz[i];
memcpy( dst, ssz+i, 4 ); dst += 4;
memcpy( dst, dbg[i].source, ssz[i] ), dst += ssz[i];
}
assert( dst - ptr == spaceNeeded + 4 );
Magic magic;
auto token = GetToken();
auto& tail = token->get_tail_index();
auto item = token->enqueue_begin( magic );
MemWrite( &item->hdr.type, QueueType::CallstackAlloc );
MemWrite( &item->callstackAlloc.ptr, (uint64_t)ptr );
MemWrite( &item->callstackAlloc.nativePtr, (uint64_t)Callstack( depth ) );
tail.store( magic + 1, std::memory_order_release );
}
static inline int LuaZoneBeginS( lua_State* L )
{
#ifdef TRACY_ON_DEMAND
const auto zoneCnt = GetLuaZoneState().counter++;
if( zoneCnt != 0 && !GetLuaZoneState().active ) return 0;
GetLuaZoneState().active = GetProfiler().IsConnected();
if( !GetLuaZoneState().active ) return 0;
#endif
const uint32_t color = Color::DeepSkyBlue3;
lua_Debug dbg;
lua_getstack( L, 1, &dbg );
lua_getinfo( L, "Snl", &dbg );
const uint32_t line = dbg.currentline;
const auto func = dbg.name ? dbg.name : dbg.short_src;
const auto fsz = strlen( func );
const auto ssz = strlen( dbg.source );
// Data layout:
// 4b payload size
// 4b color
// 4b source line
// fsz function name
// 1b null terminator
// ssz source file name
// 1b null terminator
const uint32_t sz = uint32_t( 4 + 4 + 4 + fsz + 1 + ssz + 1 );
auto ptr = (char*)tracy_malloc( sz );
memcpy( ptr, &sz, 4 );
memcpy( ptr + 4, &color, 4 );
memcpy( ptr + 8, &line, 4 );
memcpy( ptr + 12, func, fsz+1 );
memcpy( ptr + 12 + fsz + 1, dbg.source, ssz + 1 );
Magic magic;
auto token = GetToken();
auto& tail = token->get_tail_index();
auto item = token->enqueue_begin( magic );
MemWrite( &item->hdr.type, QueueType::ZoneBeginAllocSrcLocCallstack );
MemWrite( &item->zoneBegin.time, Profiler::GetTime() );
MemWrite( &item->zoneBegin.srcloc, (uint64_t)ptr );
tail.store( magic + 1, std::memory_order_release );
#ifdef TRACY_CALLSTACK
const uint32_t depth = TRACY_CALLSTACK;
#else
const auto depth = uint32_t( lua_tointeger( L, 1 ) );
#endif
SendLuaCallstack( L, depth );
return 0;
}
static inline int LuaZoneBeginNS( lua_State* L )
{
#ifdef TRACY_ON_DEMAND
const auto zoneCnt = GetLuaZoneState().counter++;
if( zoneCnt != 0 && !GetLuaZoneState().active ) return 0;
GetLuaZoneState().active = GetProfiler().IsConnected();
if( !GetLuaZoneState().active ) return 0;
#endif
const uint32_t color = Color::DeepSkyBlue3;
lua_Debug dbg;
lua_getstack( L, 1, &dbg );
lua_getinfo( L, "Snl", &dbg );
const uint32_t line = dbg.currentline;
const auto func = dbg.name ? dbg.name : dbg.short_src;
size_t nsz;
const auto name = lua_tolstring( L, 1, &nsz );
const auto fsz = strlen( func );
const auto ssz = strlen( dbg.source );
// Data layout:
// 4b payload size
// 4b color
// 4b source line
// fsz function name
// 1b null terminator
// ssz source file name
// 1b null terminator
// nsz zone name
const uint32_t sz = uint32_t( 4 + 4 + 4 + fsz + 1 + ssz + 1 + nsz );
auto ptr = (char*)tracy_malloc( sz );
memcpy( ptr, &sz, 4 );
memcpy( ptr + 4, &color, 4 );
memcpy( ptr + 8, &line, 4 );
memcpy( ptr + 12, func, fsz+1 );
memcpy( ptr + 12 + fsz + 1, dbg.source, ssz + 1 );
memcpy( ptr + 12 + fsz + 1 + ssz + 1, name, nsz );
Magic magic;
auto token = GetToken();
auto& tail = token->get_tail_index();
auto item = token->enqueue_begin( magic );
MemWrite( &item->hdr.type, QueueType::ZoneBeginAllocSrcLocCallstack );
MemWrite( &item->zoneBegin.time, Profiler::GetTime() );
MemWrite( &item->zoneBegin.srcloc, (uint64_t)ptr );
tail.store( magic + 1, std::memory_order_release );
#ifdef TRACY_CALLSTACK
const uint32_t depth = TRACY_CALLSTACK;
#else
const auto depth = uint32_t( lua_tointeger( L, 2 ) );
#endif
SendLuaCallstack( L, depth );
return 0;
}
#endif
static inline int LuaZoneBegin( lua_State* L )
{
#if defined TRACY_HAS_CALLSTACK && defined TRACY_CALLSTACK
return LuaZoneBeginS( L );
#else
#ifdef TRACY_ON_DEMAND
const auto zoneCnt = GetLuaZoneState().counter++;
if( zoneCnt != 0 && !GetLuaZoneState().active ) return 0;
GetLuaZoneState().active = GetProfiler().IsConnected();
if( !GetLuaZoneState().active ) return 0;
#endif
const uint32_t color = Color::DeepSkyBlue3;
lua_Debug dbg;
lua_getstack( L, 1, &dbg );
lua_getinfo( L, "Snl", &dbg );
const uint32_t line = dbg.currentline;
const auto func = dbg.name ? dbg.name : dbg.short_src;
const auto fsz = strlen( func );
const auto ssz = strlen( dbg.source );
// Data layout:
// 4b payload size
// 4b color
// 4b source line
// fsz function name
// 1b null terminator
// ssz source file name
// 1b null terminator
const uint32_t sz = uint32_t( 4 + 4 + 4 + fsz + 1 + ssz + 1 );
auto ptr = (char*)tracy_malloc( sz );
memcpy( ptr, &sz, 4 );
memcpy( ptr + 4, &color, 4 );
memcpy( ptr + 8, &line, 4 );
memcpy( ptr + 12, func, fsz+1 );
memcpy( ptr + 12 + fsz + 1, dbg.source, ssz + 1 );
Magic magic;
auto token = GetToken();
auto& tail = token->get_tail_index();
auto item = token->enqueue_begin( magic );
MemWrite( &item->hdr.type, QueueType::ZoneBeginAllocSrcLoc );
MemWrite( &item->zoneBegin.time, Profiler::GetTime() );
MemWrite( &item->zoneBegin.srcloc, (uint64_t)ptr );
tail.store( magic + 1, std::memory_order_release );
return 0;
#endif
}
static inline int LuaZoneBeginN( lua_State* L )
{
#if defined TRACY_HAS_CALLSTACK && defined TRACY_CALLSTACK
return LuaZoneBeginNS( L );
#else
#ifdef TRACY_ON_DEMAND
const auto zoneCnt = GetLuaZoneState().counter++;
if( zoneCnt != 0 && !GetLuaZoneState().active ) return 0;
GetLuaZoneState().active = GetProfiler().IsConnected();
if( !GetLuaZoneState().active ) return 0;
#endif
const uint32_t color = Color::DeepSkyBlue3;
lua_Debug dbg;
lua_getstack( L, 1, &dbg );
lua_getinfo( L, "Snl", &dbg );
const uint32_t line = dbg.currentline;
const auto func = dbg.name ? dbg.name : dbg.short_src;
size_t nsz;
const auto name = lua_tolstring( L, 1, &nsz );
const auto fsz = strlen( func );
const auto ssz = strlen( dbg.source );
// Data layout:
// 4b payload size
// 4b color
// 4b source line
// fsz function name
// 1b null terminator
// ssz source file name
// 1b null terminator
// nsz zone name
const uint32_t sz = uint32_t( 4 + 4 + 4 + fsz + 1 + ssz + 1 + nsz );
auto ptr = (char*)tracy_malloc( sz );
memcpy( ptr, &sz, 4 );
memcpy( ptr + 4, &color, 4 );
memcpy( ptr + 8, &line, 4 );
memcpy( ptr + 12, func, fsz+1 );
memcpy( ptr + 12 + fsz + 1, dbg.source, ssz + 1 );
memcpy( ptr + 12 + fsz + 1 + ssz + 1, name, nsz );
Magic magic;
auto token = GetToken();
auto& tail = token->get_tail_index();
auto item = token->enqueue_begin( magic );
MemWrite( &item->hdr.type, QueueType::ZoneBeginAllocSrcLoc );
MemWrite( &item->zoneBegin.time, Profiler::GetTime() );
MemWrite( &item->zoneBegin.srcloc, (uint64_t)ptr );
tail.store( magic + 1, std::memory_order_release );
return 0;
#endif
}
static inline int LuaZoneEnd( lua_State* L )
{
#ifdef TRACY_ON_DEMAND
assert( GetLuaZoneState().counter != 0 );
GetLuaZoneState().counter--;
if( !GetLuaZoneState().active ) return 0;
if( !GetProfiler().IsConnected() )
{
GetLuaZoneState().active = false;
return 0;
}
#endif
Magic magic;
auto token = GetToken();
auto& tail = token->get_tail_index();
auto item = token->enqueue_begin( magic );
MemWrite( &item->hdr.type, QueueType::ZoneEnd );
MemWrite( &item->zoneEnd.time, Profiler::GetTime() );
tail.store( magic + 1, std::memory_order_release );
return 0;
}
static inline int LuaZoneText( lua_State* L )
{
#ifdef TRACY_ON_DEMAND
if( !GetLuaZoneState().active ) return 0;
if( !GetProfiler().IsConnected() )
{
GetLuaZoneState().active = false;
return 0;
}
#endif
auto txt = lua_tostring( L, 1 );
const auto size = strlen( txt );
Magic magic;
auto token = GetToken();
auto ptr = (char*)tracy_malloc( size+1 );
memcpy( ptr, txt, size );
ptr[size] = '\0';
auto& tail = token->get_tail_index();
auto item = token->enqueue_begin( magic );
MemWrite( &item->hdr.type, QueueType::ZoneText );
MemWrite( &item->zoneText.text, (uint64_t)ptr );
tail.store( magic + 1, std::memory_order_release );
return 0;
}
static inline int LuaZoneName( lua_State* L )
{
#ifdef TRACY_ON_DEMAND
if( !GetLuaZoneState().active ) return 0;
if( !GetProfiler().IsConnected() )
{
GetLuaZoneState().active = false;
return 0;
}
#endif
auto txt = lua_tostring( L, 1 );
const auto size = strlen( txt );
Magic magic;
auto token = GetToken();
auto ptr = (char*)tracy_malloc( size+1 );
memcpy( ptr, txt, size );
ptr[size] = '\0';
auto& tail = token->get_tail_index();
auto item = token->enqueue_begin( magic );
MemWrite( &item->hdr.type, QueueType::ZoneName );
MemWrite( &item->zoneText.text, (uint64_t)ptr );
tail.store( magic + 1, std::memory_order_release );
return 0;
}
static inline int LuaMessage( lua_State* L )
{
#ifdef TRACY_ON_DEMAND
if( !GetProfiler().IsConnected() ) return 0;
#endif
auto txt = lua_tostring( L, 1 );
const auto size = strlen( txt );
Magic magic;
auto token = GetToken();
auto ptr = (char*)tracy_malloc( size+1 );
memcpy( ptr, txt, size );
ptr[size] = '\0';
auto& tail = token->get_tail_index();
auto item = token->enqueue_begin( magic );
MemWrite( &item->hdr.type, QueueType::Message );
MemWrite( &item->message.time, Profiler::GetTime() );
MemWrite( &item->message.text, (uint64_t)ptr );
tail.store( magic + 1, std::memory_order_release );
return 0;
}
}
static inline void LuaRegister( lua_State* L )
{
lua_newtable( L );
lua_pushcfunction( L, detail::LuaZoneBegin );
lua_setfield( L, -2, "ZoneBegin" );
lua_pushcfunction( L, detail::LuaZoneBeginN );
lua_setfield( L, -2, "ZoneBeginN" );
#ifdef TRACY_HAS_CALLSTACK
lua_pushcfunction( L, detail::LuaZoneBeginS );
lua_setfield( L, -2, "ZoneBeginS" );
lua_pushcfunction( L, detail::LuaZoneBeginNS );
lua_setfield( L, -2, "ZoneBeginNS" );
#else
lua_pushcfunction( L, detail::LuaZoneBegin );
lua_setfield( L, -2, "ZoneBeginS" );
lua_pushcfunction( L, detail::LuaZoneBeginN );
lua_setfield( L, -2, "ZoneBeginNS" );
#endif
lua_pushcfunction( L, detail::LuaZoneEnd );
lua_setfield( L, -2, "ZoneEnd" );
lua_pushcfunction( L, detail::LuaZoneText );
lua_setfield( L, -2, "ZoneText" );
lua_pushcfunction( L, detail::LuaZoneName );
lua_setfield( L, -2, "ZoneName" );
lua_pushcfunction( L, detail::LuaMessage );
lua_setfield( L, -2, "Message" );
lua_setglobal( L, "tracy" );
}
static inline void LuaRemove( char* script ) {}
}
#endif
#endif

271
TracyOpenGL.hpp Normal file
View File

@@ -0,0 +1,271 @@
#ifndef __TRACYOPENGL_HPP__
#define __TRACYOPENGL_HPP__
// Include this file after you include OpenGL 3.2 headers.
#if !defined TRACY_ENABLE || defined __APPLE__
#define TracyGpuContext
#define TracyGpuNamedZone(x,y)
#define TracyGpuNamedZoneC(x,y,z)
#define TracyGpuZone(x)
#define TracyGpuZoneC(x,y)
#define TracyGpuCollect
#define TracyGpuNamedZoneS(x,y,z)
#define TracyGpuNamedZoneCS(x,y,z,w)
#define TracyGpuZoneS(x,y)
#define TracyGpuZoneCS(x,y,z)
namespace tracy
{
struct SourceLocationData;
class GpuCtxScope
{
public:
GpuCtxScope( const SourceLocationData* ) {}
GpuCtxScope( const SourceLocationData*, int depth ) {}
};
}
#else
#include <atomic>
#include <assert.h>
#include <stdlib.h>
#include "Tracy.hpp"
#include "client/TracyProfiler.hpp"
#include "client/TracyCallstack.hpp"
#include "common/TracyAlign.hpp"
#include "common/TracyAlloc.hpp"
#if !defined GL_TIMESTAMP && defined GL_TIMESTAMP_EXT
# define GL_TIMESTAMP GL_TIMESTAMP_EXT
# define GL_QUERY_COUNTER_BITS GL_QUERY_COUNTER_BITS_EXT
# define glGetQueryObjectiv glGetQueryObjectivEXT
# define glGetQueryObjectui64v glGetQueryObjectui64vEXT
# define glQueryCounter glQueryCounterEXT
#endif
#define TracyGpuContext tracy::GetGpuCtx().ptr = (tracy::GpuCtx*)tracy::tracy_malloc( sizeof( tracy::GpuCtx ) ); new(tracy::GetGpuCtx().ptr) tracy::GpuCtx;
#if defined TRACY_HAS_CALLSTACK && defined TRACY_CALLSTACK
# define TracyGpuNamedZone( varname, name ) static const tracy::SourceLocationData TracyConcat(__tracy_gpu_source_location,__LINE__) { name, __FUNCTION__, __FILE__, (uint32_t)__LINE__, 0 }; tracy::GpuCtxScope varname( &TracyConcat(__tracy_gpu_source_location,__LINE__), TRACY_CALLSTACK );
# define TracyGpuNamedZoneC( varname, name, color ) static const tracy::SourceLocationData TracyConcat(__tracy_gpu_source_location,__LINE__) { name, __FUNCTION__, __FILE__, (uint32_t)__LINE__, color }; tracy::GpuCtxScope varname( &TracyConcat(__tracy_gpu_source_location,__LINE__), TRACY_CALLSTACK );
# define TracyGpuZone( name ) TracyGpuNamedZoneS( ___tracy_gpu_zone, name, TRACY_CALLSTACK )
# define TracyGpuZoneC( name, color ) TracyGpuNamedZoneCS( ___tracy_gpu_zone, name, color, TRACY_CALLSTACK )
#else
# define TracyGpuNamedZone( varname, name ) static const tracy::SourceLocationData TracyConcat(__tracy_gpu_source_location,__LINE__) { name, __FUNCTION__, __FILE__, (uint32_t)__LINE__, 0 }; tracy::GpuCtxScope varname( &TracyConcat(__tracy_gpu_source_location,__LINE__) );
# define TracyGpuNamedZoneC( varname, name, color ) static const tracy::SourceLocationData TracyConcat(__tracy_gpu_source_location,__LINE__) { name, __FUNCTION__, __FILE__, (uint32_t)__LINE__, color }; tracy::GpuCtxScope varname( &TracyConcat(__tracy_gpu_source_location,__LINE__) );
# define TracyGpuZone( name ) TracyGpuNamedZone( ___tracy_gpu_zone, name )
# define TracyGpuZoneC( name, color ) TracyGpuNamedZoneC( ___tracy_gpu_zone, name, color )
#endif
#define TracyGpuCollect tracy::GetGpuCtx().ptr->Collect();
#ifdef TRACY_HAS_CALLSTACK
# define TracyGpuNamedZoneS( varname, name, depth ) static const tracy::SourceLocationData TracyConcat(__tracy_gpu_source_location,__LINE__) { name, __FUNCTION__, __FILE__, (uint32_t)__LINE__, 0 }; tracy::GpuCtxScope varname( &TracyConcat(__tracy_gpu_source_location,__LINE__), depth );
# define TracyGpuNamedZoneCS( varname, name, color, depth ) static const tracy::SourceLocationData TracyConcat(__tracy_gpu_source_location,__LINE__) { name, __FUNCTION__, __FILE__, (uint32_t)__LINE__, color }; tracy::GpuCtxScope varname( &TracyConcat(__tracy_gpu_source_location,__LINE__), depth );
# define TracyGpuZoneS( name, depth ) TracyGpuNamedZoneS( ___tracy_gpu_zone, name, depth )
# define TracyGpuZoneCS( name, color, depth ) TracyGpuNamedZoneCS( ___tracy_gpu_zone, name, color, depth )
#else
# define TracyGpuNamedZoneS( varname, name, depth ) TracyGpuNamedZone( varname, name )
# define TracyGpuNamedZoneCS( varname, name, color, depth ) TracyGpuNamedZoneC( varname, name, color )
# define TracyGpuZoneS( name, depth ) TracyGpuZone( name )
# define TracyGpuZoneCS( name, color, depth ) TracyGpuZoneC( name, color )
#endif
namespace tracy
{
class GpuCtx
{
friend class GpuCtxScope;
enum { QueryCount = 64 * 1024 };
public:
GpuCtx()
: m_context( GetGpuCtxCounter().fetch_add( 1, std::memory_order_relaxed ) )
, m_head( 0 )
, m_tail( 0 )
{
assert( m_context != 255 );
glGenQueries( QueryCount, m_query );
int64_t tgpu;
glGetInteger64v( GL_TIMESTAMP, &tgpu );
int64_t tcpu = Profiler::GetTime();
GLint bits;
glGetQueryiv( GL_TIMESTAMP, GL_QUERY_COUNTER_BITS, &bits );
const float period = 1.f;
Magic magic;
const auto thread = GetThreadHandle();
auto token = GetToken();
auto& tail = token->get_tail_index();
auto item = token->enqueue_begin( magic );
MemWrite( &item->hdr.type, QueueType::GpuNewContext );
MemWrite( &item->gpuNewContext.cpuTime, tcpu );
MemWrite( &item->gpuNewContext.gpuTime, tgpu );
MemWrite( &item->gpuNewContext.thread, thread );
MemWrite( &item->gpuNewContext.period, period );
MemWrite( &item->gpuNewContext.context, m_context );
MemWrite( &item->gpuNewContext.accuracyBits, (uint8_t)bits );
#ifdef TRACY_ON_DEMAND
GetProfiler().DeferItem( *item );
#endif
tail.store( magic + 1, std::memory_order_release );
}
void Collect()
{
ZoneScopedC( Color::Red4 );
if( m_tail == m_head ) return;
#ifdef TRACY_ON_DEMAND
if( !GetProfiler().IsConnected() )
{
m_head = m_tail = 0;
return;
}
#endif
Magic magic;
auto token = GetToken();
auto& tail = token->get_tail_index();
while( m_tail != m_head )
{
GLint available;
glGetQueryObjectiv( m_query[m_tail], GL_QUERY_RESULT_AVAILABLE, &available );
if( !available ) return;
uint64_t time;
glGetQueryObjectui64v( m_query[m_tail], GL_QUERY_RESULT, &time );
auto item = token->enqueue_begin( magic );
MemWrite( &item->hdr.type, QueueType::GpuTime );
MemWrite( &item->gpuTime.gpuTime, (int64_t)time );
MemWrite( &item->gpuTime.queryId, (uint16_t)m_tail );
MemWrite( &item->gpuTime.context, m_context );
tail.store( magic + 1, std::memory_order_release );
m_tail = ( m_tail + 1 ) % QueryCount;
}
}
private:
tracy_force_inline unsigned int NextQueryId()
{
const auto id = m_head;
m_head = ( m_head + 1 ) % QueryCount;
assert( m_head != m_tail );
return id;
}
tracy_force_inline unsigned int TranslateOpenGlQueryId( unsigned int id )
{
return m_query[id];
}
tracy_force_inline uint8_t GetId() const
{
return m_context;
}
unsigned int m_query[QueryCount];
uint8_t m_context;
unsigned int m_head;
unsigned int m_tail;
};
class GpuCtxScope
{
public:
tracy_force_inline GpuCtxScope( const SourceLocationData* srcloc )
#ifdef TRACY_ON_DEMAND
: m_active( GetProfiler().IsConnected() )
#endif
{
#ifdef TRACY_ON_DEMAND
if( !m_active ) return;
#endif
const auto queryId = GetGpuCtx().ptr->NextQueryId();
glQueryCounter( GetGpuCtx().ptr->TranslateOpenGlQueryId( queryId ), GL_TIMESTAMP );
Magic magic;
auto token = GetToken();
auto& tail = token->get_tail_index();
auto item = token->enqueue_begin( magic );
MemWrite( &item->hdr.type, QueueType::GpuZoneBegin );
MemWrite( &item->gpuZoneBegin.cpuTime, Profiler::GetTime() );
MemWrite( &item->gpuZoneBegin.srcloc, (uint64_t)srcloc );
memset( &item->gpuZoneBegin.thread, 0, sizeof( item->gpuZoneBegin.thread ) );
MemWrite( &item->gpuZoneBegin.queryId, uint16_t( queryId ) );
MemWrite( &item->gpuZoneBegin.context, GetGpuCtx().ptr->GetId() );
tail.store( magic + 1, std::memory_order_release );
}
tracy_force_inline GpuCtxScope( const SourceLocationData* srcloc, int depth )
#ifdef TRACY_ON_DEMAND
: m_active( GetProfiler().IsConnected() )
#endif
{
#ifdef TRACY_ON_DEMAND
if( !m_active ) return;
#endif
const auto queryId = GetGpuCtx().ptr->NextQueryId();
glQueryCounter( GetGpuCtx().ptr->TranslateOpenGlQueryId( queryId ), GL_TIMESTAMP );
Magic magic;
const auto thread = GetThreadHandle();
auto token = GetToken();
auto& tail = token->get_tail_index();
auto item = token->enqueue_begin( magic );
MemWrite( &item->hdr.type, QueueType::GpuZoneBeginCallstack );
MemWrite( &item->gpuZoneBegin.cpuTime, Profiler::GetTime() );
MemWrite( &item->gpuZoneBegin.srcloc, (uint64_t)srcloc );
MemWrite( &item->gpuZoneBegin.thread, thread );
MemWrite( &item->gpuZoneBegin.queryId, uint16_t( queryId ) );
MemWrite( &item->gpuZoneBegin.context, GetGpuCtx().ptr->GetId() );
tail.store( magic + 1, std::memory_order_release );
GetProfiler().SendCallstack( depth );
}
tracy_force_inline ~GpuCtxScope()
{
#ifdef TRACY_ON_DEMAND
if( !m_active ) return;
#endif
const auto queryId = GetGpuCtx().ptr->NextQueryId();
glQueryCounter( GetGpuCtx().ptr->TranslateOpenGlQueryId( queryId ), GL_TIMESTAMP );
Magic magic;
auto token = GetToken();
auto& tail = token->get_tail_index();
auto item = token->enqueue_begin( magic );
MemWrite( &item->hdr.type, QueueType::GpuZoneEnd );
MemWrite( &item->gpuZoneEnd.cpuTime, Profiler::GetTime() );
MemWrite( &item->gpuZoneEnd.queryId, uint16_t( queryId ) );
MemWrite( &item->gpuZoneEnd.context, GetGpuCtx().ptr->GetId() );
tail.store( magic + 1, std::memory_order_release );
}
private:
#ifdef TRACY_ON_DEMAND
const bool m_active;
#endif
};
}
#endif
#endif

339
TracyVulkan.hpp Normal file
View File

@@ -0,0 +1,339 @@
#ifndef __TRACYVULKAN_HPP__
#define __TRACYVULKAN_HPP__
#if !defined TRACY_ENABLE
#define TracyVkContext(x,y,z,w) nullptr
#define TracyVkDestroy(x)
#define TracyVkNamedZone(c,x,y,z)
#define TracyVkNamedZoneC(c,x,y,z,w)
#define TracyVkZone(c,x,y)
#define TracyVkZoneC(c,x,y,z)
#define TracyVkCollect(c,x)
#define TracyVkNamedZoneS(c,x,y,z,w)
#define TracyVkNamedZoneCS(c,x,y,z,w,v)
#define TracyVkZoneS(c,x,y,z)
#define TracyVkZoneCS(c,x,y,z,w)
namespace tracy
{
class VkCtxScope {};
}
using TracyVkCtx = void*;
#else
#include <assert.h>
#include <stdlib.h>
#include <vulkan/vulkan.h>
#include "Tracy.hpp"
#include "client/TracyProfiler.hpp"
#include "client/TracyCallstack.hpp"
namespace tracy
{
class VkCtx
{
friend class VkCtxScope;
enum { QueryCount = 64 * 1024 };
public:
VkCtx( VkPhysicalDevice physdev, VkDevice device, VkQueue queue, VkCommandBuffer cmdbuf )
: m_device( device )
, m_context( GetGpuCtxCounter().fetch_add( 1, std::memory_order_relaxed ) )
, m_head( 0 )
, m_tail( 0 )
, m_oldCnt( 0 )
, m_queryCount( QueryCount )
{
assert( m_context != 255 );
VkPhysicalDeviceProperties prop;
vkGetPhysicalDeviceProperties( physdev, &prop );
const float period = prop.limits.timestampPeriod;
VkQueryPoolCreateInfo poolInfo = {};
poolInfo.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO;
poolInfo.queryCount = m_queryCount;
poolInfo.queryType = VK_QUERY_TYPE_TIMESTAMP;
while( vkCreateQueryPool( device, &poolInfo, nullptr, &m_query ) != VK_SUCCESS )
{
m_queryCount /= 2;
poolInfo.queryCount = m_queryCount;
}
VkCommandBufferBeginInfo beginInfo = {};
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
VkSubmitInfo submitInfo = {};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &cmdbuf;
vkBeginCommandBuffer( cmdbuf, &beginInfo );
vkCmdResetQueryPool( cmdbuf, m_query, 0, m_queryCount );
vkEndCommandBuffer( cmdbuf );
vkQueueSubmit( queue, 1, &submitInfo, VK_NULL_HANDLE );
vkQueueWaitIdle( queue );
vkBeginCommandBuffer( cmdbuf, &beginInfo );
vkCmdWriteTimestamp( cmdbuf, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, m_query, 0 );
vkEndCommandBuffer( cmdbuf );
vkQueueSubmit( queue, 1, &submitInfo, VK_NULL_HANDLE );
vkQueueWaitIdle( queue );
int64_t tcpu = Profiler::GetTime();
int64_t tgpu;
vkGetQueryPoolResults( device, m_query, 0, 1, sizeof( tgpu ), &tgpu, sizeof( tgpu ), VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT );
vkBeginCommandBuffer( cmdbuf, &beginInfo );
vkCmdResetQueryPool( cmdbuf, m_query, 0, 1 );
vkEndCommandBuffer( cmdbuf );
vkQueueSubmit( queue, 1, &submitInfo, VK_NULL_HANDLE );
vkQueueWaitIdle( queue );
Magic magic;
auto token = GetToken();
auto& tail = token->get_tail_index();
auto item = token->enqueue_begin( magic );
MemWrite( &item->hdr.type, QueueType::GpuNewContext );
MemWrite( &item->gpuNewContext.cpuTime, tcpu );
MemWrite( &item->gpuNewContext.gpuTime, tgpu );
memset( &item->gpuNewContext.thread, 0, sizeof( item->gpuNewContext.thread ) );
MemWrite( &item->gpuNewContext.period, period );
MemWrite( &item->gpuNewContext.context, m_context );
MemWrite( &item->gpuNewContext.accuracyBits, uint8_t( 0 ) );
#ifdef TRACY_ON_DEMAND
GetProfiler().DeferItem( *item );
#endif
tail.store( magic + 1, std::memory_order_release );
m_res = (int64_t*)tracy_malloc( sizeof( int64_t ) * m_queryCount );
}
~VkCtx()
{
tracy_free( m_res );
vkDestroyQueryPool( m_device, m_query, nullptr );
}
void Collect( VkCommandBuffer cmdbuf )
{
ZoneScopedC( Color::Red4 );
if( m_tail == m_head ) return;
#ifdef TRACY_ON_DEMAND
if( !GetProfiler().IsConnected() )
{
vkCmdResetQueryPool( cmdbuf, m_query, 0, m_queryCount );
m_head = m_tail = 0;
return;
}
#endif
unsigned int cnt;
if( m_oldCnt != 0 )
{
cnt = m_oldCnt;
m_oldCnt = 0;
}
else
{
cnt = m_head < m_tail ? m_queryCount - m_tail : m_head - m_tail;
}
if( vkGetQueryPoolResults( m_device, m_query, m_tail, cnt, sizeof( int64_t ) * m_queryCount, m_res, sizeof( int64_t ), VK_QUERY_RESULT_64_BIT ) == VK_NOT_READY )
{
m_oldCnt = cnt;
return;
}
Magic magic;
auto token = GetToken();
auto& tail = token->get_tail_index();
for( unsigned int idx=0; idx<cnt; idx++ )
{
auto item = token->enqueue_begin( magic );
MemWrite( &item->hdr.type, QueueType::GpuTime );
MemWrite( &item->gpuTime.gpuTime, m_res[idx] );
MemWrite( &item->gpuTime.queryId, uint16_t( m_tail + idx ) );
MemWrite( &item->gpuTime.context, m_context );
tail.store( magic + 1, std::memory_order_release );
}
vkCmdResetQueryPool( cmdbuf, m_query, m_tail, cnt );
m_tail += cnt;
if( m_tail == m_queryCount ) m_tail = 0;
}
private:
tracy_force_inline unsigned int NextQueryId()
{
const auto id = m_head;
m_head = ( m_head + 1 ) % m_queryCount;
assert( m_head != m_tail );
return id;
}
tracy_force_inline uint8_t GetId() const
{
return m_context;
}
VkDevice m_device;
VkQueryPool m_query;
uint8_t m_context;
unsigned int m_head;
unsigned int m_tail;
unsigned int m_oldCnt;
unsigned int m_queryCount;
int64_t* m_res;
};
class VkCtxScope
{
public:
tracy_force_inline VkCtxScope( VkCtx* ctx, const SourceLocationData* srcloc, VkCommandBuffer cmdbuf )
: m_cmdbuf( cmdbuf )
, m_ctx( ctx )
#ifdef TRACY_ON_DEMAND
, m_active( GetProfiler().IsConnected() )
#endif
{
#ifdef TRACY_ON_DEMAND
if( !m_active ) return;
#endif
const auto queryId = ctx->NextQueryId();
vkCmdWriteTimestamp( cmdbuf, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, ctx->m_query, queryId );
Magic magic;
const auto thread = GetThreadHandle();
auto token = GetToken();
auto& tail = token->get_tail_index();
auto item = token->enqueue_begin( magic );
MemWrite( &item->hdr.type, QueueType::GpuZoneBegin );
MemWrite( &item->gpuZoneBegin.cpuTime, Profiler::GetTime() );
MemWrite( &item->gpuZoneBegin.srcloc, (uint64_t)srcloc );
MemWrite( &item->gpuZoneBegin.thread, thread );
MemWrite( &item->gpuZoneBegin.queryId, uint16_t( queryId ) );
MemWrite( &item->gpuZoneBegin.context, ctx->GetId() );
tail.store( magic + 1, std::memory_order_release );
}
tracy_force_inline VkCtxScope( VkCtx* ctx, const SourceLocationData* srcloc, VkCommandBuffer cmdbuf, int depth )
: m_cmdbuf( cmdbuf )
, m_ctx( ctx )
#ifdef TRACY_ON_DEMAND
, m_active( GetProfiler().IsConnected() )
#endif
{
#ifdef TRACY_ON_DEMAND
if( !m_active ) return;
#endif
const auto queryId = ctx->NextQueryId();
vkCmdWriteTimestamp( cmdbuf, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, ctx->m_query, queryId );
Magic magic;
const auto thread = GetThreadHandle();
auto token = GetToken();
auto& tail = token->get_tail_index();
auto item = token->enqueue_begin( magic );
MemWrite( &item->hdr.type, QueueType::GpuZoneBeginCallstack );
MemWrite( &item->gpuZoneBegin.cpuTime, Profiler::GetTime() );
MemWrite( &item->gpuZoneBegin.srcloc, (uint64_t)srcloc );
MemWrite( &item->gpuZoneBegin.thread, thread );
MemWrite( &item->gpuZoneBegin.queryId, uint16_t( queryId ) );
MemWrite( &item->gpuZoneBegin.context, ctx->GetId() );
tail.store( magic + 1, std::memory_order_release );
GetProfiler().SendCallstack( depth );
}
tracy_force_inline ~VkCtxScope()
{
#ifdef TRACY_ON_DEMAND
if( !m_active ) return;
#endif
const auto queryId = m_ctx->NextQueryId();
vkCmdWriteTimestamp( m_cmdbuf, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, m_ctx->m_query, queryId );
Magic magic;
auto token = GetToken();
auto& tail = token->get_tail_index();
auto item = token->enqueue_begin( magic );
MemWrite( &item->hdr.type, QueueType::GpuZoneEnd );
MemWrite( &item->gpuZoneEnd.cpuTime, Profiler::GetTime() );
MemWrite( &item->gpuZoneEnd.queryId, uint16_t( queryId ) );
MemWrite( &item->gpuZoneEnd.context, m_ctx->GetId() );
tail.store( magic + 1, std::memory_order_release );
}
private:
VkCommandBuffer m_cmdbuf;
VkCtx* m_ctx;
#ifdef TRACY_ON_DEMAND
const bool m_active;
#endif
};
static inline VkCtx* CreateVkContext( VkPhysicalDevice physdev, VkDevice device, VkQueue queue, VkCommandBuffer cmdbuf )
{
auto ctx = (VkCtx*)tracy_malloc( sizeof( VkCtx ) );
new(ctx) VkCtx( physdev, device, queue, cmdbuf );
return ctx;
}
static inline void DestroyVkContext( VkCtx* ctx )
{
ctx->~VkCtx();
tracy_free( ctx );
}
}
using TracyVkCtx = tracy::VkCtx*;
#define TracyVkContext( physdev, device, queue, cmdbuf ) tracy::CreateVkContext( physdev, device, queue, cmdbuf );
#define TracyVkDestroy( ctx ) tracy::DestroyVkContext( ctx );
#if defined TRACY_HAS_CALLSTACK && defined TRACY_CALLSTACK
# define TracyVkNamedZone( ctx, varname, cmdbuf, name ) static const tracy::SourceLocationData TracyConcat(__tracy_gpu_source_location,__LINE__) { name, __FUNCTION__, __FILE__, (uint32_t)__LINE__, 0 }; tracy::VkCtxScope varname( ctx, &TracyConcat(__tracy_gpu_source_location,__LINE__), cmdbuf, TRACY_CALLSTACK );
# define TracyVkNamedZoneC( ctx, varname, cmdbuf, name, color ) static const tracy::SourceLocationData TracyConcat(__tracy_gpu_source_location,__LINE__) { name, __FUNCTION__, __FILE__, (uint32_t)__LINE__, color }; tracy::VkCtxScope varname( ctx, &TracyConcat(__tracy_gpu_source_location,__LINE__), cmdbuf, TRACY_CALLSTACK );
# define TracyVkZone( ctx, cmdbuf, name ) TracyVkNamedZoneS( ctx, ___tracy_gpu_zone, cmdbuf, name, TRACY_CALLSTACK )
# define TracyVkZoneC( ctx, cmdbuf, name, color ) TracyVkNamedZoneCS( ctx, ___tracy_gpu_zone, cmdbuf, name, color, TRACY_CALLSTACK )
#else
# define TracyVkNamedZone( ctx, varname, cmdbuf, name ) static const tracy::SourceLocationData TracyConcat(__tracy_gpu_source_location,__LINE__) { name, __FUNCTION__, __FILE__, (uint32_t)__LINE__, 0 }; tracy::VkCtxScope varname( ctx, &TracyConcat(__tracy_gpu_source_location,__LINE__), cmdbuf );
# define TracyVkNamedZoneC( ctx, varname, cmdbuf, name, color ) static const tracy::SourceLocationData TracyConcat(__tracy_gpu_source_location,__LINE__) { name, __FUNCTION__, __FILE__, (uint32_t)__LINE__, color }; tracy::VkCtxScope varname( ctx, &TracyConcat(__tracy_gpu_source_location,__LINE__), cmdbuf );
# define TracyVkZone( ctx, cmdbuf, name ) TracyVkNamedZone( ctx, ___tracy_gpu_zone, cmdbuf, name )
# define TracyVkZoneC( ctx, cmdbuf, name, color ) TracyVkNamedZoneC( ctx, ___tracy_gpu_zone, cmdbuf, name, color )
#endif
#define TracyVkCollect( ctx, cmdbuf ) ctx->Collect( cmdbuf );
#ifdef TRACY_HAS_CALLSTACK
# define TracyVkNamedZoneS( ctx, varname, cmdbuf, name, depth ) static const tracy::SourceLocationData TracyConcat(__tracy_gpu_source_location,__LINE__) { name, __FUNCTION__, __FILE__, (uint32_t)__LINE__, 0 }; tracy::VkCtxScope varname( ctx, &TracyConcat(__tracy_gpu_source_location,__LINE__), cmdbuf, depth );
# define TracyVkNamedZoneCS( ctx, varname, cmdbuf, name, color, depth ) static const tracy::SourceLocationData TracyConcat(__tracy_gpu_source_location,__LINE__) { name, __FUNCTION__, __FILE__, (uint32_t)__LINE__, color }; tracy::VkCtxScope varname( ctx, &TracyConcat(__tracy_gpu_source_location,__LINE__), cmdbuf, depth );
# define TracyVkZoneS( ctx, cmdbuf, name, depth ) TracyVkNamedZoneS( ctx, ___tracy_gpu_zone, cmdbuf, name, depth )
# define TracyVkZoneCS( ctx, cmdbuf, name, color, depth ) TracyVkNamedZoneCS( ctx, ___tracy_gpu_zone, cmdbuf, name, color, depth )
#else
# define TracyVkNamedZoneS( ctx, varname, cmdbuf, name, depth ) TracyVkNamedZone( ctx, varname, cmdbuf, name )
# define TracyVkNamedZoneCS( ctx, varname, cmdbuf, name, color, depth ) TracyVkNamedZoneC( ctx, varname, cmdbuf, name, color )
# define TracyVkZoneS( ctx, cmdbuf, name, depth ) TracyVkZone( ctx, cmdbuf, name )
# define TracyVkZoneCS( ctx, cmdbuf, name, color, depth ) TracyVkZoneC( ctx, cmdbuf, name, color )
#endif
#endif
#endif

View File

@@ -1,36 +0,0 @@
cmake_minimum_required(VERSION 3.16)
set(NO_STATISTICS ON)
include(${CMAKE_CURRENT_LIST_DIR}/../cmake/version.cmake)
set(CMAKE_CXX_STANDARD 20)
project(
tracy-capture
LANGUAGES C CXX
VERSION ${TRACY_VERSION_STRING}
)
include(${CMAKE_CURRENT_LIST_DIR}/../cmake/config.cmake)
include(${CMAKE_CURRENT_LIST_DIR}/../cmake/vendor.cmake)
include(${CMAKE_CURRENT_LIST_DIR}/../cmake/server.cmake)
include(${CMAKE_CURRENT_LIST_DIR}/../cmake/GitRef.cmake)
set(PROGRAM_FILES
src/capture.cpp
src/CaptureOutput.cpp
)
add_executable(${PROJECT_NAME} ${PROGRAM_FILES} ${COMMON_FILES} ${SERVER_FILES})
add_git_ref(${PROJECT_NAME})
target_link_libraries(${PROJECT_NAME} PRIVATE TracyServer TracyGetOpt)
set_property(DIRECTORY ${CMAKE_CURRENT_LIST_DIR} PROPERTY VS_STARTUP_PROJECT ${PROJECT_NAME})
install(TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR})
add_executable(tracy-capture-daemon src/capturedaemon.cpp src/CaptureOutput.cpp ${COMMON_FILES} ${SERVER_FILES})
add_git_ref(tracy-capture-daemon)
target_link_libraries(tracy-capture-daemon PRIVATE TracyServer TracyGetOpt)
install(TARGETS tracy-capture-daemon DESTINATION ${CMAKE_INSTALL_BINDIR})

View File

@@ -1,31 +0,0 @@
{
"version": 10,
"configurePresets": [
{
"name": "common",
"hidden": true,
"binaryDir": "${sourceDir}/build-${presetName}",
"generator": "Ninja",
"cacheVariables": {
"CMAKE_EXPORT_COMPILE_COMMANDS": "ON"
}
},
{
"name": "debug",
"displayName": "Debug configuration",
"inherits": "common",
"binaryDir": "${sourceDir}/build",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug"
}
},
{
"name": "release",
"displayName": "Release configuration",
"inherits": "common",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release"
}
}
]
}

View File

@@ -0,0 +1,12 @@
all: debug
debug:
@+make -f debug.mk all
release:
@+make -f release.mk all
clean:
@+make -f build.mk clean
.PHONY: all clean debug release

View File

@@ -0,0 +1,60 @@
CFLAGS +=
CXXFLAGS := $(CFLAGS) -std=gnu++17
DEFINES += -DTRACY_NO_STATISTICS
INCLUDES :=
LIBS := -lpthread
PROJECT := capture
IMAGE := $(PROJECT)-$(BUILD)
FILTER :=
BASE := $(shell egrep 'ClCompile.*cpp"' ../win32/$(PROJECT).vcxproj | sed -e 's/.*\"\(.*\)\".*/\1/' | sed -e 's@\\@/@g')
BASE2 := $(shell egrep 'ClCompile.*c"' ../win32/$(PROJECT).vcxproj | sed -e 's/.*\"\(.*\)\".*/\1/' | sed -e 's@\\@/@g')
SRC := $(filter-out $(FILTER),$(BASE))
SRC2 := $(filter-out $(FILTER),$(BASE2))
TBB := $(shell ld -ltbb -o /dev/null 2>/dev/null; echo $$?)
ifeq ($(TBB),0)
LIBS += -ltbb
endif
OBJDIRBASE := obj/$(BUILD)
OBJDIR := $(OBJDIRBASE)/o/o/o
OBJ := $(addprefix $(OBJDIR)/,$(SRC:%.cpp=%.o))
OBJ2 := $(addprefix $(OBJDIR)/,$(SRC2:%.c=%.o))
all: $(IMAGE)
$(OBJDIR)/%.o: %.cpp
$(CXX) -c $(INCLUDES) $(CXXFLAGS) $(DEFINES) $< -o $@
$(OBJDIR)/%.d : %.cpp
@echo Resolving dependencies of $<
@mkdir -p $(@D)
@$(CXX) -MM $(INCLUDES) $(CXXFLAGS) $(DEFINES) $< > $@.$$$$; \
sed 's,.*\.o[ :]*,$(OBJDIR)/$(<:.cpp=.o) $@ : ,g' < $@.$$$$ > $@; \
rm -f $@.$$$$
$(OBJDIR)/%.o: %.c
$(CC) -c $(INCLUDES) $(CFLAGS) $(DEFINES) $< -o $@
$(OBJDIR)/%.d : %.c
@echo Resolving dependencies of $<
@mkdir -p $(@D)
@$(CC) -MM $(INCLUDES) $(CFLAGS) $(DEFINES) $< > $@.$$$$; \
sed 's,.*\.o[ :]*,$(OBJDIR)/$(<:.c=.o) $@ : ,g' < $@.$$$$ > $@; \
rm -f $@.$$$$
$(IMAGE): $(OBJ) $(OBJ2)
$(CXX) $(CXXFLAGS) $(DEFINES) $(OBJ) $(OBJ2) $(LIBS) -o $@
ifneq "$(MAKECMDGOALS)" "clean"
-include $(addprefix $(OBJDIR)/,$(SRC:.cpp=.d)) %(addprefix $(OBJDIR)/,$(SRC2:.c=.d))
endif
clean:
rm -rf $(OBJDIRBASE) $(IMAGE)*
.PHONY: clean all

View File

@@ -0,0 +1,11 @@
ARCH := $(shell uname -m)
CFLAGS := -g3 -Wall
DEFINES := -DDEBUG
BUILD := debug
ifeq ($(ARCH),x86_64)
CFLAGS += -msse4.1
endif
include build.mk

View File

@@ -0,0 +1,11 @@
ARCH := $(shell uname -m)
CFLAGS := -O3 -s -fomit-frame-pointer
DEFINES := -DNDEBUG
BUILD := release
ifeq ($(ARCH),x86_64)
CFLAGS += -msse4.1
endif
include build.mk

View File

@@ -0,0 +1,25 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.27428.2002
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "capture", "capture.vcxproj", "{447D58BF-94CD-4469-BB90-549C05D03E00}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{447D58BF-94CD-4469-BB90-549C05D03E00}.Debug|x64.ActiveCfg = Debug|x64
{447D58BF-94CD-4469-BB90-549C05D03E00}.Debug|x64.Build.0 = Debug|x64
{447D58BF-94CD-4469-BB90-549C05D03E00}.Release|x64.ActiveCfg = Release|x64
{447D58BF-94CD-4469-BB90-549C05D03E00}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {3E51386C-43EA-44AC-9F24-AFAFE4D63ADE}
EndGlobalSection
EndGlobal

View File

@@ -0,0 +1,172 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>15.0</VCProjectVersion>
<ProjectGuid>{447D58BF-94CD-4469-BB90-549C05D03E00}</ProjectGuid>
<RootNamespace>capture</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup />
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<PreprocessorDefinitions>TRACY_NO_STATISTICS;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;WIN32_LEAN_AND_MEAN;NOMINMAX;_USE_MATH_DEFINES;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<EnableEnhancedInstructionSet>AdvancedVectorExtensions2</EnableEnhancedInstructionSet>
<LanguageStandard>stdcpplatest</LanguageStandard>
</ClCompile>
<Link>
<AdditionalDependencies>ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<SubSystem>Console</SubSystem>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<PreprocessorDefinitions>TRACY_NO_STATISTICS;NDEBUG;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;WIN32_LEAN_AND_MEAN;NOMINMAX;_USE_MATH_DEFINES;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<EnableEnhancedInstructionSet>AdvancedVectorExtensions2</EnableEnhancedInstructionSet>
<LanguageStandard>stdcpplatest</LanguageStandard>
</ClCompile>
<Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<SubSystem>Console</SubSystem>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\..\common\TracySocket.cpp" />
<ClCompile Include="..\..\..\common\TracySystem.cpp" />
<ClCompile Include="..\..\..\common\tracy_lz4.cpp" />
<ClCompile Include="..\..\..\common\tracy_lz4hc.cpp" />
<ClCompile Include="..\..\..\server\TracyMemory.cpp" />
<ClCompile Include="..\..\..\server\TracyPrint.cpp" />
<ClCompile Include="..\..\..\server\TracyThreadCompress.cpp" />
<ClCompile Include="..\..\..\server\TracyWorker.cpp" />
<ClCompile Include="..\..\src\capture.cpp" />
<ClCompile Include="..\..\src\getopt.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\..\common\TracyAlign.hpp" />
<ClInclude Include="..\..\..\common\TracyAlloc.hpp" />
<ClInclude Include="..\..\..\common\TracyColor.hpp" />
<ClInclude Include="..\..\..\common\TracyForceInline.hpp" />
<ClInclude Include="..\..\..\common\TracyProtocol.hpp" />
<ClInclude Include="..\..\..\common\TracyQueue.hpp" />
<ClInclude Include="..\..\..\common\TracySocket.hpp" />
<ClInclude Include="..\..\..\common\TracySystem.hpp" />
<ClInclude Include="..\..\..\common\tracy_benaphore.h" />
<ClInclude Include="..\..\..\common\tracy_lz4.hpp" />
<ClInclude Include="..\..\..\common\tracy_lz4hc.hpp" />
<ClInclude Include="..\..\..\common\tracy_sema.h" />
<ClInclude Include="..\..\..\server\TracyCharUtil.hpp" />
<ClInclude Include="..\..\..\server\TracyEvent.hpp" />
<ClInclude Include="..\..\..\server\TracyFileWrite.hpp" />
<ClInclude Include="..\..\..\server\TracyMemory.hpp" />
<ClInclude Include="..\..\..\server\TracyPopcnt.hpp" />
<ClInclude Include="..\..\..\server\TracyPrint.hpp" />
<ClInclude Include="..\..\..\server\TracySlab.hpp" />
<ClInclude Include="..\..\..\server\TracyThreadCompress.hpp" />
<ClInclude Include="..\..\..\server\TracyVector.hpp" />
<ClInclude Include="..\..\..\server\TracyWorker.hpp" />
<ClInclude Include="..\..\..\server\tracy_flat_hash_map.hpp" />
<ClInclude Include="..\..\src\getopt.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="src">
<UniqueIdentifier>{729c80ee-4d26-4a5e-8f1f-6c075783eb56}</UniqueIdentifier>
</Filter>
<Filter Include="server">
<UniqueIdentifier>{cf23ef7b-7694-4154-830b-00cf053350ea}</UniqueIdentifier>
</Filter>
<Filter Include="common">
<UniqueIdentifier>{e39d3623-47cd-4752-8da9-3ea324f964c1}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\..\common\tracy_lz4.cpp">
<Filter>common</Filter>
</ClCompile>
<ClCompile Include="..\..\..\common\TracySocket.cpp">
<Filter>common</Filter>
</ClCompile>
<ClCompile Include="..\..\..\common\TracySystem.cpp">
<Filter>common</Filter>
</ClCompile>
<ClCompile Include="..\..\..\server\TracyMemory.cpp">
<Filter>server</Filter>
</ClCompile>
<ClCompile Include="..\..\..\server\TracyWorker.cpp">
<Filter>server</Filter>
</ClCompile>
<ClCompile Include="..\..\src\capture.cpp">
<Filter>src</Filter>
</ClCompile>
<ClCompile Include="..\..\src\getopt.c">
<Filter>src</Filter>
</ClCompile>
<ClCompile Include="..\..\..\common\tracy_lz4hc.cpp">
<Filter>common</Filter>
</ClCompile>
<ClCompile Include="..\..\..\server\TracyPrint.cpp">
<Filter>server</Filter>
</ClCompile>
<ClCompile Include="..\..\..\server\TracyThreadCompress.cpp">
<Filter>server</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\..\common\tracy_lz4.hpp">
<Filter>common</Filter>
</ClInclude>
<ClInclude Include="..\..\..\common\TracyAlloc.hpp">
<Filter>common</Filter>
</ClInclude>
<ClInclude Include="..\..\..\common\TracyColor.hpp">
<Filter>common</Filter>
</ClInclude>
<ClInclude Include="..\..\..\common\TracyForceInline.hpp">
<Filter>common</Filter>
</ClInclude>
<ClInclude Include="..\..\..\common\TracyProtocol.hpp">
<Filter>common</Filter>
</ClInclude>
<ClInclude Include="..\..\..\common\TracyQueue.hpp">
<Filter>common</Filter>
</ClInclude>
<ClInclude Include="..\..\..\common\TracySocket.hpp">
<Filter>common</Filter>
</ClInclude>
<ClInclude Include="..\..\..\common\TracySystem.hpp">
<Filter>common</Filter>
</ClInclude>
<ClInclude Include="..\..\..\server\tracy_flat_hash_map.hpp">
<Filter>server</Filter>
</ClInclude>
<ClInclude Include="..\..\..\server\TracyCharUtil.hpp">
<Filter>server</Filter>
</ClInclude>
<ClInclude Include="..\..\..\server\TracyEvent.hpp">
<Filter>server</Filter>
</ClInclude>
<ClInclude Include="..\..\..\server\TracyFileWrite.hpp">
<Filter>server</Filter>
</ClInclude>
<ClInclude Include="..\..\..\server\TracyMemory.hpp">
<Filter>server</Filter>
</ClInclude>
<ClInclude Include="..\..\..\server\TracyPopcnt.hpp">
<Filter>server</Filter>
</ClInclude>
<ClInclude Include="..\..\..\server\TracySlab.hpp">
<Filter>server</Filter>
</ClInclude>
<ClInclude Include="..\..\..\server\TracyVector.hpp">
<Filter>server</Filter>
</ClInclude>
<ClInclude Include="..\..\..\server\TracyWorker.hpp">
<Filter>server</Filter>
</ClInclude>
<ClInclude Include="..\..\src\getopt.h">
<Filter>src</Filter>
</ClInclude>
<ClInclude Include="..\..\..\common\TracyAlign.hpp">
<Filter>common</Filter>
</ClInclude>
<ClInclude Include="..\..\..\common\tracy_benaphore.h">
<Filter>common</Filter>
</ClInclude>
<ClInclude Include="..\..\..\common\tracy_sema.h">
<Filter>common</Filter>
</ClInclude>
<ClInclude Include="..\..\..\common\tracy_lz4hc.hpp">
<Filter>common</Filter>
</ClInclude>
<ClInclude Include="..\..\..\server\TracyPrint.hpp">
<Filter>server</Filter>
</ClInclude>
<ClInclude Include="..\..\..\server\TracyThreadCompress.hpp">
<Filter>server</Filter>
</ClInclude>
</ItemGroup>
</Project>

View File

@@ -1,202 +0,0 @@
#ifdef _WIN32
# include <io.h>
# include <windows.h>
#else
# include <unistd.h>
#endif
#include <atomic>
#include <chrono>
#include <cstdarg>
#include <cstdio>
#include <cstring>
#include <inttypes.h>
#include <thread>
#include "CaptureOutput.hpp"
#include "../../public/common/TracyProtocol.hpp"
#include "../../public/common/TracyStackFrames.hpp"
#include "../../server/TracyMemory.hpp"
#include "../../server/TracyPrint.hpp"
#include "../../server/TracyWorker.hpp"
static bool s_isTerminal = false;
void InitTerminalDetection()
{
#ifdef _WIN32
s_isTerminal = _isatty( fileno( stdout ) );
#else
s_isTerminal = isatty( fileno( stdout ) );
#endif
}
bool IsTerminal()
{
return s_isTerminal;
}
void AnsiPrintf( const char* ansiEscape, const char* format, ... )
{
if( IsTerminal() )
{
char buf[256];
va_list args;
va_start( args, format );
vsnprintf( buf, sizeof buf, format, args );
va_end( args );
printf( "%s%s" ANSI_RESET, ansiEscape, buf );
}
else
{
va_list args;
va_start( args, format );
vfprintf( stdout, format, args );
va_end( args );
}
}
int WaitForConnection( tracy::Worker& worker )
{
while( !worker.HasData() )
{
const auto handshake = worker.GetHandshakeStatus();
if( handshake == tracy::HandshakeProtocolMismatch )
{
printf( "\nThe client you are trying to connect to uses incompatible protocol version.\nMake sure you are using the same Tracy version on both client and server.\n" );
return 1;
}
if( handshake == tracy::HandshakeNotAvailable )
{
printf( "\nThe client you are trying to connect to is no longer able to sent profiling data,\nbecause another server was already connected to it.\nYou can do the following:\n\n 1. Restart the client application.\n 2. Rebuild the client application with on-demand mode enabled.\n" );
return 2;
}
if( handshake == tracy::HandshakeDropped )
{
printf( "\nThe client you are trying to connect to has disconnected during the initial\nconnection handshake. Please check your network configuration.\n" );
return 3;
}
std::this_thread::sleep_for( std::chrono::milliseconds( 100 ) );
}
return 0;
}
void PrintWorkerFailure( tracy::Worker& worker )
{
const auto& failure = worker.GetFailureType();
if( failure == tracy::Worker::Failure::None ) return;
AnsiPrintf( ANSI_RED ANSI_BOLD, "\nInstrumentation failure: %s", tracy::Worker::GetFailureString( failure ) );
auto& fd = worker.GetFailureData();
if( !fd.message.empty() )
{
printf( "\nContext: %s", fd.message.c_str() );
}
if( fd.callstack != 0 )
{
AnsiPrintf( ANSI_BOLD, "\nFailure callstack:\n" );
auto& cs = worker.GetCallstack( fd.callstack );
int fidx = 0;
for( auto& entry : cs )
{
auto frameData = worker.GetCallstackFrame( entry );
if( !frameData )
{
printf( "%3i. %p\n", fidx++, (void*)worker.GetCanonicalPointer( entry ) );
}
else
{
const auto fsz = frameData->size;
for( uint8_t f = 0; f < fsz; f++ )
{
const auto& frame = frameData->data[f];
auto txt = worker.GetString( frame.name );
if( fidx == 0 && f != fsz - 1 )
{
auto test = tracy::s_tracyStackFrames;
bool match = false;
do
{
if( strcmp( txt, *test ) == 0 )
{
match = true;
break;
}
}
while( *++test );
if( match ) continue;
}
if( f == fsz - 1 )
{
printf( "%3i. ", fidx++ );
}
else
{
AnsiPrintf( ANSI_BLACK ANSI_BOLD, "inl. " );
}
AnsiPrintf( ANSI_CYAN, "%s ", txt );
txt = worker.GetString( frame.file );
if( frame.line == 0 )
{
AnsiPrintf( ANSI_YELLOW, "(%s)", txt );
}
else
{
AnsiPrintf( ANSI_YELLOW, "(%s:%" PRIu32 ")", txt, frame.line );
}
if( frameData->imageName.Active() )
{
AnsiPrintf( ANSI_MAGENTA, " %s\n", worker.GetString( frameData->imageName ) );
}
else
{
printf( "\n" );
}
}
}
}
}
}
void PrintCaptureProgress( tracy::Worker& worker, int64_t firstTime, int64_t memoryLimit )
{
if( !IsTerminal() ) return;
auto& lock = worker.GetMbpsDataLock();
lock.lock();
const auto mbps = worker.GetMbpsData().back();
const auto compRatio = worker.GetCompRatio();
const auto netTotal = worker.GetDataTransferred();
const auto queueSize = worker.GetSendQueueSize();
lock.unlock();
const char* unit = "Mbps";
float unitsPerMbps = 1.f;
if( mbps < 0.1f )
{
unit = "Kbps";
unitsPerMbps = 1000.f;
}
AnsiPrintf( ANSI_ERASE_LINE ANSI_CYAN ANSI_BOLD, "\r%7.2f %s", mbps * unitsPerMbps, unit );
printf( " /" );
AnsiPrintf( ANSI_CYAN ANSI_BOLD, "%5.1f%%", compRatio * 100.f );
printf( " =" );
AnsiPrintf( ANSI_YELLOW ANSI_BOLD, "%7.2f Mbps", mbps / compRatio );
printf( " | " );
AnsiPrintf( ANSI_YELLOW, "Tx: " );
AnsiPrintf( ANSI_GREEN, "%s", tracy::MemSizeToString( netTotal ) );
printf( " | " );
AnsiPrintf( ANSI_RED ANSI_BOLD, "%s", tracy::MemSizeToString( tracy::memUsage.load( std::memory_order_relaxed ) ) );
if( memoryLimit > 0 )
{
printf( " / " );
AnsiPrintf( ANSI_BLUE ANSI_BOLD, "%s", tracy::MemSizeToString( memoryLimit ) );
}
printf( " | " );
AnsiPrintf( ANSI_RED, "%s", tracy::TimeToString( worker.GetLastTime() - firstTime ) );
printf( " | " );
AnsiPrintf( ANSI_RED ANSI_BOLD, "%s query backlog", tracy::RealToString( queueSize ) );
fflush( stdout );
}

View File

@@ -1,33 +0,0 @@
#ifndef __CAPTUREOUTPUT_HPP__
#define __CAPTUREOUTPUT_HPP__
#include <stdint.h>
#define ANSI_RESET "\033[0m"
#define ANSI_BOLD "\033[1m"
#define ANSI_BLACK "\033[30m"
#define ANSI_RED "\033[31m"
#define ANSI_GREEN "\033[32m"
#define ANSI_YELLOW "\033[33m"
#define ANSI_BLUE "\033[34m"
#define ANSI_MAGENTA "\033[35m"
#define ANSI_CYAN "\033[36m"
#define ANSI_ERASE_LINE "\033[2K"
namespace tracy { class Worker; }
void InitTerminalDetection();
bool IsTerminal();
#ifdef __GNUC__
[[gnu::format( __printf__, 2, 3 )]]
#endif
void AnsiPrintf( const char* ansiEscape, const char* format, ... );
int WaitForConnection( tracy::Worker& worker );
void PrintWorkerFailure( tracy::Worker& worker );
void PrintCaptureProgress( tracy::Worker& worker, int64_t firstTime, int64_t memoryLimit );
#endif

View File

@@ -1,48 +1,36 @@
#ifdef _WIN32
# include <windows.h>
#else
# include <unistd.h>
#endif
#include <atomic>
#include <chrono>
#include <inttypes.h>
#include <mutex>
#include <signal.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include "../../common/TracyProtocol.hpp"
#include "../../server/TracyFileWrite.hpp"
#include "../../server/TracyMemory.hpp"
#include "../../server/TracyPrint.hpp"
#include "../../server/TracySysUtil.hpp"
#include "../../server/TracyWorker.hpp"
#include "../../public/common/TracyVersion.hpp"
#include "GitRef.hpp"
#include "getopt.h"
#include "CaptureOutput.hpp"
#ifdef _WIN32
# include "../../getopt/getopt.h"
#endif
// This atomic is written by a signal handler (SigInt). Traditionally that would
// have had to be `volatile sig_atomic_t`, and annoyingly, `bool` was
// technically not allowed there, even though in practice it would work.
// The good thing with C++11 atomics is that we can use atomic<bool> instead
// here and be on the actually supported path.
static std::atomic<bool> s_disconnect { false };
#ifndef _MSC_VER
struct sigaction oldsigint;
bool disconnect = false;
void SigInt( int )
{
s_disconnect.store(true, std::memory_order_relaxed);
disconnect = true;
}
#endif
[[noreturn]] void Usage()
void Usage()
{
printf( "tracy-capture %i.%i.%i / %s\n\n", tracy::Version::Major, tracy::Version::Minor, tracy::Version::Patch, tracy::GitRef );
printf( "Usage: capture -o output.tracy [-a address] [-p port] [-f] [-s seconds] [-m memlimit]\n" );
printf( "Usage: capture -a address -o output.tracy\n" );
exit( 1 );
}
@@ -56,17 +44,11 @@ int main( int argc, char** argv )
}
#endif
InitTerminalDetection();
bool overwrite = false;
const char* address = "127.0.0.1";
const char* address = nullptr;
const char* output = nullptr;
int port = 8086;
int seconds = -1;
int64_t memoryLimit = -1;
int c;
while( ( c = getopt( argc, argv, "a:o:p:fs:m:" ) ) != -1 )
while( ( c = getopt( argc, argv, "a:o:" ) ) != -1 )
{
switch( c )
{
@@ -76,18 +58,6 @@ int main( int argc, char** argv )
case 'o':
output = optarg;
break;
case 'p':
port = atoi( optarg );
break;
case 'f':
overwrite = true;
break;
case 's':
seconds = atoi(optarg);
break;
case 'm':
memoryLimit = std::clamp( atoll( optarg ), 1ll, 999ll ) * tracy::GetPhysicalMemorySize() / 100;
break;
default:
Usage();
break;
@@ -96,83 +66,86 @@ int main( int argc, char** argv )
if( !address || !output ) Usage();
struct stat st;
if( stat( output, &st ) == 0 && !overwrite )
{
printf( "Output file %s already exists! Use -f to force overwrite.\n", output );
return 4;
}
FILE* test = fopen( output, "wb" );
if( !test )
{
printf( "Cannot open output file %s for writing!\n", output );
return 5;
}
fclose( test );
unlink( output );
printf( "Connecting to %s:%i...", address, port );
printf( "Connecting to %s...", address );
fflush( stdout );
tracy::Worker worker( address, port, memoryLimit );
int result = WaitForConnection( worker );
if( result != 0 ) return result;
printf( "\nTimer resolution: %s\n", tracy::TimeToString( worker.GetResolution() ) );
tracy::Worker worker( address );
while( !worker.IsConnected() )
{
const auto handshake = worker.GetHandshakeStatus();
if( handshake == tracy::HandshakeProtocolMismatch )
{
printf( "\nThe client you are trying to connect to uses incompatible protocol version.\nMake sure you are using the same Tracy version on both client and server.\n" );
return 1;
}
if( handshake == tracy::HandshakeNotAvailable )
{
printf( "\nThe client you are trying to connect to is no longer able to sent profiling data,\nbecause another server was already connected to it.\nYou can do the following:\n\n 1. Restart the client application.\n 2. Rebuild the client application with on-demand mode enabled.\n" );
return 2;
}
if( handshake == tracy::HandshakeDropped )
{
printf( "\nThe client you are trying to connect to has disconnected during the initial\nconnection handshake. Please check your network configuration.\n" );
return 3;
}
}
while( !worker.HasData() ) std::this_thread::sleep_for( std::chrono::milliseconds( 100 ) );
printf( "\nQueue delay: %s\nTimer resolution: %s\n", tracy::TimeToString( worker.GetDelay() ), tracy::TimeToString( worker.GetResolution() ) );
#ifdef _WIN32
signal( SIGINT, SigInt );
#else
struct sigaction sigint, oldsigint;
#ifndef _MSC_VER
struct sigaction sigint;
memset( &sigint, 0, sizeof( sigint ) );
sigint.sa_handler = SigInt;
sigaction( SIGINT, &sigint, &oldsigint );
#endif
const auto firstTime = worker.GetFirstTime();
auto& lock = worker.GetMbpsDataLock();
const auto t0 = std::chrono::high_resolution_clock::now();
while( worker.IsConnected() )
{
if( s_disconnect.load( std::memory_order_relaxed ) )
#ifndef _MSC_VER
if( disconnect )
{
worker.Disconnect();
s_disconnect.store(false, std::memory_order_relaxed );
while( worker.IsConnected() ) std::this_thread::sleep_for( std::chrono::milliseconds( 100 ) );
break;
disconnect = false;
}
#endif
PrintCaptureProgress( worker, firstTime, memoryLimit );
lock.lock();
const auto mbps = worker.GetMbpsData().back();
const auto compRatio = worker.GetCompRatio();
lock.unlock();
if( mbps < 0.1f )
{
printf( "\33[2K\r\033[36;1m%7.2f Kbps", mbps * 1000.f );
}
else
{
printf( "\33[2K\r\033[36;1m%7.2f Mbps", mbps );
}
printf( " \033[0m /\033[36;1m%5.1f%% \033[0m=\033[33;1m%7.2f Mbps \033[0m| Mem: \033[31;1m%.2f MB\033[0m | \033[33mTime: %s\033[0m", compRatio * 100.f, mbps / compRatio, tracy::memUsage.load( std::memory_order_relaxed ) / ( 1024.f * 1024.f ), tracy::TimeToString( worker.GetLastTime() ) );
fflush( stdout );
std::this_thread::sleep_for( std::chrono::milliseconds( 100 ) );
if( seconds != -1 )
{
const auto dur = std::chrono::high_resolution_clock::now() - t0;
if( std::chrono::duration_cast<std::chrono::seconds>(dur).count() >= seconds )
{
s_disconnect.store(true, std::memory_order_relaxed );
}
}
}
const auto t1 = std::chrono::high_resolution_clock::now();
PrintWorkerFailure( worker );
const auto& failure = worker.GetFailureType();
if( failure != tracy::Worker::Failure::None )
{
printf( "\n\033[31;1mInstrumentation failure: %s\033[0m", tracy::Worker::GetFailureString( failure ) );
}
printf( "\nFrames: %" PRIu64 "\nTime span: %s\nZones: %s\nElapsed time: %s\nSaving trace...",
worker.GetFrameCount( *worker.GetFramesBase() ), tracy::TimeToString( worker.GetLastTime() - firstTime ), tracy::RealToString( worker.GetZoneCount() ),
tracy::TimeToString( std::chrono::duration_cast<std::chrono::nanoseconds>( t1 - t0 ).count() ) );
printf( "\nFrames: %" PRIu64 "\nTime span: %s\nZones: %s\nSaving trace...", worker.GetFrameCount( *worker.GetFramesBase() ), tracy::TimeToString( worker.GetLastTime() ), tracy::RealToString( worker.GetZoneCount(), true ) );
fflush( stdout );
auto f = std::unique_ptr<tracy::FileWrite>( tracy::FileWrite::Open( output, tracy::FileCompression::Zstd, 3, 4 ) );
auto f = std::unique_ptr<tracy::FileWrite>( tracy::FileWrite::Open( output ) );
if( f )
{
worker.Write( *f, false );
AnsiPrintf( ANSI_GREEN ANSI_BOLD, " done!\n" );
f->Finish();
const auto stats = f->GetCompressionStatistics();
printf( "Trace size %s (%.2f%% ratio)\n", tracy::MemSizeToString( stats.second ), 100.f * stats.second / stats.first );
worker.Write( *f );
printf( " \033[32;1mdone!\033[0m\n" );
}
else
{
AnsiPrintf( ANSI_RED ANSI_BOLD, " failed!\n");
printf( " \033[31;1failed!\033[0m\n" );
}
return 0;

View File

@@ -1,444 +0,0 @@
#ifdef _WIN32
# include <windows.h>
#else
# include <unistd.h>
#endif
#include <atomic>
#include <chrono>
#include <cstdint>
#include <cstring>
#include <filesystem>
#include <map>
#include <mutex>
#include <signal.h>
#include <string>
#include <thread>
#include <unordered_set>
#include <vector>
#include "../../getopt/getopt.h"
#include "../../public/common/TracySocket.hpp"
#include "../../public/common/TracyVersion.hpp"
#include "../../server/TracyBroadcast.hpp"
#include "../../server/TracyFileWrite.hpp"
#include "../../server/TracyMemory.hpp"
#include "../../server/TracyPrint.hpp"
#include "../../server/TracySysUtil.hpp"
#include "../../server/TracyWorker.hpp"
#include "GitRef.hpp"
#include "CaptureOutput.hpp"
static std::atomic<bool> g_shutdown{false};
static std::mutex g_clientsMutex;
static uint16_t g_listenPort = 8086;
static std::string g_filterName;
static int g_filterPort = 0;
static int64_t g_memoryLimit = -1;
void SigInt( int )
{
g_shutdown.store( true, std::memory_order_relaxed );
}
struct ClientStats
{
std::atomic<float> mbps{0};
std::atomic<int64_t> txBytes{0};
std::atomic<int64_t> memUsage{0};
std::atomic<int64_t> firstTime{-1};
};
struct ClientSession
{
std::string id;
std::string programName;
std::string address;
uint16_t port;
std::string outputFile;
std::thread thread;
std::atomic<bool> active{true};
std::atomic<bool> finished{false};
ClientStats stats;
std::atomic<uint64_t> fileSize{0};
};
static std::map<std::string, ClientSession*> g_clients;
static std::unordered_set<std::string> g_outputFiles;
[[noreturn]] void Usage()
{
printf( "tracy-capture-daemon %i.%i.%i / %s\n\n", tracy::Version::Major, tracy::Version::Minor, tracy::Version::Patch, tracy::GitRef );
printf( "Usage: tracy-capture-daemon -o <output_dir> [options]\n\n" );
printf( "Options:\n" );
printf( " -o, --output <dir> Output directory (required)\n" );
printf( " -p, --port <port> UDP listen port (default: 8086)\n" );
printf( " -m, --memory <limit> Memory limit per client as %% of system RAM\n" );
printf( " --filter-name <pattern> Only capture clients matching program name\n" );
printf( " --filter-port <port> Only capture clients with specific data port\n" );
printf( " -h, --help Show this help\n" );
printf( " -V, --version Show version information\n" );
exit( 1 );
}
std::string SanitizeName( const std::string& name )
{
std::string result;
for( char c : name )
{
if( ( c >= 'a' && c <= 'z' ) || ( c >= 'A' && c <= 'Z' ) || ( c >= '0' && c <= '9' ) || c == '_' || c == '-' )
{
result += c;
}
else if( c == ' ' || c == '\t' )
{
result += '_';
}
}
if( result.empty() ) result = "unknown";
return result;
}
std::string GenerateOutputFilename( const std::string& outputDir, const std::string& programName, const std::string& address, uint16_t port )
{
std::string base = SanitizeName( programName ) + "_" + address + "_" + std::to_string( port );
std::string candidate = base + ".tracy";
std::string path = outputDir + "/" + candidate;
int idx = 0;
while( g_outputFiles.count( path ) || std::filesystem::exists( path ) )
{
idx++;
candidate = base + "_" + std::to_string( idx ) + ".tracy";
path = outputDir + "/" + candidate;
}
g_outputFiles.insert( path );
return path;
}
bool MatchesFilters( const tracy::BroadcastMessage& msg )
{
if( !g_filterName.empty() )
{
if( strstr( msg.programName, g_filterName.c_str() ) == nullptr )
{
return false;
}
}
if( g_filterPort > 0 && msg.listenPort != g_filterPort )
{
return false;
}
return true;
}
void CaptureThread( ClientSession* session, const std::string& address, uint16_t port, int64_t memoryLimit, const std::string& outputFile )
{
printf( "Connecting to %s:%u...\n", address.c_str(), port );
fflush( stdout );
tracy::Worker worker( address.c_str(), port, memoryLimit );
int result = WaitForConnection( worker );
if( result != 0 )
{
session->active = false;
session->finished = true;
return;
}
printf( "Connected to %s (%s:%u)\n", session->programName.c_str(), address.c_str(), port );
int64_t firstTime = worker.GetFirstTime();
session->stats.firstTime = firstTime;
while( session->active && worker.IsConnected() )
{
auto& lock = worker.GetMbpsDataLock();
lock.lock();
float mbps = worker.GetMbpsData().back();
int64_t txTotal = worker.GetDataTransferred();
lock.unlock();
session->stats.mbps = mbps;
session->stats.txBytes = txTotal;
session->stats.memUsage = tracy::memUsage.load( std::memory_order_relaxed );
std::this_thread::sleep_for( std::chrono::milliseconds( 100 ) );
}
if( worker.IsConnected() )
{
worker.Disconnect();
while( worker.IsConnected() ) std::this_thread::sleep_for( std::chrono::milliseconds( 100 ) );
}
printf( "\nSaving %s...", outputFile.c_str() );
fflush( stdout );
auto file = std::unique_ptr<tracy::FileWrite>( tracy::FileWrite::Open( outputFile.c_str(), tracy::FileCompression::Zstd, 3, 4 ) );
if( file )
{
worker.Write( *file, false );
file->Finish();
auto stats = file->GetCompressionStatistics();
session->fileSize = stats.second;
AnsiPrintf( ANSI_GREEN ANSI_BOLD, " done!\n" );
}
else
{
AnsiPrintf( ANSI_RED ANSI_BOLD, " failed!\n" );
}
session->finished = true;
session->active = false;
}
void RefreshDisplay( const std::string& listenAddr )
{
if( !IsTerminal() ) return;
printf( "\033[H\033[J" );
size_t clientCount = 0;
{
std::lock_guard<std::mutex> lock( g_clientsMutex );
clientCount = g_clients.size();
}
printf( "[%zu client%s] Listening on %s:%u... Press Ctrl+C to stop\n\n", clientCount, clientCount == 1 ? "" : "s", listenAddr.c_str(), g_listenPort );
int idx = 1;
float totalMbps = 0;
int64_t totalTx = 0;
int64_t totalMem = 0;
{
std::lock_guard<std::mutex> lock( g_clientsMutex );
for( auto& [id, session] : g_clients )
{
printf( " [%d] %s @ %s:%u ", idx, session->programName.c_str(), session->address.c_str(), session->port );
if( session->finished )
{
printf( "finished (" );
printf( "%s", tracy::MemSizeToString( session->fileSize.load() ) );
printf( ")" );
}
else if( session->active )
{
float mbps = session->stats.mbps.load();
int64_t tx = session->stats.txBytes.load();
int64_t mem = session->stats.memUsage.load();
int64_t firstTime = session->stats.firstTime.load();
printf( "%.1f Mbps | %s | %s", mbps, tracy::MemSizeToString( tx ), tracy::MemSizeToString( mem ) );
totalMbps += mbps;
totalTx += tx;
totalMem += mem;
}
else
{
printf( "connecting..." );
}
printf( "\n" );
idx++;
}
}
printf( "\nTotal: %.1f Mbps | %s | Mem: %s", totalMbps, tracy::MemSizeToString( totalTx ), tracy::MemSizeToString( totalMem ) );
fflush( stdout );
}
void PrintSummary()
{
printf( "\n\n=== Capture Summary ===\n" );
std::lock_guard<std::mutex> lock( g_clientsMutex );
int idx = 1;
int64_t totalSize = 0;
for( auto& [id, session] : g_clients )
{
int64_t size = session->fileSize.load();
totalSize += size;
printf( " [%d] %s @ %s:%u -> %s (%s)\n", idx++, session->programName.c_str(), session->address.c_str(), session->port, session->outputFile.c_str(), tracy::MemSizeToString( size ) );
}
printf( "\nTotal: %zu files, %s\n", g_clients.size(), tracy::MemSizeToString( totalSize ) );
}
int main( int argc, char** argv )
{
#ifdef _WIN32
if( !AttachConsole( ATTACH_PARENT_PROCESS ) )
{
AllocConsole();
SetConsoleMode( GetStdHandle( STD_OUTPUT_HANDLE ), 0x07 );
}
#endif
std::string outputDir;
static struct option longOptions[] = {
{ "output", required_argument, nullptr, 'o' },
{ "port", required_argument, nullptr, 'p' },
{ "memory", required_argument, nullptr, 'm' },
{ "filter-name", required_argument, nullptr, 1 },
{ "filter-port", required_argument, nullptr, 2 },
{ "help", no_argument, nullptr, 'h' },
{ "version", no_argument, nullptr, 'V' },
{ nullptr, 0, nullptr, 0 }
};
int c;
while( ( c = getopt_long( argc, argv, "o:p:m:hV", longOptions, nullptr ) ) != -1 )
{
switch( c )
{
case 'o':
outputDir = optarg;
break;
case 'p':
g_listenPort = atoi( optarg );
break;
case 'm':
g_memoryLimit = std::clamp( atoll( optarg ), 1ll, 999ll ) * tracy::GetPhysicalMemorySize() / 100;
break;
case 1:
g_filterName = optarg;
break;
case 2:
g_filterPort = atoi( optarg );
break;
case 'h':
Usage();
break;
case 'V':
printf( "tracy-capture-daemon %i.%i.%i / %s\n", tracy::Version::Major, tracy::Version::Minor, tracy::Version::Patch, tracy::GitRef );
exit( 0 );
default:
Usage();
break;
}
}
if( outputDir.empty() )
{
fprintf( stderr, "Error: Output directory is required (-o)\n\n" );
Usage();
}
std::filesystem::create_directories( outputDir );
InitTerminalDetection();
#ifdef _WIN32
signal( SIGINT, SigInt );
#else
struct sigaction sigint, oldsigint;
memset( &sigint, 0, sizeof( sigint ) );
sigint.sa_handler = SigInt;
sigaction( SIGINT, &sigint, &oldsigint );
#endif
tracy::UdpListen udpSocket;
if( !udpSocket.Listen( g_listenPort ) )
{
fprintf( stderr, "Error: Failed to listen on port %u\n", g_listenPort );
return 1;
}
printf( "Listening on 0.0.0.0:%u... Press Ctrl+C to stop\n", g_listenPort );
printf( "Output directory: %s\n", outputDir.c_str() );
const std::string listenAddr = "0.0.0.0";
auto lastDisplay = std::chrono::steady_clock::now();
while( !g_shutdown )
{
tracy::IpAddress clientAddr;
size_t len;
const char* msg = udpSocket.Read( len, clientAddr, 100 );
if( msg )
{
auto parsed = tracy::ParseBroadcastMessage( msg, len );
if( parsed )
{
std::string clientId = std::to_string( parsed->pid ) + "_" + clientAddr.GetText() + "_" + std::to_string( parsed->listenPort );
bool isNew = false;
{
std::lock_guard<std::mutex> lock( g_clientsMutex );
isNew = g_clients.find( clientId ) == g_clients.end();
}
if( isNew && MatchesFilters( *parsed ) )
{
std::string addressStr = clientAddr.GetText();
std::string outputFile = GenerateOutputFilename( outputDir, parsed->programName, addressStr, parsed->listenPort );
auto session = new ClientSession();
session->id = clientId;
session->programName = parsed->programName;
session->address = addressStr;
session->port = parsed->listenPort;
session->outputFile = outputFile;
session->active = true;
{
std::lock_guard<std::mutex> lock( g_clientsMutex );
g_clients[clientId] = session;
}
session->thread = std::thread( CaptureThread, session, addressStr, parsed->listenPort, g_memoryLimit, outputFile );
}
}
}
auto now = std::chrono::steady_clock::now();
if( std::chrono::duration_cast<std::chrono::milliseconds>( now - lastDisplay ).count() >= 100 )
{
RefreshDisplay( listenAddr );
lastDisplay = now;
}
}
printf( "\n\nShutting down... waiting for %zu client(s) to finish\n", g_clients.size() );
{
std::lock_guard<std::mutex> lock( g_clientsMutex );
for( auto& [id, session] : g_clients )
{
session->active = false;
}
}
{
std::lock_guard<std::mutex> lock( g_clientsMutex );
for( auto& [id, session] : g_clients )
{
if( session->thread.joinable() )
{
session->thread.join();
}
}
}
PrintSummary();
{
std::lock_guard<std::mutex> lock( g_clientsMutex );
for( auto& [id, session] : g_clients )
{
delete session;
}
g_clients.clear();
}
return 0;
}

View File

@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2012-2023, Kim Grasman <kim.grasman@gmail.com>
* Copyright (c) 2012-2017, Kim Grasman <kim.grasman@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -159,7 +159,6 @@ int getopt_long(int argc, char* const argv[], const char* optstring,
const struct option* match = NULL;
int num_matches = 0;
size_t argument_name_length = 0;
size_t option_length = 0;
const char* current_argument = NULL;
int retval = -1;
@@ -176,16 +175,6 @@ int getopt_long(int argc, char* const argv[], const char* optstring,
current_argument = argv[optind] + 2;
argument_name_length = strcspn(current_argument, "=");
for (; o->name; ++o) {
/* Check for exact match first. */
option_length = strlen(o->name);
if (option_length == argument_name_length &&
strncmp(o->name, current_argument, option_length) == 0) {
match = o;
num_matches = 1;
break;
}
/* If not exact, count the number of abbreviated matches. */
if (strncmp(o->name, current_argument, argument_name_length) == 0) {
match = o;
++num_matches;

View File

@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2012-2023, Kim Grasman <kim.grasman@gmail.com>
* Copyright (c) 2012-2017, Kim Grasman <kim.grasman@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without

319
client/TracyArmCpuTable.hpp Normal file
View File

@@ -0,0 +1,319 @@
namespace tracy
{
static const char* DecodeArmImplementer( uint32_t v )
{
static char buf[16];
switch( v )
{
case 0x41: return "ARM";
case 0x42: return "Broadcom";
case 0x43: return "Cavium";
case 0x44: return "DEC";
case 0x46: return "Fujitsu";
case 0x48: return "HiSilicon";
case 0x4d: return "Motorola";
case 0x4e: return "Nvidia";
case 0x50: return "Applied Micro";
case 0x51: return "Qualcomm";
case 0x53: return "Samsung";
case 0x54: return "Texas Instruments";
case 0x56: return "Marvell";
case 0x61: return "Apple";
case 0x66: return "Faraday";
case 0x68: return "HXT";
case 0x69: return "Intel";
default: break;
}
sprintf( buf, "0x%x", v );
return buf;
}
static const char* DecodeArmPart( uint32_t impl, uint32_t part )
{
static char buf[16];
switch( impl )
{
case 0x41:
switch( part )
{
case 0x810: return "810";
case 0x920: return "920";
case 0x922: return "922";
case 0x926: return "926";
case 0x940: return "940";
case 0x946: return "946";
case 0x966: return "966";
case 0xa20: return "1020";
case 0xa22: return "1022";
case 0xa26: return "1026";
case 0xb02: return "11 MPCore";
case 0xb36: return "1136";
case 0xb56: return "1156";
case 0xb76: return "1176";
case 0xc05: return " Cortex-A5";
case 0xc07: return " Cortex-A7";
case 0xc08: return " Cortex-A8";
case 0xc09: return " Cortex-A9";
case 0xc0c: return " Cortex-A12";
case 0xc0d: return " Rockchip RK3288";
case 0xc0f: return " Cortex-A15";
case 0xc0e: return " Cortex-A17";
case 0xc14: return " Cortex-R4";
case 0xc15: return " Cortex-R5";
case 0xc17: return " Cortex-R7";
case 0xc18: return " Cortex-R8";
case 0xc20: return " Cortex-M0";
case 0xc21: return " Cortex-M1";
case 0xc23: return " Cortex-M3";
case 0xc24: return " Cortex-M4";
case 0xc27: return " Cortex-M7";
case 0xc60: return " Cortex-M0+";
case 0xd00: return " AArch64 simulator";
case 0xd01: return " Cortex-A32";
case 0xd03: return " Cortex-A53";
case 0xd04: return " Cortex-A35";
case 0xd05: return " Cortex-A55";
case 0xd06: return " Cortex-A65";
case 0xd07: return " Cortex-A57";
case 0xd08: return " Cortex-A72";
case 0xd09: return " Cortex-A73";
case 0xd0a: return " Cortex-A75";
case 0xd0b: return " Cortex-A76";
case 0xd0c: return " Neoverse N1";
case 0xd0d: return " Cortex-A77";
case 0xd0e: return " Cortex-A76AE";
case 0xd0f: return " AEMv8";
case 0xd13: return " Cortex-R52";
case 0xd20: return " Cortex-M23";
case 0xd21: return " Cortex-M33";
case 0xd4a: return " Neoverse E1";
default: break;
}
case 0x42:
switch( part )
{
case 0xf: return " Brahma B15";
case 0x100: return " Brahma B53";
case 0x516: return " ThunderX2";
default: break;
}
case 0x43:
switch( part )
{
case 0xa0: return " ThunderX";
case 0xa1: return " ThunderX 88XX";
case 0xa2: return " ThunderX 81XX";
case 0xa3: return " ThunderX 83XX";
case 0xaf: return " ThunderX2 99xx";
default: break;
}
case 0x44:
switch( part )
{
case 0xa10: return " SA110";
case 0xa11: return " SA1100";
default: break;
}
case 0x46:
switch( part )
{
case 0x1: return " A64FX";
default: break;
}
case 0x48:
switch( part )
{
case 0xd01: return " TSV100";
case 0xd40: return " Kirin 980";
default: break;
}
case 0x4e:
switch( part )
{
case 0x0: return " Denver";
case 0x3: return " Denver 2";
case 0x4: return " Carmel";
default: break;
}
case 0x50:
switch( part )
{
case 0x0: return " X-Gene";
default: break;
}
case 0x51:
switch( part )
{
case 0xf: return " Scorpion";
case 0x2d: return " Scorpion";
case 0x4d: return " Krait";
case 0x6f: return " Krait";
case 0x200: return " Kryo";
case 0x201: return " Kryo Silver (Snapdragon 821)";
case 0x205: return " Kryo Gold";
case 0x211: return " Kryo Silver (Snapdragon 820)";
case 0x800: return " Kryo 260 / 280 Gold";
case 0x801: return " Kryo 260 / 280 Silver";
case 0x802: return " Kryo 385 Gold";
case 0x803: return " Kryo 385 Silver";
case 0x804: return " Kryo 485 Gold";
case 0xc00: return " Falkor";
case 0xc01: return " Saphira";
default: break;
}
case 0x53:
switch( part )
{
case 0x1: return " Exynos M1/M2";
case 0x2: return " Exynos M3";
default: break;
}
case 0x56:
switch( part )
{
case 0x131: return " Feroceon 88FR131";
case 0x581: return " PJ4 / PJ4B";
case 0x584: return " PJ4B-MP / PJ4C";
default: break;
}
case 0x61:
switch( part )
{
case 0x1: return " Cyclone";
case 0x2: return " Typhoon";
case 0x3: return " Typhoon/Capri";
case 0x4: return " Twister";
case 0x5: return " Twister/Elba/Malta";
case 0x6: return " Hurricane";
case 0x7: return " Hurricane/Myst";
default: break;
}
case 0x66:
switch( part )
{
case 0x526: return " FA526";
case 0x626: return " FA626";
default: break;
}
case 0x68:
switch( part )
{
case 0x0: return " Phecda";
default: break;
}
default: break;
}
sprintf( buf, " 0x%x", part );
return buf;
}
static const char* DecodeIosDevice( const char* id )
{
static const char* DeviceTable[] = {
"i386", "32-bit simulator",
"x86_64", "64-bit simulator",
"iPhone1,1", "iPhone",
"iPhone1,2", "iPhone 3G",
"iPhone2,1", "iPhone 3GS",
"iPhone3,1", "iPhone 4 (GSM)",
"iPhone3,2", "iPhone 4 (GSM)",
"iPhone3,3", "iPhone 4 (CDMA)",
"iPhone4,1", "iPhone 4S",
"iPhone5,1", "iPhone 5 (A1428)",
"iPhone5,2", "iPhone 5 (A1429)",
"iPhone5,3", "iPhone 5c (A1456/A1532)",
"iPhone5,4", "iPhone 5c (A1507/A1516/1526/A1529)",
"iPhone6,1", "iPhone 5s (A1433/A1533)",
"iPhone6,2", "iPhone 5s (A1457/A1518/A1528/A1530)",
"iPhone7,1", "iPhone 6 Plus",
"iPhone7,2", "iPhone 6",
"iPhone8,1", "iPhone 6S",
"iPhone8,2", "iPhone 6S Plus",
"iPhone8,4", "iPhone SE",
"iPhone9,1", "iPhone 7 (CDMA)",
"iPhone9,2", "iPhone 7 Plus (CDMA)",
"iPhone9,3", "iPhone 7 (GSM)",
"iPhone9,4", "iPhone 7 Plus (GSM)",
"iPhone10,1", "iPhone 8 (CDMA)",
"iPhone10,2", "iPhone 8 Plus (CDMA)",
"iPhone10,3", "iPhone X (CDMA)",
"iPhone10,4", "iPhone 8 (GSM)",
"iPhone10,5", "iPhone 8 Plus (GSM)",
"iPhone10,6", "iPhone X (GSM)",
"iPhone11,2", "iPhone XS",
"iPhone11,4", "iPhone XS Max",
"iPhone11,6", "iPhone XS Max China",
"iPhone11,8", "iPhone XR",
"iPad1,1", "iPad (A1219/A1337)",
"iPad2,1", "iPad 2 (A1395)",
"iPad2,2", "iPad 2 (A1396)",
"iPad2,3", "iPad 2 (A1397)",
"iPad2,4", "iPad 2 (A1395)",
"iPad2,5", "iPad Mini (A1432)",
"iPad2,6", "iPad Mini (A1454)",
"iPad2,7", "iPad Mini (A1455)",
"iPad3,1", "iPad 3 (A1416)",
"iPad3,2", "iPad 3 (A1403)",
"iPad3,3", "iPad 3 (A1430)",
"iPad3,4", "iPad 4 (A1458)",
"iPad3,5", "iPad 4 (A1459)",
"iPad3,6", "iPad 4 (A1460)",
"iPad4,1", "iPad Air (A1474)",
"iPad4,2", "iPad Air (A1475)",
"iPad4,3", "iPad Air (A1476)",
"iPad4,4", "iPad Mini 2 (A1489)",
"iPad4,5", "iPad Mini 2 (A1490)",
"iPad4,6", "iPad Mini 2 (A1491)",
"iPad4,7", "iPad Mini 3 (A1599)",
"iPad4,8", "iPad Mini 3 (A1600)",
"iPad4,9", "iPad Mini 3 (A1601)",
"iPad5,1", "iPad Mini 4 (A1538)",
"iPad5,2", "iPad Mini 4 (A1550)",
"iPad5,3", "iPad Air 2 (A1566)",
"iPad5,4", "iPad Air 2 (A1567)",
"iPad6,3", "iPad Pro 9.7\" (A1673)",
"iPad6,4", "iPad Pro 9.7\" (A1674)",
"iPad6,5", "iPad Pro 9.7\" (A1675)",
"iPad6,7", "iPad Pro 12.9\" (A1584)",
"iPad6,8", "iPad Pro 12.9\" (A1652)",
"iPad6,11", "iPad 5th gen (A1822)",
"iPad6,12", "iPad 5th gen (A1823)",
"iPad7,1", "iPad Pro 12.9\" 2nd gen (A1670)",
"iPad7,2", "iPad Pro 12.9\" 2nd gen (A1671/A1821)",
"iPad7,3", "iPad Pro 10.5\" (A1701)",
"iPad7,4", "iPad Pro 10.5\" (A1709)",
"iPad7,5", "iPad 6th gen (A1893)",
"iPad7,6", "iPad 6th gen (A1954)",
"iPad8,1", "iPad Pro 11\" (A1980)",
"iPad8,2", "iPad Pro 11\" (A1980)",
"iPad8,3", "iPad Pro 11\" (A1934/A1979/A2013)",
"iPad8,4", "iPad Pro 11\" (A1934/A1979/A2013)",
"iPad8,5", "iPad Pro 12.9\" 3rd gen (A1876)",
"iPad8,6", "iPad Pro 12.9\" 3rd gen (A1876)",
"iPad8,7", "iPad Pro 12.9\" 3rd gen (A1895/A1983/A2014)",
"iPad8,8", "iPad Pro 12.9\" 3rd gen (A1895/A1983/A2014)",
"iPad11,1", "iPad Mini 5th gen (A2133)",
"iPad11,2", "iPad Mini 5th gen (A2124/A2125/A2126)",
"iPad11,3", "iPad Air 3rd gen (A2152)",
"iPad11,4", "iPad Air 3rd gen (A2123/A2153/A2154)",
"iPod1,1", "iPod Touch",
"iPod2,1", "iPod Touch 2nd gen",
"iPod3,1", "iPod Touch 3rd gen",
"iPod4,1", "iPod Touch 4th gen",
"iPod5,1", "iPod Touch 5th gen",
"iPod7,1", "iPod Touch 6th gen",
"iPod9,1", "iPod Touch 7th gen",
nullptr
};
auto ptr = DeviceTable;
while( *ptr )
{
if( strcmp( ptr[0], id ) == 0 ) return ptr[1];
ptr += 2;
}
return id;
}
}

599
client/TracyCallstack.cpp Normal file
View File

@@ -0,0 +1,599 @@
#include <algorithm>
#include <stdio.h>
#include "TracyCallstack.hpp"
#ifdef TRACY_HAS_CALLSTACK
#if TRACY_HAS_CALLSTACK == 1
# include <windows.h>
# ifdef _MSC_VER
# pragma warning( push )
# pragma warning( disable : 4091 )
# endif
# include <dbghelp.h>
# ifdef _MSC_VER
# pragma warning( pop )
# endif
#elif TRACY_HAS_CALLSTACK == 2 || TRACY_HAS_CALLSTACK == 3
# include "../libbacktrace/backtrace.hpp"
# include <dlfcn.h>
# include <cxxabi.h>
#elif TRACY_HAS_CALLSTACK == 4 || TRACY_HAS_CALLSTACK == 5
# include <dlfcn.h>
# include <cxxabi.h>
#endif
namespace tracy
{
#if TRACY_HAS_CALLSTACK == 1
enum { MaxCbTrace = 16 };
int cb_num;
CallstackEntry cb_data[MaxCbTrace];
extern "C" { t_RtlWalkFrameChain RtlWalkFrameChain = 0; }
#if defined __MINGW32__ && API_VERSION_NUMBER < 12
extern "C" {
// Actual required API_VERSION_NUMBER is unknown because it is undocumented. These functions are not present in at least v11.
DWORD IMAGEAPI SymAddrIncludeInlineTrace(HANDLE hProcess, DWORD64 Address);
BOOL IMAGEAPI SymQueryInlineTrace(HANDLE hProcess, DWORD64 StartAddress, DWORD StartContext, DWORD64 StartRetAddress,
DWORD64 CurAddress, LPDWORD CurContext, LPDWORD CurFrameIndex);
BOOL IMAGEAPI SymFromInlineContext(HANDLE hProcess, DWORD64 Address, ULONG InlineContext, PDWORD64 Displacement,
PSYMBOL_INFO Symbol);
BOOL IMAGEAPI SymGetLineFromInlineContext(HANDLE hProcess, DWORD64 qwAddr, ULONG InlineContext,
DWORD64 qwModuleBaseAddress, PDWORD pdwDisplacement, PIMAGEHLP_LINE64 Line64);
};
#endif
void InitCallstack()
{
#ifdef UNICODE
RtlWalkFrameChain = (t_RtlWalkFrameChain)GetProcAddress( GetModuleHandle( L"ntdll.dll" ), "RtlWalkFrameChain" );
#else
RtlWalkFrameChain = (t_RtlWalkFrameChain)GetProcAddress( GetModuleHandle( "ntdll.dll" ), "RtlWalkFrameChain" );
#endif
SymInitialize( GetCurrentProcess(), nullptr, true );
SymSetOptions( SYMOPT_LOAD_LINES );
}
const char* DecodeCallstackPtrFast( uint64_t ptr )
{
static char ret[1024];
const auto proc = GetCurrentProcess();
char buf[sizeof( SYMBOL_INFO ) + 1024];
auto si = (SYMBOL_INFO*)buf;
si->SizeOfStruct = sizeof( SYMBOL_INFO );
si->MaxNameLen = 1024;
if( SymFromAddr( proc, ptr, nullptr, si ) == 0 )
{
*ret = '\0';
}
else
{
memcpy( ret, si->Name, si->NameLen );
ret[si->NameLen] = '\0';
}
return ret;
}
CallstackEntryData DecodeCallstackPtr( uint64_t ptr )
{
int write;
const auto proc = GetCurrentProcess();
#ifndef __CYGWIN__
const auto inlineNum = std::min<DWORD>( MaxCbTrace - 1, SymAddrIncludeInlineTrace( proc, ptr ) );
DWORD ctx = 0;
DWORD idx;
BOOL doInline = FALSE;
if( inlineNum != 0 ) doInline = SymQueryInlineTrace( proc, ptr, 0, ptr, ptr, &ctx, &idx );
if( doInline )
{
write = inlineNum;
cb_num = 1 + inlineNum;
}
else
#endif
{
write = 0;
cb_num = 1;
}
char buf[sizeof( SYMBOL_INFO ) + 1024];
auto si = (SYMBOL_INFO*)buf;
si->SizeOfStruct = sizeof( SYMBOL_INFO );
si->MaxNameLen = 1024;
if( SymFromAddr( proc, ptr, nullptr, si ) == 0 )
{
memcpy( si->Name, "[unknown]", 10 );
si->NameLen = 9;
}
IMAGEHLP_LINE64 line;
DWORD displacement = 0;
line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
{
auto name = (char*)tracy_malloc(si->NameLen + 1);
memcpy(name, si->Name, si->NameLen);
name[si->NameLen] = '\0';
cb_data[write].name = name;
const char* filename;
if (SymGetLineFromAddr64(proc, ptr, &displacement, &line) == 0)
{
filename = "[unknown]";
cb_data[write].line = 0;
}
else
{
filename = line.FileName;
cb_data[write].line = line.LineNumber;
}
const auto fsz = strlen(filename);
auto file = (char*)tracy_malloc(fsz + 1);
memcpy(file, filename, fsz);
file[fsz] = '\0';
cb_data[write].file = file;
}
#ifndef __CYGWIN__
if( doInline )
{
for( DWORD i=0; i<inlineNum; i++ )
{
auto& cb = cb_data[i];
if( SymFromInlineContext( proc, ptr, ctx, nullptr, si ) == 0 )
{
memcpy( si->Name, "[unknown]", 10 );
si->NameLen = 9;
}
auto name = (char*)tracy_malloc( si->NameLen + 1 );
memcpy( name, si->Name, si->NameLen );
name[si->NameLen] = '\0';
cb.name = name;
const char* filename;
if( SymGetLineFromInlineContext( proc, ptr, ctx, 0, &displacement, &line ) == 0 )
{
filename = "[unknown]";
cb.line = 0;
}
else
{
filename = line.FileName;
cb.line = line.LineNumber;
}
const auto fsz = strlen( filename );
auto file = (char*)tracy_malloc( fsz + 1 );
memcpy( file, filename, fsz );
file[fsz] = '\0';
cb.file = file;
ctx++;
}
}
#endif
return { cb_data, uint8_t( cb_num ) };
}
#elif TRACY_HAS_CALLSTACK == 4
void InitCallstack()
{
}
const char* DecodeCallstackPtrFast( uint64_t ptr )
{
static char ret[1024];
auto vptr = (void*)ptr;
char** sym = nullptr;
const char* symname = nullptr;
Dl_info dlinfo;
if( dladdr( vptr, &dlinfo ) && dlinfo.dli_sname )
{
symname = dlinfo.dli_sname;
}
else
{
sym = backtrace_symbols( &vptr, 1 );
if( sym )
{
symname = *sym;
}
}
if( symname )
{
strcpy( ret, symname );
}
else
{
*ret = '\0';
}
return ret;
}
CallstackEntryData DecodeCallstackPtr( uint64_t ptr )
{
static CallstackEntry cb;
cb.line = 0;
char* demangled = nullptr;
const char* symname = nullptr;
const char* symloc = nullptr;
auto vptr = (void*)ptr;
char** sym = nullptr;
ptrdiff_t symoff = 0;
Dl_info dlinfo;
if( dladdr( vptr, &dlinfo ) )
{
symloc = dlinfo.dli_fname;
symname = dlinfo.dli_sname;
symoff = (char*)ptr - (char*)dlinfo.dli_saddr;
if( symname && symname[0] == '_' )
{
size_t len = 0;
int status;
demangled = abi::__cxa_demangle( symname, nullptr, &len, &status );
if( status == 0 )
{
symname = demangled;
}
}
}
if( !symname )
{
sym = backtrace_symbols( &vptr, 1 );
if( !sym )
{
symname = "[unknown]";
}
else
{
symname = *sym;
}
}
if( !symloc )
{
symloc = "[unknown]";
}
if( symoff == 0 )
{
const auto namelen = strlen( symname );
auto name = (char*)tracy_malloc( namelen + 1 );
memcpy( name, symname, namelen );
name[namelen] = '\0';
cb.name = name;
}
else
{
char buf[32];
const auto offlen = sprintf( buf, " + %td", symoff );
const auto namelen = strlen( symname );
auto name = (char*)tracy_malloc( namelen + offlen + 1 );
memcpy( name, symname, namelen );
memcpy( name + namelen, buf, offlen );
name[namelen + offlen] = '\0';
cb.name = name;
}
char buf[32];
const auto addrlen = sprintf( buf, " [%p]", (void*)ptr );
const auto loclen = strlen( symloc );
auto loc = (char*)tracy_malloc( loclen + addrlen + 1 );
memcpy( loc, symloc, loclen );
memcpy( loc + loclen, buf, addrlen );
loc[loclen + addrlen] = '\0';
cb.file = loc;
if( sym ) free( sym );
if( demangled ) free( demangled );
return { &cb, 1 };
}
#elif TRACY_HAS_CALLSTACK == 2 || TRACY_HAS_CALLSTACK == 3
enum { MaxCbTrace = 16 };
struct backtrace_state* cb_bts;
int cb_num;
CallstackEntry cb_data[MaxCbTrace];
void InitCallstack()
{
cb_bts = backtrace_create_state( nullptr, 0, nullptr, nullptr );
}
static inline char* CopyString( const char* src )
{
const auto sz = strlen( src );
auto dst = (char*)tracy_malloc( sz + 1 );
memcpy( dst, src, sz );
dst[sz] = '\0';
return dst;
}
static int FastCallstackDataCb( void* data, uintptr_t pc, const char* fn, int lineno, const char* function )
{
if( function )
{
strcpy( (char*)data, function );
}
else
{
const char* symname = nullptr;
auto vptr = (void*)pc;
Dl_info dlinfo;
if( dladdr( vptr, &dlinfo ) )
{
symname = dlinfo.dli_sname;
}
if( symname )
{
strcpy( (char*)data, symname );
}
else
{
*(char*)data = '\0';
}
}
return 1;
}
static void FastCallstackErrorCb( void* data, const char* /*msg*/, int /*errnum*/ )
{
*(char*)data = '\0';
}
const char* DecodeCallstackPtrFast( uint64_t ptr )
{
static char ret[1024];
backtrace_pcinfo( cb_bts, ptr, FastCallstackDataCb, FastCallstackErrorCb, ret );
return ret;
}
static int CallstackDataCb( void* /*data*/, uintptr_t pc, const char* fn, int lineno, const char* function )
{
enum { DemangleBufLen = 64*1024 };
char demangled[DemangleBufLen];
if( !fn && !function )
{
const char* symname = nullptr;
const char* symloc = nullptr;
auto vptr = (void*)pc;
ptrdiff_t symoff = 0;
Dl_info dlinfo;
if( dladdr( vptr, &dlinfo ) )
{
symloc = dlinfo.dli_fname;
symname = dlinfo.dli_sname;
symoff = (char*)pc - (char*)dlinfo.dli_saddr;
if( symname && symname[0] == '_' )
{
size_t len = DemangleBufLen;
int status;
abi::__cxa_demangle( symname, demangled, &len, &status );
if( status == 0 )
{
symname = demangled;
}
}
}
if( !symname ) symname = "[unknown]";
if( !symloc ) symloc = "[unknown]";
if( symoff == 0 )
{
cb_data[cb_num].name = CopyString( symname );
}
else
{
char buf[32];
const auto offlen = sprintf( buf, " + %td", symoff );
const auto namelen = strlen( symname );
auto name = (char*)tracy_malloc( namelen + offlen + 1 );
memcpy( name, symname, namelen );
memcpy( name + namelen, buf, offlen );
name[namelen + offlen] = '\0';
cb_data[cb_num].name = name;
}
char buf[32];
const auto addrlen = sprintf( buf, " [%p]", (void*)pc );
const auto loclen = strlen( symloc );
auto loc = (char*)tracy_malloc( loclen + addrlen + 1 );
memcpy( loc, symloc, loclen );
memcpy( loc + loclen, buf, addrlen );
loc[loclen + addrlen] = '\0';
cb_data[cb_num].file = loc;
cb_data[cb_num].line = 0;
}
else
{
if( !fn ) fn = "[unknown]";
if( !function )
{
function = "[unknown]";
}
else
{
if( function[0] == '_' )
{
size_t len = DemangleBufLen;
int status;
abi::__cxa_demangle( function, demangled, &len, &status );
if( status == 0 )
{
function = demangled;
}
}
}
cb_data[cb_num].name = CopyString( function );
cb_data[cb_num].file = CopyString( fn );
cb_data[cb_num].line = lineno;
}
if( ++cb_num >= MaxCbTrace )
{
return 1;
}
else
{
return 0;
}
}
static void CallstackErrorCb( void* /*data*/, const char* /*msg*/, int /*errnum*/ )
{
for( int i=0; i<cb_num; i++ )
{
tracy_free( (void*)cb_data[i].name );
tracy_free( (void*)cb_data[i].file );
}
cb_data[0].name = CopyString( "[error]" );
cb_data[0].file = CopyString( "[error]" );
cb_data[0].line = 0;
cb_num = 1;
}
CallstackEntryData DecodeCallstackPtr( uint64_t ptr )
{
cb_num = 0;
backtrace_pcinfo( cb_bts, ptr, CallstackDataCb, CallstackErrorCb, nullptr );
assert( cb_num > 0 );
return { cb_data, uint8_t( cb_num ) };
}
#elif TRACY_HAS_CALLSTACK == 5
void InitCallstack()
{
}
const char* DecodeCallstackPtrFast( uint64_t ptr )
{
static char ret[1024];
auto vptr = (void*)ptr;
char** sym = nullptr;
const char* symname = nullptr;
Dl_info dlinfo;
if( dladdr( vptr, &dlinfo ) && dlinfo.dli_sname )
{
symname = dlinfo.dli_sname;
}
if( symname )
{
strcpy( ret, symname );
}
else
{
*ret = '\0';
}
return ret;
}
CallstackEntryData DecodeCallstackPtr( uint64_t ptr )
{
static CallstackEntry cb;
cb.line = 0;
char* demangled = nullptr;
const char* symname = nullptr;
const char* symloc = nullptr;
auto vptr = (void*)ptr;
char** sym = nullptr;
ptrdiff_t symoff = 0;
Dl_info dlinfo;
if( dladdr( vptr, &dlinfo ) )
{
symloc = dlinfo.dli_fname;
symname = dlinfo.dli_sname;
symoff = (char*)ptr - (char*)dlinfo.dli_saddr;
if( symname && symname[0] == '_' )
{
size_t len = 0;
int status;
demangled = abi::__cxa_demangle( symname, nullptr, &len, &status );
if( status == 0 )
{
symname = demangled;
}
}
}
if( !symname )
{
symname = "[unknown]";
}
if( !symloc )
{
symloc = "[unknown]";
}
if( symoff == 0 )
{
const auto namelen = strlen( symname );
auto name = (char*)tracy_malloc( namelen + 1 );
memcpy( name, symname, namelen );
name[namelen] = '\0';
cb.name = name;
}
else
{
char buf[32];
const auto offlen = sprintf( buf, " + %td", symoff );
const auto namelen = strlen( symname );
auto name = (char*)tracy_malloc( namelen + offlen + 1 );
memcpy( name, symname, namelen );
memcpy( name + namelen, buf, offlen );
name[namelen + offlen] = '\0';
cb.name = name;
}
char buf[32];
const auto addrlen = sprintf( buf, " [%p]", (void*)ptr );
const auto loclen = strlen( symloc );
auto loc = (char*)tracy_malloc( loclen + addrlen + 1 );
memcpy( loc, symloc, loclen );
memcpy( loc + loclen, buf, addrlen );
loc[loclen + addrlen] = '\0';
cb.file = loc;
if( sym ) free( sym );
if( demangled ) free( demangled );
return { &cb, 1 };
}
#endif
}
#endif

22
client/TracyCallstack.h Normal file
View File

@@ -0,0 +1,22 @@
#ifndef __TRACYCALLSTACK_H__
#define __TRACYCALLSTACK_H__
#if defined _WIN32 || defined __CYGWIN__
# define TRACY_HAS_CALLSTACK 1
#elif defined __ANDROID__
# if !defined __arm__ || __ANDROID_API__ >= 21
# define TRACY_HAS_CALLSTACK 2
# else
# define TRACY_HAS_CALLSTACK 5
# endif
#elif defined __linux
# if defined _GNU_SOURCE && defined __GLIBC__
# define TRACY_HAS_CALLSTACK 3
# else
# define TRACY_HAS_CALLSTACK 2
# endif
#elif defined __APPLE__
# define TRACY_HAS_CALLSTACK 4
#endif
#endif

113
client/TracyCallstack.hpp Normal file
View File

@@ -0,0 +1,113 @@
#ifndef __TRACYCALLSTACK_HPP__
#define __TRACYCALLSTACK_HPP__
#include "TracyCallstack.h"
#if TRACY_HAS_CALLSTACK == 1
extern "C"
{
typedef unsigned long (__stdcall *t_RtlWalkFrameChain)( void**, unsigned long, unsigned long );
extern t_RtlWalkFrameChain RtlWalkFrameChain;
}
#elif TRACY_HAS_CALLSTACK == 2 || TRACY_HAS_CALLSTACK == 5
# include <unwind.h>
#elif TRACY_HAS_CALLSTACK >= 3
# include <execinfo.h>
#endif
#ifdef TRACY_HAS_CALLSTACK
#include <assert.h>
#include <stdint.h>
#include <string.h>
#include "../common/TracyAlloc.hpp"
#include "../common/TracyForceInline.hpp"
namespace tracy
{
struct CallstackEntry
{
const char* name;
const char* file;
uint32_t line;
};
struct CallstackEntryData
{
const CallstackEntry* data;
uint8_t size;
};
const char* DecodeCallstackPtrFast( uint64_t ptr );
CallstackEntryData DecodeCallstackPtr( uint64_t ptr );
void InitCallstack();
#if TRACY_HAS_CALLSTACK == 1
static tracy_force_inline void* Callstack( int depth )
{
assert( depth >= 1 && depth < 63 );
auto trace = (uintptr_t*)tracy_malloc( ( 1 + depth ) * sizeof( uintptr_t ) );
const auto num = RtlWalkFrameChain( (void**)( trace + 1 ), depth, 0 );
*trace = num;
return trace;
}
#elif TRACY_HAS_CALLSTACK == 2 || TRACY_HAS_CALLSTACK == 5
struct BacktraceState
{
void** current;
void** end;
};
static _Unwind_Reason_Code tracy_unwind_callback( struct _Unwind_Context* ctx, void* arg )
{
auto state = (BacktraceState*)arg;
uintptr_t pc = _Unwind_GetIP( ctx );
if( pc )
{
if( state->current == state->end ) return _URC_END_OF_STACK;
*state->current++ = (void*)pc;
}
return _URC_NO_REASON;
}
static tracy_force_inline void* Callstack( int depth )
{
assert( depth >= 1 && depth < 63 );
auto trace = (uintptr_t*)tracy_malloc( ( 1 + depth ) * sizeof( uintptr_t ) );
BacktraceState state = { (void**)(trace+1), (void**)(trace+1+depth) };
_Unwind_Backtrace( tracy_unwind_callback, &state );
*trace = (uintptr_t*)state.current - trace + 1;
return trace;
}
#elif TRACY_HAS_CALLSTACK == 3 || TRACY_HAS_CALLSTACK == 4
static tracy_force_inline void* Callstack( int depth )
{
assert( depth >= 1 );
auto trace = (uintptr_t*)tracy_malloc( ( 1 + depth ) * sizeof( uintptr_t ) );
const auto num = backtrace( (void**)(trace+1), depth );
*trace = num;
return trace;
}
#endif
}
#endif
#endif

View File

@@ -1,7 +1,7 @@
#include "TracyDxt1.hpp"
#include "../common/TracyAssert.hpp"
#include "../common/TracyForceInline.hpp"
#include <assert.h>
#include <stdint.h>
#include <string.h>
@@ -18,8 +18,10 @@
# include <intrin.h>
# else
# include <x86intrin.h>
# ifndef _mm256_cvtsi256_si32
# define _mm256_cvtsi256_si32( v ) ( _mm_cvtsi128_si32( _mm256_castsi256_si128( v ) ) )
# ifdef __CYGWIN__
# ifndef _mm256_cvtsi256_si32
# define _mm256_cvtsi256_si32( v ) ( _mm_cvtsi128_si32( _mm256_castsi256_si128( v ) ) )
# endif
# endif
# endif
#endif
@@ -90,8 +92,56 @@ static const uint16_t DivTable[255*3+1] = {
0x0163, 0x0163, 0x0162, 0x0162, 0x0161, 0x0161, 0x0160, 0x0160, 0x015f, 0x015f, 0x015e, 0x015e, 0x015d, 0x015d, 0x015d, 0x015c,
0x015c, 0x015b, 0x015b, 0x015a, 0x015a, 0x0159, 0x0159, 0x0158, 0x0158, 0x0158, 0x0157, 0x0157, 0x0156, 0x0156
};
#if defined __ARM_NEON && defined __aarch64__
static const uint16_t DivTableAVX[255*3+1] = {
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x38e3, 0x35e5, 0x3333, 0x30c3, 0x2e8b, 0x2c85, 0x2aaa, 0x28f5, 0x2762, 0x25ed, 0x2492, 0x234f, 0x2222, 0x2108, 0x2000,
0x1f07, 0x1e1e, 0x1d41, 0x1c71, 0x1bac, 0x1af2, 0x1a41, 0x1999, 0x18f9, 0x1861, 0x17d0, 0x1745, 0x16c1, 0x1642, 0x15c9, 0x1555,
0x14e5, 0x147a, 0x1414, 0x13b1, 0x1352, 0x12f6, 0x129e, 0x1249, 0x11f7, 0x11a7, 0x115b, 0x1111, 0x10c9, 0x1084, 0x1041, 0x1000,
0x0fc0, 0x0f83, 0x0f48, 0x0f0f, 0x0ed7, 0x0ea0, 0x0e6c, 0x0e38, 0x0e07, 0x0dd6, 0x0da7, 0x0d79, 0x0d4c, 0x0d20, 0x0cf6, 0x0ccc,
0x0ca4, 0x0c7c, 0x0c56, 0x0c30, 0x0c0c, 0x0be8, 0x0bc5, 0x0ba2, 0x0b81, 0x0b60, 0x0b40, 0x0b21, 0x0b02, 0x0ae4, 0x0ac7, 0x0aaa,
0x0a8e, 0x0a72, 0x0a57, 0x0a3d, 0x0a23, 0x0a0a, 0x09f1, 0x09d8, 0x09c0, 0x09a9, 0x0991, 0x097b, 0x0964, 0x094f, 0x0939, 0x0924,
0x090f, 0x08fb, 0x08e7, 0x08d3, 0x08c0, 0x08ad, 0x089a, 0x0888, 0x0876, 0x0864, 0x0853, 0x0842, 0x0831, 0x0820, 0x0810, 0x0800,
0x07f0, 0x07e0, 0x07d1, 0x07c1, 0x07b3, 0x07a4, 0x0795, 0x0787, 0x0779, 0x076b, 0x075d, 0x0750, 0x0743, 0x0736, 0x0729, 0x071c,
0x070f, 0x0703, 0x06f7, 0x06eb, 0x06df, 0x06d3, 0x06c8, 0x06bc, 0x06b1, 0x06a6, 0x069b, 0x0690, 0x0685, 0x067b, 0x0670, 0x0666,
0x065c, 0x0652, 0x0648, 0x063e, 0x0634, 0x062b, 0x0621, 0x0618, 0x060f, 0x0606, 0x05fd, 0x05f4, 0x05eb, 0x05e2, 0x05d9, 0x05d1,
0x05c9, 0x05c0, 0x05b8, 0x05b0, 0x05a8, 0x05a0, 0x0598, 0x0590, 0x0588, 0x0581, 0x0579, 0x0572, 0x056b, 0x0563, 0x055c, 0x0555,
0x054e, 0x0547, 0x0540, 0x0539, 0x0532, 0x052b, 0x0525, 0x051e, 0x0518, 0x0511, 0x050b, 0x0505, 0x04fe, 0x04f8, 0x04f2, 0x04ec,
0x04e6, 0x04e0, 0x04da, 0x04d4, 0x04ce, 0x04c8, 0x04c3, 0x04bd, 0x04b8, 0x04b2, 0x04ad, 0x04a7, 0x04a2, 0x049c, 0x0497, 0x0492,
0x048d, 0x0487, 0x0482, 0x047d, 0x0478, 0x0473, 0x046e, 0x0469, 0x0465, 0x0460, 0x045b, 0x0456, 0x0452, 0x044d, 0x0448, 0x0444,
0x043f, 0x043b, 0x0436, 0x0432, 0x042d, 0x0429, 0x0425, 0x0421, 0x041c, 0x0418, 0x0414, 0x0410, 0x040c, 0x0408, 0x0404, 0x0400,
0x03fc, 0x03f8, 0x03f4, 0x03f0, 0x03ec, 0x03e8, 0x03e4, 0x03e0, 0x03dd, 0x03d9, 0x03d5, 0x03d2, 0x03ce, 0x03ca, 0x03c7, 0x03c3,
0x03c0, 0x03bc, 0x03b9, 0x03b5, 0x03b2, 0x03ae, 0x03ab, 0x03a8, 0x03a4, 0x03a1, 0x039e, 0x039b, 0x0397, 0x0394, 0x0391, 0x038e,
0x038b, 0x0387, 0x0384, 0x0381, 0x037e, 0x037b, 0x0378, 0x0375, 0x0372, 0x036f, 0x036c, 0x0369, 0x0366, 0x0364, 0x0361, 0x035e,
0x035b, 0x0358, 0x0355, 0x0353, 0x0350, 0x034d, 0x034a, 0x0348, 0x0345, 0x0342, 0x0340, 0x033d, 0x033a, 0x0338, 0x0335, 0x0333,
0x0330, 0x032e, 0x032b, 0x0329, 0x0326, 0x0324, 0x0321, 0x031f, 0x031c, 0x031a, 0x0317, 0x0315, 0x0313, 0x0310, 0x030e, 0x030c,
0x0309, 0x0307, 0x0305, 0x0303, 0x0300, 0x02fe, 0x02fc, 0x02fa, 0x02f7, 0x02f5, 0x02f3, 0x02f1, 0x02ef, 0x02ec, 0x02ea, 0x02e8,
0x02e6, 0x02e4, 0x02e2, 0x02e0, 0x02de, 0x02dc, 0x02da, 0x02d8, 0x02d6, 0x02d4, 0x02d2, 0x02d0, 0x02ce, 0x02cc, 0x02ca, 0x02c8,
0x02c6, 0x02c4, 0x02c2, 0x02c0, 0x02be, 0x02bc, 0x02bb, 0x02b9, 0x02b7, 0x02b5, 0x02b3, 0x02b1, 0x02b0, 0x02ae, 0x02ac, 0x02aa,
0x02a8, 0x02a7, 0x02a5, 0x02a3, 0x02a1, 0x02a0, 0x029e, 0x029c, 0x029b, 0x0299, 0x0297, 0x0295, 0x0294, 0x0292, 0x0291, 0x028f,
0x028d, 0x028c, 0x028a, 0x0288, 0x0287, 0x0285, 0x0284, 0x0282, 0x0280, 0x027f, 0x027d, 0x027c, 0x027a, 0x0279, 0x0277, 0x0276,
0x0274, 0x0273, 0x0271, 0x0270, 0x026e, 0x026d, 0x026b, 0x026a, 0x0268, 0x0267, 0x0265, 0x0264, 0x0263, 0x0261, 0x0260, 0x025e,
0x025d, 0x025c, 0x025a, 0x0259, 0x0257, 0x0256, 0x0255, 0x0253, 0x0252, 0x0251, 0x024f, 0x024e, 0x024d, 0x024b, 0x024a, 0x0249,
0x0247, 0x0246, 0x0245, 0x0243, 0x0242, 0x0241, 0x0240, 0x023e, 0x023d, 0x023c, 0x023b, 0x0239, 0x0238, 0x0237, 0x0236, 0x0234,
0x0233, 0x0232, 0x0231, 0x0230, 0x022e, 0x022d, 0x022c, 0x022b, 0x022a, 0x0229, 0x0227, 0x0226, 0x0225, 0x0224, 0x0223, 0x0222,
0x0220, 0x021f, 0x021e, 0x021d, 0x021c, 0x021b, 0x021a, 0x0219, 0x0218, 0x0216, 0x0215, 0x0214, 0x0213, 0x0212, 0x0211, 0x0210,
0x020f, 0x020e, 0x020d, 0x020c, 0x020b, 0x020a, 0x0209, 0x0208, 0x0207, 0x0206, 0x0205, 0x0204, 0x0203, 0x0202, 0x0201, 0x0200,
0x01ff, 0x01fe, 0x01fd, 0x01fc, 0x01fb, 0x01fa, 0x01f9, 0x01f8, 0x01f7, 0x01f6, 0x01f5, 0x01f4, 0x01f3, 0x01f2, 0x01f1, 0x01f0,
0x01ef, 0x01ee, 0x01ed, 0x01ec, 0x01eb, 0x01ea, 0x01e9, 0x01e9, 0x01e8, 0x01e7, 0x01e6, 0x01e5, 0x01e4, 0x01e3, 0x01e2, 0x01e1,
0x01e0, 0x01e0, 0x01df, 0x01de, 0x01dd, 0x01dc, 0x01db, 0x01da, 0x01da, 0x01d9, 0x01d8, 0x01d7, 0x01d6, 0x01d5, 0x01d4, 0x01d4,
0x01d3, 0x01d2, 0x01d1, 0x01d0, 0x01cf, 0x01cf, 0x01ce, 0x01cd, 0x01cc, 0x01cb, 0x01cb, 0x01ca, 0x01c9, 0x01c8, 0x01c7, 0x01c7,
0x01c6, 0x01c5, 0x01c4, 0x01c3, 0x01c3, 0x01c2, 0x01c1, 0x01c0, 0x01c0, 0x01bf, 0x01be, 0x01bd, 0x01bd, 0x01bc, 0x01bb, 0x01ba,
0x01ba, 0x01b9, 0x01b8, 0x01b7, 0x01b7, 0x01b6, 0x01b5, 0x01b4, 0x01b4, 0x01b3, 0x01b2, 0x01b2, 0x01b1, 0x01b0, 0x01af, 0x01af,
0x01ae, 0x01ad, 0x01ad, 0x01ac, 0x01ab, 0x01aa, 0x01aa, 0x01a9, 0x01a8, 0x01a8, 0x01a7, 0x01a6, 0x01a6, 0x01a5, 0x01a4, 0x01a4,
0x01a3, 0x01a2, 0x01a2, 0x01a1, 0x01a0, 0x01a0, 0x019f, 0x019e, 0x019e, 0x019d, 0x019c, 0x019c, 0x019b, 0x019a, 0x019a, 0x0199,
0x0198, 0x0198, 0x0197, 0x0197, 0x0196, 0x0195, 0x0195, 0x0194, 0x0193, 0x0193, 0x0192, 0x0192, 0x0191, 0x0190, 0x0190, 0x018f,
0x018f, 0x018e, 0x018d, 0x018d, 0x018c, 0x018b, 0x018b, 0x018a, 0x018a, 0x0189, 0x0189, 0x0188, 0x0187, 0x0187, 0x0186, 0x0186,
0x0185, 0x0184, 0x0184, 0x0183, 0x0183, 0x0182, 0x0182, 0x0181, 0x0180, 0x0180, 0x017f, 0x017f, 0x017e, 0x017e, 0x017d, 0x017d,
0x017c, 0x017b, 0x017b, 0x017a, 0x017a, 0x0179, 0x0179, 0x0178, 0x0178, 0x0177, 0x0177, 0x0176, 0x0175, 0x0175, 0x0174, 0x0174,
0x0173, 0x0173, 0x0172, 0x0172, 0x0171, 0x0171, 0x0170, 0x0170, 0x016f, 0x016f, 0x016e, 0x016e, 0x016d, 0x016d, 0x016c, 0x016c,
0x016b, 0x016b, 0x016a, 0x016a, 0x0169, 0x0169, 0x0168, 0x0168, 0x0167, 0x0167, 0x0166, 0x0166, 0x0165, 0x0165, 0x0164, 0x0164,
0x0163, 0x0163, 0x0162, 0x0162, 0x0161, 0x0161, 0x0160, 0x0160, 0x015f, 0x015f, 0x015e, 0x015e, 0x015d, 0x015d, 0x015d, 0x015c,
0x015c, 0x015b, 0x015b, 0x015a, 0x015a, 0x0159, 0x0159, 0x0158, 0x0158, 0x0158, 0x0157, 0x0157, 0x0156, 0x0156
};
static const uint16_t DivTableNEON[255*3+1] = {
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x1c71, 0x1af2, 0x1999, 0x1861, 0x1745, 0x1642, 0x1555, 0x147a, 0x13b1, 0x12f6, 0x1249, 0x11a7, 0x1111, 0x1084, 0x1000,
@@ -142,7 +192,6 @@ static const uint16_t DivTableNEON[255*3+1] = {
0x00b1, 0x00b1, 0x00b1, 0x00b1, 0x00b0, 0x00b0, 0x00b0, 0x00b0, 0x00af, 0x00af, 0x00af, 0x00af, 0x00ae, 0x00ae, 0x00ae, 0x00ae,
0x00ae, 0x00ad, 0x00ad, 0x00ad, 0x00ad, 0x00ac, 0x00ac, 0x00ac, 0x00ac, 0x00ac, 0x00ab, 0x00ab, 0x00ab, 0x00ab,
};
#endif
static tracy_force_inline uint64_t ProcessRGB( const uint8_t* src )
@@ -175,12 +224,6 @@ static tracy_force_inline uint64_t ProcessRGB( const uint8_t* src )
return uint64_t( to565( src[0], src[1], src[2] ) ) << 16;
}
__m128i amask = _mm_set1_epi32( 0xFFFFFF );
px0 = _mm_and_si128( px0, amask );
px1 = _mm_and_si128( px1, amask );
px2 = _mm_and_si128( px2, amask );
px3 = _mm_and_si128( px3, amask );
__m128i min0 = _mm_min_epu8( px0, px1 );
__m128i min1 = _mm_min_epu8( px2, px3 );
__m128i min2 = _mm_min_epu8( min0, min1 );
@@ -329,11 +372,10 @@ static tracy_force_inline uint64_t ProcessRGB( const uint8_t* src )
return uint64_t( to565( src[0], src[1], src[2] ) ) << 16;
}
uint32x4_t mask = vdupq_n_u32( 0xFFFFFF );
uint8x16_t l0 = vreinterpretq_u8_u32( vandq_u32( mask, px0 ) );
uint8x16_t l1 = vreinterpretq_u8_u32( vandq_u32( mask, px1 ) );
uint8x16_t l2 = vreinterpretq_u8_u32( vandq_u32( mask, px2 ) );
uint8x16_t l3 = vreinterpretq_u8_u32( vandq_u32( mask, px3 ) );
uint8x16_t l0 = vreinterpretq_u8_u32( px0 );
uint8x16_t l1 = vreinterpretq_u8_u32( px1 );
uint8x16_t l2 = vreinterpretq_u8_u32( px2 );
uint8x16_t l3 = vreinterpretq_u8_u32( px3 );
uint8x16_t min0 = vminq_u8( l0, l1 );
uint8x16_t min1 = vminq_u8( l2, l3 );
@@ -412,20 +454,19 @@ static tracy_force_inline uint64_t ProcessRGB( const uint8_t* src )
return uint64_t( ( uint64_t( to565( vmin ) ) << 16 ) | to565( vmax ) | ( uint64_t( vp ) << 32 ) );
# endif
#else
uint32_t ref;
memcpy( &ref, src, 4 );
uint32_t refMask = ref & 0xF8FCF8;
const auto ref = to565( src[0], src[1], src[2] );
auto stmp = src + 4;
for( int i=1; i<16; i++ )
{
uint32_t px;
memcpy( &px, stmp, 4 );
if( ( px & 0xF8FCF8 ) != refMask ) break;
if( to565( stmp[0], stmp[1], stmp[2] ) != ref )
{
break;
}
stmp += 4;
}
if( stmp == src + 64 )
{
return uint64_t( to565( ref ) ) << 16;
return uint64_t( ref ) << 16;
}
uint8_t min[3] = { src[0], src[1], src[2] };
@@ -471,42 +512,6 @@ static tracy_force_inline void ProcessRGB_AVX( const uint8_t* src, char*& dst )
__m256i px2 = _mm256_loadu_si256(((__m256i*)src) + 2);
__m256i px3 = _mm256_loadu_si256(((__m256i*)src) + 3);
__m256i smask = _mm256_set1_epi32( 0xF8FCF8 );
__m256i sd0 = _mm256_and_si256( px0, smask );
__m256i sd1 = _mm256_and_si256( px1, smask );
__m256i sd2 = _mm256_and_si256( px2, smask );
__m256i sd3 = _mm256_and_si256( px3, smask );
__m256i sc = _mm256_shuffle_epi32(sd0, _MM_SHUFFLE(0, 0, 0, 0));
__m256i sc0 = _mm256_cmpeq_epi8( sd0, sc );
__m256i sc1 = _mm256_cmpeq_epi8( sd1, sc );
__m256i sc2 = _mm256_cmpeq_epi8( sd2, sc );
__m256i sc3 = _mm256_cmpeq_epi8( sd3, sc );
__m256i sm0 = _mm256_and_si256( sc0, sc1 );
__m256i sm1 = _mm256_and_si256( sc2, sc3 );
__m256i sm = _mm256_and_si256( sm0, sm1 );
const int64_t solid0 = 1 - _mm_testc_si128( _mm256_castsi256_si128( sm ), _mm_set1_epi32( -1 ) );
const int64_t solid1 = 1 - _mm_testc_si128( _mm256_extracti128_si256( sm, 1 ), _mm_set1_epi32( -1 ) );
if( solid0 + solid1 == 0 )
{
const auto c0 = uint64_t( to565( src[0], src[1], src[2] ) ) << 16;
const auto c1 = uint64_t( to565( src[16], src[17], src[18] ) ) << 16;
memcpy( dst, &c0, 8 );
memcpy( dst+8, &c1, 8 );
dst += 16;
return;
}
__m256i amask = _mm256_set1_epi32( 0xFFFFFF );
px0 = _mm256_and_si256( px0, amask );
px1 = _mm256_and_si256( px1, amask );
px2 = _mm256_and_si256( px2, amask );
px3 = _mm256_and_si256( px3, amask );
__m256i min0 = _mm256_min_epu8( px0, px1 );
__m256i min1 = _mm256_min_epu8( px2, px3 );
__m256i min2 = _mm256_min_epu8( min0, min1 );
@@ -528,8 +533,8 @@ static tracy_force_inline void ProcessRGB_AVX( const uint8_t* src, char*& dst )
__m256i range1 = _mm256_subs_epu8( rmax, rmin );
__m256i range2 = _mm256_sad_epu8( rmax, rmin );
uint16_t vrange0 = DivTable[_mm256_cvtsi256_si32( range2 ) >> 1];
uint16_t vrange1 = DivTable[_mm256_extract_epi16( range2, 8 ) >> 1];
uint16_t vrange0 = DivTableAVX[_mm256_cvtsi256_si32( range2 ) >> 1];
uint16_t vrange1 = DivTableAVX[_mm256_extract_epi16( range2, 8 ) >> 1];
__m256i range00 = _mm256_set1_epi16( vrange0 );
__m256i range = _mm256_inserti128_si256( range00, _mm_set1_epi16( vrange1 ), 1 );
@@ -573,18 +578,14 @@ static tracy_force_inline void ProcessRGB_AVX( const uint8_t* src, char*& dst )
__m256i d0 = _mm256_unpacklo_epi32( mm5, p );
__m256i d1 = _mm256_permute4x64_epi64( d0, _MM_SHUFFLE( 3, 2, 2, 0 ) );
__m128i d2 = _mm256_castsi256_si128( d1 );
__m128i mask = _mm_set_epi64x( 0xFFFF0000 | -solid1, 0xFFFF0000 | -solid0 );
__m128i d3 = _mm_and_si128( d2, mask );
_mm_storeu_si128( (__m128i*)dst, d3 );
_mm_storeu_si128( (__m128i*)dst, _mm256_castsi256_si128( d1 ) );
dst += 16;
}
#endif
void CompressImageDxt1( const char* src, char* dst, int w, int h )
{
TRACY_ASSERT( (w % 4) == 0 && (h % 4) == 0 );
assert( (w % 4) == 0 && (h % 4) == 0 );
#ifdef __AVX2__
if( w%8 == 0 )

View File

@@ -4,7 +4,6 @@
#include <stddef.h>
#include "../common/TracyAlloc.hpp"
#include "../common/TracyAssert.hpp"
#include "../common/TracyForceInline.hpp"
namespace tracy
@@ -22,7 +21,6 @@ public:
, m_write( m_ptr )
, m_end( m_ptr + capacity )
{
TRACY_ASSERT( capacity != 0 );
}
FastVector( const FastVector& ) = delete;
@@ -47,11 +45,11 @@ public:
T* end() { return m_write; }
const T* end() const { return m_write; }
T& front() { TRACY_ASSERT( !empty() ); return m_ptr[0]; }
const T& front() const { TRACY_ASSERT( !empty() ); return m_ptr[0]; }
T& front() { assert( !empty() ); return m_ptr[0]; }
const T& front() const { assert( !empty() ); return m_ptr[0]; }
T& back() { TRACY_ASSERT( !empty() ); return m_write[-1]; }
const T& back() const { TRACY_ASSERT( !empty() ); return m_write[-1]; }
T& back() { assert( !empty() ); return m_write[-1]; }
const T& back() const { assert( !empty() ); return m_write[-1]; }
T& operator[]( size_t idx ) { return m_ptr[idx]; }
const T& operator[]( size_t idx ) const { return m_ptr[idx]; }
@@ -98,11 +96,11 @@ public:
private:
tracy_no_inline void AllocMore()
{
const auto cap = size_t( m_end - m_ptr ) * 2;
const auto size = size_t( m_write - m_ptr );
const auto cap = ( m_end - m_ptr ) * 2;
const auto size = m_write - m_ptr;
T* ptr = (T*)tracy_malloc( sizeof( T ) * cap );
memcpy( ptr, m_ptr, size * sizeof( T ) );
tracy_free_fast( m_ptr );
tracy_free( m_ptr );
m_ptr = ptr;
m_write = m_ptr + size;
m_end = m_ptr + cap;

View File

@@ -6,52 +6,63 @@
#include "../common/TracySystem.hpp"
#include "../common/TracyAlign.hpp"
#include "../common/TracyAssert.hpp"
#include "TracyProfiler.hpp"
namespace tracy
{
class LockableCtx
template<class T>
class Lockable
{
public:
tracy_force_inline LockableCtx( const SourceLocationData* srcloc )
tracy_force_inline Lockable( const SourceLocationData* srcloc )
: m_id( GetLockCounter().fetch_add( 1, std::memory_order_relaxed ) )
#ifdef TRACY_ON_DEMAND
, m_lockCount( 0 )
, m_active( false )
#endif
{
TRACY_ASSERT( m_id != (std::numeric_limits<uint32_t>::max)() );
assert( m_id != std::numeric_limits<uint32_t>::max() );
auto item = Profiler::QueueSerial();
Magic magic;
auto token = GetToken();
auto& tail = token->get_tail_index();
auto item = token->enqueue_begin( magic );
MemWrite( &item->hdr.type, QueueType::LockAnnounce );
MemWrite( &item->lockAnnounce.id, m_id );
MemWrite( &item->lockAnnounce.time, Profiler::GetTime() );
MemWrite( &item->lockAnnounce.lckloc, (uint64_t)srcloc );
MemWrite( &item->lockAnnounce.type, LockType::Lockable );
#ifdef TRACY_ON_DEMAND
GetProfiler().DeferItem( *item );
#endif
Profiler::QueueSerialFinish();
tail.store( magic + 1, std::memory_order_release );
}
LockableCtx( const LockableCtx& ) = delete;
LockableCtx& operator=( const LockableCtx& ) = delete;
Lockable( const Lockable& ) = delete;
Lockable& operator=( const Lockable& ) = delete;
tracy_force_inline ~LockableCtx()
~Lockable()
{
auto item = Profiler::QueueSerial();
Magic magic;
auto token = GetToken();
auto& tail = token->get_tail_index();
auto item = token->enqueue_begin( magic );
MemWrite( &item->hdr.type, QueueType::LockTerminate );
MemWrite( &item->lockTerminate.id, m_id );
MemWrite( &item->lockTerminate.time, Profiler::GetTime() );
MemWrite( &item->lockTerminate.type, LockType::Lockable );
#ifdef TRACY_ON_DEMAND
GetProfiler().DeferItem( *item );
#endif
Profiler::QueueSerialFinish();
tail.store( magic + 1, std::memory_order_release );
}
tracy_force_inline bool BeforeLock()
tracy_force_inline void lock()
{
#ifdef TRACY_ON_DEMAND
bool queue = false;
@@ -63,30 +74,40 @@ public:
if( active != connected ) m_active.store( connected, std::memory_order_relaxed );
if( connected ) queue = true;
}
if( !queue ) return false;
if( !queue )
{
m_lockable.lock();
return;
}
#endif
const auto thread = GetThreadHandle();
auto item = Profiler::QueueSerial();
MemWrite( &item->hdr.type, QueueType::LockWait );
MemWrite( &item->lockWait.thread, GetThreadHandle() );
MemWrite( &item->lockWait.id, m_id );
MemWrite( &item->lockWait.time, Profiler::GetTime() );
Profiler::QueueSerialFinish();
return true;
{
auto item = Profiler::QueueSerial();
MemWrite( &item->hdr.type, QueueType::LockWait );
MemWrite( &item->lockWait.thread, thread );
MemWrite( &item->lockWait.id, m_id );
MemWrite( &item->lockWait.time, Profiler::GetTime() );
MemWrite( &item->lockWait.type, LockType::Lockable );
Profiler::QueueSerialFinish();
}
m_lockable.lock();
{
auto item = Profiler::QueueSerial();
MemWrite( &item->hdr.type, QueueType::LockObtain );
MemWrite( &item->lockObtain.thread, thread );
MemWrite( &item->lockObtain.id, m_id );
MemWrite( &item->lockObtain.time, Profiler::GetTime() );
Profiler::QueueSerialFinish();
}
}
tracy_force_inline void AfterLock()
tracy_force_inline void unlock()
{
auto item = Profiler::QueueSerial();
MemWrite( &item->hdr.type, QueueType::LockObtain );
MemWrite( &item->lockObtain.thread, GetThreadHandle() );
MemWrite( &item->lockObtain.id, m_id );
MemWrite( &item->lockObtain.time, Profiler::GetTime() );
Profiler::QueueSerialFinish();
}
m_lockable.unlock();
tracy_force_inline void AfterUnlock()
{
#ifdef TRACY_ON_DEMAND
m_lockCount.fetch_sub( 1, std::memory_order_relaxed );
if( !m_active.load( std::memory_order_relaxed ) ) return;
@@ -99,15 +120,18 @@ public:
auto item = Profiler::QueueSerial();
MemWrite( &item->hdr.type, QueueType::LockRelease );
MemWrite( &item->lockRelease.thread, GetThreadHandle() );
MemWrite( &item->lockRelease.id, m_id );
MemWrite( &item->lockRelease.time, Profiler::GetTime() );
Profiler::QueueSerialFinish();
}
tracy_force_inline void AfterTryLock( bool acquired )
tracy_force_inline bool try_lock()
{
const auto ret = m_lockable.try_lock();
#ifdef TRACY_ON_DEMAND
if( !acquired ) return;
if( !ret ) return ret;
bool queue = false;
const auto locks = m_lockCount.fetch_add( 1, std::memory_order_relaxed );
@@ -118,10 +142,10 @@ public:
if( active != connected ) m_active.store( connected, std::memory_order_relaxed );
if( connected ) queue = true;
}
if( !queue ) return;
if( !queue ) return ret;
#endif
if( acquired )
if( ret )
{
auto item = Profiler::QueueSerial();
MemWrite( &item->hdr.type, QueueType::LockObtain );
@@ -130,6 +154,8 @@ public:
MemWrite( &item->lockObtain.time, Profiler::GetTime() );
Profiler::QueueSerialFinish();
}
return ret;
}
tracy_force_inline void Mark( const SourceLocationData* srcloc )
@@ -153,23 +179,8 @@ public:
Profiler::QueueSerialFinish();
}
tracy_force_inline void CustomName( const char* name, size_t size )
{
TRACY_ASSERT( size < (std::numeric_limits<uint16_t>::max)() );
auto ptr = (char*)tracy_malloc( size );
memcpy( ptr, name, size );
auto item = Profiler::QueueSerial();
MemWrite( &item->hdr.type, QueueType::LockName );
MemWrite( &item->lockNameFat.id, m_id );
MemWrite( &item->lockNameFat.name, (uint64_t)ptr );
MemWrite( &item->lockNameFat.size, (uint16_t)size );
#ifdef TRACY_ON_DEMAND
GetProfiler().DeferItem( *item );
#endif
Profiler::QueueSerialFinish();
}
private:
T m_lockable;
uint32_t m_id;
#ifdef TRACY_ON_DEMAND
@@ -178,95 +189,59 @@ private:
#endif
};
template<class T>
class Lockable
class SharedLockable
{
public:
tracy_force_inline Lockable( const SourceLocationData* srcloc )
: m_ctx( srcloc )
{
}
Lockable( const Lockable& ) = delete;
Lockable& operator=( const Lockable& ) = delete;
tracy_force_inline void lock()
{
const auto runAfter = m_ctx.BeforeLock();
m_lockable.lock();
if( runAfter ) m_ctx.AfterLock();
}
tracy_force_inline void unlock()
{
m_lockable.unlock();
m_ctx.AfterUnlock();
}
tracy_force_inline bool try_lock()
{
const auto acquired = m_lockable.try_lock();
m_ctx.AfterTryLock( acquired );
return acquired;
}
tracy_force_inline void Mark( const SourceLocationData* srcloc )
{
m_ctx.Mark( srcloc );
}
tracy_force_inline void CustomName( const char* name, size_t size )
{
m_ctx.CustomName( name, size );
}
T m_lockable;
private:
LockableCtx m_ctx;
};
class SharedLockableCtx
{
public:
tracy_force_inline SharedLockableCtx( const SourceLocationData* srcloc )
tracy_force_inline SharedLockable( const SourceLocationData* srcloc )
: m_id( GetLockCounter().fetch_add( 1, std::memory_order_relaxed ) )
#ifdef TRACY_ON_DEMAND
, m_lockCount( 0 )
, m_active( false )
#endif
{
TRACY_ASSERT( m_id != (std::numeric_limits<uint32_t>::max)() );
assert( m_id != std::numeric_limits<uint32_t>::max() );
auto item = Profiler::QueueSerial();
Magic magic;
auto token = GetToken();
auto& tail = token->get_tail_index();
auto item = token->enqueue_begin( magic );
MemWrite( &item->hdr.type, QueueType::LockAnnounce );
MemWrite( &item->lockAnnounce.id, m_id );
MemWrite( &item->lockAnnounce.time, Profiler::GetTime() );
MemWrite( &item->lockAnnounce.lckloc, (uint64_t)srcloc );
MemWrite( &item->lockAnnounce.type, LockType::SharedLockable );
#ifdef TRACY_ON_DEMAND
GetProfiler().DeferItem( *item );
#endif
Profiler::QueueSerialFinish();
tail.store( magic + 1, std::memory_order_release );
}
SharedLockableCtx( const SharedLockableCtx& ) = delete;
SharedLockableCtx& operator=( const SharedLockableCtx& ) = delete;
SharedLockable( const SharedLockable& ) = delete;
SharedLockable& operator=( const SharedLockable& ) = delete;
tracy_force_inline ~SharedLockableCtx()
~SharedLockable()
{
auto item = Profiler::QueueSerial();
Magic magic;
auto token = GetToken();
auto& tail = token->get_tail_index();
auto item = token->enqueue_begin( magic );
MemWrite( &item->hdr.type, QueueType::LockTerminate );
MemWrite( &item->lockTerminate.id, m_id );
MemWrite( &item->lockTerminate.time, Profiler::GetTime() );
MemWrite( &item->lockTerminate.type, LockType::SharedLockable );
#ifdef TRACY_ON_DEMAND
GetProfiler().DeferItem( *item );
#endif
Profiler::QueueSerialFinish();
tail.store( magic + 1, std::memory_order_release );
}
tracy_force_inline bool BeforeLock()
tracy_force_inline void lock()
{
#ifdef TRACY_ON_DEMAND
bool queue = false;
@@ -278,30 +253,40 @@ public:
if( active != connected ) m_active.store( connected, std::memory_order_relaxed );
if( connected ) queue = true;
}
if( !queue ) return false;
if( !queue )
{
m_lockable.lock();
return;
}
#endif
const auto thread = GetThreadHandle();
auto item = Profiler::QueueSerial();
MemWrite( &item->hdr.type, QueueType::LockWait );
MemWrite( &item->lockWait.thread, GetThreadHandle() );
MemWrite( &item->lockWait.id, m_id );
MemWrite( &item->lockWait.time, Profiler::GetTime() );
Profiler::QueueSerialFinish();
return true;
{
auto item = Profiler::QueueSerial();
MemWrite( &item->hdr.type, QueueType::LockWait );
MemWrite( &item->lockWait.thread, thread );
MemWrite( &item->lockWait.id, m_id );
MemWrite( &item->lockWait.time, Profiler::GetTime() );
MemWrite( &item->lockWait.type, LockType::SharedLockable );
Profiler::QueueSerialFinish();
}
m_lockable.lock();
{
auto item = Profiler::QueueSerial();
MemWrite( &item->hdr.type, QueueType::LockObtain );
MemWrite( &item->lockObtain.thread, thread );
MemWrite( &item->lockObtain.id, m_id );
MemWrite( &item->lockObtain.time, Profiler::GetTime() );
Profiler::QueueSerialFinish();
}
}
tracy_force_inline void AfterLock()
tracy_force_inline void unlock()
{
auto item = Profiler::QueueSerial();
MemWrite( &item->hdr.type, QueueType::LockObtain );
MemWrite( &item->lockObtain.thread, GetThreadHandle() );
MemWrite( &item->lockObtain.id, m_id );
MemWrite( &item->lockObtain.time, Profiler::GetTime() );
Profiler::QueueSerialFinish();
}
m_lockable.unlock();
tracy_force_inline void AfterUnlock()
{
#ifdef TRACY_ON_DEMAND
m_lockCount.fetch_sub( 1, std::memory_order_relaxed );
if( !m_active.load( std::memory_order_relaxed ) ) return;
@@ -314,15 +299,18 @@ public:
auto item = Profiler::QueueSerial();
MemWrite( &item->hdr.type, QueueType::LockRelease );
MemWrite( &item->lockRelease.thread, GetThreadHandle() );
MemWrite( &item->lockRelease.id, m_id );
MemWrite( &item->lockRelease.time, Profiler::GetTime() );
Profiler::QueueSerialFinish();
}
tracy_force_inline void AfterTryLock( bool acquired )
tracy_force_inline bool try_lock()
{
const auto ret = m_lockable.try_lock();
#ifdef TRACY_ON_DEMAND
if( !acquired ) return;
if( !ret ) return ret;
bool queue = false;
const auto locks = m_lockCount.fetch_add( 1, std::memory_order_relaxed );
@@ -333,10 +321,10 @@ public:
if( active != connected ) m_active.store( connected, std::memory_order_relaxed );
if( connected ) queue = true;
}
if( !queue ) return;
if( !queue ) return ret;
#endif
if( acquired )
if( ret )
{
auto item = Profiler::QueueSerial();
MemWrite( &item->hdr.type, QueueType::LockObtain );
@@ -345,9 +333,11 @@ public:
MemWrite( &item->lockObtain.time, Profiler::GetTime() );
Profiler::QueueSerialFinish();
}
return ret;
}
tracy_force_inline bool BeforeLockShared()
tracy_force_inline void lock_shared()
{
#ifdef TRACY_ON_DEMAND
bool queue = false;
@@ -359,30 +349,40 @@ public:
if( active != connected ) m_active.store( connected, std::memory_order_relaxed );
if( connected ) queue = true;
}
if( !queue ) return false;
if( !queue )
{
m_lockable.lock_shared();
return;
}
#endif
const auto thread = GetThreadHandle();
auto item = Profiler::QueueSerial();
MemWrite( &item->hdr.type, QueueType::LockSharedWait );
MemWrite( &item->lockWait.thread, GetThreadHandle() );
MemWrite( &item->lockWait.id, m_id );
MemWrite( &item->lockWait.time, Profiler::GetTime() );
Profiler::QueueSerialFinish();
return true;
{
auto item = Profiler::QueueSerial();
MemWrite( &item->hdr.type, QueueType::LockSharedWait );
MemWrite( &item->lockWait.thread, thread );
MemWrite( &item->lockWait.id, m_id );
MemWrite( &item->lockWait.time, Profiler::GetTime() );
MemWrite( &item->lockWait.type, LockType::SharedLockable );
Profiler::QueueSerialFinish();
}
m_lockable.lock_shared();
{
auto item = Profiler::QueueSerial();
MemWrite( &item->hdr.type, QueueType::LockSharedObtain );
MemWrite( &item->lockObtain.thread, thread );
MemWrite( &item->lockObtain.id, m_id );
MemWrite( &item->lockObtain.time, Profiler::GetTime() );
Profiler::QueueSerialFinish();
}
}
tracy_force_inline void AfterLockShared()
tracy_force_inline void unlock_shared()
{
auto item = Profiler::QueueSerial();
MemWrite( &item->hdr.type, QueueType::LockSharedObtain );
MemWrite( &item->lockObtain.thread, GetThreadHandle() );
MemWrite( &item->lockObtain.id, m_id );
MemWrite( &item->lockObtain.time, Profiler::GetTime() );
Profiler::QueueSerialFinish();
}
m_lockable.unlock_shared();
tracy_force_inline void AfterUnlockShared()
{
#ifdef TRACY_ON_DEMAND
m_lockCount.fetch_sub( 1, std::memory_order_relaxed );
if( !m_active.load( std::memory_order_relaxed ) ) return;
@@ -395,16 +395,18 @@ public:
auto item = Profiler::QueueSerial();
MemWrite( &item->hdr.type, QueueType::LockSharedRelease );
MemWrite( &item->lockReleaseShared.thread, GetThreadHandle() );
MemWrite( &item->lockReleaseShared.id, m_id );
MemWrite( &item->lockReleaseShared.time, Profiler::GetTime() );
MemWrite( &item->lockRelease.thread, GetThreadHandle() );
MemWrite( &item->lockRelease.id, m_id );
MemWrite( &item->lockRelease.time, Profiler::GetTime() );
Profiler::QueueSerialFinish();
}
tracy_force_inline void AfterTryLockShared( bool acquired )
tracy_force_inline bool try_lock_shared()
{
const auto ret = m_lockable.try_lock_shared();
#ifdef TRACY_ON_DEMAND
if( !acquired ) return;
if( !ret ) return ret;
bool queue = false;
const auto locks = m_lockCount.fetch_add( 1, std::memory_order_relaxed );
@@ -415,10 +417,10 @@ public:
if( active != connected ) m_active.store( connected, std::memory_order_relaxed );
if( connected ) queue = true;
}
if( !queue ) return;
if( !queue ) return ret;
#endif
if( acquired )
if( ret )
{
auto item = Profiler::QueueSerial();
MemWrite( &item->hdr.type, QueueType::LockSharedObtain );
@@ -427,6 +429,8 @@ public:
MemWrite( &item->lockObtain.time, Profiler::GetTime() );
Profiler::QueueSerialFinish();
}
return ret;
}
tracy_force_inline void Mark( const SourceLocationData* srcloc )
@@ -450,23 +454,8 @@ public:
Profiler::QueueSerialFinish();
}
tracy_force_inline void CustomName( const char* name, size_t size )
{
TRACY_ASSERT( size < (std::numeric_limits<uint16_t>::max)() );
auto ptr = (char*)tracy_malloc( size );
memcpy( ptr, name, size );
auto item = Profiler::QueueSerial();
MemWrite( &item->hdr.type, QueueType::LockName );
MemWrite( &item->lockNameFat.id, m_id );
MemWrite( &item->lockNameFat.name, (uint64_t)ptr );
MemWrite( &item->lockNameFat.size, (uint16_t)size );
#ifdef TRACY_ON_DEMAND
GetProfiler().DeferItem( *item );
#endif
Profiler::QueueSerialFinish();
}
private:
T m_lockable;
uint32_t m_id;
#ifdef TRACY_ON_DEMAND
@@ -475,75 +464,7 @@ private:
#endif
};
template<class T>
class SharedLockable
{
public:
tracy_force_inline SharedLockable( const SourceLocationData* srcloc )
: m_ctx( srcloc )
{
}
SharedLockable( const SharedLockable& ) = delete;
SharedLockable& operator=( const SharedLockable& ) = delete;
tracy_force_inline void lock()
{
const auto runAfter = m_ctx.BeforeLock();
m_lockable.lock();
if( runAfter ) m_ctx.AfterLock();
}
tracy_force_inline void unlock()
{
m_lockable.unlock();
m_ctx.AfterUnlock();
}
tracy_force_inline bool try_lock()
{
const auto acquired = m_lockable.try_lock();
m_ctx.AfterTryLock( acquired );
return acquired;
}
tracy_force_inline void lock_shared()
{
const auto runAfter = m_ctx.BeforeLockShared();
m_lockable.lock_shared();
if( runAfter ) m_ctx.AfterLockShared();
}
tracy_force_inline void unlock_shared()
{
m_lockable.unlock_shared();
m_ctx.AfterUnlockShared();
}
tracy_force_inline bool try_lock_shared()
{
const auto acquired = m_lockable.try_lock_shared();
m_ctx.AfterTryLockShared( acquired );
return acquired;
}
tracy_force_inline void Mark( const SourceLocationData* srcloc )
{
m_ctx.Mark( srcloc );
}
tracy_force_inline void CustomName( const char* name, size_t size )
{
m_ctx.CustomName( name, size );
}
T m_lockable;
private:
SharedLockableCtx m_ctx;
};
}
#endif

2533
client/TracyProfiler.cpp Normal file

File diff suppressed because it is too large Load Diff

580
client/TracyProfiler.hpp Normal file
View File

@@ -0,0 +1,580 @@
#ifndef __TRACYPROFILER_HPP__
#define __TRACYPROFILER_HPP__
#include <assert.h>
#include <atomic>
#include <chrono>
#include <stdint.h>
#include <string.h>
#include "tracy_concurrentqueue.h"
#include "TracyCallstack.hpp"
#include "TracySysTime.hpp"
#include "TracySysTrace.hpp"
#include "TracyFastVector.hpp"
#include "../common/TracyQueue.hpp"
#include "../common/TracyAlign.hpp"
#include "../common/TracyAlloc.hpp"
#include "../common/TracyMutex.hpp"
#include "../common/TracySystem.hpp"
#if defined _WIN32 || defined __CYGWIN__
# include <intrin.h>
#endif
#ifdef __APPLE__
# include <TargetConditionals.h>
# include <mach/mach_time.h>
#endif
#if defined _WIN32 || defined __CYGWIN__ || ( ( defined __i386 || defined _M_IX86 || defined __x86_64__ || defined _M_X64 ) && !defined __ANDROID__ ) || __ARM_ARCH >= 6
# define TRACY_HW_TIMER
#endif
#ifndef TracyConcat
# define TracyConcat(x,y) TracyConcatIndirect(x,y)
#endif
#ifndef TracyConcatIndirect
# define TracyConcatIndirect(x,y) x##y
#endif
namespace tracy
{
class GpuCtx;
class Profiler;
class Socket;
class UdpBroadcast;
struct GpuCtxWrapper
{
GpuCtx* ptr;
};
TRACY_API moodycamel::ConcurrentQueue<QueueItem>::ExplicitProducer* GetToken();
TRACY_API Profiler& GetProfiler();
TRACY_API std::atomic<uint32_t>& GetLockCounter();
TRACY_API std::atomic<uint8_t>& GetGpuCtxCounter();
TRACY_API GpuCtxWrapper& GetGpuCtx();
TRACY_API uint64_t GetThreadHandle();
TRACY_API void InitRPMallocThread();
struct SourceLocationData
{
const char* name;
const char* function;
const char* file;
uint32_t line;
uint32_t color;
};
#ifdef TRACY_ON_DEMAND
struct LuaZoneState
{
uint32_t counter;
bool active;
};
#endif
using Magic = moodycamel::ConcurrentQueueDefaultTraits::index_t;
class Profiler
{
struct FrameImageQueueItem
{
void* image;
uint64_t frame;
uint16_t w;
uint16_t h;
uint8_t offset;
bool flip;
};
public:
Profiler();
~Profiler();
static tracy_force_inline int64_t GetTime()
{
#ifdef TRACY_HW_TIMER
# if TARGET_OS_IOS == 1
return mach_absolute_time();
# elif __ARM_ARCH >= 6
# ifdef CLOCK_MONOTONIC_RAW
struct timespec ts;
clock_gettime( CLOCK_MONOTONIC_RAW, &ts );
return int64_t( ts.tv_sec ) * 1000000000ll + int64_t( ts.tv_nsec );
# else
return std::chrono::duration_cast<std::chrono::nanoseconds>( std::chrono::high_resolution_clock::now().time_since_epoch() ).count();
# endif
# elif defined _WIN32 || defined __CYGWIN__
unsigned int dontcare;
const auto t = int64_t( __rdtscp( &dontcare ) );
return t;
# elif defined __i386 || defined _M_IX86 || defined __x86_64__ || defined _M_X64
uint32_t eax, edx;
asm volatile ( "rdtscp" : "=a" (eax), "=d" (edx) :: "%ecx" );
return ( uint64_t( edx ) << 32 ) + uint64_t( eax );
# endif
#else
return std::chrono::duration_cast<std::chrono::nanoseconds>( std::chrono::high_resolution_clock::now().time_since_epoch() ).count();
#endif
}
tracy_force_inline uint32_t GetNextZoneId()
{
return m_zoneId.fetch_add( 1, std::memory_order_relaxed );
}
static tracy_force_inline QueueItem* QueueSerial()
{
auto& p = GetProfiler();
p.m_serialLock.lock();
return p.m_serialQueue.prepare_next();
}
static tracy_force_inline void QueueSerialFinish()
{
auto& p = GetProfiler();
p.m_serialQueue.commit_next();
p.m_serialLock.unlock();
}
static tracy_force_inline void SendFrameMark( const char* name )
{
if( !name ) GetProfiler().m_frameCount.fetch_add( 1, std::memory_order_relaxed );
#ifdef TRACY_ON_DEMAND
if( !GetProfiler().IsConnected() ) return;
#endif
Magic magic;
auto token = GetToken();
auto& tail = token->get_tail_index();
auto item = token->enqueue_begin( magic );
MemWrite( &item->hdr.type, QueueType::FrameMarkMsg );
MemWrite( &item->frameMark.time, GetTime() );
MemWrite( &item->frameMark.name, uint64_t( name ) );
tail.store( magic + 1, std::memory_order_release );
}
static tracy_force_inline void SendFrameMark( const char* name, QueueType type )
{
assert( type == QueueType::FrameMarkMsgStart || type == QueueType::FrameMarkMsgEnd );
#ifdef TRACY_ON_DEMAND
if( !GetProfiler().IsConnected() ) return;
#endif
auto item = QueueSerial();
MemWrite( &item->hdr.type, type );
MemWrite( &item->frameMark.time, GetTime() );
MemWrite( &item->frameMark.name, uint64_t( name ) );
QueueSerialFinish();
}
static tracy_force_inline void SendFrameImage( const void* image, uint16_t w, uint16_t h, uint8_t offset, bool flip )
{
auto& profiler = GetProfiler();
#ifdef TRACY_ON_DEMAND
if( !profiler.IsConnected() ) return;
#endif
const auto sz = size_t( w ) * size_t( h ) * 4;
auto ptr = (char*)tracy_malloc( sz );
memcpy( ptr, image, sz );
profiler.m_fiLock.lock();
auto fi = profiler.m_fiQueue.prepare_next();
fi->image = ptr;
fi->frame = profiler.m_frameCount.load( std::memory_order_relaxed ) - offset;
fi->w = w;
fi->h = h;
fi->flip = flip;
profiler.m_fiQueue.commit_next();
profiler.m_fiLock.unlock();
}
static tracy_force_inline void PlotData( const char* name, int64_t val )
{
#ifdef TRACY_ON_DEMAND
if( !GetProfiler().IsConnected() ) return;
#endif
Magic magic;
auto token = GetToken();
auto& tail = token->get_tail_index();
auto item = token->enqueue_begin( magic );
MemWrite( &item->hdr.type, QueueType::PlotData );
MemWrite( &item->plotData.name, (uint64_t)name );
MemWrite( &item->plotData.time, GetTime() );
MemWrite( &item->plotData.type, PlotDataType::Int );
MemWrite( &item->plotData.data.i, val );
tail.store( magic + 1, std::memory_order_release );
}
static tracy_force_inline void PlotData( const char* name, float val )
{
#ifdef TRACY_ON_DEMAND
if( !GetProfiler().IsConnected() ) return;
#endif
Magic magic;
auto token = GetToken();
auto& tail = token->get_tail_index();
auto item = token->enqueue_begin( magic );
MemWrite( &item->hdr.type, QueueType::PlotData );
MemWrite( &item->plotData.name, (uint64_t)name );
MemWrite( &item->plotData.time, GetTime() );
MemWrite( &item->plotData.type, PlotDataType::Float );
MemWrite( &item->plotData.data.f, val );
tail.store( magic + 1, std::memory_order_release );
}
static tracy_force_inline void PlotData( const char* name, double val )
{
#ifdef TRACY_ON_DEMAND
if( !GetProfiler().IsConnected() ) return;
#endif
Magic magic;
auto token = GetToken();
auto& tail = token->get_tail_index();
auto item = token->enqueue_begin( magic );
MemWrite( &item->hdr.type, QueueType::PlotData );
MemWrite( &item->plotData.name, (uint64_t)name );
MemWrite( &item->plotData.time, GetTime() );
MemWrite( &item->plotData.type, PlotDataType::Double );
MemWrite( &item->plotData.data.d, val );
tail.store( magic + 1, std::memory_order_release );
}
static tracy_force_inline void Message( const char* txt, size_t size )
{
#ifdef TRACY_ON_DEMAND
if( !GetProfiler().IsConnected() ) return;
#endif
Magic magic;
auto token = GetToken();
auto ptr = (char*)tracy_malloc( size+1 );
memcpy( ptr, txt, size );
ptr[size] = '\0';
auto& tail = token->get_tail_index();
auto item = token->enqueue_begin( magic );
MemWrite( &item->hdr.type, QueueType::Message );
MemWrite( &item->message.time, GetTime() );
MemWrite( &item->message.text, (uint64_t)ptr );
tail.store( magic + 1, std::memory_order_release );
}
static tracy_force_inline void Message( const char* txt )
{
#ifdef TRACY_ON_DEMAND
if( !GetProfiler().IsConnected() ) return;
#endif
Magic magic;
auto token = GetToken();
auto& tail = token->get_tail_index();
auto item = token->enqueue_begin( magic );
MemWrite( &item->hdr.type, QueueType::MessageLiteral );
MemWrite( &item->message.time, GetTime() );
MemWrite( &item->message.text, (uint64_t)txt );
tail.store( magic + 1, std::memory_order_release );
}
static tracy_force_inline void MessageColor( const char* txt, size_t size, uint32_t color )
{
#ifdef TRACY_ON_DEMAND
if( !GetProfiler().IsConnected() ) return;
#endif
Magic magic;
auto token = GetToken();
auto ptr = (char*)tracy_malloc( size+1 );
memcpy( ptr, txt, size );
ptr[size] = '\0';
auto& tail = token->get_tail_index();
auto item = token->enqueue_begin( magic );
MemWrite( &item->hdr.type, QueueType::MessageColor );
MemWrite( &item->messageColor.time, GetTime() );
MemWrite( &item->messageColor.text, (uint64_t)ptr );
MemWrite( &item->messageColor.r, uint8_t( ( color ) & 0xFF ) );
MemWrite( &item->messageColor.g, uint8_t( ( color >> 8 ) & 0xFF ) );
MemWrite( &item->messageColor.b, uint8_t( ( color >> 16 ) & 0xFF ) );
tail.store( magic + 1, std::memory_order_release );
}
static tracy_force_inline void MessageColor( const char* txt, uint32_t color )
{
#ifdef TRACY_ON_DEMAND
if( !GetProfiler().IsConnected() ) return;
#endif
Magic magic;
auto token = GetToken();
auto& tail = token->get_tail_index();
auto item = token->enqueue_begin( magic );
MemWrite( &item->hdr.type, QueueType::MessageLiteralColor );
MemWrite( &item->messageColor.time, GetTime() );
MemWrite( &item->messageColor.text, (uint64_t)txt );
MemWrite( &item->messageColor.r, uint8_t( ( color ) & 0xFF ) );
MemWrite( &item->messageColor.g, uint8_t( ( color >> 8 ) & 0xFF ) );
MemWrite( &item->messageColor.b, uint8_t( ( color >> 16 ) & 0xFF ) );
tail.store( magic + 1, std::memory_order_release );
}
static tracy_force_inline void MessageAppInfo( const char* txt, size_t size )
{
Magic magic;
auto token = GetToken();
auto ptr = (char*)tracy_malloc( size+1 );
memcpy( ptr, txt, size );
ptr[size] = '\0';
auto& tail = token->get_tail_index();
auto item = token->enqueue_begin( magic );
MemWrite( &item->hdr.type, QueueType::MessageAppInfo );
MemWrite( &item->message.time, GetTime() );
MemWrite( &item->message.text, (uint64_t)ptr );
#ifdef TRACY_ON_DEMAND
GetProfiler().DeferItem( *item );
#endif
tail.store( magic + 1, std::memory_order_release );
}
static tracy_force_inline void MemAlloc( const void* ptr, size_t size )
{
#ifdef TRACY_ON_DEMAND
if( !GetProfiler().IsConnected() ) return;
#endif
const auto thread = GetThreadHandle();
GetProfiler().m_serialLock.lock();
SendMemAlloc( QueueType::MemAlloc, thread, ptr, size );
GetProfiler().m_serialLock.unlock();
}
static tracy_force_inline void MemFree( const void* ptr )
{
#ifdef TRACY_ON_DEMAND
if( !GetProfiler().IsConnected() ) return;
#endif
const auto thread = GetThreadHandle();
GetProfiler().m_serialLock.lock();
SendMemFree( QueueType::MemFree, thread, ptr );
GetProfiler().m_serialLock.unlock();
}
static tracy_force_inline void MemAllocCallstack( const void* ptr, size_t size, int depth )
{
auto& profiler = GetProfiler();
#ifdef TRACY_HAS_CALLSTACK
# ifdef TRACY_ON_DEMAND
if( !profiler.IsConnected() ) return;
# endif
const auto thread = GetThreadHandle();
rpmalloc_thread_initialize();
auto callstack = Callstack( depth );
profiler.m_serialLock.lock();
SendMemAlloc( QueueType::MemAllocCallstack, thread, ptr, size );
SendCallstackMemory( callstack );
profiler.m_serialLock.unlock();
#else
MemAlloc( ptr, size );
#endif
}
static tracy_force_inline void MemFreeCallstack( const void* ptr, int depth )
{
auto& profiler = GetProfiler();
#ifdef TRACY_HAS_CALLSTACK
# ifdef TRACY_ON_DEMAND
if( !profiler.IsConnected() ) return;
# endif
const auto thread = GetThreadHandle();
rpmalloc_thread_initialize();
auto callstack = Callstack( depth );
profiler.m_serialLock.lock();
SendMemFree( QueueType::MemFreeCallstack, thread, ptr );
SendCallstackMemory( callstack );
profiler.m_serialLock.unlock();
#else
MemFree( ptr );
#endif
}
static tracy_force_inline void SendCallstack( int depth )
{
#ifdef TRACY_HAS_CALLSTACK
auto ptr = Callstack( depth );
Magic magic;
auto token = GetToken();
auto& tail = token->get_tail_index();
auto item = token->enqueue_begin( magic );
MemWrite( &item->hdr.type, QueueType::Callstack );
MemWrite( &item->callstack.ptr, ptr );
tail.store( magic + 1, std::memory_order_release );
#endif
}
void SendCallstack( int depth, const char* skipBefore );
static void CutCallstack( void* callstack, const char* skipBefore );
static bool ShouldExit();
#ifdef TRACY_ON_DEMAND
tracy_force_inline bool IsConnected() const
{
return m_isConnected.load( std::memory_order_acquire );
}
tracy_force_inline uint64_t ConnectionId() const
{
return m_connectionId.load( std::memory_order_acquire );
}
tracy_force_inline void DeferItem( const QueueItem& item )
{
m_deferredLock.lock();
auto dst = m_deferredQueue.push_next();
memcpy( dst, &item, sizeof( item ) );
m_deferredLock.unlock();
}
#endif
void RequestShutdown() { m_shutdown.store( true, std::memory_order_relaxed ); m_shutdownManual.store( true, std::memory_order_relaxed ); }
bool HasShutdownFinished() const { return m_shutdownFinished.load( std::memory_order_relaxed ); }
void SendString( uint64_t ptr, const char* str, QueueType type );
private:
enum class DequeueStatus { Success, ConnectionLost, QueueEmpty };
static void LaunchWorker( void* ptr ) { ((Profiler*)ptr)->Worker(); }
void Worker();
static void LaunchCompressWorker( void* ptr ) { ((Profiler*)ptr)->CompressWorker(); }
void CompressWorker();
void ClearQueues( tracy::moodycamel::ConsumerToken& token );
void ClearSerial();
DequeueStatus Dequeue( tracy::moodycamel::ConsumerToken& token );
DequeueStatus DequeueContextSwitches( tracy::moodycamel::ConsumerToken& token, int64_t& timeStop );
DequeueStatus DequeueSerial();
bool AppendData( const void* data, size_t len );
bool CommitData();
bool NeedDataSize( size_t len );
tracy_force_inline void AppendDataUnsafe( const void* data, size_t len )
{
memcpy( m_buffer + m_bufferOffset, data, len );
m_bufferOffset += int( len );
}
bool SendData( const char* data, size_t len );
void SendLongString( uint64_t ptr, const char* str, size_t len, QueueType type );
void SendSourceLocation( uint64_t ptr );
void SendSourceLocationPayload( uint64_t ptr );
void SendCallstackPayload( uint64_t ptr );
void SendCallstackAlloc( uint64_t ptr );
void SendCallstackFrame( uint64_t ptr );
bool HandleServerQuery();
void HandleDisconnect();
void CalibrateTimer();
void CalibrateDelay();
static tracy_force_inline void SendCallstackMemory( void* ptr )
{
#ifdef TRACY_HAS_CALLSTACK
auto item = GetProfiler().m_serialQueue.prepare_next();
MemWrite( &item->hdr.type, QueueType::CallstackMemory );
MemWrite( &item->callstackMemory.ptr, (uint64_t)ptr );
GetProfiler().m_serialQueue.commit_next();
#endif
}
static tracy_force_inline void SendMemAlloc( QueueType type, const uint64_t thread, const void* ptr, size_t size )
{
assert( type == QueueType::MemAlloc || type == QueueType::MemAllocCallstack );
auto item = GetProfiler().m_serialQueue.prepare_next();
MemWrite( &item->hdr.type, type );
MemWrite( &item->memAlloc.time, GetTime() );
MemWrite( &item->memAlloc.thread, thread );
MemWrite( &item->memAlloc.ptr, (uint64_t)ptr );
if( compile_time_condition<sizeof( size ) == 4>::value )
{
memcpy( &item->memAlloc.size, &size, 4 );
memset( &item->memAlloc.size + 4, 0, 2 );
}
else
{
assert( sizeof( size ) == 8 );
memcpy( &item->memAlloc.size, &size, 6 );
}
GetProfiler().m_serialQueue.commit_next();
}
static tracy_force_inline void SendMemFree( QueueType type, const uint64_t thread, const void* ptr )
{
assert( type == QueueType::MemFree || type == QueueType::MemFreeCallstack );
auto item = GetProfiler().m_serialQueue.prepare_next();
MemWrite( &item->hdr.type, type );
MemWrite( &item->memFree.time, GetTime() );
MemWrite( &item->memFree.thread, thread );
MemWrite( &item->memFree.ptr, (uint64_t)ptr );
GetProfiler().m_serialQueue.commit_next();
}
double m_timerMul;
uint64_t m_resolution;
uint64_t m_delay;
std::atomic<int64_t> m_timeBegin;
uint64_t m_mainThread;
uint64_t m_epoch;
std::atomic<bool> m_shutdown;
std::atomic<bool> m_shutdownManual;
std::atomic<bool> m_shutdownFinished;
Socket* m_sock;
UdpBroadcast* m_broadcast;
bool m_noExit;
std::atomic<uint32_t> m_zoneId;
uint64_t m_threadCtx;
void* m_stream; // LZ4_stream_t*
char* m_buffer;
int m_bufferOffset;
int m_bufferStart;
QueueItem* m_itemBuf;
char* m_lz4Buf;
FastVector<QueueItem> m_serialQueue, m_serialDequeue;
TracyMutex m_serialLock;
FastVector<FrameImageQueueItem> m_fiQueue, m_fiDequeue;
TracyMutex m_fiLock;
std::atomic<uint64_t> m_frameCount;
#ifdef TRACY_ON_DEMAND
std::atomic<bool> m_isConnected;
std::atomic<uint64_t> m_connectionId;
TracyMutex m_deferredLock;
FastVector<QueueItem> m_deferredQueue;
#endif
#ifdef TRACY_HAS_SYSTIME
void ProcessSysTime();
SysTime m_sysTime;
uint64_t m_sysTimeLast = 0;
#else
void ProcessSysTime() {}
#endif
};
};
#endif

119
client/TracyScoped.hpp Normal file
View File

@@ -0,0 +1,119 @@
#ifndef __TRACYSCOPED_HPP__
#define __TRACYSCOPED_HPP__
#include <stdint.h>
#include <string.h>
#include "../common/TracySystem.hpp"
#include "../common/TracyAlign.hpp"
#include "../common/TracyAlloc.hpp"
#include "TracyProfiler.hpp"
namespace tracy
{
class ScopedZone
{
public:
tracy_force_inline ScopedZone( const SourceLocationData* srcloc, bool is_active = true )
#ifdef TRACY_ON_DEMAND
: m_active( is_active && GetProfiler().IsConnected() )
, m_connectionId( GetProfiler().ConnectionId() )
#else
: m_active( is_active )
#endif
{
if( !m_active ) return;
Magic magic;
auto token = GetToken();
auto& tail = token->get_tail_index();
auto item = token->enqueue_begin( magic );
MemWrite( &item->hdr.type, QueueType::ZoneBegin );
MemWrite( &item->zoneBegin.time, Profiler::GetTime() );
MemWrite( &item->zoneBegin.srcloc, (uint64_t)srcloc );
tail.store( magic + 1, std::memory_order_release );
}
tracy_force_inline ScopedZone( const SourceLocationData* srcloc, int depth, bool is_active = true )
#ifdef TRACY_ON_DEMAND
: m_active( is_active && GetProfiler().IsConnected() )
, m_connectionId( GetProfiler().ConnectionId() )
#else
: m_active( is_active )
#endif
{
if( !m_active ) return;
Magic magic;
auto token = GetToken();
auto& tail = token->get_tail_index();
auto item = token->enqueue_begin( magic );
MemWrite( &item->hdr.type, QueueType::ZoneBeginCallstack );
MemWrite( &item->zoneBegin.time, Profiler::GetTime() );
MemWrite( &item->zoneBegin.srcloc, (uint64_t)srcloc );
tail.store( magic + 1, std::memory_order_release );
GetProfiler().SendCallstack( depth );
}
tracy_force_inline ~ScopedZone()
{
if( !m_active ) return;
#ifdef TRACY_ON_DEMAND
if( GetProfiler().ConnectionId() != m_connectionId ) return;
#endif
Magic magic;
auto token = GetToken();
auto& tail = token->get_tail_index();
auto item = token->enqueue_begin( magic );
MemWrite( &item->hdr.type, QueueType::ZoneEnd );
MemWrite( &item->zoneEnd.time, Profiler::GetTime() );
tail.store( magic + 1, std::memory_order_release );
}
tracy_force_inline void Text( const char* txt, size_t size )
{
if( !m_active ) return;
#ifdef TRACY_ON_DEMAND
if( GetProfiler().ConnectionId() != m_connectionId ) return;
#endif
Magic magic;
auto token = GetToken();
auto ptr = (char*)tracy_malloc( size+1 );
memcpy( ptr, txt, size );
ptr[size] = '\0';
auto& tail = token->get_tail_index();
auto item = token->enqueue_begin( magic );
MemWrite( &item->hdr.type, QueueType::ZoneText );
MemWrite( &item->zoneText.text, (uint64_t)ptr );
tail.store( magic + 1, std::memory_order_release );
}
tracy_force_inline void Name( const char* txt, size_t size )
{
if( !m_active ) return;
#ifdef TRACY_ON_DEMAND
if( GetProfiler().ConnectionId() != m_connectionId ) return;
#endif
Magic magic;
auto token = GetToken();
auto ptr = (char*)tracy_malloc( size+1 );
memcpy( ptr, txt, size );
ptr[size] = '\0';
auto& tail = token->get_tail_index();
auto item = token->enqueue_begin( magic );
MemWrite( &item->hdr.type, QueueType::ZoneName );
MemWrite( &item->zoneText.text, (uint64_t)ptr );
tail.store( magic + 1, std::memory_order_release );
}
private:
const bool m_active;
#ifdef TRACY_ON_DEMAND
uint64_t m_connectionId;
#endif
};
}
#endif

View File

@@ -2,24 +2,21 @@
#ifdef TRACY_HAS_SYSTIME
# if defined _WIN32
# if defined _WIN32 || defined __CYGWIN__
# include <windows.h>
# include "../common/TracyWinFamily.hpp"
# elif defined __linux__
# include <assert.h>
# include <stdio.h>
# include <inttypes.h>
# elif defined __APPLE__
# include <mach/mach_host.h>
# include <mach/host_info.h>
# elif defined __FreeBSD__ || defined __NetBSD__ || defined __OpenBSD__ || defined __DragonFly__
# include <sys/types.h>
# include <sys/sysctl.h>
# endif
namespace tracy
{
# if defined _WIN32
# if defined _WIN32 || defined __CYGWIN__
static inline uint64_t ConvertTime( const FILETIME& t )
{
@@ -28,24 +25,13 @@ static inline uint64_t ConvertTime( const FILETIME& t )
void SysTime::ReadTimes()
{
FILETIME idleTime;
FILETIME kernelTime;
FILETIME userTime;
# if defined TRACY_GDK
FILETIME creationTime;
FILETIME exitTime;
GetProcessTimes( GetCurrentProcess(), &creationTime, &exitTime, &kernelTime, &userTime );
idle = 0;
# else
FILETIME idleTime;
GetSystemTimes( &idleTime, &kernelTime, &userTime );
idle = ConvertTime( idleTime );
# endif
const auto kernel = ConvertTime( kernelTime );
const auto user = ConvertTime( userTime );
used = kernel + user;
@@ -59,12 +45,9 @@ void SysTime::ReadTimes()
FILE* f = fopen( "/proc/stat", "r" );
if( f )
{
int read = fscanf( f, "cpu %" PRIu64 " %" PRIu64 " %" PRIu64" %" PRIu64, &user, &nice, &system, &idle );
fscanf( f, "cpu %" PRIu64 " %" PRIu64 " %" PRIu64" %" PRIu64, &user, &nice, &system, &idle );
fclose( f );
if (read == 4)
{
used = user + nice + system;
}
used = user + nice + system;
}
}
@@ -74,22 +57,11 @@ void SysTime::ReadTimes()
{
host_cpu_load_info_data_t info;
mach_msg_type_number_t cnt = HOST_CPU_LOAD_INFO_COUNT;
host_statistics( mach_host_self(), HOST_CPU_LOAD_INFO, reinterpret_cast<host_info_t>( &info ), &cnt );
host_statistics( mach_host_self(), HOST_CPU_LOAD_INFO, reinterpret_cast<host_info_t>( &info ), &cnt );
used = info.cpu_ticks[CPU_STATE_USER] + info.cpu_ticks[CPU_STATE_NICE] + info.cpu_ticks[CPU_STATE_SYSTEM];
idle = info.cpu_ticks[CPU_STATE_IDLE];
}
# elif defined __FreeBSD__ || defined __NetBSD__ || defined __OpenBSD__ || defined __DragonFly__
void SysTime::ReadTimes()
{
u_long data[5];
size_t sz = sizeof( data );
sysctlbyname( "kern.cp_time", &data, &sz, nullptr, 0 );
used = data[0] + data[1] + data[2] + data[3];
idle = data[4];
}
#endif
SysTime::SysTime()
@@ -107,9 +79,9 @@ float SysTime::Get()
const auto diffIdle = idle - oldIdle;
const auto diffUsed = used - oldUsed;
#if defined _WIN32
#if defined _WIN32 || defined __CYGWIN__
return diffUsed == 0 ? -1 : ( diffUsed - diffIdle ) * 100.f / diffUsed;
#elif defined __linux__ || defined __APPLE__ || defined __FreeBSD__ || defined __NetBSD__ || defined __OpenBSD__ || defined __DragonFly__
#elif defined __linux__ || defined __APPLE__
const auto total = diffUsed + diffIdle;
return total == 0 ? -1 : diffUsed * 100.f / total;
#endif

View File

@@ -1,7 +1,7 @@
#ifndef __TRACYSYSTIME_HPP__
#define __TRACYSYSTIME_HPP__
#if defined _WIN32 || defined __linux__ || defined __APPLE__ || defined __FreeBSD__ || defined __NetBSD__ || defined __OpenBSD__ || defined __DragonFly__
#if defined _WIN32 || defined __CYGWIN__ || defined __linux__ || defined __APPLE__
# define TRACY_HAS_SYSTIME
#endif

805
client/TracySysTrace.cpp Normal file
View File

@@ -0,0 +1,805 @@
#include "TracySysTrace.hpp"
#ifdef TRACY_HAS_SYSTEM_TRACING
# if defined _WIN32 || defined __CYGWIN__
# define INITGUID
# include <assert.h>
# include <string.h>
# include <windows.h>
# include <dbghelp.h>
# include <evntrace.h>
# include <evntcons.h>
# include <psapi.h>
# include <winternl.h>
# include "../common/TracyAlloc.hpp"
# include "../common/TracySystem.hpp"
# include "TracyProfiler.hpp"
namespace tracy
{
TRACEHANDLE s_traceHandle;
TRACEHANDLE s_traceHandle2;
EVENT_TRACE_PROPERTIES* s_prop;
struct CSwitch
{
uint32_t newThreadId;
uint32_t oldThreadId;
int8_t newThreadPriority;
int8_t oldThreadPriority;
uint8_t previousCState;
int8_t spareByte;
int8_t oldThreadWaitReason;
int8_t oldThreadWaitMode;
int8_t oldThreadState;
int8_t oldThreadWaitIdealProcessor;
uint32_t newThreadWaitTime;
uint32_t reserved;
};
struct ReadyThread
{
uint32_t threadId;
int8_t adjustReason;
int8_t adjustIncrement;
int8_t flag;
int8_t reserverd;
};
void WINAPI EventRecordCallback( PEVENT_RECORD record )
{
#ifdef TRACY_ON_DEMAND
if( !GetProfiler().IsConnected() ) return;
#endif
const auto& hdr = record->EventHeader;
if( hdr.EventDescriptor.Opcode == 36 )
{
const auto cswitch = (const CSwitch*)record->UserData;
Magic magic;
auto token = GetToken();
auto& tail = token->get_tail_index();
auto item = token->enqueue_begin( magic );
MemWrite( &item->hdr.type, QueueType::ContextSwitch );
MemWrite( &item->contextSwitch.time, hdr.TimeStamp.QuadPart );
memcpy( &item->contextSwitch.oldThread, &cswitch->oldThreadId, sizeof( cswitch->oldThreadId ) );
memcpy( &item->contextSwitch.newThread, &cswitch->newThreadId, sizeof( cswitch->newThreadId ) );
memset( ((char*)&item->contextSwitch.oldThread)+4, 0, 4 );
memset( ((char*)&item->contextSwitch.newThread)+4, 0, 4 );
MemWrite( &item->contextSwitch.cpu, record->BufferContext.ProcessorNumber );
MemWrite( &item->contextSwitch.reason, cswitch->oldThreadWaitReason );
MemWrite( &item->contextSwitch.state, cswitch->oldThreadState );
tail.store( magic + 1, std::memory_order_release );
}
else if( hdr.EventDescriptor.Opcode == 50 )
{
const auto rt = (const ReadyThread*)record->UserData;
Magic magic;
auto token = GetToken();
auto& tail = token->get_tail_index();
auto item = token->enqueue_begin( magic );
MemWrite( &item->hdr.type, QueueType::ThreadWakeup );
MemWrite( &item->threadWakeup.time, hdr.TimeStamp.QuadPart );
memcpy( &item->threadWakeup.thread, &rt->threadId, sizeof( rt->threadId ) );
memset( ((char*)&item->threadWakeup.thread)+4, 0, 4 );
tail.store( magic + 1, std::memory_order_release );
}
}
bool SysTraceStart()
{
TOKEN_PRIVILEGES priv = {};
priv.PrivilegeCount = 1;
priv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if( LookupPrivilegeValue( nullptr, SE_SYSTEM_PROFILE_NAME, &priv.Privileges[0].Luid ) == 0 ) return false;
HANDLE pt;
if( OpenProcessToken( GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &pt ) == 0 ) return false;
const auto adjust = AdjustTokenPrivileges( pt, FALSE, &priv, 0, nullptr, nullptr );
CloseHandle( pt );
if( adjust == 0 ) return false;
const auto status = GetLastError();
if( status != ERROR_SUCCESS ) return false;
const auto psz = sizeof( EVENT_TRACE_PROPERTIES ) + sizeof( KERNEL_LOGGER_NAME );
s_prop = (EVENT_TRACE_PROPERTIES*)tracy_malloc( psz );
memset( s_prop, 0, sizeof( EVENT_TRACE_PROPERTIES ) );
s_prop->EnableFlags = EVENT_TRACE_FLAG_CSWITCH | EVENT_TRACE_FLAG_DISPATCHER;
s_prop->LogFileMode = EVENT_TRACE_REAL_TIME_MODE;
s_prop->Wnode.BufferSize = psz;
s_prop->Wnode.Flags = WNODE_FLAG_TRACED_GUID;
s_prop->Wnode.ClientContext = 3;
s_prop->Wnode.Guid = SystemTraceControlGuid;
s_prop->LoggerNameOffset = sizeof( EVENT_TRACE_PROPERTIES );
memcpy( ((char*)s_prop) + sizeof( EVENT_TRACE_PROPERTIES ), KERNEL_LOGGER_NAME, sizeof( KERNEL_LOGGER_NAME ) );
auto backup = tracy_malloc( psz );
memcpy( backup, s_prop, psz );
const auto controlStatus = ControlTrace( 0, KERNEL_LOGGER_NAME, s_prop, EVENT_TRACE_CONTROL_STOP );
if( controlStatus != ERROR_SUCCESS && controlStatus != ERROR_WMI_INSTANCE_NOT_FOUND )
{
tracy_free( s_prop );
return false;
}
memcpy( s_prop, backup, psz );
tracy_free( backup );
const auto startStatus = StartTrace( &s_traceHandle, KERNEL_LOGGER_NAME, s_prop );
if( startStatus != ERROR_SUCCESS )
{
tracy_free( s_prop );
return false;
}
#ifdef UNICODE
WCHAR KernelLoggerName[sizeof( KERNEL_LOGGER_NAME )];
#else
char KernelLoggerName[sizeof( KERNEL_LOGGER_NAME )];
#endif
memcpy( KernelLoggerName, KERNEL_LOGGER_NAME, sizeof( KERNEL_LOGGER_NAME ) );
EVENT_TRACE_LOGFILE log = {};
log.LoggerName = KernelLoggerName;
log.ProcessTraceMode = PROCESS_TRACE_MODE_REAL_TIME | PROCESS_TRACE_MODE_EVENT_RECORD | PROCESS_TRACE_MODE_RAW_TIMESTAMP;
log.EventRecordCallback = EventRecordCallback;
s_traceHandle2 = OpenTrace( &log );
if( s_traceHandle2 == (TRACEHANDLE)INVALID_HANDLE_VALUE )
{
CloseTrace( s_traceHandle );
tracy_free( s_prop );
return false;
}
return true;
}
void SysTraceStop()
{
CloseTrace( s_traceHandle2 );
CloseTrace( s_traceHandle );
}
void SysTraceWorker( void* ptr )
{
SetThreadName( "Tracy SysTrace" );
ProcessTrace( &s_traceHandle2, 1, 0, 0 );
ControlTrace( 0, KERNEL_LOGGER_NAME, s_prop, EVENT_TRACE_CONTROL_STOP );
tracy_free( s_prop );
}
#ifdef __CYGWIN__
extern "C" typedef DWORD (WINAPI *t_GetProcessIdOfThread)( HANDLE );
extern "C" typedef DWORD (WINAPI *t_GetProcessImageFileNameA)( HANDLE, LPSTR, DWORD );
# ifdef UNICODE
t_GetProcessIdOfThread GetProcessIdOfThread = (t_GetProcessIdOfThread)GetProcAddress( GetModuleHandle( L"kernel32.dll" ), "GetProcessIdOfThread" );
t_GetProcessImageFileNameA GetProcessImageFileNameA = (t_GetProcessImageFileNameA)GetProcAddress( GetModuleHandle( L"kernel32.dll" ), "K32GetProcessImageFileNameA" );
# else
t_GetProcessIdOfThread GetProcessIdOfThread = (t_GetProcessIdOfThread)GetProcAddress( GetModuleHandle( "kernel32.dll" ), "GetProcessIdOfThread" );
t_GetProcessImageFileNameA GetProcessImageFileNameA = (t_GetProcessImageFileNameA)GetProcAddress( GetModuleHandle( "kernel32.dll" ), "K32GetProcessImageFileNameA" );
# endif
#endif
extern "C" typedef NTSTATUS (WINAPI *t_NtQueryInformationThread)( HANDLE, THREADINFOCLASS, PVOID, ULONG, PULONG );
extern "C" typedef BOOL (WINAPI *t_EnumProcessModules)( HANDLE, HMODULE*, DWORD, LPDWORD );
extern "C" typedef BOOL (WINAPI *t_GetModuleInformation)( HANDLE, HMODULE, LPMODULEINFO, DWORD );
extern "C" typedef DWORD (WINAPI *t_GetModuleBaseNameA)( HANDLE, HMODULE, LPSTR, DWORD );
#ifdef UNICODE
t_NtQueryInformationThread NtQueryInformationThread = (t_NtQueryInformationThread)GetProcAddress( GetModuleHandle( L"ntdll.dll" ), "NtQueryInformationThread" );
t_EnumProcessModules _EnumProcessModules = (t_EnumProcessModules)GetProcAddress( GetModuleHandle( L"kernel32.dll" ), "K32EnumProcessModules" );
t_GetModuleInformation _GetModuleInformation = (t_GetModuleInformation)GetProcAddress( GetModuleHandle( L"kernel32.dll" ), "K32GetModuleInformation" );
t_GetModuleBaseNameA _GetModuleBaseNameA = (t_GetModuleBaseNameA)GetProcAddress( GetModuleHandle( L"kernel32.dll" ), "K32GetModuleBaseNameA" );
#else
t_NtQueryInformationThread NtQueryInformationThread = (t_NtQueryInformationThread)GetProcAddress( GetModuleHandle( "ntdll.dll" ), "NtQueryInformationThread" );
t_EnumProcessModules _EnumProcessModules = (t_EnumProcessModules)GetProcAddress( GetModuleHandle( "kernel32.dll" ), "K32EnumProcessModules" );
t_GetModuleInformation _GetModuleInformation = (t_GetModuleInformation)GetProcAddress( GetModuleHandle( "kernel32.dll" ), "K32GetModuleInformation" );
t_GetModuleBaseNameA _GetModuleBaseNameA = (t_GetModuleBaseNameA)GetProcAddress( GetModuleHandle( "kernel32.dll" ), "K32GetModuleBaseNameA" );
#endif
void SysTraceSendExternalName( uint64_t thread )
{
bool threadSent = false;
auto hnd = OpenThread( THREAD_QUERY_INFORMATION, FALSE, DWORD( thread ) );
if( hnd == 0 )
{
hnd = OpenThread( THREAD_QUERY_LIMITED_INFORMATION, FALSE, DWORD( thread ) );
}
if( hnd != 0 )
{
#if defined NTDDI_WIN10_RS2 && NTDDI_VERSION >= NTDDI_WIN10_RS2
PWSTR tmp;
GetThreadDescription( hnd, &tmp );
char buf[256];
if( tmp )
{
auto ret = wcstombs( buf, tmp, 256 );
if( ret != 0 )
{
GetProfiler().SendString( thread, buf, QueueType::ExternalThreadName );
threadSent = true;
}
}
#endif
const auto pid = GetProcessIdOfThread( hnd );
if( !threadSent && NtQueryInformationThread && _EnumProcessModules && _GetModuleInformation && _GetModuleBaseNameA )
{
void* ptr;
ULONG retlen;
auto status = NtQueryInformationThread( hnd, (THREADINFOCLASS)9 /*ThreadQuerySetWin32StartAddress*/, &ptr, sizeof( &ptr ), &retlen );
if( status == 0 )
{
const auto phnd = OpenProcess( PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid );
if( phnd != INVALID_HANDLE_VALUE )
{
HMODULE modules[1024];
DWORD needed;
if( _EnumProcessModules( phnd, modules, 1024 * sizeof( HMODULE ), &needed ) != 0 )
{
const auto sz = std::min( DWORD( needed / sizeof( HMODULE ) ), DWORD( 1024 ) );
for( int i=0; i<sz; i++ )
{
MODULEINFO info;
if( _GetModuleInformation( phnd, modules[i], &info, sizeof( info ) ) != 0 )
{
if( (uint64_t)ptr >= (uint64_t)info.lpBaseOfDll && (uint64_t)ptr <= (uint64_t)info.lpBaseOfDll + (uint64_t)info.SizeOfImage )
{
char buf[1024];
if( _GetModuleBaseNameA( phnd, modules[i], buf, 1024 ) != 0 )
{
GetProfiler().SendString( thread, buf, QueueType::ExternalThreadName );
threadSent = true;
}
}
}
}
}
CloseHandle( phnd );
}
}
}
CloseHandle( hnd );
if( !threadSent )
{
GetProfiler().SendString( thread, "???", QueueType::ExternalThreadName );
}
if( pid != 0 )
{
{
uint64_t _pid = pid;
Magic magic;
auto token = GetToken();
auto& tail = token->get_tail_index();
auto item = token->enqueue_begin( magic );
MemWrite( &item->hdr.type, QueueType::TidToPid );
MemWrite( &item->tidToPid.tid, thread );
MemWrite( &item->tidToPid.pid, _pid );
tail.store( magic + 1, std::memory_order_release );
}
if( pid == 4 )
{
GetProfiler().SendString( thread, "System", QueueType::ExternalName );
return;
}
else
{
const auto phnd = OpenProcess( PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid );
if( phnd != INVALID_HANDLE_VALUE )
{
char buf[1024];
const auto sz = GetProcessImageFileNameA( phnd, buf, 1024 );
CloseHandle( phnd );
if( sz != 0 )
{
auto ptr = buf + sz - 1;
while( ptr > buf && *ptr != '\\' ) ptr--;
if( *ptr == '\\' ) ptr++;
GetProfiler().SendString( thread, ptr, QueueType::ExternalName );
return;
}
}
}
}
}
if( !threadSent )
{
GetProfiler().SendString( thread, "???", QueueType::ExternalThreadName );
}
GetProfiler().SendString( thread, "???", QueueType::ExternalName );
}
}
# elif defined __linux__
# include <sys/types.h>
# include <sys/stat.h>
# include <fcntl.h>
# include <inttypes.h>
# include <limits>
# include <poll.h>
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <unistd.h>
# include "TracyProfiler.hpp"
namespace tracy
{
static const char BasePath[] = "/sys/kernel/debug/tracing/";
static const char TracingOn[] = "tracing_on";
static const char CurrentTracer[] = "current_tracer";
static const char TraceOptions[] = "trace_options";
static const char TraceClock[] = "trace_clock";
static const char SchedSwitch[] = "events/sched/sched_switch/enable";
static const char SchedWakeup[] = "events/sched/sched_wakeup/enable";
static const char TracePipe[] = "trace_pipe";
#ifdef __ANDROID__
static bool TraceWrite( const char* path, size_t psz, const char* val, size_t vsz )
{
char tmp[256];
sprintf( tmp, "su -c 'echo \"%s\" > %s%s'", val, BasePath, path );
return system( tmp ) == 0;
}
#else
static bool TraceWrite( const char* path, size_t psz, const char* val, size_t vsz )
{
char tmp[256];
memcpy( tmp, BasePath, sizeof( BasePath ) - 1 );
memcpy( tmp + sizeof( BasePath ) - 1, path, psz );
int fd = open( tmp, O_WRONLY );
if( fd < 0 ) return false;
for(;;)
{
ssize_t cnt = write( fd, val, vsz );
if( cnt == (ssize_t)vsz )
{
close( fd );
return true;
}
if( cnt < 0 )
{
close( fd );
return false;
}
vsz -= cnt;
val += cnt;
}
}
#endif
bool SysTraceStart()
{
if( !TraceWrite( TracingOn, sizeof( TracingOn ), "0", 2 ) ) return false;
if( !TraceWrite( CurrentTracer, sizeof( CurrentTracer ), "nop", 4 ) ) return false;
TraceWrite( TraceOptions, sizeof( TraceOptions ), "norecord-cmd", 13 );
TraceWrite( TraceOptions, sizeof( TraceOptions ), "norecord-tgid", 14 );
TraceWrite( TraceOptions, sizeof( TraceOptions ), "noirq-info", 11 );
#if defined TRACY_HW_TIMER && ( defined __i386 || defined _M_IX86 || defined __x86_64__ || defined _M_X64 )
if( !TraceWrite( TraceClock, sizeof( TraceClock ), "x86-tsc", 8 ) ) return false;
#elif __ARM_ARCH >= 6
if( !TraceWrite( TraceClock, sizeof( TraceClock ), "mono_raw", 8 ) ) return false;
#endif
if( !TraceWrite( SchedSwitch, sizeof( SchedSwitch ), "1", 2 ) ) return false;
if( !TraceWrite( SchedWakeup, sizeof( SchedWakeup ), "1", 2 ) ) return false;
if( !TraceWrite( TracingOn, sizeof( TracingOn ), "1", 2 ) ) return false;
return true;
}
void SysTraceStop()
{
TraceWrite( TracingOn, sizeof( TracingOn ), "0", 2 );
}
static uint64_t ReadNumber( const char*& ptr )
{
uint64_t val = 0;
for(;;)
{
if( *ptr >= '0' && *ptr <= '9' )
{
val = val * 10 + ( *ptr - '0' );
ptr++;
}
else
{
return val;
}
}
}
static uint8_t ReadState( char state )
{
switch( state )
{
case 'D': return 101;
case 'I': return 102;
case 'R': return 103;
case 'S': return 104;
case 'T': return 105;
case 't': return 106;
case 'W': return 107;
case 'X': return 108;
case 'Z': return 109;
default: return 100;
}
}
#if defined __ANDROID__ && defined __ANDROID_API__ && __ANDROID_API__ < 18
/*-
* Copyright (c) 2011 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Christos Zoulas.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
ssize_t getdelim(char **buf, size_t *bufsiz, int delimiter, FILE *fp)
{
char *ptr, *eptr;
if (*buf == NULL || *bufsiz == 0) {
*bufsiz = BUFSIZ;
if ((*buf = (char*)malloc(*bufsiz)) == NULL)
return -1;
}
for (ptr = *buf, eptr = *buf + *bufsiz;;) {
int c = fgetc(fp);
if (c == -1) {
if (feof(fp))
return ptr == *buf ? -1 : ptr - *buf;
else
return -1;
}
*ptr++ = c;
if (c == delimiter) {
*ptr = '\0';
return ptr - *buf;
}
if (ptr + 2 >= eptr) {
char *nbuf;
size_t nbufsiz = *bufsiz * 2;
ssize_t d = ptr - *buf;
if ((nbuf = (char*)realloc(*buf, nbufsiz)) == NULL)
return -1;
*buf = nbuf;
*bufsiz = nbufsiz;
eptr = nbuf + nbufsiz;
ptr = nbuf + d;
}
}
}
ssize_t getline(char **buf, size_t *bufsiz, FILE *fp)
{
return getdelim(buf, bufsiz, '\n', fp);
}
#endif
static void HandleTraceLine( const char* line )
{
line += 24;
const auto cpu = (uint8_t)ReadNumber( line );
line++; // ']'
while( *line == ' ' ) line++;
#if defined TRACY_HW_TIMER && ( defined __i386 || defined _M_IX86 || defined __x86_64__ || defined _M_X64 )
const auto time = ReadNumber( line );
#elif __ARM_ARCH >= 6
const auto ts = ReadNumber( line );
line++; // '.'
const auto tus = ReadNumber( line );
const auto time = ts * 1000000000ll + tus * 1000ll;
#endif
line += 2; // ': '
if( memcmp( line, "sched_switch", 12 ) == 0 )
{
line += 14;
while( memcmp( line, "prev_pid", 8 ) != 0 ) line++;
line += 9;
const auto oldPid = ReadNumber( line );
line++;
while( memcmp( line, "prev_state", 10 ) != 0 ) line++;
line += 11;
const auto oldState = (uint8_t)ReadState( *line );
line += 5;
while( memcmp( line, "next_pid", 8 ) != 0 ) line++;
line += 9;
const auto newPid = ReadNumber( line );
uint8_t reason = 100;
Magic magic;
auto token = GetToken();
auto& tail = token->get_tail_index();
auto item = token->enqueue_begin( magic );
MemWrite( &item->hdr.type, QueueType::ContextSwitch );
MemWrite( &item->contextSwitch.time, time );
MemWrite( &item->contextSwitch.oldThread, oldPid );
MemWrite( &item->contextSwitch.newThread, newPid );
MemWrite( &item->contextSwitch.cpu, cpu );
MemWrite( &item->contextSwitch.reason, reason );
MemWrite( &item->contextSwitch.state, oldState );
tail.store( magic + 1, std::memory_order_release );
}
else if( memcmp( line, "sched_wakeup", 12 ) == 0 )
{
line += 14;
while( memcmp( line, "pid", 3 ) != 0 ) line++;
line += 4;
const auto pid = ReadNumber( line );
Magic magic;
auto token = GetToken();
auto& tail = token->get_tail_index();
auto item = token->enqueue_begin( magic );
MemWrite( &item->hdr.type, QueueType::ThreadWakeup );
MemWrite( &item->threadWakeup.time, time );
MemWrite( &item->threadWakeup.thread, pid );
tail.store( magic + 1, std::memory_order_release );
}
}
#ifdef __ANDROID__
static void ProcessTraceLines( int fd )
{
// Linux pipe buffer is 64KB, additional 1KB is for unfinished lines
char* buf = (char*)tracy_malloc( (64+1)*1024 );
char* line = buf;
for(;;)
{
const auto rd = read( fd, line, 64*1024 );
if( rd <= 0 ) break;
#ifdef TRACY_ON_DEMAND
if( !GetProfiler().IsConnected() )
{
if( rd < 64*1024 )
{
assert( line[rd-1] == '\n' );
line = buf;
std::this_thread::sleep_for( std::chrono::milliseconds( 10 ) );
}
else
{
const auto end = line + rd;
line = end - 1;
while( line > buf && *line != '\n' ) line--;
if( line > buf )
{
line++;
const auto lsz = end - line;
memmove( buf, line, lsz );
line = buf + lsz;
}
}
continue;
}
#endif
const auto end = line + rd;
line = buf;
for(;;)
{
auto next = line;
while( next < end && *next != '\n' ) next++;
next++;
if( next >= end )
{
const auto lsz = end - line;
memmove( buf, line, lsz );
line = buf + lsz;
break;
}
HandleTraceLine( line );
line = next;
}
if( rd < 64*1024 )
{
std::this_thread::sleep_for( std::chrono::milliseconds( 10 ) );
}
}
tracy_free( buf );
}
void SysTraceWorker( void* ptr )
{
SetThreadName( "Tracy SysTrace" );
int pipefd[2];
if( pipe( pipefd ) == 0 )
{
const auto pid = fork();
if( pid == 0 )
{
// child
close( pipefd[0] );
dup2( pipefd[1], STDERR_FILENO );
if( dup2( pipefd[1], STDOUT_FILENO ) >= 0 )
{
close( pipefd[1] );
execlp( "su", "su", "-c", "cat /sys/kernel/debug/tracing/trace_pipe", (char*)nullptr );
exit( 1 );
}
}
else if( pid > 0 )
{
// parent
close( pipefd[1] );
ProcessTraceLines( pipefd[0] );
close( pipefd[0] );
}
}
}
#else
static void ProcessTraceLines( int fd )
{
char* buf = (char*)tracy_malloc( 64*1024 );
struct pollfd pfd;
pfd.fd = fd;
pfd.events = POLLIN | POLLERR;
for(;;)
{
while( poll( &pfd, 1, 0 ) <= 0 ) std::this_thread::sleep_for( std::chrono::milliseconds( 10 ) );
const auto rd = read( fd, buf, 64*1024 );
if( rd <= 0 ) break;
#ifdef TRACY_ON_DEMAND
if( !GetProfiler().IsConnected() ) continue;
#endif
auto line = buf;
const auto end = buf + rd;
for(;;)
{
auto next = line;
while( next < end && *next != '\n' ) next++;
if( next == end ) break;
assert( *next == '\n' );
next++;
HandleTraceLine( line );
line = next;
}
}
tracy_free( buf );
}
void SysTraceWorker( void* ptr )
{
SetThreadName( "Tracy SysTrace" );
char tmp[256];
memcpy( tmp, BasePath, sizeof( BasePath ) - 1 );
memcpy( tmp + sizeof( BasePath ) - 1, TracePipe, sizeof( TracePipe ) );
int fd = open( tmp, O_RDONLY );
if( fd < 0 ) return;
ProcessTraceLines( fd );
close( fd );
}
#endif
void SysTraceSendExternalName( uint64_t thread )
{
FILE* f;
char fn[256];
sprintf( fn, "/proc/%" PRIu64 "/comm", thread );
f = fopen( fn, "rb" );
if( f )
{
char buf[256];
const auto sz = fread( buf, 1, 256, f );
if( sz > 0 && buf[sz-1] == '\n' ) buf[sz-1] = '\0';
GetProfiler().SendString( thread, buf, QueueType::ExternalThreadName );
fclose( f );
}
else
{
GetProfiler().SendString( thread, "???", QueueType::ExternalThreadName );
}
sprintf( fn, "/proc/%" PRIu64 "/status", thread );
f = fopen( fn, "rb" );
if( f )
{
int pid = -1;
size_t lsz = 1024;
auto line = (char*)malloc( lsz );
for(;;)
{
auto rd = getline( &line, &lsz, f );
if( rd <= 0 ) break;
if( memcmp( "Tgid:\t", line, 6 ) == 0 )
{
pid = atoi( line + 6 );
break;
}
}
free( line );
fclose( f );
if( pid >= 0 )
{
{
uint64_t _pid = pid;
Magic magic;
auto token = GetToken();
auto& tail = token->get_tail_index();
auto item = token->enqueue_begin( magic );
MemWrite( &item->hdr.type, QueueType::TidToPid );
MemWrite( &item->tidToPid.tid, thread );
MemWrite( &item->tidToPid.pid, _pid );
tail.store( magic + 1, std::memory_order_release );
}
sprintf( fn, "/proc/%i/comm", pid );
f = fopen( fn, "rb" );
if( f )
{
char buf[256];
const auto sz = fread( buf, 1, 256, f );
if( sz > 0 && buf[sz-1] == '\n' ) buf[sz-1] = '\0';
GetProfiler().SendString( thread, buf, QueueType::ExternalName );
fclose( f );
return;
}
}
}
GetProfiler().SendString( thread, "???", QueueType::ExternalName );
}
}
# endif
#endif

25
client/TracySysTrace.hpp Normal file
View File

@@ -0,0 +1,25 @@
#ifndef __TRACYSYSTRACE_HPP__
#define __TRACYSYSTRACE_HPP__
#if !defined TRACY_NO_SYSTEM_TRACING && ( defined _WIN32 || defined __CYGWIN__ || defined __linux__ )
# define TRACY_HAS_SYSTEM_TRACING
#endif
#ifdef TRACY_HAS_SYSTEM_TRACING
#include <stdint.h>
namespace tracy
{
bool SysTraceStart();
void SysTraceStop();
void SysTraceWorker( void* ptr );
void SysTraceSendExternalName( uint64_t thread );
}
#endif
#endif

View File

@@ -1,40 +1,16 @@
#ifndef __TRACYTHREAD_HPP__
#define __TRACYTHREAD_HPP__
#if defined _WIN32
#ifdef _MSC_VER
# include <windows.h>
#else
# include <pthread.h>
#endif
#ifdef TRACY_MANUAL_LIFETIME
# include "../common/TracyAlloc.hpp"
#endif
namespace tracy
{
#ifdef TRACY_MANUAL_LIFETIME
extern thread_local bool RpThreadInitDone;
#endif
class ThreadExitHandler
{
public:
~ThreadExitHandler()
{
#ifdef TRACY_MANUAL_LIFETIME
# if defined TRACY_HAS_CUSTOM_ALLOCATOR
PlatformAllocatorThreadFinalize();
# elif defined TRACY_USE_RPMALLOC
rpmalloc_thread_finalize( 1 );
# endif
RpThreadInitDone = false;
#endif
}
};
#if defined _WIN32
#ifdef _MSC_VER
class Thread
{

2099
client/tracy_rpmalloc.cpp Normal file

File diff suppressed because it is too large Load Diff

153
client/tracy_rpmalloc.hpp Normal file
View File

@@ -0,0 +1,153 @@
/* rpmalloc.h - Memory allocator - Public Domain - 2016 Mattias Jansson / Rampant Pixels
*
* This library provides a cross-platform lock free thread caching malloc implementation in C11.
* The latest source code is always available at
*
* https://github.com/rampantpixels/rpmalloc
*
* This library is put in the public domain; you can redistribute it and/or modify it without any restrictions.
*
*/
#pragma once
#include <stddef.h>
#include "../common/TracyApi.h"
namespace tracy
{
#if defined(__clang__) || defined(__GNUC__)
# define RPMALLOC_ATTRIBUTE __attribute__((__malloc__))
# define RPMALLOC_RESTRICT
# define RPMALLOC_CDECL
#elif defined(_MSC_VER)
# define RPMALLOC_ATTRIBUTE
# define RPMALLOC_RESTRICT __declspec(restrict)
# define RPMALLOC_CDECL __cdecl
#else
# define RPMALLOC_ATTRIBUTE
# define RPMALLOC_RESTRICT
# define RPMALLOC_CDECL
#endif
//! Flag to rpaligned_realloc to not preserve content in reallocation
#define RPMALLOC_NO_PRESERVE 1
typedef struct rpmalloc_global_statistics_t {
//! Current amount of virtual memory mapped (only if ENABLE_STATISTICS=1)
size_t mapped;
//! Current amount of memory in global caches for small and medium sizes (<64KiB)
size_t cached;
//! Total amount of memory mapped (only if ENABLE_STATISTICS=1)
size_t mapped_total;
//! Total amount of memory unmapped (only if ENABLE_STATISTICS=1)
size_t unmapped_total;
} rpmalloc_global_statistics_t;
typedef struct rpmalloc_thread_statistics_t {
//! Current number of bytes available for allocation from active spans
size_t active;
//! Current number of bytes available in thread size class caches
size_t sizecache;
//! Current number of bytes available in thread span caches
size_t spancache;
//! Current number of bytes in pending deferred deallocations
size_t deferred;
//! Total number of bytes transitioned from thread cache to global cache
size_t thread_to_global;
//! Total number of bytes transitioned from global cache to thread cache
size_t global_to_thread;
} rpmalloc_thread_statistics_t;
typedef struct rpmalloc_config_t {
//! Map memory pages for the given number of bytes. The returned address MUST be
// aligned to the rpmalloc span size, which will always be a power of two.
// Optionally the function can store an alignment offset in the offset variable
// in case it performs alignment and the returned pointer is offset from the
// actual start of the memory region due to this alignment. The alignment offset
// will be passed to the memory unmap function. The alignment offset MUST NOT be
// larger than 65535 (storable in an uint16_t), if it is you must use natural
// alignment to shift it into 16 bits.
void* (*memory_map)(size_t size, size_t* offset);
//! Unmap the memory pages starting at address and spanning the given number of bytes.
// If release is set to 1, the unmap is for an entire span range as returned by
// a previous call to memory_map and that the entire range should be released.
// If release is set to 0, the unmap is a partial decommit of a subset of the mapped
// memory range.
void (*memory_unmap)(void* address, size_t size, size_t offset, int release);
//! Size of memory pages. The page size MUST be a power of two in [512,16384] range
// (2^9 to 2^14) unless 0 - set to 0 to use system page size. All memory mapping
// requests to memory_map will be made with size set to a multiple of the page size.
size_t page_size;
//! Size of a span of memory pages. MUST be a multiple of page size, and in [4096,262144]
// range (unless 0 - set to 0 to use the default span size).
size_t span_size;
//! Number of spans to map at each request to map new virtual memory blocks. This can
// be used to minimize the system call overhead at the cost of virtual memory address
// space. The extra mapped pages will not be written until actually used, so physical
// committed memory should not be affected in the default implementation.
size_t span_map_count;
//! Debug callback if memory guards are enabled. Called if a memory overwrite is detected
void (*memory_overwrite)(void* address);
} rpmalloc_config_t;
extern int
rpmalloc_initialize(void);
extern int
rpmalloc_initialize_config(const rpmalloc_config_t* config);
extern const rpmalloc_config_t*
rpmalloc_config(void);
extern void
rpmalloc_finalize(void);
void
rpmalloc_thread_initialize(void);
extern void
rpmalloc_thread_finalize(void);
extern void
rpmalloc_thread_collect(void);
extern int
rpmalloc_is_thread_initialized(void);
extern void
rpmalloc_thread_statistics(rpmalloc_thread_statistics_t* stats);
extern void
rpmalloc_global_statistics(rpmalloc_global_statistics_t* stats);
TRACY_API RPMALLOC_RESTRICT void*
rpmalloc(size_t size) RPMALLOC_ATTRIBUTE;
TRACY_API void
rpfree(void* ptr);
extern RPMALLOC_RESTRICT void*
rpcalloc(size_t num, size_t size) RPMALLOC_ATTRIBUTE;
extern void*
rprealloc(void* ptr, size_t size);
extern void*
rpaligned_realloc(void* ptr, size_t alignment, size_t size, size_t oldsize, unsigned int flags);
extern RPMALLOC_RESTRICT void*
rpaligned_alloc(size_t alignment, size_t size) RPMALLOC_ATTRIBUTE;
extern RPMALLOC_RESTRICT void*
rpmemalign(size_t alignment, size_t size) RPMALLOC_ATTRIBUTE;
extern int
rpposix_memalign(void **memptr, size_t alignment, size_t size);
extern size_t
rpmalloc_usable_size(void* ptr);
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,300 +0,0 @@
#.rst:
# ECMFindModuleHelpers
# --------------------
#
# Helper macros for find modules: ecm_find_package_version_check(),
# ecm_find_package_parse_components() and
# ecm_find_package_handle_library_components().
#
# ::
#
# ecm_find_package_version_check(<name>)
#
# Prints warnings if the CMake version or the project's required CMake version
# is older than that required by extra-cmake-modules.
#
# ::
#
# ecm_find_package_parse_components(<name>
# RESULT_VAR <variable>
# KNOWN_COMPONENTS <component1> [<component2> [...]]
# [SKIP_DEPENDENCY_HANDLING])
#
# This macro will populate <variable> with a list of components found in
# <name>_FIND_COMPONENTS, after checking that all those components are in the
# list of KNOWN_COMPONENTS; if there are any unknown components, it will print
# an error or warning (depending on the value of <name>_FIND_REQUIRED) and call
# return().
#
# The order of components in <variable> is guaranteed to match the order they
# are listed in the KNOWN_COMPONENTS argument.
#
# If SKIP_DEPENDENCY_HANDLING is not set, for each component the variable
# <name>_<component>_component_deps will be checked for dependent components.
# If <component> is listed in <name>_FIND_COMPONENTS, then all its (transitive)
# dependencies will also be added to <variable>.
#
# ::
#
# ecm_find_package_handle_library_components(<name>
# COMPONENTS <component> [<component> [...]]
# [SKIP_DEPENDENCY_HANDLING])
# [SKIP_PKG_CONFIG])
#
# Creates an imported library target for each component. The operation of this
# macro depends on the presence of a number of CMake variables.
#
# The <name>_<component>_lib variable should contain the name of this library,
# and <name>_<component>_header variable should contain the name of a header
# file associated with it (whatever relative path is normally passed to
# '#include'). <name>_<component>_header_subdir variable can be used to specify
# which subdirectory of the include path the headers will be found in.
# ecm_find_package_components() will then search for the library
# and include directory (creating appropriate cache variables) and create an
# imported library target named <name>::<component>.
#
# Additional variables can be used to provide additional information:
#
# If SKIP_PKG_CONFIG, the <name>_<component>_pkg_config variable is set, and
# pkg-config is found, the pkg-config module given by
# <name>_<component>_pkg_config will be searched for and used to help locate the
# library and header file. It will also be used to set
# <name>_<component>_VERSION.
#
# Note that if version information is found via pkg-config,
# <name>_<component>_FIND_VERSION can be set to require a particular version
# for each component.
#
# If SKIP_DEPENDENCY_HANDLING is not set, the INTERFACE_LINK_LIBRARIES property
# of the imported target for <component> will be set to contain the imported
# targets for the components listed in <name>_<component>_component_deps.
# <component>_FOUND will also be set to false if any of the components in
# <name>_<component>_component_deps are not found. This requires the components
# in <name>_<component>_component_deps to be listed before <component> in the
# COMPONENTS argument.
#
# The following variables will be set:
#
# ``<name>_TARGETS``
# the imported targets
# ``<name>_LIBRARIES``
# the found libraries
# ``<name>_INCLUDE_DIRS``
# the combined required include directories for the components
# ``<name>_DEFINITIONS``
# the "other" CFLAGS provided by pkg-config, if any
# ``<name>_VERSION``
# the value of ``<name>_<component>_VERSION`` for the first component that
# has this variable set (note that components are searched for in the order
# they are passed to the macro), although if it is already set, it will not
# be altered
#
# Note that these variables are never cleared, so if
# ecm_find_package_handle_library_components() is called multiple times with
# different components (typically because of multiple find_package() calls) then
# ``<name>_TARGETS``, for example, will contain all the targets found in any
# call (although no duplicates).
#
# Since pre-1.0.0.
#=============================================================================
# Copyright 2014 Alex Merry <alex.merry@kde.org>
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# 3. The name of the author may not be used to endorse or promote products
# derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
macro(ecm_find_package_version_check module_name)
if(CMAKE_VERSION VERSION_LESS 2.8.12)
message(FATAL_ERROR "CMake 2.8.12 is required by Find${module_name}.cmake")
endif()
if(CMAKE_MINIMUM_REQUIRED_VERSION VERSION_LESS 2.8.12)
message(AUTHOR_WARNING "Your project should require at least CMake 2.8.12 to use Find${module_name}.cmake")
endif()
endmacro()
macro(ecm_find_package_parse_components module_name)
set(ecm_fppc_options SKIP_DEPENDENCY_HANDLING)
set(ecm_fppc_oneValueArgs RESULT_VAR)
set(ecm_fppc_multiValueArgs KNOWN_COMPONENTS DEFAULT_COMPONENTS)
cmake_parse_arguments(ECM_FPPC "${ecm_fppc_options}" "${ecm_fppc_oneValueArgs}" "${ecm_fppc_multiValueArgs}" ${ARGN})
if(ECM_FPPC_UNPARSED_ARGUMENTS)
message(FATAL_ERROR "Unexpected arguments to ecm_find_package_parse_components: ${ECM_FPPC_UNPARSED_ARGUMENTS}")
endif()
if(NOT ECM_FPPC_RESULT_VAR)
message(FATAL_ERROR "Missing RESULT_VAR argument to ecm_find_package_parse_components")
endif()
if(NOT ECM_FPPC_KNOWN_COMPONENTS)
message(FATAL_ERROR "Missing KNOWN_COMPONENTS argument to ecm_find_package_parse_components")
endif()
if(NOT ECM_FPPC_DEFAULT_COMPONENTS)
set(ECM_FPPC_DEFAULT_COMPONENTS ${ECM_FPPC_KNOWN_COMPONENTS})
endif()
if(${module_name}_FIND_COMPONENTS)
set(ecm_fppc_requestedComps ${${module_name}_FIND_COMPONENTS})
if(NOT ECM_FPPC_SKIP_DEPENDENCY_HANDLING)
# Make sure deps are included
foreach(ecm_fppc_comp ${ecm_fppc_requestedComps})
foreach(ecm_fppc_dep_comp ${${module_name}_${ecm_fppc_comp}_component_deps})
list(FIND ecm_fppc_requestedComps "${ecm_fppc_dep_comp}" ecm_fppc_index)
if("${ecm_fppc_index}" STREQUAL "-1")
if(NOT ${module_name}_FIND_QUIETLY)
message(STATUS "${module_name}: ${ecm_fppc_comp} requires ${${module_name}_${ecm_fppc_comp}_component_deps}")
endif()
list(APPEND ecm_fppc_requestedComps "${ecm_fppc_dep_comp}")
endif()
endforeach()
endforeach()
else()
message(STATUS "Skipping dependency handling for ${module_name}")
endif()
list(REMOVE_DUPLICATES ecm_fppc_requestedComps)
# This makes sure components are listed in the same order as
# KNOWN_COMPONENTS (potentially important for inter-dependencies)
set(${ECM_FPPC_RESULT_VAR})
foreach(ecm_fppc_comp ${ECM_FPPC_KNOWN_COMPONENTS})
list(FIND ecm_fppc_requestedComps "${ecm_fppc_comp}" ecm_fppc_index)
if(NOT "${ecm_fppc_index}" STREQUAL "-1")
list(APPEND ${ECM_FPPC_RESULT_VAR} "${ecm_fppc_comp}")
list(REMOVE_AT ecm_fppc_requestedComps ${ecm_fppc_index})
endif()
endforeach()
# if there are any left, they are unknown components
if(ecm_fppc_requestedComps)
set(ecm_fppc_msgType STATUS)
if(${module_name}_FIND_REQUIRED)
set(ecm_fppc_msgType FATAL_ERROR)
endif()
if(NOT ${module_name}_FIND_QUIETLY)
message(${ecm_fppc_msgType} "${module_name}: requested unknown components ${ecm_fppc_requestedComps}")
endif()
return()
endif()
else()
set(${ECM_FPPC_RESULT_VAR} ${ECM_FPPC_DEFAULT_COMPONENTS})
endif()
endmacro()
macro(ecm_find_package_handle_library_components module_name)
set(ecm_fpwc_options SKIP_PKG_CONFIG SKIP_DEPENDENCY_HANDLING)
set(ecm_fpwc_oneValueArgs)
set(ecm_fpwc_multiValueArgs COMPONENTS)
cmake_parse_arguments(ECM_FPWC "${ecm_fpwc_options}" "${ecm_fpwc_oneValueArgs}" "${ecm_fpwc_multiValueArgs}" ${ARGN})
if(ECM_FPWC_UNPARSED_ARGUMENTS)
message(FATAL_ERROR "Unexpected arguments to ecm_find_package_handle_components: ${ECM_FPWC_UNPARSED_ARGUMENTS}")
endif()
if(NOT ECM_FPWC_COMPONENTS)
message(FATAL_ERROR "Missing COMPONENTS argument to ecm_find_package_handle_components")
endif()
include(FindPackageHandleStandardArgs)
find_package(PkgConfig QUIET)
foreach(ecm_fpwc_comp ${ECM_FPWC_COMPONENTS})
set(ecm_fpwc_dep_vars)
set(ecm_fpwc_dep_targets)
if(NOT SKIP_DEPENDENCY_HANDLING)
foreach(ecm_fpwc_dep ${${module_name}_${ecm_fpwc_comp}_component_deps})
list(APPEND ecm_fpwc_dep_vars "${module_name}_${ecm_fpwc_dep}_FOUND")
list(APPEND ecm_fpwc_dep_targets "${module_name}::${ecm_fpwc_dep}")
endforeach()
endif()
if(NOT ECM_FPWC_SKIP_PKG_CONFIG AND ${module_name}_${ecm_fpwc_comp}_pkg_config)
pkg_check_modules(PKG_${module_name}_${ecm_fpwc_comp} QUIET
${${module_name}_${ecm_fpwc_comp}_pkg_config})
endif()
find_path(${module_name}_${ecm_fpwc_comp}_INCLUDE_DIR
NAMES ${${module_name}_${ecm_fpwc_comp}_header}
HINTS ${PKG_${module_name}_${ecm_fpwc_comp}_INCLUDE_DIRS}
PATH_SUFFIXES ${${module_name}_${ecm_fpwc_comp}_header_subdir}
)
find_library(${module_name}_${ecm_fpwc_comp}_LIBRARY
NAMES ${${module_name}_${ecm_fpwc_comp}_lib}
HINTS ${PKG_${module_name}_${ecm_fpwc_comp}_LIBRARY_DIRS}
)
set(${module_name}_${ecm_fpwc_comp}_VERSION "${PKG_${module_name}_${ecm_fpwc_comp}_VERSION}")
if(NOT ${module_name}_VERSION)
set(${module_name}_VERSION ${${module_name}_${ecm_fpwc_comp}_VERSION})
endif()
set(_name_mismatched_arg)
if(NOT CMAKE_VERSION VERSION_LESS 3.17)
set(_name_mismatched_arg NAME_MISMATCHED)
endif()
find_package_handle_standard_args(${module_name}_${ecm_fpwc_comp}
FOUND_VAR
${module_name}_${ecm_fpwc_comp}_FOUND
REQUIRED_VARS
${module_name}_${ecm_fpwc_comp}_LIBRARY
${module_name}_${ecm_fpwc_comp}_INCLUDE_DIR
${ecm_fpwc_dep_vars}
VERSION_VAR
${module_name}_${ecm_fpwc_comp}_VERSION
${_name_mismatched_arg}
)
mark_as_advanced(
${module_name}_${ecm_fpwc_comp}_LIBRARY
${module_name}_${ecm_fpwc_comp}_INCLUDE_DIR
)
if(${module_name}_${ecm_fpwc_comp}_FOUND)
list(APPEND ${module_name}_LIBRARIES
"${${module_name}_${ecm_fpwc_comp}_LIBRARY}")
list(APPEND ${module_name}_INCLUDE_DIRS
"${${module_name}_${ecm_fpwc_comp}_INCLUDE_DIR}")
set(${module_name}_DEFINITIONS
${${module_name}_DEFINITIONS}
${PKG_${module_name}_${ecm_fpwc_comp}_DEFINITIONS})
if(NOT TARGET ${module_name}::${ecm_fpwc_comp})
add_library(${module_name}::${ecm_fpwc_comp} UNKNOWN IMPORTED)
set_target_properties(${module_name}::${ecm_fpwc_comp} PROPERTIES
IMPORTED_LOCATION "${${module_name}_${ecm_fpwc_comp}_LIBRARY}"
INTERFACE_COMPILE_OPTIONS "${PKG_${module_name}_${ecm_fpwc_comp}_DEFINITIONS}"
INTERFACE_INCLUDE_DIRECTORIES "${${module_name}_${ecm_fpwc_comp}_INCLUDE_DIR}"
INTERFACE_LINK_LIBRARIES "${ecm_fpwc_dep_targets}"
)
endif()
list(APPEND ${module_name}_TARGETS
"${module_name}::${ecm_fpwc_comp}")
endif()
endforeach()
if(${module_name}_LIBRARIES)
list(REMOVE_DUPLICATES ${module_name}_LIBRARIES)
endif()
if(${module_name}_INCLUDE_DIRS)
list(REMOVE_DUPLICATES ${module_name}_INCLUDE_DIRS)
endif()
if(${module_name}_DEFINITIONS)
list(REMOVE_DUPLICATES ${module_name}_DEFINITIONS)
endif()
if(${module_name}_TARGETS)
list(REMOVE_DUPLICATES ${module_name}_TARGETS)
endif()
endmacro()

View File

@@ -1,170 +0,0 @@
#.rst:
# FindWaylandScanner
# ------------------
#
# Try to find wayland-scanner.
#
# If the wayland-scanner executable is not in your PATH, you can provide
# an alternative name or full path location with the ``WaylandScanner_EXECUTABLE``
# variable.
#
# This will define the following variables:
#
# ``WaylandScanner_FOUND``
# True if wayland-scanner is available.
#
# ``WaylandScanner_EXECUTABLE``
# The wayland-scanner executable.
#
# If ``WaylandScanner_FOUND`` is TRUE, it will also define the following imported
# target:
#
# ``Wayland::Scanner``
# The wayland-scanner executable.
#
# This module provides the following functions to generate C protocol
# implementations:
#
# - ``ecm_add_wayland_client_protocol``
# - ``ecm_add_wayland_server_protocol``
#
# ::
#
# ecm_add_wayland_client_protocol(<source_files_var>
# PROTOCOL <xmlfile>
# BASENAME <basename>)
#
# Generate Wayland client protocol files from ``<xmlfile>`` XML
# definition for the ``<basename>`` interface and append those files
# to ``<source_files_var>``.
#
# ::
#
# ecm_add_wayland_server_protocol(<source_files_var>
# PROTOCOL <xmlfile>
# BASENAME <basename>)
#
# Generate Wayland server protocol files from ``<xmlfile>`` XML
# definition for the ``<basename>`` interface and append those files
# to ``<source_files_var>``.
#
# Since 1.4.0.
#=============================================================================
# Copyright 2012-2014 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# 3. The name of the author may not be used to endorse or promote products
# derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#=============================================================================
include(${CMAKE_CURRENT_LIST_DIR}/ECMFindModuleHelpers.cmake)
ecm_find_package_version_check(WaylandScanner)
# Find wayland-scanner
find_program(WaylandScanner_EXECUTABLE NAMES wayland-scanner)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(WaylandScanner
FOUND_VAR
WaylandScanner_FOUND
REQUIRED_VARS
WaylandScanner_EXECUTABLE
)
mark_as_advanced(WaylandScanner_EXECUTABLE)
if(NOT TARGET Wayland::Scanner AND WaylandScanner_FOUND)
add_executable(Wayland::Scanner IMPORTED)
set_target_properties(Wayland::Scanner PROPERTIES
IMPORTED_LOCATION "${WaylandScanner_EXECUTABLE}"
)
endif()
include(FeatureSummary)
set_package_properties(WaylandScanner PROPERTIES
URL "https://wayland.freedesktop.org/"
DESCRIPTION "Executable that converts XML protocol files to C code"
)
function(ecm_add_wayland_client_protocol out_var)
# Parse arguments
set(oneValueArgs PROTOCOL BASENAME)
cmake_parse_arguments(ARGS "" "${oneValueArgs}" "" ${ARGN})
if(ARGS_UNPARSED_ARGUMENTS)
message(FATAL_ERROR "Unknown keywords given to ecm_add_wayland_client_protocol(): \"${ARGS_UNPARSED_ARGUMENTS}\"")
endif()
get_filename_component(_infile ${ARGS_PROTOCOL} ABSOLUTE)
set(_client_header "${CMAKE_CURRENT_BINARY_DIR}/wayland-${ARGS_BASENAME}-client-protocol.h")
set(_code "${CMAKE_CURRENT_BINARY_DIR}/wayland-${ARGS_BASENAME}-protocol.c")
set_source_files_properties(${_client_header} GENERATED)
set_source_files_properties(${_code} GENERATED)
set_property(SOURCE ${_client_header} PROPERTY SKIP_AUTOMOC ON)
add_custom_command(OUTPUT "${_client_header}"
COMMAND ${WaylandScanner_EXECUTABLE} client-header ${_infile} ${_client_header}
DEPENDS ${WaylandScanner_EXECUTABLE} ${_infile}
VERBATIM
)
add_custom_command(OUTPUT "${_code}"
COMMAND ${WaylandScanner_EXECUTABLE} private-code ${_infile} ${_code}
DEPENDS ${WaylandScanner_EXECUTABLE} ${_infile} ${_client_header}
VERBATIM
)
list(APPEND ${out_var} "${_client_header}" "${_code}")
set(${out_var} ${${out_var}} PARENT_SCOPE)
endfunction()
function(ecm_add_wayland_server_protocol out_var)
# Parse arguments
set(oneValueArgs PROTOCOL BASENAME)
cmake_parse_arguments(ARGS "" "${oneValueArgs}" "" ${ARGN})
if(ARGS_UNPARSED_ARGUMENTS)
message(FATAL_ERROR "Unknown keywords given to ecm_add_wayland_server_protocol(): \"${ARGS_UNPARSED_ARGUMENTS}\"")
endif()
ecm_add_wayland_client_protocol(${out_var}
PROTOCOL ${ARGS_PROTOCOL}
BASENAME ${ARGS_BASENAME})
get_filename_component(_infile ${ARGS_PROTOCOL} ABSOLUTE)
set(_server_header "${CMAKE_CURRENT_BINARY_DIR}/wayland-${ARGS_BASENAME}-server-protocol.h")
set_property(SOURCE ${_server_header} PROPERTY SKIP_AUTOMOC ON)
set_source_files_properties(${_server_header} GENERATED)
add_custom_command(OUTPUT "${_server_header}"
COMMAND ${WaylandScanner_EXECUTABLE} server-header ${_infile} ${_server_header}
DEPENDS ${WaylandScanner_EXECUTABLE} ${_infile}
VERBATIM
)
list(APPEND ${out_var} "${_server_header}")
set(${out_var} ${${out_var}} PARENT_SCOPE)
endfunction()

View File

@@ -1,37 +0,0 @@
function(add_git_ref target)
if(NOT DEFINED GIT_REV)
set(GIT_REV "HEAD")
endif()
get_property(_git_ref_created GLOBAL PROPERTY _GIT_REF_CREATED)
if(NOT _git_ref_created)
set_property(GLOBAL PROPERTY _GIT_REF_CREATED TRUE)
find_package(Git)
set_property(GLOBAL PROPERTY _GIT_FOUND "${Git_FOUND}")
if(Git_FOUND)
add_custom_target(git-ref
COMMAND ${CMAKE_COMMAND} -E echo "#pragma once" > GitRef.hpp.tmp
COMMAND ${GIT_EXECUTABLE} -C ${CMAKE_CURRENT_SOURCE_DIR} log -1 "--format=namespace tracy { static inline const char* GitRef = %x22%h%x22; }" ${GIT_REV} >> GitRef.hpp.tmp || echo "namespace tracy { static inline const char* GitRef = \"unknown\"; }" >> GitRef.hpp.tmp
COMMAND ${CMAKE_COMMAND} -E copy_if_different GitRef.hpp.tmp GitRef.hpp
BYPRODUCTS GitRef.hpp GitRef.hpp.tmp
VERBATIM
)
else()
message(WARNING "git not found, using 'unknown' as git ref.")
add_custom_command(
OUTPUT GitRef.hpp
COMMAND ${CMAKE_COMMAND} -E echo "#pragma once" > GitRef.hpp
COMMAND ${CMAKE_COMMAND} -E echo "namespace tracy { static inline const char* GitRef = \"unknown\"; }" >> GitRef.hpp
VERBATIM
)
endif()
endif()
target_include_directories(${target} PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
get_property(_git_found GLOBAL PROPERTY _GIT_FOUND)
if(_git_found)
add_dependencies(${target} git-ref)
else()
target_sources(${target} PUBLIC GitRef.hpp)
endif()
endfunction()

View File

@@ -1,80 +0,0 @@
include(${CMAKE_CURRENT_LIST_DIR}/options.cmake)
set_option(NO_ISA_EXTENSIONS "Disable ISA extensions (don't pass -march=native or -mcpu=native to the compiler)" OFF)
set_option(NO_LTO "Disable interprocedural optimization (LTO)" OFF)
set_option(NO_MOLD_LINKER "Disable mold linker (use default linker)" OFF)
set_option(NO_CCACHE "Disable ccache acceleration" OFF)
if (NOT NO_ISA_EXTENSIONS)
include(CheckCXXCompilerFlag)
if (CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64" OR CMAKE_SYSTEM_PROCESSOR MATCHES "arm64")
CHECK_CXX_COMPILER_FLAG("-mcpu=native" COMPILER_SUPPORTS_MCPU_NATIVE)
if(COMPILER_SUPPORTS_MCPU_NATIVE)
add_compile_options(-mcpu=native)
endif()
else()
CHECK_CXX_COMPILER_FLAG("-march=native" COMPILER_SUPPORTS_MARCH_NATIVE)
if(COMPILER_SUPPORTS_MARCH_NATIVE)
add_compile_options(-march=native)
endif()
endif()
if(WIN32)
add_compile_options(/arch:AVX2)
endif()
endif()
if(CMAKE_SYSTEM_NAME STREQUAL "Linux" AND NOT LEGACY)
set(USE_WAYLAND ON)
else()
set(USE_WAYLAND OFF)
endif()
if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
if(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "15")
message(FATAL_ERROR "Apple Clang 15 or newer is required.")
elseif(NOT CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "16")
# AppleClang 15 has issues with to_chars in <chrono> if target is too old
add_compile_options($<$<COMPILE_LANGUAGE:CXX>:-mmacosx-version-min=13.3>)
endif()
add_compile_options($<$<COMPILE_LANGUAGE:CXX>:-fexperimental-library>)
endif()
endif()
if(WIN32)
add_definitions(-DNOMINMAX -DWIN32_LEAN_AND_MEAN -D_DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR)
# /MP is MSVC-specific for multi-processor compilation
if(MSVC)
add_compile_options(/MP)
endif()
endif()
if(EMSCRIPTEN)
add_compile_options(-pthread -DIMGUI_IMPL_OPENGL_ES2)
endif()
if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug" AND NOT EMSCRIPTEN AND NOT NO_LTO)
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION ON)
endif()
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_SYSTEM_NAME STREQUAL "Linux" AND NOT NO_MOLD_LINKER)
find_program(MOLD_LINKER mold)
if(MOLD_LINKER)
set(CMAKE_LINKER_TYPE "MOLD")
endif()
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
add_compile_options(-fno-eliminate-unused-debug-types)
endif()
endif()
if(NOT NO_CCACHE)
find_program(CCACHE ccache)
if(CCACHE)
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache)
set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ccache)
endif()
endif()
file(GENERATE OUTPUT .gitignore CONTENT "*")
set(CMAKE_COLOR_DIAGNOSTICS ON)

View File

@@ -1,12 +0,0 @@
diff --git a/extra_symbols.txt b/extra_symbols.txt
index b95bb58..6b8f616 100644
--- a/extra_symbols.txt
+++ b/extra_symbols.txt
@@ -1,3 +1,7 @@
+glCompressedTexImage2D
+GL_LINEAR_MIPMAP_LINEAR
+GL_TEXTURE_WRAP_S
+GL_TEXTURE_WRAP_T
glReadPixels
glClearColor
glClear

View File

@@ -1,14 +0,0 @@
diff '--color=auto' -ruN 72d8f61727dc878102157113d1998f86b852d20e/imconfig.h new/imconfig.h
--- 72d8f61727dc878102157113d1998f86b852d20e/imconfig.h 2024-09-27 14:28:05.568760349 +0200
+++ new/imconfig.h 2024-09-27 14:29:47.310243707 +0200
@@ -113,6 +113,10 @@
// Read about ImGuiBackendFlags_RendererHasVtxOffset for details.
//#define ImDrawIdx unsigned int
+#ifdef __EMSCRIPTEN__
+#define ImDrawIdx unsigned int
+#endif
+
//---- Override ImDrawCallback signature (will need to modify renderer backends accordingly)
//struct ImDrawList;
//struct ImDrawCmd;

View File

@@ -1,56 +0,0 @@
diff --git i/backends/imgui_impl_opengl3_loader.h w/backends/imgui_impl_opengl3_loader.h
index 4ca0536..a1ff572 100644
--- i/backends/imgui_impl_opengl3_loader.h
+++ w/backends/imgui_impl_opengl3_loader.h
@@ -180,6 +180,7 @@ typedef khronos_uint8_t GLubyte;
#define GL_VERSION 0x1F02
#define GL_EXTENSIONS 0x1F03
#define GL_LINEAR 0x2601
+#define GL_LINEAR_MIPMAP_LINEAR 0x2703
#define GL_TEXTURE_MAG_FILTER 0x2800
#define GL_TEXTURE_MIN_FILTER 0x2801
#define GL_TEXTURE_WRAP_S 0x2802
@@ -244,8 +245,10 @@ GLAPI void APIENTRY glGenTextures (GLsizei n, GLuint *textures);
#define GL_TEXTURE0 0x84C0
#define GL_ACTIVE_TEXTURE 0x84E0
typedef void (APIENTRYP PFNGLACTIVETEXTUREPROC) (GLenum texture);
+typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE2DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data);
#ifdef GL_GLEXT_PROTOTYPES
GLAPI void APIENTRY glActiveTexture (GLenum texture);
+GLAPI void APIENTRY glCompressedTexImage2D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data);
#endif
#endif /* GL_VERSION_1_3 */
#ifndef GL_VERSION_1_4
@@ -481,7 +484,7 @@ GL3W_API GL3WglProc imgl3wGetProcAddress(const char *proc);
/* gl3w internal state */
union ImGL3WProcs {
- GL3WglProc ptr[63];
+ GL3WglProc ptr[64];
struct {
PFNGLACTIVETEXTUREPROC ActiveTexture;
PFNGLATTACHSHADERPROC AttachShader;
@@ -497,6 +500,7 @@ union ImGL3WProcs {
PFNGLCLEARPROC Clear;
PFNGLCLEARCOLORPROC ClearColor;
PFNGLCOMPILESHADERPROC CompileShader;
+ PFNGLCOMPRESSEDTEXIMAGE2DPROC CompressedTexImage2D;
PFNGLCREATEPROGRAMPROC CreateProgram;
PFNGLCREATESHADERPROC CreateShader;
PFNGLDELETEBUFFERSPROC DeleteBuffers;
@@ -563,6 +567,7 @@ GL3W_API extern union ImGL3WProcs imgl3wProcs;
#define glClear imgl3wProcs.gl.Clear
#define glClearColor imgl3wProcs.gl.ClearColor
#define glCompileShader imgl3wProcs.gl.CompileShader
+#define glCompressedTexImage2D imgl3wProcs.gl.CompressedTexImage2D
#define glCreateProgram imgl3wProcs.gl.CreateProgram
#define glCreateShader imgl3wProcs.gl.CreateShader
#define glDeleteBuffers imgl3wProcs.gl.DeleteBuffers
@@ -859,6 +864,7 @@ static const char *proc_names[] = {
"glClear",
"glClearColor",
"glCompileShader",
+ "glCompressedTexImage2D",
"glCreateProgram",
"glCreateShader",
"glDeleteBuffers",

View File

@@ -1,13 +0,0 @@
diff --git i/imconfig.h w/imconfig.h
index b40db3898..561ab7782 100644
--- i/imconfig.h
+++ w/imconfig.h
@@ -42,7 +42,7 @@
//#define IMGUI_ENABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] [Default with Visual Studio] Implement default IME handler (require imm32.lib/.a, auto-link for Visual Studio, -limm32 on command-line for MinGW)
//#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] [Default with non-Visual Studio compilers] Don't implement default IME handler (won't require imm32.lib/.a)
//#define IMGUI_DISABLE_WIN32_FUNCTIONS // [Win32] Won't use and link with any Win32 function (clipboard, IME).
-//#define IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS // [OSX] Implement default OSX clipboard handler (need to link with '-framework ApplicationServices', this is why this is not the default).
+#define IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS // [OSX] Implement default OSX clipboard handler (need to link with '-framework ApplicationServices', this is why this is not the default).
//#define IMGUI_DISABLE_TIME_FUNCTIONS // Don't setup default platform_io.Platform_SessionDate value using time(), localtime_r().
//#define IMGUI_DISABLE_DEFAULT_SHELL_FUNCTIONS // Don't implement default platform_io.Platform_OpenInShellFn() handler (Win32: ShellExecute(), require shell32.lib/.a, Mac/Linux: use system("")).
//#define IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS // Don't implement ImFormatString/ImFormatStringV so you can implement them yourself (e.g. if you don't want to link with vsnprintf)

View File

@@ -1,13 +0,0 @@
diff --git i/imconfig.h w/imconfig.h
index b40db3898..f7f864394 100644
--- i/imconfig.h
+++ w/imconfig.h
@@ -50,7 +50,7 @@
//#define IMGUI_DISABLE_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle at all (replace them with dummies)
//#define IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle so you can implement them yourself if you don't want to link with fopen/fclose/fread/fwrite. This will also disable the LogToTTY() function.
//#define IMGUI_DISABLE_DEFAULT_ALLOCATORS // Don't implement default allocators calling malloc()/free() to avoid linking with them. You will need to call ImGui::SetAllocatorFunctions().
-//#define IMGUI_DISABLE_DEFAULT_FONT // Disable default embedded fonts (ProggyClean + ProggyForever). Remove ~9 KB + ~14 KB from output binary. AddFontDefaultXXX() functions will assert.
+#define IMGUI_DISABLE_DEFAULT_FONT // Disable default embedded fonts (ProggyClean + ProggyForever). Remove ~9 KB + ~14 KB from output binary. AddFontDefaultXXX() functions will assert.
//#define IMGUI_DISABLE_DEFAULT_FONT_BITMAP // Disable default embedded bitmap font (ProggyClean). Remove ~9 KB from output binary. AddFontDefaultBitmap() will assert.
//#define IMGUI_DISABLE_DEFAULT_FONT_VECTOR // Disable default embedded vector font (ProggyForever), Remove ~14 KB from output binary. AddFontDefaultVector() will assert.
//#define IMGUI_DISABLE_SSE // Disable use of SSE intrinsics even if available

View File

@@ -1,13 +0,0 @@
diff --git a/backends/imgui_impl_opengl3.cpp b/backends/imgui_impl_opengl3.cpp
index a9e32b7ac..2cdbc4812 100644
--- a/backends/imgui_impl_opengl3.cpp
+++ b/backends/imgui_impl_opengl3.cpp
@@ -1069,7 +1069,7 @@ bool ImGui_ImplOpenGL3_Init(const char* glsl_version)
bd->HasPolygonMode = (!bd->GlProfileIsES2 && !bd->GlProfileIsES3);
#endif
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER
- bd->HasBindSampler = (bd->GlVersion >= 330 || bd->GlProfileIsES3);
+ //bd->HasBindSampler = (bd->GlVersion >= 330 || bd->GlProfileIsES3);
#endif
bd->HasClipOrigin = (bd->GlVersion >= 450);
#ifdef IMGUI_IMPL_OPENGL_HAS_EXTENSIONS

View File

@@ -1,14 +0,0 @@
diff --git a/imgui_tables.cpp b/imgui_tables.cpp
--- a/imgui_tables.cpp
+++ b/imgui_tables.cpp
@@ -4082,7 +4082,9 @@
}
if (load_flags & ImGuiTableFlags_Reorderable)
column->DisplayOrder = column_settings->DisplayOrder;
- else
+ else if (column_settings->Index != -1)
+ // An Index of -1 means this column had no "Column N" line in the .ini file (columns without saved
+ // data are not written). Keep the display order as initialized (identity for non-reorderable tables). (#9519)
column->DisplayOrder = column_settings->Index; // Because default depends on previous Index, we need to set that up and cannot rely on TableInitColumnDefaults()
if ((load_flags & ImGuiTableFlags_Hideable) && column_settings->IsEnabled != -1)
column->IsUserEnabled = column->IsUserEnabledNextFrame = (column_settings->IsEnabled == 1);

View File

@@ -1,203 +0,0 @@
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index d6a9edc..abef8d7 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -32,18 +32,18 @@ if(nfd_PLATFORM STREQUAL PLATFORM_LINUX)
if(NFD_WAYLAND)
pkg_check_modules(WAYLAND REQUIRED wayland-client)
message(STATUS "Using Wayland version: ${WAYLAND_VERSION}")
- set(NFD_WAYLAND_PROTOCOL_XDG_FOREIGN ${CMAKE_CURRENT_SOURCE_DIR}/../3ps/wayland-protocols/unstable/xdg-foreign/xdg-foreign-unstable-v1.xml)
+ set(NFD_WAYLAND_PROTOCOL_XDG_FOREIGN ${CMAKE_CURRENT_SOURCE_DIR}/../3ps/wayland-protocols/unstable/xdg-foreign/xdg-foreign-unstable-v2.xml)
add_custom_command(
- OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/xdg-foreign-unstable-v1.h
- COMMAND wayland-scanner client-header < ${NFD_WAYLAND_PROTOCOL_XDG_FOREIGN} > ${CMAKE_CURRENT_BINARY_DIR}/xdg-foreign-unstable-v1.h
+ OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/xdg-foreign-unstable-v2.h
+ COMMAND wayland-scanner client-header < ${NFD_WAYLAND_PROTOCOL_XDG_FOREIGN} > ${CMAKE_CURRENT_BINARY_DIR}/xdg-foreign-unstable-v2.h
MAIN_DEPENDENCY ${NFD_WAYLAND_PROTOCOL_XDG_FOREIGN}
)
add_custom_command(
- OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/xdg-foreign-unstable-v1.c
- COMMAND wayland-scanner private-code < ${NFD_WAYLAND_PROTOCOL_XDG_FOREIGN} > ${CMAKE_CURRENT_BINARY_DIR}/xdg-foreign-unstable-v1.c
+ OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/xdg-foreign-unstable-v2.c
+ COMMAND wayland-scanner private-code < ${NFD_WAYLAND_PROTOCOL_XDG_FOREIGN} > ${CMAKE_CURRENT_BINARY_DIR}/xdg-foreign-unstable-v2.c
MAIN_DEPENDENCY ${NFD_WAYLAND_PROTOCOL_XDG_FOREIGN}
)
- list(APPEND SOURCE_FILES ${CMAKE_CURRENT_BINARY_DIR}/xdg-foreign-unstable-v1.h ${CMAKE_CURRENT_BINARY_DIR}/xdg-foreign-unstable-v1.c)
+ list(APPEND SOURCE_FILES ${CMAKE_CURRENT_BINARY_DIR}/xdg-foreign-unstable-v2.h ${CMAKE_CURRENT_BINARY_DIR}/xdg-foreign-unstable-v2.c)
endif()
endif()
diff --git a/src/nfd_gtk.cpp b/src/nfd_gtk.cpp
index 76fdcd7..cec691d 100644
--- a/src/nfd_gtk.cpp
+++ b/src/nfd_gtk.cpp
@@ -433,17 +433,17 @@ gint RunDialogWithFocus(GtkDialog* dialog) {
#if defined(NFD_WAYLAND)
void DestroyXdgExported(void* context) {
- zxdg_exported_v1_destroy(static_cast<struct zxdg_exported_v1*>(context));
+ zxdg_exported_v2_destroy(static_cast<struct zxdg_exported_v2*>(context));
}
-void zxdg_exported_v1_handle(void* context, struct zxdg_exported_v1*, const char* handle) {
+void zxdg_exported_v2_handle(void* context, struct zxdg_exported_v2*, const char* handle) {
GdkWindow* childWindow = static_cast<GdkWindow*>(context);
// GDK doesn't modify the string, even though it takes char*, so we can cast away the constness
gdk_wayland_window_set_transient_for_exported(childWindow, const_cast<char*>(handle));
}
-constexpr struct zxdg_exported_v1_listener wayland_xdg_exported_v1_listener{
- &zxdg_exported_v1_handle};
+constexpr struct zxdg_exported_v2_listener wayland_xdg_exported_v2_listener{
+ &zxdg_exported_v2_handle};
#endif
// This is an RAII class that wraps the parenting of a GtkWidget (the file dialog).
@@ -645,17 +645,17 @@ struct NativeWindowParenter {
#if defined(NFD_WAYLAND)
void SetParentWayland(GdkWindow* childWindow) {
- if (wayland_display && wayland_xdg_exporter_v1) {
- struct zxdg_exported_v1* exported = zxdg_exporter_v1_export(
- wayland_xdg_exporter_v1, static_cast<struct wl_surface*>(parentWindowHandle));
+ if (wayland_display && wayland_xdg_exporter_v2) {
+ struct zxdg_exported_v2* exported = zxdg_exporter_v2_export_toplevel(
+ wayland_xdg_exporter_v2, static_cast<struct wl_surface*>(parentWindowHandle));
if (!exported) {
// if we fail to export the wl_surface, act as if the window has no parent
return;
}
- zxdg_exported_v1_add_listener(
- exported, &wayland_xdg_exported_v1_listener, static_cast<void*>(childWindow));
+ zxdg_exported_v2_add_listener(
+ exported, &wayland_xdg_exported_v2_listener, static_cast<void*>(childWindow));
wl_display_roundtrip(wayland_display);
- zxdg_exported_v1_set_user_data(exported, nullptr);
+ zxdg_exported_v2_set_user_data(exported, nullptr);
destroy.fn = &DestroyXdgExported;
destroy.context = static_cast<void*>(exported);
}
diff --git a/src/nfd_linux_shared.hpp b/src/nfd_linux_shared.hpp
index 1413bac..e826f1e 100644
--- a/src/nfd_linux_shared.hpp
+++ b/src/nfd_linux_shared.hpp
@@ -14,7 +14,7 @@
#ifdef NFD_WAYLAND
#include <wayland-client.h>
-#include "xdg-foreign-unstable-v1.h"
+#include "xdg-foreign-unstable-v2.h"
#endif
namespace {
@@ -81,9 +81,9 @@ nfdnchar_t* emit_case_insensitive_glob(const nfdnchar_t* begin,
#ifdef NFD_WAYLAND
struct wl_display* wayland_display;
struct wl_registry* wayland_registry;
-uint32_t wayland_xdg_exporter_v1_name;
-struct zxdg_exporter_v1* wayland_xdg_exporter_v1;
-constexpr const char* XDG_EXPORTER_V1 = "zxdg_exporter_v1";
+uint32_t wayland_xdg_exporter_v2_name;
+struct zxdg_exporter_v2* wayland_xdg_exporter_v2;
+constexpr const char* XDG_EXPORTER_V2 = "zxdg_exporter_v2";
#endif
void EmptyFn(void*) {}
@@ -103,19 +103,19 @@ void registry_handle_global(void* context,
uint32_t version) {
(void)context;
(void)version;
- if (strcmp(interface, XDG_EXPORTER_V1) == 0) {
- wayland_xdg_exporter_v1_name = name;
- wayland_xdg_exporter_v1 = static_cast<struct zxdg_exporter_v1*>(wl_registry_bind(
- registry, name, &zxdg_exporter_v1_interface, zxdg_exporter_v1_interface.version));
+ if (strcmp(interface, XDG_EXPORTER_V2) == 0) {
+ wayland_xdg_exporter_v2_name = name;
+ wayland_xdg_exporter_v2 = static_cast<struct zxdg_exporter_v2*>(wl_registry_bind(
+ registry, name, &zxdg_exporter_v2_interface, zxdg_exporter_v2_interface.version));
}
}
void registry_handle_global_remove(void* context, struct wl_registry* registry, uint32_t name) {
(void)context;
(void)registry;
- if (wayland_xdg_exporter_v1 && name == wayland_xdg_exporter_v1_name) {
- zxdg_exporter_v1_destroy(wayland_xdg_exporter_v1);
- wayland_xdg_exporter_v1 = nullptr;
+ if (wayland_xdg_exporter_v2 && name == wayland_xdg_exporter_v2_name) {
+ zxdg_exporter_v2_destroy(wayland_xdg_exporter_v2);
+ wayland_xdg_exporter_v2 = nullptr;
}
}
@@ -128,7 +128,7 @@ void NFD_Wayland_Init(void) {
void NFD_Wayland_Quit(void) {
if (wayland_display) {
- if (wayland_xdg_exporter_v1) zxdg_exporter_v1_destroy(wayland_xdg_exporter_v1);
+ if (wayland_xdg_exporter_v2) zxdg_exporter_v2_destroy(wayland_xdg_exporter_v2);
wl_registry_destroy(wayland_registry);
}
}
@@ -143,7 +143,7 @@ nfdresult_t NFD_SetWaylandDisplay(wl_display* display) {
wayland_display = display;
if (wayland_display) {
wayland_registry = wl_display_get_registry(wayland_display);
- wayland_xdg_exporter_v1 = nullptr;
+ wayland_xdg_exporter_v2 = nullptr;
// seems like registry can't be null
wl_registry_add_listener(wayland_registry, &wayland_registry_listener, nullptr);
wl_display_roundtrip(wayland_display);
diff --git a/src/nfd_portal.cpp b/src/nfd_portal.cpp
index df840e0..e66ca7f 100644
--- a/src/nfd_portal.cpp
+++ b/src/nfd_portal.cpp
@@ -148,10 +148,10 @@ constexpr const char* DBUS_REQUEST_IFACE = "org.freedesktop.portal.Request";
constexpr const char* WAYLAND_PREFIX = "wayland:";
void DestroyXdgExported(void* context) {
- zxdg_exported_v1_destroy(static_cast<struct zxdg_exported_v1*>(context));
+ zxdg_exported_v2_destroy(static_cast<struct zxdg_exported_v2*>(context));
}
-void zxdg_exported_v1_handle(void* context, struct zxdg_exported_v1*, const char* handle) {
+void zxdg_exported_v2_handle(void* context, struct zxdg_exported_v2*, const char* handle) {
DBusMessageIter& iter = *static_cast<DBusMessageIter*>(context);
const size_t handle_len = strlen(handle);
const size_t prefix_len = strlen(WAYLAND_PREFIX);
@@ -163,8 +163,8 @@ void zxdg_exported_v1_handle(void* context, struct zxdg_exported_v1*, const char
NFDi_Free(buf);
}
-constexpr struct zxdg_exported_v1_listener wayland_xdg_exported_v1_listener{
- &zxdg_exported_v1_handle};
+constexpr struct zxdg_exported_v2_listener wayland_xdg_exported_v2_listener{
+ &zxdg_exported_v2_handle};
#endif
void AppendOpenFileQueryParentWindow(DBusMessageIter& iter,
@@ -194,18 +194,18 @@ void AppendOpenFileQueryParentWindow(DBusMessageIter& iter,
#endif
#ifdef NFD_WAYLAND
case NFD_WINDOW_HANDLE_TYPE_WAYLAND: {
- if (wayland_display && wayland_xdg_exporter_v1) {
- struct zxdg_exported_v1* exported = zxdg_exporter_v1_export(
- wayland_xdg_exporter_v1, static_cast<struct wl_surface*>(parentWindow.handle));
+ if (wayland_display && wayland_xdg_exporter_v2) {
+ struct zxdg_exported_v2* exported = zxdg_exporter_v2_export_toplevel(
+ wayland_xdg_exporter_v2, static_cast<struct wl_surface*>(parentWindow.handle));
if (!exported) {
// if we fail to export the wl_surface, act as if the window has no parent
dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &STR_EMPTY);
return;
}
- zxdg_exported_v1_add_listener(
- exported, &wayland_xdg_exported_v1_listener, static_cast<void*>(&iter));
+ zxdg_exported_v2_add_listener(
+ exported, &wayland_xdg_exported_v2_listener, static_cast<void*>(&iter));
wl_display_roundtrip(wayland_display);
- zxdg_exported_v1_set_user_data(exported, nullptr);
+ zxdg_exported_v2_set_user_data(exported, nullptr);
destroy.fn = &DestroyXdgExported;
destroy.context = static_cast<void*>(exported);
return;

View File

@@ -1,48 +0,0 @@
# Reusable option macros for Tracy CMake projects
#
# Usage:
# set_option(OPTION_NAME "Help text" ON/OFF [TARGET]) - for boolean options
# set_option_value(VAR_NAME "Help text" "value" [TARGET]) - for value options (CACHE STRING)
# set_option_value_as_string(VAR_NAME "Help text" "value" [TARGET]) - for value options as C string literals
#
# [TARGET] is optional and specifies a target to which the option will
# be added as a compile definition (e.g., -DOPTION_NAME or -DVAR_NAME=value).
# Boolean option (ON/OFF).
macro(set_option option help value)
option(${option} ${help} ${value})
if(${option})
message(STATUS "${option}: ON")
if(${ARGC} GREATER 3)
target_compile_definitions(${ARGV3} PUBLIC ${option})
endif()
else()
message(STATUS "${option}: OFF")
endif()
endmacro()
# Value option (string/number).
macro(set_option_value var help default)
set(${var} ${default} CACHE STRING "${help}")
if(${var})
message(STATUS "${var}: ${${var}}")
if(${ARGC} GREATER 3)
target_compile_definitions(${ARGV3} PUBLIC ${var}=${${var}})
endif()
else()
message(STATUS "${var}: (not set)")
endif()
endmacro()
# Value option embedded as a C string literal (VAR="value").
macro(set_option_value_as_string var help default)
set(${var} ${default} CACHE STRING "${help}")
if(${var})
message(STATUS "${var}: ${${var}}")
if(${ARGC} GREATER 3)
target_compile_definitions(${ARGV3} PUBLIC "${var}=\"${${var}}\"")
endif()
else()
message(STATUS "${var}: (not set)")
endif()
endmacro()

View File

@@ -1,14 +0,0 @@
diff --git i/include/ppqsort/parameters.h w/include/ppqsort/parameters.h
index 115c3a1..3f4b669 100644
--- i/include/ppqsort/parameters.h
+++ w/include/ppqsort/parameters.h
@@ -3,7 +3,8 @@
#include <bit>
#include <execution>
-#ifndef NDEBUG
+//#ifndef NDEBUG
+#if 0
#include <bitset>
#include <iostream>
#include <syncstream>

View File

@@ -1,14 +0,0 @@
diff --git i/include/ppqsort/parallel/cpp/thread_pool.h w/include/ppqsort/parallel/cpp/thread_pool.h
--- i/include/ppqsort/parallel/cpp/thread_pool.h
+++ w/include/ppqsort/parallel/cpp/thread_pool.h
@@ -134,7 +134,9 @@ namespace ppqsort::impl::cpp {
alignas(parameters::cacheline_size) std::atomic<std::size_t> pending_tasks_{0};
alignas(parameters::cacheline_size) std::atomic<std::size_t> total_tasks_{0};
alignas(parameters::cacheline_size) std::atomic<bool> to_stop_{false};
- std::binary_semaphore threads_done_semaphore_{0}; // used to wait for all tasks to finish
+ // counting_semaphore: multiple workers may concurrently observe total_tasks_ == 0
+ // and call release(); a binary_semaphore would assert when the count exceeds 1.
+ std::counting_semaphore<> threads_done_semaphore_{0};
std::mutex mtx_priority_;
bool stopped = false;
};

View File

@@ -1,36 +0,0 @@
set(TRACY_COMMON_DIR ${CMAKE_CURRENT_LIST_DIR}/../public/common)
set(TRACY_COMMON_SOURCES
tracy_lz4.cpp
tracy_lz4hc.cpp
TracySocket.cpp
TracyStackFrames.cpp
TracySystem.cpp
)
list(TRANSFORM TRACY_COMMON_SOURCES PREPEND "${TRACY_COMMON_DIR}/")
set(TRACY_SERVER_DIR ${CMAKE_CURRENT_LIST_DIR}/../server)
set(TRACY_SERVER_SOURCES
TracyBroadcast.cpp
TracyMemory.cpp
TracyMmap.cpp
TracyPrint.cpp
TracySysUtil.cpp
TracyTaskDispatch.cpp
TracyTextureCompression.cpp
TracyThreadCompress.cpp
TracyWorker.cpp
)
list(TRANSFORM TRACY_SERVER_SOURCES PREPEND "${TRACY_SERVER_DIR}/")
add_library(TracyServer STATIC EXCLUDE_FROM_ALL ${TRACY_COMMON_SOURCES} ${TRACY_SERVER_SOURCES})
target_include_directories(TracyServer PUBLIC ${TRACY_COMMON_DIR} ${TRACY_SERVER_DIR})
target_link_libraries(TracyServer PUBLIC TracyCapstone libzstd PPQSort::PPQSort)
if(NO_STATISTICS)
target_compile_definitions(TracyServer PUBLIC TRACY_NO_STATISTICS)
endif()

View File

@@ -1,39 +0,0 @@
diff --git i/CMakeLists.txt w/CMakeLists.txt
index 8efec25..c1d101e 100644
--- i/CMakeLists.txt
+++ w/CMakeLists.txt
@@ -17,7 +17,7 @@
# @date Consult git log.
##############################################################################
-cmake_minimum_required (VERSION 2.8.12)
+cmake_minimum_required (VERSION 3.10)
set(LIB_NAME tidy)
set(LIBTIDY_DESCRIPTION "${LIB_NAME} - HTML syntax checker")
@@ -528,6 +528,7 @@ if (UNIX AND SUPPORT_CONSOLE_APP)
# Run the built EXE to generate xml output .
add_custom_command(
+ POST_BUILD
TARGET man
COMMAND ${CMAKE_CURRENT_BINARY_DIR}/${LIB_NAME} -xml-help > ${TIDYHELP}
COMMENT "Generate ${TIDYHELP}"
@@ -536,6 +537,7 @@ if (UNIX AND SUPPORT_CONSOLE_APP)
# Run the built EXE to generate more xml output.
add_custom_command(
+ POST_BUILD
TARGET man
COMMAND ${CMAKE_CURRENT_BINARY_DIR}/${LIB_NAME} -xml-config > ${TIDYCONFIG}
COMMENT "Generate ${TIDYCONFIG}"
@@ -544,8 +546,8 @@ if (UNIX AND SUPPORT_CONSOLE_APP)
# Run xsltproc to generate the install files.
add_custom_command(
+ POST_BUILD
TARGET man
- DEPENDS ${TIDYHELP}
COMMAND xsltproc ARGS ${TIDY1XSL} ${TIDYHELP} > ${CMAKE_CURRENT_BINARY_DIR}/${TIDY_MANFILE}
COMMENT "Generate ${TIDY_MANFILE}"
VERBATIM

View File

@@ -1,341 +0,0 @@
# Vendor Specific CMake
# The Tracy project keeps most vendor source locally
set (ROOT_DIR "${CMAKE_CURRENT_LIST_DIR}/../")
# Dependencies are taken from the system first and if not found, they are pulled with CPM and built from source
include(FindPkgConfig)
include(${CMAKE_CURRENT_LIST_DIR}/CPM.cmake)
if(APPLE AND BUNDLE)
set(DLOPT ON)
else()
set(DLOPT OFF)
endif()
option(DOWNLOAD_CAPSTONE "Force download capstone" ON)
if(VENDOR_GUI)
option(DOWNLOAD_GLFW "Force download glfw" ${DLOPT})
option(DOWNLOAD_FREETYPE "Force download freetype" ${DLOPT})
option(DOWNLOAD_LIBCURL "Force download libcURL" OFF)
option(DOWNLOAD_PUGIXML "Force download pugixml" ${DLOPT})
endif()
# capstone
pkg_check_modules(CAPSTONE capstone)
if(CAPSTONE_FOUND AND NOT DOWNLOAD_CAPSTONE)
message(STATUS "Capstone found: ${CAPSTONE}")
add_library(TracyCapstone INTERFACE)
target_include_directories(TracyCapstone INTERFACE ${CAPSTONE_INCLUDE_DIRS})
target_link_libraries(TracyCapstone INTERFACE ${CAPSTONE_LINK_LIBRARIES})
else()
CPMAddPackage(
NAME capstone
GITHUB_REPOSITORY capstone-engine/capstone
GIT_TAG 6.0.0-Alpha10
OPTIONS
"CAPSTONE_X86_ATT_DISABLE ON"
"CAPSTONE_ALPHA_SUPPORT OFF"
"CAPSTONE_ARC_SUPPORT OFF"
"CAPSTONE_HPPA_SUPPORT OFF"
"CAPSTONE_LOONGARCH_SUPPORT OFF"
"CAPSTONE_M680X_SUPPORT OFF"
"CAPSTONE_M68K_SUPPORT OFF"
"CAPSTONE_MIPS_SUPPORT OFF"
"CAPSTONE_MOS65XX_SUPPORT OFF"
"CAPSTONE_PPC_SUPPORT OFF"
"CAPSTONE_SPARC_SUPPORT OFF"
"CAPSTONE_SYSTEMZ_SUPPORT OFF"
"CAPSTONE_XCORE_SUPPORT OFF"
"CAPSTONE_TRICORE_SUPPORT OFF"
"CAPSTONE_TMS320C64X_SUPPORT OFF"
"CAPSTONE_M680X_SUPPORT OFF"
"CAPSTONE_EVM_SUPPORT OFF"
"CAPSTONE_WASM_SUPPORT OFF"
"CAPSTONE_BPF_SUPPORT OFF"
"CAPSTONE_RISCV_SUPPORT OFF"
"CAPSTONE_SH_SUPPORT OFF"
"CAPSTONE_XTENSA_SUPPORT OFF"
"CAPSTONE_BUILD_MACOS_THIN ON"
EXCLUDE_FROM_ALL TRUE
)
add_library(TracyCapstone INTERFACE)
target_include_directories(TracyCapstone INTERFACE ${capstone_SOURCE_DIR}/include/capstone)
target_link_libraries(TracyCapstone INTERFACE capstone_static)
endif()
# Zstd
CPMAddPackage(
NAME zstd
GITHUB_REPOSITORY facebook/zstd
GIT_TAG v1.5.7
OPTIONS
"ZSTD_BUILD_SHARED OFF"
EXCLUDE_FROM_ALL TRUE
SOURCE_SUBDIR build/cmake
)
# Diff Template Library
set(DTL_DIR "${ROOT_DIR}/dtl")
file(GLOB_RECURSE DTL_HEADERS CONFIGURE_DEPENDS RELATIVE ${DTL_DIR} "*.hpp")
add_library(TracyDtl INTERFACE)
target_sources(TracyDtl INTERFACE ${DTL_HEADERS})
target_include_directories(TracyDtl INTERFACE ${DTL_DIR})
# Get Opt
set(GETOPT_DIR "${ROOT_DIR}/getopt")
set(GETOPT_SOURCES ${GETOPT_DIR}/getopt.c)
set(GETOPT_HEADERS ${GETOPT_DIR}/getopt.h)
add_library(TracyGetOpt STATIC EXCLUDE_FROM_ALL ${GETOPT_SOURCES} ${GETOPT_HEADERS})
target_include_directories(TracyGetOpt PUBLIC ${GETOPT_DIR})
# PPQSort
CPMAddPackage(
NAME PPQSort
GITHUB_REPOSITORY GabTux/PPQSort
VERSION 1.0.6
PATCHES
"${CMAKE_CURRENT_LIST_DIR}/ppqsort-nodebug.patch"
"${CMAKE_CURRENT_LIST_DIR}/ppqsort-semaphore.patch"
EXCLUDE_FROM_ALL TRUE
)
# json
CPMAddPackage(
NAME json
GITHUB_REPOSITORY nlohmann/json
GIT_TAG v3.12.0
EXCLUDE_FROM_ALL TRUE
)
if(VENDOR_GUI)
# GLFW
if(NOT USE_WAYLAND AND NOT EMSCRIPTEN)
pkg_check_modules(GLFW glfw3)
if (GLFW_FOUND AND NOT DOWNLOAD_GLFW)
add_library(TracyGlfw3 INTERFACE)
target_include_directories(TracyGlfw3 INTERFACE ${GLFW_INCLUDE_DIRS})
target_link_libraries(TracyGlfw3 INTERFACE ${GLFW_LINK_LIBRARIES})
else()
CPMAddPackage(
NAME glfw
GITHUB_REPOSITORY glfw/glfw
GIT_TAG 3.4
OPTIONS
"GLFW_BUILD_EXAMPLES OFF"
"GLFW_BUILD_TESTS OFF"
"GLFW_BUILD_DOCS OFF"
"GLFW_INSTALL OFF"
EXCLUDE_FROM_ALL TRUE
)
add_library(TracyGlfw3 INTERFACE)
target_link_libraries(TracyGlfw3 INTERFACE glfw)
endif()
endif()
# freetype
pkg_check_modules(FREETYPE freetype2)
if (FREETYPE_FOUND AND NOT DOWNLOAD_FREETYPE)
add_library(TracyFreetype INTERFACE)
target_include_directories(TracyFreetype INTERFACE ${FREETYPE_INCLUDE_DIRS})
target_link_libraries(TracyFreetype INTERFACE ${FREETYPE_LINK_LIBRARIES})
else()
CPMAddPackage(
NAME freetype
GITHUB_REPOSITORY freetype/freetype
GIT_TAG VER-2-14-3
OPTIONS
"FT_DISABLE_HARFBUZZ ON"
"FT_WITH_HARFBUZZ OFF"
"FT_DISABLE_ZLIB ON"
"FT_DISABLE_BZIP2 ON"
"FT_DISABLE_PNG ON"
"FT_DISABLE_BROTLI ON"
EXCLUDE_FROM_ALL TRUE
)
add_library(TracyFreetype INTERFACE)
target_link_libraries(TracyFreetype INTERFACE freetype)
endif()
# ImGui
CPMAddPackage(
NAME ImGui
GITHUB_REPOSITORY ocornut/imgui
GIT_TAG v1.92.9b-docking
DOWNLOAD_ONLY TRUE
PATCHES
"${CMAKE_CURRENT_LIST_DIR}/imgui-emscripten.patch"
"${CMAKE_CURRENT_LIST_DIR}/imgui-loader.patch"
"${CMAKE_CURRENT_LIST_DIR}/imgui-no-samplers.patch"
"${CMAKE_CURRENT_LIST_DIR}/imgui-no-default-font.patch"
"${CMAKE_CURRENT_LIST_DIR}/imgui-macos-clipboard.patch"
"${CMAKE_CURRENT_LIST_DIR}/imgui-phantom-column.patch"
)
set(IMGUI_SOURCES
imgui_widgets.cpp
imgui_draw.cpp
imgui_demo.cpp
imgui.cpp
imgui_tables.cpp
misc/freetype/imgui_freetype.cpp
backends/imgui_impl_opengl3.cpp
)
list(TRANSFORM IMGUI_SOURCES PREPEND "${ImGui_SOURCE_DIR}/")
add_library(TracyImGui STATIC EXCLUDE_FROM_ALL ${IMGUI_SOURCES})
target_include_directories(TracyImGui PUBLIC ${ImGui_SOURCE_DIR})
target_link_libraries(TracyImGui PUBLIC
TracyFreetype
${CMAKE_DL_LIBS}
)
target_compile_definitions(TracyImGui PRIVATE "IMGUI_ENABLE_FREETYPE")
target_compile_definitions(TracyImGui PUBLIC "IMGUI_USE_WCHAR32")
#target_compile_definitions(TracyImGui PUBLIC "IMGUI_DISABLE_OBSOLETE_FUNCTIONS")
if (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND LEGACY)
find_package(X11 REQUIRED)
target_link_libraries(TracyImGui PUBLIC ${X11_LIBRARIES})
endif()
if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
target_compile_definitions(TracyImGui PRIVATE "IMGUI_DISABLE_DEBUG_TOOLS" "IMGUI_DISABLE_DEMO_WINDOWS")
endif()
if(APPLE)
target_link_libraries(TracyImGui PUBLIC "-framework ApplicationServices")
endif()
# NFD
if(NOT NO_FILESELECTOR AND NOT EMSCRIPTEN)
if(GTK_FILESELECTOR)
set(NFD_PORTAL OFF)
else()
set(NFD_PORTAL ON)
endif()
CPMAddPackage(
NAME nfd
GITHUB_REPOSITORY btzy/nativefiledialog-extended
GIT_TAG 3cd252a8f7ca32419b1ca235c2990ba6a0ecba7c
EXCLUDE_FROM_ALL TRUE
PATCHES
"${CMAKE_CURRENT_LIST_DIR}/nfd-xdg-foreign-v2.patch"
OPTIONS
"BUILD_SHARED_LIBS OFF"
"NFD_PORTAL ${NFD_PORTAL}"
)
endif()
# md4c
CPMAddPackage(
NAME md4c
GITHUB_REPOSITORY mity/md4c
GIT_TAG 65c6c9d72cebd9a731aaa5597414ce04d9ea5de3
OPTIONS
"BUILD_SHARED_LIBS OFF"
EXCLUDE_FROM_ALL TRUE
)
if(NOT EMSCRIPTEN)
# base64
set(BUILD_SHARED_LIBS_SAVE ${BUILD_SHARED_LIBS})
set(BUILD_SHARED_LIBS OFF)
CPMAddPackage(
NAME base64
GITHUB_REPOSITORY aklomp/base64
GIT_TAG v0.5.2
OPTIONS
"BASE64_BUILD_CLI OFF"
"BASE64_WITH_OpenMP OFF"
EXCLUDE_FROM_ALL TRUE
)
set(BUILD_SHARED_LIBS ${BUILD_SHARED_LIBS_SAVE})
# tidy
CPMAddPackage(
NAME tidy
GITHUB_REPOSITORY htacg/tidy-html5
GIT_TAG 5.8.0
PATCHES
"${CMAKE_CURRENT_LIST_DIR}/tidy-cmake.patch"
EXCLUDE_FROM_ALL TRUE
)
# usearch
CPMAddPackage(
NAME usearch
GITHUB_REPOSITORY unum-cloud/usearch
GIT_TAG v2.26.0
EXCLUDE_FROM_ALL TRUE
)
# pugixml
pkg_check_modules(PUGIXML pugixml)
if (PUGIXML_FOUND AND NOT DOWNLOAD_PUGIXML)
add_library(TracyPugixml INTERFACE)
target_include_directories(TracyPugixml INTERFACE ${PUGIXML_INCLUDE_DIRS})
target_link_libraries(TracyPugixml INTERFACE ${PUGIXML_LINK_LIBRARIES})
else()
CPMAddPackage(
NAME pugixml
GITHUB_REPOSITORY zeux/pugixml
GIT_TAG v1.16
EXCLUDE_FROM_ALL TRUE
)
add_library(TracyPugixml INTERFACE)
target_link_libraries(TracyPugixml INTERFACE pugixml)
endif()
# libcurl
pkg_check_modules(LIBCURL libcurl>=7.87.0)
if (LIBCURL_FOUND AND NOT DOWNLOAD_LIBCURL)
add_library(TracyLibcurl INTERFACE)
target_include_directories(TracyLibcurl INTERFACE ${LIBCURL_INCLUDE_DIRS})
target_link_libraries(TracyLibcurl INTERFACE ${LIBCURL_LINK_LIBRARIES})
else()
CPMAddPackage(
NAME libcurl
GITHUB_REPOSITORY curl/curl
GIT_TAG curl-8_21_0
OPTIONS
"BUILD_STATIC_LIBS ON"
"BUILD_SHARED_LIBS OFF"
"HTTP_ONLY ON"
"CURL_ZSTD OFF"
"CURL_USE_LIBPSL OFF"
"CURL_USE_LIBSSH2 OFF"
"CURL_BROTLI OFF"
"USE_NGHTTP2 OFF"
"USE_LIBIDN2 OFF"
EXCLUDE_FROM_ALL TRUE
)
add_library(TracyLibcurl INTERFACE)
target_link_libraries(TracyLibcurl INTERFACE libcurl_static)
target_include_directories(TracyLibcurl INTERFACE ${libcurl_SOURCE_DIR}/include)
endif()
endif()
endif()

View File

@@ -1,24 +0,0 @@
cmake_minimum_required(VERSION 3.10)
message("Parsing public/common/TracyVersion.hpp file")
file(READ "${CMAKE_CURRENT_LIST_DIR}/../public/common/TracyVersion.hpp" version)
# Note: This looks for a specific pattern in TracyVersion.hpp, if it changes
# this needs updating.
string(REGEX MATCH "Major = ([0-9]+)" _ ${version})
# This works do to the above () subexpression selection. See
# https://cmake.org/cmake/help/latest/command/string.html#regex-match for more
# details
set(TRACY_VERSION_MAJOR ${CMAKE_MATCH_1})
string(REGEX MATCH "Minor = ([0-9]+)" _ ${version})
set(TRACY_VERSION_MINOR ${CMAKE_MATCH_1})
string(REGEX MATCH "Patch = ([0-9]+)" _ ${version})
set(TRACY_VERSION_PATCH ${CMAKE_MATCH_1})
set(TRACY_VERSION_STRING "${TRACY_VERSION_MAJOR}.${TRACY_VERSION_MINOR}.${TRACY_VERSION_PATCH}")
message("VERSION ${TRACY_VERSION_STRING}")

27
common/TracyAlign.hpp Normal file
View File

@@ -0,0 +1,27 @@
#ifndef __TRACYALIGN_HPP__
#define __TRACYALIGN_HPP__
#include <string.h>
#include "TracyForceInline.hpp"
namespace tracy
{
template<typename T>
tracy_force_inline T MemRead( const void* ptr )
{
T val;
memcpy( &val, ptr, sizeof( T ) );
return val;
}
template<typename T>
tracy_force_inline void MemWrite( void* ptr, T val )
{
memcpy( ptr, &val, sizeof( T ) );
}
}
#endif

33
common/TracyAlloc.hpp Normal file
View File

@@ -0,0 +1,33 @@
#ifndef __TRACYALLOC_HPP__
#define __TRACYALLOC_HPP__
#include <cstdlib>
#ifdef TRACY_ENABLE
# include "../client/tracy_rpmalloc.hpp"
#endif
namespace tracy
{
static inline void* tracy_malloc( size_t size )
{
#ifdef TRACY_ENABLE
return rpmalloc( size );
#else
return malloc( size );
#endif
}
static inline void tracy_free( void* ptr )
{
#ifdef TRACY_ENABLE
rpfree( ptr );
#else
free( ptr );
#endif
}
}
#endif

14
common/TracyApi.h Normal file
View File

@@ -0,0 +1,14 @@
#ifndef __TRACYAPI_H__
#define __TRACYAPI_H__
#ifdef _WIN32
# if defined TRACY_IMPORTS
# define TRACY_API __declspec(dllimport)
# else
# define TRACY_API __declspec(dllexport)
# endif
#else
# define TRACY_API __attribute__((visibility("default")))
#endif
#endif // __TRACYAPI_H__

View File

@@ -10,6 +10,15 @@ namespace tracy
using TracyMutex = std::shared_mutex;
}
#elif defined __CYGWIN__
#include "tracy_benaphore.h"
namespace tracy
{
using TracyMutex = NonRecursiveBenaphore;
}
#else
#include <mutex>

102
common/TracyProtocol.hpp Normal file
View File

@@ -0,0 +1,102 @@
#ifndef __TRACYPROTOCOL_HPP__
#define __TRACYPROTOCOL_HPP__
#include <limits>
#include <stdint.h>
#include "../common/tracy_lz4.hpp"
namespace tracy
{
enum : uint32_t { ProtocolVersion = 17 };
enum : uint32_t { BroadcastVersion = 0 };
using lz4sz_t = uint32_t;
enum { TargetFrameSize = 256 * 1024 };
enum { LZ4Size = LZ4_COMPRESSBOUND( TargetFrameSize ) };
static_assert( LZ4Size <= std::numeric_limits<lz4sz_t>::max(), "LZ4Size greater than lz4sz_t" );
static_assert( TargetFrameSize * 2 >= 64 * 1024, "Not enough space for LZ4 stream buffer" );
enum { HandshakeShibbolethSize = 8 };
static const char HandshakeShibboleth[HandshakeShibbolethSize] = { 'T', 'r', 'a', 'c', 'y', 'P', 'r', 'f' };
enum HandshakeStatus : uint8_t
{
HandshakePending,
HandshakeWelcome,
HandshakeProtocolMismatch,
HandshakeNotAvailable,
HandshakeDropped
};
enum { WelcomeMessageProgramNameSize = 64 };
enum { WelcomeMessageHostInfoSize = 1024 };
#pragma pack( 1 )
enum ServerQuery : uint8_t
{
ServerQueryTerminate,
ServerQueryString,
ServerQueryThreadString,
ServerQuerySourceLocation,
ServerQueryPlotName,
ServerQueryCallstackFrame,
ServerQueryFrameName,
ServerQueryDisconnect,
ServerQueryExternalName
};
struct ServerQueryPacket
{
ServerQuery type;
uint64_t ptr;
};
enum { ServerQueryPacketSize = sizeof( ServerQueryPacket ) };
struct WelcomeMessage
{
double timerMul;
int64_t initBegin;
int64_t initEnd;
uint64_t delay;
uint64_t resolution;
uint64_t epoch;
uint64_t pid;
uint8_t onDemand;
uint8_t isApple;
char programName[WelcomeMessageProgramNameSize];
char hostInfo[WelcomeMessageHostInfoSize];
};
enum { WelcomeMessageSize = sizeof( WelcomeMessage ) };
struct OnDemandPayloadMessage
{
uint64_t frames;
uint64_t currentTime;
};
enum { OnDemandPayloadMessageSize = sizeof( OnDemandPayloadMessage ) };
struct BroadcastMessage
{
uint32_t broadcastVersion;
uint32_t protocolVersion;
uint32_t activeTime; // in seconds
char programName[WelcomeMessageProgramNameSize];
};
enum { BroadcastMessageSize = sizeof( BroadcastMessage ) };
#pragma pack()
}
#endif

458
common/TracyQueue.hpp Normal file
View File

@@ -0,0 +1,458 @@
#ifndef __TRACYQUEUE_HPP__
#define __TRACYQUEUE_HPP__
#include <stdint.h>
namespace tracy
{
enum class QueueType : uint8_t
{
ZoneText,
ZoneName,
Message,
MessageColor,
MessageAppInfo,
ZoneBeginAllocSrcLoc,
ZoneBeginAllocSrcLocCallstack,
CallstackMemory,
Callstack,
CallstackAlloc,
FrameImage,
Terminate,
KeepAlive,
ThreadContext,
Crash,
CrashReport,
ZoneBegin,
ZoneBeginCallstack,
ZoneEnd,
ZoneValidation,
FrameMarkMsg,
FrameMarkMsgStart,
FrameMarkMsgEnd,
SourceLocation,
LockAnnounce,
LockTerminate,
LockWait,
LockObtain,
LockRelease,
LockSharedWait,
LockSharedObtain,
LockSharedRelease,
LockMark,
PlotData,
MessageLiteral,
MessageLiteralColor,
GpuNewContext,
GpuZoneBegin,
GpuZoneBeginCallstack,
GpuZoneEnd,
GpuTime,
MemAlloc,
MemFree,
MemAllocCallstack,
MemFreeCallstack,
CallstackFrameSize,
CallstackFrame,
SysTimeReport,
ContextSwitch,
ThreadWakeup,
TidToPid,
StringData,
ThreadName,
CustomStringData,
PlotName,
SourceLocationPayload,
CallstackPayload,
CallstackAllocPayload,
FrameName,
FrameImageData,
ExternalName,
ExternalThreadName,
NUM_TYPES
};
#pragma pack( 1 )
struct QueueThreadContext
{
uint64_t thread;
};
struct QueueZoneBegin
{
int64_t time;
uint64_t srcloc; // ptr
};
struct QueueZoneEnd
{
int64_t time;
};
struct QueueZoneValidation
{
uint32_t id;
};
struct QueueStringTransfer
{
uint64_t ptr;
};
struct QueueFrameMark
{
int64_t time;
uint64_t name; // ptr
};
struct QueueFrameImage
{
uint64_t image; // ptr
uint64_t frame;
uint16_t w;
uint16_t h;
uint8_t flip;
};
struct QueueSourceLocation
{
uint64_t name;
uint64_t function; // ptr
uint64_t file; // ptr
uint32_t line;
uint8_t r;
uint8_t g;
uint8_t b;
};
struct QueueZoneText
{
uint64_t text; // ptr
};
enum class LockType : uint8_t
{
Lockable,
SharedLockable
};
struct QueueLockAnnounce
{
uint32_t id;
int64_t time;
uint64_t lckloc; // ptr
LockType type;
};
struct QueueLockTerminate
{
uint32_t id;
int64_t time;
LockType type;
};
struct QueueLockWait
{
uint64_t thread;
uint32_t id;
int64_t time;
LockType type;
};
struct QueueLockObtain
{
uint64_t thread;
uint32_t id;
int64_t time;
};
struct QueueLockRelease
{
uint64_t thread;
uint32_t id;
int64_t time;
};
struct QueueLockMark
{
uint64_t thread;
uint32_t id;
uint64_t srcloc; // ptr
};
enum class PlotDataType : uint8_t
{
Float,
Double,
Int
};
struct QueuePlotData
{
uint64_t name; // ptr
int64_t time;
PlotDataType type;
union
{
double d;
float f;
int64_t i;
} data;
};
struct QueueMessage
{
int64_t time;
uint64_t text; // ptr
};
struct QueueMessageColor : public QueueMessage
{
uint8_t r;
uint8_t g;
uint8_t b;
};
struct QueueGpuNewContext
{
int64_t cpuTime;
int64_t gpuTime;
uint64_t thread;
float period;
uint8_t context;
uint8_t accuracyBits;
};
struct QueueGpuZoneBegin
{
int64_t cpuTime;
uint64_t srcloc;
uint64_t thread;
uint16_t queryId;
uint8_t context;
};
struct QueueGpuZoneEnd
{
int64_t cpuTime;
uint16_t queryId;
uint8_t context;
};
struct QueueGpuTime
{
int64_t gpuTime;
uint16_t queryId;
uint8_t context;
};
struct QueueMemAlloc
{
int64_t time;
uint64_t thread;
uint64_t ptr;
char size[6];
};
struct QueueMemFree
{
int64_t time;
uint64_t thread;
uint64_t ptr;
};
struct QueueCallstackMemory
{
uint64_t ptr;
};
struct QueueCallstack
{
uint64_t ptr;
};
struct QueueCallstackAlloc
{
uint64_t ptr;
uint64_t nativePtr;
};
struct QueueCallstackFrameSize
{
uint64_t ptr;
uint8_t size;
};
struct QueueCallstackFrame
{
uint64_t name;
uint64_t file;
uint32_t line;
};
struct QueueCrashReport
{
int64_t time;
uint64_t text; // ptr
};
struct QueueSysTime
{
int64_t time;
float sysTime;
};
struct QueueContextSwitch
{
int64_t time;
uint64_t oldThread;
uint64_t newThread;
uint8_t cpu;
uint8_t reason;
uint8_t state;
};
struct QueueThreadWakeup
{
int64_t time;
uint64_t thread;
};
struct QueueTidToPid
{
uint64_t tid;
uint64_t pid;
};
struct QueueHeader
{
union
{
QueueType type;
uint8_t idx;
};
};
struct QueueItem
{
QueueHeader hdr;
union
{
QueueThreadContext threadCtx;
QueueZoneBegin zoneBegin;
QueueZoneEnd zoneEnd;
QueueZoneValidation zoneValidation;
QueueStringTransfer stringTransfer;
QueueFrameMark frameMark;
QueueFrameImage frameImage;
QueueSourceLocation srcloc;
QueueZoneText zoneText;
QueueLockAnnounce lockAnnounce;
QueueLockTerminate lockTerminate;
QueueLockWait lockWait;
QueueLockObtain lockObtain;
QueueLockRelease lockRelease;
QueueLockMark lockMark;
QueuePlotData plotData;
QueueMessage message;
QueueMessageColor messageColor;
QueueGpuNewContext gpuNewContext;
QueueGpuZoneBegin gpuZoneBegin;
QueueGpuZoneEnd gpuZoneEnd;
QueueGpuTime gpuTime;
QueueMemAlloc memAlloc;
QueueMemFree memFree;
QueueCallstackMemory callstackMemory;
QueueCallstack callstack;
QueueCallstackAlloc callstackAlloc;
QueueCallstackFrameSize callstackFrameSize;
QueueCallstackFrame callstackFrame;
QueueCrashReport crashReport;
QueueSysTime sysTime;
QueueContextSwitch contextSwitch;
QueueThreadWakeup threadWakeup;
QueueTidToPid tidToPid;
};
};
#pragma pack()
enum { QueueItemSize = sizeof( QueueItem ) };
static const size_t QueueDataSize[] = {
sizeof( QueueHeader ) + sizeof( QueueZoneText ),
sizeof( QueueHeader ) + sizeof( QueueZoneText ), // zone name
sizeof( QueueHeader ) + sizeof( QueueMessage ),
sizeof( QueueHeader ) + sizeof( QueueMessageColor ),
sizeof( QueueHeader ) + sizeof( QueueMessage ), // app info
sizeof( QueueHeader ) + sizeof( QueueZoneBegin ), // allocated source location
sizeof( QueueHeader ) + sizeof( QueueZoneBegin ), // allocated source location, callstack
sizeof( QueueHeader ) + sizeof( QueueCallstackMemory ),
sizeof( QueueHeader ) + sizeof( QueueCallstack ),
sizeof( QueueHeader ) + sizeof( QueueCallstackAlloc ),
sizeof( QueueHeader ) + sizeof( QueueFrameImage ),
// above items must be first
sizeof( QueueHeader ), // terminate
sizeof( QueueHeader ), // keep alive
sizeof( QueueHeader ) + sizeof( QueueThreadContext ),
sizeof( QueueHeader ), // crash
sizeof( QueueHeader ) + sizeof( QueueCrashReport ),
sizeof( QueueHeader ) + sizeof( QueueZoneBegin ),
sizeof( QueueHeader ) + sizeof( QueueZoneBegin ), // callstack
sizeof( QueueHeader ) + sizeof( QueueZoneEnd ),
sizeof( QueueHeader ) + sizeof( QueueZoneValidation ),
sizeof( QueueHeader ) + sizeof( QueueFrameMark ), // continuous frames
sizeof( QueueHeader ) + sizeof( QueueFrameMark ), // start
sizeof( QueueHeader ) + sizeof( QueueFrameMark ), // end
sizeof( QueueHeader ) + sizeof( QueueSourceLocation ),
sizeof( QueueHeader ) + sizeof( QueueLockAnnounce ),
sizeof( QueueHeader ) + sizeof( QueueLockTerminate ),
sizeof( QueueHeader ) + sizeof( QueueLockWait ),
sizeof( QueueHeader ) + sizeof( QueueLockObtain ),
sizeof( QueueHeader ) + sizeof( QueueLockRelease ),
sizeof( QueueHeader ) + sizeof( QueueLockWait ), // shared
sizeof( QueueHeader ) + sizeof( QueueLockObtain ), // shared
sizeof( QueueHeader ) + sizeof( QueueLockRelease ), // shared
sizeof( QueueHeader ) + sizeof( QueueLockMark ),
sizeof( QueueHeader ) + sizeof( QueuePlotData ),
sizeof( QueueHeader ) + sizeof( QueueMessage ), // literal
sizeof( QueueHeader ) + sizeof( QueueMessageColor ), // literal
sizeof( QueueHeader ) + sizeof( QueueGpuNewContext ),
sizeof( QueueHeader ) + sizeof( QueueGpuZoneBegin ),
sizeof( QueueHeader ) + sizeof( QueueGpuZoneBegin ), // callstack
sizeof( QueueHeader ) + sizeof( QueueGpuZoneEnd ),
sizeof( QueueHeader ) + sizeof( QueueGpuTime ),
sizeof( QueueHeader ) + sizeof( QueueMemAlloc ),
sizeof( QueueHeader ) + sizeof( QueueMemFree ),
sizeof( QueueHeader ) + sizeof( QueueMemAlloc ), // callstack
sizeof( QueueHeader ) + sizeof( QueueMemFree ), // callstack
sizeof( QueueHeader ) + sizeof( QueueCallstackFrameSize ),
sizeof( QueueHeader ) + sizeof( QueueCallstackFrame ),
sizeof( QueueHeader ) + sizeof( QueueSysTime ),
sizeof( QueueHeader ) + sizeof( QueueContextSwitch ),
sizeof( QueueHeader ) + sizeof( QueueThreadWakeup ),
sizeof( QueueHeader ) + sizeof( QueueTidToPid ),
// keep all QueueStringTransfer below
sizeof( QueueHeader ) + sizeof( QueueStringTransfer ), // string data
sizeof( QueueHeader ) + sizeof( QueueStringTransfer ), // thread name
sizeof( QueueHeader ) + sizeof( QueueStringTransfer ), // custom string data
sizeof( QueueHeader ) + sizeof( QueueStringTransfer ), // plot name
sizeof( QueueHeader ) + sizeof( QueueStringTransfer ), // allocated source location payload
sizeof( QueueHeader ) + sizeof( QueueStringTransfer ), // callstack payload
sizeof( QueueHeader ) + sizeof( QueueStringTransfer ), // callstack alloc payload
sizeof( QueueHeader ) + sizeof( QueueStringTransfer ), // frame name
sizeof( QueueHeader ) + sizeof( QueueStringTransfer ), // frame image data
sizeof( QueueHeader ) + sizeof( QueueStringTransfer ), // external name
sizeof( QueueHeader ) + sizeof( QueueStringTransfer ), // external thread name
};
static_assert( QueueItemSize == 32, "Queue item size not 32 bytes" );
static_assert( sizeof( QueueDataSize ) / sizeof( size_t ) == (uint8_t)QueueType::NUM_TYPES, "QueueDataSize mismatch" );
static_assert( sizeof( void* ) <= sizeof( uint64_t ), "Pointer size > 8 bytes" );
static_assert( sizeof( void* ) == sizeof( uintptr_t ), "Pointer size != uintptr_t" );
};
#endif

Some files were not shown because too many files have changed in this diff Show More