Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
Evaluator.cxx
Go to the documentation of this file.
1/*
2 * Project: RooFit
3 * Authors:
4 * Jonas Rembser, CERN 2021
5 * Emmanouil Michalainas, CERN 2021
6 *
7 * Copyright (c) 2021, CERN
8 *
9 * Redistribution and use in source and binary forms,
10 * with or without modification, are permitted according to the terms
11 * listed in LICENSE (http://roofit.sourceforge.net/license.txt)
12 */
13
14/**
15\file Evaluator.cxx
16\class RooFit::Evaluator
17\ingroup Roofitcore
18
19Evaluates a RooAbsReal object in other ways than recursive graph
20traversal. Currently, it is being used for evaluating a RooAbsReal object and
21supplying the value to the minimizer, during a fit. The class scans the
22dependencies and schedules the computations in a secure and efficient way. The
23computations take place in the RooBatchCompute library and can be carried off
24by either the CPU or a CUDA-supporting GPU. The Evaluator class takes care
25of data transfers. An instance of this class is created every time
26RooAbsPdf::fitTo() is called and gets destroyed when the fitting ends.
27**/
28
29#include <RooFit/Evaluator.h>
30
31#include <RooAbsCategory.h>
32#include <RooAbsData.h>
33#include <RooAbsReal.h>
34#include <RooRealVar.h>
35#include <RooBatchCompute.h>
36#include <RooMsgService.h>
37#include <RooNameReg.h>
38#include <RooSimultaneous.h>
39
40#include <RooBatchCompute.h>
41
43#include "RooFitImplHelpers.h"
44
45#include <chrono>
46#include <iomanip>
47#include <numeric>
48#include <thread>
49#include <unordered_set>
50
51namespace RooFit {
52
53namespace {
54
55// To avoid deleted move assignment.
56template <class T>
57void assignSpan(std::span<T> &to, std::span<T> const &from)
58{
59 to = from;
60}
61
63{
64 // We have to exit early if the message stream is not active. Otherwise it's
65 // possible that this function skips logging because it thinks it has
66 // already logged, but actually it didn't.
67 if (!RooMsgService::instance().isActive(nullptr, RooFit::Fitting, RooFit::INFO)) {
68 return;
69 }
70
71 // Don't repeat logging architecture info if the useGPU option didn't change
72 {
73 // Second element of pair tracks whether this function has already been called
74 static std::pair<bool, bool> lastUseGPU;
75 if (lastUseGPU.second && lastUseGPU.first == useGPU)
76 return;
77 lastUseGPU = {useGPU, true};
78 }
79
80 auto log = [](std::string_view message) {
81 oocxcoutI(static_cast<RooAbsArg *>(nullptr), Fitting) << message << std::endl;
82 };
83
85 log("using generic CPU library compiled with no vectorizations");
86 } else {
87 log(std::string("using CPU computation library compiled with -m") + RooBatchCompute::cpuArchitectureName());
88 }
89 if (useGPU) {
90 log("using CUDA computation library");
91 }
92}
93
94} // namespace
95
96/// A struct used by the Evaluator to store information on the RooAbsArgs in
97/// the computation graph.
98struct NodeInfo {
99
100 bool isScalar() const { return outputSize == 1; }
101
102 RooAbsArg *absArg = nullptr;
104
105 std::shared_ptr<RooBatchCompute::AbsBuffer> buffer;
106 std::size_t iNode = 0;
107 int remClients = 0;
108 int remServers = 0;
110 bool fromArrayInput = false;
111 bool isVariable = false;
112 bool isDirty = true;
113 bool isCategory = false;
114 bool hasLogged = false;
115 bool computeInGPU = false;
116 bool isValueServer = false; // if this node is a value server to the top node
117 std::size_t outputSize = 1;
118 std::size_t lastSetValCount = std::numeric_limits<std::size_t>::max();
119 int lastCatVal = std::numeric_limits<int>::max();
120 double scalarBuffer = 0.0;
121 std::vector<NodeInfo *> serverInfos;
122 std::vector<NodeInfo *> clientInfos;
123
126
127 /// Check the servers of a node that has been computed and release its
128 /// resources if they are no longer needed.
130 {
131 if (--remClients == 0 && !fromArrayInput) {
132 buffer.reset();
133 }
134 }
135
143};
144
145/// Construct a new Evaluator. The constructor analyzes and saves metadata about the graph,
146/// useful for the evaluation of it that will be done later. In case the CUDA mode is selected,
147/// there's also some CUDA-related initialization.
148///
149/// \param[in] absReal The RooAbsReal object that sits on top of the
150/// computation graph that we want to evaluate.
151/// \param[in] useGPU Whether the evaluation should be preferably done on the GPU.
153 : _topNode{const_cast<RooAbsReal &>(absReal)}, _useGPU{useGPU}
154{
156 if (useGPU && RooBatchCompute::initCUDA() != 0) {
157 throw std::runtime_error("Can't create Evaluator in CUDA mode because RooBatchCompute CUDA could not be loaded!");
158 }
159 // Some checks and logging of used architectures
161
164
167
169 if (useGPU) {
171 }
172
173 std::map<RooFit::Detail::DataKey, NodeInfo *> nodeInfos;
174
175 // Fill the ordered nodes list and initialize the node info structs.
176 _nodes.reserve(serverSet.size());
177 std::size_t iNode = 0;
178 for (RooAbsArg *arg : serverSet) {
179
180 _nodes.emplace_back();
181 auto &nodeInfo = _nodes.back();
182 _nodesMap[arg->namePtr()] = &nodeInfo;
183
184 nodeInfo.absArg = arg;
185 nodeInfo.originalOperMode = arg->operMode();
186 nodeInfo.iNode = iNode;
187 nodeInfos[arg] = &nodeInfo;
188
189 if (dynamic_cast<RooRealVar const *>(arg)) {
190 nodeInfo.isVariable = true;
191 } else {
192 arg->setDataToken(iNode, this);
193 }
194 if (dynamic_cast<RooAbsCategory const *>(arg)) {
195 nodeInfo.isCategory = true;
196 }
197
198 ++iNode;
199 }
200
201 for (NodeInfo &info : _nodes) {
202 info.serverInfos.reserve(info.absArg->servers().size());
203 for (RooAbsArg *server : info.absArg->servers()) {
204 if (server->isValueServer(*info.absArg)) {
205 auto *serverInfo = nodeInfos.at(server);
206 info.serverInfos.emplace_back(serverInfo);
207 serverInfo->clientInfos.emplace_back(&info);
208 }
209 }
210 }
211
212 // Figure out which nodes are value servers to the top node
213 _nodes.back().isValueServer = true; // the top node itself
214 for (auto iter = _nodes.rbegin(); iter != _nodes.rend(); ++iter) {
215 if (!iter->isValueServer)
216 continue;
217 for (auto &serverInfo : iter->serverInfos) {
218 serverInfo->isValueServer = true;
219 }
220 }
221
223
224 if (_useGPU) {
225 // create events and streams for every node
226 for (auto &info : _nodes) {
230 cfg.setCudaStream(info.stream);
231 _evalContextCUDA.setConfig(info.absArg, cfg);
232 }
233 }
234}
235
236/// If there are servers with the same name that got de-duplicated in the
237/// `_nodes` list, we need to set their data tokens too. We find such nodes by
238/// visiting the servers of every known node.
240{
241 for (NodeInfo &info : _nodes) {
242 std::size_t iValueServer = 0;
243 for (RooAbsArg *server : info.absArg->servers()) {
244 if (server->isValueServer(*info.absArg)) {
245 auto *knownServer = info.serverInfos[iValueServer]->absArg;
246 if (knownServer->hasDataToken()) {
247 server->setDataToken(knownServer->dataToken());
248 }
249 ++iValueServer;
250 }
251 }
252 }
253}
254
255void Evaluator::setInput(std::string const &name, std::span<const double> inputArray, bool isOnDevice)
256{
257 if (isOnDevice && !_useGPU) {
258 throw std::runtime_error("Evaluator can only take device array as input in CUDA mode!");
259 }
260
261 // Check if "name" is used in the computation graph. If yes, add the span to
262 // the data map and set the node info accordingly.
263
264 auto found = _nodesMap.find(RooNameReg::ptr(name.c_str()));
265
266 if (found == _nodesMap.end())
267 return;
268
270
271 NodeInfo &info = *found->second;
272
273 info.fromArrayInput = true;
274 info.absArg->setDataToken(info.iNode);
275 info.outputSize = inputArray.size();
276
277 if (!_useGPU) {
279 return;
280 }
281
282 if (info.outputSize <= 1) {
283 // Empty or scalar observables from the data don't need to be
284 // copied to the GPU.
287 return;
288 }
289
290 // For simplicity, we put the data on both host and device for
291 // now. This could be optimized by inspecting the clients of the
292 // variable.
293 if (isOnDevice) {
295 auto gpuSpan = _evalContextCUDA.at(info.absArg);
296 info.buffer = _bufferManager->makeCpuBuffer(gpuSpan.size());
297 info.buffer->assignFromDevice(gpuSpan);
298 _evalContextCPU.set(info.absArg, {info.buffer->hostReadPtr(), gpuSpan.size()});
299 } else {
301 auto cpuSpan = _evalContextCPU.at(info.absArg);
302 info.buffer = _bufferManager->makeGpuBuffer(cpuSpan.size());
303 info.buffer->assignFromHost(cpuSpan);
304 _evalContextCUDA.set(info.absArg, {info.buffer->deviceReadPtr(), cpuSpan.size()});
305 }
306}
307
309{
310 std::map<RooFit::Detail::DataKey, std::size_t> sizeMap;
311 for (auto &info : _nodes) {
312 if (info.fromArrayInput) {
313 sizeMap[info.absArg] = info.outputSize;
314 } else {
315 // any buffer for temporary results is invalidated by resetting the output sizes
316 info.buffer.reset();
317 }
318 }
319
320 auto outputSizeMap =
321 RooFit::BatchModeDataHelpers::determineOutputSizes(_topNode, [&](RooFit::Detail::DataKey key) -> int {
322 auto found = sizeMap.find(key);
323 return found != sizeMap.end() ? found->second : -1;
324 });
325
326 for (auto &info : _nodes) {
327 info.outputSize = outputSizeMap.at(info.absArg);
328 info.isDirty = true;
329 }
330
331 if (_useGPU) {
332 markGPUNodes();
333 }
334
336}
337
339{
340 for (auto &info : _nodes) {
341 // Nodes that were deleted before the Evaluator were unregistered
342 if (!info.isVariable && info.absArg) {
343 info.absArg->resetDataToken();
344 }
345 }
346}
347
348/// Called from RooAbsArg::~RooAbsArg() when a node of the computation graph is
349/// deleted while this Evaluator is still alive. The Evaluator can't be used
350/// anymore after that, but its destructor must not touch the deleted node.
351/// For internal use only.
353{
354 auto found = _nodesMap.find(arg.namePtr());
355 if (found != _nodesMap.end() && found->second->absArg == &arg) {
356 found->second->absArg = nullptr;
357 }
358}
359
361{
362 using namespace Detail;
363
364 const std::size_t nOut = info.outputSize;
365
366 double *buffer = nullptr;
367 if (nOut == 1) {
368 buffer = &info.scalarBuffer;
369 if (_useGPU) {
370 _evalContextCUDA.set(node, {buffer, nOut});
371 }
372 } else {
373 if (!info.hasLogged && _useGPU) {
374 RooAbsArg const &arg = *info.absArg;
375 oocoutI(&arg, FastEvaluations) << "The argument " << arg.ClassName() << "::" << arg.GetName()
376 << " could not be evaluated on the GPU because the class doesn't support it. "
377 "Consider requesting or implementing it to benefit from a speed up."
378 << std::endl;
379 info.hasLogged = true;
380 }
381 if (!info.buffer) {
382 info.buffer = info.copyAfterEvaluation ? _bufferManager->makePinnedBuffer(nOut, info.stream)
383 : _bufferManager->makeCpuBuffer(nOut);
384 }
385 buffer = info.buffer->hostWritePtr();
386 }
388 _evalContextCPU.set(node, {buffer, nOut});
389 if (nOut > 1) {
391 }
392 if (info.isCategory) {
393 auto nodeAbsCategory = static_cast<RooAbsCategory const *>(node);
394 if (nOut == 1) {
395 buffer[0] = nodeAbsCategory->getCurrentIndex();
396 } else {
397 throw std::runtime_error("RooFit::Evaluator - non-scalar category values are not supported!");
398 }
399 } else {
400 auto nodeAbsReal = static_cast<RooAbsReal const *>(node);
402 }
405 if (info.copyAfterEvaluation) {
406 _evalContextCUDA.set(node, {info.buffer->deviceReadPtr(), nOut});
407 if (info.event) {
409 }
410 }
411}
412
413/// Process a variable in the computation graph. This is a separate non-inlined
414/// function such that we can see in performance profiles how long this takes.
416{
417 RooAbsArg *node = nodeInfo.absArg;
418 auto *var = static_cast<RooRealVar const *>(node);
419 if (nodeInfo.lastSetValCount != var->valueResetCounter()) {
420 nodeInfo.lastSetValCount = var->valueResetCounter();
421 for (NodeInfo *clientInfo : nodeInfo.clientInfos) {
422 clientInfo->isDirty = true;
423 }
425 nodeInfo.isDirty = false;
426 }
427}
428
429/// Process a category in the computation graph. This is a separate non-inlined
430/// function such that we can see in performance profiles how long this takes.
432{
433 RooAbsArg *node = nodeInfo.absArg;
434 auto *cat = static_cast<RooAbsCategory const *>(node);
435 if (nodeInfo.lastCatVal != cat->getCurrentIndex()) {
436 nodeInfo.lastCatVal = cat->getCurrentIndex();
437 for (NodeInfo *clientInfo : nodeInfo.clientInfos) {
438 clientInfo->isDirty = true;
439 }
441 nodeInfo.isDirty = false;
442 }
443}
444
445/// Flags all the clients of a given node dirty. This is a separate non-inlined
446/// function such that we can see in performance profiles how long this takes.
448{
449 for (NodeInfo *clientInfo : nodeInfo.clientInfos) {
450 clientInfo->isDirty = true;
451 }
452}
453
454/// Returns the value of the top node in the computation graph
455std::span<const double> Evaluator::run()
456{
459
461
462 if (_useGPU) {
463 return getValHeterogeneous();
464 }
465
466 for (auto &nodeInfo : _nodes) {
467 if (!nodeInfo.fromArrayInput) {
468 if (nodeInfo.isVariable) {
470 } else if (nodeInfo.isCategory) {
472 } else {
473 if (nodeInfo.isDirty) {
476 nodeInfo.isDirty = false;
477 }
478 }
479 }
480 }
481
482 // return the final output
483 return _evalContextCPU.at(&_topNode);
484}
485
486/// Returns the value of the top node in the computation graph
487std::span<const double> Evaluator::getValHeterogeneous()
488{
489 for (auto &info : _nodes) {
490 info.remClients = info.clientInfos.size();
491 info.remServers = info.serverInfos.size();
492 if (info.buffer && !info.fromArrayInput) {
493 info.buffer.reset();
494 }
495 }
496
497 // find initial GPU nodes and assign them to GPU
498 for (auto &info : _nodes) {
499 if (info.remServers == 0 && info.computeInGPU) {
501 }
502 }
503
504 NodeInfo const &topNodeInfo = _nodes.back();
505 while (topNodeInfo.remServers != -2) {
506 // find finished GPU nodes
507 for (auto &info : _nodes) {
508 if (info.remServers == -1 && !RooBatchCompute::dispatchCUDA->cudaStreamIsActive(info.stream)) {
509 info.remServers = -2;
510 // Decrement number of remaining servers for clients and start GPU computations
511 for (auto *infoClient : info.clientInfos) {
512 --infoClient->remServers;
513 if (infoClient->computeInGPU && infoClient->remServers == 0) {
515 }
516 }
517 for (auto *serverInfo : info.serverInfos) {
518 serverInfo->decrementRemainingClients();
519 }
520 }
521 }
522
523 // find next CPU node
524 auto it = _nodes.begin();
525 for (; it != _nodes.end(); it++) {
526 if (it->remServers == 0 && !it->computeInGPU)
527 break;
528 }
529
530 // if no CPU node available sleep for a while to save CPU usage
531 if (it == _nodes.end()) {
532 std::this_thread::sleep_for(std::chrono::milliseconds(1));
533 continue;
534 }
535
536 // compute next CPU node
537 NodeInfo &info = *it;
538 RooAbsArg const *node = info.absArg;
539 info.remServers = -2; // so that it doesn't get picked again
540
541 if (!info.fromArrayInput) {
542 computeCPUNode(node, info);
543 }
544
545 // Assign the clients that are computed on the GPU
546 for (auto *infoClient : info.clientInfos) {
547 if (--infoClient->remServers == 0 && infoClient->computeInGPU) {
549 }
550 }
551 for (auto *serverInfo : info.serverInfos) {
552 serverInfo->decrementRemainingClients();
553 }
554 }
555
556 // return the final value
558}
559
560/// Assign a node to be computed in the GPU. Scan it's clients and also assign them
561/// in case they only depend on GPU nodes.
563{
564 using namespace Detail;
565
566 info.remServers = -1;
567
568 auto node = static_cast<RooAbsReal const *>(info.absArg);
569
570 // wait for every server to finish
571 for (auto *infoServer : info.serverInfos) {
572 if (infoServer->event)
574 }
575
576 const std::size_t nOut = info.outputSize;
577
578 double *buffer = nullptr;
579 if (nOut == 1) {
580 buffer = &info.scalarBuffer;
581 _evalContextCPU.set(node, {buffer, nOut});
582 } else {
583 info.buffer = info.copyAfterEvaluation ? _bufferManager->makePinnedBuffer(nOut, info.stream)
584 : _bufferManager->makeGpuBuffer(nOut);
585 buffer = info.buffer->deviceWritePtr();
586 }
588 _evalContextCUDA.set(node, {buffer, nOut});
589 node->doEval(_evalContextCUDA);
591 if (info.copyAfterEvaluation) {
592 _evalContextCPU.set(node, {info.buffer->hostReadPtr(), nOut});
593 }
594}
595
596/// Decides which nodes are assigned to the GPU in a CUDA fit.
598{
599 // Decide which nodes get evaluated on the GPU: we select nodes that support
600 // CUDA evaluation and have at least one input of size greater than one.
601 for (auto &info : _nodes) {
602 info.computeInGPU = false;
603 if (!info.absArg->canComputeBatchWithCuda()) {
604 continue;
605 }
606 for (NodeInfo const *serverInfo : info.serverInfos) {
607 if (serverInfo->outputSize > 1) {
608 info.computeInGPU = true;
609 break;
610 }
611 }
612 }
613
614 // In a second pass, figure out which nodes need to copy over their results.
615 for (auto &info : _nodes) {
616 info.copyAfterEvaluation = false;
617 // scalar nodes don't need copying
618 if (!info.isScalar()) {
619 for (auto *clientInfo : info.clientInfos) {
620 if (info.computeInGPU != clientInfo->computeInGPU) {
621 info.copyAfterEvaluation = true;
622 break;
623 }
624 }
625 }
626 }
627}
628
629/// Temporarily change the operation mode of a RooAbsArg until the
630/// Evaluator gets deleted.
632{
633 if (!_operModeChanges)
634 _operModeChanges = std::make_unique<ChangeOperModeRAII>();
635 _operModeChanges->change(arg, opMode);
636}
637
638// Change the operation modes of all RooAbsArgs in the computation graph.
639// The changes are reset when the returned RAII object goes out of scope.
640//
641// We also walk transitively through value clients of the nodes to cover any
642// node that RooAbsReal::doEval (the fallback scalar implementation) might
643// inadvertently propagate the ADirty mode to via its recursive restore: that
644// helper sets servers temporarily to AClean and then calls
645// setOperMode(oldOperMode) to restore, which recurses to value clients when
646// oldOperMode is ADirty. If we did not protect those clients here, any node
647// outside the computation graph that shares a fundamental (e.g. a parameter
648// like a RooRealVar) would be left permanently in ADirty after the first
649// minimization, dramatically slowing down later scalar evaluations (for
650// example on pdfs held by the legacy test statistics' internal cache).
651std::unique_ptr<ChangeOperModeRAII> Evaluator::setOperModes(RooAbsArg::OperMode opMode)
652{
653 auto out = std::make_unique<ChangeOperModeRAII>();
654 std::unordered_set<RooAbsArg *> visited;
655
656 std::vector<RooAbsArg *> queue;
657 queue.reserve(_nodes.size());
658 for (auto &info : _nodes) {
659 queue.push_back(info.absArg);
660 }
661
662 while (!queue.empty()) {
663 RooAbsArg *node = queue.back();
664 queue.pop_back();
665 if (!visited.insert(node).second)
666 continue;
667
668 out->change(node, opMode);
669
670 // Only follow value-client links: that is exactly the propagation path
671 // used by RooAbsArg::setOperMode with mode==ADirty.
672 if (opMode == RooAbsArg::ADirty) {
673 for (auto *client : node->valueClients()) {
674 queue.push_back(client);
675 }
676 }
677 }
678 return out;
679}
680
681void Evaluator::print(std::ostream &os)
682{
683 std::cout << "--- RooFit BatchMode evaluation ---\n";
684
685 std::vector<int> widths{9, 37, 20, 9, 10, 20};
686
687 auto printElement = [&](int iCol, auto const &t) {
688 const char separator = ' ';
689 os << separator << std::left << std::setw(widths[iCol]) << std::setfill(separator) << t;
690 os << "|";
691 };
692
693 auto printHorizontalRow = [&]() {
694 int n = 0;
695 for (int w : widths) {
696 n += w + 2;
697 }
698 for (int i = 0; i < n; i++) {
699 os << '-';
700 }
701 os << "|\n";
702 };
703
705
706 os << "|";
707 printElement(0, "Index");
708 printElement(1, "Name");
709 printElement(2, "Class");
710 printElement(3, "Size");
711 printElement(4, "From Data");
712 printElement(5, "1st value");
713 std::cout << "\n";
714
716
717 for (std::size_t iNode = 0; iNode < _nodes.size(); ++iNode) {
718 auto &nodeInfo = _nodes[iNode];
719 RooAbsArg *node = nodeInfo.absArg;
720
721 auto span = _evalContextCPU.at(node);
722
723 os << "|";
724 printElement(0, iNode);
725 printElement(1, node->GetName());
726 printElement(2, node->ClassName());
727 printElement(3, nodeInfo.outputSize);
728 printElement(4, nodeInfo.fromArrayInput);
729 printElement(5, span[0]);
730
731 std::cout << "\n";
732 }
733
735}
736
737/// Gets all the parameters of the RooAbsReal. This is in principle not
738/// necessary, because we can always ask the RooAbsReal itself, but the
739/// Evaluator has the cached information to get the answer quicker.
740/// Therefore, this is not meant to be used in general, just where it matters.
741/// \warning If we find another solution to get the parameters efficiently,
742/// this function might be removed without notice.
744{
745 RooArgSet parameters;
746 for (auto &nodeInfo : _nodes) {
747 if (nodeInfo.isValueServer && nodeInfo.absArg->isFundamental()) {
748 parameters.add(*nodeInfo.absArg);
749 }
750 }
751 // Just like in RooAbsArg::getParameters(), we sort the parameters alphabetically.
752 parameters.sort();
753 return parameters;
754}
755
756/// \brief Sets the offset mode for evaluation.
757///
758/// This function sets the offset mode for evaluation to the specified mode.
759/// It updates the offset mode for both CPU and CUDA evaluation contexts.
760///
761/// \param mode The offset mode to be set.
762///
763/// \note This function marks reducer nodes as dirty if the offset mode is
764/// changed, because only reducer nodes can use offsetting.
766{
768 return;
769
772
773 for (auto &nodeInfo : _nodes) {
774 if (nodeInfo.absArg->isReducerNode()) {
775 nodeInfo.isDirty = true;
776 }
777 }
778}
779
780} // namespace RooFit
#define oocoutI(o, a)
#define oocxcoutI(o, a)
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
Option_t Option_t TPoint TPoint const char mode
char name[80]
Definition TGX11.cxx:145
const_iterator begin() const
const_iterator end() const
Common abstract base class for objects that represent a value and a "shape" in RooFit.
Definition RooAbsArg.h:77
const TNamed * namePtr() const
De-duplicated pointer to this object's name.
Definition RooAbsArg.h:504
const RefCountList_t & valueClients() const
List of all value clients of this object. Value clients receive value updates.
Definition RooAbsArg.h:140
A space to attach TBranches.
virtual bool add(const RooAbsArg &var, bool silent=false)
Add the specified argument to list.
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...
Definition RooAbsReal.h:63
RooArgSet is a container object that can hold multiple RooAbsArg objects.
Definition RooArgSet.h:24
Minimal configuration struct to steer the evaluation of a single node with the RooBatchCompute librar...
void setCudaStream(CudaInterface::CudaStream *cudaStream)
virtual void deleteCudaEvent(CudaInterface::CudaEvent *) const =0
virtual CudaInterface::CudaEvent * newCudaEvent(bool forTiming) const =0
virtual void cudaEventRecord(CudaInterface::CudaEvent *, CudaInterface::CudaStream *) const =0
virtual std::unique_ptr< AbsBufferManager > createBufferManager() const =0
virtual void cudaStreamWaitForEvent(CudaInterface::CudaStream *, CudaInterface::CudaEvent *) const =0
virtual CudaInterface::CudaStream * newCudaStream() const =0
virtual void deleteCudaStream(CudaInterface::CudaStream *) const =0
virtual bool cudaStreamIsActive(CudaInterface::CudaStream *) const =0
void set(RooAbsArg const *arg, std::span< const double > const &span)
Definition EvalContext.h:91
std::span< const double > at(RooAbsArg const *arg, RooAbsArg const *caller=nullptr)
void enableVectorBuffers(bool enable)
OffsetMode _offsetMode
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,...
const bool _useGPU
Definition Evaluator.h:65
std::unordered_map< TNamed const *, NodeInfo * > _nodesMap
Definition Evaluator.h:71
std::unique_ptr< ChangeOperModeRAII > _operModeChanges
Definition Evaluator.h:72
std::vector< NodeInfo > _nodes
Definition Evaluator.h:70
bool _needToUpdateOutputSizes
Definition Evaluator.h:67
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 processVariable(NodeInfo &nodeInfo)
Process a variable in the computation graph.
void processCategory(NodeInfo &nodeInfo)
Process a category in the computation graph.
std::unique_ptr< RooBatchCompute::AbsBufferManager > _bufferManager
Definition Evaluator.h:63
void markGPUNodes()
Decides which nodes are assigned to the GPU in a CUDA fit.
void assignToGPU(NodeInfo &info)
Assign a node to be computed in the GPU.
void setInput(std::string const &name, std::span< const double > inputArray, bool isOnDevice)
RooFit::EvalContext _evalContextCUDA
Definition Evaluator.h:69
RooFit::EvalContext _evalContextCPU
Definition Evaluator.h:68
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.
RooAbsReal & _topNode
Definition Evaluator.h:64
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.
Definition RooRealVar.h:37
const char * GetName() const override
Returns name of object.
Definition TNamed.h:49
virtual const char * ClassName() const
Returns name of class to which the object belongs.
Definition TObject.cxx:224
RVec< PromoteType< T > > log(const RVec< T > &v)
Definition RVec.hxx:1836
const Int_t n
Definition legend1.C:16
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...
Definition CodegenImpl.h:72
@ FastEvaluations
void getSortedComputationGraph(RooAbsArg const &func, RooArgSet &out)
A struct used by the Evaluator to store information on the RooAbsArgs in the computation graph.
Definition Evaluator.cxx:98
RooBatchCompute::CudaInterface::CudaStream * stream
RooAbsArg * absArg
bool isScalar() const
std::size_t iNode
std::size_t lastSetValCount
RooBatchCompute::CudaInterface::CudaEvent * event
std::vector< NodeInfo * > serverInfos
RooAbsArg::OperMode originalOperMode
std::size_t outputSize
std::vector< NodeInfo * > clientInfos
std::shared_ptr< RooBatchCompute::AbsBuffer > buffer
void decrementRemainingClients()
Check the servers of a node that has been computed and release its resources if they are no longer ne...