Menu

#2734 Video encoding FPS problems

2020.4
Done
nobody
None
Low
2022-05-03
2022-04-24
eatdirt
No

Hi there,
follow-up of the mailing list discussion.

On my machine, as soon as I try to encode a video, the fps drops to unacceptable values. The video encoding seems to work, at very low fps, as files are created and playable.

Certainly this is some issue with the encoder, my hardware is quite reasonable:

Resolution is 2560x1600
Intel(R) Xeon(R) CPU E5-2697 v2 @ 2.70GHz (12 cores, 24 threads)
NVIDIA Corporation GP104 [GeForce GTX 1080]

fgfs does not use the extra available threads when encoding, it sticks at 100% (but threads are enable, I do see 200% sometimes while running the normal sim).

during the build of simgear I see that:

Found FFmpeg: /usr/lib64/libavcodec.so;/usr/lib64/libavformat.so;/usr/lib64/libavutil.so;/usr/lib64/libswscale.so  found components: AVCODEC AVFORMAT AVUTIL SWSCALE

which suggests that software scaling is in used? (it is ffmpeg 4.3.3), but other softs link to it seem to be able to use hardware acceleration.

ffmpeg -codecs | grep 264 gives:

 DEV.LS h264                 H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10 (decoders: h264 h264_v4l2m2m h264_qsv ) (encoders: libx264 libx264rgb h264_qsv h264_v4l2m2m h264_vaapi )

Let me know If you want me to test specific thing

Discussion

  • Frederic Petit

    Frederic Petit - 2022-04-25

    libswrescale is not only used for resizing the video, but also for colorspace conversions: https://ffmpeg.org/libswscale.html#Description

    So, it'd be worth to find out in which color format FG is capturing the frames and which codec is using that colorspace to minimize the encoding impact on FPS as much as possible.

     
  • Julian Smith

    Julian Smith - 2022-04-25

    libswscale.so is used to convert FG's main window's RGB pixels into YUV format - all the video codecs require YUV as input. I think this is pretty standard - i've just copied the ffmpeg encoding examples, and i don't think this can be a significant source of slow-down.

    I think it's suspicious that video encoding is not using your additional CPU cores here.

    Is it possible that the fgfs process is being tied to a single core for example?

    The FG video encoding code explicitly runs in its own thread so that FG can always get on with other things while we are encoding (because we wait for ffmpeg to make progress). And i think Ffmpeg also creates and runs its own threads - it certainly does for me, where video encoding changes top's cpu usage for fgfs from 50% to 380% (on a 4-core machine, i.e. it's using all available cpu cores).

    I might have a look at allowing the video encoding code to force the number of threads being used by ffmpeg, and we can see whether that changes things. But i'm a little suspicious of your setup here because the defaults should just work. (And you are also seeing a curious slowdown from Sentry).

    - Jules

     
  • eatdirt

    eatdirt - 2022-04-25

    But i'm a little suspicious of your setup here

    It is built with hardened compilation options, namely not higher than -O2 and sse2, threads enable, to be distributed under Mageia linux. So, it indeed may differ from the nightly build, but it is certainly closer to what distros will be distributing.

    If you have a suspicion of a bug related to built options, I can provide full details of the cmake command use to do the build (simgear and/or flightgear)?

    Another thing I've noted is that the default CRF (logged in the console) looks very low. At quality 1, it displays a crf of 3. For x264 codecs, this should be more around 20? Is log scale, so 3 means very close to lossless, maybe the bandwidth just become too large for 2K screen.

     

    Last edit: eatdirt 2022-04-25
  • Julian Smith

    Julian Smith - 2022-04-25

    Thanks for this info.

    Yes, please post your cmake command, just in case the compiler options are effecting things. Also would you be able to try a standard FG build?

    However i was more concerned that there could be something about your system configuration that is restricting how many cores the FG process is allowed to use. Could you try running something like recordmydesktop and see what its CPU usage is in top?

    The ideal test would be to try a different Linux distribution on the same or similar hardware, in case there's something odd about Mageia's ffmpeg package, but i appreciate that this might not be possible.

    Thanks,

    - Jules

     
  • eatdirt

    eatdirt - 2022-04-25

    I've just built and tested recordmydesktop, I did not know this one. It takes at most 1% of CPU during the recording, then 100% after pressing CTRL+C when dumping the ogv file.

    For ffmpeg, I've never tested calling the libs, but I'am using regularly the ffmpeg binary for encoding 4K images into 4K lossless films (x264). All the 24 cores are full steam when doing so.

    I can also have a look to the simgear code, maybe that would give me some clue on what could be wrong with my ffmpeg install, if any.

    Log of simgear build here:

    https://curl.irmp.ucl.ac.be/~chris/upload/fg/tmp/log_simgear.txt

    I'll test a nightly official build as soon as I can!

     

    Last edit: eatdirt 2022-04-25
  • eatdirt

    eatdirt - 2022-04-27

    I've noticed something weird with 2020.4.0, that could be related.

    One of the nasal module for the SpaceShuttle uses an extra-thread to do some calculations. With 2020.4.0, I have a huge fps drop when this thread is running. The problem may not be in ffmpeg but the way these threads are implemented? Did something change in our threading implementation, like some extra locking?

     
  • Julian Smith

    Julian Smith - 2022-04-27

    James will have a much better idea that me about potentially relevant changes on next.

    The only thing i can think of is that properties have been made thread-safe on next, using read/write locks. Various were made to ensure that this didn't slow things down measurably (which for example lead to a change to not call parent nodes' listeners for value-changed events by default), so i'd hope that this isn't causing the problem. I certainly can't see how it could cause a large slow-down to threaded code.

    One can temporarily disable the read/write locking by setting environmental variable SG_PROPERTY_LOCKING=0. Or at runtime by setting /sim/property-locking/active=false. Assuming this doesn't fix the problem, please don't keep this setting, as it opens us up to potential SEGVs in code that uses properties.

    Thanks,

    - Jules

     
  • James Turner

    James Turner - 2022-04-28

    I'm also pretty clueless about Nasal threads. But if the code was using them and property locking is impacting performance, this more or less means the previous was massively thread-unsafe, becuase it's exactly this case whcih requires properties to be locked.

    It's worth trying the test Jules suggests to disable locking, of course - to establish if properpty locking is really the issue or not.

     
  • eatdirt

    eatdirt - 2022-04-28

    All right, thanks for the feedback, I did the test and property locking is not the cause, the fps drops is about the same when I switch on video recording (or when that nasal space shuttle (STS) thread runs).

    I have not been able to test the nightly appimage, it segfaults when I start it, in dbus. That's most probably some incompatible dbus library versionning between the nightly build and my system, so nothing fancy there.

    Looking for ressources, I've tried the FG system monitor, but that looks normal. "events" take most of the resources for the STS, "gui" for the UFO, but fps drop is huge for both when video is on (from more than 100 to 10 for the UFO).

    When starting videos, perf top shows that most resources are taken by the encoder. What may not be normal is that these are not using the extra threads efficiently. This is top (H engaged to see threads) for the fgfs process when video encoding is running

     471812 chris     20   0 4677876   3.5g 126384 R  51.3   7.5   5:51.44 fgfs
     471405 chris     20   0 4677876   3.5g 126384 S  48.0   7.5   8:28.39 fgfs
     471430 chris     20   0 4677876   3.5g 126384 S   0.7   7.5   0:03.43 fgfs
     471408 chris     20   0 4677876   3.5g 126384 S   0.0   7.5   0:00.05 QXcbEventQueue
     471423 chris     20   0 4677876   3.5g 126384 S   0.0   7.5   0:00.00 fgfs
     471424 chris     20   0 4677876   3.5g 126384 S   0.0   7.5   0:00.00 fgfs
     471425 chris     20   0 4677876   3.5g 126384 S   0.0   7.5   0:00.00 fgfs
     471426 chris     20   0 4677876   3.5g 126384 S   0.0   7.5   0:00.00 fgfs
     471427 chris     20   0 4677876   3.5g 126384 S   0.0   7.5   0:00.00 fgfs
     471429 chris     20   0 4677876   3.5g 126384 S   0.0   7.5   0:00.00 fgfs
     471431 chris     20   0 4677876   3.5g 126384 S   0.0   7.5   0:00.00 fgfs
     471432 chris     20   0 4677876   3.5g 126384 S   0.0   7.5   0:00.07 fgfs
     471435 chris     20   0 4677876   3.5g 126384 S   0.0   7.5   0:41.59 fgfs
     471436 chris     20   0 4677876   3.5g 126384 S   0.0   7.5   0:00.00 fgfs
    

    Only 2 threads are active, and seems to share a single core. The other guys sleep. Perf top shows this, so encoding indeed burns most of the ressources:

    10.77%  libx264.so.157                            [.] x264_8_trellis_coefn
     10.13%  libswscale.so.5.7.100                     [.] sws_getCachedContext
      7.14%  libswscale.so.5.7.100                     [.] sws_init_context
      6.99%  libnvidia-glcore.so.470.94                [.] _nv047glcore
      6.23%  libnvidia-glcore.so.470.94                [.] _nv026glcore
      5.35%  [kernel]                                  [k] asm_exc_nmi
       2.22%  libx264.so.157                            [.] x264_8_macroblock_cache_load_progressive
      2.09%  libstdc++.so.6.0.28                 
    

    I don't have this specific issue with other threaded programs. When I stop the video encoding, I am getting that:

    471405 chris     20   0 4644972   3.5g 123952 R  99.0   7.4   9:21.92 fgfs
     471430 chris     20   0 4644972   3.5g 123952 S   0.3   7.4   0:03.82 fgfs
     471408 chris     20   0 4644972   3.5g 123952 S   0.0   7.4   0:00.06 QXcbEventQueue
     471423 chris     20   0 4644972   3.5g 123952 S   0.0   7.4   0:00.00 fgfs
     471424 chris     20   0 4644972   3.5g 123952 S   0.0   7.4   0:00.00 fgfs
     471425 chris     20   0 4644972   3.5g 123952 S   0.0   7.4   0:00.00 fgfs
     471426 chris     20   0 4644972   3.5g 123952 S   0.0   7.4   0:00.00 fgfs
     471427 chris     20   0 4644972   3.5g 123952 S   0.0   7.4   0:00.00 fgfs
     471429 chris     20   0 4644972   3.5g 123952 S   0.0   7.4   0:00.00 fgfs
     471431 chris     20   0 4644972   3.5g 123952 S   0.0   7.4   0:00.00 fgfs
     471432 chris     20   0 4644972   3.5g 123952 S   0.0   7.4   0:00.07 fgfs
     471435 chris     20   0 4644972   3.5g 123952 S   0.0   7.4   0:41.59 fgfs
     471436 chris     20   0 4644972   3.5g 123952 S   0.0   7.4   0:00.00 fgfs
    

    PS: When running the nasal STS module, the new thread properly takes 100% (fgfs at 200%), I am getting that. Most of the calls are allocating and freeing integer, but that may be just nasal specifics.

    13.01%  libc-2.32.so                              [.] _int_malloc
    6.74%  libSimGearCore.so.2020.4.0                [.] run
    4.60%  libc-2.32.so                              [.] _int_free
    4.03%  libc-2.32.so                              [.] free
    2.93%  libc-2.32.so                              [.] malloc_consolidate
    2.87%  [kernel]                                  [k] asm_exc_nmi
    2.53%  libSimGearCore.so.2020.4.0                [.] naiHash_sym
    1.93%  libc-2.32.so                              [.] malloc
    1.71%  libSimGearScene.so.2020.4.0               [.] SGTriangleBin<SGVertNor
    
     
  • Julian Smith

    Julian Smith - 2022-04-28

    Ok that's looking like there's some non-trivial thread CPU affinity going on.

    Could you run this command, with PID replaced by the pid of the fgfs process, and post the output for the three cases - normal, running STS thread, and video encoding?

    for i in `ls /proc/PID/task/`; do taskset -p $i; done

    Interestingly, for me this is showing some threads tied to particular CPUs (i've only got 4), which i wasn't expecting. For basic fgfs, i see:

    pid 17992's current affinity mask: 1
    pid 17995's current affinity mask: f
    pid 17999's current affinity mask: f
    pid 18000's current affinity mask: f
    pid 18001's current affinity mask: f
    pid 18002's current affinity mask: f
    pid 18007's current affinity mask: 1
    pid 18013's current affinity mask: 1
    pid 18014's current affinity mask: 1
    pid 18015's current affinity mask: 1
    pid 18016's current affinity mask: 1
    pid 18017's current affinity mask: 1
    pid 18018's current affinity mask: 2
    pid 18021's current affinity mask: 1
    pid 18022's current affinity mask: 1
    pid 18023's current affinity mask: 1
    pid 18026's current affinity mask: f
    pid 18027's current affinity mask: f
    pid 18030's current affinity mask: 1
    

    So the main thread 17992 is tied to cpu 0 (1), other threads are the same or run on all cpus (f) or are tied to cpu 1 (2).

    Then if i start video encoding, the extra threads look like:

    pid 18159's current affinity mask: 1
    pid 18160's current affinity mask: f
    pid 18161's current affinity mask: f
    pid 18162's current affinity mask: f
    pid 18163's current affinity mask: f
    pid 18164's current affinity mask: f
    

    So all but one of the ffmpeg threads run on all cores.

    I think that new threads default to inheriting their parent's affinity. But openscenegraph/src/OpenThreads/pthreads/PThread.cpp seems to be making calls to pthread_setaffinity_np() or sched_setaffinity().

    I haven't investigated further yet.

    - Jules

     
  • eatdirt

    eatdirt - 2022-04-29

    Ok, here we go without running the video encoding:

    pid 669079's current affinity mask: 1
    pid 669082's current affinity mask: ffffff
    pid 669094's current affinity mask: 1
    pid 669095's current affinity mask: 1
    pid 669096's current affinity mask: 1
    pid 669097's current affinity mask: 1
    pid 669098's current affinity mask: 2
    pid 669100's current affinity mask: 1
    pid 669101's current affinity mask: 1
    pid 669102's current affinity mask: 1
    pid 669103's current affinity mask: 1
    pid 669113's current affinity mask: ffffff
    pid 669114's current affinity mask: ffffff
    pid 669131's current affinity mask: 1
    

    and running it, the same!

    pid 669079's current affinity mask: 1
    pid 669082's current affinity mask: ffffff
    pid 669094's current affinity mask: 1
    pid 669095's current affinity mask: 1
    pid 669096's current affinity mask: 1
    pid 669097's current affinity mask: 1
    pid 669098's current affinity mask: 2
    pid 669100's current affinity mask: 1
    pid 669101's current affinity mask: 1
    pid 669102's current affinity mask: 1
    pid 669103's current affinity mask: 1
    pid 669113's current affinity mask: ffffff
    pid 669114's current affinity mask: ffffff
    pid 669131's current affinity mask: 1
    pid 670197's current affinity mask: 1
    

    But, I am interested in your comment about openscenegraph, I had assume that osg threads were unrelated to simgear thread. Maybe I should toy with this?

    --prop:/sim/rendering/multithreading-mode=

    Same thing with:
    --prop:/sim/rendering/multithreading-mode=DrawThreadPerContext

    no video:

    pid 671007's current affinity mask: 1
    pid 671010's current affinity mask: ffffff
    pid 671013's current affinity mask: 4
    pid 671014's current affinity mask: 4
    pid 671040's current affinity mask: 1
    pid 671041's current affinity mask: 1
    pid 671042's current affinity mask: 1
    pid 671043's current affinity mask: 1
    pid 671044's current affinity mask: 2
    pid 671046's current affinity mask: 1
    pid 671047's current affinity mask: 1
    pid 671048's current affinity mask: 1
    pid 671049's current affinity mask: 1
    pid 671052's current affinity mask: fffff0
    pid 671053's current affinity mask: fffff0
    pid 671075's current affinity mask: 1
    

    video on, the same!

    pid 671007's current affinity mask: 1
    pid 671010's current affinity mask: ffffff
    pid 671013's current affinity mask: 4
    pid 671014's current affinity mask: 4
    pid 671040's current affinity mask: 1
    pid 671041's current affinity mask: 1
    pid 671042's current affinity mask: 1
    pid 671043's current affinity mask: 1
    pid 671044's current affinity mask: 2
    pid 671046's current affinity mask: 1
    pid 671047's current affinity mask: 1
    pid 671048's current affinity mask: 1
    pid 671049's current affinity mask: 1
    pid 671052's current affinity mask: fffff0
    pid 671053's current affinity mask: fffff0
    pid 671075's current affinity mask: 1
    pid 671321's current affinity mask: 1
    

    The interesting part is that there is an extra affinity, to cpu 4, which is used, my frame rate just doubled, instead of going from 100 to 10, it went from 100 to 20. So that's it, we should understand why this affinity are set by default!

     
  • eatdirt

    eatdirt - 2022-04-29

    Just wanted to add that I suspect it is dramatic for me alone due to the resolution. For instance, even with 1 thread, when I resized the window to 800x600, the fps goes down but remain usable, like 20 fps. But full screen, that is a down to 4-5. Since the bandwitdh required scales as the square of the resolution, that goes down fast with high res!

     
  • Julian Smith

    Julian Smith - 2022-04-30

    It's very odd that activating video encoding only creates one new thread for you, and it's not surprising that encoding your large window using just this single thread slows things down a lot - Flightgear has to wait for the encoding of the current frame to complete before if can move to the next thread.

    One other thing - i think that new threads default to inheriting the affinities of their parent thread, so OSG's affinity settings on startup for the main thread and others, are likely to effect the affinities of newly-created threads later on.

    I've just pushed a change to the flightgear and simgear repositories that gives control over whether we tell OSG to tie threads to cpu cores. Running with --prop:bool:/sim/thread-cpu-affinity=false will disable these affinities; it would be interesting to see what difference this makes on your machine.

    However unless this effects how many threads ffmpeg uses, i can't see it helping your slow-down.

    I guess there's an outside chance that, when starting encoding, ffmpeg looks at the affinity of the current thread and, if it's set to a single core, figures that there's no point in creating more than one (similarly tied) new thread for encoding, because only one will get to run at a time.

    Thanks,

    - Jules

     
  • eatdirt

    eatdirt - 2022-04-30

    Ok, that definitely unlocked things.

    I'll start with the sure thing: This guy unset:

    --prop:/sim/rendering/multithreading-mode

    with this:

    --prop:bool:/sim/thread-cpu-affinity=false

    for the UFO.

    Not encoding:

    881150 chris     20   0 6428048   5.0g 132140 R  98.3  10.7   1:45.99 fgfs
     881278 chris     20   0 6428048   5.0g 132140 S   0.7  10.7   0:00.62 fgfs
     881153 chris     20   0 6428048   5.0g 132140 S   0.0  10.7   0:00.01 QXcbEventQueue
     881269 chris     20   0 6428048   5.0g 132140 S   0.0  10.7   0:00.00 fgfs
     881272 chris     20   0 6428048   5.0g 132140 S   0.0  10.7   0:00.00 fgfs
     881273 chris     20   0 6428048   5.0g 132140 S   0.0  10.7   0:00.00 fgfs
     881274 chris     20   0 6428048   5.0g 132140 S   0.0  10.7   0:00.00 fgfs
     881275 chris     20   0 6428048   5.0g 132140 S   0.0  10.7   0:00.00 fgfs
     881277 chris     20   0 6428048   5.0g 132140 S   0.0  10.7   0:00.00 fgfs
     881279 chris     20   0 6428048   5.0g 132140 S   0.0  10.7   0:00.00 fgfs
     881280 chris     20   0 6428048   5.0g 132140 S   0.0  10.7   0:00.06 fgfs
     881290 chris     20   0 6428048   5.0g 132140 S   0.0  10.7   1:37.19 fgfs
     881291 chris     20   0 6428048   5.0g 132140 S   0.0  10.7   0:00.00 fgfs
     881306 chris     20   0 6428048   5.0g 132140 S   0.0  10.7   0:02.31 fgfs
    
    pid 881150's current affinity mask: ffffff
    pid 881153's current affinity mask: ffffff
    pid 881269's current affinity mask: ffffff
    pid 881272's current affinity mask: ffffff
    pid 881273's current affinity mask: ffffff
    pid 881274's current affinity mask: ffffff
    pid 881275's current affinity mask: 2
    pid 881277's current affinity mask: ffffff
    pid 881278's current affinity mask: ffffff
    pid 881279's current affinity mask: ffffff
    pid 881280's current affinity mask: ffffff
    pid 881290's current affinity mask: ffffff
    pid 881291's current affinity mask: ffffff
    pid 881306's current affinity mask: ffffff
    

    Switching on x265 encoding, fps from 100 to ~25, but that works. Clearly ffmpeg is now forking new threads and uses them:

    881150 chris     20   0 8723956   5.4g 129504 S  59.5  11.6   2:39.47 fgfs
     881615 chris     20   0 8723956   5.4g 129504 S  44.9  11.6   0:03.17 fgfs
     881617 chris     30  10 8723956   5.4g 129504 R  30.6  11.6   0:02.12 fgfs
     881616 chris     30  10 8723956   5.4g 129504 R  29.9  11.6   0:02.11 fgfs
     881619 chris     30  10 8723956   5.4g 129504 R  29.6  11.6   0:02.09 fgfs
     881618 chris     30  10 8723956   5.4g 129504 R  28.6  11.6   0:02.04 fgfs
     881620 chris     30  10 8723956   5.4g 129504 R  27.2  11.6   0:01.91 fgfs
     881621 chris     30  10 8723956   5.4g 129504 R  26.2  11.6   0:01.85 fgfs
     881623 chris     30  10 8723956   5.4g 129504 R  26.2  11.6   0:01.79 fgfs
     881622 chris     30  10 8723956   5.4g 129504 R  24.6  11.6   0:01.76 fgfs
     881624 chris     30  10 8723956   5.4g 129504 S  23.9  11.6   0:01.65 fgfs
     881625 chris     30  10 8723956   5.4g 129504 R  18.3  11.6   0:01.30 fgfs
     881626 chris     30  10 8723956   5.4g 129504 R  18.3  11.6   0:01.28 fgfs
     881627 chris     30  10 8723956   5.4g 129504 R  17.9  11.6   0:01.25 fgfs
     881628 chris     30  10 8723956   5.4g 129504 S  17.3  11.6   0:01.20 fgfs
     881629 chris     30  10 8723956   5.4g 129504 S  16.6  11.6   0:01.16 fgfs
     881630 chris     30  10 8723956   5.4g 129504 S  16.6  11.6   0:01.13 fgfs
     881632 chris     30  10 8723956   5.4g 129504 S  15.6  11.6   0:01.07 fgfs
     881631 chris     30  10 8723956   5.4g 129504 S  15.0  11.6   0:01.07 fgfs
     881633 chris     30  10 8723956   5.4g 129504 S  14.6  11.6   0:01.06 fgfs
     881634 chris     30  10 8723956   5.4g 129504 S  14.3  11.6   0:01.00 fgfs
     881636 chris     30  10 8723956   5.4g 129504 S  13.6  11.6   0:00.91 fgfs
     881635 chris     30  10 8723956   5.4g 129504 S  13.0  11.6   0:00.91 fgfs
     881637 chris     30  10 8723956   5.4g 129504 S  13.0  11.6   0:00.94 fgfs
     881638 chris     30  10 8723956   5.4g 129504 S  11.6  11.6   0:00.83 fgfs
     881639 chris     30  10 8723956   5.4g 129504 S  10.0  11.6   0:00.68 fgfs
     881278 chris     20   0 8723956   5.4g 129504 S   0.7  11.6   0:00.93 fgfs
     881640 chris     20   0 8723956   5.4g 129504 S   0.7  11.6   0:00.04 fgfs
     881153 chris     20   0 8723956   5.4g 129504 S   0.0  11.6   0:00.01 QXcbEventQueue
     881269 chris     20   0 8723956   5.4g 129504 S   0.0  11.6   0:00.00 fgfs
     881272 chris     20   0 8723956   5.4g 129504 S   0.0  11.6   0:00.00 fgfs
     881273 chris     20   0 8723956   5.4g 129504 S   0.0  11.6   0:00.00 fgfs
     881274 chris     20   0 8723956   5.4g 129504 S   0.0  11.6   0:00.00 fgfs
     881275 chris     20   0 8723956   5.4g 129504 S   0.0  11.6   0:00.00 fgfs
     881277 chris     20   0 8723956   5.4g 129504 S   0.0  11.6   0:00.00 fgfs
     881279 chris     20   0 8723956   5.4g 129504 S   0.0  11.6   0:00.00 fgfs
     881280 chris     20   0 8723956   5.4g 129504 S   0.0  11.6   0:00.06 fgfs
     881290 chris     20   0 8723956   5.4g 129504 S   0.0  11.6   1:37.19 fgfs
     881291 chris     20   0 8723956   5.4g 129504 S   0.0  11.6   0:00.00 fgfs
     881306 chris     20   0 8723956   5.4g 129504 S   0.0  11.6   0:02.31 fgfs
    
    pid 881150's current affinity mask: ffffff
    pid 881153's current affinity mask: ffffff
    pid 881269's current affinity mask: ffffff
    pid 881272's current affinity mask: ffffff
    pid 881273's current affinity mask: ffffff
    pid 881274's current affinity mask: ffffff
    pid 881275's current affinity mask: 2
    pid 881277's current affinity mask: ffffff
    pid 881278's current affinity mask: ffffff
    pid 881279's current affinity mask: ffffff
    pid 881280's current affinity mask: ffffff
    pid 881290's current affinity mask: ffffff
    pid 881291's current affinity mask: ffffff
    pid 881306's current affinity mask: ffffff
    pid 881615's current affinity mask: ffffff
    pid 881616's current affinity mask: ffffff
    pid 881617's current affinity mask: ffffff
    pid 881618's current affinity mask: ffffff
    pid 881619's current affinity mask: ffffff
    pid 881620's current affinity mask: ffffff
    pid 881621's current affinity mask: ffffff
    pid 881622's current affinity mask: ffffff
    pid 881623's current affinity mask: ffffff
    pid 881624's current affinity mask: ffffff
    pid 881625's current affinity mask: ffffff
    pid 881626's current affinity mask: ffffff
    pid 881627's current affinity mask: ffffff
    pid 881628's current affinity mask: ffffff
    pid 881629's current affinity mask: ffffff
    pid 881630's current affinity mask: ffffff
    pid 881631's current affinity mask: ffffff
    pid 881632's current affinity mask: ffffff
    pid 881633's current affinity mask: ffffff
    pid 881634's current affinity mask: ffffff
    pid 881635's current affinity mask: ffffff
    pid 881636's current affinity mask: ffffff
    pid 881637's current affinity mask: ffffff
    pid 881638's current affinity mask: ffffff
    pid 881639's current affinity mask: ffffff
    pid 881640's current affinity mask: ffffff
    

    For x264, the same happens, but the threads are not very much efficient, the fps goes the same, from 100 to ~25, I guess that's normal, x264 being less demanding.

    881150 chris     20   0    9.8g   6.1g 132552 R  61.7  13.0   7:24.53 fgfs
     882290 chris     20   0    9.8g   6.1g 132552 S  43.7  13.0   0:04.67 fgfs
     882302 chris     30  10    9.8g   6.1g 132552 S   3.7  13.0   0:00.21 fgfs
     882301 chris     30  10    9.8g   6.1g 132552 S   3.0  13.0   0:00.23 fgfs
     882316 chris     30  10    9.8g   6.1g 132552 S   3.0  13.0   0:00.27 fgfs
     882292 chris     30  10    9.8g   6.1g 132552 S   2.3  13.0   0:00.19 fgfs
     882295 chris     30  10    9.8g   6.1g 132552 S   2.3  13.0   0:00.20 fgfs
     882304 chris     30  10    9.8g   6.1g 132552 S   2.3  13.0   0:00.16 fgfs
     882311 chris     30  10    9.8g   6.1g 132552 S   2.3  13.0   0:00.18 fgfs
     882315 chris     30  10    9.8g   6.1g 132552 S   2.3  13.0   0:00.17 fgfs
     882299 chris     30  10    9.8g   6.1g 132552 S   2.0  13.0   0:00.11 fgfs
     882314 chris     30  10    9.8g   6.1g 132552 S   2.0  13.0   0:00.14 fgfs
     882293 chris     30  10    9.8g   6.1g 132552 S   1.7  13.0   0:00.13 fgfs
     882294 chris     30  10    9.8g   6.1g 132552 S   1.7  13.0   0:00.16 fgfs
     882313 chris     30  10    9.8g   6.1g 132552 S   1.7  13.0   0:00.12 fgfs
     882322 chris     30  10    9.8g   6.1g 132552 S   1.7  13.0   0:00.19 fgfs
     882325 chris     30  10    9.8g   6.1g 132552 S   1.7  13.0   0:00.15 fgfs
     882326 chris     30  10    9.8g   6.1g 132552 S   1.7  13.0   0:00.17 fgfs
     882298 chris     30  10    9.8g   6.1g 132552 S   1.3  13.0   0:00.18 fgfs
     882308 chris     30  10    9.8g   6.1g 132552 S   1.3  13.0   0:00.17 fgfs
     882310 chris     30  10    9.8g   6.1g 132552 S   1.3  13.0   0:00.16 fgfs
     882319 chris     30  10    9.8g   6.1g 132552 S   1.3  13.0   0:00.13 fgfs
     882320 chris     30  10    9.8g   6.1g 132552 S   1.3  13.0   0:00.14 fgfs
     882303 chris     30  10    9.8g   6.1g 132552 S   1.0  13.0   0:00.12 fgfs
     882312 chris     30  10    9.8g   6.1g 132552 S   1.0  13.0   0:00.13 fgfs
     882317 chris     30  10    9.8g   6.1g 132552 S   1.0  13.0   0:00.15 fgfs
     882321 chris     30  10    9.8g   6.1g 132552 S   1.0  13.0   0:00.15 fgfs
     882327 chris     20   0    9.8g   6.1g 132552 S   1.0  13.0   0:00.09 fgfs
     882328 chris     20   0    9.8g   6.1g 132552 S   1.0  13.0   0:00.09 fgfs
     882329 chris     20   0    9.8g   6.1g 132552 S   1.0  13.0   0:00.09 fgfs
     882330 chris     20   0    9.8g   6.1g 132552 S   1.0  13.0   0:00.09 fgfs
     882332 chris     20   0    9.8g   6.1g 132552 S   1.0  13.0   0:00.09 fgfs
     881278 chris     20   0    9.8g   6.1g 132552 S   0.7  13.0   0:02.68 fgfs
     882296 chris     30  10    9.8g   6.1g 132552 S   0.7  13.0   0:00.13 fgfs
     882300 chris     30  10    9.8g   6.1g 132552 S   0.7  13.0   0:00.12 fgfs
     882305 chris     30  10    9.8g   6.1g 132552 S   0.7  13.0   0:00.16 fgfs
     882306 chris     30  10    9.8g   6.1g 132552 S   0.7  13.0   0:00.11 fgfs
     882309 chris     30  10    9.8g   6.1g 132552 S   0.7  13.0   0:00.16 fgfs
     882323 chris     30  10    9.8g   6.1g 132552 S   0.7  13.0   0:00.13 fgfs
     882331 chris     20   0    9.8g   6.1g 132552 S   0.7  13.0   0:00.08 fgfs
     882333 chris     20   0    9.8g   6.1g 132552 S   0.3  13.0   0:00.02 fgfs
     881153 chris     20   0    9.8g   6.1g 132552 S   0.0  13.0   0:00.02 QXcbEventQueue
     881269 chris     20   0    9.8g   6.1g 132552 S   0.0  13.0   0:00.00 fgfs
     881272 chris     20   0    9.8g   6.1g 132552 S   0.0  13.0   0:00.00 fgfs
     881273 chris     20   0    9.8g   6.1g 132552 S   0.0  13.0   0:00.00 fgfs
     881274 chris     20   0    9.8g   6.1g 132552 S   0.0  13.0   0:00.00 fgfs
     881275 chris     20   0    9.8g   6.1g 132552 S   0.0  13.0   0:00.00 fgfs
     881277 chris     20   0    9.8g   6.1g 132552 S   0.0  13.0   0:00.00 fgfs
     881279 chris     20   0    9.8g   6.1g 132552 S   0.0  13.0   0:00.00 fgfs
     881280 chris     20   0    9.8g   6.1g 132552 S   0.0  13.0   0:00.06 fgfs
     881290 chris     20   0    9.8g   6.1g 132552 S   0.0  13.0   1:37.40 fgfs
     881291 chris     20   0    9.8g   6.1g 132552 S   0.0  13.0   0:00.00 fgfs
     881306 chris     20   0    9.8g   6.1g 132552 S   0.0  13.0   0:02.31 fgfs
     882291 chris     30  10    9.8g   6.1g 132552 S   0.0  13.0   0:00.18 fgfs
     882297 chris     30  10    9.8g   6.1g 132552 S   0.0  13.0   0:00.10 fgfs
     882307 chris     30  10    9.8g   6.1g 132552 S   0.0  13.0   0:00.23 fgfs
     882318 chris     30  10    9.8g   6.1g 132552 S   0.0  13.0   0:00.10 fgfs
     882324 chris     30  10    9.8g   6.1g 132552 S   0.0  13.0   0:00.14 fgfs
    
    pid 881150's current affinity mask: ffffff
    pid 881153's current affinity mask: ffffff
    pid 881269's current affinity mask: ffffff
    pid 881272's current affinity mask: ffffff
    pid 881273's current affinity mask: ffffff
    pid 881274's current affinity mask: ffffff
    pid 881275's current affinity mask: 2
    pid 881277's current affinity mask: ffffff
    pid 881278's current affinity mask: ffffff
    pid 881279's current affinity mask: ffffff
    pid 881280's current affinity mask: ffffff
    pid 881290's current affinity mask: ffffff
    pid 881291's current affinity mask: ffffff
    pid 881306's current affinity mask: ffffff
    pid 882290's current affinity mask: ffffff
    pid 882291's current affinity mask: ffffff
    pid 882292's current affinity mask: ffffff
    pid 882293's current affinity mask: ffffff
    pid 882294's current affinity mask: ffffff
    pid 882295's current affinity mask: ffffff
    pid 882296's current affinity mask: ffffff
    pid 882297's current affinity mask: ffffff
    pid 882298's current affinity mask: ffffff
    pid 882299's current affinity mask: ffffff
    pid 882300's current affinity mask: ffffff
    pid 882301's current affinity mask: ffffff
    pid 882302's current affinity mask: ffffff
    pid 882303's current affinity mask: ffffff
    pid 882304's current affinity mask: ffffff
    pid 882305's current affinity mask: ffffff
    pid 882306's current affinity mask: ffffff
    pid 882307's current affinity mask: ffffff
    pid 882308's current affinity mask: ffffff
    pid 882309's current affinity mask: ffffff
    pid 882310's current affinity mask: ffffff
    pid 882311's current affinity mask: ffffff
    pid 882312's current affinity mask: ffffff
    pid 882313's current affinity mask: ffffff
    pid 882314's current affinity mask: ffffff
    pid 882315's current affinity mask: ffffff
    pid 882316's current affinity mask: ffffff
    pid 882317's current affinity mask: ffffff
    pid 882318's current affinity mask: ffffff
    pid 882319's current affinity mask: ffffff
    pid 882320's current affinity mask: ffffff
    pid 882321's current affinity mask: ffffff
    pid 882322's current affinity mask: ffffff
    pid 882323's current affinity mask: ffffff
    pid 882324's current affinity mask: ffffff
    pid 882325's current affinity mask: ffffff
    pid 882326's current affinity mask: ffffff
    pid 882327's current affinity mask: ffffff
    pid 882328's current affinity mask: ffffff
    pid 882329's current affinity mask: ffffff
    pid 882330's current affinity mask: ffffff
    pid 882331's current affinity mask: ffffff
    pid 882332's current affinity mask: ffffff
    pid 882333's current affinity mask: ffffff
    

    That also suggests that 25 fps is not really due to encoding but something else. Independently of the fps, moving the view while encoding is quite laggy, but that is not as catastrophic as before.

    Weird thing is that one thread appears to be locked to core 2?

    NB: The unsure things: I've been seeing segfaults if the multithreading-mode is changed, like this

    --prop:/sim/rendering/multithreading-mode=DrawThreadPerContext

    when stopping x264 encoding after a change from full screen to windowed mode. The rest is the same, CPU affinity is free up to number 2 and ffmpeg succeeds to fork!

    PS: It is still not perfect, the lag while encoding is quite hard, but I suspect the main issue is solved, so feel free to close the bug. I'll explore on my side what osg is doing with thread, that looks ugly, but there may be some compilation options I've missed (osg-3.6)

    Thanks for the help!

     
  • Julian Smith

    Julian Smith - 2022-05-01

    Thanks again for trying things, good to see changing affinities is helping.

    I've just pushed some more changes:

    • Tweak the handling of /sim/thread-cpu-affinity at startup - set to "none" to turn off thread affinities (same as previous handling of false), "osg" to allow OSG to set affinities but then attempt to remove main thread's affinity (not sure this works very well), or unset/"" for default behaviour (previously unset or true).

    • New property /sim/affinity-control allows crude runtime control of thread affinities on Linux - setting to "clear" remembers the current affinities and removes all threads' affinities; "revert" restores the remembered affinities.

    • New property /sim/video/log_sws_scale_stats - set to true before starting encoding to enable periodic statistics written to terminal about average time spent in sws_scale() each frame. We call sws_scale()on a single thread before sending the resulting YUV data to the encoder, so this will tell us whether it is the bottleneck in your case with a very large window.

    - Jules

     
  • eatdirt

    eatdirt - 2022-05-03

    Hello there,
    I've played with the new options. Concerning

    /sim/thread-cpu-affinity

    set to 'none' or 'osg' does the same for me, it has, as before, one thread locked onto core 2 (see previous posts).

    However, resetting the affinity in sim with

    /sim/affinity-control=clear
    

    works, this affinity to core 2 disappears. Setting "revert" also works, affinity to core 2 comes back. Starting with default OSG affinity settings in which all threads are on core 1 & 2, this affinity-control prop works as expected.

    It works only in sim though, I've tried to set it on the command line but then it does nothing, I suspect threads are not created yet.

    For the video encoding, this is the log I am getting for x264. This is the UFO at BIKF, the scenery was quite heavy with rain and looking at the city (30fps without encoding, 13 with encoding on on multithreads).

    331.67 [ALRT]:general   /home/eatdirt/perso/simgear/BUILD/simgear-2020.4.0/simgear/timing/rawprofile.hxx:82: sws_scale() time: 0.0136485
      333.70 [ALRT]:general   /home/eatdirt/perso/simgear/BUILD/simgear-2020.4.0/simgear/timing/rawprofile.hxx:82: sws_scale() time: 0.0137116
      335.70 [INFO]:nasal     /usr/share/games/flightgear/Nasal/emexec.nas:255: EMEXEC: Adjust frequency to 13.33333333333333 Hz
      335.71 [ALRT]:general   /home/eatdirt/perso/simgear/BUILD/simgear-2020.4.0/simgear/timing/rawprofile.hxx:82: sws_scale() time: 0.0141648
      337.74 [ALRT]:general   /home/eatdirt/perso/simgear/BUILD/simgear-2020.4.0/simgear/timing/rawprofile.hxx:82: sws_scale() time: 0.0137955
      339.78 [ALRT]:general   /home/eatdirt/perso/simgear/BUILD/simgear-2020.4.0/simgear/timing/rawprofile.hxx:82: sws_scale() time: 0.013781
      341.80 [ALRT]:general   /home/eatdirt/perso/simgear/BUILD/simgear-2020.4.0/simgear/timing/rawprofile.hxx:82: sws_scale() time: 0.013667
      343.82 [ALRT]:general   /home/eatdirt/perso/simgear/BUILD/simgear-2020.4.0/simgear/timing/rawprofile.hxx:82: sws_scale() time: 0.0135847
      345.85 [ALRT]:general   /home/eatdirt/perso/simgear/BUILD/simgear-2020.4.0/simgear/timing/rawprofile.hxx:82: sws_scale() time: 0.0137183
      347.86 [ALRT]:general   /home/eatdirt/perso/simgear/BUILD/simgear-2020.4.0/simgear/timing/rawprofile.hxx:82: sws_scale() time: 0.0139572
      349.86 [ALRT]:general   /home/eatdirt/perso/simgear/BUILD/simgear-2020.4.0/simgear/timing/rawprofile.hxx:82: sws_scale() time: 0.0137302
      351.86 [ALRT]:nasal     /home/eatdirt/perso/flightgear/BUILD/flightgear-2020.4.0/src/Scripting/NasalSys.cxx:1467: Nasal runtime error: No such member: models
      351.86 [ALRT]:nasal     /home/eatdirt/perso/flightgear/BUILD/flightgear-2020.4.0/src/Scripting/NasalSys.cxx:1483:   at /usr/share/games/flightgear/Aircraft/ufo/ufo.nas, line 632
      351.86 [ALRT]:nasal     /home/eatdirt/perso/flightgear/BUILD/flightgear-2020.4.0/src/Scripting/NasalSys.cxx:1483:   called from: /input/keyboard/key[359]/binding, line 3
      351.94 [ALRT]:general   /home/eatdirt/perso/simgear/BUILD/simgear-2020.4.0/simgear/timing/rawprofile.hxx:82: sws_scale() time: 0.013826
      353.95 [ALRT]:general   /home/eatdirt/perso/simgear/BUILD/simgear-2020.4.0/simgear/timing/rawprofile.hxx:82: sws_scale() time: 0.0138797
      355.99 [ALRT]:general   /home/eatdirt/perso/simgear/BUILD/simgear-2020.4.0/simgear/timing/rawprofile.hxx:82: sws_scale() time: 0.0137378
      357.24 [INFO]:nasal     /usr/share/games/flightgear/Nasal/emexec.nas:255: EMEXEC: Adjust frequency to 10 Hz
      357.55 [ALRT]:general   /home/eatdirt/perso/flightgear/BUILD/flightgear-2020.4.0/src/Viewer/viewmgr.cxx:174: Video encoding stopped.
      365.22 [INFO]:nasal     /usr/share/games/flightgear/Nasal/emexec.nas:255: EMEXEC: Adjust frequency to 13.33333333333333 Hz
      368.29 [INFO]:nasal     /usr/share/games/flightgear/Nasal/emexec.nas:255: EMEXEC: Adjust frequency to 20 Hz
      370.59 [INFO]:nasal     /usr/share/games/flightgear/Nasal/emexec.nas:255: EMEXEC: Adjust frequency to 30.03003003003003 Hz
    

    the same with x265:

     482.07 [ALRT]:systems   /home/eatdirt/perso/flightgear/BUILD/flightgear-2020.4.0/src/Viewer/viewmgr.cxx:488: Video encoding starting. codec=libx265 quality=0.75 speed=1 bitrate=0 path=Path "fgvideo-UFO-20220503-081800.mkv" path_link=Path "fgvideo-UFO.mkv"
      482.21 [ALRT]:general   /home/eatdirt/perso/simgear/BUILD/simgear-2020.4.0/simgear/screen/video-encoder-internal.hxx:359: dictionary 3:
      482.21 [ALRT]:general   /home/eatdirt/perso/simgear/BUILD/simgear-2020.4.0/simgear/screen/video-encoder-internal.hxx:365:     x265-params=log-level=error
      482.21 [ALRT]:general   /home/eatdirt/perso/simgear/BUILD/simgear-2020.4.0/simgear/screen/video-encoder-internal.hxx:365:     crf=12.750000
      482.21 [ALRT]:general   /home/eatdirt/perso/simgear/BUILD/simgear-2020.4.0/simgear/screen/video-encoder-internal.hxx:365:     preset=ultrafast
      482.23 [ALRT]:general   /home/eatdirt/perso/simgear/BUILD/simgear-2020.4.0/simgear/timing/rawprofile.hxx:82: sws_scale() time: 0.0142027
      484.27 [ALRT]:general   /home/eatdirt/perso/simgear/BUILD/simgear-2020.4.0/simgear/timing/rawprofile.hxx:82: sws_scale() time: 0.0142306
      484.93 [INFO]:nasal     /usr/share/games/flightgear/Nasal/emexec.nas:255: EMEXEC: Adjust frequency to 13.33333333333333 Hz
      486.28 [ALRT]:general   /home/eatdirt/perso/simgear/BUILD/simgear-2020.4.0/simgear/timing/rawprofile.hxx:82: sws_scale() time: 0.0139816
      488.31 [ALRT]:general   /home/eatdirt/perso/simgear/BUILD/simgear-2020.4.0/simgear/timing/rawprofile.hxx:82: sws_scale() time: 0.0141996
      490.32 [ALRT]:general   /home/eatdirt/perso/simgear/BUILD/simgear-2020.4.0/simgear/timing/rawprofile.hxx:82: sws_scale() time: 0.014077
      492.36 [ALRT]:general   /home/eatdirt/perso/simgear/BUILD/simgear-2020.4.0/simgear/timing/rawprofile.hxx:82: sws_scale() time: 0.0138251
      494.40 [ALRT]:general   /home/eatdirt/perso/simgear/BUILD/simgear-2020.4.0/simgear/timing/rawprofile.hxx:82: sws_scale() time: 0.0137867
      496.40 [ALRT]:general   /home/eatdirt/perso/simgear/BUILD/simgear-2020.4.0/simgear/timing/rawprofile.hxx:82: sws_scale() time: 0.0141077
      498.42 [ALRT]:general   /home/eatdirt/perso/simgear/BUILD/simgear-2020.4.0/simgear/timing/rawprofile.hxx:82: sws_scale() time: 0.0138043
      500.44 [ALRT]:general   /home/eatdirt/perso/simgear/BUILD/simgear-2020.4.0/simgear/timing/rawprofile.hxx:82: sws_scale() time: 0.0138649
      501.70 [ALRT]:nasal     /home/eatdirt/perso/flightgear/BUILD/flightgear-2020.4.0/src/Scripting/NasalSys.cxx:1467: Nasal runtime error: No such member: models
      501.70 [ALRT]:nasal     /home/eatdirt/perso/flightgear/BUILD/flightgear-2020.4.0/src/Scripting/NasalSys.cxx:1483:   at /usr/share/games/flightgear/Aircraft/ufo/ufo.nas, line 632
      501.70 [ALRT]:nasal     /home/eatdirt/perso/flightgear/BUILD/flightgear-2020.4.0/src/Scripting/NasalSys.cxx:1483:   called from: /input/keyboard/key[359]/binding, line 3
      502.46 [ALRT]:general   /home/eatdirt/perso/simgear/BUILD/simgear-2020.4.0/simgear/timing/rawprofile.hxx:82: sws_scale() time: 0.0139027
      503.72 [INFO]:nasal     /usr/share/games/flightgear/Nasal/emexec.nas:255: EMEXEC: Adjust frequency to 10 Hz
      504.47 [ALRT]:general   /home/eatdirt/perso/simgear/BUILD/simgear-2020.4.0/simgear/timing/rawprofile.hxx:82: sws_scale() time: 0.013839
      504.76 [ALRT]:general   /home/eatdirt/perso/flightgear/BUILD/flightgear-2020.4.0/src/Viewer/viewmgr.cxx:174: Video encoding stopped.
      511.98 [INFO]:nasal     /usr/share/games/flightgear/Nasal/emexec.nas:255: EMEXEC: Adjust frequency to 13.33333333333333 Hz
      515.05 [INFO]:nasal     /usr/share/games/flightgear/Nasal/emexec.nas:255: EMEXEC: Adjust frequency to 20 Hz
      517.34 [INFO]:nasal     /usr/share/games/flightgear/Nasal/emexec.nas:255: EMEXEC: Adjust frequency to 30.03003003003003 Hz
    

    As far as I've tested, without video encoding, I do not see any difference between OSG affinity set by default and OSG affinity removed. I am pretty sure the folks at OSG know their business, and I am old enough to remember that, at the beginning of multicore processors, OS scheduling on threads was really a problem. But this was quite some time ago :)

     
  • Julian Smith

    Julian Smith - 2022-05-03

    Thanks for testing things.

    I've seen the same thing as you with no difference between 'none' and 'osg'; see recent post on flightgear-devel@.

    I wouldn't expect /sim/affinity-control to work on the command-line; it's only for investigation purposes anyway and is limited in what it can do - if OSG creates a thread after 'clear', the new thread will have no cpu affinity and 'revert' will not change its affinity because we won't have any remembered affinity setting to restore.

    Looking at your figures, the reduction of frame rate from 30fps to 13fps implies extra time per frame of 1/13-1/30 = 0.044s. (So upper bound for framerate when recording is 1/0.044 = 22.9fps.)

    Of the 0.044s per frame, it looks like 0.014s is from sws_scale(), i.e. about 1/3 of the video encoding slowdown is from sws_scale() (running in a single-thread), and the remaining 2/3 is from the actual encoder (running on multiple threads).

    If we were to somehow eliminate sws_scale()'s delay (e.g. by running in multiple threads, giving each thread a portion of the image to convert from RGB to YUV, or by using the GPU somehow), the lower bound for encoding time per frame would be 2/3*0.044=0.029s, which would reduce 30fps frame rate to 1/(1/30+0.029) = 16.0fps.

    I notice you were ok for me to close this bug in an earlier post. The bug is mostly understood now, and fixing things properly will require wider discussion and experimentation. Also i find it much easier to communicate via emails to the mailing list than a web-based interface, so i'll close it after this post.

    Thanks,

    - Jules

     
  • Julian Smith

    Julian Smith - 2022-05-03
    • status: New --> Done
     
  • eatdirt

    eatdirt - 2022-05-03

    Yea, bug is closed. Thanks for the fixes!

     

Log in to post a comment.