]> git.seodisparate.com - EntityComponentMetaSystem/commitdiff
Improve efficiency of stored function calling
authorStephen Seo <seo.disparate@gmail.com>
Tue, 14 Nov 2017 04:51:24 +0000 (13:51 +0900)
committerStephen Seo <seo.disparate@gmail.com>
Tue, 14 Nov 2017 04:51:24 +0000 (13:51 +0900)
Previously, every called function iterated through all entities for
calling the function on matching entities.

Now, callForMatchingFunctions iterates through all entities once,
stores matching entities for each function, then calls the functions on
the matching entities.

src/EC/Manager.hpp

index 5557c9734392bc2f688c18fac354b462d16cd5f3..51a981fa49fc8280713f119b719fe4de72369026 100644 (file)
@@ -763,7 +763,11 @@ namespace EC
 
 
     private:
-        std::unordered_map<std::size_t, std::function<void(std::size_t)> >
+        std::unordered_map<std::size_t, std::tuple<
+            BitsetType,
+            std::function<void(
+                std::size_t,
+                std::vector<std::size_t>)> > >
             forMatchingFunctions;
         std::size_t functionIndex = 0;
 
@@ -827,71 +831,131 @@ namespace EC
 
             forMatchingFunctions.emplace(std::make_pair(
                 functionIndex,
-                [function, signatureBitset, helper, this] 
-                    (std::size_t threadCount)
-            {
-                if(threadCount <= 1)
+                std::make_tuple(
+                    signatureBitset,
+                    [function, helper, this] 
+                    (std::size_t threadCount,
+                        std::vector<std::size_t> matching)
                 {
-                    for(std::size_t i = 0; i < this->currentSize; ++i)
+                    if(threadCount <= 1)
                     {
-                        if(!std::get<bool>(this->entities[i]))
+                        for(auto eid : matching)
                         {
-                            continue;
+                            helper.callInstancePtr(eid, *this, &function);
                         }
-                        if((signatureBitset
-                            & std::get<BitsetType>(this->entities[i]))
-                                == signatureBitset)
+                    }
+                    else
+                    {
+                        std::vector<std::thread> threads(threadCount);
+                        std::size_t s = matching.size() / threadCount;
+                        for(std::size_t i = 0; i < threadCount; ++ i)
+                        {
+                            std::size_t begin = s * i;
+                            std::size_t end;
+                            if(i == threadCount - 1)
+                            {
+                                end = matching.size();
+                            }
+                            else
+                            {
+                                end = s * (i + 1);
+                            }
+                            threads[i] = std::thread(
+                                [this, &function, &helper]
+                                    (std::size_t begin,
+                                    std::size_t end) {
+                                for(std::size_t i = begin; i < end; ++i)
+                                {
+                                    helper.callInstancePtr(i, *this, &function);
+                                }
+                            },
+                            begin, end);
+                        }
+                        for(std::size_t i = 0; i < threadCount; ++i)
                         {
-                            helper.callInstancePtr(i, *this, &function);
+                            threads[i].join();
                         }
                     }
-                }
-                else
+                })));
+
+            return functionIndex++;
+        }
+
+    private:
+        std::vector<std::vector<std::size_t> > getMatchingEntities(
+            std::vector<BitsetType*> bitsets, std::size_t threadCount = 1)
+        {
+            std::vector<std::vector<std::size_t> > matchingV(bitsets.size());
+
+            if(threadCount <= 1)
+            {
+                for(std::size_t i = 0; i < currentSize; ++i)
                 {
-                    std::vector<std::thread> threads(threadCount);
-                    std::size_t s = this->currentSize / threadCount;
-                    for(std::size_t i = 0; i < threadCount; ++ i)
+                    if(!isAlive(i))
                     {
-                        std::size_t begin = s * i;
-                        std::size_t end;
-                        if(i == threadCount - 1)
+                        continue;
+                    }
+                    for(std::size_t j = 0; j < bitsets.size(); ++j)
+                    {
+                        if(((*bitsets[j]) & std::get<BitsetType>(entities[i]))
+                            == (*bitsets[j]))
                         {
-                            end = this->currentSize;
+                            matchingV[j].push_back(i);
                         }
-                        else
+                    }
+                }
+            }
+            else
+            {
+                std::vector<std::thread> threads(threadCount);
+                std::size_t s = currentSize / threadCount;
+                std::mutex mutex;
+                for(std::size_t i = 0; i < threadCount; ++i)
+                {
+                    std::size_t begin = s * i;
+                    std::size_t end;
+                    if(i == threadCount - 1)
+                    {
+                        end = currentSize;
+                    }
+                    else
+                    {
+                        end = s * (i + 1);
+                    }
+                    threads[i] = std::thread(
+                    [this, &matchingV, &bitsets, &mutex]
+                    (std::size_t begin, std::size_t end)
+                    {
+                        for(std::size_t j = begin; j < end; ++j)
                         {
-                            end = s * (i + 1);
-                        }
-                        threads[i] = std::thread(
-                            [this, &function, &signatureBitset, &helper]
-                                (std::size_t begin,
-                                std::size_t end) {
-                            for(std::size_t i = begin; i < end; ++i)
+                            if(!isAlive(j))
                             {
-                                if(!std::get<bool>(this->entities[i]))
-                                {
-                                    continue;
-                                }
-                                if((signatureBitset
-                                    & std::get<BitsetType>(this->entities[i]))
-                                        == signatureBitset)
+                                continue;
+                            }
+                            for(std::size_t k = 0; k < bitsets.size(); ++k)
+                            {
+                                if(((*bitsets[k]) &
+                                    std::get<BitsetType>(entities[j]))
+                                    == (*bitsets[k]))
                                 {
-                                    helper.callInstancePtr(i, *this, &function);
+                                    std::lock_guard<std::mutex> guard(mutex);
+                                    matchingV[k].push_back(j);
                                 }
                             }
-                        },
-                        begin, end);
-                    }
-                    for(std::size_t i = 0; i < threadCount; ++i)
-                    {
-                        threads[i].join();
-                    }
+                        }
+                    }, begin, end);
+                }
+                for(std::size_t i = 0; i < threadCount; ++i)
+                {
+                    threads[i].join();
                 }
-            }));
+            }
 
-            return functionIndex++;
+            return matchingV;
         }
 
+    public:
+
         /*!
             \brief Call all stored functions.
 
@@ -922,11 +986,23 @@ namespace EC
         */
         void callForMatchingFunctions(std::size_t threadCount = 1)
         {
-            for(auto functionIter = forMatchingFunctions.begin();
-                functionIter != forMatchingFunctions.end();
-                ++functionIter)
+            std::vector<BitsetType*> bitsets;
+            for(auto iter = forMatchingFunctions.begin();
+                iter != forMatchingFunctions.end();
+                ++iter)
+            {
+                bitsets.push_back(&std::get<BitsetType>(iter->second));
+            }
+
+            std::vector<std::vector<std::size_t> > matching =
+                getMatchingEntities(bitsets, threadCount);
+
+            std::size_t i = 0;
+            for(auto iter = forMatchingFunctions.begin();
+                iter != forMatchingFunctions.end();
+                ++iter)
             {
-                functionIter->second(threadCount);
+                std::get<1>(iter->second)(threadCount, matching[i++]);
             }
         }
 
@@ -966,7 +1042,10 @@ namespace EC
             {
                 return false;
             }
-            iter->second(threadCount);
+            std::vector<std::vector<std::size_t> > matching =
+                getMatchingEntities(std::vector<BitsetType*>{
+                    &std::get<BitsetType>(iter->second)}, threadCount);
+            std::get<1>(iter->second)(threadCount, matching[0]);
             return true;
         }