Introduce new logging API, fixes #858

PiperOrigin-RevId: 930744288
Change-Id: I6ec1203b55c031390f3eef23192e2337508ce886
This commit is contained in:
Yuval Tassa
2026-06-11 14:36:17 -07:00
committed by Copybara-Service
parent a2abaf7aef
commit 58f6d52491
45 changed files with 2586 additions and 422 deletions
+45 -1
View File
@@ -32,6 +32,7 @@
#include <mujoco/mujoco.h>
#include "engine/engine_support.h"
#include "engine/engine_util_errmem.h"
#include "user/user_cache.h"
#include "user/user_flexcomp.h"
#include "user/user_model.h"
@@ -204,10 +205,53 @@ int mj_encode(const mjSpec* s, const mjModel* m, const char* filename,
return nbytes;
}
// helper function to log compile time diagnostics
static void LogCompileTime(const double* t) {
std::string body(1024, '\0');
int n = std::snprintf(body.data(), body.size(),
" total: %8.1f (wall clock)\n"
" assets: %8.1f -\n"
" load: %8.1f (CPU time)\n"
" hull: %8.1f -\n"
" polygon: %8.1f -\n"
" inertia: %8.1f -\n"
" bvh: %8.1f -\n"
" octree: %8.1f -\n"
" texture: %8.1f -\n"
" other: %8.1f (wall clock)",
1e3 * t[mjCTIMER_TOTAL],
1e3 * t[mjCTIMER_ASSETS],
1e3 * t[mjCTIMER_MESH_LOAD],
1e3 * t[mjCTIMER_MESH_HULL],
1e3 * t[mjCTIMER_MESH_POLYGON],
1e3 * t[mjCTIMER_MESH_INERTIA],
1e3 * t[mjCTIMER_MESH_BVH],
1e3 * t[mjCTIMER_MESH_OCTREE],
1e3 * t[mjCTIMER_TEXTURE],
1e3 * (t[mjCTIMER_TOTAL] - t[mjCTIMER_ASSETS]));
if (n > 0 && n < body.size()) {
body.resize(n);
}
// send log message
mjLogMessage msg = {.level = mjLOG_INFO,
.topic = mjTOPIC_TIME_CMP,
.subject = "compile time (ms)",
.body = body.c_str()};
mju_message(&msg);
}
// compile model
mjModel* mj_compile(mjSpec* s, const mjVFS* vfs) {
mjCModel* modelC = static_cast<mjCModel*>(s->element);
return modelC->Compile(vfs);
mjModel* m = modelC->Compile(vfs);
// log compile time if model was compiled successfully
if (m) {
LogCompileTime(modelC->timer);
}
return m;
}
+20 -28
View File
@@ -4623,20 +4623,21 @@ void mjCModel::CheckRepeat(mjtObj type) {
constexpr int kErrorBufferSize = 500;
static thread_local std::jmp_buf error_jmp_buf;
static thread_local char errortext[kErrorBufferSize] = "";
static void errorhandler(const char* msg) {
mju::strcpy_arr(errortext, msg);
std::longjmp(error_jmp_buf, 1);
}
// warning handler for low-level engine
static thread_local char warningtext[kErrorBufferSize] = ""; // top-level warning buffer
static thread_local std::string* local_warningtext_ptr = nullptr; // sub-thread warning buffer
static void warninghandler(const char* msg) {
if (local_warningtext_ptr) {
*local_warningtext_ptr = msg;
} else {
mju::strcpy_arr(warningtext, msg);
static void compilerLogHandler(const mjLogMessage* msg) {
if (msg->level == mjLOG_ERROR) {
mju::strcpy_arr(errortext, msg->subject);
std::longjmp(error_jmp_buf, 1);
} else if (msg->level == mjLOG_WARNING) {
if (local_warningtext_ptr) {
*local_warningtext_ptr = msg->subject;
} else {
mju::strcpy_arr(warningtext, msg->subject);
}
}
}
@@ -4660,13 +4661,8 @@ mjModel* mjCModel::Compile(const mjVFS* vfs, mjModel** m) {
mjModel* volatile model = (m && *m) ? *m : nullptr;
mjData* volatile data = nullptr;
// save error and warning handlers
void (*save_error)(const char*) = _mjPRIVATE__get_tls_error_fn();
void (*save_warning)(const char*) = _mjPRIVATE__get_tls_warning_fn();
// install error and warning handlers, clear error and warning
_mjPRIVATE__set_tls_error_fn(errorhandler);
_mjPRIVATE__set_tls_warning_fn(warninghandler);
// save log handler
mjfLogHandler save_handler = _mjPRIVATE_setTlsLogHandler(compilerLogHandler);
errInfo = mjCError();
warningtext[0] = 0;
@@ -4705,14 +4701,12 @@ mjModel* mjCModel::Compile(const mjVFS* vfs, mjModel** m) {
}
// restore handler, return 0
_mjPRIVATE__set_tls_error_fn(save_error);
_mjPRIVATE__set_tls_warning_fn(save_warning);
_mjPRIVATE_setTlsLogHandler(save_handler);
return nullptr;
}
// restore error handler, mark as compiled, return mjModel
_mjPRIVATE__set_tls_error_fn(save_error);
_mjPRIVATE__set_tls_warning_fn(save_warning);
// restore log handler, mark as compiled, return mjModel
_mjPRIVATE_setTlsLogHandler(save_handler);
compiled = true;
return model;
}
@@ -4723,8 +4717,7 @@ static void CompileMesh(mjCMesh* mesh, const mjVFS* vfs,
std::exception_ptr& exception, std::mutex& exception_mutex,
std::string* warningtext) {
local_warningtext_ptr = warningtext;
auto previous_handler = _mjPRIVATE__get_tls_warning_fn();
_mjPRIVATE__set_tls_warning_fn(warninghandler);
auto previous_handler = _mjPRIVATE_setTlsLogHandler(compilerLogHandler);
try {
mesh->Compile(vfs);
@@ -4735,7 +4728,7 @@ static void CompileMesh(mjCMesh* mesh, const mjVFS* vfs,
}
}
_mjPRIVATE__set_tls_warning_fn(previous_handler);
_mjPRIVATE_setTlsLogHandler(previous_handler);
local_warningtext_ptr = nullptr;
}
@@ -4746,8 +4739,7 @@ static void CompileTexture(mjCTexture* texture, const mjVFS* vfs,
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);
auto previous_handler = _mjPRIVATE_setTlsLogHandler(compilerLogHandler);
Clock::time_point t0 = Clock::now();
try {
@@ -4760,7 +4752,7 @@ static void CompileTexture(mjCTexture* texture, const mjVFS* vfs,
}
texture->texture_time_ = Seconds(Clock::now() - t0).count();
_mjPRIVATE__set_tls_warning_fn(previous_handler);
_mjPRIVATE_setTlsLogHandler(previous_handler);
local_warningtext_ptr = nullptr;
}
@@ -4822,7 +4814,7 @@ void mjCModel::CompileMeshesAndTextures(const mjVFS* vfs) {
for (int i = 0; i < nmesh; i++) {
if (!mesh_warningtext[i].empty()) {
if (has_warning) {
concatenated_warnings += "\n";
concatenated_warnings += '\n';
}
concatenated_warnings += mesh_warningtext[i];
has_warning = true;