From 6751a406cc846f92eb9dd157feb6e007d8224f1f Mon Sep 17 00:00:00 2001 From: barrulus Date: Mon, 19 Oct 2026 20:30:27 +0100 Subject: [PATCH 1/2] feat(profiling): add optional Tracy conversion and compute stage zones --- CMakeLists.txt | 1 + HighMap/CMakeLists.txt | 7 + HighMap/include/highmap/profiling.hpp | 27 +++ .../highmap/virtual_array/virtual_array.hpp | 1 + .../highmap/virtual_array/virtual_array.inl | 182 +++++++++++------- HighMap/src/erosion/hydraulic_blur.cpp | 28 ++- HighMap/src/export/export_asset.cpp | 26 ++- .../array/sync_overlap_buffers.cpp | 2 + .../src/virtual_array/array/virtual_array.cpp | 5 + .../virtual_array/texture/virtual_texture.cpp | 4 + README.md | 6 +- docs/profiling.md | 26 +++ 12 files changed, 227 insertions(+), 88 deletions(-) create mode 100644 HighMap/include/highmap/profiling.hpp create mode 100644 docs/profiling.md diff --git a/CMakeLists.txt b/CMakeLists.txt index aa58baf2c2..7432d77236 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,6 +18,7 @@ option(HIGHMAP_ENABLE_TESTS "" ON) option(HIGHMAP_ENABLE_BENCHMARKS "" ON) option(HIGHMAP_ENABLE_PROFILE_BUILD "Enable build time profiling (-ftime-trace)" OFF) +option(HIGHMAP_ENABLE_TRACY "Enable optional Tracy CPU instrumentation" OFF) option(HIGHMAP_ENABLE_PCH "Enable Precompiled Headers (PCH)" OFF) # ----------------------------------------------------------------------------- diff --git a/HighMap/CMakeLists.txt b/HighMap/CMakeLists.txt index f272db2117..009e59b9b0 100644 --- a/HighMap/CMakeLists.txt +++ b/HighMap/CMakeLists.txt @@ -12,6 +12,13 @@ file(GLOB_RECURSE SOURCES ${PROJECT_SOURCE_DIR}/src/*.cpp) add_library(${PROJECT_NAME} STATIC ${SOURCES}) +if(HIGHMAP_ENABLE_TRACY) + find_package(Tracy CONFIG REQUIRED) + # Public because the tile dispatcher is instantiated by library consumers. + target_link_libraries(${PROJECT_NAME} PUBLIC Tracy::TracyClient) + target_compile_definitions(${PROJECT_NAME} PUBLIC HIGHMAP_ENABLE_TRACY) +endif() + target_include_directories( ${PROJECT_NAME} PUBLIC ${PROJECT_SOURCE_DIR}/include diff --git a/HighMap/include/highmap/profiling.hpp b/HighMap/include/highmap/profiling.hpp new file mode 100644 index 0000000000..20b007af23 --- /dev/null +++ b/HighMap/include/highmap/profiling.hpp @@ -0,0 +1,27 @@ +#pragma once + +// Optional CPU instrumentation. No expressions are evaluated in normal builds. +#ifdef HIGHMAP_ENABLE_TRACY +#include +#include +#ifndef TRACY_ENABLE +#error HIGHMAP_ENABLE_TRACY requires a Tracy client built with TRACY_ENABLE +#endif +#define HMAP_PROFILE_ZONE(name) ZoneScopedN(name) +#define HMAP_PROFILE_TEXT(text) \ + do \ + { \ + if (TracyIsConnected) \ + { \ + const auto &hmap_profile_text = (text); \ + const std::string_view hmap_profile_view(hmap_profile_text); \ + ZoneText(hmap_profile_view.data(), hmap_profile_view.size()); \ + } \ + } while (false) +#else +#define HMAP_PROFILE_ZONE(name) +#define HMAP_PROFILE_TEXT(text) \ + do \ + { \ + } while (false) +#endif diff --git a/HighMap/include/highmap/virtual_array/virtual_array.hpp b/HighMap/include/highmap/virtual_array/virtual_array.hpp index 8c3daa1c1e..7412e4a29d 100644 --- a/HighMap/include/highmap/virtual_array/virtual_array.hpp +++ b/HighMap/include/highmap/virtual_array/virtual_array.hpp @@ -12,6 +12,7 @@ #include #include "highmap/array.hpp" +#include "highmap/profiling.hpp" #include "highmap/filters.hpp" #include "highmap/logger.hpp" #include "highmap/math/core.hpp" diff --git a/HighMap/include/highmap/virtual_array/virtual_array.inl b/HighMap/include/highmap/virtual_array/virtual_array.inl index 9cf50edb80..d1e03c44be 100644 --- a/HighMap/include/highmap/virtual_array/virtual_array.inl +++ b/HighMap/include/highmap/virtual_array/virtual_array.inl @@ -13,7 +13,8 @@ struct TileAccess { if (!this->outputs.empty() && this->outputs.front()) return this->outputs.front(); - if (!this->inputs.empty()) return this->inputs.front(); + if (!this->inputs.empty()) + return this->inputs.front(); return nullptr; } }; @@ -21,6 +22,7 @@ struct TileAccess template void for_each_tile(const TileAccess &access, Func &&func, const ComputeMode &cm) { + HMAP_PROFILE_ZONE("HighMap::for_each_tile"); if (access.outputs.empty() && access.inputs.empty()) { hmap::log::error("no input or output VirtualArray"); @@ -28,13 +30,20 @@ void for_each_tile(const TileAccess &access, Func &&func, const ComputeMode &cm) } const VirtualArray *ref_va = access.ref_va(); - if (!ref_va) return; + if (!ref_va) + return; + + HMAP_PROFILE_TEXT(to_string(cm.mode) + " shape=" + std::to_string(ref_va->shape.x) + + "x" + std::to_string(ref_va->shape.y) + " tile=" + + std::to_string(ref_va->tile_shape.x) + "x" + + std::to_string(ref_va->tile_shape.y)); // --- validate compatibility auto check = [&](const VirtualArray *va) { - if (!va) return true; + if (!va) + return true; return va->shape == ref_va->shape && va->tile_shape == ref_va->tile_shape; }; @@ -56,25 +65,36 @@ void for_each_tile(const TileAccess &access, Func &&func, const ComputeMode &cm) auto region_dispatcher = [&](const TileRegion ®ion) { + HMAP_PROFILE_ZONE("HighMap::tile"); std::vector in_tiles; std::vector out_tiles; in_tiles.reserve(access.inputs.size()); out_tiles.reserve(access.outputs.size()); - for (auto *va : access.inputs) - in_tiles.push_back(va ? &va->storage->get_tile(region) : nullptr); - - for (auto *va : access.outputs) - out_tiles.push_back(va ? &va->storage->get_tile(region) : nullptr); + { + HMAP_PROFILE_ZONE("HighMap::tile.acquire"); + for (auto *va : access.inputs) + in_tiles.push_back(va ? &va->storage->get_tile(region) : nullptr); - func(in_tiles, out_tiles, region); + for (auto *va : access.outputs) + out_tiles.push_back(va ? &va->storage->get_tile(region) : nullptr); + } + { + HMAP_PROFILE_ZONE("HighMap::tile.algorithm"); + func(in_tiles, out_tiles, region); + } + { + HMAP_PROFILE_ZONE("HighMap::tile.release"); - for (auto *va : access.inputs) - if (va) va->storage->release_tile(region); + for (auto *va : access.inputs) + if (va) + va->storage->release_tile(region); - for (auto *va : access.outputs) - if (va) va->storage->release_tile(region); + for (auto *va : access.outputs) + if (va) + va->storage->release_tile(region); + } }; // reuse your existing modes @@ -96,10 +116,13 @@ void for_each_tile(const TileAccess &access, Func &&func, const ComputeMode &cm) if (cm.trim_storage) { + HMAP_PROFILE_ZONE("HighMap::trim_storage"); for (auto *va : access.inputs) - if (va) va->trim_storage(); + if (va) + va->trim_storage(); for (auto *va : access.outputs) - if (va) va->trim_storage(); + if (va) + va->trim_storage(); } } @@ -156,8 +179,7 @@ void for_each_tile(const std::vector &inputs, // --- COMPUTE template -void sequential_tile_loop(const VirtualArray &ref_va, - RegionDispatcher &&dispatcher) +void sequential_tile_loop(const VirtualArray &ref_va, RegionDispatcher &&dispatcher) { const int nx = ceil_div(ref_va.shape.x, ref_va.tile_shape.x); const int ny = ceil_div(ref_va.shape.y, ref_va.tile_shape.y); @@ -175,11 +197,13 @@ void distributed_tile_loop(const VirtualArray &ref_va, RegionDispatcher &&dispatcher, int nthreads = 0) { + HMAP_PROFILE_ZONE("HighMap::distributed_tile_loop"); const int nx = ceil_div(ref_va.shape.x, ref_va.tile_shape.x); const int ny = ceil_div(ref_va.shape.y, ref_va.tile_shape.y); const int ntasks = nx * ny; - if (nthreads <= 0) nthreads = std::thread::hardware_concurrency(); + if (nthreads <= 0) + nthreads = std::thread::hardware_concurrency(); nthreads = std::min(nthreads, ntasks); @@ -210,8 +234,10 @@ void distributed_tile_loop(const VirtualArray &ref_va, template void single_array_compute(const TileAccess &access, Func &&func, int stride = 1) { + HMAP_PROFILE_ZONE("HighMap::single_array"); const VirtualArray *ref_va = access.ref_va(); - if (!ref_va) return; + if (!ref_va) + return; // create temporary arrays std::vector arrays_in; @@ -232,16 +258,18 @@ void single_array_compute(const TileAccess &access, Func &&func, int stride = 1) shape_wrk = glm::ivec2(nx, ny); } - // project - for (auto *va : access.inputs) - arrays_in.push_back(va ? va->to_array(cm_local).resample_to_shape(shape_wrk) - : Array()); - - for (auto *va : access.outputs) - // TODO remove to_array(), left for retor-fit but misusage - arrays_out.push_back( - va ? va->to_array(cm_local).resample_to_shape(shape_wrk) : Array()); + { + HMAP_PROFILE_ZONE("HighMap::single_array.gather"); + // project + for (auto *va : access.inputs) + arrays_in.push_back(va ? va->to_array(cm_local).resample_to_shape(shape_wrk) + : Array()); + for (auto *va : access.outputs) + // TODO remove to_array(), left for retor-fit but misusage + arrays_out.push_back(va ? va->to_array(cm_local).resample_to_shape(shape_wrk) + : Array()); + } // create pointer vector for user func std::vector in_tiles; std::vector out_tiles; @@ -260,27 +288,33 @@ void single_array_compute(const TileAccess &access, Func &&func, int stride = 1) shape_wrk, {0, 0, 0, 0}); - func(in_tiles, out_tiles, va_region); + { + HMAP_PROFILE_ZONE("HighMap::single_array.algorithm"); + func(in_tiles, out_tiles, va_region); + } - // copy back to VirtualArrays (only outputs do not need to update const - // inputs) - for (size_t i = 0; i < access.outputs.size(); ++i) - if (access.outputs[i]) - { - if (shape_wrk != ref_va->shape) - access.outputs[i]->from_array_bicubic(arrays_out[i], cm_local); - else - access.outputs[i]->from_array(arrays_out[i], cm_local); - } + { + HMAP_PROFILE_ZONE("HighMap::single_array.scatter"); + // copy back to VirtualArrays (only outputs do not need to update const + // inputs) + for (size_t i = 0; i < access.outputs.size(); ++i) + if (access.outputs[i]) + { + if (shape_wrk != ref_va->shape) + access.outputs[i]->from_array_bicubic(arrays_out[i], cm_local); + else + access.outputs[i]->from_array(arrays_out[i], cm_local); + } + } } template -void single_array_downscaled_compute(const TileAccess &access, - Func &&func, - float kc) +void single_array_downscaled_compute(const TileAccess &access, Func &&func, float kc) { + HMAP_PROFILE_ZONE("HighMap::single_array_downscaled"); const VirtualArray *ref_va = access.ref_va(); - if (!ref_va) return; + if (!ref_va) + return; // create temporary arrays std::vector arrays_in; @@ -301,16 +335,18 @@ void single_array_downscaled_compute(const TileAccess &access, shape_wrk = glm::ivec2(nx, ny); } - // project - for (auto *va : access.inputs) - arrays_in.push_back(va ? va->to_array(cm_local).resample_to_shape(shape_wrk) - : Array()); - - for (auto *va : access.outputs) - // TODO remove to_array(), left for retor-fit but misusage - arrays_out.push_back( - va ? va->to_array(cm_local).resample_to_shape(shape_wrk) : Array()); + { + HMAP_PROFILE_ZONE("HighMap::single_array.gather"); + // project + for (auto *va : access.inputs) + arrays_in.push_back(va ? va->to_array(cm_local).resample_to_shape(shape_wrk) + : Array()); + for (auto *va : access.outputs) + // TODO remove to_array(), left for retor-fit but misusage + arrays_out.push_back(va ? va->to_array(cm_local).resample_to_shape(shape_wrk) + : Array()); + } // create pointer vector for user func std::vector in_tiles; std::vector out_tiles; @@ -329,28 +365,34 @@ void single_array_downscaled_compute(const TileAccess &access, shape_wrk, {0, 0, 0, 0}); - func(in_tiles, out_tiles, va_region); + { + HMAP_PROFILE_ZONE("HighMap::single_array.algorithm"); + func(in_tiles, out_tiles, va_region); + } - // copy back to VirtualArrays (only outputs do not need to update const - // inputs) - for (size_t i = 0; i < access.outputs.size(); ++i) - if (access.outputs[i]) - { - // resample to initial shape and add higher frequency - Array out_full = access.outputs[i]->to_array(cm_local); - Array out_low_pass = out_full.resample_to_shape(shape_wrk) - .resample_to_shape_bicubic(ref_va->shape); + { + HMAP_PROFILE_ZONE("HighMap::single_array.scatter"); + // copy back to VirtualArrays (only outputs do not need to update const + // inputs) + for (size_t i = 0; i < access.outputs.size(); ++i) + if (access.outputs[i]) + { + // resample to initial shape and add higher frequency + Array out_full = access.outputs[i]->to_array(cm_local); + Array out_low_pass = out_full.resample_to_shape(shape_wrk) + .resample_to_shape_bicubic(ref_va->shape); - // resample coarse result and use it to replace the initial - // low-frequency content - arrays_out[i] = arrays_out[i].resample_to_shape_bicubic(ref_va->shape); + // resample coarse result and use it to replace the initial + // low-frequency content + arrays_out[i] = arrays_out[i].resample_to_shape_bicubic(ref_va->shape); - // TODO add post-filter - // laplace(arrays_out[i]); + // TODO add post-filter + // laplace(arrays_out[i]); - access.outputs[i]->from_array(arrays_out[i] + (out_full - out_low_pass), - cm_local); - } + access.outputs[i]->from_array(arrays_out[i] + (out_full - out_low_pass), + cm_local); + } + } } template diff --git a/HighMap/src/erosion/hydraulic_blur.cpp b/HighMap/src/erosion/hydraulic_blur.cpp index e9e852b58b..1057f358d3 100644 --- a/HighMap/src/erosion/hydraulic_blur.cpp +++ b/HighMap/src/erosion/hydraulic_blur.cpp @@ -3,6 +3,7 @@ * this software. */ #include +#include "highmap/profiling.hpp" #include "highmap/array.hpp" #include "highmap/erosion/deprecated.hpp" #include "highmap/filters.hpp" @@ -14,20 +15,31 @@ namespace hmap void hydraulic_blur(Array &z, float vmax, float radius, float k_smoothing) { - if (!validate_non_empty(z)) return; + HMAP_PROFILE_ZONE("HighMap::hydraulic_blur"); + if (!validate_non_empty(z)) + return; int ir = std::max(1, (int)(radius * z.shape.x)); Array z_clamped = z; - if (k_smoothing) - clamp_min_smooth(z_clamped, vmax, k_smoothing); - else - clamp_min_smooth(z_clamped, vmax); + { + HMAP_PROFILE_ZONE("HighMap::hydraulic_blur.clamp"); + if (k_smoothing) + clamp_min_smooth(z_clamped, vmax, k_smoothing); + else + clamp_min_smooth(z_clamped, vmax); + } Array z_filtered = z; - smooth_cpulse(z_filtered, ir); - - z = (z_clamped + z_filtered - vmax); + { + HMAP_PROFILE_ZONE("HighMap::hydraulic_blur.smooth"); + smooth_cpulse(z_filtered, ir); + } + + { + HMAP_PROFILE_ZONE("HighMap::hydraulic_blur.combine"); + z = (z_clamped + z_filtered - vmax); + } } } // namespace hmap diff --git a/HighMap/src/export/export_asset.cpp b/HighMap/src/export/export_asset.cpp index 21deb82e3c..de86d32b1f 100644 --- a/HighMap/src/export/export_asset.cpp +++ b/HighMap/src/export/export_asset.cpp @@ -11,6 +11,7 @@ #include "hmm/src/heightmap.h" #include "hmm/src/triangulator.h" +#include "highmap/profiling.hpp" #include "highmap/algebra.hpp" #include "highmap/array.hpp" #include "highmap/export/asset.hpp" @@ -36,6 +37,7 @@ void helper_build_mesh_masked(aiMesh *p_mesh, float elevation_scaling, bool fit_boundaries) { + HMAP_PROFILE_ZONE("HighMap::export_asset.mesh_masked"); float x_max = fit_boundaries ? 1.f : (array.shape.x > 0 ? 1.f - 1.f / (float)array.shape.x @@ -130,6 +132,7 @@ void helper_build_mesh(aiMesh *p_mesh, float max_error, bool fit_boundaries) { + HMAP_PROFILE_ZONE("HighMap::export_asset.mesh"); float x_max = fit_boundaries ? 1.f : (array.shape.x > 0 ? 1.f - 1.f / (float)array.shape.x @@ -206,7 +209,10 @@ void helper_build_mesh(aiMesh *p_mesh, const int max_points = 0; hmap::log::trace("remeshing (Delaunay)"); - tri.Run(max_error, max_triangles, max_points); + { + HMAP_PROFILE_ZONE("HighMap::export_asset.triangulate"); + tri.Run(max_error, max_triangles, max_points); + } auto points = tri.Points(elevation_scaling); auto triangles = tri.Triangles(); @@ -321,10 +327,11 @@ bool export_asset(const std::string &fname, std::string format_extension = "." + asset_export_format_as_string.at( export_format)[2]; - aiReturn err = exporter.Export(p_scene, - format_id, - fname + format_extension, - 0); + aiReturn err; + { + HMAP_PROFILE_ZONE("HighMap::export_asset.write"); + err = exporter.Export(p_scene, format_id, fname + format_extension, 0); + } delete p_scene; @@ -398,10 +405,11 @@ bool export_asset(const std::string &fname, std::string format_extension = "." + asset_export_format_as_string.at( export_format)[2]; - aiReturn err = exporter.Export(p_scene, - format_id, - fname + format_extension, - 0); + aiReturn err; + { + HMAP_PROFILE_ZONE("HighMap::export_asset.write"); + err = exporter.Export(p_scene, format_id, fname + format_extension, 0); + } delete p_scene; diff --git a/HighMap/src/virtual_array/array/sync_overlap_buffers.cpp b/HighMap/src/virtual_array/array/sync_overlap_buffers.cpp index 0f6bfcefb1..a2fc54dae7 100644 --- a/HighMap/src/virtual_array/array/sync_overlap_buffers.cpp +++ b/HighMap/src/virtual_array/array/sync_overlap_buffers.cpp @@ -4,6 +4,7 @@ #include #include +#include "highmap/profiling.hpp" #include "highmap/array.hpp" #include "highmap/logger.hpp" #include "highmap/math/core.hpp" @@ -16,6 +17,7 @@ namespace hmap void VirtualArray::sync_overlap_buffers(SyncOperation op) { + HMAP_PROFILE_ZONE("HighMap::VirtualArray::sync_overlap_buffers"); if (this->storage->max_live_tiles() < 2) { hmap::log::error( diff --git a/HighMap/src/virtual_array/array/virtual_array.cpp b/HighMap/src/virtual_array/array/virtual_array.cpp index 4042916af0..e09b6ec279 100644 --- a/HighMap/src/virtual_array/array/virtual_array.cpp +++ b/HighMap/src/virtual_array/array/virtual_array.cpp @@ -11,6 +11,7 @@ #include #include +#include "highmap/profiling.hpp" #include "highmap/array.hpp" #include "highmap/internal/validation.hpp" #include "highmap/math/core.hpp" @@ -110,6 +111,7 @@ void VirtualArray::fill(float value, const ComputeMode &cm) void VirtualArray::from_array(const Array &array, const ComputeMode &cm) { + HMAP_PROFILE_ZONE("HighMap::VirtualArray::from_array"); if (!validate_non_empty(array)) return; auto lambda = [&array, this](Array &tile, const TileRegion ®ion) @@ -144,6 +146,7 @@ void VirtualArray::from_array(const Array &array, const ComputeMode &cm) void VirtualArray::from_array_bilinear(const Array &array, const ComputeMode &cm) { + HMAP_PROFILE_ZONE("HighMap::VirtualArray::from_array_bilinear"); if (!validate_non_empty(array)) return; auto lambda = [&array, this](Array &tile, const TileRegion ®ion) @@ -185,6 +188,7 @@ void VirtualArray::from_array_bilinear(const Array &array, void VirtualArray::from_array_bicubic(const Array &array, const ComputeMode &cm) { + HMAP_PROFILE_ZONE("HighMap::VirtualArray::from_array_bicubic"); if (!validate_non_empty(array)) return; auto lambda = [&array, this](Array &tile, const TileRegion ®ion) @@ -431,6 +435,7 @@ glm::ivec2 VirtualArray::tile_region_global_indices( Array VirtualArray::to_array(const glm::ivec2 &array_shape, const ComputeMode &cm) const { + HMAP_PROFILE_ZONE("HighMap::VirtualArray::to_array"); if (!validate_shape(array_shape)) return Array(); Array array(array_shape); diff --git a/HighMap/src/virtual_array/texture/virtual_texture.cpp b/HighMap/src/virtual_array/texture/virtual_texture.cpp index 28897e8c8f..1d51f332f8 100644 --- a/HighMap/src/virtual_array/texture/virtual_texture.cpp +++ b/HighMap/src/virtual_array/texture/virtual_texture.cpp @@ -8,6 +8,7 @@ #include #include +#include "highmap/profiling.hpp" #include "highmap/array.hpp" #include "highmap/internal/validation.hpp" #include "highmap/logger.hpp" @@ -138,6 +139,7 @@ void VirtualTexture::fill(int c, float value, const ComputeMode &cm) void VirtualTexture::from_arrays(const std::vector &p_arrays, const ComputeMode &cm) { + HMAP_PROFILE_ZONE("HighMap::VirtualTexture::from_arrays"); if (!validate_non_empty(p_arrays, "Array pointer list")) return; const int nch = this->channels(); @@ -163,6 +165,7 @@ std::vector VirtualTexture::to_img_8bit(const glm::ivec2 &img_shape, const ComputeMode &cm, bool flip_y) const { + HMAP_PROFILE_ZONE("HighMap::VirtualTexture::to_img_8bit"); const int nch = this->channels(); if (nch != 3 && nch != 4) @@ -228,6 +231,7 @@ std::vector VirtualTexture::to_raw(const ComputeMode &cm, bool flip_y) Texture VirtualTexture::to_texture(const glm::ivec2 &img_shape, const ComputeMode &cm) const { + HMAP_PROFILE_ZONE("HighMap::VirtualTexture::to_texture"); if (!validate_shape(img_shape)) return Texture(); const int nch = this->channels(); diff --git a/README.md b/README.md index 9b242b1840..b826f71a16 100644 --- a/README.md +++ b/README.md @@ -78,4 +78,8 @@ See the `examples` folder. ## Third Party Code This project includes code from external open-source projects. -See [THIRD_PARTY_LICENSES.md](THIRD_PARTY_LICENSES.md). \ No newline at end of file +See [THIRD_PARTY_LICENSES.md](THIRD_PARTY_LICENSES.md). + +## CPU profiling + +Optional Tracy instrumentation is described in [the profiling guide](docs/profiling.md). diff --git a/docs/profiling.md b/docs/profiling.md new file mode 100644 index 0000000000..d507928c54 --- /dev/null +++ b/docs/profiling.md @@ -0,0 +1,26 @@ +# Optional Tracy CPU profiling + +`HIGHMAP_ENABLE_TRACY` defaults to `OFF`; normal builds do not require Tracy. +To enable it, install a Tracy client built with `TRACY_ENABLE=ON`, then configure +with `-DHIGHMAP_ENABLE_TRACY=ON -DTracy_DIR=/path/to/lib/cmake/Tracy`. +Use matching client and capture/profiler versions. On-demand clients are supported. + +The `highmap` CMake target publicly propagates both the client target and +`HIGHMAP_ENABLE_TRACY`, so consumers instantiate the public tile templates with +the same instrumentation as the library. Do not manually enable the macro in +only some translation units. Link a single client into the final executable. +Disabled hooks discard metadata expressions; enabled metadata is evaluated only +while connected. + +Zones cover VirtualArray conversion/write-back, overlap synchronization, +VirtualTexture conversion, shared tiled and full-array dispatch, HydraulicBlur +stages and asset mesh generation/export. Tile dispatch separates storage acquire, +callback and release; full-array dispatch separates gather, callback and scatter. +The downscaled scatter includes high-frequency reconstruction. No per-cell zones +are emitted. Many small tiles can still generate substantial capture traffic. + +These are CPU durations, including any synchronous library work and waits. +They are not GPU kernel/transfer timing or allocation tracking. Nested times +include their children. Distributed tile zones run on worker threads, so their +sum is not dispatch wall time. Conversion callbacks also appear as tile algorithms; +interpret them using the enclosing conversion zone and thread context. From 53bbcdc8d1c97a03754dc84a2c4b45105fd040e2 Mon Sep 17 00:00:00 2001 From: Otto Link Date: Tue, 20 Oct 2026 08:52:33 +0200 Subject: [PATCH 2/2] chore: format code --- HighMap/include/highmap/carving.hpp | 13 ++-- HighMap/include/highmap/profiling.hpp | 25 ++++---- .../highmap/virtual_array/virtual_array.hpp | 2 +- .../highmap/virtual_array/virtual_array.inl | 60 +++++++++---------- HighMap/src/erosion/hydraulic_blur.cpp | 5 +- HighMap/src/export/export_asset.cpp | 2 +- .../array/sync_overlap_buffers.cpp | 2 +- .../src/virtual_array/array/virtual_array.cpp | 2 +- .../virtual_array/texture/virtual_texture.cpp | 2 +- 9 files changed, 54 insertions(+), 59 deletions(-) diff --git a/HighMap/include/highmap/carving.hpp b/HighMap/include/highmap/carving.hpp index 7245576cbf..7d52c11897 100644 --- a/HighMap/include/highmap/carving.hpp +++ b/HighMap/include/highmap/carving.hpp @@ -246,11 +246,11 @@ void trench(Array &z, * @param[in] tile_size Spatial tile partition size. * @param[in] bbox Domain bounding box. */ -void trench(Array &z, - const Graph &graph, - const std::vector &relative_widths, - float width, - bool enable_width_depth_scaling = true, +void trench(Array &z, + const Graph &graph, + const std::vector &relative_widths, + float width, + bool enable_width_depth_scaling = true, RadialProfile radial_profile = RadialProfile::RP_SMOOTHSTEP_UPPER, float radial_profile_parameter = 2.f, ElevationLongitudinalProfile longitudinal_profile = @@ -268,7 +268,8 @@ void trench(Array &z, * * @param[in,out] z Target heightmap to carve in-place. * @param[in] graph Input flow network Graph. - * @param[in] width Target river width at the outlet(s). + * @param[in] width Target river width at the + * outlet(s). * @param[in] width_exponent Scaling exponent for width with * distance to outlet (default: 1.0). * @param[in] enable_width_depth_scaling Modulate width according to depth. diff --git a/HighMap/include/highmap/profiling.hpp b/HighMap/include/highmap/profiling.hpp index 20b007af23..ad8fd1e67f 100644 --- a/HighMap/include/highmap/profiling.hpp +++ b/HighMap/include/highmap/profiling.hpp @@ -3,25 +3,26 @@ // Optional CPU instrumentation. No expressions are evaluated in normal builds. #ifdef HIGHMAP_ENABLE_TRACY #include + #include #ifndef TRACY_ENABLE #error HIGHMAP_ENABLE_TRACY requires a Tracy client built with TRACY_ENABLE #endif #define HMAP_PROFILE_ZONE(name) ZoneScopedN(name) -#define HMAP_PROFILE_TEXT(text) \ - do \ - { \ - if (TracyIsConnected) \ - { \ - const auto &hmap_profile_text = (text); \ - const std::string_view hmap_profile_view(hmap_profile_text); \ - ZoneText(hmap_profile_view.data(), hmap_profile_view.size()); \ - } \ +#define HMAP_PROFILE_TEXT(text) \ + do \ + { \ + if (TracyIsConnected) \ + { \ + const auto &hmap_profile_text = (text); \ + const std::string_view hmap_profile_view(hmap_profile_text); \ + ZoneText(hmap_profile_view.data(), hmap_profile_view.size()); \ + } \ } while (false) #else #define HMAP_PROFILE_ZONE(name) -#define HMAP_PROFILE_TEXT(text) \ - do \ - { \ +#define HMAP_PROFILE_TEXT(text) \ + do \ + { \ } while (false) #endif diff --git a/HighMap/include/highmap/virtual_array/virtual_array.hpp b/HighMap/include/highmap/virtual_array/virtual_array.hpp index 7412e4a29d..c2d2df58f3 100644 --- a/HighMap/include/highmap/virtual_array/virtual_array.hpp +++ b/HighMap/include/highmap/virtual_array/virtual_array.hpp @@ -12,10 +12,10 @@ #include #include "highmap/array.hpp" -#include "highmap/profiling.hpp" #include "highmap/filters.hpp" #include "highmap/logger.hpp" #include "highmap/math/core.hpp" +#include "highmap/profiling.hpp" #include "highmap/virtual_array/tile_region.hpp" #include "highmap/virtual_array/tile_storage.hpp" diff --git a/HighMap/include/highmap/virtual_array/virtual_array.inl b/HighMap/include/highmap/virtual_array/virtual_array.inl index d1e03c44be..44b4a40065 100644 --- a/HighMap/include/highmap/virtual_array/virtual_array.inl +++ b/HighMap/include/highmap/virtual_array/virtual_array.inl @@ -13,8 +13,7 @@ struct TileAccess { if (!this->outputs.empty() && this->outputs.front()) return this->outputs.front(); - if (!this->inputs.empty()) - return this->inputs.front(); + if (!this->inputs.empty()) return this->inputs.front(); return nullptr; } }; @@ -30,20 +29,19 @@ void for_each_tile(const TileAccess &access, Func &&func, const ComputeMode &cm) } const VirtualArray *ref_va = access.ref_va(); - if (!ref_va) - return; + if (!ref_va) return; - HMAP_PROFILE_TEXT(to_string(cm.mode) + " shape=" + std::to_string(ref_va->shape.x) + - "x" + std::to_string(ref_va->shape.y) + " tile=" + - std::to_string(ref_va->tile_shape.x) + "x" + + HMAP_PROFILE_TEXT(to_string(cm.mode) + + " shape=" + std::to_string(ref_va->shape.x) + "x" + + std::to_string(ref_va->shape.y) + + " tile=" + std::to_string(ref_va->tile_shape.x) + "x" + std::to_string(ref_va->tile_shape.y)); // --- validate compatibility auto check = [&](const VirtualArray *va) { - if (!va) - return true; + if (!va) return true; return va->shape == ref_va->shape && va->tile_shape == ref_va->tile_shape; }; @@ -88,12 +86,10 @@ void for_each_tile(const TileAccess &access, Func &&func, const ComputeMode &cm) HMAP_PROFILE_ZONE("HighMap::tile.release"); for (auto *va : access.inputs) - if (va) - va->storage->release_tile(region); + if (va) va->storage->release_tile(region); for (auto *va : access.outputs) - if (va) - va->storage->release_tile(region); + if (va) va->storage->release_tile(region); } }; @@ -118,11 +114,9 @@ void for_each_tile(const TileAccess &access, Func &&func, const ComputeMode &cm) { HMAP_PROFILE_ZONE("HighMap::trim_storage"); for (auto *va : access.inputs) - if (va) - va->trim_storage(); + if (va) va->trim_storage(); for (auto *va : access.outputs) - if (va) - va->trim_storage(); + if (va) va->trim_storage(); } } @@ -179,7 +173,8 @@ void for_each_tile(const std::vector &inputs, // --- COMPUTE template -void sequential_tile_loop(const VirtualArray &ref_va, RegionDispatcher &&dispatcher) +void sequential_tile_loop(const VirtualArray &ref_va, + RegionDispatcher &&dispatcher) { const int nx = ceil_div(ref_va.shape.x, ref_va.tile_shape.x); const int ny = ceil_div(ref_va.shape.y, ref_va.tile_shape.y); @@ -202,8 +197,7 @@ void distributed_tile_loop(const VirtualArray &ref_va, const int ny = ceil_div(ref_va.shape.y, ref_va.tile_shape.y); const int ntasks = nx * ny; - if (nthreads <= 0) - nthreads = std::thread::hardware_concurrency(); + if (nthreads <= 0) nthreads = std::thread::hardware_concurrency(); nthreads = std::min(nthreads, ntasks); @@ -236,8 +230,7 @@ void single_array_compute(const TileAccess &access, Func &&func, int stride = 1) { HMAP_PROFILE_ZONE("HighMap::single_array"); const VirtualArray *ref_va = access.ref_va(); - if (!ref_va) - return; + if (!ref_va) return; // create temporary arrays std::vector arrays_in; @@ -262,13 +255,13 @@ void single_array_compute(const TileAccess &access, Func &&func, int stride = 1) HMAP_PROFILE_ZONE("HighMap::single_array.gather"); // project for (auto *va : access.inputs) - arrays_in.push_back(va ? va->to_array(cm_local).resample_to_shape(shape_wrk) - : Array()); + arrays_in.push_back( + va ? va->to_array(cm_local).resample_to_shape(shape_wrk) : Array()); for (auto *va : access.outputs) // TODO remove to_array(), left for retor-fit but misusage - arrays_out.push_back(va ? va->to_array(cm_local).resample_to_shape(shape_wrk) - : Array()); + arrays_out.push_back( + va ? va->to_array(cm_local).resample_to_shape(shape_wrk) : Array()); } // create pointer vector for user func std::vector in_tiles; @@ -309,12 +302,13 @@ void single_array_compute(const TileAccess &access, Func &&func, int stride = 1) } template -void single_array_downscaled_compute(const TileAccess &access, Func &&func, float kc) +void single_array_downscaled_compute(const TileAccess &access, + Func &&func, + float kc) { HMAP_PROFILE_ZONE("HighMap::single_array_downscaled"); const VirtualArray *ref_va = access.ref_va(); - if (!ref_va) - return; + if (!ref_va) return; // create temporary arrays std::vector arrays_in; @@ -339,13 +333,13 @@ void single_array_downscaled_compute(const TileAccess &access, Func &&func, floa HMAP_PROFILE_ZONE("HighMap::single_array.gather"); // project for (auto *va : access.inputs) - arrays_in.push_back(va ? va->to_array(cm_local).resample_to_shape(shape_wrk) - : Array()); + arrays_in.push_back( + va ? va->to_array(cm_local).resample_to_shape(shape_wrk) : Array()); for (auto *va : access.outputs) // TODO remove to_array(), left for retor-fit but misusage - arrays_out.push_back(va ? va->to_array(cm_local).resample_to_shape(shape_wrk) - : Array()); + arrays_out.push_back( + va ? va->to_array(cm_local).resample_to_shape(shape_wrk) : Array()); } // create pointer vector for user func std::vector in_tiles; diff --git a/HighMap/src/erosion/hydraulic_blur.cpp b/HighMap/src/erosion/hydraulic_blur.cpp index 1057f358d3..83c9a30b2f 100644 --- a/HighMap/src/erosion/hydraulic_blur.cpp +++ b/HighMap/src/erosion/hydraulic_blur.cpp @@ -3,11 +3,11 @@ * this software. */ #include -#include "highmap/profiling.hpp" #include "highmap/array.hpp" #include "highmap/erosion/deprecated.hpp" #include "highmap/filters.hpp" #include "highmap/internal/validation.hpp" +#include "highmap/profiling.hpp" #include "highmap/range.hpp" namespace hmap @@ -16,8 +16,7 @@ namespace hmap void hydraulic_blur(Array &z, float vmax, float radius, float k_smoothing) { HMAP_PROFILE_ZONE("HighMap::hydraulic_blur"); - if (!validate_non_empty(z)) - return; + if (!validate_non_empty(z)) return; int ir = std::max(1, (int)(radius * z.shape.x)); diff --git a/HighMap/src/export/export_asset.cpp b/HighMap/src/export/export_asset.cpp index de86d32b1f..734fb385ac 100644 --- a/HighMap/src/export/export_asset.cpp +++ b/HighMap/src/export/export_asset.cpp @@ -11,13 +11,13 @@ #include "hmm/src/heightmap.h" #include "hmm/src/triangulator.h" -#include "highmap/profiling.hpp" #include "highmap/algebra.hpp" #include "highmap/array.hpp" #include "highmap/export/asset.hpp" #include "highmap/internal/validation.hpp" #include "highmap/logger.hpp" #include "highmap/operator.hpp" +#include "highmap/profiling.hpp" #include #include diff --git a/HighMap/src/virtual_array/array/sync_overlap_buffers.cpp b/HighMap/src/virtual_array/array/sync_overlap_buffers.cpp index a2fc54dae7..7e358bb7b0 100644 --- a/HighMap/src/virtual_array/array/sync_overlap_buffers.cpp +++ b/HighMap/src/virtual_array/array/sync_overlap_buffers.cpp @@ -4,10 +4,10 @@ #include #include -#include "highmap/profiling.hpp" #include "highmap/array.hpp" #include "highmap/logger.hpp" #include "highmap/math/core.hpp" +#include "highmap/profiling.hpp" #include "highmap/virtual_array/tile_region.hpp" #include "highmap/virtual_array/tile_storage.hpp" #include "highmap/virtual_array/virtual_array.hpp" diff --git a/HighMap/src/virtual_array/array/virtual_array.cpp b/HighMap/src/virtual_array/array/virtual_array.cpp index e09b6ec279..99e61c1336 100644 --- a/HighMap/src/virtual_array/array/virtual_array.cpp +++ b/HighMap/src/virtual_array/array/virtual_array.cpp @@ -11,10 +11,10 @@ #include #include -#include "highmap/profiling.hpp" #include "highmap/array.hpp" #include "highmap/internal/validation.hpp" #include "highmap/math/core.hpp" +#include "highmap/profiling.hpp" #include "highmap/virtual_array/tile_region.hpp" #include "highmap/virtual_array/tile_storage.hpp" #include "highmap/virtual_array/virtual_array.hpp" diff --git a/HighMap/src/virtual_array/texture/virtual_texture.cpp b/HighMap/src/virtual_array/texture/virtual_texture.cpp index 1d51f332f8..ac5e7b3d17 100644 --- a/HighMap/src/virtual_array/texture/virtual_texture.cpp +++ b/HighMap/src/virtual_array/texture/virtual_texture.cpp @@ -8,10 +8,10 @@ #include #include -#include "highmap/profiling.hpp" #include "highmap/array.hpp" #include "highmap/internal/validation.hpp" #include "highmap/logger.hpp" +#include "highmap/profiling.hpp" #include "highmap/texture.hpp" #include "highmap/virtual_array/tile_storage.hpp" #include "highmap/virtual_array/virtual_array.hpp"