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:
parent
0184e27872
commit
a7757a2b0d
11 changed files with 420 additions and 164 deletions
|
@ -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"
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -23,10 +23,8 @@
|
|||
@ingroup dir
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#ifdef WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
#include <cstdlib>
|
||||
|
||||
#include "tgf.h"
|
||||
#include "os.h"
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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_ */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue