tsan: Data race between gpu::Batch::clear() and gpu::Batch::Batch
This is a test of the thread sanitizer. I got it to run and it spit out a whole bunch of stuff. I picked one that seems to point to something interesting:
WARNING: ThreadSanitizer: data race (pid=1160340)
Write of size 8 at 0x7fc844e35f38 by thread T17:
#0 gpu::Batch::clear() /home/dale/git/vircadia/vircadia-master/libraries/gpu/src/gpu/Batch.cpp:77 (libgpu.so+0x270ae8)
#1 gpu::Context::releaseBatch(gpu::Batch*) /home/dale/git/vircadia/vircadia-master/libraries/gpu/src/gpu/Context.cpp:425 (libgpu.so+0x2ada00)
#2 operator() /home/dale/git/vircadia/vircadia-master/libraries/gpu/src/gpu/Context.cpp:421 (libgpu.so+0x2ad7c2)
#3 _M_dispose /usr/include/c++/10/bits/shared_ptr_base.h:474 (libgpu.so+0x2af1cc)
#4 std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release() /usr/include/c++/10/bits/shared_ptr_base.h:158 (interface+0x9cf4c9)
#5 std::__shared_count<(__gnu_cxx::_Lock_policy)2>::~__shared_count() /usr/include/c++/10/bits/shared_ptr_base.h:733 (interface+0x9c5d78)
#6 std::__shared_ptr<gpu::Batch, (__gnu_cxx::_Lock_policy)2>::~__shared_ptr() /usr/include/c++/10/bits/shared_ptr_base.h:1183 (libgpu.so+0x2b0085)
#7 std::shared_ptr<gpu::Batch>::~shared_ptr() /usr/include/c++/10/bits/shared_ptr.h:121 (libgpu.so+0x2b00b1)
#8 gpu::Context::executeBatch(char const*, std::function<void (gpu::Batch&)>) const /home/dale/git/vircadia/vircadia-master/libraries/gpu/src/gpu/Context.cpp:108 (libgpu.so+0x2ab9cf)
#9 gpu::Context::executeFrame(std::shared_ptr<gpu::Frame> const&) const /home/dale/git/vircadia/vircadia-master/libraries/gpu/src/gpu/Context.cpp:140 (libgpu.so+0x2abf76)
#10 OpenGLDisplayPlugin::present(std::shared_ptr<RefreshRateController> const&) /home/dale/git/vircadia/vircadia-master/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp:715 (libdisplay-plugins.so+0xe1da0)
#11 PresentThread::run() /home/dale/git/vircadia/vircadia-master/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp:197 (libdisplay-plugins.so+0xed7c2)
#12 <null> <null> (libQt5Core.so.5+0xbf592)
Previous read of size 8 at 0x7fc844e35f38 by thread T16:
#0 gpu::Batch::Batch(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) /home/dale/git/vircadia/vircadia-master/libraries/gpu/src/gpu/Batch.cpp:55 (libgpu.so+0x27025a)
#1 gpu::Context::acquireBatch(char const*) /home/dale/git/vircadia/vircadia-master/libraries/gpu/src/gpu/Context.cpp:416 (libgpu.so+0x2ad8be)
#2 gpu::doInBatch(char const*, std::shared_ptr<gpu::Context> const&, std::function<void (gpu::Batch&)> const&) /home/dale/git/vircadia/vircadia-master/libraries/gpu/src/gpu/Context.cpp:433 (libgpu.so+0x2ada9d)
#3 DrawLayered3D::run(std::shared_ptr<render::RenderContext> const&, task::VaryingSet4<std::vector<render::ItemBound, std::allocator<render::ItemBound> >, std::shared_ptr<LightingModel>, std::shared_ptr<HazeStage::Frame>, glm::vec<2, float, (glm::qualifier)0> > const&) /home/dale/git/vircadia/vircadia-master/libraries/render-utils/src/RenderCommonTask.cpp:81 (librender-utils.so+0xbe9a4e)
#4 void task::jobRun<DrawLayered3D, std::shared_ptr<render::RenderContext>, task::VaryingSet4<std::vector<render::ItemBound, std::allocator<render::ItemBound> >, std::shared_ptr<LightingModel>, std::shared_ptr<HazeStage::Frame>, glm::vec<2, float, (glm::qualifier)0> > >(DrawLayered3D&, std::shared_ptr<render::RenderContext> const&, task::VaryingSet4<std::vector<render::ItemBound, std::allocator<render::ItemBound> >, std::shared_ptr<LightingModel>, std::shared_ptr<HazeStage::Frame>, glm::vec<2, float, (glm::qualifier)0> > const&, task::JobNoIO&) /home/dale/git/vircadia/vircadia-master/libraries/task/src/task/Task.h:102 (librender-utils.so+0xc96795)
#5 task::Job<render::RenderContext, render::RenderTimeProfiler>::Model<DrawLayered3D, DrawLayered3DConfig, task::VaryingSet4<std::vector<render::ItemBound, std::allocator<render::ItemBound> >, std::shared_ptr<LightingModel>, std::shared_ptr<HazeStage::Frame>, glm::vec<2, float, (glm::qualifier)0> >, task::JobNoIO>::run(std::shared_ptr<render::RenderContext> const&) /home/dale/git/vircadia/vircadia-master/libraries/task/src/task/Task.h:178 (librender-utils.so+0xc8f585)
#6 task::Job<render::RenderContext, render::RenderTimeProfiler>::run(std::shared_ptr<render::RenderContext> const&) /home/dale/git/vircadia/vircadia-master/libraries/task/src/task/Task.h:216 (interface+0xc53e9c)
#7 task::Task<render::RenderContext, render::RenderTimeProfiler>::TaskModel<RenderHUDLayerTask, task::JobConfig, task::VaryingSet5<std::shared_ptr<gpu::Framebuffer>, std::shared_ptr<LightingModel>, std::vector<render::ItemBound, std::allocator<render::ItemBound> >, std::vector<render::ItemBound, std::allocator<render::ItemBound> >, std::shared_ptr<HazeStage::Frame> >, task::JobNoIO>::run(std::shared_ptr<render::RenderContext> const&) /home/dale/git/vircadia/vircadia-master/libraries/task/src/task/Task.h:334 (librender-utils.so+0xc8ec1d)
#8 task::Job<render::RenderContext, render::RenderTimeProfiler>::run(std::shared_ptr<render::RenderContext> const&) /home/dale/git/vircadia/vircadia-master/libraries/task/src/task/Task.h:216 (interface+0xc53e9c)
#9 task::Task<render::RenderContext, render::RenderTimeProfiler>::TaskModel<RenderForwardTask, RenderForwardTaskConfig, task::VaryingSet3<task::VaryingSet2<task::VaryingArray<std::vector<render::ItemBound, std::allocator<render::ItemBound> >, 9>, render::ItemSpatialTree::ItemSelection>, std::shared_ptr<LightingModel>, task::VaryingSet2<task::VaryingSet4<std::shared_ptr<LightStage::Frame>, std::shared_ptr<BackgroundStage::Frame>, std::shared_ptr<HazeStage::Frame>, std::shared_ptr<BloomStage::Frame> >, std::vector<render::ItemBound, std::allocator<render::ItemBound> > > >, task::JobNoIO>::run(std::shared_ptr<render::RenderContext> const&) /home/dale/git/vircadia/vircadia-master/libraries/task/src/task/Task.h:334 (librender-utils.so+0xd241e1)
#10 task::Job<render::RenderContext, render::RenderTimeProfiler>::run(std::shared_ptr<render::RenderContext> const&) /home/dale/git/vircadia/vircadia-master/libraries/task/src/task/Task.h:216 (interface+0xc53e9c)
#11 task::Switch<render::RenderContext, render::RenderTimeProfiler>::SwitchModel<DeferredForwardSwitchJob, task::JobConfig, task::VaryingSet3<task::VaryingSet2<task::VaryingArray<std::vector<render::ItemBound, std::allocator<render::ItemBound> >, 9>, render::ItemSpatialTree::ItemSelection>, std::shared_ptr<LightingModel>, task::VaryingSet2<task::VaryingSet4<std::shared_ptr<LightStage::Frame>, std::shared_ptr<BackgroundStage::Frame>, std::shared_ptr<HazeStage::Frame>, std::shared_ptr<BloomStage::Frame> >, std::vector<render::ItemBound, std::allocator<render::ItemBound> > > >, task::JobNoIO>::run(std::shared_ptr<render::RenderContext> const&) /home/dale/git/vircadia/vircadia-master/libraries/task/src/task/Task.h:475 (librender-utils.so+0xd24cb3)
#12 task::Job<render::RenderContext, render::RenderTimeProfiler>::run(std::shared_ptr<render::RenderContext> const&) /home/dale/git/vircadia/vircadia-master/libraries/task/src/task/Task.h:216 (interface+0xc53e9c)
#13 task::Task<render::RenderContext, render::RenderTimeProfiler>::TaskModel<RenderViewTask, task::JobConfig, task::VaryingSet2<task::VaryingArray<std::vector<render::ItemBound, std::allocator<render::ItemBound> >, 9>, render::ItemSpatialTree::ItemSelection>, task::JobNoIO>::run(std::shared_ptr<render::RenderContext> const&) /home/dale/git/vircadia/vircadia-master/libraries/task/src/task/Task.h:334 (interface+0xc53bcf)
#14 task::Job<render::RenderContext, render::RenderTimeProfiler>::run(std::shared_ptr<render::RenderContext> const&) /home/dale/git/vircadia/vircadia-master/libraries/task/src/task/Task.h:216 (interface+0xc53e9c)
#15 task::Task<render::RenderContext, render::RenderTimeProfiler>::TaskModel<EngineTask, task::JobConfig, task::JobNoIO, task::JobNoIO>::run(std::shared_ptr<render::RenderContext> const&) <null> (librender.so+0x256151)
#16 task::Job<render::RenderContext, render::RenderTimeProfiler>::run(std::shared_ptr<render::RenderContext> const&) /home/dale/git/vircadia/vircadia-master/libraries/task/src/task/Task.h:216 (interface+0xc53e9c)
#17 task::Engine<render::RenderContext, render::RenderTimeProfiler>::run(std::shared_ptr<render::RenderContext> const&) <null> (librender.so+0x25623b)
#18 task::Engine<render::RenderContext, render::RenderTimeProfiler>::run() /home/dale/git/vircadia/vircadia-master/libraries/task/src/task/Task.h:517 (interface+0xdf33e4)
#19 GraphicsEngine::render_runRenderFrame(render::Args*) /home/dale/git/vircadia/vircadia-master/interface/src/graphics/GraphicsEngine.cpp:126 (interface+0xde75b3)
#20 GraphicsEngine::render_performFrame() /home/dale/git/vircadia/vircadia-master/interface/src/graphics/GraphicsEngine.cpp:286 (interface+0xde8b52)
#21 operator() /home/dale/git/vircadia/vircadia-master/interface/src/graphics/GraphicsEngine.cpp:48 (interface+0xde6c1f)
#22 __invoke_impl<void, GraphicsEngine::initializeGPU(GLWidget*)::<lambda()>&> /usr/include/c++/10/bits/invoke.h:60 (interface+0xdeae23)
#23 __invoke_r<void, GraphicsEngine::initializeGPU(GLWidget*)::<lambda()>&> /usr/include/c++/10/bits/invoke.h:153 (interface+0xdea30a)
#24 _M_invoke /usr/include/c++/10/bits/std_function.h:291 (interface+0xde99cf)
#25 std::function<void ()>::operator()() const /usr/include/c++/10/bits/std_function.h:622 (interface+0xab800c)
#26 RenderEventHandler::render() /home/dale/git/vircadia/vircadia-master/interface/src/graphics/RenderEventHandler.cpp:42 (interface+0xe090c8)
#27 RenderEventHandler::event(QEvent*) /home/dale/git/vircadia/vircadia-master/interface/src/graphics/RenderEventHandler.cpp:49 (interface+0xe09125)
#28 QApplicationPrivate::notify_helper(QObject*, QEvent*) <null> (libQt5Widgets.so.5+0x1672a1)
#29 QCoreApplication::notifyInternal2(QObject*, QEvent*) <null> (libQt5Core.so.5+0x27bd21)
Location is global 'gpu::Batch::_drawCallInfosMax' of size 8 at 0x7fc844e35f38 (libgpu.so+0x000000482f38)
Thread T17 'Presentation Th' (tid=1160516, running) created by main thread at:
#0 pthread_create <null> (libtsan.so.0+0x59536)
#1 QThread::start(QThread::Priority) <null> (libQt5Core.so.5+0xbf0eb)
#2 Application::setDisplayPlugin(std::shared_ptr<DisplayPlugin>) /home/dale/git/vircadia/vircadia-master/interface/src/Application.cpp:9059 (interface+0xa680fc)
#3 Application::initializeDisplayPlugins() /home/dale/git/vircadia/vircadia-master/interface/src/Application.cpp:3168 (interface+0xa2c208)
#4 Application::Application(int&, char**, QElapsedTimer&, bool) /home/dale/git/vircadia/vircadia-master/interface/src/Application.cpp:1536 (interface+0xa20de7)
#5 main /home/dale/git/vircadia/vircadia-master/interface/src/main.cpp:381 (interface+0xe1a918)
Thread T16 'RenderThread' (tid=1160515, running) created by main thread at:
#0 pthread_create <null> (libtsan.so.0+0x59536)
#1 QThread::start(QThread::Priority) <null> (libQt5Core.so.5+0xbf0eb)
#2 RenderEventHandler::RenderEventHandler(std::function<bool ()>, std::function<void ()>) /home/dale/git/vircadia/vircadia-master/interface/src/graphics/RenderEventHandler.cpp:23 (interface+0xe08d34)
#3 GraphicsEngine::initializeGPU(GLWidget*) /home/dale/git/vircadia/vircadia-master/interface/src/graphics/GraphicsEngine.cpp:49 (interface+0xde6d0a)
#4 Application::initializeGL() /home/dale/git/vircadia/vircadia-master/interface/src/Application.cpp:3129 (interface+0xa2b843)
#5 Application::Application(int&, char**, QElapsedTimer&, bool) /home/dale/git/vircadia/vircadia-master/interface/src/Application.cpp:1532 (interface+0xa20d76)
#6 main /home/dale/git/vircadia/vircadia-master/interface/src/main.cpp:381 (interface+0xe1a918)
SUMMARY: ThreadSanitizer: data race /home/dale/git/vircadia/vircadia-master/libraries/gpu/src/gpu/Batch.cpp:77 in gpu::Batch::clear()
Batch.cpp:55 is:
_drawCallInfos.reserve(_drawCallInfosMax);
Batch.cpp:77 is:
_drawCallInfosMax = std::max(_drawCallInfos.size(), _drawCallInfosMax);
So Batch::clear() is running at the same time as the same object's constructor?
Note that my research indicates that false positives are possible, and it's in beta.
if you look in Context.cpp at acquireBatch/releaseBatch, there seems to be something going on with the recycling of Batches and the custom destructor...
I’m not sure I totally see the issue, but you could try locking the mutex around the entire body of both methods. it seems like that would stop any race?
Hello! Is this still an issue?
Hello! Is this still an issue?