elastic_trace.cc revision 12255
110259SAndrew.Bardsley@arm.com/*
210259SAndrew.Bardsley@arm.com * Copyright (c) 2013 - 2015 ARM Limited
310259SAndrew.Bardsley@arm.com * All rights reserved
410259SAndrew.Bardsley@arm.com *
510259SAndrew.Bardsley@arm.com * The license below extends only to copyright in the software and shall
610259SAndrew.Bardsley@arm.com * not be construed as granting a license to any other intellectual
710259SAndrew.Bardsley@arm.com * property including but not limited to intellectual property relating
810259SAndrew.Bardsley@arm.com * to a hardware implementation of the functionality of the software
910259SAndrew.Bardsley@arm.com * licensed hereunder.  You may use the software subject to the license
1010259SAndrew.Bardsley@arm.com * terms below provided that you ensure that this notice is replicated
1110259SAndrew.Bardsley@arm.com * unmodified and in its entirety in all distributions of the software,
1210259SAndrew.Bardsley@arm.com * modified or unmodified, in source code or in binary form.
1310259SAndrew.Bardsley@arm.com *
1410259SAndrew.Bardsley@arm.com * Redistribution and use in source and binary forms, with or without
1510259SAndrew.Bardsley@arm.com * modification, are permitted provided that the following conditions are
1610259SAndrew.Bardsley@arm.com * met: redistributions of source code must retain the above copyright
1710259SAndrew.Bardsley@arm.com * notice, this list of conditions and the following disclaimer;
1810259SAndrew.Bardsley@arm.com * redistributions in binary form must reproduce the above copyright
1910259SAndrew.Bardsley@arm.com * notice, this list of conditions and the following disclaimer in the
2010259SAndrew.Bardsley@arm.com * documentation and/or other materials provided with the distribution;
2110259SAndrew.Bardsley@arm.com * neither the name of the copyright holders nor the names of its
2210259SAndrew.Bardsley@arm.com * contributors may be used to endorse or promote products derived from
2310259SAndrew.Bardsley@arm.com * this software without specific prior written permission.
2410259SAndrew.Bardsley@arm.com *
2510259SAndrew.Bardsley@arm.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2610259SAndrew.Bardsley@arm.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2710259SAndrew.Bardsley@arm.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2810259SAndrew.Bardsley@arm.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2910259SAndrew.Bardsley@arm.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
3010259SAndrew.Bardsley@arm.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3110259SAndrew.Bardsley@arm.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3210259SAndrew.Bardsley@arm.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3310259SAndrew.Bardsley@arm.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3410259SAndrew.Bardsley@arm.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3510259SAndrew.Bardsley@arm.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3610259SAndrew.Bardsley@arm.com *
3710259SAndrew.Bardsley@arm.com * Authors: Radhika Jagtap
3810259SAndrew.Bardsley@arm.com *          Andreas Hansson
3910259SAndrew.Bardsley@arm.com *          Thomas Grass
4010259SAndrew.Bardsley@arm.com */
4110259SAndrew.Bardsley@arm.com
4210259SAndrew.Bardsley@arm.com#include "cpu/o3/probe/elastic_trace.hh"
4310259SAndrew.Bardsley@arm.com
4410259SAndrew.Bardsley@arm.com#include "base/callback.hh"
4510259SAndrew.Bardsley@arm.com#include "base/output.hh"
4610259SAndrew.Bardsley@arm.com#include "base/trace.hh"
4710259SAndrew.Bardsley@arm.com#include "cpu/reg_class.hh"
4810259SAndrew.Bardsley@arm.com#include "debug/ElasticTrace.hh"
4910259SAndrew.Bardsley@arm.com#include "mem/packet.hh"
5010259SAndrew.Bardsley@arm.com
5110259SAndrew.Bardsley@arm.comElasticTrace::ElasticTrace(const ElasticTraceParams* params)
5210259SAndrew.Bardsley@arm.com    :  ProbeListenerObject(params),
5310259SAndrew.Bardsley@arm.com       regEtraceListenersEvent([this]{ regEtraceListeners(); }, name()),
5410259SAndrew.Bardsley@arm.com       firstWin(true),
5510259SAndrew.Bardsley@arm.com       lastClearedSeqNum(0),
5610319SAndreas.Sandberg@ARM.com       depWindowSize(params->depWindowSize),
5710259SAndrew.Bardsley@arm.com       dataTraceStream(nullptr),
5810259SAndrew.Bardsley@arm.com       instTraceStream(nullptr),
5910259SAndrew.Bardsley@arm.com       startTraceInst(params->startTraceInst),
6010259SAndrew.Bardsley@arm.com       allProbesReg(false),
6111608Snikos.nikoleris@arm.com       traceVirtAddr(params->traceVirtAddr)
6210259SAndrew.Bardsley@arm.com{
6310259SAndrew.Bardsley@arm.com    cpu = dynamic_cast<FullO3CPU<O3CPUImpl>*>(params->manager);
6410259SAndrew.Bardsley@arm.com    fatal_if(!cpu, "Manager of %s is not of type O3CPU and thus does not "\
6510259SAndrew.Bardsley@arm.com                "support dependency tracing.\n", name());
6610259SAndrew.Bardsley@arm.com
6710259SAndrew.Bardsley@arm.com    fatal_if(depWindowSize == 0, "depWindowSize parameter must be non-zero. "\
6810259SAndrew.Bardsley@arm.com                "Recommended size is 3x ROB size in the O3CPU.\n");
6910259SAndrew.Bardsley@arm.com
7010259SAndrew.Bardsley@arm.com    fatal_if(cpu->numThreads > 1, "numThreads = %i, %s supports tracing for"\
7110259SAndrew.Bardsley@arm.com                "single-threaded workload only", cpu->numThreads, name());
7210259SAndrew.Bardsley@arm.com    // Initialize the protobuf output stream
7310259SAndrew.Bardsley@arm.com    fatal_if(params->instFetchTraceFile == "", "Assign instruction fetch "\
7410319SAndreas.Sandberg@ARM.com                "trace file path to instFetchTraceFile");
7510259SAndrew.Bardsley@arm.com    fatal_if(params->dataDepTraceFile == "", "Assign data dependency "\
7610259SAndrew.Bardsley@arm.com                "trace file path to dataDepTraceFile");
7710259SAndrew.Bardsley@arm.com    std::string filename = simout.resolve(name() + "." +
7810259SAndrew.Bardsley@arm.com                                            params->instFetchTraceFile);
7910259SAndrew.Bardsley@arm.com    instTraceStream = new ProtoOutputStream(filename);
8010259SAndrew.Bardsley@arm.com    filename = simout.resolve(name() + "." + params->dataDepTraceFile);
8110259SAndrew.Bardsley@arm.com    dataTraceStream = new ProtoOutputStream(filename);
8210259SAndrew.Bardsley@arm.com    // Create a protobuf message for the header and write it to the stream
8310259SAndrew.Bardsley@arm.com    ProtoMessage::PacketHeader inst_pkt_header;
8410259SAndrew.Bardsley@arm.com    inst_pkt_header.set_obj_id(name());
8510259SAndrew.Bardsley@arm.com    inst_pkt_header.set_tick_freq(SimClock::Frequency);
8610259SAndrew.Bardsley@arm.com    instTraceStream->write(inst_pkt_header);
8710259SAndrew.Bardsley@arm.com    // Create a protobuf message for the header and write it to
8810259SAndrew.Bardsley@arm.com    // the stream
8910259SAndrew.Bardsley@arm.com    ProtoMessage::InstDepRecordHeader data_rec_header;
9010259SAndrew.Bardsley@arm.com    data_rec_header.set_obj_id(name());
9110259SAndrew.Bardsley@arm.com    data_rec_header.set_tick_freq(SimClock::Frequency);
9210259SAndrew.Bardsley@arm.com    data_rec_header.set_window_size(depWindowSize);
9310259SAndrew.Bardsley@arm.com    dataTraceStream->write(data_rec_header);
9410259SAndrew.Bardsley@arm.com    // Register a callback to flush trace records and close the output streams.
9510259SAndrew.Bardsley@arm.com    Callback* cb = new MakeCallback<ElasticTrace,
9610259SAndrew.Bardsley@arm.com        &ElasticTrace::flushTraces>(this);
9710259SAndrew.Bardsley@arm.com    registerExitCallback(cb);
9810259SAndrew.Bardsley@arm.com}
9910259SAndrew.Bardsley@arm.com
10010259SAndrew.Bardsley@arm.comvoid
10110259SAndrew.Bardsley@arm.comElasticTrace::regProbeListeners()
10210259SAndrew.Bardsley@arm.com{
10310259SAndrew.Bardsley@arm.com    inform("@%llu: regProbeListeners() called, startTraceInst = %llu",
10410259SAndrew.Bardsley@arm.com        curTick(), startTraceInst);
10510259SAndrew.Bardsley@arm.com    if (startTraceInst == 0) {
10610259SAndrew.Bardsley@arm.com        // If we want to start tracing from the start of the simulation,
10711612Sandreas.sandberg@arm.com        // register all elastic trace probes now.
10811612Sandreas.sandberg@arm.com        regEtraceListeners();
10910259SAndrew.Bardsley@arm.com    } else {
11011303Ssteve.reinhardt@amd.com        // Schedule an event to register all elastic trace probes when
11110259SAndrew.Bardsley@arm.com        // specified no. of instructions are committed.
11210259SAndrew.Bardsley@arm.com        cpu->comInstEventQueue[(ThreadID)0]->schedule(&regEtraceListenersEvent,
11310259SAndrew.Bardsley@arm.com                                                      startTraceInst);
11410259SAndrew.Bardsley@arm.com    }
11510259SAndrew.Bardsley@arm.com}
11610259SAndrew.Bardsley@arm.com
11711611SReiley.Jeyapaul@arm.comvoid
11810259SAndrew.Bardsley@arm.comElasticTrace::regEtraceListeners()
11910259SAndrew.Bardsley@arm.com{
12010259SAndrew.Bardsley@arm.com    assert(!allProbesReg);
12110259SAndrew.Bardsley@arm.com    inform("@%llu: No. of instructions committed = %llu, registering elastic"
12210259SAndrew.Bardsley@arm.com        " probe listeners", curTick(), cpu->numSimulatedInsts());
12310259SAndrew.Bardsley@arm.com    // Create new listeners: provide method to be called upon a notify() for
12410319SAndreas.Sandberg@ARM.com    // each probe point.
12511611SReiley.Jeyapaul@arm.com    listeners.push_back(new ProbeListenerArg<ElasticTrace, RequestPtr>(this,
12610259SAndrew.Bardsley@arm.com                        "FetchRequest", &ElasticTrace::fetchReqTrace));
12712104Snathanael.premillieu@arm.com    listeners.push_back(new ProbeListenerArg<ElasticTrace, DynInstPtr>(this,
12812104Snathanael.premillieu@arm.com                        "Execute", &ElasticTrace::recordExecTick));
12912104Snathanael.premillieu@arm.com    listeners.push_back(new ProbeListenerArg<ElasticTrace, DynInstPtr>(this,
13010259SAndrew.Bardsley@arm.com                        "ToCommit", &ElasticTrace::recordToCommTick));
13110259SAndrew.Bardsley@arm.com    listeners.push_back(new ProbeListenerArg<ElasticTrace, DynInstPtr>(this,
13210259SAndrew.Bardsley@arm.com                        "Rename", &ElasticTrace::updateRegDep));
13311611SReiley.Jeyapaul@arm.com    listeners.push_back(new ProbeListenerArg<ElasticTrace, SeqNumRegPair>(this,
13410259SAndrew.Bardsley@arm.com                        "SquashInRename", &ElasticTrace::removeRegDepMapEntry));
13512104Snathanael.premillieu@arm.com    listeners.push_back(new ProbeListenerArg<ElasticTrace, DynInstPtr>(this,
13612104Snathanael.premillieu@arm.com                        "Squash", &ElasticTrace::addSquashedInst));
13712104Snathanael.premillieu@arm.com    listeners.push_back(new ProbeListenerArg<ElasticTrace, DynInstPtr>(this,
13810259SAndrew.Bardsley@arm.com                        "Commit", &ElasticTrace::addCommittedInst));
13910259SAndrew.Bardsley@arm.com    allProbesReg = true;
14010259SAndrew.Bardsley@arm.com}
14111611SReiley.Jeyapaul@arm.com
14210259SAndrew.Bardsley@arm.comvoid
14312104Snathanael.premillieu@arm.comElasticTrace::fetchReqTrace(const RequestPtr &req)
14412104Snathanael.premillieu@arm.com{
14512104Snathanael.premillieu@arm.com
14610259SAndrew.Bardsley@arm.com    DPRINTFR(ElasticTrace, "Fetch Req %i,(%lli,%lli,%lli),%i,%i,%lli\n",
14710259SAndrew.Bardsley@arm.com             (MemCmd::ReadReq),
14810259SAndrew.Bardsley@arm.com             req->getPC(), req->getVaddr(), req->getPaddr(),
14911611SReiley.Jeyapaul@arm.com             req->getFlags(), req->getSize(), curTick());
15010259SAndrew.Bardsley@arm.com
15112104Snathanael.premillieu@arm.com    // Create a protobuf message including the request fields necessary to
15212104Snathanael.premillieu@arm.com    // recreate the request in the TraceCPU.
15312104Snathanael.premillieu@arm.com    ProtoMessage::Packet inst_fetch_pkt;
15410259SAndrew.Bardsley@arm.com    inst_fetch_pkt.set_tick(curTick());
15510259SAndrew.Bardsley@arm.com    inst_fetch_pkt.set_cmd(MemCmd::ReadReq);
15610259SAndrew.Bardsley@arm.com    inst_fetch_pkt.set_pc(req->getPC());
15710259SAndrew.Bardsley@arm.com    inst_fetch_pkt.set_flags(req->getFlags());
15811611SReiley.Jeyapaul@arm.com    inst_fetch_pkt.set_addr(req->getPaddr());
15910259SAndrew.Bardsley@arm.com    inst_fetch_pkt.set_size(req->getSize());
16012104Snathanael.premillieu@arm.com    // Write the message to the stream.
16112104Snathanael.premillieu@arm.com    instTraceStream->write(inst_fetch_pkt);
16212104Snathanael.premillieu@arm.com}
16310259SAndrew.Bardsley@arm.com
16410259SAndrew.Bardsley@arm.comvoid
16510259SAndrew.Bardsley@arm.comElasticTrace::recordExecTick(const DynInstPtr &dyn_inst)
16610259SAndrew.Bardsley@arm.com{
16711611SReiley.Jeyapaul@arm.com
16810259SAndrew.Bardsley@arm.com    // In a corner case, a retired instruction is propagated backward to the
16912104Snathanael.premillieu@arm.com    // IEW instruction queue to handle some side-channel information. But we
17012104Snathanael.premillieu@arm.com    // must not process an instruction again. So we test the sequence number
17112104Snathanael.premillieu@arm.com    // against the lastClearedSeqNum and skip adding the instruction for such
17210259SAndrew.Bardsley@arm.com    // corner cases.
17310259SAndrew.Bardsley@arm.com    if (dyn_inst->seqNum <= lastClearedSeqNum) {
17410259SAndrew.Bardsley@arm.com        DPRINTFR(ElasticTrace, "[sn:%lli] Ignoring in execute as instruction \
17511611SReiley.Jeyapaul@arm.com        has already retired (mostly squashed)", dyn_inst->seqNum);
17610259SAndrew.Bardsley@arm.com        // Do nothing as program has proceeded and this inst has been
17710259SAndrew.Bardsley@arm.com        // propagated backwards to handle something.
17810259SAndrew.Bardsley@arm.com        return;
17910259SAndrew.Bardsley@arm.com    }
18010259SAndrew.Bardsley@arm.com
18111611SReiley.Jeyapaul@arm.com    DPRINTFR(ElasticTrace, "[sn:%lli] Execute Tick = %i\n", dyn_inst->seqNum,
18210259SAndrew.Bardsley@arm.com                curTick());
18310259SAndrew.Bardsley@arm.com    // Either the execution info object will already exist if this
18410259SAndrew.Bardsley@arm.com    // instruction had a register dependency recorded in the rename probe
18510259SAndrew.Bardsley@arm.com    // listener before entering execute stage or it will not exist and will
18610259SAndrew.Bardsley@arm.com    // need to be created here.
18711611SReiley.Jeyapaul@arm.com    InstExecInfo* exec_info_ptr;
18810259SAndrew.Bardsley@arm.com    auto itr_exec_info = tempStore.find(dyn_inst->seqNum);
18910259SAndrew.Bardsley@arm.com    if (itr_exec_info != tempStore.end()) {
19010259SAndrew.Bardsley@arm.com        exec_info_ptr = itr_exec_info->second;
19110259SAndrew.Bardsley@arm.com    } else {
19210259SAndrew.Bardsley@arm.com        exec_info_ptr = new InstExecInfo;
19311611SReiley.Jeyapaul@arm.com        tempStore[dyn_inst->seqNum] = exec_info_ptr;
19410259SAndrew.Bardsley@arm.com    }
19510259SAndrew.Bardsley@arm.com
19610259SAndrew.Bardsley@arm.com    exec_info_ptr->executeTick = curTick();
19710259SAndrew.Bardsley@arm.com    maxTempStoreSize = std::max(tempStore.size(),
19810259SAndrew.Bardsley@arm.com                                (std::size_t)maxTempStoreSize.value());
19910698Sandreas.hansson@arm.com}
20010259SAndrew.Bardsley@arm.com
20110259SAndrew.Bardsley@arm.comvoid
20210259SAndrew.Bardsley@arm.comElasticTrace::recordToCommTick(const DynInstPtr &dyn_inst)
20310259SAndrew.Bardsley@arm.com{
20410259SAndrew.Bardsley@arm.com    // If tracing has just been enabled then the instruction at this stage of
20511611SReiley.Jeyapaul@arm.com    // execution is far enough that we cannot gather info about its past like
20610259SAndrew.Bardsley@arm.com    // the tick it started execution. Simply return until we see an instruction
20710259SAndrew.Bardsley@arm.com    // that is found in the tempStore.
20810259SAndrew.Bardsley@arm.com    auto itr_exec_info = tempStore.find(dyn_inst->seqNum);
20910259SAndrew.Bardsley@arm.com    if (itr_exec_info == tempStore.end()) {
21010259SAndrew.Bardsley@arm.com        DPRINTFR(ElasticTrace, "recordToCommTick: [sn:%lli] Not in temp store,"
21111611SReiley.Jeyapaul@arm.com                    " skipping.\n", dyn_inst->seqNum);
21210259SAndrew.Bardsley@arm.com        return;
21310259SAndrew.Bardsley@arm.com    }
21410259SAndrew.Bardsley@arm.com
21510259SAndrew.Bardsley@arm.com    DPRINTFR(ElasticTrace, "[sn:%lli] To Commit Tick = %i\n", dyn_inst->seqNum,
21610259SAndrew.Bardsley@arm.com                curTick());
21711611SReiley.Jeyapaul@arm.com    InstExecInfo* exec_info_ptr = itr_exec_info->second;
21810259SAndrew.Bardsley@arm.com    exec_info_ptr->toCommitTick = curTick();
21912104Snathanael.premillieu@arm.com
22012104Snathanael.premillieu@arm.com}
22112104Snathanael.premillieu@arm.com
22210259SAndrew.Bardsley@arm.comvoid
22310259SAndrew.Bardsley@arm.comElasticTrace::updateRegDep(const DynInstPtr &dyn_inst)
22410259SAndrew.Bardsley@arm.com{
22510259SAndrew.Bardsley@arm.com    // Get the sequence number of the instruction
22611611SReiley.Jeyapaul@arm.com    InstSeqNum seq_num = dyn_inst->seqNum;
22710259SAndrew.Bardsley@arm.com
22812104Snathanael.premillieu@arm.com    assert(dyn_inst->seqNum > lastClearedSeqNum);
22912104Snathanael.premillieu@arm.com
23012104Snathanael.premillieu@arm.com    // Since this is the first probe activated in the pipeline, create
23110259SAndrew.Bardsley@arm.com    // a new execution info object to track this instruction as it
23210259SAndrew.Bardsley@arm.com    // progresses through the pipeline.
23310259SAndrew.Bardsley@arm.com    InstExecInfo* exec_info_ptr = new InstExecInfo;
23411611SReiley.Jeyapaul@arm.com    tempStore[seq_num] = exec_info_ptr;
23510259SAndrew.Bardsley@arm.com
23610259SAndrew.Bardsley@arm.com    // Loop through the source registers and look up the dependency map. If
23710259SAndrew.Bardsley@arm.com    // the source register entry is found in the dependency map, add a
23810259SAndrew.Bardsley@arm.com    // dependency on the last writer.
23910259SAndrew.Bardsley@arm.com    int8_t max_regs = dyn_inst->numSrcRegs();
24010259SAndrew.Bardsley@arm.com    for (int src_idx = 0; src_idx < max_regs; src_idx++) {
24110259SAndrew.Bardsley@arm.com
24210259SAndrew.Bardsley@arm.com        const RegId& src_reg = dyn_inst->srcRegIdx(src_idx);
24310259SAndrew.Bardsley@arm.com        if (!src_reg.isMiscReg() &&
24411611SReiley.Jeyapaul@arm.com            !src_reg.isZeroReg()) {
24510259SAndrew.Bardsley@arm.com            // Get the physical register index of the i'th source register.
24610259SAndrew.Bardsley@arm.com            PhysRegIdPtr phys_src_reg = dyn_inst->renamedSrcRegIdx(src_idx);
24710259SAndrew.Bardsley@arm.com            DPRINTFR(ElasticTrace, "[sn:%lli] Check map for src reg"
24810259SAndrew.Bardsley@arm.com                     " %i (%s)\n", seq_num,
24910259SAndrew.Bardsley@arm.com                     phys_src_reg->flatIndex(), phys_src_reg->className());
25010259SAndrew.Bardsley@arm.com            auto itr_writer = physRegDepMap.find(phys_src_reg->flatIndex());
25110259SAndrew.Bardsley@arm.com            if (itr_writer != physRegDepMap.end()) {
25210259SAndrew.Bardsley@arm.com                InstSeqNum last_writer = itr_writer->second;
25310259SAndrew.Bardsley@arm.com                // Additionally the dependency distance is kept less than the
25411877Sbrandon.potter@amd.com                // window size parameter to limit the memory allocation to
25511611SReiley.Jeyapaul@arm.com                // nodes in the graph. If the window were tending to infinite
25610259SAndrew.Bardsley@arm.com                // we would have to load a large number of node objects during
25710259SAndrew.Bardsley@arm.com                // replay.
25810259SAndrew.Bardsley@arm.com                if (seq_num - last_writer < depWindowSize) {
25911877Sbrandon.potter@amd.com                    // Record a physical register dependency.
26010259SAndrew.Bardsley@arm.com                    exec_info_ptr->physRegDepSet.insert(last_writer);
26110259SAndrew.Bardsley@arm.com                }
26211611SReiley.Jeyapaul@arm.com            }
26310259SAndrew.Bardsley@arm.com
26410259SAndrew.Bardsley@arm.com        }
26511611SReiley.Jeyapaul@arm.com
26611611SReiley.Jeyapaul@arm.com    }
26710259SAndrew.Bardsley@arm.com
26811005Sandreas.sandberg@arm.com    // Loop through the destination registers of this instruction and update
26910259SAndrew.Bardsley@arm.com    // the physical register dependency map for last writers to registers.
27010259SAndrew.Bardsley@arm.com    max_regs = dyn_inst->numDestRegs();
27110259SAndrew.Bardsley@arm.com    for (int dest_idx = 0; dest_idx < max_regs; dest_idx++) {
27210259SAndrew.Bardsley@arm.com        // For data dependency tracking the register must be an int, float or
27311611SReiley.Jeyapaul@arm.com        // CC register and not a Misc register.
27410259SAndrew.Bardsley@arm.com        const RegId& dest_reg = dyn_inst->destRegIdx(dest_idx);
27510259SAndrew.Bardsley@arm.com        if (!dest_reg.isMiscReg() &&
27610259SAndrew.Bardsley@arm.com            !dest_reg.isZeroReg()) {
27710259SAndrew.Bardsley@arm.com            // Get the physical register index of the i'th destination
27810259SAndrew.Bardsley@arm.com            // register.
27910935Snilay@cs.wisc.edu            PhysRegIdPtr phys_dest_reg = dyn_inst->renamedDestRegIdx(dest_idx);
28011611SReiley.Jeyapaul@arm.com            DPRINTFR(ElasticTrace, "[sn:%lli] Update map for dest reg"
28110935Snilay@cs.wisc.edu                     " %i (%s)\n", seq_num, phys_dest_reg->flatIndex(),
28212104Snathanael.premillieu@arm.com                     dest_reg.className());
28312104Snathanael.premillieu@arm.com            physRegDepMap[phys_dest_reg->flatIndex()] = seq_num;
28412104Snathanael.premillieu@arm.com        }
28510935Snilay@cs.wisc.edu    }
28610935Snilay@cs.wisc.edu    maxPhysRegDepMapSize = std::max(physRegDepMap.size(),
28710935Snilay@cs.wisc.edu                                    (std::size_t)maxPhysRegDepMapSize.value());
28811611SReiley.Jeyapaul@arm.com}
28910935Snilay@cs.wisc.edu
29012104Snathanael.premillieu@arm.comvoid
29112104Snathanael.premillieu@arm.comElasticTrace::removeRegDepMapEntry(const SeqNumRegPair &inst_reg_pair)
29212104Snathanael.premillieu@arm.com{
29310935Snilay@cs.wisc.edu    DPRINTFR(ElasticTrace, "Remove Map entry for Reg %i\n",
29410935Snilay@cs.wisc.edu            inst_reg_pair.second);
29510259SAndrew.Bardsley@arm.com    auto itr_regdep_map = physRegDepMap.find(inst_reg_pair.second);
29610259SAndrew.Bardsley@arm.com    if (itr_regdep_map != physRegDepMap.end())
29710259SAndrew.Bardsley@arm.com        physRegDepMap.erase(itr_regdep_map);
29810259SAndrew.Bardsley@arm.com}
29910259SAndrew.Bardsley@arm.com
30010259SAndrew.Bardsley@arm.comvoid
30110259SAndrew.Bardsley@arm.comElasticTrace::addSquashedInst(const DynInstPtr &head_inst)
30210259SAndrew.Bardsley@arm.com{
30310259SAndrew.Bardsley@arm.com    // If the squashed instruction was squashed before being processed by
30410259SAndrew.Bardsley@arm.com    // execute stage then it will not be in the temporary store. In this case
30510259SAndrew.Bardsley@arm.com    // do nothing and return.
30610259SAndrew.Bardsley@arm.com    auto itr_exec_info = tempStore.find(head_inst->seqNum);
30710259SAndrew.Bardsley@arm.com    if (itr_exec_info == tempStore.end())
30811611SReiley.Jeyapaul@arm.com        return;
30910259SAndrew.Bardsley@arm.com
31010259SAndrew.Bardsley@arm.com    // If there is a squashed load for which a read request was
31110259SAndrew.Bardsley@arm.com    // sent before it got squashed then add it to the trace.
31210259SAndrew.Bardsley@arm.com    DPRINTFR(ElasticTrace, "Attempt to add squashed inst [sn:%lli]\n",
31310259SAndrew.Bardsley@arm.com                head_inst->seqNum);
31410259SAndrew.Bardsley@arm.com    // Get pointer to the execution info object corresponding to the inst.
31510259SAndrew.Bardsley@arm.com    InstExecInfo* exec_info_ptr = itr_exec_info->second;
31611611SReiley.Jeyapaul@arm.com    if (head_inst->isLoad() && exec_info_ptr->executeTick != MaxTick &&
31710259SAndrew.Bardsley@arm.com        exec_info_ptr->toCommitTick != MaxTick &&
31810259SAndrew.Bardsley@arm.com        head_inst->hasRequest() &&
31910259SAndrew.Bardsley@arm.com        head_inst->getFault() == NoFault) {
32010259SAndrew.Bardsley@arm.com        // Add record to depTrace with commit parameter as false.
32110259SAndrew.Bardsley@arm.com        addDepTraceRecord(head_inst, exec_info_ptr, false);
32210259SAndrew.Bardsley@arm.com    }
32312104Snathanael.premillieu@arm.com    // As the information contained is no longer needed, remove the execution
32410259SAndrew.Bardsley@arm.com    // info object from the temporary store.
32510259SAndrew.Bardsley@arm.com    clearTempStoreUntil(head_inst);
32610259SAndrew.Bardsley@arm.com}
32710259SAndrew.Bardsley@arm.com
32812104Snathanael.premillieu@arm.comvoid
32912104Snathanael.premillieu@arm.comElasticTrace::addCommittedInst(const DynInstPtr &head_inst)
33012104Snathanael.premillieu@arm.com{
33112104Snathanael.premillieu@arm.com    DPRINTFR(ElasticTrace, "Attempt to add committed inst [sn:%lli]\n",
33212104Snathanael.premillieu@arm.com                head_inst->seqNum);
33312104Snathanael.premillieu@arm.com
33412104Snathanael.premillieu@arm.com    // Add the instruction to the depTrace.
33512104Snathanael.premillieu@arm.com    if (!head_inst->isNop()) {
33612104Snathanael.premillieu@arm.com
33712104Snathanael.premillieu@arm.com        // If tracing has just been enabled then the instruction at this stage
33812104Snathanael.premillieu@arm.com        // of execution is far enough that we cannot gather info about its past
33912104Snathanael.premillieu@arm.com        // like the tick it started execution. Simply return until we see an
34012104Snathanael.premillieu@arm.com        // instruction that is found in the tempStore.
34110259SAndrew.Bardsley@arm.com        auto itr_temp_store = tempStore.find(head_inst->seqNum);
34210259SAndrew.Bardsley@arm.com        if (itr_temp_store == tempStore.end()) {
34310259SAndrew.Bardsley@arm.com            DPRINTFR(ElasticTrace, "addCommittedInst: [sn:%lli] Not in temp "
34410259SAndrew.Bardsley@arm.com                "store, skipping.\n", head_inst->seqNum);
34512104Snathanael.premillieu@arm.com            return;
34610259SAndrew.Bardsley@arm.com        }
34710259SAndrew.Bardsley@arm.com
34810259SAndrew.Bardsley@arm.com        // Get pointer to the execution info object corresponding to the inst.
34910259SAndrew.Bardsley@arm.com        InstExecInfo* exec_info_ptr = itr_temp_store->second;
35010259SAndrew.Bardsley@arm.com        assert(exec_info_ptr->executeTick != MaxTick);
35112104Snathanael.premillieu@arm.com        assert(exec_info_ptr->toCommitTick != MaxTick);
35212104Snathanael.premillieu@arm.com
35312104Snathanael.premillieu@arm.com        // Check if the instruction had a fault, if it predicated false and
35412104Snathanael.premillieu@arm.com        // thus previous register values were restored or if it was a
35512104Snathanael.premillieu@arm.com        // load/store that did not have a request (e.g. when the size of the
35612104Snathanael.premillieu@arm.com        // request is zero). In all these cases the instruction is set as
35712104Snathanael.premillieu@arm.com        // executed and is picked up by the commit probe listener. But a
35812104Snathanael.premillieu@arm.com        // request is not issued and registers are not written. So practically,
35912104Snathanael.premillieu@arm.com        // skipping these should not hurt as execution would not stall on them.
36012104Snathanael.premillieu@arm.com        // Alternatively, these could be included merely as a compute node in
36112104Snathanael.premillieu@arm.com        // the graph. Removing these for now. If correlation accuracy needs to
36212104Snathanael.premillieu@arm.com        // be improved in future these can be turned into comp nodes at the
36310259SAndrew.Bardsley@arm.com        // cost of bigger traces.
36410259SAndrew.Bardsley@arm.com        if (head_inst->getFault() != NoFault) {
36510529Smorr@cs.wisc.edu            DPRINTF(ElasticTrace, "%s [sn:%lli] has faulted so "
36610529Smorr@cs.wisc.edu                    "skip adding it to the trace\n",
36710529Smorr@cs.wisc.edu                    (head_inst->isMemRef() ? "Load/store" : "Comp inst."),
36811611SReiley.Jeyapaul@arm.com                    head_inst->seqNum);
36911567Smitch.hayenga@arm.com        } else if (head_inst->isMemRef() && !head_inst->hasRequest()) {
37011567Smitch.hayenga@arm.com            DPRINTF(ElasticTrace, "Load/store [sn:%lli]  has no request so "
37111611SReiley.Jeyapaul@arm.com                    "skip adding it to the trace\n", head_inst->seqNum);
37211567Smitch.hayenga@arm.com        } else if (!head_inst->readPredicate()) {
37311567Smitch.hayenga@arm.com            DPRINTF(ElasticTrace, "%s [sn:%lli] is predicated false so "
37411611SReiley.Jeyapaul@arm.com                    "skip adding it to the trace\n",
37511567Smitch.hayenga@arm.com                    (head_inst->isMemRef() ? "Load/store" : "Comp inst."),
37611567Smitch.hayenga@arm.com                    head_inst->seqNum);
37711611SReiley.Jeyapaul@arm.com        } else {
37811567Smitch.hayenga@arm.com            // Add record to depTrace with commit parameter as true.
37910259SAndrew.Bardsley@arm.com            addDepTraceRecord(head_inst, exec_info_ptr, true);
38010259SAndrew.Bardsley@arm.com        }
38110259SAndrew.Bardsley@arm.com    }
38210259SAndrew.Bardsley@arm.com    // As the information contained is no longer needed, remove the execution
38310259SAndrew.Bardsley@arm.com    // info object from the temporary store.
384    clearTempStoreUntil(head_inst);
385}
386
387void
388ElasticTrace::addDepTraceRecord(const DynInstPtr &head_inst,
389                                InstExecInfo* exec_info_ptr, bool commit)
390{
391    // Create a record to assign dynamic intruction related fields.
392    TraceInfo* new_record = new TraceInfo;
393    // Add to map for sequence number look up to retrieve the TraceInfo pointer
394    traceInfoMap[head_inst->seqNum] = new_record;
395
396    // Assign fields from the instruction
397    new_record->instNum = head_inst->seqNum;
398    new_record->commit = commit;
399    new_record->type = head_inst->isLoad() ? Record::LOAD :
400                        (head_inst->isStore() ? Record::STORE :
401                        Record::COMP);
402
403    // Assign fields for creating a request in case of a load/store
404    new_record->reqFlags = head_inst->memReqFlags;
405    new_record->virtAddr = head_inst->effAddr;
406    new_record->asid = head_inst->asid;
407    new_record->physAddr = head_inst->physEffAddrLow;
408    // Currently the tracing does not support split requests.
409    new_record->size = head_inst->effSize;
410    new_record->pc = head_inst->instAddr();
411
412    // Assign the timing information stored in the execution info object
413    new_record->executeTick = exec_info_ptr->executeTick;
414    new_record->toCommitTick = exec_info_ptr->toCommitTick;
415    new_record->commitTick = curTick();
416
417    // Assign initial values for number of dependents and computational delay
418    new_record->numDepts = 0;
419    new_record->compDelay = -1;
420
421    // The physical register dependency set of the first instruction is
422    // empty. Since there are no records in the depTrace at this point, the
423    // case of adding an ROB dependency by using a reverse iterator is not
424    // applicable. Thus, populate the fields of the record corresponding to the
425    // first instruction and return.
426    if (depTrace.empty()) {
427        // Store the record in depTrace.
428        depTrace.push_back(new_record);
429        DPRINTF(ElasticTrace, "Added first inst record %lli to DepTrace.\n",
430                new_record->instNum);
431        return;
432    }
433
434    // Clear register dependencies for squashed loads as they may be dependent
435    // on squashed instructions and we do not add those to the trace.
436    if (head_inst->isLoad() && !commit) {
437         (exec_info_ptr->physRegDepSet).clear();
438    }
439
440    // Assign the register dependencies stored in the execution info object
441    std::set<InstSeqNum>::const_iterator dep_set_it;
442    for (dep_set_it = (exec_info_ptr->physRegDepSet).begin();
443         dep_set_it != (exec_info_ptr->physRegDepSet).end();
444         ++dep_set_it) {
445        auto trace_info_itr = traceInfoMap.find(*dep_set_it);
446        if (trace_info_itr != traceInfoMap.end()) {
447            // The register dependency is valid. Assign it and calculate
448            // computational delay
449            new_record->physRegDepList.push_back(*dep_set_it);
450            DPRINTF(ElasticTrace, "Inst %lli has register dependency on "
451                    "%lli\n", new_record->instNum, *dep_set_it);
452            TraceInfo* reg_dep = trace_info_itr->second;
453            reg_dep->numDepts++;
454            compDelayPhysRegDep(reg_dep, new_record);
455            ++numRegDep;
456        } else {
457            // The instruction that this has a register dependency on was
458            // not added to the trace because of one of the following
459            // 1. it was an instruction that had a fault
460            // 2. it was an instruction that was predicated false and
461            // previous register values were restored
462            // 3. it was load/store that did not have a request (e.g. when
463            // the size of the request is zero but this may not be a fault)
464            // In all these cases the instruction is set as executed and is
465            // picked up by the commit probe listener. But a request is not
466            // issued and registers are not written to in these cases.
467            DPRINTF(ElasticTrace, "Inst %lli has register dependency on "
468                    "%lli is skipped\n",new_record->instNum, *dep_set_it);
469        }
470    }
471
472    // Check for and assign an ROB dependency in addition to register
473    // dependency before adding the record to the trace.
474    // As stores have to commit in order a store is dependent on the last
475    // committed load/store. This is recorded in the ROB dependency.
476    if (head_inst->isStore()) {
477        // Look up store-after-store order dependency
478        updateCommitOrderDep(new_record, false);
479        // Look up store-after-load order dependency
480        updateCommitOrderDep(new_record, true);
481    }
482
483    // In case a node is dependency-free or its dependency got discarded
484    // because it was outside the window, it is marked ready in the ROB at the
485    // time of issue. A request is sent as soon as possible. To model this, a
486    // node is assigned an issue order dependency on a committed instruction
487    // that completed earlier than it. This is done to avoid the problem of
488    // determining the issue times of such dependency-free nodes during replay
489    // which could lead to too much parallelism, thinking conservatively.
490    if (new_record->robDepList.empty() && new_record->physRegDepList.empty()) {
491        updateIssueOrderDep(new_record);
492    }
493
494    // Store the record in depTrace.
495    depTrace.push_back(new_record);
496    DPRINTF(ElasticTrace, "Added %s inst %lli to DepTrace.\n",
497            (commit ? "committed" : "squashed"), new_record->instNum);
498
499    // To process the number of records specified by depWindowSize in the
500    // forward direction, the depTrace must have twice as many records
501    // to check for dependencies.
502    if (depTrace.size() == 2 * depWindowSize) {
503
504        DPRINTF(ElasticTrace, "Writing out trace...\n");
505
506        // Write out the records which have been processed to the trace
507        // and remove them from the depTrace.
508        writeDepTrace(depWindowSize);
509
510        // After the first window, writeDepTrace() must check for valid
511        // compDelay.
512        firstWin = false;
513    }
514}
515
516void
517ElasticTrace::updateCommitOrderDep(TraceInfo* new_record,
518                                    bool find_load_not_store)
519{
520    assert(new_record->isStore());
521    // Iterate in reverse direction to search for the last committed
522    // load/store that completed earlier than the new record
523    depTraceRevItr from_itr(depTrace.end());
524    depTraceRevItr until_itr(depTrace.begin());
525    TraceInfo* past_record = *from_itr;
526    uint32_t num_go_back = 0;
527
528    // The execution time of this store is when it is sent, that is committed
529    Tick execute_tick = curTick();
530    // Search for store-after-load or store-after-store order dependency
531    while (num_go_back < depWindowSize && from_itr != until_itr) {
532        if (find_load_not_store) {
533            // Check if previous inst is a load completed earlier by comparing
534            // with execute tick
535            if (hasLoadCompleted(past_record, execute_tick)) {
536                // Assign rob dependency and calculate the computational delay
537                assignRobDep(past_record, new_record);
538                ++numOrderDepStores;
539                return;
540            }
541        } else {
542            // Check if previous inst is a store sent earlier by comparing with
543            // execute tick
544            if (hasStoreCommitted(past_record, execute_tick)) {
545                // Assign rob dependency and calculate the computational delay
546                assignRobDep(past_record, new_record);
547                ++numOrderDepStores;
548                return;
549            }
550        }
551        ++from_itr;
552        past_record = *from_itr;
553        ++num_go_back;
554    }
555}
556
557void
558ElasticTrace::updateIssueOrderDep(TraceInfo* new_record)
559{
560    // Interate in reverse direction to search for the last committed
561    // record that completed earlier than the new record
562    depTraceRevItr from_itr(depTrace.end());
563    depTraceRevItr until_itr(depTrace.begin());
564    TraceInfo* past_record = *from_itr;
565
566    uint32_t num_go_back = 0;
567    Tick execute_tick = 0;
568
569    if (new_record->isLoad()) {
570        // The execution time of a load is when a request is sent
571        execute_tick = new_record->executeTick;
572        ++numIssueOrderDepLoads;
573    } else if (new_record->isStore()) {
574        // The execution time of a store is when it is sent, i.e. committed
575        execute_tick = curTick();
576        ++numIssueOrderDepStores;
577    } else {
578        // The execution time of a non load/store is when it completes
579        execute_tick = new_record->toCommitTick;
580        ++numIssueOrderDepOther;
581    }
582
583    // We search if this record has an issue order dependency on a past record.
584    // Once we find it, we update both the new record and the record it depends
585    // on and return.
586    while (num_go_back < depWindowSize && from_itr != until_itr) {
587        // Check if a previous inst is a load sent earlier, or a store sent
588        // earlier, or a comp inst completed earlier by comparing with execute
589        // tick
590        if (hasLoadBeenSent(past_record, execute_tick) ||
591            hasStoreCommitted(past_record, execute_tick) ||
592            hasCompCompleted(past_record, execute_tick)) {
593            // Assign rob dependency and calculate the computational delay
594            assignRobDep(past_record, new_record);
595            return;
596        }
597        ++from_itr;
598        past_record = *from_itr;
599        ++num_go_back;
600    }
601}
602
603void
604ElasticTrace::assignRobDep(TraceInfo* past_record, TraceInfo* new_record) {
605    DPRINTF(ElasticTrace, "%s %lli has ROB dependency on %lli\n",
606            new_record->typeToStr(), new_record->instNum,
607            past_record->instNum);
608    // Add dependency on past record
609    new_record->robDepList.push_back(past_record->instNum);
610    // Update new_record's compute delay with respect to the past record
611    compDelayRob(past_record, new_record);
612    // Increment number of dependents of the past record
613    ++(past_record->numDepts);
614    // Update stat to log max number of dependents
615    maxNumDependents = std::max(past_record->numDepts,
616                                (uint32_t)maxNumDependents.value());
617}
618
619bool
620ElasticTrace::hasStoreCommitted(TraceInfo* past_record,
621                                    Tick execute_tick) const
622{
623    return (past_record->isStore() && past_record->commitTick <= execute_tick);
624}
625
626bool
627ElasticTrace::hasLoadCompleted(TraceInfo* past_record,
628                                    Tick execute_tick) const
629{
630    return(past_record->isLoad() && past_record->commit &&
631                past_record->toCommitTick <= execute_tick);
632}
633
634bool
635ElasticTrace::hasLoadBeenSent(TraceInfo* past_record,
636                                Tick execute_tick) const
637{
638    // Check if previous inst is a load sent earlier than this
639    return (past_record->isLoad() && past_record->commit &&
640        past_record->executeTick <= execute_tick);
641}
642
643bool
644ElasticTrace::hasCompCompleted(TraceInfo* past_record,
645                                    Tick execute_tick) const
646{
647    return(past_record->isComp() && past_record->toCommitTick <= execute_tick);
648}
649
650void
651ElasticTrace::clearTempStoreUntil(const DynInstPtr head_inst)
652{
653    // Clear from temp store starting with the execution info object
654    // corresponding the head_inst and continue clearing by decrementing the
655    // sequence number until the last cleared sequence number.
656    InstSeqNum temp_sn = (head_inst->seqNum);
657    while (temp_sn > lastClearedSeqNum) {
658        auto itr_exec_info = tempStore.find(temp_sn);
659        if (itr_exec_info != tempStore.end()) {
660            InstExecInfo* exec_info_ptr = itr_exec_info->second;
661            // Free allocated memory for the info object
662            delete exec_info_ptr;
663            // Remove entry from temporary store
664            tempStore.erase(itr_exec_info);
665        }
666        temp_sn--;
667    }
668    // Update the last cleared sequence number to that of the head_inst
669    lastClearedSeqNum = head_inst->seqNum;
670}
671
672void
673ElasticTrace::compDelayRob(TraceInfo* past_record, TraceInfo* new_record)
674{
675    // The computation delay is the delay between the completion tick of the
676    // inst. pointed to by past_record and the execution tick of its dependent
677    // inst. pointed to by new_record.
678    int64_t comp_delay = -1;
679    Tick execution_tick = 0, completion_tick = 0;
680
681    DPRINTF(ElasticTrace, "Seq num %lli has ROB dependency on seq num %lli.\n",
682            new_record->instNum, past_record->instNum);
683
684    // Get the tick when the node is executed as per the modelling of
685    // computation delay
686    execution_tick = new_record->getExecuteTick();
687
688    if (past_record->isLoad()) {
689        if (new_record->isStore()) {
690            completion_tick = past_record->toCommitTick;
691        } else {
692            completion_tick = past_record->executeTick;
693        }
694    } else if (past_record->isStore()) {
695        completion_tick = past_record->commitTick;
696    } else if (past_record->isComp()){
697        completion_tick = past_record->toCommitTick;
698    }
699    assert(execution_tick >= completion_tick);
700    comp_delay = execution_tick - completion_tick;
701
702    DPRINTF(ElasticTrace, "Computational delay is %lli - %lli = %lli\n",
703            execution_tick, completion_tick, comp_delay);
704
705    // Assign the computational delay with respect to the dependency which
706    // completes the latest.
707    if (new_record->compDelay == -1)
708        new_record->compDelay = comp_delay;
709    else
710        new_record->compDelay = std::min(comp_delay, new_record->compDelay);
711    DPRINTF(ElasticTrace, "Final computational delay = %lli.\n",
712            new_record->compDelay);
713}
714
715void
716ElasticTrace::compDelayPhysRegDep(TraceInfo* past_record,
717                                    TraceInfo* new_record)
718{
719    // The computation delay is the delay between the completion tick of the
720    // inst. pointed to by past_record and the execution tick of its dependent
721    // inst. pointed to by new_record.
722    int64_t comp_delay = -1;
723    Tick execution_tick = 0, completion_tick = 0;
724
725    DPRINTF(ElasticTrace, "Seq. num %lli has register dependency on seq. num"
726            " %lli.\n", new_record->instNum, past_record->instNum);
727
728    // Get the tick when the node is executed as per the modelling of
729    // computation delay
730    execution_tick = new_record->getExecuteTick();
731
732    // When there is a physical register dependency on an instruction, the
733    // completion tick of that instruction is when it wrote to the register,
734    // that is toCommitTick. In case, of a store updating a destination
735    // register, this is approximated to commitTick instead
736    if (past_record->isStore()) {
737        completion_tick = past_record->commitTick;
738    } else {
739        completion_tick = past_record->toCommitTick;
740    }
741    assert(execution_tick >= completion_tick);
742    comp_delay = execution_tick - completion_tick;
743    DPRINTF(ElasticTrace, "Computational delay is %lli - %lli = %lli\n",
744            execution_tick, completion_tick, comp_delay);
745
746    // Assign the computational delay with respect to the dependency which
747    // completes the latest.
748    if (new_record->compDelay == -1)
749        new_record->compDelay = comp_delay;
750    else
751        new_record->compDelay = std::min(comp_delay, new_record->compDelay);
752    DPRINTF(ElasticTrace, "Final computational delay = %lli.\n",
753            new_record->compDelay);
754}
755
756Tick
757ElasticTrace::TraceInfo::getExecuteTick() const
758{
759    if (isLoad()) {
760        // Execution tick for a load instruction is when the request was sent,
761        // that is executeTick.
762        return executeTick;
763    } else if (isStore()) {
764        // Execution tick for a store instruction is when the request was sent,
765        // that is commitTick.
766        return commitTick;
767    } else {
768        // Execution tick for a non load/store instruction is when the register
769        // value was written to, that is commitTick.
770        return toCommitTick;
771    }
772}
773
774void
775ElasticTrace::writeDepTrace(uint32_t num_to_write)
776{
777    // Write the trace with fields as follows:
778    // Instruction sequence number
779    // If instruction was a load
780    // If instruction was a store
781    // If instruction has addr
782    // If instruction has size
783    // If instruction has flags
784    // List of order dependencies - optional, repeated
785    // Computational delay with respect to last completed dependency
786    // List of physical register RAW dependencies - optional, repeated
787    // Weight of a node equal to no. of filtered nodes before it - optional
788    uint16_t num_filtered_nodes = 0;
789    depTraceItr dep_trace_itr(depTrace.begin());
790    depTraceItr dep_trace_itr_start = dep_trace_itr;
791    while (num_to_write > 0) {
792        TraceInfo* temp_ptr = *dep_trace_itr;
793        assert(temp_ptr->type != Record::INVALID);
794        // If no node dependends on a comp node then there is no reason to
795        // track the comp node in the dependency graph. We filter out such
796        // nodes but count them and add a weight field to the subsequent node
797        // that we do include in the trace.
798        if (!temp_ptr->isComp() || temp_ptr->numDepts != 0) {
799            DPRINTFR(ElasticTrace, "Instruction with seq. num %lli "
800                     "is as follows:\n", temp_ptr->instNum);
801            if (temp_ptr->isLoad() || temp_ptr->isStore()) {
802                DPRINTFR(ElasticTrace, "\tis a %s\n", temp_ptr->typeToStr());
803                DPRINTFR(ElasticTrace, "\thas a request with phys addr %i, "
804                         "size %i, flags %i\n", temp_ptr->physAddr,
805                         temp_ptr->size, temp_ptr->reqFlags);
806            } else {
807                 DPRINTFR(ElasticTrace, "\tis a %s\n", temp_ptr->typeToStr());
808            }
809            if (firstWin && temp_ptr->compDelay == -1) {
810                if (temp_ptr->isLoad()) {
811                    temp_ptr->compDelay = temp_ptr->executeTick;
812                } else if (temp_ptr->isStore()) {
813                    temp_ptr->compDelay = temp_ptr->commitTick;
814                } else {
815                    temp_ptr->compDelay = temp_ptr->toCommitTick;
816                }
817            }
818            assert(temp_ptr->compDelay != -1);
819            DPRINTFR(ElasticTrace, "\thas computational delay %lli\n",
820                     temp_ptr->compDelay);
821
822            // Create a protobuf message for the dependency record
823            ProtoMessage::InstDepRecord dep_pkt;
824            dep_pkt.set_seq_num(temp_ptr->instNum);
825            dep_pkt.set_type(temp_ptr->type);
826            dep_pkt.set_pc(temp_ptr->pc);
827            if (temp_ptr->isLoad() || temp_ptr->isStore()) {
828                dep_pkt.set_flags(temp_ptr->reqFlags);
829                dep_pkt.set_p_addr(temp_ptr->physAddr);
830                // If tracing of virtual addresses is enabled, set the optional
831                // field for it
832                if (traceVirtAddr) {
833                    dep_pkt.set_v_addr(temp_ptr->virtAddr);
834                    dep_pkt.set_asid(temp_ptr->asid);
835                }
836                dep_pkt.set_size(temp_ptr->size);
837            }
838            dep_pkt.set_comp_delay(temp_ptr->compDelay);
839            if (temp_ptr->robDepList.empty()) {
840                DPRINTFR(ElasticTrace, "\thas no order (rob) dependencies\n");
841            }
842            while (!temp_ptr->robDepList.empty()) {
843                DPRINTFR(ElasticTrace, "\thas order (rob) dependency on %lli\n",
844                         temp_ptr->robDepList.front());
845                dep_pkt.add_rob_dep(temp_ptr->robDepList.front());
846                temp_ptr->robDepList.pop_front();
847            }
848            if (temp_ptr->physRegDepList.empty()) {
849                DPRINTFR(ElasticTrace, "\thas no register dependencies\n");
850            }
851            while (!temp_ptr->physRegDepList.empty()) {
852                DPRINTFR(ElasticTrace, "\thas register dependency on %lli\n",
853                         temp_ptr->physRegDepList.front());
854                dep_pkt.add_reg_dep(temp_ptr->physRegDepList.front());
855                temp_ptr->physRegDepList.pop_front();
856            }
857            if (num_filtered_nodes != 0) {
858                // Set the weight of this node as the no. of filtered nodes
859                // between this node and the last node that we wrote to output
860                // stream. The weight will be used during replay to model ROB
861                // occupancy of filtered nodes.
862                dep_pkt.set_weight(num_filtered_nodes);
863                num_filtered_nodes = 0;
864            }
865            // Write the message to the protobuf output stream
866            dataTraceStream->write(dep_pkt);
867        } else {
868            // Don't write the node to the trace but note that we have filtered
869            // out a node.
870            ++numFilteredNodes;
871            ++num_filtered_nodes;
872        }
873        dep_trace_itr++;
874        traceInfoMap.erase(temp_ptr->instNum);
875        delete temp_ptr;
876        num_to_write--;
877    }
878    depTrace.erase(dep_trace_itr_start, dep_trace_itr);
879}
880
881void
882ElasticTrace::regStats() {
883    ProbeListenerObject::regStats();
884
885    using namespace Stats;
886    numRegDep
887        .name(name() + ".numRegDep")
888        .desc("Number of register dependencies recorded during tracing")
889        ;
890
891    numOrderDepStores
892        .name(name() + ".numOrderDepStores")
893        .desc("Number of commit order (rob) dependencies for a store recorded"
894              " on a past load/store during tracing")
895        ;
896
897    numIssueOrderDepLoads
898        .name(name() + ".numIssueOrderDepLoads")
899        .desc("Number of loads that got assigned issue order dependency"
900              " because they were dependency-free")
901        ;
902
903    numIssueOrderDepStores
904        .name(name() + ".numIssueOrderDepStores")
905        .desc("Number of stores that got assigned issue order dependency"
906              " because they were dependency-free")
907        ;
908
909    numIssueOrderDepOther
910        .name(name() + ".numIssueOrderDepOther")
911        .desc("Number of non load/store insts that got assigned issue order"
912              " dependency because they were dependency-free")
913        ;
914
915    numFilteredNodes
916        .name(name() + ".numFilteredNodes")
917        .desc("No. of nodes filtered out before writing the output trace")
918        ;
919
920    maxNumDependents
921        .name(name() + ".maxNumDependents")
922        .desc("Maximum number or dependents on any instruction")
923        ;
924
925    maxTempStoreSize
926        .name(name() + ".maxTempStoreSize")
927        .desc("Maximum size of the temporary store during the run")
928        ;
929
930    maxPhysRegDepMapSize
931        .name(name() + ".maxPhysRegDepMapSize")
932        .desc("Maximum size of register dependency map")
933        ;
934}
935
936const std::string&
937ElasticTrace::TraceInfo::typeToStr() const
938{
939    return Record::RecordType_Name(type);
940}
941
942const std::string
943ElasticTrace::name() const
944{
945    return ProbeListenerObject::name();
946}
947
948void
949ElasticTrace::flushTraces()
950{
951    // Write to trace all records in the depTrace.
952    writeDepTrace(depTrace.size());
953    // Delete the stream objects
954    delete dataTraceStream;
955    delete instTraceStream;
956}
957
958ElasticTrace*
959ElasticTraceParams::create()
960{
961    return new ElasticTrace(this);
962}
963