50#include <unordered_set>
58void assignSpan(std::span<T> &to, std::span<T>
const &from)
63void logArchitectureInfo(
bool useGPU)
75 static std::pair<bool, bool> lastUseGPU;
76 if (lastUseGPU.second && lastUseGPU.first == useGPU)
78 lastUseGPU = {useGPU,
true};
81 auto log = [](std::string_view message) {
86 log(
"using generic CPU library compiled with no vectorizations");
91 log(
"using CUDA computation library");
101void logMissingCudaSupport(
RooAbsArg const &arg)
106 static std::set<std::string> warnedClasses;
107 static std::mutex warnedClassesMutex;
108 std::scoped_lock guard{warnedClassesMutex};
109 if (warnedClasses.insert(arg.
ClassName()).second) {
111 <<
" could not be evaluated on the GPU because it doesn't support it."
112 <<
" Consider requesting or implementing it to benefit from a speed up."
128 std::shared_ptr<RooBatchCompute::AbsBuffer>
buffer;
154 : _topNode{const_cast<
RooAbsReal &>(absReal)}, _useGPU{useGPU}
158 throw std::runtime_error(
"Can't create Evaluator in CUDA mode because RooBatchCompute CUDA could not be loaded!");
174 std::map<RooFit::Detail::DataKey, NodeInfo *> nodeInfos;
178 std::size_t iNode = 0;
182 auto &nodeInfo =
_nodes.back();
185 nodeInfo.absArg = arg;
186 nodeInfo.originalOperMode = arg->
operMode();
187 nodeInfo.iNode = iNode;
188 nodeInfos[arg] = &nodeInfo;
191 nodeInfo.isVariable =
true;
196 nodeInfo.isCategory =
true;
203 info.serverInfos.reserve(info.absArg->servers().size());
204 for (
RooAbsArg *server : info.absArg->servers()) {
205 if (server->isValueServer(*info.absArg)) {
206 auto *serverInfo = nodeInfos.at(server);
207 info.serverInfos.emplace_back(serverInfo);
208 serverInfo->clientInfos.emplace_back(&info);
214 _nodes.back().isValueServer =
true;
215 for (
auto iter =
_nodes.rbegin(); iter !=
_nodes.rend(); ++iter) {
216 if (!iter->isValueServer)
218 for (
auto &serverInfo : iter->serverInfos) {
219 serverInfo->isValueServer =
true;
233 for (
auto &info :
_nodes) {
245 std::size_t iValueServer = 0;
246 for (
RooAbsArg *server : info.absArg->servers()) {
247 if (server->isValueServer(*info.absArg)) {
248 auto *knownServer = info.serverInfos[iValueServer]->absArg;
249 if (knownServer->hasDataToken()) {
250 server->setDataToken(knownServer->dataToken());
261 throw std::runtime_error(
"Evaluator can only take device array as input in CUDA mode!");
278 static std::atomic<std::size_t> nextInputGeneration{1};
279 const std::size_t gen = ++nextInputGeneration;
310 info.
buffer->assignFromDevice(gpuSpan);
316 info.
buffer->assignFromHost(cpuSpan);
323 std::map<RooFit::Detail::DataKey, std::size_t> sizeMap;
324 for (
auto &info :
_nodes) {
325 if (info.fromArrayInput) {
326 sizeMap[info.absArg] = info.outputSize;
335 auto found = sizeMap.find(key);
336 return found != sizeMap.end() ? found->second : -1;
339 for (
auto &info :
_nodes) {
340 info.outputSize = outputSizeMap.at(info.absArg);
353 for (
auto &info :
_nodes) {
355 if (!info.isVariable && info.absArg) {
356 info.absArg->resetDataToken();
371 if (found !=
_nodesMap.end() && found->second->absArg == &arg) {
372 found->second->absArg =
nullptr;
378 using namespace Detail;
382 double *buffer =
nullptr;
392 logMissingCudaSupport(*info.
absArg);
399 buffer = info.
buffer->hostWritePtr();
409 buffer[0] = nodeAbsCategory->getCurrentIndex();
411 throw std::runtime_error(
"RooFit::Evaluator - non-scalar category values are not supported!");
414 auto nodeAbsReal =
static_cast<RooAbsReal const *
>(node);
432 auto *var =
static_cast<RooRealVar const *
>(node);
436 clientInfo->isDirty =
true;
449 if (nodeInfo.
lastCatVal != cat->getCurrentIndex()) {
452 clientInfo->isDirty =
true;
464 clientInfo->isDirty =
true;
485 for (
auto &nodeInfo :
_nodes) {
486 if (!nodeInfo.fromArrayInput) {
487 if (nodeInfo.isVariable) {
489 }
else if (nodeInfo.isCategory) {
492 if (nodeInfo.isDirty) {
495 nodeInfo.isDirty =
false;
536 for (
auto &info :
_nodes) {
537 if (info.fromArrayInput) {
540 if (info.isVariable) {
542 }
else if (info.isCategory) {
544 }
else if (info.isDirty) {
546 if (info.computeInGPU) {
551 info.isDirty =
false;
584 for (
auto &action : ctx->_deferredActions) {
587 ctx->_deferredActions.clear();
597 using namespace Detail;
603 double *buffer =
nullptr;
612 buffer = info.
buffer->deviceWritePtr();
629 for (
auto &info :
_nodes) {
630 info.computeInGPU =
false;
631 if (!info.absArg->canComputeBatchWithCuda()) {
634 for (
NodeInfo const *serverInfo : info.serverInfos) {
635 if (serverInfo->outputSize > 1) {
636 info.computeInGPU =
true;
643 for (
auto &info :
_nodes) {
644 info.copyAfterEvaluation =
false;
646 if (!info.isScalar()) {
647 for (
auto *clientInfo : info.clientInfos) {
648 if (info.computeInGPU != clientInfo->computeInGPU) {
649 info.copyAfterEvaluation =
true;
666 for (
auto &info :
_nodes) {
667 if (info.isVariable) {
700 auto out = std::make_unique<ChangeOperModeRAII>();
701 std::unordered_set<RooAbsArg *> visited;
703 std::vector<RooAbsArg *> queue;
704 queue.reserve(
_nodes.size());
705 for (
auto &info :
_nodes) {
706 queue.push_back(info.absArg);
709 while (!queue.empty()) {
712 if (!visited.insert(node).second)
715 out->change(node, opMode);
721 queue.push_back(client);
730 std::cout <<
"--- RooFit BatchMode evaluation ---\n";
732 std::vector<int> widths{9, 37, 20, 9, 10, 20};
734 auto printElement = [&](
int iCol,
auto const &t) {
735 const char separator =
' ';
736 os << separator << std::left << std::setw(widths[iCol]) << std::setfill(separator) << t;
740 auto printHorizontalRow = [&]() {
742 for (
int w : widths) {
745 for (
int i = 0; i <
n; i++) {
751 printHorizontalRow();
754 printElement(0,
"Index");
755 printElement(1,
"Name");
756 printElement(2,
"Class");
757 printElement(3,
"Size");
758 printElement(4,
"From Data");
759 printElement(5,
"1st value");
762 printHorizontalRow();
764 for (std::size_t iNode = 0; iNode <
_nodes.size(); ++iNode) {
765 auto &nodeInfo =
_nodes[iNode];
771 printElement(0, iNode);
772 printElement(1, node->
GetName());
774 printElement(3, nodeInfo.outputSize);
775 printElement(4, nodeInfo.fromArrayInput);
776 printElement(5, span[0]);
781 printHorizontalRow();
793 for (
auto &nodeInfo :
_nodes) {
794 if (nodeInfo.isValueServer && nodeInfo.absArg->isFundamental()) {
795 parameters.
add(*nodeInfo.absArg);
820 for (
auto &nodeInfo :
_nodes) {
821 if (nodeInfo.absArg->isReducerNode()) {
822 nodeInfo.isDirty =
true;
Option_t Option_t TPoint TPoint const char mode
Common abstract base class for objects that represent a value and a "shape" in RooFit.
const TNamed * namePtr() const
De-duplicated pointer to this object's name.
const RefCountList_t & valueClients() const
List of all value clients of this object. Value clients receive value updates.
void setDataToken(std::size_t index, RooFit::Evaluator *evaluator=nullptr)
Sets the token for retrieving results in the BatchMode.
OperMode operMode() const
Query the operation mode of this node.
A space to attach TBranches.
virtual bool add(const RooAbsArg &var, bool silent=false)
Add the specified argument to list.
Storage_t::size_type size() const
void sort(bool reverse=false)
Sort collection using std::sort and name comparison.
Abstract base class for objects that represent a real value and implements functionality common to al...
virtual void doEval(RooFit::EvalContext &) const
Base function for computing multiple values of a RooAbsReal.
RooArgSet is a container object that can hold multiple RooAbsArg objects.
Minimal configuration struct to steer the evaluation of a single node with the RooBatchCompute librar...
void setCudaStream(CudaInterface::CudaStream *cudaStream)
void setNThreads(int nThreads)
Number of threads to use for CPU batch computations and reductions.
virtual void synchronizeCudaStream(CudaInterface::CudaStream *) const =0
Wait until all work that was enqueued on the stream has completed.
virtual std::unique_ptr< AbsBufferManager > createBufferManager() const =0
virtual CudaInterface::CudaStream * newCudaStream() const =0
virtual void deleteCudaStream(CudaInterface::CudaStream *) const =0
std::size_t _inputGeneration
std::vector< std::function< void()> > _deferredActions
void set(RooAbsArg const *arg, std::span< const double > const &span)
std::span< const double > at(RooAbsArg const *arg, RooAbsArg const *caller=nullptr)
void resetVectorBuffers()
void enableVectorBuffers(bool enable)
RooBatchCompute::Config config(RooAbsArg const *arg) const
void setConfig(RooAbsArg const *arg, RooBatchCompute::Config const &config)
std::span< double > _currentOutput
void resize(std::size_t n)
void print(std::ostream &os)
void setClientsDirty(NodeInfo &nodeInfo)
Flags all the clients of a given node dirty.
std::unique_ptr< ChangeOperModeRAII > setOperModes(RooAbsArg::OperMode opMode)
RooArgSet getParameters() const
Gets all the parameters of the RooAbsReal.
void setOffsetMode(RooFit::EvalContext::OffsetMode)
Sets the offset mode for evaluation.
void unregisterNode(RooAbsArg const &arg)
Called from RooAbsArg::~RooAbsArg() when a node of the computation graph is deleted while this Evalua...
void syncDataTokens()
If there are servers with the same name that got de-duplicated in the _nodes list,...
std::unordered_map< TNamed const *, NodeInfo * > _nodesMap
std::unique_ptr< ChangeOperModeRAII > _operModeChanges
std::vector< NodeInfo > _nodes
bool _needToUpdateOutputSizes
std::span< const double > getValHeterogeneous()
Returns the value of the top node in the computation graph.
std::span< const double > run()
Returns the value of the top node in the computation graph.
Evaluator(const RooAbsReal &absReal, bool useGPU=false)
Construct a new Evaluator.
void setNThreads(int nThreads)
Sets the number of threads to use for the evaluation of a single node.
void processVariable(NodeInfo &nodeInfo)
Process a variable in the computation graph.
void processCategory(NodeInfo &nodeInfo)
Process a category in the computation graph.
RooBatchCompute::CudaInterface::CudaStream * _cudaStream
std::unique_ptr< RooBatchCompute::AbsBufferManager > _bufferManager
void markGPUNodes()
Decides which nodes are assigned to the GPU in a CUDA fit.
void assignToGPU(NodeInfo &info)
Enqueue the computation of a node on the GPU.
void setInput(std::string const &name, std::span< const double > inputArray, bool isOnDevice)
RooFit::EvalContext _evalContextCUDA
RooFit::EvalContext _evalContextCPU
void computeCPUNode(const RooAbsArg *node, NodeInfo &info)
void setOperMode(RooAbsArg *arg, RooAbsArg::OperMode opMode)
Temporarily change the operation mode of a RooAbsArg until the Evaluator gets deleted.
static RooMsgService & instance()
Return reference to singleton instance.
static const TNamed * ptr(const char *stringPtr)
Return a unique TNamed pointer for given C++ string.
Variable that can be changed from the outside.
const char * GetName() const override
Returns name of object.
virtual const char * ClassName() const
Returns name of class to which the object belongs.
RVec< PromoteType< T > > log(const RVec< T > &v)
R__EXTERN RooBatchComputeInterface * dispatchCUDA
std::string cpuArchitectureName()
R__EXTERN RooBatchComputeInterface * dispatchCPU
This dispatch pointer points to an implementation of the compute library, provided one has been loade...
Architecture cpuArchitecture()
int initCPU()
Inspect hardware capabilities, and load the optimal library for RooFit computations.
The namespace RooFit contains mostly switches that change the behaviour of functions of PDFs (or othe...
void getSortedComputationGraph(RooAbsArg const &func, RooArgSet &out)
A struct used by the Evaluator to store information on the RooAbsArgs in the computation graph.
std::size_t lastSetValCount
std::vector< NodeInfo * > serverInfos
RooAbsArg::OperMode originalOperMode
std::vector< NodeInfo * > clientInfos
std::shared_ptr< RooBatchCompute::AbsBuffer > buffer