Tom Rollet has submitted this change. ( https://gem5-review.googlesource.com/c/public/gem5/+/50733 )

Change subject: cpu-o3: remove LSQSenderState
......................................................................

cpu-o3: remove LSQSenderState

The LSQSenderState that was attached to Request was not useful.
All the fields were either a duplicate of information in the
LSQRequest or totally unused.

The LSQRequest class now inherits from Packet::SenderState and is
attached to the Packet that are sent to memory. We do not need
anymore the indirection Packet->SenderState->LSQRequest.

This helps making the code clearer as it was sometimes hard to
follow the difference between what the LSQRequest and
LSQSenserState was doing
(ex: number of outstanding requests in the memory).

Change-Id: I5b21e007e6d183c6aa79c27c1787ca56dcbc3fb0
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/50733
Reviewed-by: Bobby R. Bruce <bbr...@ucdavis.edu>
Maintainer: Bobby R. Bruce <bbr...@ucdavis.edu>
Tested-by: kokoro <noreply+kok...@google.com>
---
M src/cpu/o3/lsq.cc
M src/cpu/o3/lsq.hh
M src/cpu/o3/lsq_unit.cc
M src/cpu/o3/lsq_unit.hh
4 files changed, 103 insertions(+), 217 deletions(-)

Approvals:
  Bobby R. Bruce: Looks good to me, approved; Looks good to me, approved
  kokoro: Regressions pass




diff --git a/src/cpu/o3/lsq.cc b/src/cpu/o3/lsq.cc
index babfa92..61823df 100644
--- a/src/cpu/o3/lsq.cc
+++ b/src/cpu/o3/lsq.cc
@@ -64,16 +64,6 @@
 namespace o3
 {

-LSQ::LSQSenderState::LSQSenderState(LSQRequest *request, bool is_load) :
-    _request(request), isLoad(is_load), needWB(is_load)
-{}
-
-ContextID
-LSQ::LSQSenderState::contextId()
-{
-    return inst->contextId();
-}
-
 LSQ::DcachePort::DcachePort(LSQ *_lsq, CPU *_cpu) :
     RequestPort(_cpu->name() + ".dcache_port", _cpu), lsq(_lsq), cpu(_cpu)
 {}
@@ -402,8 +392,8 @@
 void
 LSQ::completeDataAccess(PacketPtr pkt)
 {
-    auto senderState = dynamic_cast<LSQSenderState*>(pkt->senderState);
-    thread[cpu->contextToThread(senderState->contextId())]
+    LSQRequest *request = dynamic_cast<LSQRequest*>(pkt->senderState);
+    thread[cpu->contextToThread(request->contextId())]
         .completeDataAccess(pkt);
 }

@@ -414,10 +404,10 @@
         DPRINTF(LSQ, "Got error packet back for address: %#X\n",
                 pkt->getAddr());

-    auto senderState = dynamic_cast<LSQSenderState*>(pkt->senderState);
-    panic_if(!senderState, "Got packet back with unknown sender state\n");
+    LSQRequest *request = dynamic_cast<LSQRequest*>(pkt->senderState);
+    panic_if(!request, "Got packet back with unknown sender state\n");

- thread[cpu->contextToThread(senderState->contextId())].recvTimingResp(pkt);
+    thread[cpu->contextToThread(request->contextId())].recvTimingResp(pkt);

     if (pkt->isInvalidate()) {
// This response also contains an invalidate; e.g. this can be the case
@@ -439,7 +429,7 @@
         }
     }
     // Update the LSQRequest state (this may delete the request)
-    senderState->request()->packetReplied();
+    request->packetReplied();

     return true;
 }
@@ -1041,14 +1031,15 @@

 LSQ::LSQRequest::LSQRequest(
         LSQUnit *port, const DynInstPtr& inst, bool isLoad) :
-    _state(State::NotIssued), _senderState(nullptr),
+    _state(State::NotIssued),
     _port(*port), _inst(inst), _data(nullptr),
     _res(nullptr), _addr(0), _size(0), _flags(0),
     _numOutstandingPackets(0), _amo_op(nullptr)
 {
     flags.set(Flag::IsLoad, isLoad);
-    flags.set(Flag::WbStore,
-              _inst->isStoreConditional() || _inst->isAtomic());
+    flags.set(Flag::WriteBackToRegister,
+              _inst->isStoreConditional() || _inst->isAtomic() ||
+              _inst->isLoad());
     flags.set(Flag::IsAtomic, _inst->isAtomic());
     install();
 }
@@ -1057,7 +1048,7 @@
         LSQUnit *port, const DynInstPtr& inst, bool isLoad,
const Addr& addr, const uint32_t& size, const Request::Flags& flags_,
            PacketDataPtr data, uint64_t* res, AtomicOpFunctorPtr amo_op)
-    : _state(State::NotIssued), _senderState(nullptr),
+    : _state(State::NotIssued),
     numTranslatedFragments(0),
     numInTranslationFragments(0),
     _port(*port), _inst(inst), _data(data),
@@ -1067,8 +1058,9 @@
     _amo_op(std::move(amo_op))
 {
     flags.set(Flag::IsLoad, isLoad);
-    flags.set(Flag::WbStore,
-              _inst->isStoreConditional() || _inst->isAtomic());
+    flags.set(Flag::WriteBackToRegister,
+              _inst->isStoreConditional() || _inst->isAtomic() ||
+              _inst->isLoad());
     flags.set(Flag::IsAtomic, _inst->isAtomic());
     install();
 }
@@ -1105,13 +1097,17 @@
 {
     assert(!isAnyOutstandingRequest());
     _inst->savedReq = nullptr;
-    if (_senderState)
-        delete _senderState;

     for (auto r: _packets)
         delete r;
 };

+ContextID
+LSQ::LSQRequest::contextId() const
+{
+    return _inst->contextId();
+}
+
 void
 LSQ::LSQRequest::sendFragmentToTranslation(int i)
 {
@@ -1124,9 +1120,7 @@
 LSQ::SingleDataRequest::recvTimingResp(PacketPtr pkt)
 {
     assert(_numOutstandingPackets == 1);
-    auto state = dynamic_cast<LSQSenderState*>(pkt->senderState);
     flags.set(Flag::Complete);
-    state->outstanding--;
     assert(pkt == _packets.front());
     _port.completeDataAccess(pkt);
     return true;
@@ -1135,13 +1129,11 @@
 bool
 LSQ::SplitDataRequest::recvTimingResp(PacketPtr pkt)
 {
-    auto state = dynamic_cast<LSQSenderState*>(pkt->senderState);
     uint32_t pktIdx = 0;
     while (pktIdx < _packets.size() && pkt != _packets[pktIdx])
         pktIdx++;
     assert(pktIdx < _packets.size());
     numReceivedPackets++;
-    state->outstanding--;
     if (numReceivedPackets == _packets.size()) {
         flags.set(Flag::Complete);
         /* Assemble packets. */
@@ -1152,7 +1144,7 @@
             resp->dataStatic(_inst->memData);
         else
             resp->dataStatic(_data);
-        resp->senderState = _senderState;
+        resp->senderState = this;
         _port.completeDataAccess(resp);
         delete resp;
     }
@@ -1162,7 +1154,6 @@
 void
 LSQ::SingleDataRequest::buildPackets()
 {
-    assert(_senderState);
     /* Retries do not create new packets. */
     if (_packets.size() == 0) {
         _packets.push_back(
@@ -1170,7 +1161,7 @@
                     ?  Packet::createRead(request())
                     :  Packet::createWrite(request()));
         _packets.back()->dataStatic(_inst->memData);
-        _packets.back()->senderState = _senderState;
+        _packets.back()->senderState = this;

         // hardware transactional memory
// If request originates in a transaction (not necessarily a HtmCmd),
@@ -1233,7 +1224,7 @@
                         r->getSize());
                 pkt->dataDynamic(req_data);
             }
-            pkt->senderState = _senderState;
+            pkt->senderState = this;
             _packets.push_back(pkt);

             // hardware transactional memory
diff --git a/src/cpu/o3/lsq.hh b/src/cpu/o3/lsq.hh
index f843e64..4dc374e 100644
--- a/src/cpu/o3/lsq.hh
+++ b/src/cpu/o3/lsq.hh
@@ -76,48 +76,6 @@
 {
   public:
     class LSQRequest;
-    /** Derived class to hold any sender state the LSQ needs. */
-    class LSQSenderState : public Packet::SenderState
-    {
-      protected:
-        /** The senderState needs to know the LSQRequest who owns it. */
-        LSQRequest* _request;
-
-        /** Default constructor. */
-        LSQSenderState(LSQRequest* request, bool is_load);
-
-      public:
-        /** Instruction which initiated the access to memory. */
-        DynInstPtr inst;
-        /** The main packet from a split load, used during writeback. */
-        PacketPtr mainPkt = nullptr;
-        /** A second packet from a split store that needs sending. */
-        PacketPtr pendingPacket = nullptr;
-        /** Number of outstanding packets to complete. */
-        uint8_t outstanding = 0;
-        /** Whether or not it is a load. */
-        bool isLoad = false;
-        /** Whether or not the instruction will need to writeback. */
-        bool needWB = false;
-        /** Whether or not this access is split in two. */
-        bool isSplit = false;
-        /** Whether or not there is a packet that needs sending. */
-        bool pktToSend = false;
-        /** Has the request been deleted?
- * LSQ entries can be squashed before the response comes back. in that
-         * case the SenderState knows.
-         */
-        bool deleted = false;
-        ContextID contextId();
-
- /** Completes a packet and returns whether the access is finished. */
-        bool isComplete() { return outstanding == 0; }
-        void deleteRequest() { deleted = true; }
-        bool alive() { return !deleted; }
-        LSQRequest* request() { return _request; }
-        virtual void complete() = 0;
-        void writebackDone() { _request->writebackDone(); }
-    };

     /**
      * DcachePort class for the load/store queue.
@@ -164,12 +122,12 @@
      * This class holds the information about a memory operation. It lives
      * from initiateAcc to resource deallocation at commit or squash.
      * LSQRequest objects are owned by the LQ/SQ Entry in the LSQUnit that
- * holds the operation. It is also used by the LSQSenderState. In addition, - * the LSQRequest is a TranslationState, therefore, upon squash, there must
-     * be a defined ownership transferal in case the LSQ resources are
- * deallocated before the TLB is done using the TranslationState. If that - * happens, the LSQRequest will be self-owned, and responsible to detect
-     * that its services are no longer required and self-destruct.
+ * holds the operation. In addition, the LSQRequest is a TranslationState,
+     * therefore, upon squash, there must be a defined ownership transferal
+ * in case the LSQ resources are deallocated before the TLB is done using
+     * the TranslationState.
+ * If that happens, the LSQRequest will be self-owned, and responsible to
+     * detect that its services are no longer required and self-destruct.
      *
      * Lifetime of a LSQRequest:
      *                 +--------------------+
@@ -215,8 +173,8 @@
      *            | |  +--------------------+
      *            | |
      *            | |  +--------------------+
-     *            | |  |  senderState owns  |
-     *            | +->|  onRecvTimingResp  |
+     *            | |  |    self owned      |
+     *            | +->|  on recvTimingResp |
      *            |    |   free resources   |
      *            |    +--------------------+
      *            |
@@ -228,7 +186,7 @@
      *
      *
      */
-    class LSQRequest : public BaseMMU::Translation
+ class LSQRequest : public BaseMMU::Translation, public Packet::SenderState
     {
       protected:
         typedef uint32_t FlagsStorage;
@@ -237,8 +195,11 @@
         enum Flag : FlagsStorage
         {
             IsLoad              = 0x00000001,
- /** True if this is a store/atomic that writes registers (SC). */
-            WbStore             = 0x00000002,
+            /** True if this request needs to writeBack to register.
+              * Will be set in case of load or a store/atomic
+              * that writes registers (SC)
+              */
+            WriteBackToRegister = 0x00000002,
             Delayed             = 0x00000004,
             IsSplit             = 0x00000008,
             /** True if any translation has been sent to TLB. */
@@ -272,14 +233,11 @@
             PartialFault,
         };
         State _state;
-        LSQSenderState* _senderState;
         void setState(const State& newState) { _state = newState; }

         uint32_t numTranslatedFragments;
         uint32_t numInTranslationFragments;

-        /** LQ/SQ entry idx. */
-        uint32_t _entryIdx;

         void markDelayed() override { flags.set(Flag::Delayed); }
         bool isDelayed() { return flags.isSet(Flag::Delayed); }
@@ -324,17 +282,6 @@

         bool squashed() const override;

-        /**
-         * Test if the LSQRequest has been released, i.e. self-owned.
- * An LSQRequest manages itself when the resources on the LSQ are freed - * but the translation is still going on and the LSQEntry was freed.
-         */
-        bool
-        isReleased()
-        {
-            return flags.isSet(Flag::LSQEntryFreed) ||
-                flags.isSet(Flag::Discarded);
-        }

         /** Release the LSQRequest.
* Notify the sender state that the request it points to is not valid
@@ -352,9 +299,6 @@
             if (!isAnyOutstandingRequest()) {
                 delete this;
             } else {
-                if (_senderState) {
-                    _senderState->deleteRequest();
-                }
                 flags.set(reason);
             }
         }
@@ -396,6 +340,8 @@
             request()->setVirt(vaddr, size, flags_, requestor_id, pc);
         }

+        ContextID contextId() const;
+
         void
         taskId(const uint32_t& v)
         {
@@ -432,33 +378,6 @@
             return request();
         }

-        void
-        senderState(LSQSenderState* st)
-        {
-            _senderState = st;
-            for (auto& pkt: _packets) {
-                if (pkt)
-                    pkt->senderState = st;
-            }
-        }
-
-        const LSQSenderState*
-        senderState() const
-        {
-            return _senderState;
-        }
-
-        /**
- * Mark senderState as discarded. This will cause to discard response
-         * packets from the cache.
-         */
-        void
-        discardSenderState()
-        {
-            assert(_senderState);
-            _senderState->deleteRequest();
-        }
-
         /**
          * Test if there is any in-flight translation or mem access request
          */
@@ -471,11 +390,29 @@
                  !flags.isSet(Flag::WritebackDone));
         }

+        /**
+         * Test if the LSQRequest has been released, i.e. self-owned.
+ * An LSQRequest manages itself when the resources on the LSQ are freed + * but the translation is still going on and the LSQEntry was freed.
+         */
+        bool
+        isReleased()
+        {
+            return flags.isSet(Flag::LSQEntryFreed) ||
+                flags.isSet(Flag::Discarded);
+        }
+
         bool
         isSplit() const
         {
             return flags.isSet(Flag::IsSplit);
         }
+
+        bool
+        needWBToRegister() const
+        {
+            return flags.isSet(Flag::WriteBackToRegister);
+        }
         /** @} */
         virtual bool recvTimingResp(PacketPtr pkt) = 0;
         virtual void sendPacketToCache() = 0;
@@ -644,7 +581,6 @@
         using LSQRequest::_port;
         using LSQRequest::_res;
         using LSQRequest::_taskId;
-        using LSQRequest::_senderState;
         using LSQRequest::_state;
         using LSQRequest::flags;
         using LSQRequest::isLoad;
@@ -723,7 +659,6 @@
         using LSQRequest::_requests;
         using LSQRequest::_res;
         using LSQRequest::_byteEnable;
-        using LSQRequest::_senderState;
         using LSQRequest::_size;
         using LSQRequest::_state;
         using LSQRequest::_taskId;
diff --git a/src/cpu/o3/lsq_unit.cc b/src/cpu/o3/lsq_unit.cc
index 8b7bca5..c5187ea 100644
--- a/src/cpu/o3/lsq_unit.cc
+++ b/src/cpu/o3/lsq_unit.cc
@@ -92,25 +92,21 @@
 bool
 LSQUnit::recvTimingResp(PacketPtr pkt)
 {
-    auto senderState = dynamic_cast<LSQSenderState*>(pkt->senderState);
-    LSQRequest* req = senderState->request();
-    assert(req != nullptr);
+    LSQRequest *request = dynamic_cast<LSQRequest*>(pkt->senderState);
+    assert(request != nullptr);
     bool ret = true;
     /* Check that the request is still alive before any further action. */
-    if (senderState->alive()) {
-        ret = req->recvTimingResp(pkt);
-    } else {
-        senderState->outstanding--;
+    if (!request->isReleased()) {
+        ret = request->recvTimingResp(pkt);
     }
     return ret;
-
 }

 void
 LSQUnit::completeDataAccess(PacketPtr pkt)
 {
- LSQSenderState *state = dynamic_cast<LSQSenderState *>(pkt->senderState);
-    DynInstPtr inst = state->inst;
+    LSQRequest *request = dynamic_cast<LSQRequest *>(pkt->senderState);
+    DynInstPtr inst = request->instruction();

     // hardware transactional memory
     // sanity check
@@ -167,13 +163,9 @@

     cpu->ppDataAccessComplete->notify(std::make_pair(inst, pkt));

-    /* Notify the sender state that the access is complete (for ownership
-     * tracking). */
-    state->complete();
-
     assert(!cpu->switchedOut());
     if (!inst->isSquashed()) {
-        if (state->needWB) {
+        if (request->needWBToRegister()) {
// Only loads, store conditionals and atomics perform the writeback
             // after receving the response from the memory
             assert(inst->isLoad() || inst->isStoreConditional() ||
@@ -181,20 +173,19 @@

             // hardware transactional memory
             if (pkt->htmTransactionFailedInCache()) {
- state->request()->mainPacket()->setHtmTransactionFailedInCache(
+                request->mainPacket()->setHtmTransactionFailedInCache(
                     pkt->getHtmTransactionFailedInCacheRC() );
             }

-            writeback(inst, state->request()->mainPacket());
+            writeback(inst, request->mainPacket());
             if (inst->isStore() || inst->isAtomic()) {
-                auto ss = dynamic_cast<SQSenderState*>(state);
-                ss->writebackDone();
-                completeStore(ss->idx);
+                request->writebackDone();
+                completeStore(request->instruction()->sqIt);
             }
         } else if (inst->isStore()) {
             // This is a regular store (i.e., not store conditionals and
             // atomics), so it can complete without writing back
-            completeStore(dynamic_cast<SQSenderState*>(state)->idx);
+            completeStore(request->instruction()->sqIt);
         }
     }
 }
@@ -397,6 +388,8 @@
     storeQueue.advance_tail();

     store_inst->sqIdx = storeQueue.tail();
+    store_inst->sqIt = storeQueue.getIterator(store_inst->sqIdx);
+
     store_inst->lqIdx = loadQueue.tail() + 1;
     assert(store_inst->lqIdx > 0);
     store_inst->lqIt = loadQueue.end();
@@ -859,18 +852,6 @@
             memcpy(inst->memData, storeWBIt->data(), req->_size);


-        if (req->senderState() == nullptr) {
-            SQSenderState *state = new SQSenderState(storeWBIt);
-            state->isLoad = false;
-            state->needWB = false;
-            state->inst = inst;
-
-            req->senderState(state);
-            if (inst->isStoreConditional() || inst->isAtomic()) {
-                /* Only store conditionals and atomics need a writeback. */
-                state->needWB = true;
-            }
-        }
         req->buildPackets();

         DPRINTF(LSQUnit, "D-Cache: Writing back store idx:%i PC:%s "
@@ -1221,7 +1202,7 @@
     bool ret = true;
     bool cache_got_blocked = false;

-    auto state = dynamic_cast<LSQSenderState*>(data_pkt->senderState);
+    LSQRequest *request = dynamic_cast<LSQRequest*>(data_pkt->senderState);

     if (!lsq->cacheBlocked() &&
         lsq->cachePortAvailable(isLoad)) {
@@ -1238,22 +1219,21 @@
             isStoreBlocked = false;
         }
         lsq->cachePortBusy(isLoad);
-        state->outstanding++;
-        state->request()->packetSent();
+        request->packetSent();
     } else {
         if (cache_got_blocked) {
             lsq->cacheBlocked(true);
             ++stats.blockedByCache;
         }
         if (!isLoad) {
-            assert(state->request() == storeWBIt->request());
+            assert(request == storeWBIt->request());
             isStoreBlocked = true;
         }
-        state->request()->packetNotSent();
+        request->packetNotSent();
     }
     DPRINTF(LSQUnit, "Memory request (pkt: %s) from inst [sn:%llu] was"
             " %ssent (cache is blocked: %d, cache_got_blocked: %d)\n",
-            data_pkt->print(), state->inst->seqNum,
+            data_pkt->print(), request->instruction()->seqNum,
             ret ? "": "not ", lsq->cacheBlocked(), cache_got_blocked);
     return ret;
 }
@@ -1528,7 +1508,7 @@
                     // This may happen if the store was not complete the
// first time this load got executed. Signal the senderSate
                     // that response packets should be discarded.
-                    req->discardSenderState();
+                    req->discard();
                 }

WritebackEvent *wb = new WritebackEvent(load_inst, data_pkt,
@@ -1609,14 +1589,6 @@
     // and arbitrate between loads and stores.

     // if we the cache is not blocked, do cache access
-    if (req->senderState() == nullptr) {
-        LQSenderState *state = new LQSenderState(
-                loadQueue.getIterator(load_idx));
-        state->isLoad = true;
-        state->inst = load_inst;
-        state->isSplit = req->isSplit();
-        req->senderState(state);
-    }
     req->buildPackets();
     req->sendPacketToCache();
     if (!req->isSent())
diff --git a/src/cpu/o3/lsq_unit.hh b/src/cpu/o3/lsq_unit.hh
index 5b31d20..9bb1124 100644
--- a/src/cpu/o3/lsq_unit.hh
+++ b/src/cpu/o3/lsq_unit.hh
@@ -91,7 +91,6 @@
   public:
     static constexpr auto MaxDataBytes = MaxVecRegLenInBytes;

-    using LSQSenderState = LSQ::LSQSenderState;
     using LSQRequest = LSQ::LSQRequest;
   private:
     class LSQEntry
@@ -405,43 +404,6 @@
     /** Pointer to the dcache port.  Used only for sending. */
     RequestPort *dcachePort;

-    /** Particularisation of the LSQSenderState to the LQ. */
-    class LQSenderState : public LSQSenderState
-    {
-        using LSQSenderState::alive;
-      public:
-        LQSenderState(typename LoadQueue::iterator idx_)
-            : LSQSenderState(idx_->request(), true), idx(idx_) { }
-
-        /** The LQ index of the instruction. */
-        typename LoadQueue::iterator idx;
-        //virtual LSQRequest* request() { return idx->request(); }
-        virtual void
-        complete()
-        {
-            //if (alive())
-            //  idx->request()->senderState(nullptr);
-        }
-    };
-
-    /** Particularisation of the LSQSenderState to the SQ. */
-    class SQSenderState : public LSQSenderState
-    {
-        using LSQSenderState::alive;
-      public:
-        SQSenderState(typename StoreQueue::iterator idx_)
-            : LSQSenderState(idx_->request(), false), idx(idx_) { }
-        /** The SQ index of the instruction. */
-        typename StoreQueue::iterator idx;
-        //virtual LSQRequest* request() { return idx->request(); }
-        virtual void
-        complete()
-        {
-            //if (alive())
-            //   idx->request()->senderState(nullptr);
-        }
-    };
-
/** Writeback event, specifically for when stores forward data to loads. */
     class WritebackEvent : public Event
     {

--
To view, visit https://gem5-review.googlesource.com/c/public/gem5/+/50733
To unsubscribe, or for help writing mail filters, visit https://gem5-review.googlesource.com/settings

Gerrit-Project: public/gem5
Gerrit-Branch: develop
Gerrit-Change-Id: I5b21e007e6d183c6aa79c27c1787ca56dcbc3fb0
Gerrit-Change-Number: 50733
Gerrit-PatchSet: 5
Gerrit-Owner: Tom Rollet <tom.rol...@huawei.com>
Gerrit-Reviewer: Andreas Sandberg <andreas.sandb...@arm.com>
Gerrit-Reviewer: Bobby R. Bruce <bbr...@ucdavis.edu>
Gerrit-Reviewer: Gabe Black <gabe.bl...@gmail.com>
Gerrit-Reviewer: Jason Lowe-Power <ja...@lowepower.com>
Gerrit-Reviewer: Tom Rollet <tom.rol...@huawei.com>
Gerrit-Reviewer: kokoro <noreply+kok...@google.com>
Gerrit-MessageType: merged
_______________________________________________
gem5-dev mailing list -- gem5-dev@gem5.org
To unsubscribe send an email to gem5-dev-le...@gem5.org
%(web_page_url)slistinfo%(cgiext)s/%(_internal_name)s

Reply via email to