elastic_trace.cc revision 12104
111308Santhony.gutierrez@amd.com/*
211308Santhony.gutierrez@amd.com * Copyright (c) 2013 - 2015 ARM Limited
311308Santhony.gutierrez@amd.com * All rights reserved
411308Santhony.gutierrez@amd.com *
511308Santhony.gutierrez@amd.com * The license below extends only to copyright in the software and shall
611308Santhony.gutierrez@amd.com * not be construed as granting a license to any other intellectual
711308Santhony.gutierrez@amd.com * property including but not limited to intellectual property relating
811308Santhony.gutierrez@amd.com * to a hardware implementation of the functionality of the software
911308Santhony.gutierrez@amd.com * licensed hereunder.  You may use the software subject to the license
1011308Santhony.gutierrez@amd.com * terms below provided that you ensure that this notice is replicated
1111308Santhony.gutierrez@amd.com * unmodified and in its entirety in all distributions of the software,
1211308Santhony.gutierrez@amd.com * modified or unmodified, in source code or in binary form.
1311308Santhony.gutierrez@amd.com *
1411308Santhony.gutierrez@amd.com * Redistribution and use in source and binary forms, with or without
1511308Santhony.gutierrez@amd.com * modification, are permitted provided that the following conditions are
1611308Santhony.gutierrez@amd.com * met: redistributions of source code must retain the above copyright
1711308Santhony.gutierrez@amd.com * notice, this list of conditions and the following disclaimer;
1811308Santhony.gutierrez@amd.com * redistributions in binary form must reproduce the above copyright
1911308Santhony.gutierrez@amd.com * notice, this list of conditions and the following disclaimer in the
2011308Santhony.gutierrez@amd.com * documentation and/or other materials provided with the distribution;
2111308Santhony.gutierrez@amd.com * neither the name of the copyright holders nor the names of its
2211308Santhony.gutierrez@amd.com * contributors may be used to endorse or promote products derived from
2311308Santhony.gutierrez@amd.com * this software without specific prior written permission.
2411308Santhony.gutierrez@amd.com *
2511308Santhony.gutierrez@amd.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2611308Santhony.gutierrez@amd.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2711308Santhony.gutierrez@amd.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2811308Santhony.gutierrez@amd.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2911308Santhony.gutierrez@amd.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
3011308Santhony.gutierrez@amd.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3111308Santhony.gutierrez@amd.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3211308Santhony.gutierrez@amd.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3311308Santhony.gutierrez@amd.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3411308Santhony.gutierrez@amd.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3511308Santhony.gutierrez@amd.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3611308Santhony.gutierrez@amd.com *
3711308Santhony.gutierrez@amd.com * Authors: Radhika Jagtap
3811308Santhony.gutierrez@amd.com *          Andreas Hansson
3911308Santhony.gutierrez@amd.com *          Thomas Grass
4011308Santhony.gutierrez@amd.com */
4111308Santhony.gutierrez@amd.com
4211308Santhony.gutierrez@amd.com#include "cpu/o3/probe/elastic_trace.hh"
4311308Santhony.gutierrez@amd.com
4411308Santhony.gutierrez@amd.com#include "base/callback.hh"
4511308Santhony.gutierrez@amd.com#include "base/output.hh"
4611308Santhony.gutierrez@amd.com#include "base/trace.hh"
4711308Santhony.gutierrez@amd.com#include "cpu/reg_class.hh"
4811308Santhony.gutierrez@amd.com#include "debug/ElasticTrace.hh"
4911308Santhony.gutierrez@amd.com#include "mem/packet.hh"
5011308Santhony.gutierrez@amd.com
5111308Santhony.gutierrez@amd.comElasticTrace::ElasticTrace(const ElasticTraceParams* params)
5211308Santhony.gutierrez@amd.com    :  ProbeListenerObject(params),
5311308Santhony.gutierrez@amd.com       regEtraceListenersEvent([this]{ regEtraceListeners(); }, name()),
5411308Santhony.gutierrez@amd.com       firstWin(true),
5511308Santhony.gutierrez@amd.com       lastClearedSeqNum(0),
5611308Santhony.gutierrez@amd.com       depWindowSize(params->depWindowSize),
5711308Santhony.gutierrez@amd.com       dataTraceStream(nullptr),
5811308Santhony.gutierrez@amd.com       instTraceStream(nullptr),
5911308Santhony.gutierrez@amd.com       startTraceInst(params->startTraceInst),
6011308Santhony.gutierrez@amd.com       allProbesReg(false),
6111308Santhony.gutierrez@amd.com       traceVirtAddr(params->traceVirtAddr)
6211308Santhony.gutierrez@amd.com{
6311308Santhony.gutierrez@amd.com    cpu = dynamic_cast<FullO3CPU<O3CPUImpl>*>(params->manager);
6411308Santhony.gutierrez@amd.com    fatal_if(!cpu, "Manager of %s is not of type O3CPU and thus does not "\
6511308Santhony.gutierrez@amd.com                "support dependency tracing.\n", name());
6611308Santhony.gutierrez@amd.com
6711308Santhony.gutierrez@amd.com    fatal_if(depWindowSize == 0, "depWindowSize parameter must be non-zero. "\
6811308Santhony.gutierrez@amd.com                "Recommended size is 3x ROB size in the O3CPU.\n");
6911308Santhony.gutierrez@amd.com
7011308Santhony.gutierrez@amd.com    fatal_if(cpu->numThreads > 1, "numThreads = %i, %s supports tracing for"\
7111308Santhony.gutierrez@amd.com                "single-threaded workload only", cpu->numThreads, name());
7211308Santhony.gutierrez@amd.com    // Initialize the protobuf output stream
7311308Santhony.gutierrez@amd.com    fatal_if(params->instFetchTraceFile == "", "Assign instruction fetch "\
7411308Santhony.gutierrez@amd.com                "trace file path to instFetchTraceFile");
7511308Santhony.gutierrez@amd.com    fatal_if(params->dataDepTraceFile == "", "Assign data dependency "\
7611308Santhony.gutierrez@amd.com                "trace file path to dataDepTraceFile");
7711308Santhony.gutierrez@amd.com    std::string filename = simout.resolve(name() + "." +
7811308Santhony.gutierrez@amd.com                                            params->instFetchTraceFile);
7911308Santhony.gutierrez@amd.com    instTraceStream = new ProtoOutputStream(filename);
8011308Santhony.gutierrez@amd.com    filename = simout.resolve(name() + "." + params->dataDepTraceFile);
8111308Santhony.gutierrez@amd.com    dataTraceStream = new ProtoOutputStream(filename);
8211308Santhony.gutierrez@amd.com    // Create a protobuf message for the header and write it to the stream
8311308Santhony.gutierrez@amd.com    ProtoMessage::PacketHeader inst_pkt_header;
8411308Santhony.gutierrez@amd.com    inst_pkt_header.set_obj_id(name());
8511308Santhony.gutierrez@amd.com    inst_pkt_header.set_tick_freq(SimClock::Frequency);
8611308Santhony.gutierrez@amd.com    instTraceStream->write(inst_pkt_header);
8711308Santhony.gutierrez@amd.com    // Create a protobuf message for the header and write it to
8811308Santhony.gutierrez@amd.com    // the stream
8911308Santhony.gutierrez@amd.com    ProtoMessage::InstDepRecordHeader data_rec_header;
9011308Santhony.gutierrez@amd.com    data_rec_header.set_obj_id(name());
9111308Santhony.gutierrez@amd.com    data_rec_header.set_tick_freq(SimClock::Frequency);
9211308Santhony.gutierrez@amd.com    data_rec_header.set_window_size(depWindowSize);
9311308Santhony.gutierrez@amd.com    dataTraceStream->write(data_rec_header);
9411308Santhony.gutierrez@amd.com    // Register a callback to flush trace records and close the output streams.
9511308Santhony.gutierrez@amd.com    Callback* cb = new MakeCallback<ElasticTrace,
9611308Santhony.gutierrez@amd.com        &ElasticTrace::flushTraces>(this);
9711308Santhony.gutierrez@amd.com    registerExitCallback(cb);
9811308Santhony.gutierrez@amd.com}
9911308Santhony.gutierrez@amd.com
10011308Santhony.gutierrez@amd.comvoid
10111308Santhony.gutierrez@amd.comElasticTrace::regProbeListeners()
10211308Santhony.gutierrez@amd.com{
10311308Santhony.gutierrez@amd.com    inform("@%llu: regProbeListeners() called, startTraceInst = %llu",
10411308Santhony.gutierrez@amd.com        curTick(), startTraceInst);
10511308Santhony.gutierrez@amd.com    if (startTraceInst == 0) {
10611308Santhony.gutierrez@amd.com        // If we want to start tracing from the start of the simulation,
10711308Santhony.gutierrez@amd.com        // register all elastic trace probes now.
10811308Santhony.gutierrez@amd.com        regEtraceListeners();
10911308Santhony.gutierrez@amd.com    } else {
11011308Santhony.gutierrez@amd.com        // Schedule an event to register all elastic trace probes when
11111308Santhony.gutierrez@amd.com        // specified no. of instructions are committed.
11211308Santhony.gutierrez@amd.com        cpu->comInstEventQueue[(ThreadID)0]->schedule(&regEtraceListenersEvent,
11311308Santhony.gutierrez@amd.com                                                      startTraceInst);
11411308Santhony.gutierrez@amd.com    }
11511308Santhony.gutierrez@amd.com}
11611308Santhony.gutierrez@amd.com
11711308Santhony.gutierrez@amd.comvoid
11811308Santhony.gutierrez@amd.comElasticTrace::regEtraceListeners()
11911308Santhony.gutierrez@amd.com{
12011308Santhony.gutierrez@amd.com    assert(!allProbesReg);
12111308Santhony.gutierrez@amd.com    inform("@%llu: No. of instructions committed = %llu, registering elastic"
12211308Santhony.gutierrez@amd.com        " probe listeners", curTick(), cpu->numSimulatedInsts());
12311308Santhony.gutierrez@amd.com    // Create new listeners: provide method to be called upon a notify() for
12411308Santhony.gutierrez@amd.com    // each probe point.
12511308Santhony.gutierrez@amd.com    listeners.push_back(new ProbeListenerArg<ElasticTrace, RequestPtr>(this,
12611308Santhony.gutierrez@amd.com                        "FetchRequest", &ElasticTrace::fetchReqTrace));
12711308Santhony.gutierrez@amd.com    listeners.push_back(new ProbeListenerArg<ElasticTrace, DynInstPtr>(this,
12811308Santhony.gutierrez@amd.com                        "Execute", &ElasticTrace::recordExecTick));
12911308Santhony.gutierrez@amd.com    listeners.push_back(new ProbeListenerArg<ElasticTrace, DynInstPtr>(this,
13011308Santhony.gutierrez@amd.com                        "ToCommit", &ElasticTrace::recordToCommTick));
13111308Santhony.gutierrez@amd.com    listeners.push_back(new ProbeListenerArg<ElasticTrace, DynInstPtr>(this,
13211308Santhony.gutierrez@amd.com                        "Rename", &ElasticTrace::updateRegDep));
13311308Santhony.gutierrez@amd.com    listeners.push_back(new ProbeListenerArg<ElasticTrace, SeqNumRegPair>(this,
13411308Santhony.gutierrez@amd.com                        "SquashInRename", &ElasticTrace::removeRegDepMapEntry));
13511308Santhony.gutierrez@amd.com    listeners.push_back(new ProbeListenerArg<ElasticTrace, DynInstPtr>(this,
13611308Santhony.gutierrez@amd.com                        "Squash", &ElasticTrace::addSquashedInst));
13711308Santhony.gutierrez@amd.com    listeners.push_back(new ProbeListenerArg<ElasticTrace, DynInstPtr>(this,
13811308Santhony.gutierrez@amd.com                        "Commit", &ElasticTrace::addCommittedInst));
13911308Santhony.gutierrez@amd.com    allProbesReg = true;
14011308Santhony.gutierrez@amd.com}
14111308Santhony.gutierrez@amd.com
14211308Santhony.gutierrez@amd.comvoid
14311308Santhony.gutierrez@amd.comElasticTrace::fetchReqTrace(const RequestPtr &req)
14411308Santhony.gutierrez@amd.com{
14511308Santhony.gutierrez@amd.com
14611308Santhony.gutierrez@amd.com    DPRINTFR(ElasticTrace, "Fetch Req %i,(%lli,%lli,%lli),%i,%i,%lli\n",
14711308Santhony.gutierrez@amd.com             (MemCmd::ReadReq),
14811308Santhony.gutierrez@amd.com             req->getPC(), req->getVaddr(), req->getPaddr(),
14911308Santhony.gutierrez@amd.com             req->getFlags(), req->getSize(), curTick());
15011308Santhony.gutierrez@amd.com
15111308Santhony.gutierrez@amd.com    // Create a protobuf message including the request fields necessary to
15211308Santhony.gutierrez@amd.com    // recreate the request in the TraceCPU.
15311308Santhony.gutierrez@amd.com    ProtoMessage::Packet inst_fetch_pkt;
15411308Santhony.gutierrez@amd.com    inst_fetch_pkt.set_tick(curTick());
15511308Santhony.gutierrez@amd.com    inst_fetch_pkt.set_cmd(MemCmd::ReadReq);
15611308Santhony.gutierrez@amd.com    inst_fetch_pkt.set_pc(req->getPC());
15711308Santhony.gutierrez@amd.com    inst_fetch_pkt.set_flags(req->getFlags());
15811308Santhony.gutierrez@amd.com    inst_fetch_pkt.set_addr(req->getPaddr());
15911308Santhony.gutierrez@amd.com    inst_fetch_pkt.set_size(req->getSize());
16011308Santhony.gutierrez@amd.com    // Write the message to the stream.
16111308Santhony.gutierrez@amd.com    instTraceStream->write(inst_fetch_pkt);
16211308Santhony.gutierrez@amd.com}
16311308Santhony.gutierrez@amd.com
16411308Santhony.gutierrez@amd.comvoid
16511308Santhony.gutierrez@amd.comElasticTrace::recordExecTick(const DynInstPtr &dyn_inst)
16611308Santhony.gutierrez@amd.com{
16711308Santhony.gutierrez@amd.com
16811308Santhony.gutierrez@amd.com    // In a corner case, a retired instruction is propagated backward to the
16911308Santhony.gutierrez@amd.com    // IEW instruction queue to handle some side-channel information. But we
17011308Santhony.gutierrez@amd.com    // must not process an instruction again. So we test the sequence number
17111308Santhony.gutierrez@amd.com    // against the lastClearedSeqNum and skip adding the instruction for such
17211308Santhony.gutierrez@amd.com    // corner cases.
17311308Santhony.gutierrez@amd.com    if (dyn_inst->seqNum <= lastClearedSeqNum) {
17411308Santhony.gutierrez@amd.com        DPRINTFR(ElasticTrace, "[sn:%lli] Ignoring in execute as instruction \
17511308Santhony.gutierrez@amd.com        has already retired (mostly squashed)", dyn_inst->seqNum);
17611308Santhony.gutierrez@amd.com        // Do nothing as program has proceeded and this inst has been
17711308Santhony.gutierrez@amd.com        // propagated backwards to handle something.
17811308Santhony.gutierrez@amd.com        return;
17911308Santhony.gutierrez@amd.com    }
18011308Santhony.gutierrez@amd.com
18111308Santhony.gutierrez@amd.com    DPRINTFR(ElasticTrace, "[sn:%lli] Execute Tick = %i\n", dyn_inst->seqNum,
18211308Santhony.gutierrez@amd.com                curTick());
18311308Santhony.gutierrez@amd.com    // Either the execution info object will already exist if this
18411308Santhony.gutierrez@amd.com    // instruction had a register dependency recorded in the rename probe
18511308Santhony.gutierrez@amd.com    // listener before entering execute stage or it will not exist and will
18611308Santhony.gutierrez@amd.com    // need to be created here.
18711308Santhony.gutierrez@amd.com    InstExecInfo* exec_info_ptr;
18811308Santhony.gutierrez@amd.com    auto itr_exec_info = tempStore.find(dyn_inst->seqNum);
18911308Santhony.gutierrez@amd.com    if (itr_exec_info != tempStore.end()) {
19011308Santhony.gutierrez@amd.com        exec_info_ptr = itr_exec_info->second;
19111308Santhony.gutierrez@amd.com    } else {
19211308Santhony.gutierrez@amd.com        exec_info_ptr = new InstExecInfo;
19311308Santhony.gutierrez@amd.com        tempStore[dyn_inst->seqNum] = exec_info_ptr;
19411308Santhony.gutierrez@amd.com    }
19511308Santhony.gutierrez@amd.com
19611308Santhony.gutierrez@amd.com    exec_info_ptr->executeTick = curTick();
19711308Santhony.gutierrez@amd.com    maxTempStoreSize = std::max(tempStore.size(),
19811308Santhony.gutierrez@amd.com                                (std::size_t)maxTempStoreSize.value());
19911308Santhony.gutierrez@amd.com}
20011308Santhony.gutierrez@amd.com
20111308Santhony.gutierrez@amd.comvoid
20211308Santhony.gutierrez@amd.comElasticTrace::recordToCommTick(const DynInstPtr &dyn_inst)
20311308Santhony.gutierrez@amd.com{
20411308Santhony.gutierrez@amd.com    // If tracing has just been enabled then the instruction at this stage of
20511308Santhony.gutierrez@amd.com    // execution is far enough that we cannot gather info about its past like
20611308Santhony.gutierrez@amd.com    // the tick it started execution. Simply return until we see an instruction
20711308Santhony.gutierrez@amd.com    // that is found in the tempStore.
20811308Santhony.gutierrez@amd.com    auto itr_exec_info = tempStore.find(dyn_inst->seqNum);
20911308Santhony.gutierrez@amd.com    if (itr_exec_info == tempStore.end()) {
21011308Santhony.gutierrez@amd.com        DPRINTFR(ElasticTrace, "recordToCommTick: [sn:%lli] Not in temp store,"
21111308Santhony.gutierrez@amd.com                    " skipping.\n", dyn_inst->seqNum);
21211308Santhony.gutierrez@amd.com        return;
21311308Santhony.gutierrez@amd.com    }
21411308Santhony.gutierrez@amd.com
21511308Santhony.gutierrez@amd.com    DPRINTFR(ElasticTrace, "[sn:%lli] To Commit Tick = %i\n", dyn_inst->seqNum,
21611308Santhony.gutierrez@amd.com                curTick());
21711308Santhony.gutierrez@amd.com    InstExecInfo* exec_info_ptr = itr_exec_info->second;
21811308Santhony.gutierrez@amd.com    exec_info_ptr->toCommitTick = curTick();
21911308Santhony.gutierrez@amd.com
22011308Santhony.gutierrez@amd.com}
22111308Santhony.gutierrez@amd.com
22211308Santhony.gutierrez@amd.comvoid
22311308Santhony.gutierrez@amd.comElasticTrace::updateRegDep(const DynInstPtr &dyn_inst)
22411308Santhony.gutierrez@amd.com{
22511435Smitch.hayenga@arm.com    // Get the sequence number of the instruction
22611308Santhony.gutierrez@amd.com    InstSeqNum seq_num = dyn_inst->seqNum;
22711308Santhony.gutierrez@amd.com
22811308Santhony.gutierrez@amd.com    assert(dyn_inst->seqNum > lastClearedSeqNum);
22911308Santhony.gutierrez@amd.com
23011308Santhony.gutierrez@amd.com    // Since this is the first probe activated in the pipeline, create
23111308Santhony.gutierrez@amd.com    // a new execution info object to track this instruction as it
23211308Santhony.gutierrez@amd.com    // progresses through the pipeline.
23311308Santhony.gutierrez@amd.com    InstExecInfo* exec_info_ptr = new InstExecInfo;
23411308Santhony.gutierrez@amd.com    tempStore[seq_num] = exec_info_ptr;
23511308Santhony.gutierrez@amd.com
23611308Santhony.gutierrez@amd.com    // Loop through the source registers and look up the dependency map. If
23711308Santhony.gutierrez@amd.com    // the source register entry is found in the dependency map, add a
23811308Santhony.gutierrez@amd.com    // dependency on the last writer.
23911308Santhony.gutierrez@amd.com    int8_t max_regs = dyn_inst->numSrcRegs();
24011308Santhony.gutierrez@amd.com    for (int src_idx = 0; src_idx < max_regs; src_idx++) {
24111308Santhony.gutierrez@amd.com        // Get the physical register index of the i'th source register.
24211308Santhony.gutierrez@amd.com        PhysRegIndex src_reg = dyn_inst->renamedSrcRegIdx(src_idx);
24311308Santhony.gutierrez@amd.com        DPRINTFR(ElasticTrace, "[sn:%lli] Check map for src reg %i\n", seq_num,
24411308Santhony.gutierrez@amd.com                    src_reg);
24511308Santhony.gutierrez@amd.com        auto itr_last_writer = physRegDepMap.find(src_reg);
24611308Santhony.gutierrez@amd.com        if (itr_last_writer != physRegDepMap.end()) {
24711308Santhony.gutierrez@amd.com            InstSeqNum last_writer = itr_last_writer->second;
24811308Santhony.gutierrez@amd.com            // Additionally the dependency distance is kept less than the window
24911308Santhony.gutierrez@amd.com            // size parameter to limit the memory allocation to nodes in the
25011308Santhony.gutierrez@amd.com            // graph. If the window were tending to infinite we would have to
25111308Santhony.gutierrez@amd.com            // load a large number of node objects during replay.
25211308Santhony.gutierrez@amd.com            if (seq_num - last_writer < depWindowSize) {
25311308Santhony.gutierrez@amd.com                // Record a physical register dependency.
25411308Santhony.gutierrez@amd.com                exec_info_ptr->physRegDepSet.insert(last_writer);
25511308Santhony.gutierrez@amd.com            }
25611308Santhony.gutierrez@amd.com        }
25711308Santhony.gutierrez@amd.com    }
25811308Santhony.gutierrez@amd.com
25911308Santhony.gutierrez@amd.com    // Loop through the destination registers of this instruction and update
26011308Santhony.gutierrez@amd.com    // the physical register dependency map for last writers to registers.
26111308Santhony.gutierrez@amd.com    max_regs = dyn_inst->numDestRegs();
26211308Santhony.gutierrez@amd.com    for (int dest_idx = 0; dest_idx < max_regs; dest_idx++) {
26311308Santhony.gutierrez@amd.com        // For data dependency tracking the register must be an int, float or
26411308Santhony.gutierrez@amd.com        // CC register and not a Misc register.
26511308Santhony.gutierrez@amd.com        RegId dest_reg = dyn_inst->destRegIdx(dest_idx);
26611308Santhony.gutierrez@amd.com        if (dest_reg.isRenameable() &&
26711308Santhony.gutierrez@amd.com            !dest_reg.isZeroReg()) {
26811308Santhony.gutierrez@amd.com            // Get the physical register index of the i'th destination
26911308Santhony.gutierrez@amd.com            // register.
27011308Santhony.gutierrez@amd.com            PhysRegIndex phys_dest_reg = dyn_inst->renamedDestRegIdx(dest_idx);
27111308Santhony.gutierrez@amd.com            DPRINTFR(ElasticTrace, "[sn:%lli] Update map for dest reg %i\n",
27211308Santhony.gutierrez@amd.com                    seq_num, dest_reg.regIdx);
27311308Santhony.gutierrez@amd.com            physRegDepMap[phys_dest_reg] = seq_num;
27411308Santhony.gutierrez@amd.com        }
27511435Smitch.hayenga@arm.com    }
27611308Santhony.gutierrez@amd.com    maxPhysRegDepMapSize = std::max(physRegDepMap.size(),
27711308Santhony.gutierrez@amd.com                                    (std::size_t)maxPhysRegDepMapSize.value());
27811308Santhony.gutierrez@amd.com}
27911308Santhony.gutierrez@amd.com
28011308Santhony.gutierrez@amd.comvoid
28111308Santhony.gutierrez@amd.comElasticTrace::removeRegDepMapEntry(const SeqNumRegPair &inst_reg_pair)
28211308Santhony.gutierrez@amd.com{
28311308Santhony.gutierrez@amd.com    DPRINTFR(ElasticTrace, "Remove Map entry for Reg %i\n",
28411308Santhony.gutierrez@amd.com                inst_reg_pair.second);
28511308Santhony.gutierrez@amd.com    auto itr_regdep_map = physRegDepMap.find(inst_reg_pair.second);
28611308Santhony.gutierrez@amd.com    if (itr_regdep_map != physRegDepMap.end())
28711308Santhony.gutierrez@amd.com        physRegDepMap.erase(itr_regdep_map);
28811308Santhony.gutierrez@amd.com}
28911308Santhony.gutierrez@amd.com
29011308Santhony.gutierrez@amd.comvoid
29111308Santhony.gutierrez@amd.comElasticTrace::addSquashedInst(const DynInstPtr &head_inst)
29211308Santhony.gutierrez@amd.com{
29311308Santhony.gutierrez@amd.com    // If the squashed instruction was squashed before being processed by
29411308Santhony.gutierrez@amd.com    // execute stage then it will not be in the temporary store. In this case
29511308Santhony.gutierrez@amd.com    // do nothing and return.
29611308Santhony.gutierrez@amd.com    auto itr_exec_info = tempStore.find(head_inst->seqNum);
29711308Santhony.gutierrez@amd.com    if (itr_exec_info == tempStore.end())
29811308Santhony.gutierrez@amd.com        return;
29911308Santhony.gutierrez@amd.com
30011308Santhony.gutierrez@amd.com    // If there is a squashed load for which a read request was
30111308Santhony.gutierrez@amd.com    // sent before it got squashed then add it to the trace.
30211308Santhony.gutierrez@amd.com    DPRINTFR(ElasticTrace, "Attempt to add squashed inst [sn:%lli]\n",
30311308Santhony.gutierrez@amd.com                head_inst->seqNum);
30411308Santhony.gutierrez@amd.com    // Get pointer to the execution info object corresponding to the inst.
30511308Santhony.gutierrez@amd.com    InstExecInfo* exec_info_ptr = itr_exec_info->second;
30611308Santhony.gutierrez@amd.com    if (head_inst->isLoad() && exec_info_ptr->executeTick != MaxTick &&
30711308Santhony.gutierrez@amd.com        exec_info_ptr->toCommitTick != MaxTick &&
30811308Santhony.gutierrez@amd.com        head_inst->hasRequest() &&
30911308Santhony.gutierrez@amd.com        head_inst->getFault() == NoFault) {
31011308Santhony.gutierrez@amd.com        // Add record to depTrace with commit parameter as false.
31111308Santhony.gutierrez@amd.com        addDepTraceRecord(head_inst, exec_info_ptr, false);
31211308Santhony.gutierrez@amd.com    }
31311308Santhony.gutierrez@amd.com    // As the information contained is no longer needed, remove the execution
31411308Santhony.gutierrez@amd.com    // info object from the temporary store.
31511308Santhony.gutierrez@amd.com    clearTempStoreUntil(head_inst);
31611308Santhony.gutierrez@amd.com}
31711308Santhony.gutierrez@amd.com
31811308Santhony.gutierrez@amd.comvoid
31911308Santhony.gutierrez@amd.comElasticTrace::addCommittedInst(const DynInstPtr &head_inst)
32011308Santhony.gutierrez@amd.com{
32111308Santhony.gutierrez@amd.com    DPRINTFR(ElasticTrace, "Attempt to add committed inst [sn:%lli]\n",
32211308Santhony.gutierrez@amd.com                head_inst->seqNum);
32311308Santhony.gutierrez@amd.com
32411308Santhony.gutierrez@amd.com    // Add the instruction to the depTrace.
32511308Santhony.gutierrez@amd.com    if (!head_inst->isNop()) {
32611308Santhony.gutierrez@amd.com
32711308Santhony.gutierrez@amd.com        // If tracing has just been enabled then the instruction at this stage
32811308Santhony.gutierrez@amd.com        // of execution is far enough that we cannot gather info about its past
32911308Santhony.gutierrez@amd.com        // like the tick it started execution. Simply return until we see an
33011308Santhony.gutierrez@amd.com        // instruction that is found in the tempStore.
33111308Santhony.gutierrez@amd.com        auto itr_temp_store = tempStore.find(head_inst->seqNum);
33211308Santhony.gutierrez@amd.com        if (itr_temp_store == tempStore.end()) {
33311308Santhony.gutierrez@amd.com            DPRINTFR(ElasticTrace, "addCommittedInst: [sn:%lli] Not in temp "
33411308Santhony.gutierrez@amd.com                "store, skipping.\n", head_inst->seqNum);
33511308Santhony.gutierrez@amd.com            return;
33611308Santhony.gutierrez@amd.com        }
33711308Santhony.gutierrez@amd.com
33811308Santhony.gutierrez@amd.com        // Get pointer to the execution info object corresponding to the inst.
33911308Santhony.gutierrez@amd.com        InstExecInfo* exec_info_ptr = itr_temp_store->second;
34011308Santhony.gutierrez@amd.com        assert(exec_info_ptr->executeTick != MaxTick);
34111308Santhony.gutierrez@amd.com        assert(exec_info_ptr->toCommitTick != MaxTick);
34211308Santhony.gutierrez@amd.com
34311308Santhony.gutierrez@amd.com        // Check if the instruction had a fault, if it predicated false and
34411308Santhony.gutierrez@amd.com        // thus previous register values were restored or if it was a
34511308Santhony.gutierrez@amd.com        // load/store that did not have a request (e.g. when the size of the
34611308Santhony.gutierrez@amd.com        // request is zero). In all these cases the instruction is set as
34711308Santhony.gutierrez@amd.com        // executed and is picked up by the commit probe listener. But a
34811308Santhony.gutierrez@amd.com        // request is not issued and registers are not written. So practically,
34911308Santhony.gutierrez@amd.com        // skipping these should not hurt as execution would not stall on them.
35011308Santhony.gutierrez@amd.com        // Alternatively, these could be included merely as a compute node in
35111308Santhony.gutierrez@amd.com        // the graph. Removing these for now. If correlation accuracy needs to
35211308Santhony.gutierrez@amd.com        // be improved in future these can be turned into comp nodes at the
35311308Santhony.gutierrez@amd.com        // cost of bigger traces.
35411308Santhony.gutierrez@amd.com        if (head_inst->getFault() != NoFault) {
35511308Santhony.gutierrez@amd.com            DPRINTF(ElasticTrace, "%s [sn:%lli] has faulted so "
35611308Santhony.gutierrez@amd.com                    "skip adding it to the trace\n",
35711308Santhony.gutierrez@amd.com                    (head_inst->isMemRef() ? "Load/store" : "Comp inst."),
35811308Santhony.gutierrez@amd.com                    head_inst->seqNum);
35911308Santhony.gutierrez@amd.com        } else if (head_inst->isMemRef() && !head_inst->hasRequest()) {
36011308Santhony.gutierrez@amd.com            DPRINTF(ElasticTrace, "Load/store [sn:%lli]  has no request so "
36111308Santhony.gutierrez@amd.com                    "skip adding it to the trace\n", head_inst->seqNum);
36211308Santhony.gutierrez@amd.com        } else if (!head_inst->readPredicate()) {
36311308Santhony.gutierrez@amd.com            DPRINTF(ElasticTrace, "%s [sn:%lli] is predicated false so "
36411308Santhony.gutierrez@amd.com                    "skip adding it to the trace\n",
36511308Santhony.gutierrez@amd.com                    (head_inst->isMemRef() ? "Load/store" : "Comp inst."),
36611308Santhony.gutierrez@amd.com                    head_inst->seqNum);
36711308Santhony.gutierrez@amd.com        } else {
36811308Santhony.gutierrez@amd.com            // Add record to depTrace with commit parameter as true.
36911308Santhony.gutierrez@amd.com            addDepTraceRecord(head_inst, exec_info_ptr, true);
37011308Santhony.gutierrez@amd.com        }
37111308Santhony.gutierrez@amd.com    }
37211308Santhony.gutierrez@amd.com    // As the information contained is no longer needed, remove the execution
37311308Santhony.gutierrez@amd.com    // info object from the temporary store.
37411308Santhony.gutierrez@amd.com    clearTempStoreUntil(head_inst);
37511308Santhony.gutierrez@amd.com}
37611308Santhony.gutierrez@amd.com
37711308Santhony.gutierrez@amd.comvoid
37811308Santhony.gutierrez@amd.comElasticTrace::addDepTraceRecord(const DynInstPtr &head_inst,
37911308Santhony.gutierrez@amd.com                                InstExecInfo* exec_info_ptr, bool commit)
38011308Santhony.gutierrez@amd.com{
38111308Santhony.gutierrez@amd.com    // Create a record to assign dynamic intruction related fields.
38211308Santhony.gutierrez@amd.com    TraceInfo* new_record = new TraceInfo;
38311308Santhony.gutierrez@amd.com    // Add to map for sequence number look up to retrieve the TraceInfo pointer
38411308Santhony.gutierrez@amd.com    traceInfoMap[head_inst->seqNum] = new_record;
38511308Santhony.gutierrez@amd.com
38611308Santhony.gutierrez@amd.com    // Assign fields from the instruction
38711308Santhony.gutierrez@amd.com    new_record->instNum = head_inst->seqNum;
38811308Santhony.gutierrez@amd.com    new_record->commit = commit;
38911308Santhony.gutierrez@amd.com    new_record->type = head_inst->isLoad() ? Record::LOAD :
39011308Santhony.gutierrez@amd.com                        (head_inst->isStore() ? Record::STORE :
39111308Santhony.gutierrez@amd.com                        Record::COMP);
39211308Santhony.gutierrez@amd.com
39311308Santhony.gutierrez@amd.com    // Assign fields for creating a request in case of a load/store
39411308Santhony.gutierrez@amd.com    new_record->reqFlags = head_inst->memReqFlags;
395    new_record->virtAddr = head_inst->effAddr;
396    new_record->asid = head_inst->asid;
397    new_record->physAddr = head_inst->physEffAddrLow;
398    // Currently the tracing does not support split requests.
399    new_record->size = head_inst->effSize;
400    new_record->pc = head_inst->instAddr();
401
402    // Assign the timing information stored in the execution info object
403    new_record->executeTick = exec_info_ptr->executeTick;
404    new_record->toCommitTick = exec_info_ptr->toCommitTick;
405    new_record->commitTick = curTick();
406
407    // Assign initial values for number of dependents and computational delay
408    new_record->numDepts = 0;
409    new_record->compDelay = -1;
410
411    // The physical register dependency set of the first instruction is
412    // empty. Since there are no records in the depTrace at this point, the
413    // case of adding an ROB dependency by using a reverse iterator is not
414    // applicable. Thus, populate the fields of the record corresponding to the
415    // first instruction and return.
416    if (depTrace.empty()) {
417        // Store the record in depTrace.
418        depTrace.push_back(new_record);
419        DPRINTF(ElasticTrace, "Added first inst record %lli to DepTrace.\n",
420                new_record->instNum);
421        return;
422    }
423
424    // Clear register dependencies for squashed loads as they may be dependent
425    // on squashed instructions and we do not add those to the trace.
426    if (head_inst->isLoad() && !commit) {
427         (exec_info_ptr->physRegDepSet).clear();
428    }
429
430    // Assign the register dependencies stored in the execution info object
431    std::set<InstSeqNum>::const_iterator dep_set_it;
432    for (dep_set_it = (exec_info_ptr->physRegDepSet).begin();
433         dep_set_it != (exec_info_ptr->physRegDepSet).end();
434         ++dep_set_it) {
435        auto trace_info_itr = traceInfoMap.find(*dep_set_it);
436        if (trace_info_itr != traceInfoMap.end()) {
437            // The register dependency is valid. Assign it and calculate
438            // computational delay
439            new_record->physRegDepList.push_back(*dep_set_it);
440            DPRINTF(ElasticTrace, "Inst %lli has register dependency on "
441                    "%lli\n", new_record->instNum, *dep_set_it);
442            TraceInfo* reg_dep = trace_info_itr->second;
443            reg_dep->numDepts++;
444            compDelayPhysRegDep(reg_dep, new_record);
445            ++numRegDep;
446        } else {
447            // The instruction that this has a register dependency on was
448            // not added to the trace because of one of the following
449            // 1. it was an instruction that had a fault
450            // 2. it was an instruction that was predicated false and
451            // previous register values were restored
452            // 3. it was load/store that did not have a request (e.g. when
453            // the size of the request is zero but this may not be a fault)
454            // In all these cases the instruction is set as executed and is
455            // picked up by the commit probe listener. But a request is not
456            // issued and registers are not written to in these cases.
457            DPRINTF(ElasticTrace, "Inst %lli has register dependency on "
458                    "%lli is skipped\n",new_record->instNum, *dep_set_it);
459        }
460    }
461
462    // Check for and assign an ROB dependency in addition to register
463    // dependency before adding the record to the trace.
464    // As stores have to commit in order a store is dependent on the last
465    // committed load/store. This is recorded in the ROB dependency.
466    if (head_inst->isStore()) {
467        // Look up store-after-store order dependency
468        updateCommitOrderDep(new_record, false);
469        // Look up store-after-load order dependency
470        updateCommitOrderDep(new_record, true);
471    }
472
473    // In case a node is dependency-free or its dependency got discarded
474    // because it was outside the window, it is marked ready in the ROB at the
475    // time of issue. A request is sent as soon as possible. To model this, a
476    // node is assigned an issue order dependency on a committed instruction
477    // that completed earlier than it. This is done to avoid the problem of
478    // determining the issue times of such dependency-free nodes during replay
479    // which could lead to too much parallelism, thinking conservatively.
480    if (new_record->robDepList.empty() && new_record->physRegDepList.empty()) {
481        updateIssueOrderDep(new_record);
482    }
483
484    // Store the record in depTrace.
485    depTrace.push_back(new_record);
486    DPRINTF(ElasticTrace, "Added %s inst %lli to DepTrace.\n",
487            (commit ? "committed" : "squashed"), new_record->instNum);
488
489    // To process the number of records specified by depWindowSize in the
490    // forward direction, the depTrace must have twice as many records
491    // to check for dependencies.
492    if (depTrace.size() == 2 * depWindowSize) {
493
494        DPRINTF(ElasticTrace, "Writing out trace...\n");
495
496        // Write out the records which have been processed to the trace
497        // and remove them from the depTrace.
498        writeDepTrace(depWindowSize);
499
500        // After the first window, writeDepTrace() must check for valid
501        // compDelay.
502        firstWin = false;
503    }
504}
505
506void
507ElasticTrace::updateCommitOrderDep(TraceInfo* new_record,
508                                    bool find_load_not_store)
509{
510    assert(new_record->isStore());
511    // Iterate in reverse direction to search for the last committed
512    // load/store that completed earlier than the new record
513    depTraceRevItr from_itr(depTrace.end());
514    depTraceRevItr until_itr(depTrace.begin());
515    TraceInfo* past_record = *from_itr;
516    uint32_t num_go_back = 0;
517
518    // The execution time of this store is when it is sent, that is committed
519    Tick execute_tick = curTick();
520    // Search for store-after-load or store-after-store order dependency
521    while (num_go_back < depWindowSize && from_itr != until_itr) {
522        if (find_load_not_store) {
523            // Check if previous inst is a load completed earlier by comparing
524            // with execute tick
525            if (hasLoadCompleted(past_record, execute_tick)) {
526                // Assign rob dependency and calculate the computational delay
527                assignRobDep(past_record, new_record);
528                ++numOrderDepStores;
529                return;
530            }
531        } else {
532            // Check if previous inst is a store sent earlier by comparing with
533            // execute tick
534            if (hasStoreCommitted(past_record, execute_tick)) {
535                // Assign rob dependency and calculate the computational delay
536                assignRobDep(past_record, new_record);
537                ++numOrderDepStores;
538                return;
539            }
540        }
541        ++from_itr;
542        past_record = *from_itr;
543        ++num_go_back;
544    }
545}
546
547void
548ElasticTrace::updateIssueOrderDep(TraceInfo* new_record)
549{
550    // Interate in reverse direction to search for the last committed
551    // record that completed earlier than the new record
552    depTraceRevItr from_itr(depTrace.end());
553    depTraceRevItr until_itr(depTrace.begin());
554    TraceInfo* past_record = *from_itr;
555
556    uint32_t num_go_back = 0;
557    Tick execute_tick = 0;
558
559    if (new_record->isLoad()) {
560        // The execution time of a load is when a request is sent
561        execute_tick = new_record->executeTick;
562        ++numIssueOrderDepLoads;
563    } else if (new_record->isStore()) {
564        // The execution time of a store is when it is sent, i.e. committed
565        execute_tick = curTick();
566        ++numIssueOrderDepStores;
567    } else {
568        // The execution time of a non load/store is when it completes
569        execute_tick = new_record->toCommitTick;
570        ++numIssueOrderDepOther;
571    }
572
573    // We search if this record has an issue order dependency on a past record.
574    // Once we find it, we update both the new record and the record it depends
575    // on and return.
576    while (num_go_back < depWindowSize && from_itr != until_itr) {
577        // Check if a previous inst is a load sent earlier, or a store sent
578        // earlier, or a comp inst completed earlier by comparing with execute
579        // tick
580        if (hasLoadBeenSent(past_record, execute_tick) ||
581            hasStoreCommitted(past_record, execute_tick) ||
582            hasCompCompleted(past_record, execute_tick)) {
583            // Assign rob dependency and calculate the computational delay
584            assignRobDep(past_record, new_record);
585            return;
586        }
587        ++from_itr;
588        past_record = *from_itr;
589        ++num_go_back;
590    }
591}
592
593void
594ElasticTrace::assignRobDep(TraceInfo* past_record, TraceInfo* new_record) {
595    DPRINTF(ElasticTrace, "%s %lli has ROB dependency on %lli\n",
596            new_record->typeToStr(), new_record->instNum,
597            past_record->instNum);
598    // Add dependency on past record
599    new_record->robDepList.push_back(past_record->instNum);
600    // Update new_record's compute delay with respect to the past record
601    compDelayRob(past_record, new_record);
602    // Increment number of dependents of the past record
603    ++(past_record->numDepts);
604    // Update stat to log max number of dependents
605    maxNumDependents = std::max(past_record->numDepts,
606                                (uint32_t)maxNumDependents.value());
607}
608
609bool
610ElasticTrace::hasStoreCommitted(TraceInfo* past_record,
611                                    Tick execute_tick) const
612{
613    return (past_record->isStore() && past_record->commitTick <= execute_tick);
614}
615
616bool
617ElasticTrace::hasLoadCompleted(TraceInfo* past_record,
618                                    Tick execute_tick) const
619{
620    return(past_record->isLoad() && past_record->commit &&
621                past_record->toCommitTick <= execute_tick);
622}
623
624bool
625ElasticTrace::hasLoadBeenSent(TraceInfo* past_record,
626                                Tick execute_tick) const
627{
628    // Check if previous inst is a load sent earlier than this
629    return (past_record->isLoad() && past_record->commit &&
630        past_record->executeTick <= execute_tick);
631}
632
633bool
634ElasticTrace::hasCompCompleted(TraceInfo* past_record,
635                                    Tick execute_tick) const
636{
637    return(past_record->isComp() && past_record->toCommitTick <= execute_tick);
638}
639
640void
641ElasticTrace::clearTempStoreUntil(const DynInstPtr head_inst)
642{
643    // Clear from temp store starting with the execution info object
644    // corresponding the head_inst and continue clearing by decrementing the
645    // sequence number until the last cleared sequence number.
646    InstSeqNum temp_sn = (head_inst->seqNum);
647    while (temp_sn > lastClearedSeqNum) {
648        auto itr_exec_info = tempStore.find(temp_sn);
649        if (itr_exec_info != tempStore.end()) {
650            InstExecInfo* exec_info_ptr = itr_exec_info->second;
651            // Free allocated memory for the info object
652            delete exec_info_ptr;
653            // Remove entry from temporary store
654            tempStore.erase(itr_exec_info);
655        }
656        temp_sn--;
657    }
658    // Update the last cleared sequence number to that of the head_inst
659    lastClearedSeqNum = head_inst->seqNum;
660}
661
662void
663ElasticTrace::compDelayRob(TraceInfo* past_record, TraceInfo* new_record)
664{
665    // The computation delay is the delay between the completion tick of the
666    // inst. pointed to by past_record and the execution tick of its dependent
667    // inst. pointed to by new_record.
668    int64_t comp_delay = -1;
669    Tick execution_tick = 0, completion_tick = 0;
670
671    DPRINTF(ElasticTrace, "Seq num %lli has ROB dependency on seq num %lli.\n",
672            new_record->instNum, past_record->instNum);
673
674    // Get the tick when the node is executed as per the modelling of
675    // computation delay
676    execution_tick = new_record->getExecuteTick();
677
678    if (past_record->isLoad()) {
679        if (new_record->isStore()) {
680            completion_tick = past_record->toCommitTick;
681        } else {
682            completion_tick = past_record->executeTick;
683        }
684    } else if (past_record->isStore()) {
685        completion_tick = past_record->commitTick;
686    } else if (past_record->isComp()){
687        completion_tick = past_record->toCommitTick;
688    }
689    assert(execution_tick >= completion_tick);
690    comp_delay = execution_tick - completion_tick;
691
692    DPRINTF(ElasticTrace, "Computational delay is %lli - %lli = %lli\n",
693            execution_tick, completion_tick, comp_delay);
694
695    // Assign the computational delay with respect to the dependency which
696    // completes the latest.
697    if (new_record->compDelay == -1)
698        new_record->compDelay = comp_delay;
699    else
700        new_record->compDelay = std::min(comp_delay, new_record->compDelay);
701    DPRINTF(ElasticTrace, "Final computational delay = %lli.\n",
702            new_record->compDelay);
703}
704
705void
706ElasticTrace::compDelayPhysRegDep(TraceInfo* past_record,
707                                    TraceInfo* new_record)
708{
709    // The computation delay is the delay between the completion tick of the
710    // inst. pointed to by past_record and the execution tick of its dependent
711    // inst. pointed to by new_record.
712    int64_t comp_delay = -1;
713    Tick execution_tick = 0, completion_tick = 0;
714
715    DPRINTF(ElasticTrace, "Seq. num %lli has register dependency on seq. num"
716            " %lli.\n", new_record->instNum, past_record->instNum);
717
718    // Get the tick when the node is executed as per the modelling of
719    // computation delay
720    execution_tick = new_record->getExecuteTick();
721
722    // When there is a physical register dependency on an instruction, the
723    // completion tick of that instruction is when it wrote to the register,
724    // that is toCommitTick. In case, of a store updating a destination
725    // register, this is approximated to commitTick instead
726    if (past_record->isStore()) {
727        completion_tick = past_record->commitTick;
728    } else {
729        completion_tick = past_record->toCommitTick;
730    }
731    assert(execution_tick >= completion_tick);
732    comp_delay = execution_tick - completion_tick;
733    DPRINTF(ElasticTrace, "Computational delay is %lli - %lli = %lli\n",
734            execution_tick, completion_tick, comp_delay);
735
736    // Assign the computational delay with respect to the dependency which
737    // completes the latest.
738    if (new_record->compDelay == -1)
739        new_record->compDelay = comp_delay;
740    else
741        new_record->compDelay = std::min(comp_delay, new_record->compDelay);
742    DPRINTF(ElasticTrace, "Final computational delay = %lli.\n",
743            new_record->compDelay);
744}
745
746Tick
747ElasticTrace::TraceInfo::getExecuteTick() const
748{
749    if (isLoad()) {
750        // Execution tick for a load instruction is when the request was sent,
751        // that is executeTick.
752        return executeTick;
753    } else if (isStore()) {
754        // Execution tick for a store instruction is when the request was sent,
755        // that is commitTick.
756        return commitTick;
757    } else {
758        // Execution tick for a non load/store instruction is when the register
759        // value was written to, that is commitTick.
760        return toCommitTick;
761    }
762}
763
764void
765ElasticTrace::writeDepTrace(uint32_t num_to_write)
766{
767    // Write the trace with fields as follows:
768    // Instruction sequence number
769    // If instruction was a load
770    // If instruction was a store
771    // If instruction has addr
772    // If instruction has size
773    // If instruction has flags
774    // List of order dependencies - optional, repeated
775    // Computational delay with respect to last completed dependency
776    // List of physical register RAW dependencies - optional, repeated
777    // Weight of a node equal to no. of filtered nodes before it - optional
778    uint16_t num_filtered_nodes = 0;
779    depTraceItr dep_trace_itr(depTrace.begin());
780    depTraceItr dep_trace_itr_start = dep_trace_itr;
781    while (num_to_write > 0) {
782        TraceInfo* temp_ptr = *dep_trace_itr;
783        assert(temp_ptr->type != Record::INVALID);
784        // If no node dependends on a comp node then there is no reason to
785        // track the comp node in the dependency graph. We filter out such
786        // nodes but count them and add a weight field to the subsequent node
787        // that we do include in the trace.
788        if (!temp_ptr->isComp() || temp_ptr->numDepts != 0) {
789            DPRINTFR(ElasticTrace, "Instruction with seq. num %lli "
790                     "is as follows:\n", temp_ptr->instNum);
791            if (temp_ptr->isLoad() || temp_ptr->isStore()) {
792                DPRINTFR(ElasticTrace, "\tis a %s\n", temp_ptr->typeToStr());
793                DPRINTFR(ElasticTrace, "\thas a request with phys addr %i, "
794                         "size %i, flags %i\n", temp_ptr->physAddr,
795                         temp_ptr->size, temp_ptr->reqFlags);
796            } else {
797                 DPRINTFR(ElasticTrace, "\tis a %s\n", temp_ptr->typeToStr());
798            }
799            if (firstWin && temp_ptr->compDelay == -1) {
800                if (temp_ptr->isLoad()) {
801                    temp_ptr->compDelay = temp_ptr->executeTick;
802                } else if (temp_ptr->isStore()) {
803                    temp_ptr->compDelay = temp_ptr->commitTick;
804                } else {
805                    temp_ptr->compDelay = temp_ptr->toCommitTick;
806                }
807            }
808            assert(temp_ptr->compDelay != -1);
809            DPRINTFR(ElasticTrace, "\thas computational delay %lli\n",
810                     temp_ptr->compDelay);
811
812            // Create a protobuf message for the dependency record
813            ProtoMessage::InstDepRecord dep_pkt;
814            dep_pkt.set_seq_num(temp_ptr->instNum);
815            dep_pkt.set_type(temp_ptr->type);
816            dep_pkt.set_pc(temp_ptr->pc);
817            if (temp_ptr->isLoad() || temp_ptr->isStore()) {
818                dep_pkt.set_flags(temp_ptr->reqFlags);
819                dep_pkt.set_p_addr(temp_ptr->physAddr);
820                // If tracing of virtual addresses is enabled, set the optional
821                // field for it
822                if (traceVirtAddr) {
823                    dep_pkt.set_v_addr(temp_ptr->virtAddr);
824                    dep_pkt.set_asid(temp_ptr->asid);
825                }
826                dep_pkt.set_size(temp_ptr->size);
827            }
828            dep_pkt.set_comp_delay(temp_ptr->compDelay);
829            if (temp_ptr->robDepList.empty()) {
830                DPRINTFR(ElasticTrace, "\thas no order (rob) dependencies\n");
831            }
832            while (!temp_ptr->robDepList.empty()) {
833                DPRINTFR(ElasticTrace, "\thas order (rob) dependency on %lli\n",
834                         temp_ptr->robDepList.front());
835                dep_pkt.add_rob_dep(temp_ptr->robDepList.front());
836                temp_ptr->robDepList.pop_front();
837            }
838            if (temp_ptr->physRegDepList.empty()) {
839                DPRINTFR(ElasticTrace, "\thas no register dependencies\n");
840            }
841            while (!temp_ptr->physRegDepList.empty()) {
842                DPRINTFR(ElasticTrace, "\thas register dependency on %lli\n",
843                         temp_ptr->physRegDepList.front());
844                dep_pkt.add_reg_dep(temp_ptr->physRegDepList.front());
845                temp_ptr->physRegDepList.pop_front();
846            }
847            if (num_filtered_nodes != 0) {
848                // Set the weight of this node as the no. of filtered nodes
849                // between this node and the last node that we wrote to output
850                // stream. The weight will be used during replay to model ROB
851                // occupancy of filtered nodes.
852                dep_pkt.set_weight(num_filtered_nodes);
853                num_filtered_nodes = 0;
854            }
855            // Write the message to the protobuf output stream
856            dataTraceStream->write(dep_pkt);
857        } else {
858            // Don't write the node to the trace but note that we have filtered
859            // out a node.
860            ++numFilteredNodes;
861            ++num_filtered_nodes;
862        }
863        dep_trace_itr++;
864        traceInfoMap.erase(temp_ptr->instNum);
865        delete temp_ptr;
866        num_to_write--;
867    }
868    depTrace.erase(dep_trace_itr_start, dep_trace_itr);
869}
870
871void
872ElasticTrace::regStats() {
873    ProbeListenerObject::regStats();
874
875    using namespace Stats;
876    numRegDep
877        .name(name() + ".numRegDep")
878        .desc("Number of register dependencies recorded during tracing")
879        ;
880
881    numOrderDepStores
882        .name(name() + ".numOrderDepStores")
883        .desc("Number of commit order (rob) dependencies for a store recorded"
884              " on a past load/store during tracing")
885        ;
886
887    numIssueOrderDepLoads
888        .name(name() + ".numIssueOrderDepLoads")
889        .desc("Number of loads that got assigned issue order dependency"
890              " because they were dependency-free")
891        ;
892
893    numIssueOrderDepStores
894        .name(name() + ".numIssueOrderDepStores")
895        .desc("Number of stores that got assigned issue order dependency"
896              " because they were dependency-free")
897        ;
898
899    numIssueOrderDepOther
900        .name(name() + ".numIssueOrderDepOther")
901        .desc("Number of non load/store insts that got assigned issue order"
902              " dependency because they were dependency-free")
903        ;
904
905    numFilteredNodes
906        .name(name() + ".numFilteredNodes")
907        .desc("No. of nodes filtered out before writing the output trace")
908        ;
909
910    maxNumDependents
911        .name(name() + ".maxNumDependents")
912        .desc("Maximum number or dependents on any instruction")
913        ;
914
915    maxTempStoreSize
916        .name(name() + ".maxTempStoreSize")
917        .desc("Maximum size of the temporary store during the run")
918        ;
919
920    maxPhysRegDepMapSize
921        .name(name() + ".maxPhysRegDepMapSize")
922        .desc("Maximum size of register dependency map")
923        ;
924}
925
926const std::string&
927ElasticTrace::TraceInfo::typeToStr() const
928{
929    return Record::RecordType_Name(type);
930}
931
932const std::string
933ElasticTrace::name() const
934{
935    return ProbeListenerObject::name();
936}
937
938void
939ElasticTrace::flushTraces()
940{
941    // Write to trace all records in the depTrace.
942    writeDepTrace(depTrace.size());
943    // Delete the stream objects
944    delete dataTraceStream;
945    delete instTraceStream;
946}
947
948ElasticTrace*
949ElasticTraceParams::create()
950{
951    return new ElasticTrace(this);
952}
953