Threaded Visualization

Discussion in 'Visualization' started by Vassilios Tsounis, Dec 7, 2017.

  1. Hi,

    I am working on a implementing a C++ interface to MuJoCo that consists of two threads: a) the first will actually run the model cyclically, e.g. at at 1kHz (ideally at 2kHz), and will provide buffered interfaces for commands and state data, while b) the second thread manages the visualization (using simulation.cpp as an example) and samples from the data generated by the first thread at 60Hz.

    I profiled the duration of mj_copyData() (for the humanoid.xml) and it was around 1ms in my workstation laptop (Thinkpad P50), which is considerable. I also measured using a monotonic clock in linux that without using mjData copies, mjv_updateScene() for the humanoid.xml takes anywhere in the range of 35 μs to 220 μs to run. Considering that I also need to copy allot of other data from mjData for the profiler and simulation status etc, this is borderline for simulating reliably at even 1kHz.

    Therefore, my questions are the following:

    1. If using two copies of mjData (one for each thread), what is the minimal set of elements from this struct which are need by mjv_updateScene()? I did not find any info in the documentation, and I really need to retrieve data from mjData in a way which least blocks the simulation thread. (I am using boost shared mutex for thread synchronization).

    2. Is there any better and more efficient way of going about this?

    3. I have noticed that calls to glfwTerminate() are causing segfaults, regardless of weather the GLFW window exists or not (I am running Ubuntu 16.04LTS). Any thoughts? I even verified this behavior on the provided examples in mjpro150.

    Best regards,

    Vassilios
     
  2. Emo Todorov

    Emo Todorov Administrator Staff Member

    mjData is indeed big and you should not copy it. Instead, the simulation thread should run at 1 KHz and occasionally (i.e. at 60Hz) update mjvData. This is very fast since these is no actual rendering.

    Then, the rendering thread should use mjvData to render the pixels. You need a mutex to protect access to mjvData which will be used by both threads. Or, you could use a circular buffer with two mjvData's, and have the simulation thread update one slot while the rendering thread is using the other slot.