Introduced OpenThreads::Affinity support into osg::Camera, osg::GraphicsContext::Traitse, osgDB::DatabasePager and osgViewer::ViewerBase/Viewer/CompositeViewer.

Added ViewerBase::configureAffinity() to help with the setting of the affinity of camera, graphics context and pager threads
This commit is contained in:
Robert Osfield 2016-09-28 18:44:58 +01:00
parent 77c5e96ccb
commit ee97db3488
10 changed files with 161 additions and 91 deletions

View File

@ -541,6 +541,11 @@ class OSG_EXPORT Camera : public Transform, public CullSettings
} }
} }
/** Set the process affinity hint for any Camera Threads that are/will be assigned to this Camera.*/
void setProcessorAffinity(const OpenThreads::Affinity& affinity);
OpenThreads::Affinity& getProcessorAffinity() { return _affinity; }
const OpenThreads::Affinity& getProcessorAffinity() const { return _affinity; }
/** Create a operation thread for this camera.*/ /** Create a operation thread for this camera.*/
void createCameraThread(); void createCameraThread();
@ -707,6 +712,7 @@ class OSG_EXPORT Camera : public Transform, public CullSettings
unsigned int _attachmentMapModifiedCount; unsigned int _attachmentMapModifiedCount;
OpenThreads::Affinity _affinity;
ref_ptr<OperationThread> _cameraThread; ref_ptr<OperationThread> _cameraThread;
ref_ptr<GraphicsContext> _graphicsContext; ref_ptr<GraphicsContext> _graphicsContext;

View File

@ -145,6 +145,9 @@ class OSG_EXPORT GraphicsContext : public Object
bool overrideRedirect; bool overrideRedirect;
DisplaySettings::SwapMethod swapMethod; DisplaySettings::SwapMethod swapMethod;
// hint of what affinity to use for any thrads associated with the graphics context created using these Traits
OpenThreads::Affinity affinity;
}; };
/** Simple resolution structure used by WindowingSystemInterface to get and set screen resolution. /** Simple resolution structure used by WindowingSystemInterface to get and set screen resolution.

View File

@ -126,9 +126,9 @@ class OSGDB_EXPORT DatabasePager : public osg::NodeVisitor::DatabaseRequestHandl
}; };
virtual void setProcessorAffinty(const OpenThreads::Affinity& affinity); virtual void setProcessorAffinity(const OpenThreads::Affinity& affinity);
OpenThreads::Affinity& getProcessorAffinty() { return _affinity; } OpenThreads::Affinity& getProcessorAffinity() { return _affinity; }
const OpenThreads::Affinity& getProcessorAffinty() const { return _affinity; } const OpenThreads::Affinity& getProcessorAffinity() const { return _affinity; }
void setUpThreads(unsigned int totalNumThreads=2, unsigned int numHttpThreads=1); void setUpThreads(unsigned int totalNumThreads=2, unsigned int numHttpThreads=1);

View File

@ -59,6 +59,15 @@ class OSGVIEWER_EXPORT ViewerBase : public virtual osg::Object
/** set up windows and associated threads.*/ /** set up windows and associated threads.*/
virtual void realize() = 0; virtual void realize() = 0;
/** analyse the viewer configuration and select an appropriate Affinity for main thread, and any graphics, camera threads and database pagers that are required.*/
virtual void configureAffinity();
/** Set the processor affinity of main thread.*/
virtual void setProcessorAffinty(const OpenThreads::Affinity& affinity) { _affinity = affinity; }
OpenThreads::Affinity& getProcessorAffinty() { return _affinity; }
const OpenThreads::Affinity& getProcessorAffinty() const { return _affinity; }
enum ThreadingModel enum ThreadingModel
{ {
SingleThreaded, SingleThreaded,
@ -318,6 +327,7 @@ protected:
bool _quitEventSetsDone; bool _quitEventSetsDone;
bool _releaseContextAtEndOfFrameHint; bool _releaseContextAtEndOfFrameHint;
OpenThreads::Affinity _affinity;
ThreadingModel _threadingModel; ThreadingModel _threadingModel;
bool _threadsRunning; bool _threadsRunning;

View File

@ -74,6 +74,7 @@ Camera::Camera(const Camera& camera,const CopyOp& copyop):
_implicitBufferAttachmentRenderMask(camera._implicitBufferAttachmentRenderMask), _implicitBufferAttachmentRenderMask(camera._implicitBufferAttachmentRenderMask),
_implicitBufferAttachmentResolveMask(camera._implicitBufferAttachmentResolveMask), _implicitBufferAttachmentResolveMask(camera._implicitBufferAttachmentResolveMask),
_attachmentMapModifiedCount(camera._attachmentMapModifiedCount), _attachmentMapModifiedCount(camera._attachmentMapModifiedCount),
_affinity(camera._affinity),
_initialDrawCallback(camera._initialDrawCallback), _initialDrawCallback(camera._initialDrawCallback),
_preDrawCallback(camera._preDrawCallback), _preDrawCallback(camera._preDrawCallback),
_postDrawCallback(camera._postDrawCallback), _postDrawCallback(camera._postDrawCallback),
@ -521,6 +522,12 @@ void Camera::resize(int width, int height, int resizeMask)
} }
} }
void Camera::setProcessorAffinity(const OpenThreads::Affinity& affinity)
{
_affinity = affinity;
if (_cameraThread.valid()) _cameraThread->setProcessorAffinity(affinity);
}
void Camera::createCameraThread() void Camera::createCameraThread()
{ {
@ -543,6 +550,8 @@ void Camera::setCameraThread(OperationThread* gt)
_cameraThread = gt; _cameraThread = gt;
_cameraThread->setProcessorAffinity(_affinity);
if (_cameraThread.valid()) if (_cameraThread.valid())
{ {
_cameraThread->setParent(this); _cameraThread->setParent(this);

View File

@ -589,6 +589,11 @@ void GraphicsContext::createGraphicsThread()
if (!_graphicsThread) if (!_graphicsThread)
{ {
setGraphicsThread(new GraphicsThread); setGraphicsThread(new GraphicsThread);
if (_traits.valid())
{
_graphicsThread->setProcessorAffinity(_traits->affinity);
}
} }
} }

View File

@ -1190,7 +1190,7 @@ DatabasePager::DatabasePager(const DatabasePager& rhs)
_databaseThreads.push_back(new DatabaseThread(**dt_itr,this)); _databaseThreads.push_back(new DatabaseThread(**dt_itr,this));
} }
setProcessorAffinty(rhs.getProcessorAffinty()); setProcessorAffinity(rhs.getProcessorAffinity());
_activePagedLODList = rhs._activePagedLODList->clone(); _activePagedLODList = rhs._activePagedLODList->clone();
@ -1249,7 +1249,7 @@ DatabasePager* DatabasePager::create()
new DatabasePager; new DatabasePager;
} }
void DatabasePager::setProcessorAffinty(const OpenThreads::Affinity& affinity) void DatabasePager::setProcessorAffinity(const OpenThreads::Affinity& affinity)
{ {
_affinity = affinity; _affinity = affinity;

View File

@ -627,7 +627,6 @@ void CompositeViewer::realize()
// attach contexts to _incrementalCompileOperation if attached. // attach contexts to _incrementalCompileOperation if attached.
if (_incrementalCompileOperation) _incrementalCompileOperation->assignContexts(contexts); if (_incrementalCompileOperation) _incrementalCompileOperation->assignContexts(contexts);
bool grabFocus = true; bool grabFocus = true;
if (grabFocus) if (grabFocus)
{ {
@ -655,9 +654,6 @@ void CompositeViewer::realize()
if (osg::DisplaySettings::instance()->getCompileContextsHint()) if (osg::DisplaySettings::instance()->getCompileContextsHint())
{ {
int numProcessors = osg::maximum(1, OpenThreads::GetNumberOfProcessors());
int processNum = 0;
for(unsigned int i=0; i<= osg::GraphicsContext::getMaxContextID(); ++i) for(unsigned int i=0; i<= osg::GraphicsContext::getMaxContextID(); ++i)
{ {
osg::GraphicsContext* gc = osg::GraphicsContext::getOrCreateCompileContext(i); osg::GraphicsContext* gc = osg::GraphicsContext::getOrCreateCompileContext(i);
@ -665,10 +661,7 @@ void CompositeViewer::realize()
if (gc) if (gc)
{ {
gc->createGraphicsThread(); gc->createGraphicsThread();
gc->getGraphicsThread()->setProcessorAffinity(processNum % numProcessors);
gc->getGraphicsThread()->startThread(); gc->getGraphicsThread()->startThread();
++processNum;
} }
} }
} }

View File

@ -171,12 +171,12 @@ Viewer::Viewer(osg::ArgumentParser& arguments)
if (ss3d) if (ss3d)
{ {
setThreadingModel(SingleThreaded); //setThreadingModel(SingleThreaded);
setUpViewFor3DSphericalDisplay(radius, collar, screenNum, intensityMap.get()); setUpViewFor3DSphericalDisplay(radius, collar, screenNum, intensityMap.get());
} }
else else
{ {
setThreadingModel(SingleThreaded); //setThreadingModel(SingleThreaded);
setUpViewForPanoramicSphericalDisplay(radius, collar, screenNum, intensityMap.get()); setUpViewForPanoramicSphericalDisplay(radius, collar, screenNum, intensityMap.get());
} }
} }
@ -604,9 +604,6 @@ void Viewer::realize()
if (osg::DisplaySettings::instance()->getCompileContextsHint()) if (osg::DisplaySettings::instance()->getCompileContextsHint())
{ {
int numProcessors = osg::maximum(1, OpenThreads::GetNumberOfProcessors());
int processNum = 0;
for(unsigned int i=0; i<= osg::GraphicsContext::getMaxContextID(); ++i) for(unsigned int i=0; i<= osg::GraphicsContext::getMaxContextID(); ++i)
{ {
osg::GraphicsContext* gc = osg::GraphicsContext::getOrCreateCompileContext(i); osg::GraphicsContext* gc = osg::GraphicsContext::getOrCreateCompileContext(i);
@ -614,10 +611,7 @@ void Viewer::realize()
if (gc) if (gc)
{ {
gc->createGraphicsThread(); gc->createGraphicsThread();
gc->getGraphicsThread()->setProcessorAffinity(processNum % numProcessors);
gc->getGraphicsThread()->startThread(); gc->getGraphicsThread()->startThread();
++processNum;
} }
} }
} }

View File

@ -57,6 +57,7 @@ void ViewerBase::viewerBaseInit()
_keyEventSetsDone = osgGA::GUIEventAdapter::KEY_Escape; _keyEventSetsDone = osgGA::GUIEventAdapter::KEY_Escape;
_quitEventSetsDone = true; _quitEventSetsDone = true;
_releaseContextAtEndOfFrameHint = true; _releaseContextAtEndOfFrameHint = true;
_threadingModel = AutomaticSelection; _threadingModel = AutomaticSelection;
_threadsRunning = false; _threadsRunning = false;
_endBarrierPosition = AfterSwapBuffers; _endBarrierPosition = AfterSwapBuffers;
@ -81,6 +82,95 @@ void ViewerBase::viewerBaseInit()
} }
} }
void ViewerBase::configureAffinity()
{
unsigned int numProcessors = OpenThreads::GetNumberOfProcessors();
OSG_NOTICE<<"ViewerBase::configureAffinity() numProcessors="<<numProcessors<<std::endl;
if (numProcessors==1) return;
bool requiresCameraThreads = false;
bool requiresDrawThreads = false;
switch(_threadingModel)
{
case(CullDrawThreadPerContext):
requiresDrawThreads = true;
break;
case(DrawThreadPerContext):
requiresDrawThreads = true;
break;
case(CullThreadPerCameraDrawThreadPerContext):
requiresCameraThreads = true;
requiresDrawThreads = true;
break;
default:
break;
};
unsigned int availableProcessor = 0;
_affinity = OpenThreads::Affinity(availableProcessor++);
if (requiresCameraThreads)
{
Cameras cameras;
getCameras(cameras);
for(Cameras::iterator itr = cameras.begin();
itr != cameras.end();
++itr)
{
(*itr)->setProcessorAffinity(OpenThreads::Affinity((availableProcessor++)%numProcessors));
}
}
if (requiresDrawThreads)
{
Contexts contexts;
getContexts(contexts);
for(Contexts::iterator itr = contexts.begin();
itr != contexts.end();
++itr)
{
if ((*itr)->getTraits())
{
osg::GraphicsContext::Traits* traits = const_cast<osg::GraphicsContext::Traits*>((*itr)->getTraits());
traits->affinity = OpenThreads::Affinity((availableProcessor++)%numProcessors);
}
}
}
if (availableProcessor<numProcessors)
{
Scenes scenes;
getScenes(scenes);
typedef std::list<osgDB::DatabasePager*> DatabasePagers;
DatabasePagers databasePagers;
for(Scenes::iterator itr = scenes.begin();
itr != scenes.end();
++itr)
{
if ((*itr)->getDatabasePager()) databasePagers.push_back((*itr)->getDatabasePager());
}
OSG_NOTICE<<" databasePagers = "<<databasePagers.size()<<std::endl;
for(DatabasePagers::iterator itr = databasePagers.begin();
itr != databasePagers.end();
++itr)
{
(*itr)->setProcessorAffinity(OpenThreads::Affinity(availableProcessor, numProcessors-availableProcessor));
}
}
}
void ViewerBase::setThreadingModel(ThreadingModel threadingModel) void ViewerBase::setThreadingModel(ThreadingModel threadingModel)
{ {
if (_threadingModel == threadingModel) return; if (_threadingModel == threadingModel) return;
@ -140,37 +230,40 @@ ViewerBase::ThreadingModel ViewerBase::suggestBestThreadingModel()
void ViewerBase::setUpThreading() void ViewerBase::setUpThreading()
{ {
if (_threadingModel==AutomaticSelection)
{
_threadingModel = suggestBestThreadingModel();
}
// configure affinity before we start threads
configureAffinity();
Contexts contexts; Contexts contexts;
getContexts(contexts); getContexts(contexts);
// set up affinity of main thread
OpenThreads::SetProcessorAffinityOfCurrentThread(_affinity);
// set up the number of graphics contexts.
{
Scenes scenes;
getScenes(scenes);
for(Scenes::iterator scitr = scenes.begin();
scitr != scenes.end();
++scitr)
{
if ((*scitr)->getSceneData())
{
// update the scene graph so that it has enough GL object buffer memory for the graphics contexts that will be using it.
(*scitr)->getSceneData()->resizeGLObjectBuffers(osg::DisplaySettings::instance()->getMaxNumberOfGraphicsContexts());
}
}
}
if (_threadingModel==SingleThreaded) if (_threadingModel==SingleThreaded)
{ {
if (_threadsRunning) stopThreading(); if (_threadsRunning) stopThreading();
else
{
// we'll set processor affinity here to help single threaded apps
// with multiple processor cores, and using the database pager.
int numProcessors = OpenThreads::GetNumberOfProcessors();
bool affinity = numProcessors>1;
if (affinity)
{
OpenThreads::SetProcessorAffinityOfCurrentThread(0);
Scenes scenes;
getScenes(scenes);
for(Scenes::iterator scitr = scenes.begin();
scitr != scenes.end();
++scitr)
{
if ((*scitr)->getSceneData())
{
// update the scene graph so that it has enough GL object buffer memory for the graphics contexts that will be using it.
(*scitr)->getSceneData()->resizeGLObjectBuffers(osg::DisplaySettings::instance()->getMaxNumberOfGraphicsContexts());
}
}
}
}
} }
else else
{ {
@ -272,8 +365,6 @@ void ViewerBase::startThreading()
// release any context held by the main thread. // release any context held by the main thread.
releaseContext(); releaseContext();
_threadingModel = _threadingModel==AutomaticSelection ? suggestBestThreadingModel() : _threadingModel;
Contexts contexts; Contexts contexts;
getContexts(contexts); getContexts(contexts);
@ -325,9 +416,6 @@ void ViewerBase::startThreading()
} }
} }
int numProcessors = osg::maximum(1, OpenThreads::GetNumberOfProcessors());
bool affinity = numProcessors>1;
Contexts::iterator citr; Contexts::iterator citr;
unsigned int numViewerDoubleBufferedRenderingOperation = 0; unsigned int numViewerDoubleBufferedRenderingOperation = 0;
@ -383,13 +471,9 @@ void ViewerBase::startThreading()
osg::ref_ptr<osg::SwapBuffersOperation> swapOp = new osg::SwapBuffersOperation(); osg::ref_ptr<osg::SwapBuffersOperation> swapOp = new osg::SwapBuffersOperation();
typedef std::map<OpenThreads::Thread*, int> ThreadAffinityMap;
ThreadAffinityMap threadAffinityMap;
unsigned int processNum = 1;
for(citr = contexts.begin(); for(citr = contexts.begin();
citr != contexts.end(); citr != contexts.end();
++citr, ++processNum) ++citr)
{ {
osg::GraphicsContext* gc = (*citr); osg::GraphicsContext* gc = (*citr);
@ -404,9 +488,6 @@ void ViewerBase::startThreading()
// create the a graphics thread for this context // create the a graphics thread for this context
gc->createGraphicsThread(); gc->createGraphicsThread();
if (affinity) gc->getGraphicsThread()->setProcessorAffinity(processNum % numProcessors);
threadAffinityMap[gc->getGraphicsThread()] = processNum % numProcessors;
// add the startRenderingBarrier // add the startRenderingBarrier
if (_threadingModel==CullDrawThreadPerContext && _startRenderingBarrier.valid()) gc->getGraphicsThread()->add(_startRenderingBarrier.get()); if (_threadingModel==CullDrawThreadPerContext && _startRenderingBarrier.valid()) gc->getGraphicsThread()->add(_startRenderingBarrier.get());
@ -438,14 +519,11 @@ void ViewerBase::startThreading()
for(camItr = cameras.begin(); for(camItr = cameras.begin();
camItr != cameras.end(); camItr != cameras.end();
++camItr, ++processNum) ++camItr)
{ {
osg::Camera* camera = *camItr; osg::Camera* camera = *camItr;
camera->createCameraThread(); camera->createCameraThread();
if (affinity) camera->getCameraThread()->setProcessorAffinity(processNum % numProcessors);
threadAffinityMap[camera->getCameraThread()] = processNum % numProcessors;
osg::GraphicsContext* gc = camera->getGraphicsContext(); osg::GraphicsContext* gc = camera->getGraphicsContext();
// add the startRenderingBarrier // add the startRenderingBarrier
@ -479,34 +557,6 @@ void ViewerBase::startThreading()
} }
} }
#if 0
if (affinity)
{
OpenThreads::SetProcessorAffinityOfCurrentThread(0);
if (_scene.valid() && _scene->getDatabasePager())
{
#if 0
_scene->getDatabasePager()->setProcessorAffinity(1);
#else
_scene->getDatabasePager()->setProcessorAffinity(0);
#endif
}
}
#endif
#if 0
if (affinity)
{
for(ThreadAffinityMap::iterator titr = threadAffinityMap.begin();
titr != threadAffinityMap.end();
++titr)
{
titr->first->setProcessorAffinity(titr->second);
}
}
#endif
for(citr = contexts.begin(); for(citr = contexts.begin();
citr != contexts.end(); citr != contexts.end();
++citr) ++citr)