36 auto* non_atomic_batches = batches_.load();
37 if (non_atomic_batches !=
nullptr) {
38 for (uint64_t i = 0; i < num_batches_; ++i) {
39 delete non_atomic_batches[i];
41 delete[] non_atomic_batches;
50 auto bidx = index / kBatchSize;
51 if (bidx >= num_batches_) {
53 std::max(index,
static_cast<uint32_t
>(num_batches_ * kBatchSize * 1.1));
57 auto el_idx = index % kBatchSize;
58 (*batches_.load()[bidx])[el_idx] = value;
66 auto bidx = index / kBatchSize;
67 if (bidx >= num_batches_) {
68 Log::Fatal(
"ThreadSafeAgentUidMap::operator[]",
69 Concat(
"AgentUid out of range access: AgentUid: ", uid,
70 ", ThreadSafeAgentUidMap max index ",
71 num_batches_ * kBatchSize));
75 auto el_idx = index % kBatchSize;
76 return (*batches_.load()[bidx])[el_idx];
80 return num_batches_ * kBatchSize;
85 auto new_num_batches = new_size / kBatchSize + 1;
86 std::lock_guard<Spinlock> guard(lock_);
87 if (new_num_batches >= num_batches_) {
88 auto bcopy =
new Batch*[new_num_batches];
89 auto** non_atomic_batches = batches_.load();
90 for (uint64_t i = 0; i < new_num_batches; ++i) {
91 if (i < num_batches_) {
92 bcopy[i] = non_atomic_batches[i];
94 bcopy[i] =
new Batch();
95 bcopy[i]->reserve(kBatchSize);
98 batches_.exchange(bcopy);
99 old_copies_.push_back(non_atomic_batches);
100 num_batches_ = new_num_batches;
105 for (
auto& entry : old_copies_) {
106 if (entry !=
nullptr) {
114 const std::shared_ptr<ThreadSafeAgentUidMap>& map)
127 const std::vector<ExecutionContext*>& all_exec_ctxts) {
134 const std::vector<ExecutionContext*>& all_exec_ctxts) {
143 const std::vector<ExecutionContext*>& all_exec_ctxts) {}
146 const std::vector<ExecutionContext*>& all_exec_ctxts) {}
153 if (param->thread_safety_mechanism ==
154 Param::ThreadSafetyMechanism::kUserSpecified) {
172 locks_.push_back(aptr->GetLock());
174 for (uint64_t i = 0; i <
locks_.size(); ++i) {
196 for (
int i =
locks_.size() - 1; i >= 0; --i) {
202 for (
auto& op : operations) {
205 for (
int i =
locks_.size() - 1; i >= 0; --i) {
208 }
else if (param->thread_safety_mechanism ==
209 Param::ThreadSafetyMechanism::kAutomatic) {
210 auto* nb_mutex_builder = env->GetNeighborMutexBuilder();
211 auto* mutex = nb_mutex_builder->GetMutex(agent->
GetBoxIdx());
212 std::lock_guard<decltype(*mutex)> guard(*mutex);
215 for (
auto* op : operations) {
218 }
else if (param->thread_safety_mechanism ==
219 Param::ThreadSafetyMechanism::kNone) {
222 for (
auto* op : operations) {
226 Log::Fatal(
"InPlaceExecutionContext::Execute",
227 "Invalid value for parameter thread_safety_mechanism: ",
228 param->thread_safety_mechanism);
238 real_t query_squared_radius)
const {
256 auto for_each =
L2F([&](
Agent* agent) { lambda(agent); });
257 env->ForEachNeighbor(for_each, query, criteria);
266 if (pair.second < squared_radius) {
267 lambda(pair.first, pair.second);
282 if (param->cache_neighbors) {
283 neighbor_cache_.push_back(std::make_pair(agent, squared_distance));
285 lambda(agent, squared_distance);
287 env->ForEachNeighbor(for_each, query, squared_radius);
294 lambda(agent, squared_distance);
302 auto* rm = sim->GetResourceManager();
303 auto* agent = rm->GetAgent(uid);
304 if (agent !=
nullptr) {
320 const std::vector<ExecutionContext*>& all_exec_ctxts) {
326 auto* ctxt = bdm_static_cast<InPlaceExecutionContext*>(all_exec_ctxts[tid]);
328 thread_offsets[tid] = new_agent_per_numa[nid];
329 new_agent_per_numa[nid] += ctxt->new_agents_.size();
336 for (
unsigned n = 0; n < new_agent_per_numa.size(); n++) {
337 numa_offsets[n] = rm->GrowAgentContainer(new_agent_per_numa[n], n);
341 #pragma omp parallel for schedule(static, 1)
343 auto* ctxt = bdm_static_cast<InPlaceExecutionContext*>(all_exec_ctxts[i]);
345 uint64_t offset = thread_offsets[i] + numa_offsets[nid];
346 rm->AddAgents(nid, offset, ctxt->new_agents_);
347 ctxt->new_agents_.clear();
357 const std::vector<ExecutionContext*>& all_exec_ctxts) {
360 auto num_removals = 0;
362 auto* ctxt = bdm_static_cast<InPlaceExecutionContext*>(all_exec_ctxts[i]);
363 all_remove[i] = &ctxt->remove_;
364 num_removals += ctxt->remove_.size();
367 if (num_removals != 0) {
372 auto* ctxt = bdm_static_cast<InPlaceExecutionContext*>(all_exec_ctxts[i]);
373 ctxt->remove_.clear();
Contains code required by all agents.
virtual void CriticalRegion(std::vector< AgentPointer<>> *aptrs)
const AgentUid & GetUid() const
uint32_t GetBoxIdx() const
virtual void ForEachNeighbor(Functor< void, Agent *, real_t > &lambda, const Agent &query, real_t squared_radius)=0
void SetupAgentOpsAll(const std::vector< ExecutionContext * > &all_exec_ctxts) override
std::vector< Agent * > new_agents_
Pointer to new agents.
void TearDownIterationAll(const std::vector< ExecutionContext * > &all_exec_ctxts) override
virtual void RemoveAgentsFromRm(const std::vector< ExecutionContext * > &all_exec_ctxts)
const Agent * GetConstAgent(const AgentUid &uid) override
bool IsNeighborCacheValid(real_t query_squared_radius) const
void AddAgent(Agent *new_agent) override
Adds the agent to the simulation (threadsafe, takes ownership). Note that we avoid the use of smart p...
std::vector< Spinlock * > locks_
Agent * GetAgent(const AgentUid &uid) override
std::vector< std::pair< Agent *, real_t > > neighbor_cache_
std::shared_ptr< ThreadSafeAgentUidMap > new_agent_map_
Lookup table AgentUid -> AgentPointer for new created agents.
virtual void AddAgentsToRm(const std::vector< ExecutionContext * > &all_exec_ctxts)
void RemoveAgent(const AgentUid &uid) override
bool cache_neighbors_
Cache the value of Param::cache_neighbors.
void ForEachNeighbor(Functor< void, Agent * > &lambda, const Agent &query, void *criteria) override
void TearDownAgentOpsAll(const std::vector< ExecutionContext * > &all_exec_ctxts) override
real_t cached_squared_search_radius_
The radius that was used to cache neighbors in neighbor_cache_
std::vector< AgentUid > remove_
~InPlaceExecutionContext() override
void Execute(Agent *agent, AgentHandle ah, const std::vector< Operation * > &operations) override
void SetupIterationAll(const std::vector< ExecutionContext * > &all_exec_ctxts) override
InPlaceExecutionContext(const std::shared_ptr< ThreadSafeAgentUidMap > &map)
std::vector< AgentPointer<> > critical_region_
Used to determine which agents must not be updated from different threads.
std::vector< AgentPointer<> > critical_region_2_
Used to determine which agents must not be updated from different threads.
static void Fatal(const std::string &location, const Args &... parts)
Prints fatal error message.
virtual void EndOfIteration()
void RemoveAgents(const std::vector< std::vector< AgentUid > * > &uids)
ResourceManager * GetResourceManager()
Returns the ResourceManager instance.
static Simulation * GetActive()
This function returns the currently active Simulation simulation.
Environment * GetEnvironment()
const Param * GetParam() const
Returns the simulation parameters.
This class stores information about each thread. (e.g. to which NUMA node it belongs to....
int GetNumaNode(int omp_thread_id) const
Returns the numa node the given openmp thread is bound to.
int GetNumaNodes() const
Returns the number of NUMA nodes on this machine.
int GetMaxThreads() const
Return the maximum number of threads.
LambdaFunctor< decltype(&TLambda::operator())> L2F(const TLambda &l)
std::string Concat(const Args &... parts)
Concatenates all arguments into a string. Equivalent to streaming all arguments into a stringstream a...
std::vector< value_type > Batch
constexpr static uint64_t kBatchSize
void Insert(const AgentUid &uid, const value_type &value)
const value_type & operator[](const AgentUid &key) const
void Resize(uint64_t new_size)