Ticket #1707: rangemanager_vectorization_binsearch.patch

File rangemanager_vectorization_binsearch.patch, 16.1 KB (added by mrf, 10 years ago)
  • source/simulation2/components/CCmpRangeManager.cpp

     
    9292 */
    9393struct EntityData
    9494{
    95     EntityData() : retainInFog(0), owner(-1), inWorld(0), flags(1) { }
     95    EntityData(entity_id_t entity = INVALID_ENTITY) :
     96        id(entity), retainInFog(0), owner(-1), inWorld(0), flags(1)
     97    {
     98    }
     99
     100    entity_id_t id;
    96101    entity_pos_t x, z;
    97102    entity_pos_t visionRange;
    98103    u8 retainInFog; // boolean
     
    101106    u8 flags; // See GetEntityFlagMask
    102107};
    103108
    104 cassert(sizeof(EntityData) == 16);
     109cassert(sizeof(EntityData) == 20);
    105110
    106111
    107112/**
     
    131136    template<typename S>
    132137    void operator()(S& serialize, const char* UNUSED(name), EntityData& value)
    133138    {
     139        serialize.NumberU32_Unbounded("id", value.id);
    134140        serialize.NumberFixed_Unbounded("x", value.x);
    135141        serialize.NumberFixed_Unbounded("z", value.z);
    136142        serialize.NumberFixed_Unbounded("vision", value.visionRange);
     
    143149
    144150
    145151/**
     152 * Search entity by id in a vector of EntityData.
     153 * Adapted binary search, for sorted set of (non-negative) integers. The min and max entity id's are used to speed up the search.
     154 */
     155cassert(sizeof(entity_id_t) <= sizeof(size_t));
     156
     157template<class EntityDataRandomAccessIterator>
     158static inline EntityDataRandomAccessIterator find_entity(EntityDataRandomAccessIterator first, EntityDataRandomAccessIterator last, entity_id_t entity, entity_id_t minentity, entity_id_t maxentity)
     159{
     160    if (first == last)
     161    {
     162        return last;
     163    }
     164   
     165    size_t imin, imax, minoffset, maxoffset;
     166    imin = 0;
     167    imax = (last-first)-1;
     168    minoffset = (size_t)minentity-imin;
     169    maxoffset = (size_t)maxentity-imax;
     170    imin = std::max<size_t>(imin, (entity>maxoffset)?entity-maxoffset:0);
     171    imax = std::min<size_t>(imax, (entity>minoffset)?entity-minoffset:0);
     172    while(imax >= imin)
     173    {
     174        size_t imid = imin + ((imax - imin) / 2);
     175        entity_id_t entitymid = first[imid].id;
     176        if (entity < entitymid)
     177        {
     178            maxoffset = entitymid - imid;
     179            imin = std::max<size_t>(imin, (entity>maxoffset)?entity-maxoffset:0);
     180            imax = imid - 1;
     181        }
     182        else if (entity > entitymid)
     183        {
     184            minoffset = entitymid - imid;
     185            imin = imid + 1;
     186            imax = std::min<size_t>(imax, (entity>minoffset)?entity-minoffset:0);
     187        }
     188        else
     189        {
     190            return first + imid;
     191        }
     192    }
     193    return last;
     194}
     195
     196template<class EntityDataRandomAccessIterator>
     197static inline EntityDataRandomAccessIterator find_entity(EntityDataRandomAccessIterator first, EntityDataRandomAccessIterator last, entity_id_t entity)
     198{
     199    if (first == last)
     200    {
     201        return last;
     202    }
     203   
     204    entity_id_t minentity = first->id;
     205    entity_id_t maxentity = (last-1)->id;
     206    return find_entity(first, last, entity, minentity, maxentity);
     207}
     208
     209/**
     210 * Standard binary search
     211 */
     212struct EntityIdComp
     213{
     214    inline bool operator()(const EntityData &data, const entity_id_t id)
     215    {
     216        return data.id < id;
     217    }
     218};
     219template<class EntityDataRandomAccessIterator>
     220static inline EntityDataRandomAccessIterator find_entity_std(EntityDataRandomAccessIterator first, EntityDataRandomAccessIterator last, entity_id_t entity)
     221{
     222    EntityIdComp comp;
     223    EntityDataRandomAccessIterator it = std::lower_bound(first, last, entity, comp);
     224
     225    if (it != last && it->id == entity)
     226    {
     227        return it;
     228    }
     229    else
     230    {
     231        return last;
     232    }
     233}
     234
     235/**
    146236 * Functor for sorting entities by distance from a source point.
    147237 * It must only be passed entities that are in 'entities'
    148238 * and are currently in the world.
    149239 */
    150240struct EntityDistanceOrdering
    151241{
    152     EntityDistanceOrdering(const std::map<entity_id_t, EntityData>& entities, const CFixedVector2D& source) :
     242    EntityDistanceOrdering(const std::vector<EntityData> &entities, const CFixedVector2D& source) :
    153243        m_EntityData(entities), m_Source(source)
    154244    {
     245        m_MinEntityId = m_EntityData.front().id;
     246        m_MaxEntityId = m_EntityData.back().id;
    155247    }
    156248
    157249    bool operator()(entity_id_t a, entity_id_t b)
    158250    {
    159         const EntityData& da = m_EntityData.find(a)->second;
    160         const EntityData& db = m_EntityData.find(b)->second;
     251        const EntityData& da = *find_entity(m_EntityData.begin(), m_EntityData.end(), a, m_MinEntityId, m_MaxEntityId);
     252        const EntityData& db = *find_entity(m_EntityData.begin(), m_EntityData.end(), b, m_MinEntityId, m_MaxEntityId);
    161253        CFixedVector2D vecA = CFixedVector2D(da.x, da.z) - m_Source;
    162254        CFixedVector2D vecB = CFixedVector2D(db.x, db.z) - m_Source;
    163255        return (vecA.CompareLength(vecB) < 0);
    164256    }
    165257
    166     const std::map<entity_id_t, EntityData>& m_EntityData;
     258    const std::vector<EntityData> m_EntityData;
     259    entity_id_t m_MinEntityId, m_MaxEntityId;
    167260    CFixedVector2D m_Source;
    168261
    169262private:
     
    210303    // Range query state:
    211304    tag_t m_QueryNext; // next allocated id
    212305    std::map<tag_t, Query> m_Queries;
    213     std::map<entity_id_t, EntityData> m_EntityData;
     306    std::vector<EntityData> m_EntityData;
    214307    SpatialSubdivision<entity_id_t> m_Subdivision; // spatial index of m_EntityData
    215308
    216309    // LOS state:
     
    284377
    285378        serialize.NumberU32_Unbounded("query next", m_QueryNext);
    286379        SerializeMap<SerializeU32_Unbounded, SerializeQuery>()(serialize, "queries", m_Queries);
    287         SerializeMap<SerializeU32_Unbounded, SerializeEntityData>()(serialize, "entity data", m_EntityData);
     380        SerializeVector<SerializeEntityData>()(serialize, "entity data", m_EntityData);
    288381
    289382        SerializeMap<SerializeI32_Unbounded, SerializeBool>()(serialize, "los reveal all", m_LosRevealAll);
    290383        serialize.Bool("los circular", m_LosCircular);
     
    335428            // The newly-created entity will have owner -1 and position out-of-world
    336429            // (any initialisation of those values will happen later), so we can just
    337430            // use the default-constructed EntityData here
    338             EntityData entdata;
     431            EntityData entdata(ent);
    339432
    340433            // Store the LOS data, if any
    341434            CmpPtr<ICmpVision> cmpVision(GetSimContext(), ent);
     
    345438                entdata.retainInFog = (cmpVision->GetRetainInFog() ? 1 : 0);
    346439            }
    347440
     441            // The entity id's are expected to be increasing
     442            ENSURE(m_EntityData.empty() || ent > m_EntityData.back().id);
     443           
    348444            // Remember this entity
    349             m_EntityData.insert(std::make_pair(ent, entdata));
     445            m_EntityData.push_back(entdata);
    350446
    351447            break;
    352448        }
     
    355451            const CMessagePositionChanged& msgData = static_cast<const CMessagePositionChanged&> (msg);
    356452            entity_id_t ent = msgData.entity;
    357453
    358             std::map<entity_id_t, EntityData>::iterator it = m_EntityData.find(ent);
     454            std::vector<EntityData>::iterator it = FindEntityData(ent);
    359455
    360456            // Ignore if we're not already tracking this entity
    361457            if (it == m_EntityData.end())
     
    363459
    364460            if (msgData.inWorld)
    365461            {
    366                 if (it->second.inWorld)
     462                if (it->inWorld)
    367463                {
    368                     CFixedVector2D from(it->second.x, it->second.z);
     464                    CFixedVector2D from(it->x, it->z);
    369465                    CFixedVector2D to(msgData.x, msgData.z);
    370466                    m_Subdivision.Move(ent, from, to);
    371                     LosMove(it->second.owner, it->second.visionRange, from, to);
     467                    LosMove(it->owner, it->visionRange, from, to);
    372468                }
    373469                else
    374470                {
    375471                    CFixedVector2D to(msgData.x, msgData.z);
    376472                    m_Subdivision.Add(ent, to);
    377                     LosAdd(it->second.owner, it->second.visionRange, to);
     473                    LosAdd(it->owner, it->visionRange, to);
    378474                }
    379475
    380                 it->second.inWorld = 1;
    381                 it->second.x = msgData.x;
    382                 it->second.z = msgData.z;
     476                it->inWorld = 1;
     477                it->x = msgData.x;
     478                it->z = msgData.z;
    383479            }
    384480            else
    385481            {
    386                 if (it->second.inWorld)
     482                if (it->inWorld)
    387483                {
    388                     CFixedVector2D from(it->second.x, it->second.z);
     484                    CFixedVector2D from(it->x, it->z);
    389485                    m_Subdivision.Remove(ent, from);
    390                     LosRemove(it->second.owner, it->second.visionRange, from);
     486                    LosRemove(it->owner, it->visionRange, from);
    391487                }
    392488
    393                 it->second.inWorld = 0;
    394                 it->second.x = entity_pos_t::Zero();
    395                 it->second.z = entity_pos_t::Zero();
     489                it->inWorld = 0;
     490                it->x = entity_pos_t::Zero();
     491                it->z = entity_pos_t::Zero();
    396492            }
    397493
    398494            break;
     
    402498            const CMessageOwnershipChanged& msgData = static_cast<const CMessageOwnershipChanged&> (msg);
    403499            entity_id_t ent = msgData.entity;
    404500
    405             std::map<entity_id_t, EntityData>::iterator it = m_EntityData.find(ent);
     501            std::vector<EntityData>::iterator it = FindEntityData(ent);
    406502
    407503            // Ignore if we're not already tracking this entity
    408504            if (it == m_EntityData.end())
    409505                break;
    410506
    411             if (it->second.inWorld)
     507            if (it->inWorld)
    412508            {
    413                 CFixedVector2D pos(it->second.x, it->second.z);
    414                 LosRemove(it->second.owner, it->second.visionRange, pos);
    415                 LosAdd(msgData.to, it->second.visionRange, pos);
     509                CFixedVector2D pos(it->x, it->z);
     510                LosRemove(it->owner, it->visionRange, pos);
     511                LosAdd(msgData.to, it->visionRange, pos);
    416512            }
    417513
    418514            ENSURE(-128 <= msgData.to && msgData.to <= 127);
    419             it->second.owner = (i8)msgData.to;
     515            it->owner = (i8)msgData.to;
    420516
    421517            break;
    422518        }
     
    425521            const CMessageDestroy& msgData = static_cast<const CMessageDestroy&> (msg);
    426522            entity_id_t ent = msgData.entity;
    427523
    428             std::map<entity_id_t, EntityData>::iterator it = m_EntityData.find(ent);
     524            std::vector<EntityData>::iterator it = FindEntityData(ent);
    429525
    430526            // Ignore if we're not already tracking this entity
    431527            if (it == m_EntityData.end())
    432528                break;
    433529
    434             if (it->second.inWorld)
    435                 m_Subdivision.Remove(ent, CFixedVector2D(it->second.x, it->second.z));
     530            if (it->inWorld)
     531                m_Subdivision.Remove(ent, CFixedVector2D(it->x, it->z));
    436532
    437533            // This will be called after Ownership's OnDestroy, so ownership will be set
    438534            // to -1 already and we don't have to do a LosRemove here
    439             ENSURE(it->second.owner == -1);
     535            ENSURE(it->owner == -1);
    440536
     537            // TODO: be smarter and just mark the data as deleted and then do a bulk-remove once performing queries.
    441538            m_EntityData.erase(it);
    442539
    443540            break;
     
    447544            const CMessageVisionRangeChanged& msgData = static_cast<const CMessageVisionRangeChanged&> (msg);
    448545            entity_id_t ent = msgData.entity;
    449546
    450             std::map<entity_id_t, EntityData>::iterator it = m_EntityData.find(ent);
     547            std::vector<EntityData>::iterator it = FindEntityData(ent);
    451548
    452549            // Ignore if we're not already tracking this entity
    453550            if (it == m_EntityData.end())
     
    457554            if (!cmpVision)
    458555                break;
    459556
    460             entity_pos_t oldRange = it->second.visionRange;
     557            entity_pos_t oldRange = it->visionRange;
    461558            entity_pos_t newRange = msgData.newRange;
    462559
    463560            // If the range changed and the entity's in-world, we need to manually adjust it
    464561            //  but if it's not in-world, we only need to set the new vision range
    465             CFixedVector2D pos(it->second.x, it->second.z);
    466             if (it->second.inWorld)
    467                 LosRemove(it->second.owner, oldRange, pos);
     562            CFixedVector2D pos(it->x, it->z);
     563            if (it->inWorld)
     564                LosRemove(it->owner, oldRange, pos);
    468565
    469             it->second.visionRange = newRange;
     566            it->visionRange = newRange;
    470567
    471             if (it->second.inWorld)
    472                 LosAdd(it->second.owner, newRange, pos);
     568            if (it->inWorld)
     569                LosAdd(it->owner, newRange, pos);
    473570
    474571            break;
    475572        }
     
    555652        m_LosStateRevealed.clear();
    556653        m_LosStateRevealed.resize(m_TerrainVerticesPerSide*m_TerrainVerticesPerSide);
    557654
    558         for (std::map<entity_id_t, EntityData>::const_iterator it = m_EntityData.begin(); it != m_EntityData.end(); ++it)
     655        for (std::vector<EntityData>::const_iterator it = m_EntityData.begin(); it != m_EntityData.end(); ++it)
    559656        {
    560             if (it->second.inWorld)
    561                 LosAdd(it->second.owner, it->second.visionRange, CFixedVector2D(it->second.x, it->second.z));
     657            if (it->inWorld)
     658                LosAdd(it->owner, it->visionRange, CFixedVector2D(it->x, it->z));
    562659        }
    563660
    564661        for (ssize_t j = 0; j < m_TerrainVerticesPerSide; ++j)
     
    572669        // (TODO: find the optimal number instead of blindly guessing)
    573670        m_Subdivision.Reset(x1, z1, entity_pos_t::FromInt(8*TERRAIN_TILE_SIZE));
    574671
    575         for (std::map<entity_id_t, EntityData>::const_iterator it = m_EntityData.begin(); it != m_EntityData.end(); ++it)
     672        for (std::vector<EntityData>::const_iterator it = m_EntityData.begin(); it != m_EntityData.end(); ++it)
    576673        {
    577             if (it->second.inWorld)
    578                 m_Subdivision.Add(it->first, CFixedVector2D(it->second.x, it->second.z));
     674            if (it->inWorld)
     675                m_Subdivision.Add(it->id, CFixedVector2D(it->x, it->z));
    579676        }
    580677    }
    581678
     
    589686        return id;
    590687    }
    591688
     689    virtual std::vector<EntityData>::iterator FindEntityData(entity_id_t entity)
     690    {
     691        std::vector<EntityData>::iterator it = find_entity(m_EntityData.begin(), m_EntityData.end(), entity);
     692        return it;
     693    }
     694
    592695    virtual void DestroyActiveQuery(tag_t tag)
    593696    {
    594697        if (m_Queries.find(tag) == m_Queries.end())
     
    693796
    694797        u32 ownerMask = CalcOwnerMask(player);
    695798
    696         for (std::map<entity_id_t, EntityData>::const_iterator it = m_EntityData.begin(); it != m_EntityData.end(); ++it)
     799        for (std::vector<EntityData>::const_iterator it = m_EntityData.begin(); it != m_EntityData.end(); ++it)
    697800        {
    698801            // Check owner and add to list if it matches
    699             if (CalcOwnerMask(it->second.owner) & ownerMask)
    700                 entities.push_back(it->first);
     802            if (CalcOwnerMask(it->owner) & ownerMask)
     803                entities.push_back(it->id);
    701804        }
    702805
    703806        return entities;
     
    766869    /**
    767870     * Returns whether the given entity matches the given query (ignoring maxRange)
    768871     */
    769     bool TestEntityQuery(const Query& q, entity_id_t id, const EntityData& entity)
     872    bool TestEntityQuery(const Query& q, const EntityData& entity)
    770873    {
    771874        // Quick filter to ignore entities with the wrong owner
    772875        if (!(CalcOwnerMask(entity.owner) & q.ownersMask))
     
    781884            return false;
    782885
    783886        // Ignore self
    784         if (id == q.source)
     887        if (entity.id == q.source)
    785888            return false;
    786889
    787890        // Ignore if it's missing the required interface
    788         if (q.interface && !GetSimContext().GetComponentManager().QueryInterface(id, q.interface))
     891        if (q.interface && !GetSimContext().GetComponentManager().QueryInterface(entity.id, q.interface))
    789892            return false;
    790893
    791894        return true;
     
    796899     */
    797900    void PerformQuery(const Query& q, std::vector<entity_id_t>& r)
    798901    {
     902        PROFILE("PerformQuery");
    799903        CmpPtr<ICmpPosition> cmpSourcePosition(GetSimContext(), q.source);
    800904        if (!cmpSourcePosition || !cmpSourcePosition->IsInWorld())
    801905            return;
     
    804908        // Special case: range -1.0 means check all entities ignoring distance
    805909        if (q.maxRange == entity_pos_t::FromInt(-1))
    806910        {
    807             for (std::map<entity_id_t, EntityData>::const_iterator it = m_EntityData.begin(); it != m_EntityData.end(); ++it)
     911            for (std::vector<EntityData>::const_iterator it = m_EntityData.begin(); it != m_EntityData.end(); ++it)
    808912            {
    809                 if (!TestEntityQuery(q, it->first, it->second))
     913                if (!TestEntityQuery(q, *it))
    810914                    continue;
    811915
    812                 r.push_back(it->first);
     916                r.push_back(it->id);
    813917            }
    814918        }
    815919        else
     
    819923
    820924            for (size_t i = 0; i < ents.size(); ++i)
    821925            {
    822                 std::map<entity_id_t, EntityData>::const_iterator it = m_EntityData.find(ents[i]);
     926                std::vector<EntityData>::const_iterator it = FindEntityData(ents[i]);
    823927                ENSURE(it != m_EntityData.end());
    824928
    825                 if (!TestEntityQuery(q, it->first, it->second))
     929                if (!TestEntityQuery(q, *it))
    826930                    continue;
    827931
    828932                // Restrict based on precise distance
    829                 int distVsMax = (CFixedVector2D(it->second.x, it->second.z) - pos).CompareLength(q.maxRange);
     933                int distVsMax = (CFixedVector2D(it->x, it->z) - pos).CompareLength(q.maxRange);
    830934                if (distVsMax > 0)
    831935                    continue;
    832936
    833937                if (!q.minRange.IsZero())
    834938                {
    835                     int distVsMin = (CFixedVector2D(it->second.x, it->second.z) - pos).CompareLength(q.minRange);
     939                    int distVsMin = (CFixedVector2D(it->x, it->z) - pos).CompareLength(q.minRange);
    836940                    if (distVsMin < 0)
    837941                        continue;
    838942                }
    839943
    840                 r.push_back(it->first);
     944                r.push_back(ents[i]);
    841945            }
    842946        }
    843947    }
     
    9451049   
    9461050    virtual void SetEntityFlag(entity_id_t ent, std::string identifier, bool value)
    9471051    {
    948         std::map<entity_id_t, EntityData>::iterator it = m_EntityData.find(ent);
     1052        std::vector<EntityData>::iterator it = FindEntityData(ent);
    9491053
    9501054        // We don't have this entity
    9511055        if (it == m_EntityData.end())
     
    9611065        }
    9621066
    9631067        if (value)
    964             it->second.flags |= flag;
     1068            it->flags |= flag;
    9651069        else
    966             it->second.flags &= ~flag;
     1070            it->flags &= ~flag;
    9671071    }
    9681072
    9691073    // ****************************************************************