diff --git a/.github/workflows/ci_windows.yml b/.github/workflows/ci_windows.yml index 3bf59e9443d1c..ba229e9725c38 100644 --- a/.github/workflows/ci_windows.yml +++ b/.github/workflows/ci_windows.yml @@ -38,7 +38,22 @@ jobs: - uses: johnwason/vcpkg-action@v6 with: # TODO: Add ode and coin-or-ipopt - pkgs: assimp eigen3 fcl fmt spdlog bullet3 freeglut glfw3 nlopt opengl osg pagmo2 tinyxml2 urdfdom + pkgs: > + assimp + eigen3 + fcl + fmt + spdlog + bullet3 + freeglut + glfw3 + nlopt + opengl + osg + pagmo2 + tinyxml2 + tracy + urdfdom triplet: x64-windows revision: "2024.02.14" github-binarycache: true diff --git a/.github/workflows/publish_dartpy.yml b/.github/workflows/publish_dartpy.yml index ccf2b44e58396..2dec358a14891 100644 --- a/.github/workflows/publish_dartpy.yml +++ b/.github/workflows/publish_dartpy.yml @@ -99,7 +99,25 @@ jobs: if: ${{ matrix.os == 'windows-latest' && (matrix.release_only == false || github.ref == 'refs/heads/main') }} uses: johnwason/vcpkg-action@v6 with: - pkgs: assimp ccd eigen3 fcl fmt spdlog bullet3 coin-or-ipopt freeglut glfw3 imgui nlopt ode opengl osg pagmo2 tinyxml2 urdfdom + pkgs: > + assimp + ccd + eigen3 + fcl + fmt + spdlog + bullet3 + coin-or-ipopt + freeglut + glfw3 + imgui + nlopt + ode + opengl + osg + pagmo2 + tinyxml2 + urdfdom triplet: x64-windows revision: "2024.02.14" github-binarycache: true diff --git a/Brewfile b/Brewfile index 5591ae2c34e09..83201c5ab8aae 100644 --- a/Brewfile +++ b/Brewfile @@ -1,6 +1,7 @@ # Build dependencies brew 'cmake' brew 'pkg-config' +brew 'tracy' brew 'assimp' brew 'bullet' diff --git a/CMakeLists.txt b/CMakeLists.txt index 867eaf80863ea..fb6d870f38cd0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -88,6 +88,7 @@ dart_option(DART_ENABLE_SIMD "Build DART with all SIMD instructions on the current local machine" OFF) dart_option(DART_BUILD_GUI_OSG "Build osgDart library" ON) dart_option(DART_BUILD_DARTPY "Build dartpy" ON) +dart_option(DART_BUILD_PROFILE "Build DART with profiling options" OFF) dart_option(DART_CODECOV "Turn on codecov support" OFF) dart_option(DART_FAST_DEBUG "Add -O1 option for DEBUG mode build" OFF) # GCC and Clang add ANSI-formatted colors when they detect the output medium is a diff --git a/cmake/DARTFindDependencies.cmake b/cmake/DARTFindDependencies.cmake index a763ce18b0354..33af2bb1d0aed 100644 --- a/cmake/DARTFindDependencies.cmake +++ b/cmake/DARTFindDependencies.cmake @@ -110,6 +110,22 @@ endif() # Optional dependencies #======================= +if(DART_BUILD_PROFILE) + include(FetchContent) + FetchContent_Declare(tracy + GIT_REPOSITORY https://github.com/wolfpld/tracy.git + GIT_TAG v0.10 + GIT_SHALLOW TRUE + GIT_PROGRESS TRUE + ) + FetchContent_MakeAvailable(tracy) + if(MSVC) + target_compile_options(external_lib_target PRIVATE /W0) + else() + target_compile_options(TracyClient PRIVATE -w) + endif() +endif() + find_package(Python3 COMPONENTS Interpreter Development) option(DART_SKIP_spdlog "If ON, do not use spdlog even if it is found." OFF) diff --git a/dart/CMakeLists.txt b/dart/CMakeLists.txt index a67a03ce653cd..3c547e94389f2 100644 --- a/dart/CMakeLists.txt +++ b/dart/CMakeLists.txt @@ -234,6 +234,10 @@ if(DART_CODECOV) target_link_libraries(dart PUBLIC coverage_config) endif() +if(DART_BUILD_PROFILE) + target_link_libraries(dart PUBLIC TracyClient) +endif() + install(FILES dart.hpp DESTINATION include/dart/ COMPONENT headers) dart_format_add(${dart_core_headers} ${dart_core_sources}) diff --git a/dart/common/Profile.hpp b/dart/common/Profile.hpp new file mode 100644 index 0000000000000..6fffbc9672b63 --- /dev/null +++ b/dart/common/Profile.hpp @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2011-2024, The DART development contributors + * All rights reserved. + * + * The list of contributors can be found at: + * https://github.com/dartsim/dart/blob/main/LICENSE + * + * This file is provided under the following "BSD-style" License: + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. + */ + +#pragma once + +#include + +#if DART_BUILD_PROFILE + #include +#endif + +#if DART_BUILD_PROFILE + + #define DART_PROFILE_FRAME FrameMark + #define DART_PROFILE_SCOPED ZoneScoped + #define DART_PROFILE_SCOPED_N(name) ZoneScopedN(name) + +#else // no-op + + #define DART_PROFILE_FRAME + #define DART_PROFILE_SCOPED + #define DART_PROFILE_SCOPED_N(name) + +#endif + +namespace dart::common { + +// + +} // namespace dart::common diff --git a/dart/config.hpp.in b/dart/config.hpp.in index 6aaed81ca6b16..7ee2997fd7a80 100644 --- a/dart/config.hpp.in +++ b/dart/config.hpp.in @@ -96,3 +96,5 @@ #cmakedefine BT_USE_DOUBLE_PRECISION #cmakedefine01 DART_USE_SYSTEM_IMGUI + +#cmakedefine01 DART_BUILD_PROFILE diff --git a/dart/constraint/BoxedLcpConstraintSolver.cpp b/dart/constraint/BoxedLcpConstraintSolver.cpp index d9049e5fe2ea6..9939aaa22a479 100644 --- a/dart/constraint/BoxedLcpConstraintSolver.cpp +++ b/dart/constraint/BoxedLcpConstraintSolver.cpp @@ -39,6 +39,7 @@ #endif #include "dart/common/Console.hpp" +#include "dart/common/Profile.hpp" #include "dart/constraint/ConstraintBase.hpp" #include "dart/constraint/DantzigBoxedLcpSolver.hpp" #include "dart/constraint/PgsBoxedLcpSolver.hpp" @@ -140,6 +141,8 @@ ConstBoxedLcpSolverPtr BoxedLcpConstraintSolver::getSecondaryBoxedLcpSolver() //============================================================================== void BoxedLcpConstraintSolver::solveConstrainedGroup(ConstrainedGroup& group) { + DART_PROFILE_SCOPED; + // Build LCP terms by aggregating them from constraints const std::size_t numConstraints = group.getNumConstraints(); const std::size_t n = group.getTotalDimension(); @@ -171,54 +174,60 @@ void BoxedLcpConstraintSolver::solveConstrainedGroup(ConstrainedGroup& group) } // For each constraint - ConstraintInfo constInfo; - constInfo.invTimeStep = 1.0 / mTimeStep; - for (std::size_t i = 0; i < numConstraints; ++i) { - const ConstraintBasePtr& constraint = group.getConstraint(i); - - constInfo.x = mX.data() + mOffset[i]; - constInfo.lo = mLo.data() + mOffset[i]; - constInfo.hi = mHi.data() + mOffset[i]; - constInfo.b = mB.data() + mOffset[i]; - constInfo.findex = mFIndex.data() + mOffset[i]; - constInfo.w = mW.data() + mOffset[i]; - - // Fill vectors: lo, hi, b, w - constraint->getInformation(&constInfo); - - // Fill a matrix by impulse tests: A - constraint->excite(); - for (std::size_t j = 0; j < constraint->getDimension(); ++j) { - // Adjust findex for global index - if (mFIndex[mOffset[i] + j] >= 0) - mFIndex[mOffset[i] + j] += mOffset[i]; - - // Apply impulse for mipulse test - constraint->applyUnitImpulse(j); - - // Fill upper triangle blocks of A matrix - int index = nSkip * (mOffset[i] + j) + mOffset[i]; - constraint->getVelocityChange(mA.data() + index, true); - for (std::size_t k = i + 1; k < numConstraints; ++k) { - index = nSkip * (mOffset[i] + j) + mOffset[k]; - group.getConstraint(k)->getVelocityChange(mA.data() + index, false); - } + { + DART_PROFILE_SCOPED_N("Construct LCP"); + ConstraintInfo constInfo; + constInfo.invTimeStep = 1.0 / mTimeStep; + for (std::size_t i = 0; i < numConstraints; ++i) { + const ConstraintBasePtr& constraint = group.getConstraint(i); + + constInfo.x = mX.data() + mOffset[i]; + constInfo.lo = mLo.data() + mOffset[i]; + constInfo.hi = mHi.data() + mOffset[i]; + constInfo.b = mB.data() + mOffset[i]; + constInfo.findex = mFIndex.data() + mOffset[i]; + constInfo.w = mW.data() + mOffset[i]; + + // Fill vectors: lo, hi, b, w + constraint->getInformation(&constInfo); + + // Fill a matrix by impulse tests: A + constraint->excite(); + for (std::size_t j = 0; j < constraint->getDimension(); ++j) { + // Adjust findex for global index + if (mFIndex[mOffset[i] + j] >= 0) + mFIndex[mOffset[i] + j] += mOffset[i]; + + // Apply impulse for mipulse test + constraint->applyUnitImpulse(j); + + // Fill upper triangle blocks of A matrix + int index = nSkip * (mOffset[i] + j) + mOffset[i]; + constraint->getVelocityChange(mA.data() + index, true); + for (std::size_t k = i + 1; k < numConstraints; ++k) { + index = nSkip * (mOffset[i] + j) + mOffset[k]; + group.getConstraint(k)->getVelocityChange(mA.data() + index, false); + } - // Filling symmetric part of A matrix - for (std::size_t k = 0; k < i; ++k) { - const int indexI = mOffset[i] + j; - for (std::size_t l = 0; l < group.getConstraint(k)->getDimension(); - ++l) { - const int indexJ = mOffset[k] + l; - mA(indexI, indexJ) = mA(indexJ, indexI); + // Filling symmetric part of A matrix + for (std::size_t k = 0; k < i; ++k) { + const int indexI = mOffset[i] + j; + for (std::size_t l = 0; l < group.getConstraint(k)->getDimension(); + ++l) { + const int indexJ = mOffset[k] + l; + mA(indexI, indexJ) = mA(indexJ, indexI); + } } } - } - assert(isSymmetric( - n, mA.data(), mOffset[i], mOffset[i] + constraint->getDimension() - 1)); + assert(isSymmetric( + n, + mA.data(), + mOffset[i], + mOffset[i] + constraint->getDimension() - 1)); - constraint->unexcite(); + constraint->unexcite(); + } } assert(isSymmetric(n, mA.data())); @@ -259,6 +268,7 @@ void BoxedLcpConstraintSolver::solveConstrainedGroup(ConstrainedGroup& group) success = false; if (!success && mSecondaryBoxedLcpSolver) { + DART_PROFILE_SCOPED_N("Secondary LCP"); mSecondaryBoxedLcpSolver->solve( n, mABackup.data(), @@ -287,10 +297,13 @@ void BoxedLcpConstraintSolver::solveConstrainedGroup(ConstrainedGroup& group) // std::cout << std::endl; // Apply constraint impulses - for (std::size_t i = 0; i < numConstraints; ++i) { - const ConstraintBasePtr& constraint = group.getConstraint(i); - constraint->applyImpulse(mX.data() + mOffset[i]); - constraint->excite(); + { + DART_PROFILE_SCOPED_N("Apply constraint impulses"); + for (std::size_t i = 0; i < numConstraints; ++i) { + const ConstraintBasePtr& constraint = group.getConstraint(i); + constraint->applyImpulse(mX.data() + mOffset[i]); + constraint->excite(); + } } } diff --git a/dart/constraint/ConstraintSolver.cpp b/dart/constraint/ConstraintSolver.cpp index 58d3d4c130e1b..488b8060bfc23 100644 --- a/dart/constraint/ConstraintSolver.cpp +++ b/dart/constraint/ConstraintSolver.cpp @@ -40,6 +40,7 @@ #include "dart/collision/fcl/FCLCollisionDetector.hpp" #include "dart/common/Console.hpp" #include "dart/common/Macros.hpp" +#include "dart/common/Profile.hpp" #include "dart/constraint/ConstrainedGroup.hpp" #include "dart/constraint/ContactConstraint.hpp" #include "dart/constraint/ContactSurface.hpp" @@ -361,6 +362,8 @@ LCPSolver* ConstraintSolver::getLCPSolver() const //============================================================================== void ConstraintSolver::solve() { + DART_PROFILE_SCOPED_N("ConstraintSolver::solve"); + for (auto& skeleton : mSkeletons) { skeleton->clearConstraintImpulses(); DART_SUPPRESS_DEPRECATED_BEGIN @@ -454,6 +457,8 @@ bool ConstraintSolver::checkAndAddConstraint( //============================================================================== void ConstraintSolver::updateConstraints() { + DART_PROFILE_SCOPED; + // Clear previous active constraint list mActiveConstraints.clear(); @@ -635,6 +640,8 @@ void ConstraintSolver::updateConstraints() //============================================================================== void ConstraintSolver::buildConstrainedGroups() { + DART_PROFILE_SCOPED; + // Clear constrained groups mConstrainedGroups.clear(); @@ -687,8 +694,12 @@ void ConstraintSolver::buildConstrainedGroups() //============================================================================== void ConstraintSolver::solveConstrainedGroups() { - for (auto& constraintGroup : mConstrainedGroups) + DART_PROFILE_SCOPED; + + for (auto& constraintGroup : mConstrainedGroups) { + DART_PROFILE_SCOPED; solveConstrainedGroup(constraintGroup); + } } //============================================================================== diff --git a/dart/constraint/DantzigBoxedLcpSolver.cpp b/dart/constraint/DantzigBoxedLcpSolver.cpp index ed9214998d068..635a671182d50 100644 --- a/dart/constraint/DantzigBoxedLcpSolver.cpp +++ b/dart/constraint/DantzigBoxedLcpSolver.cpp @@ -32,6 +32,7 @@ #include "dart/constraint/DantzigBoxedLcpSolver.hpp" +#include "dart/common/Profile.hpp" #include "dart/external/odelcpsolver/lcp.h" namespace dart { @@ -62,6 +63,7 @@ bool DantzigBoxedLcpSolver::solve( int* findex, bool earlyTermination) { + DART_PROFILE_SCOPED; return external::ode::dSolveLCP( n, A, x, b, nullptr, 0, lo, hi, findex, earlyTermination); } diff --git a/dart/constraint/PGSLCPSolver.cpp b/dart/constraint/PGSLCPSolver.cpp index f3844364988c4..58a5ff377eae3 100644 --- a/dart/constraint/PGSLCPSolver.cpp +++ b/dart/constraint/PGSLCPSolver.cpp @@ -38,6 +38,7 @@ #endif #include "dart/common/Console.hpp" +#include "dart/common/Profile.hpp" #include "dart/constraint/ConstrainedGroup.hpp" #include "dart/constraint/ConstraintBase.hpp" #include "dart/external/odelcpsolver/lcp.h" @@ -55,6 +56,7 @@ PGSLCPSolver::~PGSLCPSolver() {} //============================================================================== void PGSLCPSolver::solve(ConstrainedGroup* _group) { + DART_PROFILE_SCOPED; // If there is no constraint, then just return true. std::size_t numConstraints = _group->getNumConstraints(); if (numConstraints == 0) diff --git a/dart/simulation/World.cpp b/dart/simulation/World.cpp index 838372aaedbf5..4a68d849eb73d 100644 --- a/dart/simulation/World.cpp +++ b/dart/simulation/World.cpp @@ -40,6 +40,7 @@ #include "dart/collision/CollisionGroup.hpp" #include "dart/common/Console.hpp" +#include "dart/common/Profile.hpp" #include "dart/constraint/BoxedLcpConstraintSolver.hpp" #include "dart/constraint/ConstrainedGroup.hpp" #include "dart/dynamics/Skeleton.hpp" @@ -163,16 +164,22 @@ void World::reset() void World::step(bool _resetCommand) { // Integrate velocity for unconstrained skeletons - for (auto& skel : mSkeletons) { - if (!skel->isMobile()) - continue; - - skel->computeForwardDynamics(); - skel->integrateVelocities(mTimeStep); + { + DART_PROFILE_SCOPED_N("World::step - Integrate velocity"); + for (auto& skel : mSkeletons) { + if (!skel->isMobile()) + continue; + + skel->computeForwardDynamics(); + skel->integrateVelocities(mTimeStep); + } } // Detect activated constraints and compute constraint impulses - mConstraintSolver->solve(); + { + DART_PROFILE_SCOPED_N("World::step - Solve constraints"); + mConstraintSolver->solve(); + } // Compute velocity changes given constraint impulses for (auto& skel : mSkeletons) { @@ -195,6 +202,7 @@ void World::step(bool _resetCommand) mTime += mTimeStep; mFrame++; + DART_PROFILE_FRAME; } //============================================================================== diff --git a/docker/dev/v6.14/Dockerfile.tracy b/docker/dev/v6.14/Dockerfile.tracy new file mode 100644 index 0000000000000..73c1188262734 --- /dev/null +++ b/docker/dev/v6.14/Dockerfile.tracy @@ -0,0 +1,34 @@ +# Use an Ubuntu base image +FROM ubuntu:22.04 + +# Avoid warnings by switching to noninteractive +ENV DEBIAN_FRONTEND=noninteractive + +# Install build dependencies, X11 libraries, CA certificates, and Wayland protocols +RUN apt-get update && apt-get install -y \ + build-essential \ + cmake \ + git \ + libx11-dev \ + libgl1-mesa-dev \ + libgtk-3-dev \ + xorg-dev \ + ca-certificates \ + wayland-protocols \ + --no-install-recommends \ + && rm -rf /var/lib/apt/lists/* + +# Clone the Tracy Profiler repository +RUN git clone --depth 1 https://github.com/wolfpld/tracy.git + +# Build Tracy Profiler +WORKDIR /tracy/profiler/build/unix +RUN cmake ../.. && make + +# Use the `entrypoint.sh` to start the profiler +COPY entrypoint.sh /entrypoint.sh +RUN chmod +x /entrypoint.sh +ENTRYPOINT ["/entrypoint.sh"] + +# Reset the frontend to its default value +ENV DEBIAN_FRONTEND= \ No newline at end of file diff --git a/docker/dev/v6.14/Dockerfile.tracy.archlinux b/docker/dev/v6.14/Dockerfile.tracy.archlinux new file mode 100644 index 0000000000000..ddfc08491cc8d --- /dev/null +++ b/docker/dev/v6.14/Dockerfile.tracy.archlinux @@ -0,0 +1,33 @@ +# Use an Arch Linux base image +FROM archlinux:latest + +# Initialize the keyring, populate the Arch Linux keyring, and update the system +RUN pacman-key --init \ + && pacman-key --populate archlinux \ + && pacman -Sy archlinux-keyring --noconfirm \ + && pacman -Su --noconfirm + +# Install build dependencies +RUN pacman -S --noconfirm base-devel \ + cmake \ + git \ + freetype2 \ + tbb \ + debuginfod \ + wayland \ + dbus \ + libxkbcommon \ + libglvnd \ + meson \ + wayland-protocols \ + --needed \ + && pacman -Scc --noconfirm + +# Clone the Tracy Profiler repository +RUN git clone --depth 1 https://github.com/wolfpld/tracy.git -b master + +# Build Tracy Profiler GUI +WORKDIR /tracy/profiler/build +RUN cmake -S ../ -B . && cmake --build . --config Release --parallel + +ENTRYPOINT [ "/tracy/profiler/build/tracy-profiler" ] diff --git a/docker/dev/v6.14/entrypoint.sh b/docker/dev/v6.14/entrypoint.sh new file mode 100755 index 0000000000000..9e8f29e33f93a --- /dev/null +++ b/docker/dev/v6.14/entrypoint.sh @@ -0,0 +1,8 @@ +#!/bin/bash +# entrypoint.sh + +# Use the host's display server for the GUI +export DISPLAY=host.docker.internal:0 + +# Start Tracy Profiler +./tracy/profiler/build/unix/Tracy-release diff --git a/examples/speed_test/CMakeLists.txt b/examples/speed_test/CMakeLists.txt index e912116a765b7..7d117e0fec73e 100644 --- a/examples/speed_test/CMakeLists.txt +++ b/examples/speed_test/CMakeLists.txt @@ -4,8 +4,8 @@ get_filename_component(example_name ${CMAKE_CURRENT_LIST_DIR} NAME) project(${example_name}) -set(required_components utils-urdf gui) -set(required_libraries dart dart-utils-urdf dart-gui) +set(required_components utils-urdf) +set(required_libraries dart dart-utils-urdf) if(DART_IN_SOURCE_BUILD) dart_build_example_in_source(${example_name} LINK_LIBRARIES ${required_libraries})