Commit 424bfe9c authored by peastman's avatar peastman
Browse files

Created a property for setting the number of CPU cores to use

parent 55237c86
......@@ -1878,6 +1878,24 @@ values. For example,
This tells it to use both devices 0 and 1, splitting the work between them.
CPU Platform
************
The CPU Platform recognizes the following Platform-specific properties:
* CpuThreads: This specifies the number of CPU threads to use. If you do not
specify this, OpenMM will select a default number of threads as follows:
* If an environment variable called OPENMM_CPU_THREADS is set, its value is
used as the number of threads.
* Otherwise, the number of threads is set to the number of logical CPU cores
in the computer it is running on.
Usually the default value works well. This is mainly useful when you are
running something else on the computer at the same time, and you want to
prevent OpenMM from monopolizing all available cores.
.. _using-openmm-with-software-written-in-languages-other-than-c++:
Using OpenMM with Software Written in Languages Other than C++
......
......@@ -53,7 +53,13 @@ class OPENMM_EXPORT ThreadPool {
public:
class Task;
class ThreadData;
ThreadPool();
/**
* Create a ThreadPool.
*
* @param numThreads the number of worker threads to create. If this is 0 (the default), the
* number of threads is set equal to the number of logical CPU cores available
*/
ThreadPool(int numThreads=0);
~ThreadPool();
/**
* Get the number of worker threads in the pool.
......
......@@ -6,7 +6,7 @@
* Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. *
* *
* Portions copyright (c) 2013 Stanford University and the Authors. *
* Portions copyright (c) 2013-2014 Stanford University and the Authors. *
* Authors: Peter Eastman *
* Contributors: *
* *
......@@ -60,8 +60,10 @@ static void* threadBody(void* args) {
return 0;
}
ThreadPool::ThreadPool() {
numThreads = getNumProcessors();
ThreadPool::ThreadPool(int numThreads) {
if (numThreads <= 0)
numThreads = getNumProcessors();
this->numThreads = numThreads;
pthread_cond_init(&startCondition, NULL);
pthread_cond_init(&endCondition, NULL);
pthread_mutex_init(&lock, NULL);
......
......@@ -55,27 +55,37 @@ public:
return name;
}
double getSpeed() const;
const std::string& getPropertyValue(const Context& context, const std::string& property) const;
bool supportsDoublePrecision() const;
static bool isProcessorSupported();
void contextCreated(ContextImpl& context, const std::map<std::string, std::string>& properties) const;
void contextDestroyed(ContextImpl& context) const;
/**
* This is the name of the parameter for selecting the number of threads to use.
*/
static const std::string& CpuThreads() {
static const std::string key = "CpuThreads";
return key;
}
/**
* We cannot use the standard mechanism for platform data, because that is already used by the superclass.
* Instead, we maintain a table of ContextImpls to PlatformDatas.
*/
static PlatformData& getPlatformData(ContextImpl& context);
static const PlatformData& getPlatformData(const ContextImpl& context);
private:
static std::map<ContextImpl*, PlatformData*> contextData;
static std::map<const ContextImpl*, PlatformData*> contextData;
};
class CpuPlatform::PlatformData {
public:
PlatformData(int numParticles);
PlatformData(int numParticles, int numThreads);
AlignedArray<float> posq;
std::vector<AlignedArray<float> > threadForce;
ThreadPool threads;
bool isPeriodic;
CpuRandom random;
std::map<std::string, std::string> propertyValues;
};
} // namespace OpenMM
......
......@@ -6,7 +6,7 @@
* Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. *
* *
* Portions copyright (c) 2013 Stanford University and the Authors. *
* Portions copyright (c) 2013-2014 Stanford University and the Authors. *
* Authors: Peter Eastman *
* Contributors: *
* *
......@@ -35,6 +35,7 @@
#include "CpuSETTLE.h"
#include "ReferenceConstraints.h"
#include "openmm/internal/hardware.h"
#include <sstream>
using namespace OpenMM;
using namespace std;
......@@ -53,7 +54,7 @@ extern "C" OPENMM_EXPORT_CPU void registerPlatforms() {
}
#endif
map<ContextImpl*, CpuPlatform::PlatformData*> CpuPlatform::contextData;
map<const ContextImpl*, CpuPlatform::PlatformData*> CpuPlatform::contextData;
CpuPlatform::CpuPlatform() {
CpuKernelFactory* factory = new CpuKernelFactory();
......@@ -63,6 +64,23 @@ CpuPlatform::CpuPlatform() {
registerKernelFactory(CalcNonbondedForceKernel::Name(), factory);
registerKernelFactory(CalcGBSAOBCForceKernel::Name(), factory);
registerKernelFactory(IntegrateLangevinStepKernel::Name(), factory);
platformProperties.push_back(CpuThreads());
int threads = getNumProcessors();
char* threadsEnv = getenv("OPENMM_CPU_THREADS");
if (threadsEnv != NULL)
stringstream(threadsEnv) >> threads;
stringstream defaultThreads;
defaultThreads << threads;
setPropertyDefaultValue(CpuThreads(), defaultThreads.str());
}
const string& CpuPlatform::getPropertyValue(const Context& context, const string& property) const {
const ContextImpl& impl = getContextImpl(context);
const PlatformData& data = getPlatformData(impl);
map<string, string>::const_iterator value = data.propertyValues.find(property);
if (value != data.propertyValues.end())
return value->second;
return ReferencePlatform::getPropertyValue(context, property);
}
double CpuPlatform::getSpeed() const {
......@@ -87,7 +105,11 @@ bool CpuPlatform::isProcessorSupported() {
void CpuPlatform::contextCreated(ContextImpl& context, const map<string, string>& properties) const {
ReferencePlatform::contextCreated(context, properties);
PlatformData* data = new PlatformData(context.getSystem().getNumParticles());
const string& threadsPropValue = (properties.find(CpuThreads()) == properties.end() ?
getPropertyDefaultValue(CpuThreads()) : properties.find(CpuThreads())->second);
int numThreads;
stringstream(threadsPropValue) >> numThreads;
PlatformData* data = new PlatformData(context.getSystem().getNumParticles(), numThreads);
contextData[&context] = data;
ReferenceConstraints& constraints = *(ReferenceConstraints*) reinterpret_cast<ReferencePlatform::PlatformData*>(context.getPlatformData())->constraints;
if (constraints.settle != NULL) {
......@@ -107,10 +129,17 @@ CpuPlatform::PlatformData& CpuPlatform::getPlatformData(ContextImpl& context) {
return *contextData[&context];
}
CpuPlatform::PlatformData::PlatformData(int numParticles) : posq(4*numParticles) {
int numThreads = threads.getNumThreads();
const CpuPlatform::PlatformData& CpuPlatform::getPlatformData(const ContextImpl& context) {
return *contextData[&context];
}
CpuPlatform::PlatformData::PlatformData(int numParticles, int numThreads) : posq(4*numParticles), threads(numThreads) {
numThreads = threads.getNumThreads();
threadForce.resize(numThreads);
for (int i = 0; i < numThreads; i++)
threadForce[i].resize(4*numParticles);
isPeriodic = false;
stringstream threadsProperty;
threadsProperty << numThreads;
propertyValues[CpuThreads()] = threadsProperty.str();
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment