Re #132 : Added inhibitable thread affinity (OK under WinXP, WIP under Linux)

git-svn-id: https://svn.code.sf.net/p/speed-dreams/code/trunk@2565 30fe4595-0a0c-4342-8851-515496e4dcbd

Former-commit-id: e213dd158c71de0e304ae0256c3e8d6be540e805
Former-commit-id: fe3be73c8454a434f87f9df725ec2137ac4385d7
This commit is contained in:
pouillot 2010-07-13 20:56:47 +00:00
parent 0184e27872
commit a7757a2b0d
11 changed files with 420 additions and 164 deletions

View file

@ -348,6 +348,11 @@ typedef struct RmInfo
#define RM_VAL_MORE_CLOUDS "more clouds"
#define RM_VAL_OVERCAST_CLOUDS "overcast clouds"
#define RM_VAL_NO_CLOUDS "no clouds"
#define RM_VAL_SCARCE_CLOUDS "scarce clouds"
#define RM_VAL_MORE_CLOUDS "more clouds"
#define RM_VAL_OVERCAST_CLOUDS "overcast clouds"
/* Movie capture */
#define RM_SECT_MOVIE_CAPTURE "Movie Capture"
@ -393,6 +398,7 @@ typedef struct RmInfo
#define RM_SECT_RACE_ENGINE "Race Engine"
#define RM_ATTR_MULTI_THREADING "multi-threading"
#define RM_ATTR_THREAD_AFFINITY "thread affinity"
#define RM_VAL_AUTO "auto"
#define RM_VAL_ON "on"

View file

@ -44,25 +44,33 @@ static int CurSimuVersion = 0;
static const char *MultiThreadSchemeList[] = {RM_VAL_AUTO, RM_VAL_ON, RM_VAL_OFF};
static const int NbMultiThreadSchemes = sizeof(MultiThreadSchemeList) / sizeof(MultiThreadSchemeList[0]);
/* list of available thread affinity schemes */
static const char *ThreadAffinitySchemeList[] = {RM_VAL_ON, RM_VAL_OFF};
static const int NbThreadAffinitySchemes = sizeof(ThreadAffinitySchemeList) / sizeof(ThreadAffinitySchemeList[0]);
#ifdef ReMultiThreaded
static int CurMultiThreadScheme = 0;
static int CurMultiThreadScheme = 0; // Auto
static int CurThreadAffinityScheme = 0; // On
#else
static int CurMultiThreadScheme = 2;
static int CurMultiThreadScheme = 2; // Off
static int CurThreadAffinityScheme = 1; // Off
#endif
/* gui label ids */
static int SimuVersionId;
static int MultiThreadSchemeId;
static int ThreadAffinitySchemeId;
/* gui screen handles */
static void *ScrHandle = NULL;
static void *PrevScrHandle = NULL;
static void *ScrHandle = NULL;
static void *PrevScrHandle = NULL;
static void loadSimuCfg(void)
{
const char *simuVersionName;
const char *multiThreadSchemeName;
const char *threadAffinitySchemeName;
int i;
char buf[1024];
@ -88,12 +96,21 @@ static void loadSimuCfg(void)
}
}
threadAffinitySchemeName = GfParmGetStr(paramHandle, RM_SECT_RACE_ENGINE, RM_ATTR_THREAD_AFFINITY, ThreadAffinitySchemeList[0]);
for (i = 0; i < NbThreadAffinitySchemes; i++) {
if (strcmp(threadAffinitySchemeName, ThreadAffinitySchemeList[i]) == 0) {
CurThreadAffinityScheme = i;
break;
}
}
#endif
GfParmReleaseHandle(paramHandle);
GfuiLabelSetText(ScrHandle, SimuVersionId, SimuVersionList[CurSimuVersion]);
GfuiLabelSetText(ScrHandle, MultiThreadSchemeId, MultiThreadSchemeList[CurMultiThreadScheme]);
GfuiLabelSetText(ScrHandle, ThreadAffinitySchemeId, ThreadAffinitySchemeList[CurThreadAffinityScheme]);
}
@ -106,6 +123,7 @@ static void storeSimuCfg(void * /* dummy */)
void *paramHandle = GfParmReadFile(buf, GFPARM_RMODE_REREAD | GFPARM_RMODE_CREAT);
GfParmSetStr(paramHandle, RM_SECT_MODULES, RM_ATTR_MOD_SIMU, SimuVersionList[CurSimuVersion]);
GfParmSetStr(paramHandle, RM_SECT_RACE_ENGINE, RM_ATTR_MULTI_THREADING, MultiThreadSchemeList[CurMultiThreadScheme]);
GfParmSetStr(paramHandle, RM_SECT_RACE_ENGINE, RM_ATTR_THREAD_AFFINITY, ThreadAffinitySchemeList[CurThreadAffinityScheme]);
GfParmWriteFile(NULL, paramHandle, "raceengine");
GfParmReleaseHandle(paramHandle);
@ -114,24 +132,35 @@ static void storeSimuCfg(void * /* dummy */)
return;
}
/* change the simulation version */
/* Change the simulation version */
static void
onChangeSimuVersion(void *vp)
{
CurSimuVersion = (CurSimuVersion + NbSimuVersions + (int)(long)vp) % NbSimuVersions;
GfuiLabelSetText(ScrHandle, SimuVersionId, SimuVersionList[CurSimuVersion]);
GfuiLabelSetText(ScrHandle, SimuVersionId, SimuVersionList[CurSimuVersion]);
}
/* change the multi-threading scheme */
/* Change the multi-threading scheme */
static void
onChangeMultiThreadScheme(void *vp)
{
CurMultiThreadScheme =
(CurMultiThreadScheme + NbMultiThreadSchemes + (int)(long)vp) % NbMultiThreadSchemes;
GfuiLabelSetText(ScrHandle, MultiThreadSchemeId, MultiThreadSchemeList[CurMultiThreadScheme]);
GfuiLabelSetText(ScrHandle, MultiThreadSchemeId, MultiThreadSchemeList[CurMultiThreadScheme]);
}
/* Change the thread affinity scheme */
static void
onChangeThreadAffinityScheme(void *vp)
{
CurThreadAffinityScheme =
(CurThreadAffinityScheme + NbThreadAffinitySchemes + (int)(long)vp) % NbThreadAffinitySchemes;
GfuiLabelSetText(ScrHandle, ThreadAffinitySchemeId, ThreadAffinitySchemeList[CurThreadAffinityScheme]);
}
@ -166,6 +195,13 @@ SimuMenuInit(void *prevMenu)
CreateButtonControl(ScrHandle, menuDescHdle, "mthreadleftarrow", (void*)-1, onChangeMultiThreadScheme);
CreateButtonControl(ScrHandle, menuDescHdle, "mthreadrightarrow", (void*)1, onChangeMultiThreadScheme);
#endif
ThreadAffinitySchemeId = CreateLabelControl(ScrHandle, menuDescHdle, "threadafflabel");
#ifdef ReMultiThreaded
CreateButtonControl(ScrHandle, menuDescHdle, "threadaffleftarrow", (void*)-1, onChangeThreadAffinityScheme);
CreateButtonControl(ScrHandle, menuDescHdle, "threadaffrightarrow", (void*)1, onChangeThreadAffinityScheme);
#endif
CreateButtonControl(ScrHandle, menuDescHdle, "accept", PrevScrHandle, storeSimuCfg);
CreateButtonControl(ScrHandle, menuDescHdle, "cancel", PrevScrHandle, GfuiScreenActivate);

View file

@ -66,6 +66,11 @@ tRmInfo* ReGetSituation()
#include "SDL/SDL.h"
#include "SDL/SDL_thread.h"
// Index of the CPU to use for thread affinity if any and if there are at least 2 ones.
static const int NGraphicsCPUId = 0;
static const int NUpdaterCPUId = 1;
// The situation updater thread class.
class reSituationUpdater
{
public:
@ -134,6 +139,9 @@ private:
//! True if the updater is actually threaded (may be not the case)
bool _bThreaded;
//! True if thread affinity has to be applied (even in case !_bThreaded)
bool _bThreadAffinity;
//! Flag to set in order to terminate the updater.
bool _bTerminate;
};
@ -1301,6 +1309,11 @@ int reSituationUpdater::threadLoop()
// Current real time.
double realTime;
// Apply thread affinity to the current = situation updater thread if specified.
// Note: No need to reset the affinity, as the thread is just born.
if (_bThreadAffinity)
GfSetThreadAffinity(NUpdaterCPUId);
GfOut("SituationUpdater thread is started.\n");
do
@ -1370,7 +1383,8 @@ reSituationUpdater::reSituationUpdater(tRmInfo* pReInfo)
_pCurrReInfo = pReInfo;
_nInitDrivers = _pCurrReInfo->s->_ncars;
// No dedicated thread if only 1 CPU/core.
// Determine if we have a dedicated separate thread or not
// (according to the user settings, and the actual number of CPUs).
snprintf(buf, 1024, "%s%s", GetLocalDir(), RACE_ENG_CFG);
void *paramHandle = GfParmReadFile(buf, GFPARM_RMODE_REREAD | GFPARM_RMODE_CREAT);
const char* pszMultiThreadScheme =
@ -1383,8 +1397,19 @@ reSituationUpdater::reSituationUpdater(tRmInfo* pReInfo)
else // Can't be anything else than RM_VAL_AUTO
_bThreaded = GfGetNumberOfCPUs() > 1;
// Determine if we apply some thread affinity or not (according to the user settings).
const char* pszThreadAffinityScheme =
GfParmGetStr(paramHandle, RM_SECT_RACE_ENGINE, RM_ATTR_THREAD_AFFINITY, RM_VAL_OFF);
_bThreadAffinity = strcmp(pszThreadAffinityScheme, RM_VAL_ON) == 0;
GfParmReleaseHandle(paramHandle);
// Apply thread affinity to the current = main = graphics thread
// (and don't forget to reset it when specified :
// user settings may have changed since last race).
GfSetThreadAffinity(_bThreadAffinity ? NGraphicsCPUId : GfAffinityAnyCPU);
// Initialize termination flag.
_bTerminate = false;
if (_bThreaded)
@ -1404,6 +1429,9 @@ reSituationUpdater::reSituationUpdater(tRmInfo* pReInfo)
_pDataMutex = 0;
_pUpdateThread = 0;
}
GfOut("SituationUpdater initialized (%sseparate thread, CPU affinity %s).\n",
(_bThreaded ? "" : "no "), (_bThreadAffinity ? "On" : "Off"));
}
reSituationUpdater::~reSituationUpdater()

View file

@ -14,7 +14,7 @@
<!DOCTYPE params SYSTEM "../tgf/params.dtd">
<params name="" type="template" mode="mw" version="1.1">
<params name="" type="template" mode="mw" version="1.2">
<section name="Modules">
<attstr name="track" val="track"/>
@ -30,6 +30,7 @@
<section name="Race Engine">
<attstr name="multi-threading" in="auto,on,off" val="off"/>
<attstr name="thread affinity" in="on,off" val="off"/>
</section>
</params>

View file

@ -23,10 +23,8 @@
@ingroup dir
*/
#include <stdlib.h>
#ifdef WIN32
#include <windows.h>
#endif
#include <cstdlib>
#include "tgf.h"
#include "os.h"

View file

@ -52,3 +52,29 @@ GfTimeClock(void)
return 0;
}
}
/* Retrieve the actual number of CPUs in the system
* Note that a core is considered here as a "CPU", and an Intel hyper-threaded processor
* will report twice as many "CPUs" as actual cores ...
*/
unsigned GfGetNumberOfCPUs()
{
if (GfOs.sysGetNumberOfCPUs) {
return GfOs.sysGetNumberOfCPUs();
} else {
return 0;
}
}
/* Force the current thread to run on the specified CPU.
* @param nCPUId the index in [0, # of actual CPUs on the system [ (any other value will actually reset the thread affinity to the "system" affinity mask, meaning no special processor / core assignement)
* @return true if any error occured, false otherwise
*/
bool GfSetThreadAffinity(int nCPUId)
{
if (GfOs.sysSetThreadAffinity) {
return GfOs.sysSetThreadAffinity(nCPUId);
} else {
return false;
}
}

View file

@ -28,12 +28,18 @@ typedef int (*tfModUnloadList)(tModList **);
typedef int (*tfModGetInfo)(unsigned int, const char*, tModList **);
typedef int (*tfModGetInfoDir)(unsigned int, const char*, int, tModList **);
typedef int (*tfModFreeInfoList)(tModList **);
/* directory interface */
typedef tFList *(*tfDirGetList)(const char *);
typedef tFList *(*tfDirGetListFiltered)(const char *, const char *);
/* time interface */
typedef double (*tfTimeClock)(void);
/* System interface */
typedef unsigned (*tfSysGetNumberOfCPUs)(void);
typedef bool (*tfSysSetThreadAffinity)(int nCPUId);
typedef struct {
tfModLoad modLoad;
tfModLoadDir modLoadDir;
@ -44,15 +50,10 @@ typedef struct {
tfDirGetList dirGetList;
tfDirGetListFiltered dirGetListFiltered;
tfTimeClock timeClock;
tfSysSetThreadAffinity sysSetThreadAffinity;
tfSysGetNumberOfCPUs sysGetNumberOfCPUs;
} tGfOs;
#ifdef WIN32
#ifdef tgf_EXPORTS
__declspec(dllexport)
#else // TGF_EXPORTS
__declspec(dllimport)
#endif // TGF_EXPORTS
#endif // WIN32
extern tGfOs GfOs;
TGF_API extern tGfOs GfOs;
#endif /* _OS__H_ */

View file

@ -22,16 +22,10 @@
#else
#include <sys/stat.h>
#include <sys/types.h>
#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)
#include <sys/param.h>
#include <sys/sysctl.h>
#else
#include <unistd.h>
#endif
#endif
#include <errno.h>
#include <time.h>
#include <ctime>
#include <cstring>
#include "tgf.h"
@ -702,7 +696,11 @@ int GfNearestPow2 (int x)
return (1 << r);
}
// Create a directory
/** Create a directory and the parents if needed
@ingroup dir
@param dir full directory path-name
@return GF_DIR_CREATED on success, GF_DIR_CREATION_FAILED otherwise.
*/
int GfCreateDir(const char *path)
{
if (path == NULL) {
@ -752,63 +750,3 @@ int GfCreateDir(const char *path)
return (err == -1 && errno != EEXIST) ? GF_DIR_CREATION_FAILED : GF_DIR_CREATED;
}
/* Get the actual number of CPUs / cores
TODO: Be careful about fake CPUs like those displayed by hyperthreaded processors ...
TODO: Test under pltaforms other than Windows, Linux, Solaris, AIX (mainly BDS and MacOS X).
*/
int GfGetNumberOfCPUs()
{
int nCPUs = 0;
// Windows
#if defined(WIN32)
SYSTEM_INFO sysinfo;
GetSystemInfo(&sysinfo);
nCPUs = sysinfo.dwNumberOfProcessors;
// MacOS X, FreeBSD, OpenBSD, NetBSD, etc ...
#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)
nt mib[4];
size_t len;
// Set the mib for hw.ncpu
// Get the number of CPUs from the system
// 1) Try HW_AVAILCPU first.
mib[0] = CTL_HW;
mib[1] = HW_AVAILCPU; // alternatively, try HW_NCPU;
sysctl(mib, 2, &nCPUs, &len, NULL, 0);
if (nCPUs < 1)
{
// 2) Try alternatively HW_NCPU.
mib[1] = HW_NCPU;
sysctl(mib, 2, &nCPUs, &len, NULL, 0);
}
// Linux, Solaris, AIX
#elif defined(linux) || defined(__linux__)
nCPUs = sysconf(_SC_NPROCESSORS_ONLN);
#else
#warning "Unsupported OS"
#endif // WIN32
if (nCPUs < 1)
{
GfOut("Could not get the number of CPUs here ; assuming only 1\n");
nCPUs = 1;
}
else
GfOut("Detected %d CPUs\n", nCPUs);
return nCPUs;
}

View file

@ -432,14 +432,20 @@ typedef struct
TGF_API tdble gfMean(tdble v, tMeanVal *pvt, int n, int w);
TGF_API void gfMeanReset(tdble v, tMeanVal *pvt);
/* Get the actual number of CPUs / cores */
TGF_API int GfGetNumberOfCPUs();
/********************
* System Interface *
********************/
TGF_API unsigned GfGetNumberOfCPUs();
enum { GfAffinityAnyCPU = -1 };
TGF_API bool GfSetThreadAffinity(int nCPUId);
/* Run-time dirs accessors */
TGF_API const char *GetLocalDir(void);
TGF_API const char *SetLocalDir(const char *buf);
TGF_API const char *GetLibDir(void);
TGF_API const char *SetLibDir(const char *buf);
TGF_API const char *GetDataDir(void);
TGF_API const char *SetDataDir(const char *buf);
TGF_API const char *GetBinDir(void);

View file

@ -18,7 +18,7 @@
***************************************************************************/
#include <stddef.h>
#include <cstddef>
#include <sys/types.h>
#include <dirent.h>
#include <dlfcn.h>
@ -26,6 +26,18 @@
#include <sys/time.h>
#include <unistd.h>
#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)
#include <sys/param.h>
#include <sys/sysctl.h>
#if defined(__APPLE__)
#include <Carbon/Carbon.h> /* Carbon APIs for Multiprocessing */
#endif
#else
// Define _GNU_SOURCE in order to have access to pthread_set/getaffinity_np
//#define _GNU_SOURCE
//#include <pthread.h>
#endif
#include <tgf.h>
#include <os.h>
@ -551,26 +563,171 @@ linuxTimeClock(void)
struct timeval tv;
gettimeofday(&tv, 0);
return (double)(tv.tv_sec + tv.tv_usec * 1e-6);
return (double)(tv.tv_sec + tv.tv_usec * 1e-6);
}
/*
* Function
* linuxGetNumberOfCPUs
*
* Description
* Retrieve the actual number of CPUs in the system
* Note that a core is considered here as a "CPU", and an Intel hyper-threaded processor
* will report twice as many "CPUs" as actual cores ...
*
* Parameters
* None
*
* Return
* The number of CPUs in the system
*
* Remarks
* WARNING: Not tested under platforms other than Linux : Mac OS X, BSD, Solaris, AIX.
*
*/
unsigned linuxGetNumberOfCPUs()
{
static unsigned nCPUs = 0;
if (nCPUs == 0)
{
// MacOS X, FreeBSD, OpenBSD, NetBSD, etc ...
#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)
nt mib[4];
size_t len;
// Set the mib for hw.ncpu
// Get the number of CPUs from the system
// 1) Try HW_AVAILCPU first.
mib[0] = CTL_HW;
mib[1] = HW_AVAILCPU; // alternatively, try HW_NCPU;
sysctl(mib, 2, &nCPUs, &len, NULL, 0);
if (nCPUs < 1)
{
// 2) Try alternatively HW_NCPU.
mib[1] = HW_NCPU;
sysctl(mib, 2, &nCPUs, &len, NULL, 0);
}
// Linux, Solaris, AIX
#elif defined(linux) || defined(__linux__)
nCPUs = (unsigned)sysconf(_SC_NPROCESSORS_ONLN);
// Anything else ... not supported.
#else
#warning "Unsupported Linux OS"
#endif
if (nCPUs < 1)
{
GfOut("Could not get the number of CPUs here ; assuming only 1\n");
nCPUs = 1;
}
else
GfOut("Detected %d CPUs\n", nCPUs);
}
return nCPUs;
}
/*
* Function
* linuxSetThreadAffinity
*
* Description
* Force the current thread to run on the specified CPU.
*
* Parameters
* nCPUId : the index in [0, # of actual CPUs on the system [ (any other value will actually reset the thread affinity to the "system" affinity mask, meaning no special CPU assignement)
*
* Return
* true if any error occured, false otherwise
*
* Remarks
*
*/
bool
linuxSetThreadAffinity(int nCPUId)
{
#if 0
// MacOS X, FreeBSD, OpenBSD, NetBSD, etc ...
#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)
GfOut("Warning: Thread affinity not yet implemented on Mac OS X or BSD.\n");
return false;
// Linux, Solaris, AIX ... with NPTL (Native POSIX Threads Library)
#elif defined(linux) || defined(__linux__)
// Get the handle for the current thread.
pthread_t hCurrThread = pthread_self();
GfOut("Current pthread handle is 0x%X\n", hCurrThread);
// Determine the affinity mask to set for the current thread.
cpu_set_t nThreadAffinityMask;
CPU_ZERO(&nThreadAffinityMask);
if (nCPUId == GfAffinityAnyCore)
{
// No special affinity on any CPU => set "system" affinity mask
// (1 bit for each installed CPU).
for (int nCPUIndex = 0; nCPUIndex < linuxGetNumberOfCPUs(); nCPUIndex++)
CPU_SET(nCPUIndex, &nThreadAffinityMask);
}
else
{
// Affinity on a specified CPU => compute its mask.
CPU_SET(nCPUId, &nThreadAffinityMask);
}
// Set the affinity mask for the current thread ("stick" it to the target core).
if (pthread_setaffinity_np(hCurrThread, sizeof(nThreadAffinityMask), &nThreadAffinityMask))
{
GfError("Failed to set current pthread (handle=0x%X) affinity mask to 0x%X)\n",
hCurrThread, nThreadAffinityMask);
return false;
}
else
GfOut("Affinity mask set to 0x%X for current pthread (handle=0x%X)\n",
nThreadAffinityMask, hCurrThread);
return true;
// Anything else ... not supported.
#else
#warning "linuxspec.cpp::linuxSetThreadAffinity : Unsupported Linux OS"
GfOut("Warning: Thread affinity not yet implemented on this unknown Unix.\n");
return false;
#endif
#endif
return true; // Temporary empty and silent implementation.
}
/*
* Function
* LinuxSpecInit
* LinuxSpecInit
*
* Description
* Init the specific linux functions
* Initialize the specific linux functions
*
* Parameters
* none
* none
*
* Return
* none
* none
*
* Remarks
*
*
*/
void
LinuxSpecInit(void)
@ -585,5 +742,7 @@ LinuxSpecInit(void)
GfOs.dirGetList = linuxDirGetList;
GfOs.dirGetListFiltered = linuxDirGetListFiltered;
GfOs.timeClock = linuxTimeClock;
GfOs.sysGetNumberOfCPUs = linuxGetNumberOfCPUs;
GfOs.sysSetThreadAffinity = linuxSetThreadAffinity;
}

View file

@ -29,7 +29,6 @@
#include <os.h>
/*
* Function
* windowsModLoad
@ -551,58 +550,6 @@ windowsTimeClock(void)
return( D );
}
/*
* Function
* windowsSetAffinity
*
* Description
* Restrict game executable to one CPU core/processor.
* This avoids jerky rendering, especially under Vista.
*
* Parameters
* none
*
* Return
* none
*/
static void
windowsSetAffinity(void)
{
#ifndef ULONG_PTR
typedef unsigned long ULONG_PTR;
#endif
#ifndef ULONG_PTR
typedef unsigned long ULONG_PTR;
#endif
#ifndef PDWORD_PTR
#ifndef DWORD_PTR
typedef ULONG_PTR DWORD_PTR;
#endif
typedef DWORD_PTR *PDWORD_PTR;
#endif
#ifndef PDWORD_PTR
#ifndef DWORD_PTR
typedef ULONG_PTR DWORD_PTR;
#endif
typedef DWORD_PTR *PDWORD_PTR;
#endif
HANDLE hProcess = GetCurrentProcess();
ULONG_PTR ProcAM, SysAM;
GetProcessAffinityMask( hProcess, (PDWORD_PTR) &ProcAM, (PDWORD_PTR) &SysAM );
if (ProcAM > 1)
{
ProcAM = 1;
GfOut("Setting process affinity mask to 1");
SetProcessAffinityMask( hProcess, ProcAM );
}
}
/*
* Function
* windowsGetOSInfo
@ -771,25 +718,140 @@ windowsGetOSInfo(int* pnMajor, int* pnMinor, int* pnBits)
/*
* Function
* WindowsSpecInit
* windowsGetNumberOfCPUs
*
* Description
* Init the specific windows functions
* Retrieve the actual number of CPUs in the system
* Note that a core is considered here as a "CPU", and an Intel hyper-threaded processor
* will report twice as many "CPUs" as actual cores ...
*
* Parameters
* none
* None
*
* Return
* none
* The number of CPUs in the system
*
* Remarks
*
*/
static unsigned
windowsGetNumberOfCPUs()
{
static unsigned nCPUs = 0;
if (nCPUs == 0)
{
SYSTEM_INFO sysinfo;
GetSystemInfo(&sysinfo);
nCPUs = sysinfo.dwNumberOfProcessors;
if (nCPUs < 1)
{
GfOut("Could not get the number of CPUs here ; assuming only 1\n");
nCPUs = 1;
}
else
GfOut("Detected %u CPUs\n", nCPUs);
}
return nCPUs;
}
/*
* Function
* windowsSetThreadAffinity
*
* Description
* Force the current thread to run on the specified CPU.
*
* Parameters
* nCPUId : the index in [0, # of actual CPUs on the system [ (any other value will actually reset the thread affinity to the "system" affinity mask, meaning no special CPU assignement)
*
* Return
* true if any error occured, false otherwise
*
* Remarks
*
*/
static bool
windowsSetThreadAffinity(int nCPUId)
{
// Get the system affinity mask : it is what we want for the thread
// (1 bit for all the cores available in the system)
// Note: We don't care about the process affinity mask here.
DWORD_PTR nProcessMask, nSystemMask;
GetProcessAffinityMask(GetCurrentProcess(), &nProcessMask, &nSystemMask);
// Determine the affinity mask to set
ULONGLONG nThreadAffinityMask;
if (nCPUId == GfAffinityAnyCPU)
{
// No special affinity on any processor => set "system" affinity mask.
nThreadAffinityMask = nSystemMask;
}
else
{
// Affinity on a specified CPU => compute its mask (1 bit in the "system" mask).
int nCPUIndex = -1;
int nBitIndex = 0;
while (nBitIndex < sizeof(nSystemMask)*8 && nCPUIndex < nCPUId)
{
if (nSystemMask & 1)
nCPUIndex++;
nSystemMask >>= 1;
nBitIndex++;
}
nBitIndex--;
if (nCPUIndex != nCPUId)
{
GfError("Target CPU %d not found (erroneous id specified ?)\n", nCPUId);
return false;
}
// We've got it.
nThreadAffinityMask = (1 << nBitIndex);
}
// Get the handle for the current thread.
HANDLE hCurrThread = GetCurrentThread();
GfOut("Current thread handle is 0x%X\n", hCurrThread);
// Set the affinity mask for the current thread ("stick" it to the target core).
if (SetThreadAffinityMask(hCurrThread, (DWORD_PTR)nThreadAffinityMask) == 0)
{
GfError("Failed to set current thread (handle=0x%X) affinity mask to 0x%X)\n",
hCurrThread, nThreadAffinityMask);
return false;
}
else
GfOut("Affinity mask set to 0x%X for current thread (handle=0x%X)\n",
nThreadAffinityMask, hCurrThread);
return true;
}
/*
* Function
* WindowsSpecInit
*
* Description
* Init the specific windows functions
*
* Parameters
* none
*
* Return
* none
*
* Remarks
*
*/
void
WindowsSpecInit(void)
{
memset(&GfOs, 0, sizeof(GfOs));
GfOs.modLoad = windowsModLoad;
GfOs.modLoadDir = windowsModLoadDir;
GfOs.modUnloadList = windowsModUnloadList;
@ -798,11 +860,6 @@ WindowsSpecInit(void)
GfOs.dirGetList = windowsDirGetList;
GfOs.dirGetListFiltered = windowsDirGetListFiltered;
GfOs.timeClock = windowsTimeClock;
//>>> Multithreading-Issue:
// Windows XP/windows 7 and ATI Radenon: card no problems without this!
// Workaround for Vista jerky rendering on multicore CPUs.
int nMajor, nMinor, nBits;
if (windowsGetOSInfo(&nMajor, &nMinor, &nBits) && nMajor >= 6)
windowsSetAffinity();
//<<<
GfOs.sysGetNumberOfCPUs = windowsGetNumberOfCPUs;
GfOs.sysSetThreadAffinity = windowsSetThreadAffinity;
}