diff --git a/CMakeLists.txt b/CMakeLists.txt index d52d55134..5d0cc3932 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -82,6 +82,7 @@ option(IPC_TOOLKIT_WITH_ABSEIL "Use Abseil's hash functions" option(IPC_TOOLKIT_WITH_FILIB "Use filib for interval arithmetic" ON) option(IPC_TOOLKIT_WITH_INEXACT_CCD "Use the original inexact CCD method of IPC" OFF) option(IPC_TOOLKIT_WITH_PROFILER "Enable performance profiler" OFF) +option(IPC_TOOLKIT_WITH_TRACY "Enable Tracy frame profiler" OFF) # Advanced options option(IPC_TOOLKIT_WITH_CODE_COVERAGE "Enable coverage reporting" OFF) @@ -250,6 +251,12 @@ if(IPC_TOOLKIT_WITH_PROFILER) target_link_libraries(ipc_toolkit PUBLIC nlohmann_json::nlohmann_json) endif() +# Tracy profiler +if(IPC_TOOLKIT_WITH_TRACY) + include(tracy) + target_link_libraries(ipc_toolkit PUBLIC Tracy::TracyClient) +endif() + # Extra warnings (link last for highest priority) include(ipc_toolkit_warnings) target_link_libraries(ipc_toolkit PRIVATE ipc::toolkit::warnings) diff --git a/cmake/recipes/tracy.cmake b/cmake/recipes/tracy.cmake new file mode 100644 index 000000000..cd2697660 --- /dev/null +++ b/cmake/recipes/tracy.cmake @@ -0,0 +1,17 @@ +# Tracy (https://github.com/wolfpld/tracy) +# License: BSD-3-Clause +if(TARGET Tracy::TracyClient) + return() +endif() + +message(STATUS "Third-party: creating target 'Tracy::TracyClient'") + +include(CPM) +CPMAddPackage( + URI "gh:wolfpld/tracy@0.13.1" + OPTIONS + "TRACY_ENABLE ${IPC_TOOLKIT_WITH_TRACY}" + "TRACY_ON_DEMAND ON" +) + +set_target_properties(TracyClient PROPERTIES FOLDER "ThirdParty") \ No newline at end of file diff --git a/docs/source/_static/graphviz/dependencies.dot b/docs/source/_static/graphviz/dependencies.dot index a2ae83709..50643f46d 100644 --- a/docs/source/_static/graphviz/dependencies.dot +++ b/docs/source/_static/graphviz/dependencies.dot @@ -84,4 +84,7 @@ digraph "IPC Toolkit Dependencies" { // ipc_toolkit -> nlohmann_json "node14" [label = "nlohmann_json\n(nlohmann_json::nlohmann_json)";shape = box;style = "rounded,filled";fillcolor = "#FFE6CC";color = "#DAA52D";]; "node5" -> "node14" [color = "#8FB976";]; + // ipc_toolkit -> tracy + "node16" [label = "TracyClient\n(Tracy::TracyClient)";shape = box;style = "rounded,filled";fillcolor = "#D5E8D4";color = "#8FB976";]; + "node5" -> "node16" [color = "#8FB976";]; } \ No newline at end of file diff --git a/docs/source/_static/graphviz/dependencies.svg b/docs/source/_static/graphviz/dependencies.svg index 0802bd436..d502307ca 100644 --- a/docs/source/_static/graphviz/dependencies.svg +++ b/docs/source/_static/graphviz/dependencies.svg @@ -1,299 +1,312 @@ - - + IPC Toolkit Dependencies clusterLegend -Legend +Legend legendNode0 - -Static Library + +Static Library legendNode1 - -Shared Library + +Shared Library legendNode0->legendNode1 - - -Public + + +Public legendNode2 - -Interface Library + +Interface Library legendNode1->legendNode2 - - -Private + + +Private legendNode2->legendNode0 - - -Interface + + +Interface node5 - -ipc_toolkit -(ipc::toolkit) + +ipc_toolkit +(ipc::toolkit) node0 - -Eigen3_Eigen -(Eigen3::Eigen) + +Eigen3_Eigen +(Eigen3::Eigen) node5->node0 - - + + node1 - -filib -(filib::filib) + +filib +(filib::filib) node5->node1 - - + + node2 - -igl_core -(igl::core) + +igl_core +(igl::core) node5->node2 - - + + node3 - -igl_predicates -(igl::predicates) + +igl_predicates +(igl::predicates) node5->node3 - - + + node15 - -xsimd -(xsimd::xsimd) + +xsimd +(xsimd::xsimd) node5->node15 - - + + node6 - -robin_map -(tsl::robin_map) + +robin_map +(tsl::robin_map) node5->node6 - - + + node7 - -scalable_ccd -(scalable_ccd::scalable_ccd) + +scalable_ccd +(scalable_ccd::scalable_ccd) node5->node7 - - + + node8 - -spdlog -(spdlog::spdlog) + +spdlog +(spdlog::spdlog) node5->node8 - - + + node9 - -tbb -(TBB::tbb) + +tbb +(TBB::tbb) node5->node9 - - + + node11 - -tight_inclusion -(tight_inclusion::tight_inclusion) + +tight_inclusion +(tight_inclusion::tight_inclusion) node5->node11 - - + + node12 - -absl_hash -(absl::hash) + +absl_hash +(absl::hash) node5->node12 - - + + node13 - -TinyAD -(TinyAD::TinyAD) + +TinyAD +(TinyAD::TinyAD) node5->node13 - - + + node14 - -nlohmann_json -(nlohmann_json::nlohmann_json) + +nlohmann_json +(nlohmann_json::nlohmann_json) node5->node14 - - + + + + + +node16 + +TracyClient +(Tracy::TracyClient) + + + +node5->node16 + + node2->node0 - - + + node3->node2 - - + + node4 - -predicates -(predicates::predicates) + +predicates +(predicates::predicates) node3->node4 - - + + node7->node0 - - + + node7->node8 - - + + node7->node9 - - + + node11->node0 - - + + node11->node8 - - + + node13->node0 - - + + node13->node9 - - + + diff --git a/docs/source/about/dependencies.rst b/docs/source/about/dependencies.rst index dce384b85..5ca6d6760 100644 --- a/docs/source/about/dependencies.rst +++ b/docs/source/about/dependencies.rst @@ -93,6 +93,12 @@ Additionally, IPC Toolkit may optionally use the following libraries: - `github.com/nlohmann/json `_ - |:white_large_square:| - ``IPC_TOOLKIT_WITH_PROFILER`` + * - Tracy + - Frame profiler + - BSD-3-Clause + - `github.com/wolfpld/tracy `_ + - |:white_large_square:| + - ``IPC_TOOLKIT_WITH_TRACY`` * - rational-cpp - Rational arithmetic used for exact intersection checks (requires `GMP `_ to be installed at a system level) - MIT diff --git a/src/ipc/config.hpp.in b/src/ipc/config.hpp.in index 2cfdba279..3c5c84e75 100644 --- a/src/ipc/config.hpp.in +++ b/src/ipc/config.hpp.in @@ -20,6 +20,7 @@ #cmakedefine IPC_TOOLKIT_WITH_ABSEIL #cmakedefine IPC_TOOLKIT_WITH_FILIB #cmakedefine IPC_TOOLKIT_WITH_PROFILER +#cmakedefine IPC_TOOLKIT_WITH_TRACY // #define IPC_TOOLKIT_DEBUG_AUTODIFF namespace ipc { diff --git a/src/ipc/potentials/potential.cpp b/src/ipc/potentials/potential.cpp index 839ae594c..d4c08feae 100644 --- a/src/ipc/potentials/potential.cpp +++ b/src/ipc/potentials/potential.cpp @@ -40,7 +40,7 @@ double Potential::operator()( Eigen::ConstRef X) const { assert(X.rows() == mesh.num_vertices()); - IPC_TOOLKIT_PROFILE_BLOCK(this->name() + "::operator()"); + IPC_TOOLKIT_PROFILE_BLOCK("Potential::operator()"); return tbb::parallel_reduce( tbb::blocked_range(size_t(0), collisions.size()), 0.0, @@ -63,7 +63,7 @@ Eigen::VectorXd Potential::gradient( Eigen::ConstRef X) const { assert(X.rows() == mesh.num_vertices()); - IPC_TOOLKIT_PROFILE_BLOCK(this->name() + "::gradient()"); + IPC_TOOLKIT_PROFILE_BLOCK("Potential::gradient()"); if (collisions.empty()) { return Eigen::VectorXd::Zero(X.size()); @@ -74,7 +74,7 @@ Eigen::VectorXd Potential::gradient( tbb::combinable grad(Eigen::VectorXd::Zero(X.size())); { - IPC_TOOLKIT_PROFILE_BLOCK("compute local gradients"); + IPC_TOOLKIT_PROFILE_BLOCK("Compute Local Gradients"); tbb::parallel_for(size_t(0), collisions.size(), [&](size_t i) { const TCollision& collision = collisions[i]; @@ -88,7 +88,7 @@ Eigen::VectorXd Potential::gradient( } { - IPC_TOOLKIT_PROFILE_BLOCK("combine local gradients"); + IPC_TOOLKIT_PROFILE_BLOCK("Combine Local Gradients"); return grad.combine([](const Eigen::VectorXd& a, const Eigen::VectorXd& b) { return a + b; }); } @@ -102,7 +102,7 @@ Eigen::SparseMatrix Potential::hessian( const PSDProjectionMethod project_hessian_to_psd) const { assert(X.rows() == mesh.num_vertices()); - IPC_TOOLKIT_PROFILE_BLOCK(this->name() + "::hessian()"); + IPC_TOOLKIT_PROFILE_BLOCK("Potential::hessian()"); if (collisions.empty()) { return Eigen::SparseMatrix(X.size(), X.size()); @@ -129,7 +129,7 @@ Eigen::SparseMatrix Potential::hessian( MatrixMaxNd local_hess; { - IPC_TOOLKIT_PROFILE_BLOCK("compute local hessian"); + IPC_TOOLKIT_PROFILE_BLOCK("Compute Local Hessian"); local_hess = this->hessian( collision, collision.dof(X, edges, faces), project_hessian_to_psd); @@ -137,7 +137,7 @@ Eigen::SparseMatrix Potential::hessian( { IPC_TOOLKIT_PROFILE_BLOCK( - "map local hessian to global triplets"); + "Map Local Hessian to Global Triplets"); local_hessian_to_global_triplets( local_hess, collision.vertex_ids(edges, faces), dim, *(hess_triplets.cache), mesh.num_vertices()); @@ -152,7 +152,7 @@ Eigen::SparseMatrix Potential::hessian( // storage { - IPC_TOOLKIT_PROFILE_BLOCK("prune local storages"); + IPC_TOOLKIT_PROFILE_BLOCK("Prune Local Storages"); tbb::parallel_for_each( storage.begin(), storage.end(), [](const auto& local_storage) { local_storage.cache->prune(); }); @@ -188,13 +188,13 @@ Eigen::SparseMatrix Potential::hessian( // Allocate triplets { - IPC_TOOLKIT_PROFILE_BLOCK("allocate triplets"); + IPC_TOOLKIT_PROFILE_BLOCK("Allocate Triplets"); triplets.resize(triplet_count); } // Parallel copy into triplets { - IPC_TOOLKIT_PROFILE_BLOCK("parallel copy into triplets"); + IPC_TOOLKIT_PROFILE_BLOCK("Parallel Copy into Triplets"); tbb::parallel_for(size_t(0), storage.size(), [&](size_t i) { const SparseMatrixCache& cache = dynamic_cast( @@ -214,7 +214,7 @@ Eigen::SparseMatrix Potential::hessian( // Sort and assemble { - IPC_TOOLKIT_PROFILE_BLOCK("assemble hessian from triplets"); + IPC_TOOLKIT_PROFILE_BLOCK("Assemble Hessian from Triplets"); hess.setFromTriplets(triplets.begin(), triplets.end()); } diff --git a/src/ipc/utils/profiler.hpp b/src/ipc/utils/profiler.hpp index 766fd2097..de955ad1b 100644 --- a/src/ipc/utils/profiler.hpp +++ b/src/ipc/utils/profiler.hpp @@ -2,6 +2,15 @@ #include +#ifdef IPC_TOOLKIT_WITH_TRACY +#include +#else +// Empty macro to avoid compilation errors when Tracy is not enabled. +#define ZoneScopedN(name) ((void)0) +#endif + +#include + #ifdef IPC_TOOLKIT_WITH_PROFILER // clang-format off @@ -22,7 +31,8 @@ #define IPC_TOOLKIT_PROFILE_BLOCK(...) \ ipc::ProfilePoint IPC_TOOLKIT_PROFILE_BLOCK_CONCAT( \ - __ipc_profile_point_, __COUNTER__)(__VA_ARGS__) + __ipc_profile_point_, __COUNTER__)(__VA_ARGS__); \ + ZoneScopedN(__VA_ARGS__) namespace ipc { @@ -132,6 +142,7 @@ template class ProfilePoint { #else -#define IPC_TOOLKIT_PROFILE_BLOCK(...) +// Custom profiler disabled: Tracy zone only. +#define IPC_TOOLKIT_PROFILE_BLOCK(...) ZoneScopedN(__VA_ARGS__) #endif \ No newline at end of file