vircadia-native-core icon indicating copy to clipboard operation
vircadia-native-core copied to clipboard

tsan: Data race between gpu::Batch::clear() and gpu::Batch::Batch

Open daleglass opened this issue 5 years ago • 3 comments

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.

daleglass avatar Apr 02 '21 23:04 daleglass

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?

HifiExperiments avatar Apr 03 '21 06:04 HifiExperiments

Hello! Is this still an issue?

stale[bot] avatar Oct 07 '21 20:10 stale[bot]

Hello! Is this still an issue?

stale[bot] avatar Aug 09 '22 23:08 stale[bot]