Unverified Commit 3b8df952 authored by Peter Eastman's avatar Peter Eastman Committed by GitHub
Browse files

Merge pull request #4632 from ex-rzr/make-hip-standard-platform

HIP platform
parents 5ce6a85d 28fb2918
#ifndef OPENMM_HIPPARAMETERSET_H_
#define OPENMM_HIPPARAMETERSET_H_
/* -------------------------------------------------------------------------- *
* OpenMM *
* -------------------------------------------------------------------------- *
* This is part of the OpenMM molecular simulation toolkit originating from *
* Simbios, the NIH National Center for Physics-Based Simulation of *
* Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. *
* *
* Portions copyright (c) 2009-2019 Stanford University and the Authors. *
* Portions copyright (c) 2020 Advanced Micro Devices, Inc. *
* Authors: Peter Eastman, Nicholas Curtis *
* Contributors: *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as published *
* by the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* -------------------------------------------------------------------------- */
#include "HipContext.h"
#include "HipNonbondedUtilities.h"
#include "openmm/common/ComputeParameterSet.h"
namespace OpenMM {
class HipNonbondedUtilities;
/**
* This class exists for backward compatibility. For most purposes you can use
* ComputeParameterSet directly instead.
*/
class OPENMM_EXPORT_COMMON HipParameterSet : public ComputeParameterSet {
public:
/**
* Create an HipParameterSet.
*
* @param context the context for which to create the parameter set
* @param numParameters the number of parameters for each object
* @param numObjects the number of objects to store parameter values for
* @param name the name of the parameter set
* @param bufferPerParameter if true, a separate buffer is created for each parameter. If false,
* multiple parameters may be combined into a single buffer.
* @param useDoublePrecision whether values should be stored as single or double precision
*/
HipParameterSet(HipContext& context, int numParameters, int numObjects, const std::string& name, bool bufferPerParameter=false, bool useDoublePrecision=false);
/**
* Get a set of HipNonbondedUtilities::ParameterInfo objects which describe the Buffers
* containing the data.
*/
std::vector<HipNonbondedUtilities::ParameterInfo>& getBuffers() {
return buffers;
}
private:
std::vector<HipNonbondedUtilities::ParameterInfo> buffers;
};
} // namespace OpenMM
#endif /*OPENMM_HIPPARAMETERSET_H_*/
#ifndef OPENMM_HIPPLATFORM_H_
#define OPENMM_HIPPLATFORM_H_
/* -------------------------------------------------------------------------- *
* OpenMM *
* -------------------------------------------------------------------------- *
* This is part of the OpenMM molecular simulation toolkit originating from *
* Simbios, the NIH National Center for Physics-Based Simulation of *
* Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. *
* *
* Portions copyright (c) 2008-2016 Stanford University and the Authors. *
* Portions copyright (c) 2020 Advanced Micro Devices, Inc. *
* Authors: Peter Eastman, Nicholas Curtis *
* Contributors: *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as published *
* by the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* -------------------------------------------------------------------------- */
#include "openmm/Platform.h"
#include "openmm/System.h"
#include "openmm/internal/ThreadPool.h"
#include "openmm/common/windowsExportCommon.h"
namespace OpenMM {
class HipContext;
/**
* This Platform subclass uses HIP implementations of the OpenMM kernels.
*/
class OPENMM_EXPORT_COMMON HipPlatform : public Platform {
public:
class PlatformData;
HipPlatform();
const std::string& getName() const {
static const std::string name = "HIP";
return name;
}
double getSpeed() const;
bool supportsDoublePrecision() const;
const std::string& getPropertyValue(const Context& context, const std::string& property) const;
void setPropertyValue(Context& context, const std::string& property, const std::string& value) const;
void contextCreated(ContextImpl& context, const std::map<std::string, std::string>& properties) const;
void linkedContextCreated(ContextImpl& context, ContextImpl& originalContext) const;
void contextDestroyed(ContextImpl& context) const;
/**
* This is the name of the parameter for selecting which HIP device or devices to use.
*/
static const std::string& HipDeviceIndex() {
static const std::string key = "DeviceIndex";
return key;
}
/**
* This is the name of the parameter that reports the HIP device or devices being used.
*/
static const std::string& HipDeviceName() {
static const std::string key = "DeviceName";
return key;
}
/**
* This is the name of the parameter for selecting whether HIP should sync or spin loop while waiting for results.
*/
static const std::string& HipUseBlockingSync() {
static const std::string key = "UseBlockingSync";
return key;
}
/**
* This is the name of the parameter for selecting what numerical precision to use.
*/
static const std::string& HipPrecision() {
static const std::string key = "Precision";
return key;
}
/**
* This is the name of the parameter for selecting whether to use the CPU based PME calculation.
*/
static const std::string& HipUseCpuPme() {
static const std::string key = "UseCpuPme";
return key;
}
/**
* This is the name of the parameter for specifying the path to the directory for creating temporary files.
*/
static const std::string& HipTempDirectory() {
static const std::string key = "TempDirectory";
return key;
}
/**
* This is the name of the parameter for selecting whether to disable use of a separate stream for PME.
*/
static const std::string& HipDisablePmeStream() {
static const std::string key = "DisablePmeStream";
return key;
}
/**
* This is the name of the parameter for requesting that force computations be fully deterministic.
*/
static const std::string& HipDeterministicForces() {
static const std::string key = "DeterministicForces";
return key;
}
};
class OPENMM_EXPORT_COMMON HipPlatform::PlatformData {
public:
PlatformData(ContextImpl* context, const System& system, const std::string& deviceIndexProperty, const std::string& blockingProperty, const std::string& precisionProperty,
const std::string& cpuPmeProperty, const std::string& tempProperty,
const std::string& pmeStreamProperty, const std::string& deterministicForcesProperty, int numThreads, ContextImpl* originalContext);
~PlatformData();
void initializeContexts(const System& system);
void syncContexts();
ContextImpl* context;
std::vector<HipContext*> contexts;
std::vector<double> contextEnergy;
bool hasInitializedContexts, removeCM, peerAccessSupported, useCpuPme, disablePmeStream, deterministicForces;
int cmMotionFrequency, computeForceCount;
long long stepCount;
double time;
std::map<std::string, std::string> propertyValues;
ThreadPool threads;
};
} // namespace OpenMM
#endif /*OPENMM_HIPPLATFORM_H_*/
#ifndef OPENMM_HIPPROGRAM_H_
#define OPENMM_HIPPROGRAM_H_
/* -------------------------------------------------------------------------- *
* OpenMM *
* -------------------------------------------------------------------------- *
* This is part of the OpenMM molecular simulation toolkit originating from *
* Simbios, the NIH National Center for Physics-Based Simulation of *
* Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. *
* *
* Portions copyright (c) 2019 Stanford University and the Authors. *
* Portions copyright (c) 2020 Advanced Micro Devices, Inc. *
* Authors: Peter Eastman, Nicholas Curtis *
* Contributors: *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as published *
* by the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* -------------------------------------------------------------------------- */
#include "openmm/common/ComputeProgram.h"
#include "HipContext.h"
namespace OpenMM {
/**
* This is the HIP implementation of the ComputeProgramImpl interface.
*/
class HipProgram : public ComputeProgramImpl {
public:
/**
* Create a new HipProgram.
*
* @param context the context this kernel belongs to
* @param module the compiled module
*/
HipProgram(HipContext& context, hipModule_t module);
/**
* Create a ComputeKernel for one of the kernels in this program.
*
* @param name the name of the kernel to get
*/
ComputeKernel createKernel(const std::string& name);
private:
HipContext& context;
hipModule_t module;
};
} // namespace OpenMM
#endif /*OPENMM_HIPPROGRAM_H_*/
#ifndef __OPENMM_HIPSORT_H__
#define __OPENMM_HIPSORT_H__
/* -------------------------------------------------------------------------- *
* OpenMM *
* -------------------------------------------------------------------------- *
* This is part of the OpenMM molecular simulation toolkit originating from *
* Simbios, the NIH National Center for Physics-Based Simulation of *
* Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. *
* *
* Portions copyright (c) 2010-2018 Stanford University and the Authors. *
* Portions copyright (c) 2020-2023 Advanced Micro Devices, Inc. *
* Authors: Peter Eastman, Nicholas Curtis *
* Contributors: *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as published *
* by the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* -------------------------------------------------------------------------- */
#include "HipArray.h"
#include "openmm/common/windowsExportCommon.h"
#include "HipContext.h"
namespace OpenMM {
/**
* This class sorts arrays of values. It supports any type of values, not just scalars,
* so long as an appropriate sorting key can be defined by which to sort them.
*
* The sorting behavior is specified by a "trait" class that defines the type of data to
* sort and the key for sorting it. Here is an example of a trait class for
* sorting floats:
*
* class FloatTrait : public HipSort::SortTrait {
* int getDataSize() const {return 4;}
* int getKeySize() const {return 4;}
* const char* getDataType() const {return "float";}
* const char* getKeyType() const {return "float";}
* const char* getMinKey() const {return "-3.40282e+38f";}
* const char* getMaxKey() const {return "3.40282e+38f";}
* const char* getMaxValue() const {return "3.40282e+38f";}
* const char* getSortKey() const {return "value";}
* };
*
* The algorithm used is a bucket sort, followed by a bitonic sort within each bucket
* (in local memory when possible, in global memory otherwise). This is similar to
* the algorithm described in
*
* Shifu Chen, Jing Qin, Yongming Xie, Junping Zhao, and Pheng-Ann Heng. "An Efficient
* Sorting Algorithm with CUDA" Journal of the Chinese Institute of Engineers, 32(7),
* pp. 915-921 (2009)
*
* but with many modifications and simplifications. In particular, this algorithm
* involves much less communication between host and device, which is critical to get
* good performance with the array sizes we typically work with (10,000 to 100,000
* elements).
*/
class OPENMM_EXPORT_COMMON HipSort {
public:
class SortTrait;
/**
* Create a HipSort object for sorting data of a particular type.
*
* @param context the context in which to perform calculations
* @param trait a SortTrait defining the type of data to sort. It should have been allocated
* on the heap with the "new" operator. This object takes over ownership of it,
* and deletes it when the HipSort is deleted.
* @param length the length of the arrays this object will be used to sort.
* @param uniform whether the input data is expected to follow a uniform or nonuniform
* distribution. This argument is used only as a hint.
*/
HipSort(HipContext& context, SortTrait* trait, unsigned int length, bool uniform=true);
~HipSort();
/**
* Sort an array.
*/
void sort(HipArray& data);
private:
HipContext& context;
SortTrait* trait;
HipArray counters;
HipArray dataRange;
HipArray bucketOfElement;
HipArray offsetInBucket;
HipArray bucketOffset;
HipArray buckets;
hipFunction_t shortListKernel, shortList2Kernel, computeRangeKernel, assignElementsKernel, computeBucketPositionsKernel, copyToBucketsKernel, sortBucketsKernel;
unsigned int dataLength, rangeKernelBlocks, rangeKernelSize, positionsKernelSize, sortKernelSize;
bool isShortList, uniform;
};
/**
* A subclass of SortTrait defines the type of value to sort, and the key for sorting them.
*/
class HipSort::SortTrait {
public:
virtual ~SortTrait() {
}
/**
* Get the size of each data value in bytes.
*/
virtual int getDataSize() const = 0;
/**
* Get the size of each key value in bytes.
*/
virtual int getKeySize() const = 0;
/**
* Get the data type of the values to sort.
*/
virtual const char* getDataType() const = 0;
/**
* Get the data type of the sorting key.
*/
virtual const char* getKeyType() const = 0;
/**
* Get the minimum value a key can take.
*/
virtual const char* getMinKey() const = 0;
/**
* Get the maximum value a key can take.
*/
virtual const char* getMaxKey() const = 0;
/**
* Get a value whose key is guaranteed to equal getMaxKey().
*/
virtual const char* getMaxValue() const = 0;
/**
* Get the HIP code to select the key from the data value.
*/
virtual const char* getSortKey() const = 0;
};
} // namespace OpenMM
#endif // __OPENMM_HIPSORT_H__
/* -------------------------------------------------------------------------- *
* OpenMM *
* -------------------------------------------------------------------------- *
* This is part of the OpenMM molecular simulation toolkit originating from *
* Simbios, the NIH National Center for Physics-Based Simulation of *
* Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. *
* *
* Portions copyright (c) 2012-2022 Stanford University and the Authors. *
* Portions copyright (c) 2020-2023 Advanced Micro Devices, Inc. *
* Authors: Peter Eastman, Nicholas Curtis *
* Contributors: *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as published *
* by the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* -------------------------------------------------------------------------- */
#include "HipArray.h"
#include "HipContext.h"
#include "openmm/common/ContextSelector.h"
#include <iostream>
#include <sstream>
#include <vector>
using namespace OpenMM;
HipArray::HipArray() : pointer(0), ownsMemory(false) {
}
HipArray::HipArray(HipContext& context, size_t size, int elementSize, const std::string& name) : pointer(0) {
initialize(context, size, elementSize, name);
}
HipArray::~HipArray() {
if (pointer != 0 && ownsMemory && context->getContextIsValid()) {
ContextSelector selector(*context);
hipError_t result = hipFree(pointer);
if (result != hipSuccess) {
std::stringstream str;
str<<"Error deleting array "<<name<<": "<<HipContext::getErrorString(result)<<" ("<<result<<")";
throw OpenMMException(str.str());
}
}
}
void HipArray::initialize(ComputeContext& context, size_t size, int elementSize, const std::string& name) {
if (this->pointer != 0)
throw OpenMMException("HipArray has already been initialized");
this->context = &dynamic_cast<HipContext&>(context);
this->size = size;
this->elementSize = elementSize;
this->name = name;
ownsMemory = true;
ContextSelector selector(*this->context);
hipError_t result = hipMalloc(&pointer, size*elementSize);
if (result != hipSuccess) {
std::stringstream str;
str<<"Error creating array "<<name<<": "<<HipContext::getErrorString(result)<<" ("<<result<<")";
throw OpenMMException(str.str());
}
}
void HipArray::resize(size_t size) {
if (pointer == 0)
throw OpenMMException("HipArray has not been initialized");
if (!ownsMemory)
throw OpenMMException("Cannot resize an array that does not own its storage");
ContextSelector selector(*context);
hipError_t result = hipFree(pointer);
if (result != hipSuccess) {
std::stringstream str;
str<<"Error deleting array "<<name<<": "<<HipContext::getErrorString(result)<<" ("<<result<<")";
throw OpenMMException(str.str());
}
pointer = 0;
initialize(*context, size, elementSize, name);
}
ComputeContext& HipArray::getContext() {
return *context;
}
void HipArray::uploadSubArray(const void* data, int offset, int elements, bool blocking) {
if (pointer == 0)
throw OpenMMException("HipArray has not been initialized");
if (offset < 0 || offset+elements > getSize())
throw OpenMMException("uploadSubArray: data exceeds range of array");
hipError_t result;
result = hipMemcpyAsync(reinterpret_cast<char*>(pointer)+offset*elementSize, const_cast<void*>(data), elements*elementSize, hipMemcpyHostToDevice, context->getCurrentStream());
if (blocking && result == hipSuccess)
result = hipStreamSynchronize(context->getCurrentStream());
if (result != hipSuccess) {
std::stringstream str;
str<<"Error uploading array "<<name<<": "<<HipContext::getErrorString(result)<<" ("<<result<<")";
throw OpenMMException(str.str());
}
}
void HipArray::download(void* data, bool blocking) const {
if (pointer == 0)
throw OpenMMException("HipArray has not been initialized");
hipError_t result;
result = hipMemcpyAsync(data, pointer, size*elementSize, hipMemcpyDeviceToHost, context->getCurrentStream());
if (blocking && result == hipSuccess)
result = hipStreamSynchronize(context->getCurrentStream());
if (result != hipSuccess) {
std::stringstream str;
str<<"Error downloading array "<<name<<": "<<HipContext::getErrorString(result)<<" ("<<result<<")";
throw OpenMMException(str.str());
}
}
void HipArray::copyTo(ArrayInterface& dest) const {
if (pointer == 0)
throw OpenMMException("HipArray has not been initialized");
if (dest.getSize() != size || dest.getElementSize() != elementSize)
throw OpenMMException("Error copying array "+name+" to "+dest.getName()+": The destination array does not match the size of the array");
HipArray& cuDest = context->unwrap(dest);
hipError_t result = hipMemcpyAsync(cuDest.getDevicePointer(), pointer, size*elementSize, hipMemcpyDeviceToDevice, context->getCurrentStream());
if (result != hipSuccess) {
std::stringstream str;
str<<"Error copying array "<<name<<" to "<<dest.getName()<<": "<<HipContext::getErrorString(result)<<" ("<<result<<")";
throw OpenMMException(str.str());
}
}
This diff is collapsed.
/* -------------------------------------------------------------------------- *
* OpenMM *
* -------------------------------------------------------------------------- *
* This is part of the OpenMM molecular simulation toolkit originating from *
* Simbios, the NIH National Center for Physics-Based Simulation of *
* Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. *
* *
* Portions copyright (c) 2019 Stanford University and the Authors. *
* Portions copyright (c) 2020-2023 Advanced Micro Devices, Inc. *
* Authors: Peter Eastman, Nicholas Curtis *
* Contributors: *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as published *
* by the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* -------------------------------------------------------------------------- */
#include "HipEvent.h"
#include "openmm/OpenMMException.h"
using namespace OpenMM;
HipEvent::HipEvent(HipContext& context) : context(context), eventCreated(false) {
hipError_t result = hipEventCreateWithFlags(&event, context.getEventFlags());
if (result != hipSuccess)
throw OpenMMException("Error creating HIP event:"+HipContext::getErrorString(result));
eventCreated = true;
}
HipEvent::~HipEvent() {
if (eventCreated)
hipEventDestroy(event);
}
void HipEvent::enqueue() {
hipEventRecord(event, context.getCurrentStream());
}
void HipEvent::wait() {
hipEventSynchronize(event);
}
/* -------------------------------------------------------------------------- *
* OpenMM *
* -------------------------------------------------------------------------- *
* This is part of the OpenMM molecular simulation toolkit originating from *
* Simbios, the NIH National Center for Physics-Based Simulation of *
* Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. *
* *
* Portions copyright (c) 2009-2015 Stanford University and the Authors. *
* Portions copyright (c) 2021 Advanced Micro Devices, Inc. *
* Authors: *
* Contributors: *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as published *
* by the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* -------------------------------------------------------------------------- */
#include "HipFFT3D.h"
#include "HipContext.h"
#include <fstream>
#include <iostream>
#include <sstream>
#include <iterator>
using namespace OpenMM;
using namespace std;
HipFFT3D::HipFFT3D(HipContext& context, int xsize, int ysize, int zsize, bool realToComplex, hipStream_t stream, HipArray& in, HipArray& out) :
context(context), stream(stream) {
deviceIndex = context.getDeviceIndex();
inputBuffer = in.getDevicePointer();
outputBuffer = out.getDevicePointer();
size_t valueSize = context.getUseDoublePrecision() ? sizeof(double) : sizeof(float);
inputBufferSize = zsize * ysize * xsize * valueSize;
if (realToComplex) {
outputBufferSize = (zsize/2 + 1) * ysize * xsize * valueSize * 2;
}
else {
outputBufferSize = zsize * ysize * xsize * valueSize;
}
VkFFTConfiguration configuration = {};
configuration.performR2C = realToComplex;
configuration.device = &deviceIndex;
configuration.num_streams = 1;
configuration.stream = &this->stream;
configuration.doublePrecision = context.getUseDoublePrecision();
configuration.FFTdim = 3;
configuration.size[0] = zsize;
configuration.size[1] = ysize;
configuration.size[2] = xsize;
configuration.inverseReturnToInputBuffer = true;
configuration.isInputFormatted = true;
configuration.inputBufferSize = &inputBufferSize;
configuration.inputBuffer = &inputBuffer;
configuration.inputBufferStride[0] = zsize;
configuration.inputBufferStride[1] = configuration.inputBufferStride[0] * ysize;
configuration.inputBufferStride[2] = configuration.inputBufferStride[1] * xsize;
configuration.bufferSize = &outputBufferSize;
configuration.buffer = &outputBuffer;
configuration.bufferStride[0] = realToComplex ? (zsize/2 + 1) : zsize;
configuration.bufferStride[1] = configuration.bufferStride[0] * ysize;
configuration.bufferStride[2] = configuration.bufferStride[1] * xsize;
// Combine all parameters into a unique key
stringstream info;
int runtimeVersion;
(void)hipRuntimeGetVersion(&runtimeVersion);
info << runtimeVersion;
info << " " << VkFFTGetVersion();
info << " " << xsize << " " << ysize << " " << zsize;
info << " " << realToComplex << " " << context.getUseDoublePrecision();
string cacheFile = context.getCacheFileName(info.str());
bool hasCache = false;
vector<char> cacheContent;
ifstream cache(cacheFile.c_str(), ios::in | ios::binary);
if (cache.is_open()) {
cacheContent.insert(cacheContent.begin(), istreambuf_iterator<char>(cache), istreambuf_iterator<char>());
cache.close();
hasCache = true;
// There is an existing cache, load VkFFT kernels from it
configuration.loadApplicationFromString = 1;
configuration.loadApplicationString = cacheContent.data();
}
else {
// There is no existing cache, request saving
configuration.saveApplicationToString = 1;
}
app = new VkFFTApplication();
VkFFTResult fftResult = initializeVkFFT(app, configuration);
if (fftResult != VKFFT_SUCCESS) {
throw OpenMMException("Error executing initializeVkFFT: "+context.intToString(fftResult));
}
if (!hasCache) {
// There is no existing cache, create it
string outputFile = context.getTempFileName() + ".vkfftcache";
try {
ofstream out(outputFile.c_str(), ios::out | ios::binary);
out.write(reinterpret_cast<char*>(app->saveApplicationString), size_t(app->applicationStringSize));
out.close();
if (!out.fail()) {
if (rename(outputFile.c_str(), cacheFile.c_str()) != 0)
remove(outputFile.c_str());
}
}
catch (...) {
// An error occurred. Possibly we don't have permission to write to the temp directory.
}
}
}
HipFFT3D::~HipFFT3D() {
deleteVkFFT(app);
delete app;
}
void HipFFT3D::execFFT(bool forward) {
VkFFTResult fftResult = VkFFTAppend(app, forward ? -1 : 1, NULL);
if (fftResult != VKFFT_SUCCESS) {
throw OpenMMException("Error executing VkFFTAppend: "+context.intToString(fftResult));
}
}
int HipFFT3D::findLegalDimension(int minimum) {
if (minimum < 1)
return 1;
while (true) {
// Attempt to factor the current value.
int unfactored = minimum;
// VkFFT supports prime factors up to 13
for (int factor = 2; factor <= 13; factor++) {
while (unfactored > 1 && unfactored%factor == 0)
unfactored /= factor;
}
if (unfactored == 1)
return minimum;
minimum++;
}
}
/* -------------------------------------------------------------------------- *
* OpenMM *
* -------------------------------------------------------------------------- *
* This is part of the OpenMM molecular simulation toolkit originating from *
* Simbios, the NIH National Center for Physics-Based Simulation of *
* Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. *
* *
* Portions copyright (c) 2009-2021 Stanford University and the Authors. *
* Portions copyright (c) 2020-2023 Advanced Micro Devices, Inc. *
* Authors: Peter Eastman, Nicholas Curtis *
* Contributors: *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as published *
* by the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* -------------------------------------------------------------------------- */
#include "HipIntegrationUtilities.h"
#include "HipContext.h"
#include "openmm/common/ContextSelector.h"
using namespace OpenMM;
using namespace std;
#define CHECK_RESULT(result) CHECK_RESULT2(result, errorMessage);
#define CHECK_RESULT2(result, prefix) \
if (result != hipSuccess) { \
std::stringstream m; \
m<<prefix<<": "<<dynamic_cast<HipContext&>(context).getErrorString(result)<<" ("<<result<<")"<<" at "<<__FILE__<<":"<<__LINE__; \
throw OpenMMException(m.str());\
}
HipIntegrationUtilities::HipIntegrationUtilities(HipContext& context, const System& system) : IntegrationUtilities(context, system),
ccmaConvergedMemory(NULL) {
CHECK_RESULT2(hipEventCreateWithFlags(&ccmaEvent, context.getEventFlags()), "Error creating event for CCMA");
CHECK_RESULT2(hipHostMalloc((void**) &ccmaConvergedMemory, sizeof(int), context.getHostMallocFlags()), "Error allocating pinned memory");
CHECK_RESULT2(hipHostGetDevicePointer(&ccmaConvergedDeviceMemory, ccmaConvergedMemory, 0), "Error getting device address for pinned memory");
}
HipIntegrationUtilities::~HipIntegrationUtilities() {
ContextSelector selector(context);
if (ccmaConvergedMemory != NULL) {
hipHostFree(ccmaConvergedMemory);
hipEventDestroy(ccmaEvent);
}
}
HipArray& HipIntegrationUtilities::getPosDelta() {
return dynamic_cast<HipContext&>(context).unwrap(posDelta);
}
HipArray& HipIntegrationUtilities::getRandom() {
return dynamic_cast<HipContext&>(context).unwrap(random);
}
HipArray& HipIntegrationUtilities::getStepSize() {
return dynamic_cast<HipContext&>(context).unwrap(stepSize);
}
void HipIntegrationUtilities::applyConstraintsImpl(bool constrainVelocities, double tol) {
ContextSelector selector(context);
ComputeKernel settleKernel, shakeKernel, ccmaForceKernel;
if (constrainVelocities) {
settleKernel = settleVelKernel;
shakeKernel = shakeVelKernel;
ccmaForceKernel = ccmaVelForceKernel;
}
else {
settleKernel = settlePosKernel;
shakeKernel = shakePosKernel;
ccmaForceKernel = ccmaPosForceKernel;
}
if (settleAtoms.isInitialized()) {
if (context.getUseDoublePrecision() || context.getUseMixedPrecision())
settleKernel->setArg(1, tol);
else
settleKernel->setArg(1, (float) tol);
settleKernel->execute(settleAtoms.getSize());
}
if (shakeAtoms.isInitialized()) {
if (context.getUseDoublePrecision() || context.getUseMixedPrecision())
shakeKernel->setArg(1, tol);
else
shakeKernel->setArg(1, (float) tol);
shakeKernel->execute(shakeAtoms.getSize());
}
if (ccmaConstraintAtoms.isInitialized()) {
if (ccmaConstraintAtoms.getSize() <= 1024) {
// Use the version of CCMA that runs in a single kernel with one workgroup.
ccmaFullKernel->setArg(0, (int) constrainVelocities);
if (context.getUseDoublePrecision() || context.getUseMixedPrecision())
ccmaFullKernel->setArg(14, tol);
else
ccmaFullKernel->setArg(14, (float) tol);
ccmaFullKernel->execute(128, 128);
}
else {
ccmaForceKernel->setArg(6, ccmaConvergedDeviceMemory);
if (context.getUseDoublePrecision() || context.getUseMixedPrecision())
ccmaForceKernel->setArg(7, tol);
else
ccmaForceKernel->setArg(7, (float) tol);
ccmaDirectionsKernel->execute(ccmaConstraintAtoms.getSize());
const int checkInterval = 4;
ccmaConvergedMemory[0] = 0;
ccmaUpdateKernel->setArg(4, constrainVelocities ? context.getVelm() : posDelta);
for (int i = 0; i < 150; i++) {
ccmaForceKernel->setArg(8, i);
ccmaForceKernel->execute(ccmaConstraintAtoms.getSize());
if ((i+1)%checkInterval == 0)
CHECK_RESULT2(hipEventRecord(ccmaEvent, dynamic_cast<HipContext&>(context).getCurrentStream()), "Error recording event for CCMA");
ccmaMultiplyKernel->setArg(5, i);
ccmaMultiplyKernel->execute(ccmaConstraintAtoms.getSize());
ccmaUpdateKernel->setArg(9, i);
ccmaUpdateKernel->execute(context.getNumAtoms());
if ((i+1)%checkInterval == 0) {
CHECK_RESULT2(hipEventSynchronize(ccmaEvent), "Error synchronizing on event for CCMA");
if (ccmaConvergedMemory[0])
break;
}
}
}
}
}
void HipIntegrationUtilities::distributeForcesFromVirtualSites() {
ContextSelector selector(context);
for (int i = numVsiteStages-1; i >= 0; i--) {
vsiteForceKernel->setArg(2, context.getLongForceBuffer());
vsiteForceKernel->setArg(15, i);
vsiteForceKernel->execute(numVsites);
}
}
/* -------------------------------------------------------------------------- *
* OpenMM *
* -------------------------------------------------------------------------- *
* This is part of the OpenMM molecular simulation toolkit originating from *
* Simbios, the NIH National Center for Physics-Based Simulation of *
* Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. *
* *
* Portions copyright (c) 2019 Stanford University and the Authors. *
* Portions copyright (c) 2020 Advanced Micro Devices, Inc. *
* Authors: Peter Eastman, Nicholas Curtis *
* Contributors: *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as published *
* by the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* -------------------------------------------------------------------------- */
#include "HipKernel.h"
#include "openmm/common/ComputeArray.h"
#include "openmm/internal/AssertionUtilities.h"
#include <cstring>
#include <vector>
using namespace OpenMM;
using namespace std;
HipKernel::HipKernel(HipContext& context, hipFunction_t kernel, const string& name) : context(context), kernel(kernel), name(name) {
}
string HipKernel::getName() const {
return name;
}
int HipKernel::getMaxBlockSize() const {
int size;
hipError_t result = hipFuncGetAttribute(&size, HIP_FUNC_ATTRIBUTE_MAX_THREADS_PER_BLOCK, kernel);
if (result != hipSuccess)
throw OpenMMException("Error querying max thread block size: "+context.getErrorString(result));
return size;
}
void HipKernel::execute(int threads, int blockSize) {
int numArgs = arrayArgs.size();
argPointers.resize(numArgs);
for (int i = 0; i < numArgs; i++) {
if (arrayArgs[i] != NULL)
argPointers[i] = &arrayArgs[i]->getDevicePointer();
else
argPointers[i] = &primitiveArgs[i];
}
context.executeKernel(kernel, argPointers.data(), threads, blockSize);
}
void HipKernel::addArrayArg(ArrayInterface& value) {
int index = arrayArgs.size();
addEmptyArg();
setArrayArg(index, value);
}
void HipKernel::addPrimitiveArg(const void* value, int size) {
int index = arrayArgs.size();
addEmptyArg();
setPrimitiveArg(index, value, size);
}
void HipKernel::addEmptyArg() {
primitiveArgs.push_back(make_double4(0, 0, 0, 0));
arrayArgs.push_back(NULL);
}
void HipKernel::setArrayArg(int index, ArrayInterface& value) {
ASSERT_VALID_INDEX(index, arrayArgs);
arrayArgs[index] = &context.unwrap(value);
}
void HipKernel::setPrimitiveArg(int index, const void* value, int size) {
ASSERT_VALID_INDEX(index, primitiveArgs);
if (size > sizeof(double4))
throw OpenMMException("Unsupported value type for kernel argument");
memcpy(&primitiveArgs[index], value, size);
arrayArgs[index] = NULL;
}
This diff is collapsed.
/* -------------------------------------------------------------------------- *
* OpenMM *
* -------------------------------------------------------------------------- *
* This is part of the OpenMM molecular simulation toolkit originating from *
* Simbios, the NIH National Center for Physics-Based Simulation of *
* Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. *
* *
* Portions copyright (c) 2012 Stanford University and the Authors. *
* Portions copyright (c) 2020 Advanced Micro Devices, Inc. *
* Authors: Peter Eastman, Nicholas Curtis *
* Contributors: *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as published *
* by the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* -------------------------------------------------------------------------- */
#include "HipKernelSources.h"
using namespace OpenMM;
using namespace std;
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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