Add compiler timing diagnostics to mjsCompiler, printed by compile.cc

For example, `compile mujoco_menagerie/robotis_op3/scene.xml` now outputs

```
Compile 1 (cold cache):
  total:      317.2 ms
  assets:     284.8 ms (wall clock)
    load:     616.1 ms
    hull:      26.4 ms
    poly:     137.8 ms
    inert:    177.8 ms
    bvh:      568.2 ms
    octr:       1.6 ms
    tex:       25.3 ms
  other:       32.4 ms

Compile 2 (warm cache):
  total:       79.9 ms
  assets:      54.5 ms (wall clock)
    load:     888.5 ms
    hull:       0.0 ms
    poly:       0.0 ms
    inert:      0.0 ms
    bvh:        0.0 ms
    octr:       0.0 ms
    tex:       21.4 ms
  other:       25.3 ms
```

PiperOrigin-RevId: 917850214
Change-Id: Iaec86230bec0faf2e47820e20cbff61de5b2621e
This commit is contained in:
Yuval Tassa
2026-05-19 08:27:35 -07:00
committed by Copybara-Service
parent f712eed4ce
commit bdf00966f9
23 changed files with 309 additions and 43 deletions
+30 -6
View File
@@ -16,7 +16,7 @@
#include <algorithm>
#include <array>
#include <atomic>
#include <chrono>
#include <cmath>
#include <csetjmp>
#include <cstdint>
@@ -662,7 +662,6 @@ mjCModel& mjCModel::operator+=(mjCDef& subtree) {
// remove default class from array
mjCModel& mjCModel::operator-=(const mjCDef& subtree) {
// check we aren't trying to remove the 'main' default
if (subtree.id == 0) {
throw mjCError(0, "cannot remove the global default ('main')");
@@ -922,7 +921,7 @@ void mjCModel::ComputeSparseSizes() {
// 1. build dof_parentid, dof_bodyid
if (nbody > 0) {
body_lastdof_map[0] = -1; // world has no parent dof
body_lastdof_map[0] = -1; // world has no parent dof
}
for (int i = 0; i < nbody; ++i) {
mjCBody* pb = bodies_[i];
@@ -961,7 +960,7 @@ void mjCModel::ComputeSparseSizes() {
nD = 2 * nM - nv;
// 4. compute subtreedofs and nB
for(int i = nbody - 1; i >= 0; --i) {
for (int i = nbody - 1; i >= 0; --i) {
bodies_[i]->subtreedofs = bodies_[i]->dofnum;
for (const auto* child : bodies_[i]->Bodies()) {
bodies_[i]->subtreedofs += child->subtreedofs;
@@ -984,7 +983,7 @@ void mjCModel::ComputeSparseSizes() {
}
// 5. compute nC
for(int i = 0; i < nbody; ++i) {
for (int i = 0; i < nbody; ++i) {
mjCBody* pb = bodies_[i];
mjCBody* par = pb->parent;
int parentid = par ? par->id : 0;
@@ -4744,10 +4743,13 @@ static void CompileMesh(mjCMesh* mesh, const mjVFS* vfs,
static void CompileTexture(mjCTexture* texture, const mjVFS* vfs,
std::exception_ptr& exception,
std::mutex& exception_mutex, std::string* warningtext) {
using Clock = std::chrono::steady_clock;
using Seconds = std::chrono::duration<double>;
local_warningtext_ptr = warningtext;
auto previous_handler = _mjPRIVATE__get_tls_warning_fn();
_mjPRIVATE__set_tls_warning_fn(warninghandler);
Clock::time_point t0 = Clock::now();
try {
texture->Compile(vfs);
} catch (...) {
@@ -4756,6 +4758,7 @@ static void CompileTexture(mjCTexture* texture, const mjVFS* vfs,
exception = std::current_exception();
}
}
texture->texture_time_ = Seconds(Clock::now() - t0).count();
_mjPRIVATE__set_tls_warning_fn(previous_handler);
local_warningtext_ptr = nullptr;
@@ -4843,6 +4846,15 @@ void mjCModel::CompileMeshesAndTextures(const mjVFS* vfs) {
if (texture_exception) {
std::rethrow_exception(texture_exception);
}
for (int i = 0; i < nmesh; i++) {
for (int t = 0; t < mjNCTIMER; t++) {
timer[t] += meshes_[i]->mesh_timer_[t];
}
}
for (int i = 0; i < ntexture; i++) {
timer[mjCTIMER_TEXTURE] += textures_[i]->texture_time_;
}
}
// compute qpos0
@@ -4984,6 +4996,12 @@ void mjCModel::TryCompile(mjModel*& m, mjData*& d, const mjVFS* vfs) {
} disable_usethread(compiler.usethread);
#endif
using Clock = std::chrono::steady_clock;
using Seconds = std::chrono::duration<double>;
for (int i=0; i < mjNCTIMER; i++) {
timer[i] = 0;
}
Clock::time_point timer_start = Clock::now();
// check if nan test works
double test = mjNAN;
if (mjuu_defined(test)) {
@@ -5085,7 +5103,11 @@ void mjCModel::TryCompile(mjModel*& m, mjData*& d, const mjVFS* vfs) {
SetNuser();
// compile meshes and textures (needed for geom compilation)
CompileMeshesAndTextures(vfs);
{
Clock::time_point t0 = Clock::now();
CompileMeshesAndTextures(vfs);
timer[mjCTIMER_ASSETS] = Seconds(Clock::now() - t0).count();
}
// compile objects in kinematic tree
for (int i=0; i < bodies_.size(); i++) {
@@ -5359,6 +5381,8 @@ void mjCModel::TryCompile(mjModel*& m, mjData*& d, const mjVFS* vfs) {
// save signature
m->signature = Signature();
timer[mjCTIMER_TOTAL] = Seconds(Clock::now() - timer_start).count();
// special cases that are not caused by user edits
if (compiler.fusestatic || compiler.discardvisual ||
!pairs_.empty() || !excludes_.empty()) {