BioDynaMo  v1.05.0-137fdb15
resource_manager.h
Go to the documentation of this file.
1 // -----------------------------------------------------------------------------
2 //
3 // Copyright (C) 2021 CERN & University of Surrey for the benefit of the
4 // BioDynaMo collaboration. All Rights Reserved.
5 //
6 // Licensed under the Apache License, Version 2.0 (the "License");
7 // you may not use this file except in compliance with the License.
8 //
9 // See the LICENSE file distributed with this work for details.
10 // See the NOTICE file distributed with this work for additional information
11 // regarding copyright ownership.
12 //
13 // -----------------------------------------------------------------------------
14 
15 #ifndef CORE_RESOURCE_MANAGER_H_
16 #define CORE_RESOURCE_MANAGER_H_
17 
18 #include <omp.h>
19 #include <sched.h>
20 #include <algorithm>
21 #include <cmath>
22 #include <limits>
23 #include <memory>
24 #include <ostream>
25 #include <set>
26 #include <string>
27 #include <unordered_map>
28 #include <utility>
29 #include <vector>
30 
31 #include "core/agent/agent.h"
33 #include "core/agent/agent_uid.h"
38 #include "core/functor.h"
40 #include "core/simulation.h"
41 #include "core/type_index.h"
42 #include "core/util/numa.h"
43 #include "core/util/root.h"
44 #include "core/util/thread_info.h"
45 #include "core/util/type.h"
46 
47 namespace bdm {
48 
54  public:
55  explicit ResourceManager(TRootIOCtor* r) {}
56 
58 
59  virtual ~ResourceManager();
60 
62  if (agents_.size() != other.agents_.size()) {
63  Log::Fatal(
64  "Restored ResourceManager has different number of NUMA nodes.");
65  }
66  for (auto& el : continuum_models_) {
67  delete el.second;
68  }
69  for (auto& numa_agents : agents_) {
70  for (auto* agent : numa_agents) {
71  delete agent;
72  }
73  }
74  agents_ = std::move(other.agents_);
75  agents_lb_.resize(agents_.size());
76  continuum_models_ = std::move(other.continuum_models_);
77 
79  // restore type_index_
80  if (type_index_) {
81  for (auto& numa_agents : agents_) {
82  for (auto* agent : numa_agents) {
83  type_index_->Add(agent);
84  }
85  }
86  }
87  return *this;
88  }
89 
91  // rebuild uid_ah_map_
92  uid_ah_map_.clear();
93  auto* agent_uid_generator = Simulation::GetActive()->GetAgentUidGenerator();
94  uid_ah_map_.resize(agent_uid_generator->GetHighestIndex() + 1);
95  for (AgentHandle::NumaNode_t n = 0; n < agents_.size(); ++n) {
96  for (AgentHandle::ElementIdx_t i = 0; i < agents_[n].size(); ++i) {
97  auto* agent = agents_[n][i];
98  this->uid_ah_map_.Insert(agent->GetUid(), AgentHandle(n, i));
99  }
100  }
101  }
102 
103  Agent* GetAgent(const AgentUid& uid) {
104  if (!uid_ah_map_.Contains(uid)) {
105  return nullptr;
106  }
107  auto& ah = uid_ah_map_[uid];
108  return agents_[ah.GetNumaNode()][ah.GetElementIdx()];
109  }
110 
112  return agents_[ah.GetNumaNode()][ah.GetElementIdx()];
113  }
114 
115  AgentHandle GetAgentHandle(const AgentUid& uid) { return uid_ah_map_[uid]; }
116 
117  void SwapAgents(std::vector<std::vector<Agent*>>* agents);
118 
119  [[deprecated("Use AddContinuum() instead")]] void AddDiffusionGrid(
120  DiffusionGrid* dgrid) {
121  AddContinuum(dgrid);
122  }
123 
125  auto tmp = cm->GetContinuumId();
126  if (tmp < 0) {
127  Log::Fatal("ResourceManager::AddContinuum",
128  "You tried to add a continuum model that was not properly "
129  "initialized. "
130  "Continuum id is negative but should be positive. "
131  "Continuum id is " +
132  std::to_string(tmp));
133  }
134  auto continuum_id = static_cast<uint64_t>(tmp);
135  auto search = continuum_models_.find(continuum_id);
136  if (search != continuum_models_.end()) {
137  Log::Fatal("ResourceManager::AddContinuum",
138  "You tried to add a continuum model with an already existing "
139  "substance id. Please choose a different substance id.");
140  } else {
141  continuum_models_[continuum_id] = cm;
142  }
144  }
145 
146  [[deprecated("Use RemoveContinuum() instead")]] void RemoveDiffusionGrid(
147  size_t substance_id) {
148  RemoveContinuum(substance_id);
149  }
150 
151  void RemoveContinuum(size_t continuum_id) {
152  auto search = continuum_models_.find(continuum_id);
153  if (search != continuum_models_.end()) {
154  delete search->second;
155  continuum_models_.erase(search);
156  } else {
157  Log::Error("ResourceManager::RemoveContinuum",
158  "You tried to remove a continuum model that does not exist.");
159  }
160  }
161 
165  DiffusionGrid* GetDiffusionGrid(size_t substance_id) const {
166  auto* cm = GetContinuum(substance_id);
167  auto* dgrid = dynamic_cast<DiffusionGrid*>(cm);
168  if (!dgrid) {
169  Log::Error("ResourceManager::GetDiffusionGrid",
170  "You tried to get a diffusion grid but the substance id "
171  "does not correspond to a diffusion grid.");
172  }
173  return dgrid;
174  }
175 
177  Continuum* GetContinuum(size_t continuum_id) const {
178  auto search = continuum_models_.find(continuum_id);
179  if (search != continuum_models_.end()) {
180  return search->second;
181  } else {
182  Log::Error("ResourceManager::GetContinuum",
183  "You tried to request continuum model '", continuum_id,
184  "', but it does not exist! Make sure that it's the correct id "
185  "and that the continuum model is registered.");
186  return nullptr;
187  }
188  }
189 
195  DiffusionGrid* GetDiffusionGrid(const std::string& substance_name) const {
196  auto* cm = GetContinuum(substance_name);
197  auto* dgrid = dynamic_cast<DiffusionGrid*>(cm);
198  if (!dgrid) {
199  Log::Error("ResourceManager::GetDiffusionGrid",
200  "You tried to get a diffusion grid but the substance name "
201  "does not correspond to a diffusion grid.");
202  }
203  return dgrid;
204  }
205 
209  Continuum* GetContinuum(const std::string& continuum_name) const {
210  for (auto& el : continuum_models_) {
211  auto& cm = el.second;
212  if (cm->GetContinuumName() == continuum_name) {
213  return cm;
214  }
215  }
216  Log::Error("ResourceManager::GetContinuum",
217  "You tried to request a continuum model named '", continuum_name,
218  "', but it does not exist! Make sure that it's spelled "
219  "correctly and that the continuum model is registered.");
220  return nullptr;
221  }
222 
229  template <typename TFunctor>
230  void ForEachDiffusionGrid(TFunctor&& f) const {
231  for (auto& el : continuum_models_) {
232  auto* dgrid = dynamic_cast<DiffusionGrid*>(el.second);
233  if (dgrid) {
234  f(dgrid);
235  }
236  }
237  }
238 
245  template <typename TFunctor>
246  void ForEachContinuum(TFunctor&& f) const {
247  for (auto& el : continuum_models_) {
248  f(el.second);
249  }
250  }
251 
254  size_t GetNumAgents(int numa_node = -1) const {
255  if (numa_node == -1) {
256  size_t num_agents = 0;
257  for (auto& numa_agents : agents_) {
258  num_agents += numa_agents.size();
259  }
260  return num_agents;
261  } else {
262  return agents_[numa_node].size();
263  }
264  }
265 
266  size_t GetAgentVectorCapacity(int numa_node);
267 
278  virtual void ForEachAgent(const std::function<void(Agent*)>& function,
279  Functor<bool, Agent*>* filter = nullptr) {
280  for (auto& numa_agents : agents_) {
281  for (auto* agent : numa_agents) {
282  if (!filter || (filter && (*filter)(agent))) {
283  function(agent);
284  }
285  }
286  }
287  }
288 
289  virtual void ForEachAgent(
290  const std::function<void(Agent*, AgentHandle)>& function,
291  Functor<bool, Agent*>* filter = nullptr) {
292  for (AgentHandle::NumaNode_t n = 0; n < agents_.size(); ++n) {
293  auto& numa_agents = agents_[n];
294  for (AgentHandle::ElementIdx_t i = 0; i < numa_agents.size(); ++i) {
295  auto* a = numa_agents[i];
296  if (!filter || (filter && (*filter)(a))) {
297  function(a, AgentHandle(n, i));
298  }
299  }
300  }
301  }
302 
310  virtual void ForEachAgentParallel(Functor<void, Agent*>& function,
311  Functor<bool, Agent*>* filter = nullptr);
312 
317  virtual void ForEachAgentParallel(Operation& op,
318  Functor<bool, Agent*>* filter = nullptr);
319 
320  virtual void ForEachAgentParallel(
322  Functor<bool, Agent*>* filter = nullptr);
323 
331  virtual void ForEachAgentParallel(
332  uint64_t chunk, Functor<void, Agent*, AgentHandle>& function,
333  Functor<bool, Agent*>* filter = nullptr);
334 
337  void Reserve(size_t capacity) {
338  for (auto& numa_agents : agents_) {
339  numa_agents.reserve(capacity);
340  }
341  if (type_index_) {
342  type_index_->Reserve(capacity);
343  }
344  }
345 
349  uint64_t GrowAgentContainer(size_t additional, size_t numa_node) {
350  if (additional == 0) {
351  return agents_[numa_node].size();
352  }
353  auto current = agents_[numa_node].size();
354  if (current + additional < agents_[numa_node].size()) {
355  agents_[numa_node].reserve((current + additional) * 1.5);
356  }
357  agents_[numa_node].resize(current + additional);
358  return current;
359  }
360 
363  bool ContainsAgent(const AgentUid& uid) const {
364  return uid_ah_map_.Contains(uid);
365  }
366 
371  void ClearAgents() {
372  uid_ah_map_.clear();
373  for (auto& numa_agents : agents_) {
374  for (auto* agent : numa_agents) {
375  delete agent;
376  }
377  numa_agents.clear();
378  }
379  if (type_index_) {
380  type_index_->Clear();
381  }
382  }
383 
386  virtual void LoadBalance();
387 
388  void DebugNuma() const;
389 
393  void AddAgent(Agent* agent, // NOLINT
394  typename AgentHandle::NumaNode_t numa_node = 0) {
395  auto uid = agent->GetUid();
396  if (uid.GetIndex() >= uid_ah_map_.size()) {
397  uid_ah_map_.resize(uid.GetIndex() + 1);
398  }
399  agents_[numa_node].push_back(agent);
400  uid_ah_map_.Insert(
401  uid, AgentHandle(numa_node, static_cast<AgentHandle::ElementIdx_t>(
402  agents_[numa_node].size() - 1u)));
403  if (type_index_) {
404  type_index_->Add(agent);
405  }
407  }
408 
410  auto* agent_uid_generator = Simulation::GetActive()->GetAgentUidGenerator();
411  auto highest_idx = agent_uid_generator->GetHighestIndex();
412  auto new_size = highest_idx * 1.5 + 1;
413  if (highest_idx >= uid_ah_map_.size()) {
414  uid_ah_map_.resize(new_size);
415  }
416  if (type_index_) {
417  type_index_->Reserve(new_size);
418  }
419  }
420 
421  virtual void EndOfIteration() {}
422 
427  virtual void AddAgents(typename AgentHandle::NumaNode_t numa_node,
428  uint64_t offset,
429  const std::vector<Agent*>& new_agents) {
430  uint64_t i = 0;
431  for (auto* agent : new_agents) {
432  auto uid = agent->GetUid();
433  uid_ah_map_.Insert(
434  uid, AgentHandle(numa_node,
435  static_cast<AgentHandle::ElementIdx_t>(offset + i)));
436  agents_[numa_node][offset + i] = agent;
437  i++;
438  }
439  if (type_index_) {
440 #pragma omp critical
441  for (auto* agent : new_agents) {
442  type_index_->Add(agent);
443  }
444  }
445 #pragma omp single
446  if (new_agents.size() != 0) {
448  }
449  }
450 
455  void RemoveAgent(const AgentUid& uid) {
456  // remove from map
457  if (uid_ah_map_.Contains(uid)) {
458  auto ah = uid_ah_map_[uid];
459  uid_ah_map_.Remove(uid);
460  // remove from vector
461  auto& numa_agents = agents_[ah.GetNumaNode()];
462  Agent* agent = nullptr;
463  if (ah.GetElementIdx() == numa_agents.size() - 1) {
464  agent = numa_agents.back();
465  numa_agents.pop_back();
466  } else {
467  // swap
468  agent = numa_agents[ah.GetElementIdx()];
469  auto* reordered = numa_agents.back();
470  numa_agents[ah.GetElementIdx()] = reordered;
471  numa_agents.pop_back();
472  uid_ah_map_.Insert(reordered->GetUid(), ah);
473  }
474  if (type_index_) {
475  type_index_->Remove(agent);
476  }
477  delete agent;
479  }
481  }
482 
483  // \param uids: one vector for each thread containing one vector for each numa
484  // node
485  void RemoveAgents(const std::vector<std::vector<AgentUid>*>& uids);
486 
487  const TypeIndex* GetTypeIndex() const { return type_index_; }
488 
489  protected:
494 
497  std::vector<std::vector<Agent*>> agents_;
500  std::vector<std::vector<Agent*>> agents_lb_;
501 
503 
504  TypeIndex* type_index_ = nullptr;
505 
507  std::vector<std::vector<uint64_t>> to_right;
508  std::vector<std::vector<uint64_t>> not_to_left;
509  };
510 
513 
514  friend class SimulationBackup;
515  friend std::ostream& operator<<(std::ostream& os, const ResourceManager& rm);
516 
517  private:
519  std::unordered_map<uint64_t, Continuum*> continuum_models_;
520 
522 };
523 
524 inline std::ostream& operator<<(std::ostream& os, const ResourceManager& rm) {
525  os << "\033[1mAgents per numa node\033[0m" << std::endl;
526  uint64_t cnt = 0;
527  for (auto& numa_agents : rm.agents_) {
528  os << "numa node " << cnt++ << " -> size: " << numa_agents.size()
529  << std::endl;
530  }
531  return os;
532 }
533 
534 } // namespace bdm
535 
536 #endif // CORE_RESOURCE_MANAGER_H_
bdm::ResourceManager::ContainsAgent
bool ContainsAgent(const AgentUid &uid) const
Definition: resource_manager.h:363
bdm::AgentHandle::NumaNode_t
uint16_t NumaNode_t
Definition: agent_handle.h:31
bdm::ResourceManager::EndOfIteration
virtual void EndOfIteration()
Definition: resource_manager.h:421
bdm::ResourceManager::agents_lb_
std::vector< std::vector< Agent * > > agents_lb_
Container used during load balancing.
Definition: resource_manager.h:500
agent_uid_map.h
bdm::ResourceManager::GetNumAgents
size_t GetNumAgents(int numa_node=-1) const
Definition: resource_manager.h:254
bdm::TypeIndex::Add
void Add(Agent *agent)
Definition: type_index.cc:22
agent_uid.h
bdm::ThreadInfo::GetInstance
static ThreadInfo * GetInstance()
Definition: thread_info.cc:21
bdm::ResourceManager::ResizeAgentUidMap
void ResizeAgentUidMap()
Definition: resource_manager.h:409
bdm::ResourceManager::LoadBalance
virtual void LoadBalance()
Definition: resource_manager.cc:239
agent_handle.h
bdm::ResourceManager::GetAgent
Agent * GetAgent(const AgentUid &uid)
Definition: resource_manager.h:103
bdm::ResourceManager::type_index_
TypeIndex * type_index_
Definition: resource_manager.h:504
bdm
Definition: agent.cc:39
bdm::ResourceManager::GetTypeIndex
const TypeIndex * GetTypeIndex() const
Definition: resource_manager.h:487
operation.h
bdm::ResourceManager::RemoveAgents
void RemoveAgents(const std::vector< std::vector< AgentUid > * > &uids)
Definition: resource_manager.cc:339
thread_info.h
bdm::ResourceManager::GetDiffusionGrid
DiffusionGrid * GetDiffusionGrid(size_t substance_id) const
Definition: resource_manager.h:165
bdm::ResourceManager::Reserve
void Reserve(size_t capacity)
Definition: resource_manager.h:337
bdm::ResourceManager::ResourceManager
ResourceManager(TRootIOCtor *r)
Definition: resource_manager.h:55
bdm::ResourceManager::ParallelRemovalAuxData::to_right
std::vector< std::vector< uint64_t > > to_right
Definition: resource_manager.h:507
bdm::ResourceManager::SwapAgents
void SwapAgents(std::vector< std::vector< Agent * >> *agents)
Definition: resource_manager.cc:584
bdm::Agent::GetUid
const AgentUid & GetUid() const
Definition: agent.cc:123
bdm::ResourceManager::AddDiffusionGrid
void AddDiffusionGrid(DiffusionGrid *dgrid)
Definition: resource_manager.h:119
bdm::ResourceManager::operator=
ResourceManager & operator=(ResourceManager &&other) noexcept
Definition: resource_manager.h:61
type.h
bdm::DiffusionGrid
Definition: diffusion_grid.h:33
bdm::AgentUidGenerator::ReuseAgentUid
void ReuseAgentUid(const AgentUid &uid)
Definition: agent_uid_generator.h:60
bdm::TypeIndex
Definition: type_index.h:27
bdm::AgentHandle::ElementIdx_t
uint32_t ElementIdx_t
Definition: agent_handle.h:32
bdm::Continuum
Continuum class to interface with BioDynaMo for hybrid simulations.
Definition: continuum_interface.h:52
bdm::ResourceManager::GetDiffusionGrid
DiffusionGrid * GetDiffusionGrid(const std::string &substance_name) const
Definition: resource_manager.h:195
bdm::ResourceManager::parallel_remove_
ParallelRemovalAuxData parallel_remove_
auxiliary data required for parallel agent removal
Definition: resource_manager.h:512
bdm::ResourceManager::ParallelRemovalAuxData
Definition: resource_manager.h:506
bdm::ResourceManager::ForEachAgent
virtual void ForEachAgent(const std::function< void(Agent *)> &function, Functor< bool, Agent * > *filter=nullptr)
Definition: resource_manager.h:278
bdm::Agent
Contains code required by all agents.
Definition: agent.h:79
bdm::ResourceManager::RebuildAgentUidMap
void RebuildAgentUidMap()
Definition: resource_manager.h:90
bdm::AgentUidGenerator::GetHighestIndex
AgentUid::Index_t GetHighestIndex() const
Thread-safe.
Definition: agent_uid_generator.h:56
bdm::ResourceManager::RemoveContinuum
void RemoveContinuum(size_t continuum_id)
Definition: resource_manager.h:151
bdm::Functor
Definition: functor.h:24
bdm::ResourceManager::AddAgents
virtual void AddAgents(typename AgentHandle::NumaNode_t numa_node, uint64_t offset, const std::vector< Agent * > &new_agents)
Definition: resource_manager.h:427
bdm::ResourceManager::uid_ah_map_
AgentUidMap< AgentHandle > uid_ah_map_
Maps an AgentUid to its storage location in agents_ .
Definition: resource_manager.h:496
bdm::ResourceManager::RemoveAgent
void RemoveAgent(const AgentUid &uid)
Definition: resource_manager.h:455
bdm::ResourceManager::AddAgent
void AddAgent(Agent *agent, typename AgentHandle::NumaNode_t numa_node=0)
Definition: resource_manager.h:393
bdm::ResourceManager::GetContinuum
Continuum * GetContinuum(size_t continuum_id) const
Return the continuum model which holds the substance of specified id.
Definition: resource_manager.h:177
continuum_interface.h
diffusion_grid.h
bdm::ResourceManager::ParallelRemovalAuxData::not_to_left
std::vector< std::vector< uint64_t > > not_to_left
Definition: resource_manager.h:508
bdm::ResourceManager::BDM_CLASS_DEF_NV
BDM_CLASS_DEF_NV(ResourceManager, 2)
bdm::ResourceManager::GetAgent
Agent * GetAgent(AgentHandle ah)
Definition: resource_manager.h:111
bdm::ResourceManager::GetAgentHandle
AgentHandle GetAgentHandle(const AgentUid &uid)
Definition: resource_manager.h:115
bdm::ResourceManager
Definition: resource_manager.h:53
bdm::Continuum::GetContinuumId
int GetContinuumId() const
Returns the ID of the continuum.
Definition: continuum_interface.h:87
numa.h
bdm::ResourceManager::~ResourceManager
virtual ~ResourceManager()
Definition: resource_manager.cc:45
root.h
bdm::ResourceManager::ClearAgents
void ClearAgents()
Definition: resource_manager.h:371
bdm::ResourceManager::agents_
std::vector< std::vector< Agent * > > agents_
Pointer container for all agents.
Definition: resource_manager.h:498
bdm::ResourceManager::GetContinuum
Continuum * GetContinuum(const std::string &continuum_name) const
Definition: resource_manager.h:209
agent_uid_generator.h
bdm::TypeIndex::Remove
void Remove(Agent *agent)
Definition: type_index.cc:40
bdm::TypeIndex::Clear
void Clear()
Definition: type_index.cc:55
agent.h
bdm::AgentUidMap
Definition: agent_uid_map.h:31
bdm::ResourceManager::RemoveDiffusionGrid
void RemoveDiffusionGrid(size_t substance_id)
Definition: resource_manager.h:146
bdm::Log::Fatal
static void Fatal(const std::string &location, const Args &... parts)
Prints fatal error message.
Definition: log.h:115
bdm::Log::Error
static void Error(const std::string &location, const Args &... parts)
Prints error message.
Definition: log.h:79
bdm::Simulation::GetAgentUidGenerator
AgentUidGenerator * GetAgentUidGenerator()
Definition: simulation.cc:273
bdm::ResourceManager::GrowAgentContainer
uint64_t GrowAgentContainer(size_t additional, size_t numa_node)
Definition: resource_manager.h:349
bdm::ResourceManager::continuum_models_
std::unordered_map< uint64_t, Continuum * > continuum_models_
Maps a continuum ID to the pointer to the continuum models.
Definition: resource_manager.h:519
bdm::ResourceManager::ForEachAgent
virtual void ForEachAgent(const std::function< void(Agent *, AgentHandle)> &function, Functor< bool, Agent * > *filter=nullptr)
Definition: resource_manager.h:289
type_index.h
bdm::ResourceManager::ForEachDiffusionGrid
void ForEachDiffusionGrid(TFunctor &&f) const
Definition: resource_manager.h:230
bdm::AgentUid
Definition: agent_uid.h:25
bdm::ResourceManager::ResourceManager
ResourceManager()
Definition: resource_manager.cc:30
bdm::operator<<
std::ostream & operator<<(std::ostream &o, const MathArray< T, N > &arr)
Definition: math_array.h:412
bdm::SimulationBackup
Definition: simulation_backup.h:33
bdm::ResourceManager::ForEachContinuum
void ForEachContinuum(TFunctor &&f) const
Definition: resource_manager.h:246
bdm::ResourceManager::ForEachAgentParallel
virtual void ForEachAgentParallel(Functor< void, Agent * > &function, Functor< bool, Agent * > *filter=nullptr)
Definition: resource_manager.cc:92
bdm::ResourceManager::thread_info_
ThreadInfo * thread_info_
Definition: resource_manager.h:502
simulation.h
bdm::ResourceManager::DebugNuma
void DebugNuma() const
bdm::AgentHandle::GetNumaNode
NumaNode_t GetNumaNode() const
Definition: agent_handle.h:44
bdm::Simulation::GetActive
static Simulation * GetActive()
This function returns the currently active Simulation simulation.
Definition: simulation.cc:67
bdm::Operation
Definition: operation.h:98
bdm::ResourceManager::AddContinuum
void AddContinuum(Continuum *cm)
Definition: resource_manager.h:124
bdm::AgentHandle::GetElementIdx
ElementIdx_t GetElementIdx() const
Definition: agent_handle.h:45
functor.h
bdm::ResourceManager::MarkEnvironmentOutOfSync
void MarkEnvironmentOutOfSync()
Definition: resource_manager.cc:588
bdm::ResourceManager::operator<<
friend std::ostream & operator<<(std::ostream &os, const ResourceManager &rm)
Definition: resource_manager.h:524
bdm::ThreadInfo
This class stores information about each thread. (e.g. to which NUMA node it belongs to....
Definition: thread_info.h:31
bdm::TypeIndex::Reserve
void Reserve(uint64_t capacity)
Definition: type_index.cc:63
bdm::ResourceManager::GetAgentVectorCapacity
size_t GetAgentVectorCapacity(int numa_node)
Definition: resource_manager.cc:579
bdm::AgentHandle
Definition: agent_handle.h:29